diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000000..13eb5742dbf0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# We vendor typeshed from https://github.com/python/typeshed +mypy/typeshed/ linguist-vendored diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index ee2777a75fe6..1b3a16eebd2c 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -7,6 +7,12 @@ labels: "bug" **Bug Report** diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml index 948a4230a644..1d56057854c3 100644 --- a/.github/workflows/build_wheels.yml +++ b/.github/workflows/build_wheels.yml @@ -2,15 +2,8 @@ name: Trigger wheel build on: push: - branches: [master] + branches: [master, 'release*'] tags: ['*'] - paths-ignore: - - 'docs/**' - - '**/*.rst' - - '**/*.md' - - .gitignore - - CREDITS - - LICENSE jobs: build-wheels: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index f314257790a7..d44f9143bdc7 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -2,7 +2,7 @@ name: Check documentation build on: push: - branches: [master] + branches: [master, 'release*'] tags: ['*'] pull_request: paths: diff --git a/.github/workflows/mypy_primer.yml b/.github/workflows/mypy_primer.yml index b2166e12330d..fcd8b938f295 100644 --- a/.github/workflows/mypy_primer.yml +++ b/.github/workflows/mypy_primer.yml @@ -11,7 +11,7 @@ on: jobs: mypy_primer: - name: Run + name: Run mypy_primer runs-on: ubuntu-latest permissions: contents: read @@ -37,16 +37,19 @@ jobs: cd mypy_to_test echo "new commit" git rev-list --format=%s --max-count=1 $GITHUB_SHA - git checkout -b upstream_master origin/master + + MERGE_BASE=$(git merge-base $GITHUB_SHA origin/master) + git checkout -b base_commit $MERGE_BASE echo "base commit" - git rev-list --format=%s --max-count=1 upstream_master + git rev-list --format=%s --max-count=1 base_commit + echo '' cd .. # fail action if exit code isn't zero or one ( mypy_primer \ --repo mypy_to_test \ - --new $GITHUB_SHA --old upstream_master \ + --new $GITHUB_SHA --old base_commit \ --num-shards 3 --shard-index ${{ matrix.shard-index }} \ --debug \ --output concise \ diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2e1f73e981a3..3081c15594cb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,7 +2,7 @@ name: Tests on: push: - branches: [master] + branches: [master, 'release*'] tags: ['*'] pull_request: paths-ignore: @@ -56,6 +56,12 @@ jobs: toxenv: py tox_extra_args: "-n 2" test_mypyc: true + - name: Test suite with py310-ubuntu + python: '3.10' + arch: x64 + os: ubuntu-latest + toxenv: py + tox_extra_args: "-n 2" - name: mypyc runtime tests with py36-macos python: '3.6' arch: x64 @@ -96,7 +102,7 @@ jobs: ./misc/build-debug-python.sh $PYTHONVERSION $PYTHONDIR $VENV source $VENV/bin/activate - name: Install tox - run: pip install --upgrade 'setuptools!=50' 'virtualenv<16.7.11' tox==3.20.1 + run: pip install --upgrade 'setuptools!=50' 'virtualenv>=20.6.0' tox==3.20.1 - name: Compiled with mypyc if: ${{ matrix.test_mypyc }} run: | @@ -107,23 +113,24 @@ jobs: - name: Test run: tox -e ${{ matrix.toxenv }} --skip-pkg-install -- ${{ matrix.tox_extra_args }} - python-nightly: - runs-on: ubuntu-latest - name: Test suite with Python nightly - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - with: - python-version: '3.10-dev' - - name: Install tox - run: | - pip install -U pip==21.2.3 setuptools - pip install --upgrade 'setuptools!=50' virtualenv==20.4.7 tox==3.20.1 - - name: Setup tox environment - run: tox -e py --notest - - name: Test - run: tox -e py --skip-pkg-install -- "-n 2" - continue-on-error: true - - name: Mark as a success - run: exit 0 +# TODO: uncomment this when 3.11-dev is available +# python-nightly: +# runs-on: ubuntu-latest +# name: Test suite with Python nightly +# steps: +# - uses: actions/checkout@v2 +# - uses: actions/setup-python@v2 +# with: +# python-version: '3.11-dev' +# - name: Install tox +# run: | +# pip install -U pip==21.2.3 setuptools +# pip install --upgrade 'setuptools!=50' virtualenv==20.4.7 tox==3.20.1 +# - name: Setup tox environment +# run: tox -e py --notest +# - name: Test +# run: tox -e py --skip-pkg-install -- "-n 2" +# continue-on-error: true +# - name: Mark as a success +# run: exit 0 diff --git a/.github/workflows/test_stubgenc.yml b/.github/workflows/test_stubgenc.yml index 5aa0c7cdf200..6408f21ccffe 100644 --- a/.github/workflows/test_stubgenc.yml +++ b/.github/workflows/test_stubgenc.yml @@ -2,7 +2,7 @@ name: Test stubgenc on pybind11-mypy-demo on: push: - branches: [master] + branches: [master, 'release*'] tags: ['*'] pull_request: paths: diff --git a/.gitignore b/.gitignore index c6238dc32beb..3c0f60cfae4f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,7 @@ docs/source/_build mypyc/doc/_build *.iml /out/ -.venv*/ +.venv venv/ .mypy_cache/ .incremental_checker_cache.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 13aeab4d01f5..9e5bdeb90a69 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,74 +1,89 @@ -Contributing to Mypy -==================== +# Contributing to Mypy Welcome! Mypy is a community project that aims to work for a wide -range of Python users and Python codebases. If you're trying Mypy on +range of Python users and Python codebases. If you're trying mypy on your Python code, your experience and what you can contribute are important to the project's success. +## Code of Conduct -Getting started, building, and testing --------------------------------------- +Everyone participating in the Mypy community, and in particular in our +issue tracker, pull requests, and chat, is expected to treat +other people with respect and more generally to follow the guidelines +articulated in the [Python Community Code of Conduct](https://www.python.org/psf/codeofconduct/). -If you haven't already, take a look at the project's -[README.md file](README.md) -and the [Mypy documentation](https://mypy.readthedocs.io/en/latest/), -and try adding type annotations to your file and type-checking it with Mypy. +## Getting started with development -Discussion ----------- +### Setup -If you've run into behavior in Mypy you don't understand, or you're -having trouble working out a good way to apply it to your code, or -you've found a bug or would like a feature it doesn't have, we want to -hear from you! +Run the following: +``` +# Clone the mypy repository +git clone https://github.com/python/mypy.git -Our main forum for discussion is the project's [GitHub issue -tracker](https://github.com/python/mypy/issues). This is the right -place to start a discussion of any of the above or most any other -topic concerning the project. +# Enter the repository +cd mypy -For less formal discussion we have a chat room on -[gitter.im](https://gitter.im/python/typing). Some Mypy core developers -are almost always present; feel free to find us there and we're happy -to chat. Substantive technical discussion will be directed to the -issue tracker. +# Create then activate a virtual environment +python3 -m venv venv +source venv/bin/activate -(We also have an IRC channel, `#python-mypy` on irc.freenode.net. -This is lightly used, we have mostly switched to the gitter room -mentioned above.) +# Install the test requirements and the project +python3 -m pip install -r test-requirements.txt +python3 -m pip install -e . +hash -r +``` -#### Code of Conduct +### Running tests -Everyone participating in the Mypy community, and in particular in our -issue tracker, pull requests, and IRC channel, is expected to treat -other people with respect and more generally to follow the guidelines -articulated in the [Python Community Code of -Conduct](https://www.python.org/psf/codeofconduct/). +Once setup, you should be able to run tests: +``` +python3 runtests.py +``` + +To use mypy to check mypy's own code, run: +``` +python3 runtests.py self +# or equivalently: +python3 -m mypy --config-file mypy_self_check.ini -p mypy +``` + +You can also use `tox` to run tests, for instance: +``` +tox -e py +``` + +## First time contributors + +If you're looking for things to help with, browse our [issue tracker](https://github.com/python/mypy/issues)! -First Time Contributors ------------------------ +In particular, look for: +- [good first issues](https://github.com/python/mypy/labels/good-first-issue) +- [good second issues](https://github.com/python/mypy/labels/good-second-issue) +- [documentation issues](https://github.com/python/mypy/labels/documentation) -Mypy appreciates your contribution! If you are interested in helping improve -mypy, there are several ways to get started: +It's also extremely easy to get started contributing to our sister project +[typeshed](https://github.com/python/typeshed/issues) that provides type stubs +for libraries. This is a great way to become familiar with type syntax. -* Contributing to [typeshed](https://github.com/python/typeshed/issues) is a great way to -become familiar with Python's type syntax. -* Work on [documentation issues](https://github.com/python/mypy/labels/documentation). -* Ask on [the chat](https://gitter.im/python/typing) or on -[the issue tracker](https://github.com/python/mypy/issues) about good beginner issues. +If you need help getting started, don't hesitate to ask on +[gitter](https://gitter.im/python/typing). -Submitting Changes ------------------- +To get help fixing a specific issue, it's often best to comment on the issue +itself. The more details you provide about what you've tried and where you've +looked, the easier it will be for you to get help. + +Interactive debuggers like `pdb` and `ipdb` are really useful for getting +started with the mypy codebase. This is a +[useful tutorial](https://realpython.com/python-debugging-pdb/). + +## Submitting changes Even more excellent than a good bug report is a fix for a bug, or the -implementation of a much-needed new feature. (*) We'd love to have +implementation of a much-needed new feature. We'd love to have your contributions. -(*) If your new feature will be a lot of work, we recommend talking to - us early -- see below. - We use the usual GitHub pull-request flow, which may be familiar to you if you've contributed to other projects on GitHub. For the mechanics, see [our git and GitHub workflow help page](https://github.com/python/mypy/wiki/Using-Git-And-GitHub), @@ -76,17 +91,8 @@ or [GitHub's own documentation](https://help.github.com/articles/using-pull-requ Anyone interested in Mypy may review your code. One of the Mypy core developers will merge your pull request when they think it's ready. -For every pull request, we aim to promptly either merge it or say why -it's not yet ready; if you go a few days without a reply, please feel -free to ping the thread by adding a new comment. - -For a list of mypy core developers, see the file [CREDITS](CREDITS). - -Preparing Changes ------------------ - -Before you begin: if your change will be a significant amount of work +If your change will be a significant amount of work to write, we highly recommend starting by opening an issue laying out what you want to do. That lets a conversation happen early in case other contributors disagree with what you'd like to do or have ideas @@ -113,8 +119,7 @@ You may also find other pages in the helpful in developing your change. -Core developer guidelines -------------------------- +## Core developer guidelines Core developers should follow these rules when processing pull requests: @@ -138,52 +143,3 @@ Core developers should follow these rules when processing pull requests: * If the PR fixes an issue, make sure something like "Fixes #xxx." occurs in the body of the message (not in the subject). * Use Markdown for formatting. - - -Issue-tracker conventions -------------------------- - -We aim to reply to all new issues promptly. We'll assign a milestone -to help us track which issues we intend to get to when, and may apply -labels to carry some other information. Here's what our milestones -and labels mean. - -### Task priority and sizing - -We use GitHub "labels" ([see our -list](https://github.com/python/mypy/labels)) to roughly order what we -want to do soon and less soon. There's two dimensions taken into -account: **priority** (does it matter to our users) and **size** (how -long will it take to complete). - -Bugs that aren't a huge deal but do matter to users and don't seem -like a lot of work to fix generally will be dealt with sooner; things -that will take longer may go further out. - -We are trying to keep the backlog at a manageable size, an issue that is -unlikely to be acted upon in foreseeable future is going to be -respectfully closed. This doesn't mean the issue is not important, but -rather reflects the limits of the team. - -The **question** label is for issue threads where a user is asking a -question but it isn't yet clear that it represents something to actually -change. We use the issue tracker as the preferred venue for such -questions, even when they aren't literally issues, to keep down the -number of distinct discussion venues anyone needs to track. These might -evolve into a bug or feature request. - -Issues **without a priority or size** haven't been triaged. We aim to -triage all new issues promptly, but there are some issues from previous -years that we haven't yet re-reviewed since adopting these conventions. - -### Other labels - -* **needs discussion**: This issue needs agreement on some kind of - design before it makes sense to implement it, and it either doesn't - yet have a design or doesn't yet have agreement on one. -* **feature**, **bug**, **crash**, **refactoring**, **documentation**: - These classify the user-facing impact of the change. Specifically - "refactoring" means there should be no user-facing effect. -* **topic-** labels group issues touching a similar aspect of the - project, for example PEP 484 compatibility, a specific command-line - option or dependency. diff --git a/CREDITS b/CREDITS index 508616cf2516..d0e53de5ee01 100644 --- a/CREDITS +++ b/CREDITS @@ -10,14 +10,16 @@ the release blog posts at https://mypy-lang.blogspot.com/. Dropbox core team: Jukka Lehtosalo - Guido van Rossum Ivan Levkivskyi - Michael J. Sullivan Non-Dropbox core team members: Ethan Smith + Guido van Rossum Jelle Zijlstra + Michael J. Sullivan + Shantanu Jain + Xuanda Yang Past Dropbox core team members: diff --git a/MANIFEST.in b/MANIFEST.in index dd65e119e147..fc657091a3dc 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -41,7 +41,7 @@ include runtests.py include pytest.ini include LICENSE mypyc/README.md -exclude .gitmodules CONTRIBUTING.md CREDITS ROADMAP.md tox.ini +exclude .gitmodules CONTRIBUTING.md CREDITS ROADMAP.md tox.ini action.yml global-exclude *.py[cod] global-exclude .DS_Store diff --git a/README.md b/README.md index 3c7a1e708642..16436e208cd3 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,76 @@ mypy logo -Mypy: Optional Static Typing for Python +Mypy: Static Typing for Python ======================================= [![Build Status](https://api.travis-ci.com/python/mypy.svg?branch=master)](https://travis-ci.com/python/mypy) +[![Documentation Status](https://readthedocs.org/projects/mypy/badge/?version=latest)](https://mypy.readthedocs.io/en/latest/?badge=latest) [![Chat at https://gitter.im/python/typing](https://badges.gitter.im/python/typing.svg)](https://gitter.im/python/typing?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Checked with mypy](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/) -Got a question? Join us on Gitter! ----------------------------------- +Got a question? +--------------- -We don't have a mailing list; but we are always happy to answer -questions on [gitter chat](https://gitter.im/python/typing). If you are -sure you've found a bug please search our issue trackers for a -duplicate before filing a new issue: +We are always happy to answer questions! Here are some good places to ask them: -- [mypy tracker](https://github.com/python/mypy/issues) - for mypy issues -- [typeshed tracker](https://github.com/python/typeshed/issues) - for issues with specific modules -- [typing tracker](https://github.com/python/typing/issues) - for discussion of new type system features (PEP 484 changes) and - runtime bugs in the typing module +- for anything you're curious about, try [gitter chat](https://gitter.im/python/typing) +- for general questions about Python typing, try [typing discussions](https://github.com/python/typing/discussions) -What is mypy? -------------- +If you're just getting started, +[the documentation](https://mypy.readthedocs.io/en/stable/introduction.html) +and [type hints cheat sheet](https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html) +can also help answer questions. -Mypy is an optional static type checker for Python. You can add type -hints ([PEP 484](https://www.python.org/dev/peps/pep-0484/)) to your -Python programs, and use mypy to type check them statically. -Find bugs in your programs without even running them! +If you think you've found a bug: -You can mix dynamic and static typing in your programs. You can always -fall back to dynamic typing when static typing is not convenient, such -as for legacy code. +- check our [common issues page](https://mypy.readthedocs.io/en/stable/common_issues.html) +- search our [issue tracker](https://github.com/python/mypy/issues) to see if + it's already been reported +- consider asking on [gitter chat](https://gitter.im/python/typing) -Here is a small example to whet your appetite (Python 3): +To report a bug or request an enhancement: -```python -from typing import Iterator +- report at [our issue tracker](https://github.com/python/mypy/issues) +- if the issue is with a specific library or function, consider reporting it at + [typeshed tracker](https://github.com/python/typeshed/issues) or the issue + tracker for that library -def fib(n: int) -> Iterator[int]: - a, b = 0, 1 - while a < n: - yield a - a, b = b, a + b -``` -See [the documentation](https://mypy.readthedocs.io/en/stable/introduction.html) for more examples. +To discuss a new type system feature: +- discuss at [typing-sig mailing list](https://mail.python.org/archives/list/typing-sig@python.org/) +- there is also some historical discussion [here](https://github.com/python/typing/issues) -For Python 2.7, the standard annotations are written as comments: -```python -def is_palindrome(s): - # type: (str) -> bool - return s == s[::-1] -``` -See [the documentation for Python 2 support](https://mypy.readthedocs.io/en/latest/python2.html). +What is mypy? +------------- -Mypy is in development; some features are missing and there are bugs. -See 'Development status' below. +Mypy is a static type checker for Python. -Requirements ------------- +Type checkers help ensure that you're using variables and functions in your code +correctly. With mypy, add type hints ([PEP 484](https://www.python.org/dev/peps/pep-0484/)) +to your Python programs, and mypy will warn you when you use those types +incorrectly. -You need Python 3.5 or later to run mypy. You can have multiple Python -versions (2.x and 3.x) installed on the same system without problems. +Python is a dynamic language, so usually you'll only see errors in your code +when you attempt to run it. Mypy is a *static* checker, so it finds bugs +in your programs without even running them! -In Ubuntu, Mint and Debian you can install Python 3 like this: +Mypy is designed with gradual typing in mind. This means you can add type +hints to your code base slowly and that you can always fall back to dynamic +typing when static typing is not convenient. - $ sudo apt-get install python3 python3-pip +Here is a small example to whet your appetite: -For other Linux flavors, macOS and Windows, packages are available at +```python +number = input("What is your favourite number?") +print("Well, my favourite number is: ", number + 1) # error: Unsupported operand types for + ("str" and "int") +``` + +See [the documentation](https://mypy.readthedocs.io/en/stable/introduction.html) for more examples. - https://www.python.org/getit/ +In particular, see: +- [type hints cheat sheet](https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html) +- [getting started](https://mypy.readthedocs.io/en/stable/getting_started.html) Quick start @@ -81,23 +78,21 @@ Quick start Mypy can be installed using pip: - $ python3 -m pip install -U mypy + python3 -m pip install -U mypy If you want to run the latest version of the code, you can install from git: - $ python3 -m pip install -U git+git://github.com/python/mypy.git + python3 -m pip install -U git+git://github.com/python/mypy.git -Now, if Python on your system is configured properly (else see -"Troubleshooting" below), you can type-check the [statically typed parts] of a -program like this: +Now you can type-check the [statically typed parts] of a program like this: - $ mypy PROGRAM + mypy PROGRAM -You can always use a Python interpreter to run your statically typed -programs, even if they have type errors: +You can always use the Python interpreter to run your statically typed +programs, even if mypy reports type errors: - $ python3 PROGRAM + python3 PROGRAM You can also try mypy in an [online playground](https://mypy-play.net/) (developed by Yusuke Miyazaki). @@ -105,8 +100,8 @@ Yusuke Miyazaki). [statically typed parts]: https://mypy.readthedocs.io/en/latest/getting_started.html#function-signatures-and-dynamic-vs-static-typing -IDE, Linter Integrations, and Pre-commit ----------------------------------------- +Integrations +------------ Mypy can be integrated into popular IDEs: @@ -121,99 +116,34 @@ Mypy can be integrated into popular IDEs: * PyCharm: [mypy plugin](https://github.com/dropbox/mypy-PyCharm-plugin) (PyCharm integrates [its own implementation of PEP 484](https://www.jetbrains.com/help/pycharm/type-hinting-in-product.html)) * VS Code: provides [basic integration](https://code.visualstudio.com/docs/python/linting#_mypy) with mypy. - -Mypy can also be set up as a pre-commit hook using [pre-commit mirrors-mypy]. - -[pre-commit mirrors-mypy]: https://github.com/pre-commit/mirrors-mypy +* pre-commit: use [pre-commit mirrors-mypy](https://github.com/pre-commit/mirrors-mypy). Web site and documentation -------------------------- -Documentation and additional information is available at the web site: +Additional information is available at the web site: http://www.mypy-lang.org/ -Or you can jump straight to the documentation: +Jump straight to the documentation: https://mypy.readthedocs.io/ +Follow along our changelog at: -Troubleshooting ---------------- - -Depending on your configuration, you may have to run `pip` like -this: - - $ python3 -m pip install -U mypy - -This should automatically install the appropriate version of -mypy's parser, typed-ast. If for some reason it does not, you -can install it manually: - - $ python3 -m pip install -U typed-ast - -If the `mypy` command isn't found after installation: After -`python3 -m pip install`, the `mypy` script and -dependencies, including the `typing` module, will be installed to -system-dependent locations. Sometimes the script directory will not -be in `PATH`, and you have to add the target directory to `PATH` -manually or create a symbolic link to the script. In particular, on -macOS, the script may be installed under `/Library/Frameworks`: - - /Library/Frameworks/Python.framework/Versions//bin - -In Windows, the script is generally installed in -`\PythonNN\Scripts`. So, type check a program like this (replace -`\Python34` with your Python installation path): - - C:\>\Python34\python \Python34\Scripts\mypy PROGRAM - -### Working with `virtualenv` - -If you are using [`virtualenv`](https://virtualenv.pypa.io/en/stable/), -make sure you are running a python3 environment. Installing via `pip3` -in a v2 environment will not configure the environment to run installed -modules from the command line. - - $ python3 -m pip install -U virtualenv - $ python3 -m virtualenv env + https://mypy-lang.blogspot.com/ -Quick start for contributing to mypy ------------------------------------- - -If you want to contribute, first clone the mypy git repository: - - $ git clone https://github.com/python/mypy.git - -From the mypy directory, use pip to install mypy: - - $ cd mypy - $ python3 -m pip install -U . - -Replace `python3` with your Python 3 interpreter. You may have to do -the above as root. For example, in Ubuntu: - - $ sudo python3 -m pip install -U . - -Now you can use the `mypy` program just as above. In case of trouble -see "Troubleshooting" above. - -> NOTE: Installing with sudo can be a security risk. Please try with the `--user` flag first. - $ python3 -m pip install --user -U . - - -Tests ------ +Contributing +------------ -The basic way to run tests: +Help in testing, development, documentation and other tasks is +highly appreciated and useful to the project. There are tasks for +contributors of all experience levels. - $ pip3 install -r test-requirements.txt - $ python2 -m pip install -U typing - $ ./runtests.py +To get started with developing mypy, see [CONTRIBUTING.md](CONTRIBUTING.md). -For more on the tests, such as how to write tests and how to control -which tests to run, see [Test README.md](test-data/unit/README.md). +If you need help getting started, don't hesitate to ask on [gitter](https://gitter.im/python/typing). Development status @@ -223,58 +153,19 @@ Mypy is beta software, but it has already been used in production for several years at Dropbox and in many other organizations, and it has an extensive test suite. -See [the roadmap](ROADMAP.md) if you are interested in plans for the -future. - - -Changelog ---------- - -Follow mypy's updates on the blog: https://mypy-lang.blogspot.com/ - - -Issue tracker -------------- - -Please report any bugs and enhancement ideas using the mypy issue -tracker: https://github.com/python/mypy/issues - -If you have any questions about using mypy or types, please ask -in the typing gitter instead: https://gitter.im/python/typing - - -Compiled version of mypy ------------------------- +mypyc and compiled version of mypy +---------------------------------- -We have built a compiled version of mypy using the [mypyc -compiler](https://github.com/python/mypy/tree/master/mypyc) for -mypy-annotated Python code. It is approximately 4 times faster than -interpreted mypy and is available (and the default) for 64-bit -Windows, macOS, and Linux. +[Mypyc](https://github.com/mypyc/mypyc) uses Python type hints to compile Python +modules to faster C extensions. Mypy is itself compiled using mypyc: this makes +mypy approximately 4 times faster than if interpreted! To install an interpreted mypy instead, use: - $ python3 -m pip install --no-binary mypy -U mypy + python3 -m pip install --no-binary mypy -U mypy -If you wish to test out the compiled version of a development -version of mypy, you can directly install a binary from +To use a compiled version of a development +version of mypy, directly install a binary from https://github.com/mypyc/mypy_mypyc-wheels/releases/latest. - -Help wanted ------------ - -Any help in testing, development, documentation and other tasks is -highly appreciated and useful to the project. There are tasks for -contributors of all experience levels. If you're just getting started, -ask on the [gitter chat](https://gitter.im/python/typing) for ideas of good -beginner issues. - -For more details, see the file [CONTRIBUTING.md](CONTRIBUTING.md). - - -License -------- - -Mypy is licensed under the terms of the MIT License (see the file -LICENSE). +To contribute to the mypyc project, check out https://github.com/mypyc/mypyc diff --git a/ROADMAP.md b/ROADMAP.md deleted file mode 100644 index b881799be8f1..000000000000 --- a/ROADMAP.md +++ /dev/null @@ -1,38 +0,0 @@ -# Mypy Roadmap - -The goal of the roadmap is to document areas the mypy core team is -planning to work on in the future or is currently working on. PRs -targeting these areas are very welcome, but please check first with a -core team member that nobody else is working on the same thing. - -**Note:** This doesn’t include everything that the core team will work -on, and everything is subject to change. - -- Continue making error messages more useful and informative. - ([issues](https://github.com/python/mypy/labels/topic-usability)) - -- Refactor and simplify specific tricky parts of mypy internals, such - as the [conditional type binder](https://github.com/python/mypy/issues/3457) - and the [semantic analyzer](https://github.com/python/mypy/issues/6204). - -- Use the redesigned semantic analyzer to support general recursive types - ([issue](https://github.com/python/mypy/issues/731)). - -- Infer signature of a single function using static analysis and integrate this - functionality in mypy daemon. - -- Support user defined variadic generics (focus on the use cases needed for precise - typing of decorators, see [issue](https://github.com/python/mypy/issues/3157)). - -- Dedicated support for NumPy and Python numeric stack (including - integer generics/shape types, and a NumPy plugin, see - [issue](https://github.com/python/mypy/issues/3540)). - -- Gradual improvements to [mypyc compiler](https://github.com/mypyc/mypyc). - -- Invest some effort into systematically filling in missing - stubs in typeshed, with focus on libraries heavily used at Dropbox. - Help with [typeshed transformation](https://github.com/python/typeshed/issues/2491) - if needed. - -- Support selected IDE features and deeper editor integrations. diff --git a/action.yml b/action.yml new file mode 100644 index 000000000000..df8715327830 --- /dev/null +++ b/action.yml @@ -0,0 +1,83 @@ +name: "Mypy" +description: "Optional Static Typing for Python." +author: "Jukka Lehtosalo and contributors" +inputs: + options: + description: > + Options passed to mypy. Use `mypy --help` to see available options. + required: false + paths: + description: > + Explicit paths to run mypy on. Defaults to the current directory. + required: false + default: "." + version: + description: > + Mypy version to use (PEP440) - e.g. "0.910" + required: false + default: "" + install_types: + description: > + Whether to automatically install missing library stub packages. + ('yes'|'no', default: 'yes') + default: "yes" + install_project_dependencies: + description: > + Whether to attempt to install project dependencies into mypy + environment. ('yes'|'no', default: 'yes') + default: "yes" +branding: + color: "blue" + icon: "check-circle" +runs: + using: composite + steps: + - name: mypy setup + shell: bash + run: | + echo ::group::Installing mypy... + export PIP_DISABLE_PIP_VERSION_CHECK=1 + + if [ "$RUNNER_OS" == "Windows" ]; then + HOST_PYTHON=python + else + HOST_PYTHON=python3 + fi + + venv_script="import os.path; import venv; import sys; + path = os.path.join(r'${{ github.action_path }}', '.mypy-venv'); + venv.main([path]); + bin_subdir = 'Scripts' if sys.platform == 'win32' else 'bin'; + print(os.path.join(path, bin_subdir, 'python')); + " + + VENV_PYTHON=$(echo $venv_script | "$HOST_PYTHON") + mypy_spec="mypy" + + if [ -n "${{ inputs.version }}" ]; then + mypy_spec+="==${{ inputs.version }}" + fi + + if ! "$VENV_PYTHON" -m pip install "$mypy_spec"; then + echo "::error::Could not install mypy." + exit 1 + fi + echo ::endgroup:: + + if [ "${{ inputs.install_project_dependencies }}" == "yes" ]; then + VENV=$("$VENV_PYTHON" -c 'import sys;print(sys.prefix)') + echo ::group::Installing project dependencies... + "$VENV_PYTHON" -m pip download --dest="$VENV"/deps . + "$VENV_PYTHON" -m pip install -U --find-links="$VENV"/deps "$VENV"/deps/* + echo ::endgroup:: + fi + + echo ::group::Running mypy... + mypy_opts="" + if [ "${{ inputs.install_types }}" == "yes" ]; then + mypy_opts+="--install-types --non-interactive" + fi + + echo "mypy $mypy_opts ${{ inputs.options }} ${{ inputs.paths }}" + "$VENV_PYTHON" -m mypy $mypy_opts ${{ inputs.options }} ${{ inputs.paths }} + echo ::endgroup:: diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index d20641e7edf5..7e3d31ebea98 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,2 +1,2 @@ -Sphinx >= 1.4.4 -sphinx-rtd-theme >= 0.1.9 +sphinx>=4.2.0,<5.0.0 +sphinx-rtd-theme>=1.0.0,<2.0.0 diff --git a/docs/source/additional_features.rst b/docs/source/additional_features.rst index fc151598cff0..19e0d4dcce01 100644 --- a/docs/source/additional_features.rst +++ b/docs/source/additional_features.rst @@ -21,10 +21,10 @@ They can be defined using the :py:func:`@dataclasses.dataclass @dataclass class Application: name: str - plugins: List[str] = field(default_factory=list) + plugins: list[str] = field(default_factory=list) test = Application("Testing...") # OK - bad = Application("Testing...", "with plugin") # Error: List[str] expected + bad = Application("Testing...", "with plugin") # Error: list[str] expected Mypy will detect special methods (such as :py:meth:`__lt__ `) depending on the flags used to define dataclasses. For example: diff --git a/docs/source/cheat_sheet_py3.rst b/docs/source/cheat_sheet_py3.rst index 35c60f5a0610..734bc16ddea5 100644 --- a/docs/source/cheat_sheet_py3.rst +++ b/docs/source/cheat_sheet_py3.rst @@ -45,6 +45,7 @@ Built-in types .. code-block:: python + from typing import List, Set, Dict, Tuple, Optional # For simple built-in types, just use the name of the type @@ -60,7 +61,7 @@ Built-in types x: set[int] = {6, 7} # In Python 3.8 and earlier, the name of the collection type is - # capitalized, and the type is imported from 'typing' + # capitalized, and the type is imported from the 'typing' module x: List[int] = [1] x: Set[int] = {6, 7} @@ -68,8 +69,8 @@ Built-in types x = [1] # type: List[int] # For mappings, we need the types of both keys and values - x: dict[str, float] = {'field': 2.0} # Python 3.9+ - x: Dict[str, float] = {'field': 2.0} + x: dict[str, float] = {"field": 2.0} # Python 3.9+ + x: Dict[str, float] = {"field": 2.0} # For tuples of fixed size, we specify the types of all the elements x: tuple[int, str, float] = (3, "yes", 7.5) # Python 3.9+ @@ -95,7 +96,7 @@ Python 3 supports an annotation syntax for function declarations. .. code-block:: python - from typing import Callable, Iterator, Union, Optional, List + from typing import Callable, Iterator, Union, Optional # This is how you annotate a function definition def stringify(num: int) -> str: @@ -121,12 +122,12 @@ Python 3 supports an annotation syntax for function declarations. i += 1 # You can of course split a function annotation over multiple lines - def send_email(address: Union[str, List[str]], + def send_email(address: Union[str, list[str]], sender: str, - cc: Optional[List[str]], - bcc: Optional[List[str]], + cc: Optional[list[str]], + bcc: Optional[list[str]], subject='', - body: Optional[List[str]] = None + body: Optional[list[str]] = None ) -> bool: ... @@ -143,7 +144,7 @@ When you're puzzled or when things are complicated .. code-block:: python - from typing import Union, Any, List, Optional, cast + from typing import Union, Any, Optional, cast # To find out what type mypy infers for an expression anywhere in # your program, wrap it in reveal_type(). Mypy will print an error @@ -151,7 +152,7 @@ When you're puzzled or when things are complicated reveal_type(1) # -> Revealed type is "builtins.int" # Use Union when something could be one of a few types - x: List[Union[int, str]] = [3, 5, "test", "fun"] + x: list[Union[int, str]] = [3, 5, "test", "fun"] # Use Any if you don't know the type of something or it's too # dynamic to write a type for @@ -159,7 +160,7 @@ When you're puzzled or when things are complicated # If you initialize a variable with an empty container or "None" # you may have to help mypy a bit by providing a type annotation - x: List[str] = [] + x: list[str] = [] x: Optional[str] = None # This makes each positional arg and each keyword arg a "str" @@ -176,8 +177,8 @@ When you're puzzled or when things are complicated # "cast" is a helper function that lets you override the inferred # type of an expression. It's only for mypy -- there's no runtime check. a = [4] - b = cast(List[int], a) # Passes fine - c = cast(List[str], a) # Passes fine (no runtime check) + b = cast(list[int], a) # Passes fine + c = cast(list[str], a) # Passes fine (no runtime check) reveal_type(c) # -> Revealed type is "builtins.list[builtins.str]" print(c) # -> [4]; the object is not cast @@ -209,25 +210,25 @@ that are common in idiomatic Python are standardized. .. code-block:: python - from typing import Mapping, MutableMapping, Sequence, Iterable, List, Set + from typing import Mapping, MutableMapping, Sequence, Iterable # Use Iterable for generic iterables (anything usable in "for"), # and Sequence where a sequence (supporting "len" and "__getitem__") is # required - def f(ints: Iterable[int]) -> List[str]: + def f(ints: Iterable[int]) -> list[str]: return [str(x) for x in ints] f(range(1, 3)) # Mapping describes a dict-like object (with "__getitem__") that we won't # mutate, and MutableMapping one (with "__setitem__") that we might - def f(my_mapping: Mapping[int, str]) -> List[int]: + def f(my_mapping: Mapping[int, str]) -> list[int]: my_mapping[5] = 'maybe' # if we try this, mypy will throw an error... return list(my_mapping.keys()) f({3: 'yes', 4: 'no'}) - def f(my_mapping: MutableMapping[int, str]) -> Set[str]: + def f(my_mapping: MutableMapping[int, str]) -> set[str]: my_mapping[5] = 'maybe' # ...but mypy is OK with this. return set(my_mapping.values()) @@ -262,12 +263,12 @@ Classes # You can use the ClassVar annotation to declare a class variable class Car: seats: ClassVar[int] = 4 - passengers: ClassVar[List[str]] + passengers: ClassVar[list[str]] # You can also declare the type of an attribute in "__init__" class Box: def __init__(self) -> None: - self.items: List[str] = [] + self.items: list[str] = [] Coroutines and asyncio diff --git a/docs/source/class_basics.rst b/docs/source/class_basics.rst index 8e604427e683..3c12b4b06d9b 100644 --- a/docs/source/class_basics.rst +++ b/docs/source/class_basics.rst @@ -33,7 +33,7 @@ a type annotation: .. code-block:: python class A: - x: List[int] # Declare attribute 'x' of type List[int] + x: list[int] # Declare attribute 'x' of type list[int] a = A() a.x = [1] # OK @@ -48,7 +48,7 @@ than 3.6: .. code-block:: python class A: - x = None # type: List[int] # Declare attribute 'x' of type List[int] + x = None # type: list[int] # Declare attribute 'x' of type list[int] Note that attribute definitions in the class body that use a type comment are special: a ``None`` value is valid as the initializer, even though @@ -62,7 +62,7 @@ in a method: class A: def __init__(self) -> None: - self.x: List[int] = [] + self.x: list[int] = [] def f(self) -> None: self.y: Any = 0 @@ -160,7 +160,7 @@ This behavior will change in the future, since it's surprising. .. note:: A :py:data:`~typing.ClassVar` type parameter cannot include type variables: - ``ClassVar[T]`` and ``ClassVar[List[T]]`` + ``ClassVar[T]`` and ``ClassVar[list[T]]`` are both invalid if ``T`` is a type variable (see :ref:`generic-classes` for more about type variables). @@ -200,7 +200,7 @@ override has a compatible signature: You can also vary return types **covariantly** in overriding. For example, you could override the return type ``Iterable[int]`` with a - subtype such as ``List[int]``. Similarly, you can vary argument types + subtype such as ``list[int]``. Similarly, you can vary argument types **contravariantly** -- subclasses can have more general argument types. You can also override a statically typed method with a dynamically @@ -315,3 +315,35 @@ class, including an abstract method defined in an abstract base class. You can implement an abstract property using either a normal property or an instance variable. + +Slots +***** + +When a class has explicitly defined +`__slots__ `_, +mypy will check that all attributes assigned to are members of ``__slots__``: + +.. code-block:: python + + class Album: + __slots__ = ('name', 'year') + + def __init__(self, name: str, year: int) -> None: + self.name = name + self.year = year + # Error: Trying to assign name "released" that is not in "__slots__" of type "Album" + self.released = True + + my_album = Album('Songs about Python', 2021) + +Mypy will only check attribute assignments against ``__slots__`` when +the following conditions hold: + +1. All base classes (except builtin ones) must have explicit + ``__slots__`` defined (this mirrors Python semantics). + +2. ``__slots__`` does not include ``__dict__``. If ``__slots__`` + includes ``__dict__``, arbitrary attributes can be set, similar to + when ``__slots__`` is not defined (this mirrors Python semantics). + +3. All values in ``__slots__`` must be string literals. diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index 4b54e6a4dab0..a729ac2baca0 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -59,8 +59,8 @@ for full details, see :ref:`running-mypy`. pass ``--exclude '/setup\.py$'``. Similarly, you can ignore discovering directories with a given name by e.g. ``--exclude /build/`` or those matching a subpath with ``--exclude /project/vendor/``. To ignore - multiple files / directories / paths, you can combine expressions with - ``|``, e.g ``--exclude '/setup\.py$|/build/'``. + multiple files / directories / paths, you can provide the --exclude + flag more than once, e.g ``--exclude '/setup\.py$' --exclude '/build/'``. Note that this flag only affects recursive directory tree discovery, that is, when mypy is discovering files within a directory tree or submodules of @@ -312,9 +312,8 @@ The following options are available: .. option:: --disallow-any-generics This flag disallows usage of generic types that do not specify explicit - type parameters. Moreover, built-in collections (such as :py:class:`list` and - :py:class:`dict`) become disallowed as you should use their aliases from the :py:mod:`typing` - module (such as :py:class:`List[int] ` and :py:class:`Dict[str, str] `). + type parameters. For example, you can't use a bare ``x: list``. Instead, you + must always write something like ``x: list[int]``. .. option:: --disallow-subclassing-any @@ -419,7 +418,7 @@ For more details, see :ref:`no_strict_optional`. Configuring warnings ******************** -The follow flags enable warnings for code that is sound but is +The following flags enable warnings for code that is sound but is potentially problematic or redundant in some way. .. option:: --warn-redundant-casts @@ -521,10 +520,10 @@ of the above sections. .. code-block:: python - def process(items: List[str]) -> None: - # 'items' has type List[str] + def process(items: list[str]) -> None: + # 'items' has type list[str] items = [item.split() for item in items] - # 'items' now has type List[List[str]] + # 'items' now has type list[list[str]] ... .. option:: --local-partial-types @@ -585,9 +584,9 @@ of the above sections. .. code-block:: python - from typing import List, Text + from typing import Text - items: List[int] + items: list[int] if 'some string' in items: # Error: non-overlapping container check! ... diff --git a/docs/source/common_issues.rst b/docs/source/common_issues.rst index d3c1761bc994..c4adc9b563bd 100644 --- a/docs/source/common_issues.rst +++ b/docs/source/common_issues.rst @@ -26,102 +26,102 @@ No errors reported for obviously wrong code There are several common reasons why obviously wrong code is not flagged as an error. -- **The function containing the error is not annotated.** Functions that - do not have any annotations (neither for any argument nor for the - return type) are not type-checked, and even the most blatant type - errors (e.g. ``2 + 'a'``) pass silently. The solution is to add - annotations. Where that isn't possible, functions without annotations - can be checked using :option:`--check-untyped-defs `. +**The function containing the error is not annotated.** Functions that +do not have any annotations (neither for any argument nor for the +return type) are not type-checked, and even the most blatant type +errors (e.g. ``2 + 'a'``) pass silently. The solution is to add +annotations. Where that isn't possible, functions without annotations +can be checked using :option:`--check-untyped-defs `. - Example: +Example: - .. code-block:: python +.. code-block:: python - def foo(a): - return '(' + a.split() + ')' # No error! + def foo(a): + return '(' + a.split() + ')' # No error! - This gives no error even though ``a.split()`` is "obviously" a list - (the author probably meant ``a.strip()``). The error is reported - once you add annotations: +This gives no error even though ``a.split()`` is "obviously" a list +(the author probably meant ``a.strip()``). The error is reported +once you add annotations: - .. code-block:: python +.. code-block:: python - def foo(a: str) -> str: - return '(' + a.split() + ')' - # error: Unsupported operand types for + ("str" and List[str]) + def foo(a: str) -> str: + return '(' + a.split() + ')' + # error: Unsupported operand types for + ("str" and List[str]) - If you don't know what types to add, you can use ``Any``, but beware: +If you don't know what types to add, you can use ``Any``, but beware: -- **One of the values involved has type 'Any'.** Extending the above - example, if we were to leave out the annotation for ``a``, we'd get - no error: +**One of the values involved has type 'Any'.** Extending the above +example, if we were to leave out the annotation for ``a``, we'd get +no error: - .. code-block:: python +.. code-block:: python - def foo(a) -> str: - return '(' + a.split() + ')' # No error! + def foo(a) -> str: + return '(' + a.split() + ')' # No error! - The reason is that if the type of ``a`` is unknown, the type of - ``a.split()`` is also unknown, so it is inferred as having type - ``Any``, and it is no error to add a string to an ``Any``. +The reason is that if the type of ``a`` is unknown, the type of +``a.split()`` is also unknown, so it is inferred as having type +``Any``, and it is no error to add a string to an ``Any``. - If you're having trouble debugging such situations, - :ref:`reveal_type() ` might come in handy. +If you're having trouble debugging such situations, +:ref:`reveal_type() ` might come in handy. - Note that sometimes library stubs have imprecise type information, - e.g. the :py:func:`pow` builtin returns ``Any`` (see `typeshed issue 285 - `_ for the reason). +Note that sometimes library stubs have imprecise type information, +e.g. the :py:func:`pow` builtin returns ``Any`` (see `typeshed issue 285 +`_ for the reason). -- :py:meth:`__init__ ` **method has no annotated - arguments or return type annotation.** :py:meth:`__init__ ` - is considered fully-annotated **if at least one argument is annotated**, - while mypy will infer the return type as ``None``. - The implication is that, for a :py:meth:`__init__ ` method - that has no argument, you'll have to explicitly annotate the return type - as ``None`` to type-check this :py:meth:`__init__ ` method: +:py:meth:`__init__ ` **method has no annotated +arguments or return type annotation.** :py:meth:`__init__ ` +is considered fully-annotated **if at least one argument is annotated**, +while mypy will infer the return type as ``None``. +The implication is that, for a :py:meth:`__init__ ` method +that has no argument, you'll have to explicitly annotate the return type +as ``None`` to type-check this :py:meth:`__init__ ` method: - .. code-block:: python +.. code-block:: python - def foo(s: str) -> str: - return s - - class A(): - def __init__(self, value: str): # Return type inferred as None, considered as typed method - self.value = value - foo(1) # error: Argument 1 to "foo" has incompatible type "int"; expected "str" - - class B(): - def __init__(self): # No argument is annotated, considered as untyped method - foo(1) # No error! - - class C(): - def __init__(self) -> None: # Must specify return type to type-check - foo(1) # error: Argument 1 to "foo" has incompatible type "int"; expected "str" - -- **Some imports may be silently ignored**. Another source of - unexpected ``Any`` values are the :option:`--ignore-missing-imports - ` and :option:`--follow-imports=skip - ` flags. When you use :option:`--ignore-missing-imports `, - any imported module that cannot be found is silently replaced with - ``Any``. When using :option:`--follow-imports=skip ` the same is true for - modules for which a ``.py`` file is found but that are not specified - on the command line. (If a ``.pyi`` stub is found it is always - processed normally, regardless of the value of - :option:`--follow-imports `.) To help debug the former situation (no - module found at all) leave out :option:`--ignore-missing-imports `; to get - clarity about the latter use :option:`--follow-imports=error `. You can - read up about these and other useful flags in :ref:`command-line`. - -- **A function annotated as returning a non-optional type returns 'None' - and mypy doesn't complain**. + def foo(s: str) -> str: + return s - .. code-block:: python + class A(): + def __init__(self, value: str): # Return type inferred as None, considered as typed method + self.value = value + foo(1) # error: Argument 1 to "foo" has incompatible type "int"; expected "str" + + class B(): + def __init__(self): # No argument is annotated, considered as untyped method + foo(1) # No error! + + class C(): + def __init__(self) -> None: # Must specify return type to type-check + foo(1) # error: Argument 1 to "foo" has incompatible type "int"; expected "str" - def foo() -> str: - return None # No error! +**Some imports may be silently ignored**. Another source of +unexpected ``Any`` values are the :option:`--ignore-missing-imports +` and :option:`--follow-imports=skip +` flags. When you use :option:`--ignore-missing-imports `, +any imported module that cannot be found is silently replaced with +``Any``. When using :option:`--follow-imports=skip ` the same is true for +modules for which a ``.py`` file is found but that are not specified +on the command line. (If a ``.pyi`` stub is found it is always +processed normally, regardless of the value of +:option:`--follow-imports `.) To help debug the former situation (no +module found at all) leave out :option:`--ignore-missing-imports `; to get +clarity about the latter use :option:`--follow-imports=error `. You can +read up about these and other useful flags in :ref:`command-line`. - You may have disabled strict optional checking (see - :ref:`no_strict_optional` for more). +**A function annotated as returning a non-optional type returns 'None' +and mypy doesn't complain**. + +.. code-block:: python + + def foo() -> str: + return None # No error! + +You may have disabled strict optional checking (see +:ref:`no_strict_optional` for more). .. _silencing_checker: @@ -383,10 +383,10 @@ explicit type cast: if index < 0: raise ValueError('No str found') - found = a[index] # Has `object` type, despite the fact that we know it is `str` - return cast(str, found) # So, we need an explicit cast to make mypy happy + found = a[index] # Has type "object", despite the fact that we know it is "str" + return cast(str, found) # We need an explicit cast to make mypy happy -Alternatively, you can use ``assert`` statement together with some +Alternatively, you can use an ``assert`` statement together with some of the supported type inference techniques: .. code-block:: python @@ -396,9 +396,9 @@ of the supported type inference techniques: if index < 0: raise ValueError('No str found') - found = a[index] # Has `object` type, despite the fact that we know it is `str` - assert isinstance(found, str) # Now, `found` will be narrowed to `str` subtype - return found # No need for the explicit `cast()` anymore + found = a[index] # Has type "object", despite the fact that we know it is "str" + assert isinstance(found, str) # Now, "found" will be narrowed to "str" + return found # No need for the explicit "cast()" anymore .. note:: @@ -411,7 +411,7 @@ of the supported type inference techniques: .. note:: - You can read more about type narrowing techniques here. + You can read more about type narrowing techniques :ref:`here `. Type inference in Mypy is designed to work well in common cases, to be predictable and to let the type checker give useful error @@ -634,43 +634,62 @@ You can install the latest development version of mypy from source. Clone the Variables vs type aliases ------------------------- -Mypy has both type aliases and variables with types like ``Type[...]`` and it is important to know their difference. +Mypy has both *type aliases* and variables with types like ``Type[...]``. These are +subtly different, and it's important to understand how they differ to avoid pitfalls. -1. Variables with type ``Type[...]`` should be created by assignments with an explicit type annotations: +1. A variable with type ``Type[...]`` is defined using an assignment with an + explicit type annotation: -.. code-block:: python + .. code-block:: python - class A: ... - tp: Type[A] = A + class A: ... + tp: Type[A] = A -2. Aliases are created by assignments without an explicit type: +2. You can define a type alias using an assignment without an explicit type annotation + at the top level of a module: -.. code-block:: python + .. code-block:: python - class A: ... - Alias = A + class A: ... + Alias = A -3. The difference is that aliases are completely known statically and can be used in type context (annotations): + You can also use ``TypeAlias`` (:pep:`613`) to define an *explicit type alias*: -.. code-block:: python + .. code-block:: python + + from typing import TypeAlias # "from typing_extensions" in Python 3.9 and earlier + + class A: ... + Alias: TypeAlias = A + + You should always use ``TypeAlias`` to define a type alias in a class body or + inside a function. + +The main difference is that the target of an alias is precisely known statically, and this +means that they can be used in type annotations and other *type contexts*. Type aliases +can't be defined conditionally (unless using +:ref:`supported Python version and platform checks `): + + .. code-block:: python - class A: ... - class B: ... + class A: ... + class B: ... - if random() > 0.5: - Alias = A - else: - Alias = B # error: Cannot assign multiple types to name "Alias" without an explicit "Type[...]" annotation \ - # error: Incompatible types in assignment (expression has type "Type[B]", variable has type "Type[A]") + if random() > 0.5: + Alias = A + else: + # error: Cannot assign multiple types to name "Alias" without an + # explicit "Type[...]" annotation + Alias = B - tp: Type[object] # tp is a type variable - if random() > 0.5: - tp = A - else: - tp = B # This is OK + tp: Type[object] # "tp" is a variable with a type object value + if random() > 0.5: + tp = A + else: + tp = B # This is OK - def fun1(x: Alias) -> None: ... # This is OK - def fun2(x: tp) -> None: ... # error: Variable "__main__.tp" is not valid as a type + def fun1(x: Alias) -> None: ... # OK + def fun2(x: tp) -> None: ... # Error: "tp" is not valid as a type Incompatible overrides ---------------------- diff --git a/docs/source/config_file.rst b/docs/source/config_file.rst index 9998a15467c4..c34f23d9e169 100644 --- a/docs/source/config_file.rst +++ b/docs/source/config_file.rst @@ -197,12 +197,19 @@ section of the command line docs. .. confval:: exclude - :type: regular expression + :type: newline separated list of regular expressions - A regular expression that matches file names, directory names and paths + A newline list of regular expression that matches file names, directory names and paths which mypy should ignore while recursively discovering files to check. Use forward slashes on all platforms. + .. code-block:: ini + + [mypy] + exclude = + ^file1\.py$ + ^file2\.py$ + For more details, see :option:`--exclude `. This option may only be set in the global section (``[mypy]``). @@ -323,7 +330,7 @@ Platform configuration :type: string Specifies the Python version used to parse and check the target - program. The string should be in the format ``DIGIT.DIGIT`` -- + program. The string should be in the format ``MAJOR.MINOR`` -- for example ``2.7``. The default is the version of the Python interpreter used to run mypy. diff --git a/docs/source/error_code_list.rst b/docs/source/error_code_list.rst index 3afde02e3ee6..852913ce79bb 100644 --- a/docs/source/error_code_list.rst +++ b/docs/source/error_code_list.rst @@ -117,15 +117,15 @@ Example: .. code-block:: python - from typing import List, Optional + from typing import Optional - def first(x: List[int]) -> Optional[int]: + def first(x: list[int]) -> Optional[int]: return x[0] if x else 0 - t = (5, 4) - # Error: Argument 1 to "first" has incompatible type "Tuple[int, int]"; - # expected "List[int]" [arg-type] - print(first(t)) + t = (5, 4) + # Error: Argument 1 to "first" has incompatible type "tuple[int, int]"; + # expected "list[int]" [arg-type] + print(first(t)) Check calls to overloaded functions [call-overload] --------------------------------------------------- @@ -171,26 +171,24 @@ This example incorrectly uses the function ``log`` as a type: .. code-block:: python - from typing import List + def log(x: object) -> None: + print('log:', repr(x)) - def log(x: object) -> None: - print('log:', repr(x)) - - # Error: Function "t.log" is not valid as a type [valid-type] - def log_all(objs: List[object], f: log) -> None: - for x in objs: - f(x) + # Error: Function "t.log" is not valid as a type [valid-type] + def log_all(objs: list[object], f: log) -> None: + for x in objs: + f(x) You can use :py:data:`~typing.Callable` as the type for callable objects: .. code-block:: python - from typing import List, Callable + from typing import Callable - # OK - def log_all(objs: List[object], f: Callable[[object], None]) -> None: - for x in objs: - f(x) + # OK + def log_all(objs: list[object], f: Callable[[object], None]) -> None: + for x in objs: + f(x) Require annotation if variable type is unclear [var-annotated] -------------------------------------------------------------- @@ -206,23 +204,21 @@ Example with an error: .. code-block:: python - class Bundle: - def __init__(self) -> None: - # Error: Need type annotation for "items" - # (hint: "items: List[] = ...") [var-annotated] - self.items = [] + class Bundle: + def __init__(self) -> None: + # Error: Need type annotation for "items" + # (hint: "items: list[] = ...") [var-annotated] + self.items = [] - reveal_type(Bundle().items) # list[Any] + reveal_type(Bundle().items) # list[Any] To address this, we add an explicit annotation: .. code-block:: python - from typing import List - - class Bundle: - def __init__(self) -> None: - self.items: List[str] = [] # OK + class Bundle: + def __init__(self) -> None: + self.items: list[str] = [] # OK reveal_type(Bundle().items) # list[str] @@ -377,10 +373,10 @@ Example: a['x'] # OK - # Error: Invalid index type "int" for "Dict[str, int]"; expected type "str" [index] + # Error: Invalid index type "int" for "dict[str, int]"; expected type "str" [index] print(a[1]) - # Error: Invalid index type "bytes" for "Dict[str, int]"; expected type "str" [index] + # Error: Invalid index type "bytes" for "dict[str, int]"; expected type "str" [index] a[b'x'] = 4 Check list items [list-item] @@ -394,10 +390,8 @@ Example: .. code-block:: python - from typing import List - # Error: List item 0 has incompatible type "int"; expected "str" [list-item] - a: List[str] = [0] + a: list[str] = [0] Check dict items [dict-item] ---------------------------- @@ -410,10 +404,8 @@ Example: .. code-block:: python - from typing import Dict - # Error: Dict entry 0 has incompatible type "str": "str"; expected "str": "int" [dict-item] - d: Dict[str, int] = {'key': 'value'} + d: dict[str, int] = {'key': 'value'} Check TypedDict items [typeddict-item] -------------------------------------- @@ -545,7 +537,7 @@ Check instantiation of abstract classes [abstract] -------------------------------------------------- Mypy generates an error if you try to instantiate an abstract base -class (ABC). An abtract base class is a class with at least one +class (ABC). An abstract base class is a class with at least one abstract method or attribute. (See also :py:mod:`abc` module documentation) Sometimes a class is made accidentally abstract, often due to an diff --git a/docs/source/error_code_list2.rst b/docs/source/error_code_list2.rst index 429302a94277..1e035fcf7f69 100644 --- a/docs/source/error_code_list2.rst +++ b/docs/source/error_code_list2.rst @@ -19,10 +19,10 @@ Check that type arguments exist [type-arg] ------------------------------------------ If you use :option:`--disallow-any-generics `, mypy requires that each generic -type has values for each type argument. For example, the types ``List`` or -``dict`` would be rejected. You should instead use types like ``List[int]`` or -``Dict[str, int]``. Any omitted generic type arguments get implicit ``Any`` -values. The type ``List`` is equivalent to ``List[Any]``, and so on. +type has values for each type argument. For example, the types ``list`` or +``dict`` would be rejected. You should instead use types like ``list[int]`` or +``dict[str, int]``. Any omitted generic type arguments get implicit ``Any`` +values. The type ``list`` is equivalent to ``list[Any]``, and so on. Example: @@ -30,10 +30,8 @@ Example: # mypy: disallow-any-generics - from typing import List - - # Error: Missing type parameters for generic type "List" [type-arg] - def remove_dups(items: List) -> List: + # Error: Missing type parameters for generic type "list" [type-arg] + def remove_dups(items: list) -> list: ... Check that every function has an annotation [no-untyped-def] diff --git a/docs/source/error_codes.rst b/docs/source/error_codes.rst index 8a654571bc6b..5255a6984b7b 100644 --- a/docs/source/error_codes.rst +++ b/docs/source/error_codes.rst @@ -31,6 +31,8 @@ or config `show_error_codes = True` to display error codes. Error codes are show $ mypy --show-error-codes prog.py prog.py:1: error: "str" has no attribute "trim" [attr-defined] +.. _silence-error-codes: + Silencing errors based on error codes ------------------------------------- diff --git a/docs/source/extending_mypy.rst b/docs/source/extending_mypy.rst index 90e5f2f1fec1..5c59bef506cc 100644 --- a/docs/source/extending_mypy.rst +++ b/docs/source/extending_mypy.rst @@ -9,10 +9,10 @@ Integrating mypy into another Python application ************************************************ It is possible to integrate mypy into another Python 3 application by -importing ``mypy.api`` and calling the ``run`` function with a parameter of type ``List[str]``, containing +importing ``mypy.api`` and calling the ``run`` function with a parameter of type ``list[str]``, containing what normally would have been the command line arguments to mypy. -Function ``run`` returns a ``Tuple[str, str, int]``, namely +Function ``run`` returns a ``tuple[str, str, int]``, namely ``(, , )``, in which ```` is what mypy normally writes to :py:data:`sys.stdout`, ```` is what mypy normally writes to :py:data:`sys.stderr` and ``exit_status`` is the exit status mypy normally @@ -246,7 +246,7 @@ when the configuration for a module changes, we want to invalidate mypy's cache for that module so that it can be rechecked. This hook should be used to report to mypy any relevant configuration data, so that mypy knows to recheck the module if the configuration changes. -The hooks hould return data encodable as JSON. +The hooks should return data encodable as JSON. Notes about the semantic analyzer ********************************* diff --git a/docs/source/faq.rst b/docs/source/faq.rst index 43ba3d0d066e..2a79498dd792 100644 --- a/docs/source/faq.rst +++ b/docs/source/faq.rst @@ -201,7 +201,8 @@ the following aspects, among others: Does it run on PyPy? ********************* -No. MyPy relies on `typed-ast +Somewhat. With PyPy 3.8, mypy is at least able to type check itself. +With older versions of PyPy, mypy relies on `typed-ast `_, which uses several APIs that PyPy does not support (including some internal CPython APIs). diff --git a/docs/source/final_attrs.rst b/docs/source/final_attrs.rst index 8c42ae9ec56b..e5d209644fce 100644 --- a/docs/source/final_attrs.rst +++ b/docs/source/final_attrs.rst @@ -119,9 +119,9 @@ annotations. Using it in any other position is an error. In particular, .. code-block:: python - x: List[Final[int]] = [] # Error! + x: list[Final[int]] = [] # Error! - def fun(x: Final[List[int]]) -> None: # Error! + def fun(x: Final[list[int]]) -> None: # Error! ... ``Final`` and :py:data:`~typing.ClassVar` should not be used together. Mypy will infer diff --git a/docs/source/generics.rst b/docs/source/generics.rst index f09e0572ee35..7e64aa181403 100644 --- a/docs/source/generics.rst +++ b/docs/source/generics.rst @@ -2,7 +2,7 @@ Generics ======== This section explains how you can define your own generic classes that take -one or more type parameters, similar to built-in types such as ``List[X]``. +one or more type parameters, similar to built-in types such as ``list[X]``. User-defined generics are a moderately advanced feature and you can get far without ever using them -- feel free to skip this section and come back later. @@ -13,8 +13,8 @@ Defining generic classes The built-in collection classes are generic classes. Generic types have one or more type parameters, which can be arbitrary types. For -example, ``Dict[int, str]`` has the type parameters ``int`` and -``str``, and ``List[int]`` has a type parameter ``int``. +example, ``dict[int, str]`` has the type parameters ``int`` and +``str``, and ``list[int]`` has a type parameter ``int``. Programs can also define new generic classes. Here is a very simple generic class that represents a stack: @@ -28,7 +28,7 @@ generic class that represents a stack: class Stack(Generic[T]): def __init__(self) -> None: # Create an empty list with items of type T - self.items: List[T] = [] + self.items: list[T] = [] def push(self, item: T) -> None: self.items.append(item) @@ -40,7 +40,7 @@ generic class that represents a stack: return not self.items The ``Stack`` class can be used to represent a stack of any type: -``Stack[int]``, ``Stack[Tuple[int, str]]``, etc. +``Stack[int]``, ``Stack[tuple[int, str]]``, etc. Using ``Stack`` is similar to built-in container types: @@ -77,8 +77,8 @@ Generic class internals *********************** You may wonder what happens at runtime when you index -``Stack``. Actually, indexing ``Stack`` returns essentially a copy -of ``Stack`` that returns instances of the original class on +``Stack``. Indexing ``Stack`` returns a *generic alias* +to ``Stack`` that returns instances of the original class on instantiation: .. code-block:: python @@ -90,25 +90,46 @@ instantiation: >>> print(Stack[int]().__class__) __main__.Stack -Note that built-in types :py:class:`list`, :py:class:`dict` and so on do not support -indexing in Python. This is why we have the aliases :py:class:`~typing.List`, :py:class:`~typing.Dict` -and so on in the :py:mod:`typing` module. Indexing these aliases gives -you a class that directly inherits from the target class in Python: +Generic aliases can be instantiated or subclassed, similar to real +classes, but the above examples illustrate that type variables are +erased at runtime. Generic ``Stack`` instances are just ordinary +Python objects, and they have no extra runtime overhead or magic due +to being generic, other than a metaclass that overloads the indexing +operator. + +Note that in Python 3.8 and lower, the built-in types +:py:class:`list`, :py:class:`dict` and others do not support indexing. +This is why we have the aliases :py:class:`~typing.List`, +:py:class:`~typing.Dict` and so on in the :py:mod:`typing` +module. Indexing these aliases gives you a generic alias that +resembles generic aliases constructed by directly indexing the target +class in more recent versions of Python: .. code-block:: python + >>> # Only relevant for Python 3.8 and below + >>> # For Python 3.9 onwards, prefer `list[int]` syntax >>> from typing import List >>> List[int] typing.List[int] - >>> List[int].__bases__ - (, typing.MutableSequence) -Generic types could be instantiated or subclassed as usual classes, -but the above examples illustrate that type variables are erased at -runtime. Generic ``Stack`` instances are just ordinary -Python objects, and they have no extra runtime overhead or magic due -to being generic, other than a metaclass that overloads the indexing -operator. +Note that the generic aliases in ``typing`` don't support constructing +instances: + +.. code-block:: python + + >>> from typing import List + >>> List[int]() + Traceback (most recent call last): + ... + TypeError: Type List cannot be instantiated; use list() instead + +.. note:: + + In Python 3.6 indexing generic types or type aliases results in actual + type objects. This means that generic types in type annotations can + have a significant runtime cost. This was changed in Python 3.7, and + indexing generic types became a cheap operation. .. _generic-subclasses: @@ -121,7 +142,7 @@ non-generic. For example: .. code-block:: python - from typing import Generic, TypeVar, Mapping, Iterator, Dict + from typing import Generic, TypeVar, Mapping, Iterator KT = TypeVar('KT') VT = TypeVar('VT') @@ -136,7 +157,7 @@ non-generic. For example: items: MyMap[str, int] # Okay - class StrDict(Dict[str, str]): # This is a non-generic subclass of Dict + class StrDict(dict[str, str]): # This is a non-generic subclass of dict def __str__(self) -> str: return 'StrDict({})'.format(super().__str__()) @@ -284,7 +305,7 @@ For class methods, you can also define generic ``cls``, using :py:class:`Type[T] .. code-block:: python - from typing import TypeVar, Tuple, Type + from typing import TypeVar, Type T = TypeVar('T', bound='Friend') @@ -292,7 +313,7 @@ For class methods, you can also define generic ``cls``, using :py:class:`Type[T] other = None # type: Friend @classmethod - def make_pair(cls: Type[T]) -> Tuple[T, T]: + def make_pair(cls: Type[T]) -> tuple[T, T]: a, b = cls(), cls() a.other = b b.other = a @@ -345,8 +366,8 @@ Let us illustrate this by few simple examples: .. code-block:: python - def salaries(staff: List[Manager], - accountant: Callable[[Manager], int]) -> List[int]: ... + def salaries(staff: list[Manager], + accountant: Callable[[Manager], int]) -> list[int]: ... This function needs a callable that can calculate a salary for managers, and if we give it a callable that can calculate a salary for an arbitrary @@ -363,10 +384,10 @@ Let us illustrate this by few simple examples: def rotate(self): ... - def add_one(things: List[Shape]) -> None: + def add_one(things: list[Shape]) -> None: things.append(Shape()) - my_things: List[Circle] = [] + my_things: list[Circle] = [] add_one(my_things) # This may appear safe, but... my_things[0].rotate() # ...this will fail @@ -532,7 +553,7 @@ Here's a complete example of a function decorator: .. code-block:: python - from typing import Any, Callable, TypeVar, Tuple, cast + from typing import Any, Callable, TypeVar, cast F = TypeVar('F', bound=Callable[..., Any]) @@ -724,11 +745,11 @@ variables replaced with ``Any``. Examples (following :pep:`PEP 484: Type aliases .. code-block:: python - from typing import TypeVar, Iterable, Tuple, Union, Callable + from typing import TypeVar, Iterable, Union, Callable S = TypeVar('S') - TInt = Tuple[int, S] + TInt = tuple[int, S] UInt = Union[S, int] CBack = Callable[..., S] @@ -736,11 +757,11 @@ variables replaced with ``Any``. Examples (following :pep:`PEP 484: Type aliases ... def activate(cb: CBack[S]) -> S: # Same as Callable[..., S] ... - table_entry: TInt # Same as Tuple[int, Any] + table_entry: TInt # Same as tuple[int, Any] T = TypeVar('T', int, float, complex) - Vec = Iterable[Tuple[T, T]] + Vec = Iterable[tuple[T, T]] def inproduct(v: Vec[T]) -> T: return sum(x*y for x, y in v) @@ -748,8 +769,8 @@ variables replaced with ``Any``. Examples (following :pep:`PEP 484: Type aliases def dilate(v: Vec[T], scale: T) -> Vec[T]: return ((x * scale, y * scale) for x, y in v) - v1: Vec[int] = [] # Same as Iterable[Tuple[int, int]] - v2: Vec = [] # Same as Iterable[Tuple[Any, Any]] + v1: Vec[int] = [] # Same as Iterable[tuple[int, int]] + v2: Vec = [] # Same as Iterable[tuple[Any, Any]] v3: Vec[int, int] = [] # Error: Invalid alias, too many type arguments! Type aliases can be imported from modules just like other names. An diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 12dfba2add93..f9b21d8dbf60 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -153,8 +153,8 @@ Arguments with default values can be annotated like so: .. code-block:: python def stars(*args: int, **kwargs: float) -> None: - # 'args' has type 'Tuple[int, ...]' (a tuple of ints) - # 'kwargs' has type 'Dict[str, float]' (a dict of strs to floats) + # 'args' has type 'tuple[int, ...]' (a tuple of ints) + # 'kwargs' has type 'dict[str, float]' (a dict of strs to floats) for arg in args: print(arg) for key, value in kwargs: @@ -182,8 +182,8 @@ strings, use the ``list[str]`` type (Python 3.9 and later): greet_all(names) # Ok! greet_all(ages) # Error due to incompatible types -The ``list`` type is an example of something called a *generic type*: it can -accept one or more *type parameters*. In this case, we *parameterized* ``list`` +The :py:class:`list` type is an example of something called a *generic type*: it can +accept one or more *type parameters*. In this case, we *parameterized* :py:class:`list` by writing ``list[str]``. This lets mypy know that ``greet_all`` accepts specifically lists containing strings, and not lists containing ints or any other type. @@ -207,9 +207,8 @@ After all, there's no reason why this function must accept *specifically* a list it would run just fine if you were to pass in a tuple, a set, or any other custom iterable. You can express this idea using the -:py:class:`collections.abc.Iterable` type instead of -:py:class:`~typing.List` (or :py:class:`typing.Iterable` in Python -3.8 and earlier): +:py:class:`collections.abc.Iterable` (or :py:class:`typing.Iterable` in Python +3.8 and earlier) type instead of :py:class:`list` : .. code-block:: python @@ -268,7 +267,7 @@ generic types or your own type aliases) by looking through the In some examples we use capitalized variants of types, such as ``List``, and sometimes we use plain ``list``. They are equivalent, - but the prior variant is needed if you are not using a recent Python. + but the prior variant is needed if you are using Python 3.8 or earlier. Local type inference ******************** @@ -286,7 +285,7 @@ in that if statement. As another example, consider the following function. Mypy can type check this function without a problem: it will use the available context and deduce that ``output`` must be -of type ``List[float]`` and that ``num`` must be of type ``float``: +of type ``list[float]`` and that ``num`` must be of type ``float``: .. code-block:: python diff --git a/docs/source/index.rst b/docs/source/index.rst index 8aae6e0a8ac7..9cd9220c60b9 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -60,6 +60,7 @@ Mypy is a static type checker for Python 3 and Python 2.7. installed_packages extending_mypy stubgen + stubtest .. toctree:: :maxdepth: 2 diff --git a/docs/source/installed_packages.rst b/docs/source/installed_packages.rst index 036185c818e5..8db113e4ba9e 100644 --- a/docs/source/installed_packages.rst +++ b/docs/source/installed_packages.rst @@ -178,9 +178,10 @@ the Python 2 stubs in a directory with the suffix ``-python2-stubs``. We recommend that Python 2 and Python 3 stubs are bundled together for simplicity, instead of distributing them separately. -The instructions are enough to ensure that built wheels contains the appropriate -files. However, to ensure inclusion inside the ``sdist`` (``.tar.gz`` archive), -you may also need to modify the inclusion rules in your ``MANIFEST.in``: +The instructions above are enough to ensure that the built wheels +contain the appropriate files. However, to ensure inclusion inside the +``sdist`` (``.tar.gz`` archive), you may also need to modify the +inclusion rules in your ``MANIFEST.in``: .. code-block:: text diff --git a/docs/source/kinds_of_types.rst b/docs/source/kinds_of_types.rst index 1efc2b30c328..866535949d74 100644 --- a/docs/source/kinds_of_types.rst +++ b/docs/source/kinds_of_types.rst @@ -108,23 +108,24 @@ The ``Any`` type is discussed in more detail in section :ref:`dynamic-typing`. Tuple types *********** -The type ``Tuple[T1, ..., Tn]`` represents a tuple with the item types ``T1``, ..., ``Tn``: +The type ``tuple[T1, ..., Tn]`` represents a tuple with the item types ``T1``, ..., ``Tn``: .. code-block:: python - def f(t: Tuple[int, str]) -> None: + # Use `typing.Tuple` in Python 3.8 and earlier + def f(t: tuple[int, str]) -> None: t = 1, 'foo' # OK t = 'foo', 1 # Type check error A tuple type of this kind has exactly a specific number of items (2 in the above example). Tuples can also be used as immutable, -varying-length sequences. You can use the type ``Tuple[T, ...]`` (with +varying-length sequences. You can use the type ``tuple[T, ...]`` (with a literal ``...`` -- it's part of the syntax) for this purpose. Example: .. code-block:: python - def print_squared(t: Tuple[int, ...]) -> None: + def print_squared(t: tuple[int, ...]) -> None: for n in t: print(n, n ** 2) @@ -134,12 +135,12 @@ purpose. Example: .. note:: - Usually it's a better idea to use ``Sequence[T]`` instead of ``Tuple[T, ...]``, as + Usually it's a better idea to use ``Sequence[T]`` instead of ``tuple[T, ...]``, as :py:class:`~typing.Sequence` is also compatible with lists and other non-tuple sequences. .. note:: - ``Tuple[...]`` is valid as a base class in Python 3.6 and later, and + ``tuple[...]`` is valid as a base class in Python 3.6 and later, and always in stub files. In earlier Python versions you can sometimes work around this limitation by using a named tuple as a base class (see section :ref:`named-tuples`). @@ -194,7 +195,7 @@ using bidirectional type inference: .. code-block:: python - l = map(lambda x: x + 1, [1, 2, 3]) # Infer x as int and l as List[int] + l = map(lambda x: x + 1, [1, 2, 3]) # Infer x as int and l as list[int] If you want to give the argument or return value types explicitly, use an ordinary, perhaps nested function definition. @@ -353,20 +354,16 @@ and ``None`` is used as a dummy, placeholder initializer: .. code-block:: python - from typing import List - class Container: - items = None # type: List[str] # OK (only with type comment) + items = None # type: list[str] # OK (only with type comment) This is not a problem when using variable annotations, since no initializer is needed: .. code-block:: python - from typing import List - class Container: - items: List[str] # No initializer + items: list[str] # No initializer Mypy generally uses the first assignment to a variable to infer the type of the variable. However, if you assign both a ``None`` @@ -419,8 +416,6 @@ the runtime with some limitations (see :ref:`runtime_troubles`). .. code-block:: python - from typing import List - t1: int | str # equivalent to Union[int, str] t2: int | None # equivalent to Optional[int] @@ -505,7 +500,7 @@ In certain situations, type names may end up being long and painful to type: .. code-block:: python - def f() -> Union[List[Dict[Tuple[int, str], Set[int]]], Tuple[str, List[str]]]: + def f() -> Union[list[dict[tuple[int, str], set[int]]], tuple[str, list[str]]]: ... When cases like this arise, you can define a type alias by simply @@ -513,7 +508,7 @@ assigning the type to a variable: .. code-block:: python - AliasType = Union[List[Dict[Tuple[int, str], Set[int]]], Tuple[str, List[str]]] + AliasType = Union[list[dict[tuple[int, str], set[int]]], tuple[str, list[str]]] # Now we can use AliasType in place of the full name: @@ -526,6 +521,25 @@ assigning the type to a variable: another type -- it's equivalent to the target type except for :ref:`generic aliases `. +Since Mypy 0.930 you can also use *explicit type aliases*, which were +introduced in :pep:`613`. + +There can be confusion about exactly when an assignment defines an implicit type alias -- +for example, when the alias contains forward references, invalid types, or violates some other +restrictions on type alias declarations. Because the +distinction between an unannotated variable and a type alias is implicit, +ambiguous or incorrect type alias declarations default to defining +a normal variable instead of a type alias. + +Explicit type aliases are unambiguous and can also improve readability by +making the intent clear: + +.. code-block:: python + + from typing import TypeAlias # "from typing_extensions" in Python 3.9 and earlier + + AliasType: TypeAlias = Union[list[dict[tuple[int, str], set[int]]], tuple[str, list[str]]] + .. _named-tuples: Named tuples @@ -566,6 +580,31 @@ Python 3.6 introduced an alternative, class-based syntax for named tuples with t p = Point(x=1, y='x') # Argument has incompatible type "str"; expected "int" +.. note:: + + You can use the raw ``NamedTuple`` "pseudo-class" in type annotations + if any ``NamedTuple`` object is valid. + + For example, it can be useful for deserialization: + + .. code-block:: python + + def deserialize_named_tuple(arg: NamedTuple) -> Dict[str, Any]: + return arg._asdict() + + Point = namedtuple('Point', ['x', 'y']) + Person = NamedTuple('Person', [('name', str), ('age', int)]) + + deserialize_named_tuple(Point(x=1, y=2)) # ok + deserialize_named_tuple(Person(name='Nikita', age=18)) # ok + + # Error: Argument 1 to "deserialize_named_tuple" has incompatible type + # "Tuple[int, int]"; expected "NamedTuple" + deserialize_named_tuple((1, 2)) + + Note that this behavior is highly experimental, non-standard, + and may not be supported by other type checkers and IDEs. + .. _type-of-class: The type of class objects @@ -702,7 +741,7 @@ For more details, see :ref:`type-variable-value-restriction`. Generators ********** -A basic generator that only yields values can be annotated as having a return +A basic generator that only yields values can be succinctly annotated as having a return type of either :py:class:`Iterator[YieldType] ` or :py:class:`Iterable[YieldType] `. For example: .. code-block:: python @@ -711,9 +750,20 @@ type of either :py:class:`Iterator[YieldType] ` or :py:class:`I for i in range(n): yield i * i +A good rule of thumb is to annotate functions with the most specific return +type possible. However, you should also take care to avoid leaking implementation +details into a function's public API. In keeping with these two principles, prefer +:py:class:`Iterator[YieldType] ` over +:py:class:`Iterable[YieldType] ` as the return-type annotation for a +generator function, as it lets mypy know that users are able to call :py:func:`next` on +the object returned by the function. Nonetheless, bear in mind that ``Iterable`` may +sometimes be the better option, if you consider it an implementation detail that +``next()`` can be called on the object returned by your function. + If you want your generator to accept values via the :py:meth:`~generator.send` method or return -a value, you should use the -:py:class:`Generator[YieldType, SendType, ReturnType] ` generic type instead. For example: +a value, on the other hand, you should use the +:py:class:`Generator[YieldType, SendType, ReturnType] ` generic type instead of +either ``Iterator`` or ``Iterable``. For example: .. code-block:: python @@ -736,7 +786,7 @@ annotated the first example as the following: for i in range(n): yield i * i -This is slightly different from using ``Iterable[int]`` or ``Iterator[int]``, +This is slightly different from using ``Iterator[int]`` or ``Iterable[int]``, since generators have :py:meth:`~generator.close`, :py:meth:`~generator.send`, and :py:meth:`~generator.throw` methods that -generic iterables don't. If you will call these methods on the returned -generator, use the :py:class:`~typing.Generator` type instead of :py:class:`~typing.Iterable` or :py:class:`~typing.Iterator`. +generic iterators and iterables don't. If you plan to call these methods on the returned +generator, use the :py:class:`~typing.Generator` type instead of :py:class:`~typing.Iterator` or :py:class:`~typing.Iterable`. diff --git a/docs/source/literal_types.rst b/docs/source/literal_types.rst index 216313b6c20e..b1669d01062a 100644 --- a/docs/source/literal_types.rst +++ b/docs/source/literal_types.rst @@ -142,7 +142,7 @@ as adding an explicit ``Literal[...]`` annotation, it often leads to the same ef in practice. The main cases where the behavior of context-sensitive vs true literal types differ are -when you try using those types in places that are not explicitly expecting a ``Literal[...]``. +when you try using those types in places that are not explicitly expecting a ``Literal[...]``. For example, compare and contrast what happens when you try appending these types to a list: .. code-block:: python @@ -152,16 +152,16 @@ For example, compare and contrast what happens when you try appending these type a: Final = 19 b: Literal[19] = 19 - # Mypy will chose to infer List[int] here. + # Mypy will choose to infer list[int] here. list_of_ints = [] list_of_ints.append(a) - reveal_type(list_of_ints) # Revealed type is "List[int]" + reveal_type(list_of_ints) # Revealed type is "list[int]" # But if the variable you're appending is an explicit Literal, mypy - # will infer List[Literal[19]]. + # will infer list[Literal[19]]. list_of_lits = [] list_of_lits.append(b) - reveal_type(list_of_lits) # Revealed type is "List[Literal[19]]" + reveal_type(list_of_lits) # Revealed type is "list[Literal[19]]" Intelligent indexing @@ -208,7 +208,7 @@ corresponding to some particular index, we can use Literal types like so: # You can also index using unions of literals id_key: Literal["main_id", "backup_id"] - reveal_type(d[id_key]) # Revealed type is "int" + reveal_type(d[id_key]) # Revealed type is "int" .. _tagged_unions: @@ -248,7 +248,7 @@ type. Then, you can discriminate between each kind of TypedDict by checking the # Literal["new-job", "cancel-job"], but the check below will narrow # the type to either Literal["new-job"] or Literal["cancel-job"]. # - # This in turns narrows the type of 'event' to either NewJobEvent + # This in turns narrows the type of 'event' to either NewJobEvent # or CancelJobEvent. if event["tag"] == "new-job": print(event["job_name"]) @@ -289,11 +289,11 @@ using ``isinstance()``: This feature is sometimes called "sum types" or "discriminated union types" in other programming languages. -Exhaustive checks -***************** +Exhaustiveness checks +********************* -One may want to check that some code covers all possible ``Literal`` or ``Enum`` cases, -example: +You may want to check that some code covers all possible +``Literal`` or ``Enum`` cases. Example: .. code-block:: python @@ -306,21 +306,22 @@ example: return True elif x == 'two': return False - raise ValueError('Wrong values passed: {0}'.format(x)) + raise ValueError(f'Invalid value: {x}') assert validate('one') is True assert validate('two') is False -In the code above it is really easy to make a mistake in the future: -by adding a new literal value to ``PossibleValues``, -but not adding its handler to ``validate`` function: +In the code above, it's easy to make a mistake. You can +add a new literal value to ``PossibleValues`` but forget +to handle it in the ``validate`` function: .. code-block:: python PossibleValues = Literal['one', 'two', 'three'] -Mypy won't catch that ``'three'`` is not covered. -However, if you want to have exhaustive check, you need to guard it properly: +Mypy won't catch that ``'three'`` is not covered. If you want mypy to +perform an exhaustiveness check, you need to update your code to use an +``assert_never()`` check: .. code-block:: python @@ -329,8 +330,8 @@ However, if you want to have exhaustive check, you need to guard it properly: PossibleValues = Literal['one', 'two'] def assert_never(value: NoReturn) -> NoReturn: - # This also works in runtime as well: - assert False, 'This code should never be reached, got: {0}'.format(value) + # This also works at runtime as well + assert False, f'This code should never be reached, got: {value}' def validate(x: PossibleValues) -> bool: if x == 'one': @@ -339,22 +340,21 @@ However, if you want to have exhaustive check, you need to guard it properly: return False assert_never(x) -In this case, when adding new values to ``PossibleValues``: +Now if you add a new value to ``PossibleValues`` but don't update ``validate``, +mypy will spot the error: .. code-block:: python PossibleValues = Literal['one', 'two', 'three'] -Mypy will cover you: - -.. code-block:: python - def validate(x: PossibleValues) -> bool: if x == 'one': return True elif x == 'two': return False - assert_never(x) # E: Argument 1 to "assert_never" has incompatible type "Literal['three']"; expected "NoReturn" + # Error: Argument 1 to "assert_never" has incompatible type "Literal['three']"; + # expected "NoReturn" + assert_never(x) Limitations *********** diff --git a/docs/source/more_types.rst b/docs/source/more_types.rst index a240ac338988..82a6568afcb2 100644 --- a/docs/source/more_types.rst +++ b/docs/source/more_types.rst @@ -84,7 +84,7 @@ certain values from base class instances. Example: ... However, this approach introduces some runtime overhead. To avoid this, the typing -module provides a helper function :py:func:`NewType ` that creates simple unique types with +module provides a helper object :py:func:`NewType ` that creates simple unique types with almost zero runtime overhead. Mypy will treat the statement ``Derived = NewType('Derived', Base)`` as being roughly equivalent to the following definition: @@ -95,7 +95,7 @@ definition: def __init__(self, _x: Base) -> None: ... -However, at runtime, ``NewType('Derived', Base)`` will return a dummy function that +However, at runtime, ``NewType('Derived', Base)`` will return a dummy callable that simply returns its argument: .. code-block:: python @@ -127,7 +127,7 @@ containing the name of the new type and must equal the name of the variable to w type is assigned. The second argument must be a properly subclassable class, i.e., not a type construct like :py:data:`~typing.Union`, etc. -The function returned by :py:func:`NewType ` accepts only one argument; this is equivalent to +The callable returned by :py:func:`NewType ` accepts only one argument; this is equivalent to supporting only one constructor accepting an instance of the base class (see above). Example: @@ -148,8 +148,7 @@ Example: tcp_packet = TcpPacketId(127, 0) # Fails in type checker and at runtime You cannot use :py:func:`isinstance` or :py:func:`issubclass` on the object returned by -:py:func:`~typing.NewType`, because function objects don't support these operations. You cannot -create subclasses of these objects either. +:py:func:`~typing.NewType`, nor can you subclass an object returned by :py:func:`~typing.NewType`. .. note:: @@ -295,10 +294,10 @@ return type by using overloads like so: subtypes, you can use a :ref:`value restriction `. -The default values of a function's arguments don't affect its signature, only +The default values of a function's arguments don't affect its signature -- only the absence or presence of a default value does. So in order to reduce -redundancy it's possible to replace default values in overload definitions with -`...` as a placeholder. +redundancy, it's possible to replace default values in overload definitions with +``...`` as a placeholder: .. code-block:: python @@ -355,13 +354,15 @@ program: .. code-block:: python - from typing import List, overload + # For Python 3.8 and below you must use `typing.List` instead of `list`. e.g. + # from typing import List + from typing import overload @overload - def summarize(data: List[int]) -> float: ... + def summarize(data: list[int]) -> float: ... @overload - def summarize(data: List[str]) -> str: ... + def summarize(data: list[str]) -> str: ... def summarize(data): if not data: @@ -375,7 +376,7 @@ program: output = summarize([]) The ``summarize([])`` call matches both variants: an empty list could -be either a ``List[int]`` or a ``List[str]``. In this case, mypy +be either a ``list[int]`` or a ``list[str]``. In this case, mypy will break the tie by picking the first matching variant: ``output`` will have an inferred type of ``float``. The implementor is responsible for making sure ``summarize`` breaks ties in the same way at runtime. @@ -397,7 +398,7 @@ matching variant returns: .. code-block:: python - some_list: Union[List[int], List[str]] + some_list: Union[list[int], list[str]] # output3 is of type 'Union[float, str]' output3 = summarize(some_list) @@ -524,7 +525,7 @@ suppose we modify the above snippet so it calls ``summarize`` instead of .. code-block:: python - some_list: List[str] = [] + some_list: list[str] = [] summarize(some_list) + "danger danger" # Type safe, yet crashes at runtime! We run into a similar issue here. This program type checks if we look just at the @@ -571,7 +572,7 @@ with ``Union[int, slice]`` and ``Union[T, Sequence]``. Previously, mypy used to perform type erasure on all overload variants. For example, the ``summarize`` example from the previous section used to be - illegal because ``List[str]`` and ``List[int]`` both erased to just ``List[Any]``. + illegal because ``list[str]`` and ``list[int]`` both erased to just ``list[Any]``. This restriction was removed in mypy 0.620. Mypy also previously used to select the best matching variant using a different @@ -623,7 +624,7 @@ argument is itself generic: def first_chunk(self: Storage[Sequence[S]]) -> S: return self.content[0] - page: Storage[List[str]] + page: Storage[list[str]] page.first_chunk() # OK, type is "str" Storage(0).first_chunk() # Error: Invalid self argument "Storage[int]" to attribute function @@ -708,13 +709,13 @@ classes are generic, self-type allows giving them precise signatures: self.item = item @classmethod - def make_pair(cls: Type[Q], item: T) -> Tuple[Q, Q]: + def make_pair(cls: Type[Q], item: T) -> tuple[Q, Q]: return cls(item), cls(item) class Sub(Base[T]): ... - pair = Sub.make_pair('yes') # Type is "Tuple[Sub[str], Sub[str]]" + pair = Sub.make_pair('yes') # Type is "tuple[Sub[str], Sub[str]]" bad = Sub[int].make_pair('no') # Error: Argument 1 to "make_pair" of "Base" # has incompatible type "str"; expected "int" @@ -906,7 +907,7 @@ Here is a typical example: Only a fixed set of string keys is expected (``'name'`` and ``'year'`` above), and each key has an independent value type (``str`` for ``'name'`` and ``int`` for ``'year'`` above). We've previously -seen the ``Dict[K, V]`` type, which lets you declare uniform +seen the ``dict[K, V]`` type, which lets you declare uniform dictionary types, where every value has the same type, and arbitrary keys are supported. This is clearly not a good fit for ``movie`` above. Instead, you can use a ``TypedDict`` to give a precise @@ -925,7 +926,7 @@ dictionary value depends on the key: and ``'year'`` (with type ``int``). Note that we used an explicit type annotation for the ``movie`` variable. This type annotation is important -- without it, mypy will try to infer a regular, uniform -:py:class:`~typing.Dict` type for ``movie``, which is not what we want here. +:py:class:`dict` type for ``movie``, which is not what we want here. .. note:: @@ -934,7 +935,7 @@ important -- without it, mypy will try to infer a regular, uniform desired type based on the declared argument type. Also, if an assignment target has been previously defined, and it has a ``TypedDict`` type, mypy will treat the assigned value as a ``TypedDict``, - not :py:class:`~typing.Dict`. + not :py:class:`dict`. Now mypy will recognize these as valid: @@ -975,8 +976,8 @@ extra items is compatible with (a subtype of) a narrower ``TypedDict``, assuming item types are compatible (*totality* also affects subtyping, as discussed below). -A ``TypedDict`` object is not a subtype of the regular ``Dict[...]`` -type (and vice versa), since :py:class:`~typing.Dict` allows arbitrary keys to be +A ``TypedDict`` object is not a subtype of the regular ``dict[...]`` +type (and vice versa), since :py:class:`dict` allows arbitrary keys to be added and removed, unlike ``TypedDict``. However, any ``TypedDict`` object is a subtype of (that is, compatible with) ``Mapping[str, object]``, since :py:class:`~typing.Mapping` only provides read-only access to the dictionary items: @@ -1149,5 +1150,5 @@ TypedDict in the same way you can with regular objects. Instead, you can use the :ref:`tagged union pattern `. The referenced section of the docs has a full description with an example, but in short, you will need to give each TypedDict the same key where each value has a unique -unique :ref:`Literal type `. Then, check that key to distinguish +:ref:`Literal type `. Then, check that key to distinguish between your TypedDicts. diff --git a/docs/source/protocols.rst b/docs/source/protocols.rst index 38d1ee9bf357..cd59f841d8a0 100644 --- a/docs/source/protocols.rst +++ b/docs/source/protocols.rst @@ -455,19 +455,19 @@ member: .. code-block:: python - from typing import Optional, Iterable, List + from typing import Optional, Iterable from typing_extensions import Protocol class Combiner(Protocol): - def __call__(self, *vals: bytes, maxlen: Optional[int] = None) -> List[bytes]: ... + def __call__(self, *vals: bytes, maxlen: Optional[int] = None) -> list[bytes]: ... def batch_proc(data: Iterable[bytes], cb_results: Combiner) -> bytes: for item in data: ... - def good_cb(*vals: bytes, maxlen: Optional[int] = None) -> List[bytes]: + def good_cb(*vals: bytes, maxlen: Optional[int] = None) -> list[bytes]: ... - def bad_cb(*vals: bytes, maxitems: Optional[int]) -> List[bytes]: + def bad_cb(*vals: bytes, maxitems: Optional[int]) -> list[bytes]: ... batch_proc([], good_cb) # OK diff --git a/docs/source/running_mypy.rst b/docs/source/running_mypy.rst index 3afebde22aaf..d1c701e27e5a 100644 --- a/docs/source/running_mypy.rst +++ b/docs/source/running_mypy.rst @@ -81,7 +81,7 @@ Note that if you use namespace packages (in particular, packages without $ mypy -c 'x = [1, 2]; print(x())' ...will type check the above string as a mini-program (and in this case, - will report that ``List[int]`` is not callable). + will report that ``list[int]`` is not callable). Reading a list of files from a file @@ -133,14 +133,12 @@ Missing imports *************** When you import a module, mypy may report that it is unable to follow -the import. - -This can cause errors that look like the following: +the import. This can cause errors that look like the following: .. code-block:: text - main.py:1: error: Library stubs not installed for "requests" (or incompatible with Python 3.8) - main.py:2: error: Skipping analyzing 'django': found module but no type hints or library stubs + main.py:1: error: Skipping analyzing 'django': module is installed, but missing library stubs or py.typed marker + main.py:2: error: Library stubs not installed for "requests" (or incompatible with Python 3.8) main.py:3: error: Cannot find implementation or library stub for module named "this_module_does_not_exist" If you get any of these errors on an import, mypy will assume the type of that @@ -155,55 +153,14 @@ attribute of the module will automatically succeed: # But this type checks, and x will have type 'Any' x = does_not_exist.foobar() -The next sections describe what each error means and recommended next steps. - -Library stubs not installed ---------------------------- - -If mypy can't find stubs for a third-party library, and it knows that stubs exist for -the library, you will get a message like this: +The next sections describe what each of these errors means and recommended next steps; scroll to +the section that matches your error. -.. code-block:: text - main.py:1: error: Library stubs not installed for "yaml" (or incompatible with Python 3.8) - main.py:1: note: Hint: "python3 -m pip install types-PyYAML" - main.py:1: note: (or run "mypy --install-types" to install all missing stub packages) +Missing library stubs or py.typed marker +---------------------------------------- -You can resolve the issue by running the suggested pip command or -commands. Alternatively, you can use :option:`--install-types ` to install all known missing stubs: - -.. code-block:: text - - mypy --install-types - -This installs any stub packages that were suggested in the previous -mypy run. You can also use your normal mypy command line with the -extra :option:`--install-types ` option to -install missing stubs at the end of the run (if any were found). - -Use :option:`--install-types ` with -:option:`--non-interactive ` to install all suggested -stub packages without asking for confirmation, *and* type check your -code, in a single command: - -.. code-block:: text - - mypy --install-types --non-interactive src/ - -This can be useful in Continuous Integration jobs if you'd prefer not -to manage stub packages manually. This is somewhat slower than -explicitly installing stubs before running mypy, since it may type -check your code twice -- the first time to find the missing stubs, and -the second time to type check your code properly after mypy has -installed the stubs. - -.. _missing-type-hints-for-third-party-library: - -Missing type hints for third party library ------------------------------------------- - -If you are getting a "Skipping analyzing X: found module but no type hints or library stubs", +If you are getting a ``Skipping analyzing X: module is installed, but missing library stubs or py.typed marker``, error, this means mypy was able to find the module you were importing, but no corresponding type hints. @@ -277,10 +234,54 @@ will continue to be of type ``Any``. We recommend using this approach only as a last resort: it's equivalent to adding a ``# type: ignore`` to all unresolved imports in your codebase. -Unable to find module ---------------------- -If you are getting a "Cannot find implementation or library stub for module" +Library stubs not installed +--------------------------- + +If mypy can't find stubs for a third-party library, and it knows that stubs exist for +the library, you will get a message like this: + +.. code-block:: text + + main.py:1: error: Library stubs not installed for "yaml" (or incompatible with Python 3.8) + main.py:1: note: Hint: "python3 -m pip install types-PyYAML" + main.py:1: note: (or run "mypy --install-types" to install all missing stub packages) + +You can resolve the issue by running the suggested pip command or +commands. Alternatively, you can use :option:`--install-types ` to install all known missing stubs: + +.. code-block:: text + + mypy --install-types + +This installs any stub packages that were suggested in the previous +mypy run. You can also use your normal mypy command line with the +extra :option:`--install-types ` option to +install missing stubs at the end of the run (if any were found). + +Use :option:`--install-types ` with +:option:`--non-interactive ` to install all suggested +stub packages without asking for confirmation, *and* type check your +code, in a single command: + +.. code-block:: text + + mypy --install-types --non-interactive src/ + +This can be useful in Continuous Integration jobs if you'd prefer not +to manage stub packages manually. This is somewhat slower than +explicitly installing stubs before running mypy, since it may type +check your code twice -- the first time to find the missing stubs, and +the second time to type check your code properly after mypy has +installed the stubs. + +.. _missing-type-hints-for-third-party-library: + +Cannot find implementation or library stub +------------------------------------------ + +If you are getting a ``Cannot find implementation or library stub for module`` error, this means mypy was not able to find the module you are trying to import, whether it comes bundled with type hints or not. If you are getting this error, try: diff --git a/docs/source/runtime_troubles.rst b/docs/source/runtime_troubles.rst index 863d0c9c85eb..e748fb000b71 100644 --- a/docs/source/runtime_troubles.rst +++ b/docs/source/runtime_troubles.rst @@ -30,7 +30,7 @@ string-literal types with non-string-literal types freely: .. code-block:: python - def f(a: List['A']) -> None: ... # OK + def f(a: list['A']) -> None: ... # OK def g(n: 'int') -> None: ... # OK, though not useful class A: pass @@ -70,7 +70,7 @@ required to be valid Python syntax. For more details, see :pep:`563`. # base class example from __future__ import annotations - class A(Tuple['B', 'C']): ... # String literal types needed here + class A(tuple['B', 'C']): ... # String literal types needed here class B: ... class C: ... @@ -156,23 +156,22 @@ File ``foo.py``: .. code-block:: python - from typing import List, TYPE_CHECKING + from typing import TYPE_CHECKING if TYPE_CHECKING: import bar - def listify(arg: 'bar.BarClass') -> 'List[bar.BarClass]': + def listify(arg: 'bar.BarClass') -> 'list[bar.BarClass]': return [arg] File ``bar.py``: .. code-block:: python - from typing import List from foo import listify class BarClass: - def listifyme(self) -> 'List[BarClass]': + def listifyme(self) -> 'list[BarClass]': return listify(self) .. _not-generic-runtime: diff --git a/docs/source/stubgen.rst b/docs/source/stubgen.rst index a58a022e6c67..33fdac2089f7 100644 --- a/docs/source/stubgen.rst +++ b/docs/source/stubgen.rst @@ -1,4 +1,4 @@ -.. _stugen: +.. _stubgen: .. program:: stubgen diff --git a/docs/source/stubs.rst b/docs/source/stubs.rst index a15c16d85da3..38eded7ce57d 100644 --- a/docs/source/stubs.rst +++ b/docs/source/stubs.rst @@ -36,11 +36,16 @@ the source code. This can be useful, for example, if you use 3rd party open source libraries in your program (and there are no stubs in typeshed yet). -That's it! Now you can access the module in mypy programs and type check +That's it! + +Now you can access the module in mypy programs and type check code that uses the library. If you write a stub for a library module, consider making it available for other programmers that use mypy by contributing it back to the typeshed repo. +Mypy also ships with two tools for making it easier to create and maintain +stubs: :ref:`stubgen` and :ref:`stubtest`. + The following sections explain the kinds of type annotations you can use in your programs and stub files. @@ -112,22 +117,21 @@ For example: .. code-block:: python - from typing import List from typing_extensions import Protocol class Resource(Protocol): - def ok_1(self, foo: List[str] = ...) -> None: ... + def ok_1(self, foo: list[str] = ...) -> None: ... - def ok_2(self, foo: List[str] = ...) -> None: + def ok_2(self, foo: list[str] = ...) -> None: raise NotImplementedError() - def ok_3(self, foo: List[str] = ...) -> None: + def ok_3(self, foo: list[str] = ...) -> None: """Some docstring""" pass # Error: Incompatible default for argument "foo" (default has - # type "ellipsis", argument has type "List[str]") - def not_ok(self, foo: List[str] = ...) -> None: + # type "ellipsis", argument has type "list[str]") + def not_ok(self, foo: list[str] = ...) -> None: print(foo) .. note:: diff --git a/docs/source/stubtest.rst b/docs/source/stubtest.rst new file mode 100644 index 000000000000..828931fbdf2b --- /dev/null +++ b/docs/source/stubtest.rst @@ -0,0 +1,136 @@ +.. _stubtest: + +.. program:: stubtest + +Automatic stub testing (stubtest) +================================= + +Stub files are files containing type annotations. See +`PEP 484 `_ +for more motivation and details. + +A common problem with stub files is that they tend to diverge from the +actual implementation. Mypy includes the ``stubtest`` tool that can +automatically check for discrepancies between the stubs and the +implementation at runtime. + +What stubtest does and does not do +********************************** + +Stubtest will import your code and introspect your code objects at runtime, for +example, by using the capabilities of the :py:mod:`inspect` module. Stubtest +will then analyse the stub files, and compare the two, pointing out things that +differ between stubs and the implementation at runtime. + +It's important to be aware of the limitations of this comparison. Stubtest will +not make any attempt to statically analyse your actual code and relies only on +dynamic runtime introspection (in particular, this approach means stubtest works +well with extension modules). However, this means that stubtest has limited +visibility; for instance, it cannot tell if a return type of a function is +accurately typed in the stubs. + +For clarity, here are some additional things stubtest can't do: + +* Type check your code -- use ``mypy`` instead +* Generate stubs -- use ``stubgen`` or ``pyright --createstub`` instead +* Generate stubs based on running your application or test suite -- use ``monkeytype`` instead +* Apply stubs to code to produce inline types -- use ``retype`` or ``libcst`` instead + +In summary, stubtest works very well for ensuring basic consistency between +stubs and implementation or to check for stub completeness. It's used to +test Python's official collection of library stubs, +`typeshed `_. + +Example +******* + +Here's a quick example of what stubtest can do: + +.. code-block:: shell + + $ python3 -m pip install mypy + + $ cat library.py + x = "hello, stubtest" + + def foo(x=None): + print(x) + + $ cat library.pyi + x: int + + def foo(x: int) -> None: ... + + $ python3 -m mypy.stubtest library + error: library.foo is inconsistent, runtime argument "x" has a default value but stub argument does not + Stub: at line 3 + def (x: builtins.int) + Runtime: at line 3 in file ~/library.py + def (x=None) + + error: library.x variable differs from runtime type Literal['hello, stubtest'] + Stub: at line 1 + builtins.int + Runtime: + hello, stubtest + + +Usage +***** + +Running stubtest can be as simple as ``stubtest module_to_check``. +Run :option:`stubtest --help` for a quick summary of options. + +Subtest must be able to import the code to be checked, so make sure that mypy +is installed in the same environment as the library to be tested. In some +cases, setting ``PYTHONPATH`` can help stubtest find the code to import. + +Similarly, stubtest must be able to find the stubs to be checked. Stubtest +respects the ``MYPYPATH`` environment variable. + +If you wish to ignore some of stubtest's complaints, stubtest supports a +pretty handy allowlist system. + +The rest of this section documents the command line interface of stubtest. + +.. option:: --concise + + Makes stubtest's output more concise, one line per error + +.. option:: --ignore-missing-stub + + Ignore errors for stub missing things that are present at runtime + +.. option:: --ignore-positional-only + + Ignore errors for whether an argument should or shouldn't be positional-only + +.. option:: --allowlist FILE + + Use file as an allowlist. Can be passed multiple times to combine multiple + allowlists. Allowlists can be created with --generate-allowlist. Allowlists + support regular expressions. + +.. option:: --generate-allowlist + + Print an allowlist (to stdout) to be used with --allowlist + +.. option:: --ignore-unused-allowlist + + Ignore unused allowlist entries + +.. option:: --mypy-config-file FILE + + Use specified mypy config file to determine mypy plugins and mypy path + +.. option:: --custom-typeshed-dir DIR + + Use the custom typeshed in DIR + +.. option:: --check-typeshed + + Check all stdlib modules in typeshed + +.. option:: --help + + Show a help message :-) diff --git a/docs/source/type_inference_and_annotations.rst b/docs/source/type_inference_and_annotations.rst index 38518a8f2c3b..8150f88e579e 100644 --- a/docs/source/type_inference_and_annotations.rst +++ b/docs/source/type_inference_and_annotations.rst @@ -12,7 +12,7 @@ static type of the value expression: .. code-block:: python i = 1 # Infer type "int" for i - l = [1, 2] # Infer type "List[int]" for l + l = [1, 2] # Infer type "list[int]" for l Type inference is not used in dynamically typed functions (those without a function type annotation) — every local variable type defaults @@ -84,24 +84,33 @@ In these cases you can give the type explicitly using a type annotation: .. code-block:: python - l: List[int] = [] # Create empty list with type List[int] - d: Dict[str, int] = {} # Create empty dictionary (str -> int) + l: list[int] = [] # Create empty list with type list[int] + d: dict[str, int] = {} # Create empty dictionary (str -> int) Similarly, you can also give an explicit type when creating an empty set: .. code-block:: python - s: Set[int] = set() + s: set[int] = set() + +.. note:: + + Using type arguments (e.g. ``list[int]``) on builtin collections like + :py:class:`list`, :py:class:`dict`, :py:class:`tuple`, and :py:class:`set` + only works in Python 3.9 and later. For Python 3.8 and earlier, you must use + :py:class:`~typing.List` (e.g. ``List[int]``), :py:class:`~typing.Dict`, and + so on. + Compatibility of container types ******************************** -The following program generates a mypy error, since ``List[int]`` -is not compatible with ``List[object]``: +The following program generates a mypy error, since ``list[int]`` +is not compatible with ``list[object]``: .. code-block:: python - def f(l: List[object], k: List[int]) -> None: + def f(l: list[object], k: list[int]) -> None: l = k # Type check error: incompatible types in assignment The reason why the above assignment is disallowed is that allowing the @@ -109,12 +118,12 @@ assignment could result in non-int values stored in a list of ``int``: .. code-block:: python - def f(l: List[object], k: List[int]) -> None: + def f(l: list[object], k: list[int]) -> None: l = k l.append('x') - print(k[-1]) # Ouch; a string in List[int] + print(k[-1]) # Ouch; a string in list[int] -Other container types like :py:class:`~typing.Dict` and :py:class:`~typing.Set` behave similarly. We +Other container types like :py:class:`dict` and :py:class:`set` behave similarly. We will discuss how you can work around this in :ref:`variance`. You can still run the above program; it prints ``x``. This illustrates @@ -132,23 +141,23 @@ example, the following is valid: .. code-block:: python - def f(l: List[object]) -> None: - l = [1, 2] # Infer type List[object] for [1, 2], not List[int] + def f(l: list[object]) -> None: + l = [1, 2] # Infer type list[object] for [1, 2], not list[int] In an assignment, the type context is determined by the assignment target. In this case this is ``l``, which has the type -``List[object]``. The value expression ``[1, 2]`` is type checked in -this context and given the type ``List[object]``. In the previous +``list[object]``. The value expression ``[1, 2]`` is type checked in +this context and given the type ``list[object]``. In the previous example we introduced a new variable ``l``, and here the type context was empty. Declared argument types are also used for type context. In this program -mypy knows that the empty list ``[]`` should have type ``List[int]`` based +mypy knows that the empty list ``[]`` should have type ``list[int]`` based on the declared type of ``arg`` in ``foo``: .. code-block:: python - def foo(arg: List[int]) -> None: + def foo(arg: list[int]) -> None: print('Items:', ''.join(str(a) for a in arg)) foo([]) # OK @@ -159,7 +168,7 @@ in the following statement: .. code-block:: python - def foo(arg: List[int]) -> None: + def foo(arg: list[int]) -> None: print('Items:', ', '.join(arg)) a = [] # Error: Need type annotation for "a" @@ -170,7 +179,7 @@ Working around the issue is easy by adding a type annotation: .. code-block:: Python ... - a: List[int] = [] # OK + a: list[int] = [] # OK foo(a) Declaring multiple variable types at a time @@ -206,13 +215,77 @@ right-hand side of an assignment, but not always: p, q, *rs = 1, 2 # Error: Type of rs cannot be inferred On first line, the type of ``bs`` is inferred to be -``List[int]``. However, on the second line, mypy cannot infer the type +``list[int]``. However, on the second line, mypy cannot infer the type of ``rs``, because there is no right-hand side value for ``rs`` to infer the type from. In cases like these, the starred expression needs to be annotated with a starred type: .. code-block:: python - p, q, *rs = 1, 2 # type: int, int, List[int] + p, q, *rs = 1, 2 # type: int, int, list[int] + +Here, the type of ``rs`` is set to ``list[int]``. + +Silencing type errors +********************* + +You might want to disable type checking on specific lines, or within specific +files in your codebase. To do that, you can use a ``# type: ignore`` comment. + +For example, say that the web framework that you use now takes an integer +argument to ``run()``, which starts it on localhost on that port. Like so: + +.. code-block:: python + + # Starting app on http://localhost:8000 + app.run(8000) + +However, the type stubs that the package uses is not up-to-date, and it still +expects only ``str`` types for ``run()``. This would give you the following error: + +.. code-block:: text + + error: Argument 1 to "run" of "A" has incompatible type "int"; expected "str" + +If you cannot directly fix the type stubs yourself, you can temporarily +disable type checking on that line, by adding a ``# type: ignore``: + +.. code-block:: python -Here, the type of ``rs`` is set to ``List[int]``. + # Starting app on http://localhost:8000 + app.run(8000) # type: ignore + +This will suppress any mypy errors that would have raised on that specific line. + +You should probably add some more information on the ``# type: ignore`` comment, +to explain why the ignore was added in the first place. This could be a link to +an issue on the repository responsible for the type stubs, or it could be a +short explanation of the bug. To do that, use this format: + +.. code-block:: python + + # Starting app on http://localhost:8000 + app.run(8000) # type: ignore # `run()` now accepts an `int`, as a port + + +Mypy displays an error code for each error if you use +:option:`--show-error-codes `: + +.. code-block:: text + + error: "str" has no attribute "trim" [attr-defined] + + +It is possible to add a specific error-code in your ignore comment (e.g. +``# type: ignore[attr-defined]``) to clarify what's being silenced. You can +find more information about error codes :ref:`here `. + +Similarly, you can also ignore all mypy checks in a file, by adding a +``# type: ignore`` at the top of the file: + +.. code-block:: python + + # type: ignore + # This is a test file, skipping type checking in it. + import unittest + ... diff --git a/docs/source/type_narrowing.rst b/docs/source/type_narrowing.rst index 25d6629aa694..b5f297d283c0 100644 --- a/docs/source/type_narrowing.rst +++ b/docs/source/type_narrowing.rst @@ -17,6 +17,7 @@ The simplest way to narrow a type is to use one of the supported expressions: - :py:func:`isinstance` like in ``isinstance(obj, float)`` will narrow ``obj`` to have ``float`` type - :py:func:`issubclass` like in ``issubclass(cls, MyClass)`` will narrow ``cls`` to be ``Type[MyClass]`` - :py:func:`type` like in ``type(obj) is int`` will narrow ``obj`` to have ``int`` type +- :py:func:`callable` like in ``callable(obj)`` will narrow object to callable type Type narrowing is contextual. For example, based on the condition, mypy will narrow an expression only within an ``if`` branch: @@ -37,7 +38,8 @@ Type narrowing is contextual. For example, based on the condition, mypy will nar # Back outside of the ``if`` statement, the type isn't narrowed: reveal_type(arg) # Revealed type: "builtins.object" -Mypy understands the implications `return` or exception raising can have for what type an object could be: +Mypy understands the implications ``return`` or exception raising can have +for what type an object could be: .. code-block:: python @@ -56,6 +58,34 @@ We can also use ``assert`` to narrow types in the same context: assert isinstance(arg, int) reveal_type(arg) # Revealed type: "builtins.int" +.. note:: + + With :option:`--warn-unreachable ` + narrowing types to some impossible state will be treated as an error. + + .. code-block:: python + + def function(arg: int): + # error: Subclass of "int" and "str" cannot exist: + # would have incompatible method signatures + assert isinstance(arg, str) + + # error: Statement is unreachable + print("so mypy concludes the assert will always trigger") + + Without ``--warn-unreachable`` mypy will simply not check code it deems to be + unreachable. See :ref:`unreachable` for more information. + + .. code-block:: python + + x: int = 1 + assert isinstance(x, str) + reveal_type(x) # Revealed type is "builtins.int" + print(x + '!') # Typechecks with `mypy`, but fails in runtime. + +issubclass +~~~~~~~~~~ + Mypy can also use :py:func:`issubclass` for better type inference when working with types and metaclasses: @@ -74,31 +104,36 @@ for better type inference when working with types and metaclasses: reveal_type(t) # Revealed type is "Type[MyCalcMeta]" t.calc() # Okay -.. note:: +callable +~~~~~~~~ - With :option:`--warn-unreachable ` - narrowing types to some impossible state will be treated as an error. +Mypy knows what types are callable and which ones are not during type checking. +So, we know what ``callable()`` will return. For example: - .. code-block:: python +.. code-block:: python - def function(arg: int): - # error: Subclass of "int" and "str" cannot exist: - # would have incompatible method signatures - assert isinstance(arg, str) + from typing import Callable - # error: Statement is unreachable - print("so mypy concludes the assert will always trigger") + x: Callable[[], int] - Without ``--warn-unreachable`` mypy will simply not check code it deems to be - unreachable. See :ref:`unreachable` for more information. + if callable(x): + reveal_type(x) # N: Revealed type is "def () -> builtins.int" + else: + ... # Will never be executed and will raise error with `--warn-unreachable` - .. code-block:: python +``callable`` function can even split ``Union`` type +for callable and non-callable parts: - x: int = 1 - assert isinstance(x, str) - reveal_type(x) # Revealed type is "builtins.int" - print(x + '!') # Typechecks with `mypy`, but fails in runtime. +.. code-block:: python + + from typing import Callable, Union + x: Union[int, Callable[[], int]] + + if callable(x): + reveal_type(x) # N: Revealed type is "def () -> builtins.int" + else: + reveal_type(x) # N: Revealed type is "builtins.int" .. _casts: @@ -113,11 +148,11 @@ to perform a cast: .. code-block:: python - from typing import cast, List + from typing import cast o: object = [1] - x = cast(List[int], o) # OK - y = cast(List[str], o) # OK (cast performs no actual runtime check) + x = cast(list[int], o) # OK + y = cast(list[str], o) # OK (cast performs no actual runtime check) To support runtime checking of casts such as the above, we'd have to check the types of all list items, which would be very inefficient for large lists. @@ -166,35 +201,32 @@ Let's have a look at the regular ``bool`` example: .. code-block:: python - from typing import List - - def is_str_list(val: List[object]) -> bool: + def is_str_list(val: list[object]) -> bool: """Determines whether all objects in the list are strings""" return all(isinstance(x, str) for x in val) - def func1(val: List[object]) -> None: + def func1(val: list[object]) -> None: if is_str_list(val): - reveal_type(val) # Reveals List[object] + reveal_type(val) # Reveals list[object] print(" ".join(val)) # Error: incompatible type The same example with ``TypeGuard``: .. code-block:: python - from typing import List from typing import TypeGuard # use `typing_extensions` for Python 3.9 and below - def is_str_list(val: List[object]) -> TypeGuard[List[str]]: + def is_str_list(val: list[object]) -> TypeGuard[list[str]]: """Determines whether all objects in the list are strings""" return all(isinstance(x, str) for x in val) - def func1(val: List[object]) -> None: + def func1(val: list[object]) -> None: if is_str_list(val): - reveal_type(val) # List[str] + reveal_type(val) # list[str] print(" ".join(val)) # ok How does it work? ``TypeGuard`` narrows the first function argument (``val``) -to the type specified as the first type parameter (``List[str]``). +to the type specified as the first type parameter (``list[str]``). .. note:: @@ -225,19 +257,19 @@ Generic TypeGuards .. code-block:: python - from typing import Tuple, TypeVar + from typing import TypeVar from typing import TypeGuard # use `typing_extensions` for `python<3.10` _T = TypeVar("_T") - def is_two_element_tuple(val: Tuple[_T, ...]) -> TypeGuard[Tuple[_T, _T]]: + def is_two_element_tuple(val: tuple[_T, ...]) -> TypeGuard[tuple[_T, _T]]: return len(val) == 2 - def func(names: Tuple[str, ...]): + def func(names: tuple[str, ...]): if is_two_element_tuple(names): - reveal_type(names) # Tuple[str, str] + reveal_type(names) # tuple[str, str] else: - reveal_type(names) # Tuple[str, ...] + reveal_type(names) # tuple[str, ...] Typeguards with parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -246,17 +278,17 @@ Type guard functions can accept extra arguments: .. code-block:: python - from typing import Type, Set, TypeVar + from typing import Type, TypeVar from typing import TypeGuard # use `typing_extensions` for `python<3.10` _T = TypeVar("_T") - def is_set_of(val: Set[Any], type: Type[_T]) -> TypeGuard[Set[_T]]: + def is_set_of(val: set[Any], type: Type[_T]) -> TypeGuard[set[_T]]: return all(isinstance(x, type) for x in val) - items: Set[Any] + items: set[Any] if is_set_of(items, str): - reveal_type(items) # Set[str] + reveal_type(items) # set[str] TypeGuards as methods ~~~~~~~~~~~~~~~~~~~~~ @@ -295,3 +327,35 @@ TypeGuards as methods def is_child(instance: Parent) -> TypeGuard[Child]: return isinstance(instance, Child) + +Assignment expressions as TypeGuards +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes you might need to create a new variable and narrow it +to some specific type at the same time. +This can be achieved by using ``TypeGuard`` together +with `:= operator `_. + +.. code-block:: python + + from typing import TypeGuard # use `typing_extensions` for `python<3.10` + + def is_float(a: object) -> TypeGuard[float]: + return isinstance(a, float) + + def main(a: object) -> None: + if is_float(x := a): + reveal_type(x) # N: Revealed type is 'builtins.float' + reveal_type(a) # N: Revealed type is 'builtins.object' + reveal_type(x) # N: Revealed type is 'builtins.object' + reveal_type(a) # N: Revealed type is 'builtins.object' + +What happens here? + +1. We create a new variable ``x`` and assign a value of ``a`` to it +2. We run ``is_float()`` type guard on ``x`` +3. It narrows ``x`` to be ``float`` in the ``if`` context and does not touch ``a`` + +.. note:: + + The same will work with ``isinstance(x := a, float)`` as well. diff --git a/misc/build_wheel.py b/misc/build_wheel.py index b21c19da98eb..44b40c2e8fed 100644 --- a/misc/build_wheel.py +++ b/misc/build_wheel.py @@ -3,13 +3,11 @@ The main GitHub workflow where this script is used: https://github.com/mypyc/mypy_mypyc-wheels/blob/master/.github/workflows/build.yml -This uses cibuildwheel (https://github.com/pypa/cibuildwheel) to -build the wheels. +This uses cibuildwheel (https://github.com/pypa/cibuildwheel) to build the wheels. Usage: - build_wheel_ci.py --python-version \ - --output-dir + build_wheel.py --python-version --output-dir Wheels for the given Python version will be created in the given directory. Python version is in form "39". @@ -18,9 +16,7 @@ You can test locally by using --extra-opts. macOS example: - mypy/misc/build_wheel_ci.py --python-version 39 --output-dir out --extra-opts="--platform macos" - -Other supported values for platform: linux, windows + mypy/misc/build_wheel.py --python-version 39 --output-dir out --extra-opts="--platform macos" """ import argparse @@ -39,13 +35,13 @@ def create_environ(python_version: str) -> Dict[str, str]: """Set up environment variables for cibuildwheel.""" env = os.environ.copy() - env['CIBW_BUILD'] = "cp{}-*".format(python_version) + env['CIBW_BUILD'] = f"cp{python_version}-*" # Don't build 32-bit wheels env['CIBW_SKIP'] = "*-manylinux_i686 *-win32" # Apple Silicon support - # When cross-compiling on Intel, it is not possible to test arm64 and + # When cross-compiling on Intel, it is not possible to test arm64 and # the arm64 part of a universal2 wheel. Warnings will be silenced with # following CIBW_TEST_SKIP env['CIBW_ARCHS_MACOS'] = "x86_64 arm64" @@ -56,20 +52,15 @@ def create_environ(python_version: str) -> Dict[str, str]: # mypy's isolated builds don't specify the requirements mypyc needs, so install # requirements and don't use isolated builds. we need to use build-requirements.txt # with recent mypy commits to get stub packages needed for compilation. - # - # TODO: remove use of mypy-requirements.txt once we no longer need to support - # building pre modular typeshed releases env['CIBW_BEFORE_BUILD'] = """ - pip install -r {package}/mypy-requirements.txt && - (pip install -r {package}/build-requirements.txt || true) + pip install -r {package}/build-requirements.txt """.replace('\n', ' ') # download a copy of clang to use to compile on linux. this was probably built in 2018, # speeds up compilation 2x env['CIBW_BEFORE_BUILD_LINUX'] = """ (cd / && curl -L %s | tar xzf -) && - pip install -r {package}/mypy-requirements.txt && - (pip install -r {package}/build-requirements.txt || true) + pip install -r {package}/build-requirements.txt """.replace('\n', ' ') % LLVM_URL # the double negative is counterintuitive, https://github.com/pypa/pip/issues/5735 @@ -128,8 +119,7 @@ def main() -> None: output_dir = args.output_dir extra_opts = args.extra_opts environ = create_environ(python_version) - script = 'python -m cibuildwheel {} --output-dir {} {}'.format(extra_opts, output_dir, - ROOT_DIR) + script = f'python -m cibuildwheel {extra_opts} --output-dir {output_dir} {ROOT_DIR}' subprocess.check_call(script, shell=True, env=environ) diff --git a/misc/cherry-pick-typeshed.py b/misc/cherry-pick-typeshed.py new file mode 100644 index 000000000000..627c8990a155 --- /dev/null +++ b/misc/cherry-pick-typeshed.py @@ -0,0 +1,67 @@ +"""Cherry-pick a commit from typeshed. + +Usage: + + python3 misc/cherry-pick-typeshed.py --typeshed-dir dir hash +""" + +import argparse +import os.path +import re +import subprocess +import sys +import tempfile + + +def parse_commit_title(diff: str) -> str: + m = re.search("\n ([^ ].*)", diff) + assert m is not None, "Could not parse diff" + return m.group(1) + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument( + "--typeshed-dir", help="location of typeshed", metavar="dir", required=True + ) + parser.add_argument( + "commit", help="typeshed commit hash to cherry-pick" + ) + args = parser.parse_args() + typeshed_dir = args.typeshed_dir + commit = args.commit + + if not os.path.isdir(typeshed_dir): + sys.exit(f"error: {typeshed_dir} does not exist") + if not re.match("[0-9a-fA-F]+$", commit): + sys.exit(f"error: Invalid commit {commit!r}") + + if not os.path.exists("mypy") or not os.path.exists("mypyc"): + sys.exit(f"error: This script must be run at the mypy repository root directory") + + with tempfile.TemporaryDirectory() as d: + diff_file = os.path.join(d, "diff") + out = subprocess.run(["git", "show", commit], + capture_output=True, + text=True, + check=True, + cwd=typeshed_dir) + with open(diff_file, "w") as f: + f.write(out.stdout) + subprocess.run(["git", + "apply", + "--index", + "--directory=mypy/typeshed", + "--exclude=**/tests/**", + diff_file], + check=True) + + title = parse_commit_title(out.stdout) + subprocess.run(["git", "commit", "-m", f"Typeshed cherry-pick: {title}"], check=True) + + print() + print(f"Cherry-picked commit {commit} from {typeshed_dir}") + + +if __name__ == '__main__': + main() diff --git a/misc/proper_plugin.py b/misc/proper_plugin.py index 25dfac131bf8..249ad983266b 100644 --- a/misc/proper_plugin.py +++ b/misc/proper_plugin.py @@ -66,6 +66,7 @@ def is_special_target(right: ProperType) -> bool: if right.type_object().fullname in ( 'mypy.types.UnboundType', 'mypy.types.TypeVarType', + 'mypy.types.ParamSpecType', 'mypy.types.RawExpressionType', 'mypy.types.EllipsisType', 'mypy.types.StarType', diff --git a/mypy-requirements.txt b/mypy-requirements.txt index 96888e221128..61e0a9f28e01 100644 --- a/mypy-requirements.txt +++ b/mypy-requirements.txt @@ -1,4 +1,4 @@ -typing_extensions>=3.7.4 -mypy_extensions>=0.4.3,<0.5.0 -typed_ast>=1.4.0,<1.5.0 -tomli>=1.1.0,<1.2.0 +typing_extensions>=3.10 +mypy_extensions>=0.4.3 +typed_ast>=1.4.0,<2; python_version<'3.8' +tomli>=1.1.0 diff --git a/mypy/__main__.py b/mypy/__main__.py index 353e8e526758..aebeb4baedf8 100644 --- a/mypy/__main__.py +++ b/mypy/__main__.py @@ -1,9 +1,10 @@ """Mypy type checker command line tool.""" - -import sys import os +import sys +import traceback -from mypy.main import main +from mypy.main import main, process_options +from mypy.util import FancyFormatter def console_entry() -> None: @@ -17,6 +18,16 @@ def console_entry() -> None: devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) sys.exit(2) + except KeyboardInterrupt: + _, options = process_options(args=sys.argv[1:]) + if options.show_traceback: + sys.stdout.write(traceback.format_exc()) + formatter = FancyFormatter(sys.stdout, sys.stderr, False) + msg = "Interrupted\n" + sys.stdout.write(formatter.style(msg, color="red", bold=True)) + sys.stdout.flush() + sys.stderr.flush() + sys.exit(2) if __name__ == '__main__': diff --git a/mypy/api.py b/mypy/api.py index ef3016ac31da..f6e40b4fc3ec 100644 --- a/mypy/api.py +++ b/mypy/api.py @@ -67,7 +67,7 @@ def run(args: List[str]) -> Tuple[str, str, int]: # Lazy import to avoid needing to import all of mypy to call run_dmypy from mypy.main import main return _run(lambda stdout, stderr: main(None, args=args, - stdout=stdout, stderr=stderr)) + stdout=stdout, stderr=stderr, clean_exit=True)) def run_dmypy(args: List[str]) -> Tuple[str, str, int]: diff --git a/mypy/applytype.py b/mypy/applytype.py index 324e40db7e65..5b803a4aaa0b 100644 --- a/mypy/applytype.py +++ b/mypy/applytype.py @@ -5,7 +5,7 @@ from mypy.expandtype import expand_type from mypy.types import ( Type, TypeVarId, TypeVarType, CallableType, AnyType, PartialType, get_proper_types, - TypeVarLikeType, ProperType, ParamSpecType + TypeVarLikeType, ProperType, ParamSpecType, get_proper_type ) from mypy.nodes import Context @@ -18,9 +18,8 @@ def get_target_type( context: Context, skip_unsatisfied: bool ) -> Optional[Type]: - # TODO(shantanu): fix for ParamSpecType if isinstance(tvar, ParamSpecType): - return None + return type assert isinstance(tvar, TypeVarType) values = get_proper_types(tvar.values) if values: @@ -90,6 +89,14 @@ def apply_generic_arguments( if target_type is not None: id_to_type[tvar.id] = target_type + param_spec = callable.param_spec() + if param_spec is not None: + nt = id_to_type.get(param_spec.id) + if nt is not None: + nt = get_proper_type(nt) + if isinstance(nt, CallableType): + callable = callable.expand_param_spec(nt) + # Apply arguments to argument types. arg_types = [expand_type(at, id_to_type) for at in callable.arg_types] diff --git a/mypy/argmap.py b/mypy/argmap.py index d9453aa0b640..bcb864472038 100644 --- a/mypy/argmap.py +++ b/mypy/argmap.py @@ -1,12 +1,16 @@ """Utilities for mapping between actual and formal arguments (and their types).""" -from typing import List, Optional, Sequence, Callable, Set +from typing import TYPE_CHECKING, List, Optional, Sequence, Callable, Set +from mypy.maptype import map_instance_to_supertype from mypy.types import ( - Type, Instance, TupleType, AnyType, TypeOfAny, TypedDictType, get_proper_type + Type, Instance, TupleType, AnyType, TypeOfAny, TypedDictType, ParamSpecType, get_proper_type ) from mypy import nodes +if TYPE_CHECKING: + from mypy.infer import ArgumentInferContext + def map_actuals_to_formals(actual_kinds: List[nodes.ArgKind], actual_names: Optional[Sequence[Optional[str]]], @@ -69,7 +73,7 @@ def map_actuals_to_formals(actual_kinds: List[nodes.ArgKind], assert actual_kind == nodes.ARG_STAR2 actualt = get_proper_type(actual_arg_type(ai)) if isinstance(actualt, TypedDictType): - for name, value in actualt.items.items(): + for name in actualt.items: if name in formal_names: formal_to_actual[formal_names.index(name)].append(ai) elif nodes.ARG_STAR2 in formal_kinds: @@ -140,11 +144,13 @@ def f(x: int, *args: str) -> None: ... needs a separate instance since instances have per-call state. """ - def __init__(self) -> None: + def __init__(self, context: 'ArgumentInferContext') -> None: # Next tuple *args index to use. self.tuple_index = 0 # Keyword arguments in TypedDict **kwargs used. self.kwargs_used: Set[str] = set() + # Type context for `*` and `**` arg kinds. + self.context = context def expand_actual_type(self, actual_type: Type, @@ -164,14 +170,18 @@ def expand_actual_type(self, """ actual_type = get_proper_type(actual_type) if actual_kind == nodes.ARG_STAR: - if isinstance(actual_type, Instance): - if actual_type.type.fullname == 'builtins.list': - # List *arg. - return actual_type.args[0] - elif actual_type.args: - # TODO: Try to map type arguments to Iterable - return actual_type.args[0] + if isinstance(actual_type, Instance) and actual_type.args: + from mypy.subtypes import is_subtype + if is_subtype(actual_type, self.context.iterable_type): + return map_instance_to_supertype( + actual_type, + self.context.iterable_type.type, + ).args[0] else: + # We cannot properly unpack anything other + # than `Iterable` type with `*`. + # Just return `Any`, other parts of code would raise + # a different error for improper use. return AnyType(TypeOfAny.from_error) elif isinstance(actual_type, TupleType): # Get the next tuple item of a tuple *arg. @@ -181,9 +191,13 @@ def expand_actual_type(self, else: self.tuple_index += 1 return actual_type.items[self.tuple_index - 1] + elif isinstance(actual_type, ParamSpecType): + # ParamSpec is valid in *args but it can't be unpacked. + return actual_type else: return AnyType(TypeOfAny.from_error) elif actual_kind == nodes.ARG_STAR2: + from mypy.subtypes import is_subtype if isinstance(actual_type, TypedDictType): if formal_kind != nodes.ARG_STAR2 and formal_name in actual_type.items: # Lookup type based on keyword argument name. @@ -193,11 +207,20 @@ def expand_actual_type(self, formal_name = (set(actual_type.items.keys()) - self.kwargs_used).pop() self.kwargs_used.add(formal_name) return actual_type.items[formal_name] - elif (isinstance(actual_type, Instance) - and (actual_type.type.fullname == 'builtins.dict')): - # Dict **arg. - # TODO: Handle arbitrary Mapping - return actual_type.args[1] + elif ( + isinstance(actual_type, Instance) and + len(actual_type.args) > 1 and + is_subtype(actual_type, self.context.mapping_type) + ): + # Only `Mapping` type can be unpacked with `**`. + # Other types will produce an error somewhere else. + return map_instance_to_supertype( + actual_type, + self.context.mapping_type.type, + ).args[1] + elif isinstance(actual_type, ParamSpecType): + # ParamSpec is valid in **kwargs but it can't be unpacked. + return actual_type else: return AnyType(TypeOfAny.from_error) else: diff --git a/mypy/binder.py b/mypy/binder.py index 523367a7685c..2f83ffb095fc 100644 --- a/mypy/binder.py +++ b/mypy/binder.py @@ -2,7 +2,7 @@ from collections import defaultdict from typing import Dict, List, Set, Iterator, Union, Optional, Tuple, cast -from typing_extensions import DefaultDict +from typing_extensions import DefaultDict, TypeAlias as _TypeAlias from mypy.types import ( Type, AnyType, PartialType, UnionType, TypeOfAny, NoneType, get_proper_type @@ -13,10 +13,10 @@ from mypy.erasetype import remove_instance_last_known_values from mypy.nodes import Expression, Var, RefExpr from mypy.literals import Key, literal, literal_hash, subkeys -from mypy.nodes import IndexExpr, MemberExpr, NameExpr +from mypy.nodes import IndexExpr, MemberExpr, AssignmentExpr, NameExpr -BindableExpression = Union[IndexExpr, MemberExpr, NameExpr] +BindableExpression: _TypeAlias = Union[IndexExpr, MemberExpr, AssignmentExpr, NameExpr] class Frame: @@ -136,7 +136,7 @@ def _get(self, key: Key, index: int = -1) -> Optional[Type]: return None def put(self, expr: Expression, typ: Type) -> None: - if not isinstance(expr, (IndexExpr, MemberExpr, NameExpr)): + if not isinstance(expr, (IndexExpr, MemberExpr, AssignmentExpr, NameExpr)): return if not literal(expr): return diff --git a/mypy/build.py b/mypy/build.py index 9c77adba8d30..5eebc0a22a85 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -15,6 +15,7 @@ import gc import json import os +import platform import re import stat import sys @@ -23,7 +24,7 @@ from typing import (AbstractSet, Any, Dict, Iterable, Iterator, List, Sequence, Mapping, NamedTuple, Optional, Set, Tuple, TypeVar, Union, Callable, TextIO) -from typing_extensions import ClassVar, Final, TYPE_CHECKING +from typing_extensions import ClassVar, Final, TYPE_CHECKING, TypeAlias as _TypeAlias from mypy_extensions import TypedDict from mypy.nodes import MypyFile, ImportBase, Import, ImportFrom, ImportAll, SymbolTable @@ -69,7 +70,7 @@ DEBUG_FINE_GRAINED: Final = False # These modules are special and should always come from typeshed. -CORE_BUILTIN_MODULES = { +CORE_BUILTIN_MODULES: Final = { 'builtins', 'typing', 'types', @@ -81,7 +82,7 @@ } -Graph = Dict[str, 'State'] +Graph: _TypeAlias = Dict[str, 'State'] # TODO: Get rid of BuildResult. We might as well return a BuildManager. @@ -201,8 +202,9 @@ def _build(sources: List[BuildSource], stderr: TextIO, extra_plugins: Sequence[Plugin], ) -> BuildResult: - # This seems the most reasonable place to tune garbage collection. - gc.set_threshold(150 * 1000) + if platform.python_implementation() == 'CPython': + # This seems the most reasonable place to tune garbage collection. + gc.set_threshold(150 * 1000) data_dir = default_data_dir() fscache = fscache or FileSystemCache() @@ -492,6 +494,7 @@ def take_module_snapshot(module: types.ModuleType) -> str: (e.g. if there is a change in modules imported by a plugin). """ if hasattr(module, '__file__'): + assert module.__file__ is not None with open(module.__file__, 'rb') as f: digest = hash_digest(f.read()) else: @@ -1093,7 +1096,9 @@ def _load_json_file(file: str, manager: BuildManager, if manager.verbosity() >= 2: manager.trace(log_success + data.rstrip()) try: + t1 = time.time() result = json.loads(data) + manager.add_stats(data_json_load_time=time.time() - t1) except json.JSONDecodeError: manager.errors.set_file(file, None) manager.errors.report(-1, -1, @@ -1306,8 +1311,11 @@ def validate_meta(meta: Optional[CacheMeta], id: str, path: Optional[str], assert path is not None, "Internal error: meta was provided without a path" if not manager.options.skip_cache_mtime_checks: # Check data_json; assume if its mtime matches it's good. - # TODO: stat() errors - data_mtime = manager.getmtime(meta.data_json) + try: + data_mtime = manager.getmtime(meta.data_json) + except OSError: + manager.log('Metadata abandoned for {}: failed to stat data_json'.format(id)) + return None if data_mtime != meta.data_mtime: manager.log('Metadata abandoned for {}: data cache is modified'.format(id)) return None @@ -1503,9 +1511,6 @@ def write_cache(id: str, path: str, tree: MypyFile, # Write data cache file, if applicable # Note that for Bazel we don't record the data file's mtime. if old_interface_hash == interface_hash: - # If the interface is unchanged, the cached data is guaranteed - # to be equivalent, and we only need to update the metadata. - data_mtime = manager.getmtime(data_json) manager.trace("Interface for {} is unchanged".format(id)) else: manager.trace("Interface for {} has changed".format(id)) @@ -1522,7 +1527,12 @@ def write_cache(id: str, path: str, tree: MypyFile, # Both have the effect of slowing down the next run a # little bit due to an out-of-date cache file. return interface_hash, None + + try: data_mtime = manager.getmtime(data_json) + except OSError: + manager.log("Error in os.stat({!r}), skipping cache write".format(data_json)) + return interface_hash, None mtime = 0 if bazel else int(st.st_mtime) size = st.st_size @@ -1976,17 +1986,17 @@ def load_fine_grained_deps(self) -> Dict[str, Set[str]]: def load_tree(self, temporary: bool = False) -> None: assert self.meta is not None, "Internal error: this method must be called only" \ " for cached modules" + + data = _load_json_file(self.meta.data_json, self.manager, "Load tree ", + "Could not load tree: ") + if data is None: + return None + t0 = time.time() - raw = self.manager.metastore.read(self.meta.data_json) - t1 = time.time() - data = json.loads(raw) - t2 = time.time() # TODO: Assert data file wasn't changed. self.tree = MypyFile.deserialize(data) - t3 = time.time() - self.manager.add_stats(data_read_time=t1 - t0, - data_json_load_time=t2 - t1, - deserialize_time=t3 - t2) + t1 = time.time() + self.manager.add_stats(deserialize_time=t1 - t0) if not temporary: self.manager.modules[self.id] = self.tree self.manager.add_stats(fresh_trees=1) @@ -2889,7 +2899,14 @@ def load_graph(sources: List[BuildSource], manager: BuildManager, -1, 0, 'Source file found twice under different module names: ' '"{}" and "{}"'.format(seen_files[newst_path].id, newst.id), - blocker=True) + blocker=True, + ) + manager.errors.report( + -1, 0, + "See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules " # noqa: E501 + "for more info", + severity='note', + ) manager.errors.raise_error() seen_files[newst_path] = newst diff --git a/mypy/checker.py b/mypy/checker.py index af4604faacc5..b90221a0a5a5 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -8,8 +8,9 @@ Any, Dict, Set, List, cast, Tuple, TypeVar, Union, Optional, NamedTuple, Iterator, Iterable, Sequence, Mapping, Generic, AbstractSet, Callable ) -from typing_extensions import Final +from typing_extensions import Final, TypeAlias as _TypeAlias +from mypy.backports import nullcontext from mypy.errors import Errors, report_internal_error from mypy.nodes import ( SymbolTable, Statement, MypyFile, Var, Expression, Lvalue, Node, @@ -36,7 +37,8 @@ UnionType, TypeVarId, TypeVarType, PartialType, DeletedType, UninhabitedType, is_named_instance, union_items, TypeQuery, LiteralType, is_optional, remove_optional, TypeTranslator, StarType, get_proper_type, ProperType, - get_proper_types, is_literal_type, TypeAliasType, TypeGuardedType) + get_proper_types, is_literal_type, TypeAliasType, TypeGuardedType, ParamSpecType +) from mypy.sametypes import is_same_type from mypy.messages import ( MessageBuilder, make_inferred_type_note, append_invariance_notes, pretty_seq, @@ -44,17 +46,21 @@ ) import mypy.checkexpr from mypy.checkmember import ( - analyze_member_access, analyze_descriptor_access, type_object_type, + MemberContext, analyze_member_access, analyze_descriptor_access, + type_object_type, + analyze_decorator_or_funcbase_access, ) +from mypy.semanal_enum import ENUM_BASES, ENUM_SPECIAL_PROPS from mypy.typeops import ( map_type_from_supertype, bind_self, erase_to_bound, make_simplified_union, erase_def_to_union_or_bound, erase_to_union_or_bound, coerce_to_literal, try_getting_str_literals_from_type, try_getting_int_literals_from_type, - tuple_fallback, is_singleton_type, try_expanding_enum_to_union, + tuple_fallback, is_singleton_type, try_expanding_sum_type_to_union, true_only, false_only, function_type, get_type_vars, custom_special_method, is_literal_type_like, ) from mypy import message_registry +from mypy.message_registry import ErrorMessage from mypy.subtypes import ( is_subtype, is_equivalent, is_proper_subtype, is_more_precise, restrict_subtype_away, is_subtype_ignoring_tvars, is_callable_compatible, @@ -85,8 +91,8 @@ DEFAULT_LAST_PASS: Final = 1 # Pass numbers start at 0 -DeferredNodeType = Union[FuncDef, LambdaExpr, OverloadedFuncDef, Decorator] -FineGrainedDeferredNodeType = Union[FuncDef, MypyFile, OverloadedFuncDef] +DeferredNodeType: _TypeAlias = Union[FuncDef, LambdaExpr, OverloadedFuncDef, Decorator] +FineGrainedDeferredNodeType: _TypeAlias = Union[FuncDef, MypyFile, OverloadedFuncDef] # A node which is postponed to be processed during the next pass. # In normal mode one can defer functions and methods (also decorated and/or overloaded) @@ -123,7 +129,7 @@ # probably be better to have the dict keyed by the nodes' literal_hash # field instead. -TypeMap = Optional[Dict[Expression, Type]] +TypeMap: _TypeAlias = Optional[Dict[Expression, Type]] # An object that represents either a precise type or a type with an upper bound; # it is important for correct type inference with isinstance. @@ -300,6 +306,11 @@ def check_first_pass(self) -> None: with self.tscope.module_scope(self.tree.fullname): with self.enter_partial_types(), self.binder.top_frame_context(): for d in self.tree.defs: + if (self.binder.is_unreachable() + and self.should_report_unreachable_issues() + and not self.is_raising_or_empty(d)): + self.msg.unreachable_statement(d) + break self.accept(d) assert not self.current_node_deferred @@ -347,9 +358,9 @@ def check_second_pass(self, # (self.pass_num, type_name, node.fullname or node.name)) done.add(node) with self.tscope.class_scope(active_typeinfo) if active_typeinfo \ - else nothing(): + else nullcontext(): with self.scope.push_class(active_typeinfo) if active_typeinfo \ - else nothing(): + else nullcontext(): self.check_partial(node) return True @@ -494,8 +505,26 @@ def check_overlapping_overloads(self, defn: OverloadedFuncDef) -> None: # decorator or if the implementation is untyped -- we gave up on the types. inner_type = get_proper_type(inner_type) if inner_type is not None and not isinstance(inner_type, AnyType): - assert isinstance(inner_type, CallableType) - impl_type = inner_type + if isinstance(inner_type, CallableType): + impl_type = inner_type + elif isinstance(inner_type, Instance): + inner_call = get_proper_type( + analyze_member_access( + name='__call__', + typ=inner_type, + context=defn.impl, + is_lvalue=False, + is_super=False, + is_operator=True, + msg=self.msg, + original_type=inner_type, + chk=self, + ), + ) + if isinstance(inner_call, CallableType): + impl_type = inner_call + if impl_type is None: + self.msg.not_callable(inner_type, defn.impl) is_descriptor_get = defn.info and defn.name == "__get__" for i, item in enumerate(defn.items): @@ -963,13 +992,15 @@ def check_func_def(self, defn: FuncItem, typ: CallableType, name: Optional[str]) ctx = typ self.fail(message_registry.FUNCTION_PARAMETER_CANNOT_BE_COVARIANT, ctx) if typ.arg_kinds[i] == nodes.ARG_STAR: - # builtins.tuple[T] is typing.Tuple[T, ...] - arg_type = self.named_generic_type('builtins.tuple', - [arg_type]) + if not isinstance(arg_type, ParamSpecType): + # builtins.tuple[T] is typing.Tuple[T, ...] + arg_type = self.named_generic_type('builtins.tuple', + [arg_type]) elif typ.arg_kinds[i] == nodes.ARG_STAR2: - arg_type = self.named_generic_type('builtins.dict', - [self.str_type(), - arg_type]) + if not isinstance(arg_type, ParamSpecType): + arg_type = self.named_generic_type('builtins.dict', + [self.str_type(), + arg_type]) item.arguments[i].variable.type = arg_type # Type check initialization expressions. @@ -1007,10 +1038,9 @@ def check_func_def(self, defn: FuncItem, typ: CallableType, name: Optional[str]) # entirely pass/Ellipsis/raise NotImplementedError. if isinstance(return_type, UninhabitedType): # This is a NoReturn function - self.msg.fail(message_registry.INVALID_IMPLICIT_RETURN, defn) + self.fail(message_registry.INVALID_IMPLICIT_RETURN, defn) else: - self.msg.fail(message_registry.MISSING_RETURN_STATEMENT, defn, - code=codes.RETURN) + self.fail(message_registry.MISSING_RETURN_STATEMENT, defn) self.return_types.pop() @@ -1066,38 +1096,42 @@ def is_unannotated_any(t: Type) -> bool: if fdef.type is None and self.options.disallow_untyped_defs: if (not fdef.arguments or (len(fdef.arguments) == 1 and (fdef.arg_names[0] == 'self' or fdef.arg_names[0] == 'cls'))): - self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef, - code=codes.NO_UNTYPED_DEF) + self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef) if not has_return_statement(fdef) and not fdef.is_generator: self.note('Use "-> None" if function does not return a value', fdef, code=codes.NO_UNTYPED_DEF) else: - self.fail(message_registry.FUNCTION_TYPE_EXPECTED, fdef, - code=codes.NO_UNTYPED_DEF) + self.fail(message_registry.FUNCTION_TYPE_EXPECTED, fdef) elif isinstance(fdef.type, CallableType): ret_type = get_proper_type(fdef.type.ret_type) if is_unannotated_any(ret_type): - self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef, - code=codes.NO_UNTYPED_DEF) + self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef) elif fdef.is_generator: if is_unannotated_any(self.get_generator_return_type(ret_type, fdef.is_coroutine)): - self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef, - code=codes.NO_UNTYPED_DEF) + self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef) elif fdef.is_coroutine and isinstance(ret_type, Instance): if is_unannotated_any(self.get_coroutine_return_type(ret_type)): - self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef, - code=codes.NO_UNTYPED_DEF) + self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef) if any(is_unannotated_any(t) for t in fdef.type.arg_types): - self.fail(message_registry.ARGUMENT_TYPE_EXPECTED, fdef, - code=codes.NO_UNTYPED_DEF) + self.fail(message_registry.ARGUMENT_TYPE_EXPECTED, fdef) def check___new___signature(self, fdef: FuncDef, typ: CallableType) -> None: self_type = fill_typevars_with_any(fdef.info) bound_type = bind_self(typ, self_type, is_classmethod=True) # Check that __new__ (after binding cls) returns an instance # type (or any). - if not isinstance(get_proper_type(bound_type.ret_type), + if isinstance(fdef.info, TypeInfo) and fdef.info.is_metaclass(): + # This is a metaclass, so it must return a new unrelated type. + self.check_subtype( + bound_type.ret_type, + self.type_type(), + fdef, + message_registry.INVALID_NEW_TYPE, + 'returns', + 'but must return a subtype of' + ) + elif not isinstance(get_proper_type(bound_type.ret_type), (AnyType, Instance, TupleType)): self.fail( message_registry.NON_INSTANCE_NEW_TYPE.format( @@ -1365,7 +1399,7 @@ def check_getattr_method(self, typ: Type, context: Context, name: str) -> None: if len(self.scope.stack) == 1: # module scope if name == '__getattribute__': - self.msg.fail(message_registry.MODULE_LEVEL_GETATTRIBUTE, context) + self.fail(message_registry.MODULE_LEVEL_GETATTRIBUTE, context) return # __getattr__ is fine at the module level as of Python 3.7 (PEP 562). We could # show an error for Python < 3.7, but that would be annoying in code that supports @@ -1408,7 +1442,7 @@ def expand_typevars(self, defn: FuncItem, if defn.info: # Class type variables tvars += defn.info.defn.type_vars or [] - # TODO(shantanu): audit for paramspec + # TODO(PEP612): audit for paramspec for tvar in tvars: if isinstance(tvar, TypeVarType) and tvar.values: subst.append([(tvar.id, value) for value in tvar.values]) @@ -1520,6 +1554,16 @@ def check_method_override_for_base_with_name( original_type = self.function_type(original_node) elif isinstance(original_node, Decorator): original_type = self.function_type(original_node.func) + elif isinstance(original_node, Var): + # Super type can define method as an attribute. + # See https://github.com/python/mypy/issues/10134 + + # We also check that sometimes `original_node.type` is None. + # This is the case when we use something like `__hash__ = None`. + if original_node.type is not None: + original_type = get_proper_type(original_node.type) + else: + original_type = NoneType() else: assert False, str(base_attr.node) if isinstance(original_node, (FuncDef, OverloadedFuncDef)): @@ -1857,7 +1901,7 @@ def check_protocol_variance(self, defn: ClassDef) -> None: expected = CONTRAVARIANT else: expected = INVARIANT - if expected != tvar.variance: + if isinstance(tvar, TypeVarType) and expected != tvar.variance: self.msg.bad_proto_variance(tvar.variance, tvar.name, expected, defn) def check_multiple_inheritance(self, typ: TypeInfo) -> None: @@ -2473,13 +2517,14 @@ def check_compatibility_final_super(self, node: Var, self.msg.cant_override_final(node.name, base.name, node) return False if node.is_final: + if base.fullname in ENUM_BASES and node.name in ENUM_SPECIAL_PROPS: + return True self.check_if_final_var_override_writable(node.name, base_node, node) return True def check_if_final_var_override_writable(self, name: str, - base_node: - Optional[Node], + base_node: Optional[Node], ctx: Context) -> None: """Check that a final variable doesn't override writeable attribute. @@ -2542,7 +2587,7 @@ def check_final(self, name = lv.node.name cls = self.scope.active_class() if cls is not None: - # Theses additional checks exist to give more error messages + # These additional checks exist to give more error messages # even if the final attribute was overridden with a new symbol # (which is itself an error)... for base in cls.mro[1:]: @@ -2586,7 +2631,7 @@ def check_assignment_to_slots(self, lvalue: Lvalue) -> None: return self.fail( - 'Trying to assign name "{}" that is not in "__slots__" of type "{}"'.format( + message_registry.NAME_NOT_IN_SLOTS.format( lvalue.name, inst.type.fullname, ), lvalue, @@ -2630,16 +2675,16 @@ def check_assignment_to_multiple_lvalues(self, lvalues: List[Lvalue], rvalue: Ex elif self.type_is_iterable(typs) and isinstance(typs, Instance): if (iterable_type is not None and iterable_type != self.iterable_item_type(typs)): - self.fail("Contiguous iterable with same type expected", context) + self.fail(message_registry.CONTIGUOUS_ITERABLE_EXPECTED, context) else: if last_idx is None or last_idx + 1 == idx_rval: rvalues.append(rval) last_idx = idx_rval iterable_type = self.iterable_item_type(typs) else: - self.fail("Contiguous iterable with same type expected", context) + self.fail(message_registry.CONTIGUOUS_ITERABLE_EXPECTED, context) else: - self.fail("Invalid type '{}' for *expr (iterable expected)".format(typs), + self.fail(message_registry.ITERABLE_TYPE_EXPECTED.format(typs), context) else: rvalues.append(rval) @@ -3158,9 +3203,12 @@ def check_member_assignment(self, instance_type: Type, attribute_type: Type, code=codes.ASSIGNMENT) return rvalue_type, attribute_type, True - get_type = analyze_descriptor_access( - instance_type, attribute_type, self.named_type, - self.msg, context, chk=self) + mx = MemberContext( + is_lvalue=False, is_super=False, is_operator=False, + original_type=instance_type, context=context, self_type=None, + msg=self.msg, chk=self, + ) + get_type = analyze_descriptor_access(attribute_type, mx) 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, @@ -3172,12 +3220,12 @@ def check_member_assignment(self, instance_type: Type, attribute_type: Type, dunder_set = attribute_type.type.get_method('__set__') if dunder_set is None: - self.msg.fail(message_registry.DESCRIPTOR_SET_NOT_CALLABLE.format(attribute_type), - context) + self.fail(message_registry.DESCRIPTOR_SET_NOT_CALLABLE.format(attribute_type), context) return AnyType(TypeOfAny.from_error), get_type, False - function = function_type(dunder_set, self.named_type('builtins.function')) - bound_method = bind_self(function, attribute_type) + bound_method = analyze_decorator_or_funcbase_access( + defn=dunder_set, itype=attribute_type, info=attribute_type.type, + self_type=attribute_type, name='__set__', mx=mx) typ = map_instance_to_supertype(attribute_type, dunder_set.info) dunder_set_type = expand_type_by_instance(bound_method, typ) @@ -3235,25 +3283,9 @@ def check_indexed_assignment(self, lvalue: IndexExpr, """ self.try_infer_partial_type_from_indexed_assignment(lvalue, rvalue) basetype = get_proper_type(self.expr_checker.accept(lvalue.base)) - if (isinstance(basetype, TypedDictType) or (isinstance(basetype, TypeVarType) - and isinstance(get_proper_type(basetype.upper_bound), TypedDictType))): - if isinstance(basetype, TypedDictType): - typed_dict_type = basetype - else: - upper_bound_type = get_proper_type(basetype.upper_bound) - assert isinstance(upper_bound_type, TypedDictType) - typed_dict_type = upper_bound_type - item_type = self.expr_checker.visit_typeddict_index_expr(typed_dict_type, lvalue.index) - method_type: Type = CallableType( - arg_types=[self.named_type('builtins.str'), item_type], - arg_kinds=[ARG_POS, ARG_POS], - arg_names=[None, None], - ret_type=NoneType(), - fallback=self.named_type('builtins.function') - ) - else: - method_type = self.expr_checker.analyze_external_member_access( - '__setitem__', basetype, context) + method_type = self.expr_checker.analyze_external_member_access( + '__setitem__', basetype, lvalue) + lvalue.method_type = method_type self.expr_checker.check_method_call( '__setitem__', basetype, method_type, [lvalue.index, rvalue], @@ -3356,8 +3388,7 @@ def check_return_stmt(self, s: ReturnStmt) -> None: # Functions returning a value of type None are allowed to have a None return. if is_lambda or isinstance(typ, NoneType): return - self.fail(message_registry.NO_RETURN_VALUE_EXPECTED, s, - code=codes.RETURN_VALUE) + self.fail(message_registry.NO_RETURN_VALUE_EXPECTED, s) else: self.check_subtype( subtype_label='got', @@ -3379,7 +3410,7 @@ def check_return_stmt(self, s: ReturnStmt) -> None: return if self.in_checked_function(): - self.fail(message_registry.RETURN_VALUE_EXPECTED, s, code=codes.RETURN_VALUE) + self.fail(message_registry.RETURN_VALUE_EXPECTED, s) def visit_if_stmt(self, s: IfStmt) -> None: """Type check an if statement.""" @@ -3850,8 +3881,21 @@ def visit_print_stmt(self, s: PrintStmt) -> None: if s.target: target_type = get_proper_type(self.expr_checker.accept(s.target)) if not isinstance(target_type, NoneType): - # TODO: Also verify the type of 'write'. - self.expr_checker.analyze_external_member_access('write', target_type, s.target) + write_type = self.expr_checker.analyze_external_member_access( + 'write', target_type, s.target) + required_type = CallableType( + arg_types=[self.named_type('builtins.str')], + arg_kinds=[ARG_POS], + arg_names=[None], + ret_type=AnyType(TypeOfAny.implementation_artifact), + fallback=self.named_type('builtins.function'), + ) + # This has to be hard-coded, since it is a syntax pattern, not a function call. + if not is_subtype(write_type, required_type): + self.fail(message_registry.PYTHON2_PRINT_FILE_TYPE.format( + write_type, + required_type, + ), s.target) def visit_break_stmt(self, s: BreakStmt) -> None: self.binder.handle_break() @@ -4151,38 +4195,27 @@ def _check_for_truthy_type(self, t: Type, expr: Expression) -> None: return def format_expr_type() -> str: + typ = format_type(t) if isinstance(expr, MemberExpr): - return f'Member "{expr.name}" has type "{t}"' + return f'Member "{expr.name}" has type {typ}' elif isinstance(expr, RefExpr) and expr.fullname: - return f'"{expr.fullname}" has type "{t}"' + return f'"{expr.fullname}" has type {typ}' elif isinstance(expr, CallExpr): if isinstance(expr.callee, MemberExpr): - return f'"{expr.callee.name}" returns "{t}"' + return f'"{expr.callee.name}" returns {typ}' elif isinstance(expr.callee, RefExpr) and expr.callee.fullname: - return f'"{expr.callee.fullname}" returns "{t}"' - return f'Call returns "{t}"' + return f'"{expr.callee.fullname}" returns {typ}' + return f'Call returns {typ}' else: - return f'Expression has type "{t}"' + return f'Expression has type {typ}' if isinstance(t, FunctionLike): - self.msg.fail( - f'Function "{t}" could always be true in boolean context', expr, - code=codes.TRUTHY_BOOL, - ) + self.fail(message_registry.FUNCTION_ALWAYS_TRUE.format(format_type(t)), expr) elif isinstance(t, UnionType): - self.msg.fail( - f"{format_expr_type()} of which no members implement __bool__ or __len__ " - "so it could always be true in boolean context", - expr, - code=codes.TRUTHY_BOOL, - ) + self.fail(message_registry.TYPE_ALWAYS_TRUE_UNIONTYPE.format(format_expr_type()), + expr) else: - self.msg.fail( - f'{format_expr_type()} which does not implement __bool__ or __len__ ' - 'so it could always be true in boolean context', - expr, - code=codes.TRUTHY_BOOL, - ) + self.fail(message_registry.TYPE_ALWAYS_TRUE.format(format_expr_type()), expr) def find_type_equals_check(self, node: ComparisonExpr, expr_indices: List[int] ) -> Tuple[TypeMap, TypeMap]: @@ -4274,7 +4307,8 @@ def find_isinstance_check(self, node: Expression If either of the values in the tuple is None, then that particular branch can never occur. - Guaranteed to not return None, None. (But may return {}, {}) + May return {}, {}. + Can return None, None in situations involving NoReturn. """ if_map, else_map = self.find_isinstance_check_helper(node) new_if_map = self.propagate_up_typemap_info(self.type_map, if_map) @@ -4285,12 +4319,10 @@ def find_isinstance_check_helper(self, node: Expression) -> Tuple[TypeMap, TypeM type_map = self.type_map if is_true_literal(node): return {}, None - elif is_false_literal(node): + if is_false_literal(node): return None, {} - elif isinstance(node, CallExpr): - self._check_for_truthy_type(type_map[node], node) - if len(node.args) == 0: - return {}, {} + + if isinstance(node, CallExpr) and len(node.args) != 0: expr = collapse_walrus(node.args[0]) if refers_to_fullname(node.callee, 'builtins.isinstance'): if len(node.args) != 2: # the error will be reported elsewhere @@ -4316,7 +4348,7 @@ def find_isinstance_check_helper(self, node: Expression) -> Tuple[TypeMap, TypeM if node.callee.type_guard is not None: # TODO: Follow keyword args or *args, **kwargs if node.arg_kinds[0] != nodes.ARG_POS: - self.fail("Type guard requires positional argument", node) + self.fail(message_registry.TYPE_GUARD_POS_ARG_REQUIRED, node) return {}, {} if literal(expr) == LITERAL_TYPE: # Note: we wrap the target type, so that we can special case later. @@ -4471,43 +4503,67 @@ def has_no_custom_eq_checks(t: Type) -> bool: return reduce_conditional_maps(partial_type_maps) elif isinstance(node, AssignmentExpr): - return self.find_isinstance_check_helper(node.target) - elif isinstance(node, RefExpr): - # Restrict the type of the variable to True-ish/False-ish in the if and else branches - # respectively - vartype = type_map[node] - self._check_for_truthy_type(vartype, node) - if_type: Type = true_only(vartype) - else_type: Type = false_only(vartype) - ref: Expression = node - if_map = ({ref: if_type} if not isinstance(get_proper_type(if_type), UninhabitedType) - else None) - else_map = ({ref: else_type} if not isinstance(get_proper_type(else_type), - UninhabitedType) - else None) - return if_map, else_map + if_map = {} + else_map = {} + + if_assignment_map, else_assignment_map = self.find_isinstance_check(node.target) + + if if_assignment_map is not None: + if_map.update(if_assignment_map) + if else_assignment_map is not None: + else_map.update(else_assignment_map) + + if_condition_map, else_condition_map = self.find_isinstance_check(node.value) + + if if_condition_map is not None: + if_map.update(if_condition_map) + if else_condition_map is not None: + else_map.update(else_condition_map) + + return ( + (None if if_assignment_map is None or if_condition_map is None else if_map), + (None if else_assignment_map is None or else_condition_map is None else else_map), + ) elif isinstance(node, OpExpr) and node.op == 'and': - left_if_vars, left_else_vars = self.find_isinstance_check_helper(node.left) - right_if_vars, right_else_vars = self.find_isinstance_check_helper(node.right) + left_if_vars, left_else_vars = self.find_isinstance_check(node.left) + right_if_vars, right_else_vars = self.find_isinstance_check(node.right) # (e1 and e2) is true if both e1 and e2 are true, # and false if at least one of e1 and e2 is false. return (and_conditional_maps(left_if_vars, right_if_vars), or_conditional_maps(left_else_vars, right_else_vars)) elif isinstance(node, OpExpr) and node.op == 'or': - left_if_vars, left_else_vars = self.find_isinstance_check_helper(node.left) - right_if_vars, right_else_vars = self.find_isinstance_check_helper(node.right) + left_if_vars, left_else_vars = self.find_isinstance_check(node.left) + right_if_vars, right_else_vars = self.find_isinstance_check(node.right) # (e1 or e2) is true if at least one of e1 or e2 is true, # and false if both e1 and e2 are false. return (or_conditional_maps(left_if_vars, right_if_vars), and_conditional_maps(left_else_vars, right_else_vars)) elif isinstance(node, UnaryExpr) and node.op == 'not': - left, right = self.find_isinstance_check_helper(node.expr) + left, right = self.find_isinstance_check(node.expr) return right, left - # Not a supported isinstance check - return {}, {} + # Restrict the type of the variable to True-ish/False-ish in the if and else branches + # respectively + original_vartype = type_map[node] + self._check_for_truthy_type(original_vartype, node) + vartype = try_expanding_sum_type_to_union(original_vartype, "builtins.bool") + + if_type = true_only(vartype) # type: Type + else_type = false_only(vartype) # type: Type + ref = node # type: Expression + if_map = ( + {ref: if_type} + if not isinstance(get_proper_type(if_type), UninhabitedType) + else None + ) + else_map = ( + {ref: else_type} + if not isinstance(get_proper_type(else_type), UninhabitedType) + else None + ) + return if_map, else_map def propagate_up_typemap_info(self, existing_types: Mapping[Expression, Type], @@ -4583,7 +4639,6 @@ def refine_parent_types(self, def replay_lookup(new_parent_type: ProperType) -> Optional[Type]: msg_copy = self.msg.clean_copy() - msg_copy.disable_count = 0 member_type = analyze_member_access( name=member_name, typ=new_parent_type, @@ -4655,8 +4710,7 @@ def replay_lookup(new_parent_type: ProperType) -> Optional[Type]: # Take each element in the parent union and replay the original lookup procedure # to figure out which parents are compatible. new_parent_types = [] - for item in parent_type.items: - item = get_proper_type(item) + for item in union_items(parent_type): member_type = replay_lookup(item) if member_type is None: # We were unable to obtain the member type. So, we give up on refining this @@ -4675,8 +4729,6 @@ def replay_lookup(new_parent_type: ProperType) -> Optional[Type]: expr = parent_expr expr_type = output[parent_expr] = make_simplified_union(new_parent_types) - return output - def refine_identity_comparison_expression(self, operands: List[Expression], operand_types: List[Type], @@ -4770,10 +4822,11 @@ def refine_identity_comparison_expression(self, if singleton_index == -1: singleton_index = possible_target_indices[-1] - enum_name = None + sum_type_name = None target = get_proper_type(target) - if isinstance(target, LiteralType) and target.is_enum_literal(): - enum_name = target.fallback.type.fullname + if (isinstance(target, LiteralType) and + (target.is_enum_literal() or isinstance(target.value, bool))): + sum_type_name = target.fallback.type.fullname target_type = [TypeRange(target, is_upper_bound=False)] @@ -4794,8 +4847,8 @@ def refine_identity_comparison_expression(self, expr = operands[i] expr_type = coerce_to_literal(operand_types[i]) - if enum_name is not None: - expr_type = try_expanding_enum_to_union(expr_type, enum_name) + if sum_type_name is not None: + expr_type = try_expanding_sum_type_to_union(expr_type, sum_type_name) # We intentionally use 'conditional_type_map' directly here instead of # 'self.conditional_type_map_with_intersection': we only compute ad-hoc @@ -4843,7 +4896,7 @@ def check_subtype(self, subtype: Type, supertype: Type, context: Context, - msg: str = message_registry.INCOMPATIBLE_TYPES, + msg: Union[str, ErrorMessage] = message_registry.INCOMPATIBLE_TYPES, subtype_label: Optional[str] = None, supertype_label: Optional[str] = None, *, @@ -4853,9 +4906,14 @@ def check_subtype(self, if is_subtype(subtype, supertype): return True + if isinstance(msg, ErrorMessage): + msg_text = msg.value + code = msg.code + else: + msg_text = msg subtype = get_proper_type(subtype) supertype = get_proper_type(supertype) - if self.msg.try_report_long_tuple_assignment_error(subtype, supertype, context, msg, + if self.msg.try_report_long_tuple_assignment_error(subtype, supertype, context, msg_text, subtype_label, supertype_label, code=code): return False if self.should_suppress_optional_error([subtype]): @@ -4874,8 +4932,9 @@ def check_subtype(self, if isinstance(subtype, Instance) and isinstance(supertype, Instance): notes = append_invariance_notes([], subtype, supertype) if extra_info: - msg += ' (' + ', '.join(extra_info) + ')' - self.fail(msg, context, code=code) + msg_text += ' (' + ', '.join(extra_info) + ')' + + self.fail(ErrorMessage(msg_text, code=code), context) for note in notes: self.msg.note(note, context, code=code) if note_msg: @@ -4964,9 +5023,8 @@ def in_checked_function(self) -> bool: or not self.dynamic_funcs or not self.dynamic_funcs[-1]) - def lookup(self, name: str, kind: int) -> SymbolTableNode: + def lookup(self, name: str) -> SymbolTableNode: """Look up a definition from the symbol table with the given name. - TODO remove kind argument """ if name in self.globals: return self.globals[name] @@ -4980,7 +5038,7 @@ def lookup(self, name: str, kind: int) -> SymbolTableNode: def lookup_qualified(self, name: str) -> SymbolTableNode: if '.' not in name: - return self.lookup(name, GDEF) # FIX kind + return self.lookup(name) else: parts = name.split('.') n = self.modules[parts[0]] @@ -5147,8 +5205,12 @@ def temp_node(self, t: Type, context: Optional[Context] = None) -> TempNode: """Create a temporary node with the given, fixed type.""" return TempNode(t, context=context) - def fail(self, msg: str, context: Context, *, code: Optional[ErrorCode] = None) -> None: + def fail(self, msg: Union[str, ErrorMessage], context: Context, *, + code: Optional[ErrorCode] = None) -> None: """Produce an error message.""" + if isinstance(msg, ErrorMessage): + self.msg.fail(msg.value, context, code=msg.code) + return self.msg.fail(msg, context, code=code) def note(self, @@ -5308,9 +5370,11 @@ def conditional_type_map(expr: Expression, return None, {} else: # we can only restrict when the type is precise, not bounded - proposed_precise_type = UnionType([type_range.item - for type_range in proposed_type_ranges - if not type_range.is_upper_bound]) + proposed_precise_type = UnionType.make_union([ + type_range.item + for type_range in proposed_type_ranges + if not type_range.is_upper_bound + ]) remaining_type = restrict_subtype_away(current_type, proposed_precise_type) return {expr: proposed_type}, {expr: remaining_type} else: @@ -5352,7 +5416,7 @@ class Foo(Enum): B = 2 ...and if the expression 'Foo' referred to that enum within the current type context, - then the expression 'Foo.A' would be a a literal enum. However, if we did 'a = Foo.A', + then the expression 'Foo.A' would be a literal enum. However, if we did 'a = Foo.A', then the variable 'a' would *not* be a literal enum. We occasionally special-case expressions like 'Foo.A' and treat them as a single primitive @@ -5875,11 +5939,6 @@ def push_class(self, info: TypeInfo) -> Iterator[None]: self.stack.pop() -@contextmanager -def nothing() -> Iterator[None]: - yield - - TKey = TypeVar('TKey') TValue = TypeVar('TValue') @@ -6094,6 +6153,12 @@ def is_untyped_decorator(typ: Optional[Type]) -> bool: elif isinstance(typ, Instance): method = typ.type.get_method('__call__') if method: + if isinstance(method, Decorator): + return ( + is_untyped_decorator(method.func.type) + or is_untyped_decorator(method.var.type) + ) + if isinstance(method.type, Overloaded): return any(is_untyped_decorator(item) for item in method.type.items) else: diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 30db1e8ac87d..dfac5be27d95 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -1,24 +1,24 @@ """Expression type checker. This file is conceptually part of TypeChecker.""" -from mypy.util import unnamed_function from mypy.backports import OrderedDict, nullcontext from contextlib import contextmanager import itertools from typing import ( Any, cast, Dict, Set, List, Tuple, Callable, Union, Optional, Sequence, Iterator ) -from typing_extensions import ClassVar, Final, overload +from typing_extensions import ClassVar, Final, overload, TypeAlias as _TypeAlias from mypy.errors import report_internal_error from mypy.typeanal import ( has_any_from_unimported_type, check_for_explicit_any, set_any_tvars, expand_type_alias, make_optional_type, ) +from mypy.semanal_enum import ENUM_BASES from mypy.types import ( Type, AnyType, CallableType, Overloaded, NoneType, TypeVarType, TupleType, TypedDictType, Instance, ErasedType, UnionType, PartialType, DeletedType, UninhabitedType, TypeType, TypeOfAny, LiteralType, LiteralValue, - is_named_instance, FunctionLike, ParamSpecType, + is_named_instance, FunctionLike, ParamSpecType, ParamSpecFlavor, StarType, is_optional, remove_optional, is_generic_instance, get_proper_type, ProperType, get_proper_types, flatten_nested_unions ) @@ -45,7 +45,9 @@ from mypy.maptype import map_instance_to_supertype from mypy.messages import MessageBuilder from mypy import message_registry -from mypy.infer import infer_type_arguments, infer_function_type_arguments +from mypy.infer import ( + ArgumentInferContext, infer_type_arguments, infer_function_type_arguments, +) from mypy import join from mypy.meet import narrow_declared_type, is_overlapping_types from mypy.subtypes import is_subtype, is_proper_subtype, is_equivalent, non_method_protocol_members @@ -64,26 +66,31 @@ FunctionContext, FunctionSigContext, ) from mypy.typeops import ( - tuple_fallback, make_simplified_union, true_only, false_only, erase_to_union_or_bound, - function_type, callable_type, try_getting_str_literals, custom_special_method, + try_expanding_sum_type_to_union, tuple_fallback, make_simplified_union, + true_only, false_only, erase_to_union_or_bound, function_type, + callable_type, try_getting_str_literals, custom_special_method, is_literal_type_like, ) +from mypy.message_registry import ErrorMessage import mypy.errorcodes as codes # Type of callback user for checking individual function arguments. See # check_args() below for details. -ArgChecker = Callable[[Type, - Type, - ArgKind, - Type, - int, - int, - CallableType, - Optional[Type], - Context, - Context, - MessageBuilder], - None] +ArgChecker: _TypeAlias = Callable[[ + Type, + Type, + ArgKind, + Type, + int, + int, + CallableType, + Optional[Type], + Context, + Context, + MessageBuilder, + ], + None, +] # Maximum nesting level for math union in overloads, setting this to large values # may cause performance issues. The reason is that although union math algorithm we use @@ -94,11 +101,15 @@ # Types considered safe for comparisons with --strict-equality due to known behaviour of __eq__. # NOTE: All these types are subtypes of AbstractSet. -OVERLAPPING_TYPES_WHITELIST: Final = [ +OVERLAPPING_TYPES_ALLOWLIST: Final = [ "builtins.set", "builtins.frozenset", "typing.KeysView", "typing.ItemsView", + "builtins._dict_keys", + "builtins._dict_items", + "_collections_abc.dict_keys", + "_collections_abc.dict_items", ] @@ -335,12 +346,6 @@ def visit_call_expr_inner(self, e: CallExpr, allow_none_return: bool = False) -> and callee_type.implicit): self.msg.untyped_function_call(callee_type, e) - if (isinstance(callee_type, CallableType) - and not callee_type.is_type_obj() - and unnamed_function(callee_type.name)): - self.msg.underscore_function_call(e) - return AnyType(TypeOfAny.from_error) - # Figure out the full name of the callee for plugin lookup. object_type = None member = None @@ -989,9 +994,7 @@ def check_callable_call(self, ret_type = get_proper_type(callee.ret_type) if callee.is_type_obj() and isinstance(ret_type, Instance): callable_name = ret_type.type.fullname - if (isinstance(callable_node, RefExpr) - and callable_node.fullname in ('enum.Enum', 'enum.IntEnum', - 'enum.Flag', 'enum.IntFlag')): + if isinstance(callable_node, RefExpr) and callable_node.fullname in ENUM_BASES: # An Enum() call that failed SemanticAnalyzerPass2.check_enum_call(). return callee.ret_type, callee @@ -1015,11 +1018,31 @@ def check_callable_call(self, lambda i: self.accept(args[i])) if callee.is_generic(): + need_refresh = any(isinstance(v, ParamSpecType) for v in callee.variables) callee = freshen_function_type_vars(callee) callee = self.infer_function_type_arguments_using_context( callee, context) callee = self.infer_function_type_arguments( callee, args, arg_kinds, formal_to_actual, context) + if need_refresh: + # Argument kinds etc. may have changed due to + # ParamSpec variables being replaced with an arbitrary + # number of arguments; recalculate actual-to-formal map + formal_to_actual = map_actuals_to_formals( + arg_kinds, arg_names, + callee.arg_kinds, callee.arg_names, + lambda i: self.accept(args[i])) + + param_spec = callee.param_spec() + if param_spec is not None and arg_kinds == [ARG_STAR, ARG_STAR2]: + arg1 = self.accept(args[0]) + arg2 = self.accept(args[1]) + if (isinstance(arg1, ParamSpecType) + and isinstance(arg2, ParamSpecType) + and arg1.flavor == ParamSpecFlavor.ARGS + and arg2.flavor == ParamSpecFlavor.KWARGS + and arg1.id == arg2.id == param_spec.id): + return callee.ret_type, callee arg_types = self.infer_arg_types_in_context( callee, args, arg_kinds, formal_to_actual) @@ -1235,6 +1258,7 @@ def infer_function_type_arguments(self, callee_type: CallableType, inferred_args = infer_function_type_arguments( callee_type, pass1_args, arg_kinds, formal_to_actual, + context=self.argument_infer_context(), strict=self.chk.in_checked_function()) if 2 in arg_pass_nums: @@ -1256,7 +1280,7 @@ def infer_function_type_arguments(self, callee_type: CallableType, if isinstance(first_arg, (NoneType, UninhabitedType)): inferred_args[0] = self.named_type('builtins.str') elif not first_arg or not is_subtype(self.named_type('builtins.str'), first_arg): - self.msg.fail(message_registry.KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE, + self.chk.fail(message_registry.KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE, context) else: # In dynamically typed functions use implicit 'Any' types for @@ -1296,10 +1320,18 @@ def infer_function_type_arguments_pass2( callee_type, args, arg_kinds, formal_to_actual) inferred_args = infer_function_type_arguments( - callee_type, arg_types, arg_kinds, formal_to_actual) + callee_type, arg_types, arg_kinds, formal_to_actual, + context=self.argument_infer_context(), + ) return callee_type, inferred_args + def argument_infer_context(self) -> ArgumentInferContext: + return ArgumentInferContext( + self.chk.named_type('typing.Mapping'), + self.chk.named_type('typing.Iterable'), + ) + def get_arg_infer_passes(self, arg_types: List[Type], formal_to_actual: List[List[int]], num_actuals: int) -> List[int]: @@ -1474,7 +1506,7 @@ def check_argument_types(self, messages = messages or self.msg check_arg = check_arg or self.check_arg # Keep track of consumed tuple *arg items. - mapper = ArgTypeExpander() + mapper = ArgTypeExpander(self.argument_infer_context()) for i, actuals in enumerate(formal_to_actual): for actual in actuals: actual_type = arg_types[actual] @@ -1632,15 +1664,14 @@ def check_overload_call(self, else: code = codes.OPERATOR arg_messages.no_variant_matches_arguments( - plausible_targets, callee, arg_types, context, code=code) + callee, arg_types, context, code=code) result = self.check_call(target, args, arg_kinds, context, arg_names, arg_messages=arg_messages, callable_name=callable_name, object_type=object_type) if union_interrupted: - self.chk.fail("Not all union combinations were tried" - " because there are too many unions", context) + self.chk.fail(message_registry.TOO_MANY_UNION_COMBINATIONS, context) return result def plausible_overload_call_targets(self, @@ -2214,10 +2245,15 @@ def visit_comparison_expr(self, e: ComparisonExpr) -> Type: # Keep track of whether we get type check errors (these won't be reported, they # are just to verify whether something is valid typing wise). - local_errors = self.msg.copy() - local_errors.disable_count = 0 + local_errors = self.msg.clean_copy() _, method_type = self.check_method_call_by_name( - '__contains__', right_type, [left], [ARG_POS], e, local_errors) + method='__contains__', + base_type=right_type, + args=[left], + arg_kinds=[ARG_POS], + context=e, + local_errors=local_errors, + ) sub_result = self.bool_type() # Container item type for strict type overlap checks. Note: we need to only # check for nominal type, because a usual "Unsupported operands for in" @@ -2357,8 +2393,8 @@ def dangerous_comparison(self, left: Type, right: Type, return False if isinstance(left, Instance) and isinstance(right, Instance): # Special case some builtin implementations of AbstractSet. - if (left.type.fullname in OVERLAPPING_TYPES_WHITELIST and - right.type.fullname in OVERLAPPING_TYPES_WHITELIST): + if (left.type.fullname in OVERLAPPING_TYPES_ALLOWLIST and + right.type.fullname in OVERLAPPING_TYPES_ALLOWLIST): abstract_set = self.chk.lookup_typeinfo('typing.AbstractSet') left = map_instance_to_supertype(left, abstract_set) right = map_instance_to_supertype(right, abstract_set) @@ -2466,12 +2502,6 @@ def check_op_reversible(self, right_expr: Expression, context: Context, msg: MessageBuilder) -> Tuple[Type, Type]: - def make_local_errors() -> MessageBuilder: - """Creates a new MessageBuilder object.""" - local_errors = msg.clean_copy() - local_errors.disable_count = 0 - return local_errors - def lookup_operator(op_name: str, base_type: Type) -> Optional[Type]: """Looks up the given operator and returns the corresponding type, if it exists.""" @@ -2483,7 +2513,7 @@ def lookup_operator(op_name: str, base_type: Type) -> Optional[Type]: if not self.has_member(base_type, op_name): return None - local_errors = make_local_errors() + local_errors = msg.clean_copy() member = analyze_member_access( name=op_name, @@ -2614,7 +2644,7 @@ def lookup_definer(typ: Instance, attr_name: str) -> Optional[str]: errors = [] results = [] for method, obj, arg in variants: - local_errors = make_local_errors() + local_errors = msg.clean_copy() result = self.check_method_call( op_name, obj, method, [arg], [ARG_POS], context, local_errors) if local_errors.is_errors(): @@ -2636,7 +2666,7 @@ def lookup_definer(typ: Instance, attr_name: str) -> Optional[str]: # call the __op__ method (even though it's missing). if not variants: - local_errors = make_local_errors() + local_errors = msg.clean_copy() result = self.check_method_call_by_name( op_name, left_type, [right_expr], [ARG_POS], context, local_errors) @@ -2683,7 +2713,6 @@ def check_op(self, method: str, base_type: Type, # just the left ones. (Mypy can sometimes perform some more precise inference # if we leave the right operands a union -- see testOperatorWithEmptyListAndSum.) msg = self.msg.clean_copy() - msg.disable_count = 0 all_results = [] all_inferred = [] @@ -2718,11 +2747,13 @@ def check_op(self, method: str, base_type: Type, right_variants = [(right_type, arg)] right_type = get_proper_type(right_type) if isinstance(right_type, UnionType): - right_variants = [(item, TempNode(item, context=context)) - for item in flatten_nested_unions(right_type.relevant_items(), - handle_type_alias_type=True)] + right_variants = [ + (item, TempNode(item, context=context)) + for item in flatten_nested_unions(right_type.relevant_items(), + handle_type_alias_type=True) + ] + msg = self.msg.clean_copy() - msg.disable_count = 0 all_results = [] all_inferred = [] @@ -2785,6 +2816,9 @@ def check_boolean_op(self, e: OpExpr, context: Context) -> Type: # '[1] or []' are inferred correctly. ctx = self.type_context[-1] left_type = self.accept(e.left, ctx) + expanded_left_type = try_expanding_sum_type_to_union( + self.accept(e.left, ctx), "builtins.bool" + ) assert e.op in ('and', 'or') # Checked by visit_op_expr @@ -2819,23 +2853,26 @@ def check_boolean_op(self, e: OpExpr, context: Context) -> Type: # to be unreachable and therefore any errors found in the right branch # should be suppressed. with (self.msg.disable_errors() if right_map is None else nullcontext()): - right_type = self.analyze_cond_branch(right_map, e.right, left_type) + right_type = self.analyze_cond_branch(right_map, e.right, expanded_left_type) + + if left_map is None and right_map is None: + return UninhabitedType() if right_map is None: # The boolean expression is statically known to be the left value - assert left_map is not None # find_isinstance_check guarantees this + assert left_map is not None return left_type if left_map is None: # The boolean expression is statically known to be the right value - assert right_map is not None # find_isinstance_check guarantees this + assert right_map is not None return right_type if e.op == 'and': - restricted_left_type = false_only(left_type) - result_is_left = not left_type.can_be_true + restricted_left_type = false_only(expanded_left_type) + result_is_left = not expanded_left_type.can_be_true elif e.op == 'or': - restricted_left_type = true_only(left_type) - result_is_left = not left_type.can_be_false + restricted_left_type = true_only(expanded_left_type) + result_is_left = not expanded_left_type.can_be_false if isinstance(restricted_left_type, UninhabitedType): # The left operand can never be the result @@ -2945,6 +2982,9 @@ def visit_index_with_type(self, left_type: Type, e: IndexExpr, elif (isinstance(left_type, CallableType) and left_type.is_type_obj() and left_type.type_object().is_enum): return self.visit_enum_index_expr(left_type.type_object(), e.index, e) + elif (isinstance(left_type, TypeVarType) + and not self.has_member(left_type.upper_bound, "__getitem__")): + return self.visit_index_with_type(left_type.upper_bound, e, original_type) else: result, method_type = self.check_method_call_by_name( '__getitem__', left_type, [e.index], [ARG_POS], e, @@ -3506,6 +3546,9 @@ def visit_lambda_expr(self, e: LambdaExpr) -> Type: # Type check everything in the body except for the final return # statement (it can contain tuple unpacking before return). with self.chk.scope.push_function(e): + # Lambdas can have more than one element in body, + # when we add "fictional" AssigmentStatement nodes, like in: + # `lambda (a, b): a` for stmt in e.body.body[:-1]: stmt.accept(self.chk) # Only type check the return expression, not the return statement. @@ -3553,20 +3596,27 @@ def infer_lambda_type_using_context(self, e: LambdaExpr) -> Tuple[Optional[Calla callable_ctx = get_proper_type(replace_meta_vars(ctx, ErasedType())) assert isinstance(callable_ctx, CallableType) + if callable_ctx.type_guard is not None: + # Lambda's return type cannot be treated as a `TypeGuard`, + # because it is implicit. And `TypeGuard`s must be explicit. + # See https://github.com/python/mypy/issues/9927 + return None, None + arg_kinds = [arg.kind for arg in e.arguments] - if callable_ctx.is_ellipsis_args: + if callable_ctx.is_ellipsis_args or ctx.param_spec() is not None: # Fill in Any arguments to match the arguments of the lambda. callable_ctx = callable_ctx.copy_modified( is_ellipsis_args=False, arg_types=[AnyType(TypeOfAny.special_form)] * len(arg_kinds), arg_kinds=arg_kinds, - arg_names=[None] * len(arg_kinds) + arg_names=e.arg_names[:], ) if ARG_STAR in arg_kinds or ARG_STAR2 in arg_kinds: # TODO treat this case appropriately return callable_ctx, None + if callable_ctx.arg_kinds != arg_kinds: # Incompatible context; cannot use it to infer types. self.chk.fail(message_registry.CANNOT_INFER_LAMBDA_TYPE, e) @@ -3643,7 +3693,7 @@ def _super_arg_types(self, e: SuperExpr) -> Union[Type, Tuple[Type, Type]]: return AnyType(TypeOfAny.unannotated) elif len(e.call.args) == 0: if self.chk.options.python_version[0] == 2: - self.chk.fail(message_registry.TOO_FEW_ARGS_FOR_SUPER, e, code=codes.CALL_ARG) + self.chk.fail(message_registry.TOO_FEW_ARGS_FOR_SUPER, e) return AnyType(TypeOfAny.from_error) elif not e.info: # This has already been reported by the semantic analyzer. @@ -3942,7 +3992,8 @@ def is_valid_var_arg(self, typ: Type) -> bool: return (isinstance(typ, TupleType) or is_subtype(typ, self.chk.named_generic_type('typing.Iterable', [AnyType(TypeOfAny.special_form)])) or - isinstance(typ, AnyType)) + isinstance(typ, AnyType) or + isinstance(typ, ParamSpecType)) def is_valid_keyword_var_arg(self, typ: Type) -> bool: """Is a type valid as a **kwargs argument?""" @@ -3950,7 +4001,9 @@ def is_valid_keyword_var_arg(self, typ: Type) -> bool: is_subtype(typ, self.chk.named_generic_type('typing.Mapping', [self.named_type('builtins.str'), AnyType(TypeOfAny.special_form)])) or is_subtype(typ, self.chk.named_generic_type('typing.Mapping', - [UninhabitedType(), UninhabitedType()]))) + [UninhabitedType(), UninhabitedType()])) or + isinstance(typ, ParamSpecType) + ) if self.chk.options.python_version[0] < 3: ret = ret or is_subtype(typ, self.chk.named_generic_type('typing.Mapping', [self.named_type('builtins.unicode'), AnyType(TypeOfAny.special_form)])) @@ -4027,7 +4080,7 @@ def visit_await_expr(self, e: AwaitExpr) -> Type: return self.check_awaitable_expr(actual_type, e, message_registry.INCOMPATIBLE_TYPES_IN_AWAIT) - def check_awaitable_expr(self, t: Type, ctx: Context, msg: str) -> Type: + def check_awaitable_expr(self, t: Type, ctx: Context, msg: Union[str, ErrorMessage]) -> Type: """Check the argument to `await` and extract the type of value. Also used by `async for` and `async with`. @@ -4445,7 +4498,7 @@ def merge_typevars_in_callables_by_name( "S", but we treat them as distinct, unrelated typevars. (E.g. they could both have distinct ids.) - If we pass in both callables into this function, it returns a a list containing two + If we pass in both callables into this function, it returns a list containing two new callables that are identical in signature, but use the same underlying TypeVarType for T and S. @@ -4466,7 +4519,7 @@ def merge_typevars_in_callables_by_name( for tv in target.variables: name = tv.fullname if name not in unique_typevars: - # TODO(shantanu): fix for ParamSpecType + # TODO(PEP612): fix for ParamSpecType if isinstance(tv, ParamSpecType): continue assert isinstance(tv, TypeVarType) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 403153fc4293..c01f52de5a77 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -6,13 +6,13 @@ from mypy.types import ( Type, Instance, AnyType, TupleType, TypedDictType, CallableType, FunctionLike, TypeVarLikeType, Overloaded, TypeVarType, UnionType, PartialType, TypeOfAny, LiteralType, - DeletedType, NoneType, TypeType, has_type_vars, get_proper_type, ProperType + DeletedType, NoneType, TypeType, has_type_vars, get_proper_type, ProperType, ParamSpecType ) from mypy.nodes import ( TypeInfo, FuncBase, Var, FuncDef, SymbolNode, SymbolTable, Context, MypyFile, TypeVarExpr, ARG_POS, ARG_STAR, ARG_STAR2, Decorator, OverloadedFuncDef, TypeAlias, TempNode, is_final_node, - SYMBOL_FUNCBASE_TYPES, + SYMBOL_FUNCBASE_TYPES, IndexExpr ) from mypy.messages import MessageBuilder from mypy.maptype import map_instance_to_supertype @@ -60,14 +60,15 @@ def __init__(self, self.chk = chk self.module_symbol_table = module_symbol_table - def builtin_type(self, name: str) -> Instance: + def named_type(self, name: str) -> Instance: return self.chk.named_type(name) def not_ready_callback(self, name: str, context: Context) -> None: self.chk.handle_cannot_determine_type(name, context) def copy_modified(self, *, messages: Optional[MessageBuilder] = None, - self_type: Optional[Type] = None) -> 'MemberContext': + self_type: Optional[Type] = None, + is_lvalue: Optional[bool] = 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) @@ -75,6 +76,8 @@ def copy_modified(self, *, messages: Optional[MessageBuilder] = None, mx.msg = messages if self_type is not None: mx.self_type = self_type + if is_lvalue is not None: + mx.is_lvalue = is_lvalue return mx @@ -153,9 +156,11 @@ def _analyze_member_access(name: str, elif isinstance(typ, TupleType): # Actually look up from the fallback instance type. return _analyze_member_access(name, tuple_fallback(typ), mx, override_info) - elif isinstance(typ, (TypedDictType, LiteralType, FunctionLike)): + elif isinstance(typ, (LiteralType, FunctionLike)): # Actually look up from the fallback instance type. return _analyze_member_access(name, typ.fallback, mx, override_info) + elif isinstance(typ, TypedDictType): + return analyze_typeddict_access(name, typ, mx, override_info) elif isinstance(typ, NoneType): return analyze_none_member_access(name, typ, mx) elif isinstance(typ, TypeVarType): @@ -195,14 +200,14 @@ def analyze_instance_member_access(name: str, # Look up the member. First look up the method dictionary. method = info.get_method(name) - if method: + if method and not isinstance(method, Decorator): if method.is_property: assert isinstance(method, OverloadedFuncDef) first_item = cast(Decorator, method.items[0]) return analyze_var(name, first_item.var, typ, info, mx) if mx.is_lvalue: mx.msg.cant_assign_to_method(mx.context) - signature = function_type(method, mx.builtin_type('builtins.function')) + signature = function_type(method, mx.named_type('builtins.function')) signature = freshen_function_type_vars(signature) if name == '__new__': # __new__ is special and behaves like a static method -- don't strip @@ -266,7 +271,7 @@ def analyze_type_type_member_access(name: str, override_info: Optional[TypeInfo]) -> Type: # Similar to analyze_type_callable_attribute_access. item = None - fallback = mx.builtin_type('builtins.type') + fallback = mx.named_type('builtins.type') ignore_messages = mx.msg.copy() ignore_messages.disable_errors().__enter__() if isinstance(typ.item, Instance): @@ -317,19 +322,20 @@ def analyze_union_member_access(name: str, typ: UnionType, mx: MemberContext) -> def analyze_none_member_access(name: str, typ: NoneType, mx: MemberContext) -> Type: - if mx.chk.should_suppress_optional_error([typ]): - return AnyType(TypeOfAny.from_error) is_python_3 = mx.chk.options.python_version[0] >= 3 # In Python 2 "None" has exactly the same attributes as "object". Python 3 adds a single # extra attribute, "__bool__". if is_python_3 and name == '__bool__': + literal_false = LiteralType(False, fallback=mx.named_type('builtins.bool')) return CallableType(arg_types=[], arg_kinds=[], arg_names=[], - ret_type=mx.builtin_type('builtins.bool'), - fallback=mx.builtin_type('builtins.function')) + ret_type=literal_false, + fallback=mx.named_type('builtins.function')) + elif mx.chk.should_suppress_optional_error([typ]): + return AnyType(TypeOfAny.from_error) else: - return _analyze_member_access(name, mx.builtin_type('builtins.object'), mx) + return _analyze_member_access(name, mx.named_type('builtins.object'), mx) def analyze_member_var_access(name: str, @@ -354,7 +360,7 @@ def analyze_member_var_access(name: str, # If the associated variable is a TypeInfo synthesize a Var node for # the purposes of type checking. This enables us to type check things # like accessing class attributes on an inner class. - v = Var(name, type=type_object_type(vv, mx.builtin_type)) + v = Var(name, type=type_object_type(vv, mx.named_type)) v.info = info if isinstance(vv, TypeAlias) and isinstance(get_proper_type(vv.target), Instance): @@ -364,7 +370,7 @@ def analyze_member_var_access(name: str, # class C: # A = List[int] # x = C.A() <- this is OK - typ = instance_alias_type(vv, mx.builtin_type) + typ = instance_alias_type(vv, mx.named_type) v = Var(name, type=typ) v.info = info @@ -380,33 +386,42 @@ def analyze_member_var_access(name: str, elif isinstance(v, FuncDef): assert False, "Did not expect a function" elif (not v and name not in ['__getattr__', '__setattr__', '__getattribute__'] and - not mx.is_operator): + not mx.is_operator and mx.module_symbol_table is None): + # Above we skip ModuleType.__getattr__ etc. if we have a + # module symbol table, since the symbol table allows precise + # checking. if not mx.is_lvalue: for method_name in ('__getattribute__', '__getattr__'): method = info.get_method(method_name) + # __getattribute__ is defined on builtins.object and returns Any, so without # the guard this search will always find object.__getattribute__ and conclude # that the attribute exists if method and method.info.fullname != 'builtins.object': - function = function_type(method, mx.builtin_type('builtins.function')) - bound_method = bind_self(function, mx.self_type) + bound_method = analyze_decorator_or_funcbase_access( + defn=method, itype=itype, info=info, + self_type=mx.self_type, name=method_name, mx=mx) typ = map_instance_to_supertype(itype, method.info) getattr_type = get_proper_type(expand_type_by_instance(bound_method, typ)) if isinstance(getattr_type, CallableType): result = getattr_type.ret_type - - # Call the attribute hook before returning. - fullname = '{}.{}'.format(method.info.fullname, name) - hook = mx.chk.plugin.get_attribute_hook(fullname) - if hook: - result = hook(AttributeContext(get_proper_type(mx.original_type), - result, mx.context, mx.chk)) - return result + else: + result = getattr_type + + # Call the attribute hook before returning. + fullname = '{}.{}'.format(method.info.fullname, name) + hook = mx.chk.plugin.get_attribute_hook(fullname) + if hook: + result = hook(AttributeContext(get_proper_type(mx.original_type), + result, mx.context, mx.chk)) + return result else: setattr_meth = info.get_method('__setattr__') if setattr_meth and setattr_meth.info.fullname != 'builtins.object': - setattr_func = function_type(setattr_meth, mx.builtin_type('builtins.function')) - bound_type = bind_self(setattr_func, mx.self_type) + bound_type = analyze_decorator_or_funcbase_access( + defn=setattr_meth, itype=itype, info=info, + self_type=mx.self_type, name=name, + mx=mx.copy_modified(is_lvalue=False)) typ = map_instance_to_supertype(itype, setattr_meth.info) setattr_type = get_proper_type(expand_type_by_instance(bound_type, typ)) if isinstance(setattr_type, CallableType) and len(setattr_type.arg_types) > 0: @@ -435,32 +450,24 @@ 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(instance_type: Type, - descriptor_type: Type, - builtin_type: Callable[[str], Instance], - msg: MessageBuilder, - context: Context, *, - chk: 'mypy.checker.TypeChecker') -> Type: +def analyze_descriptor_access(descriptor_type: Type, + mx: MemberContext) -> Type: """Type check descriptor access. Arguments: - instance_type: The type of the instance on which the descriptor - attribute is being accessed (the type of ``a`` in ``a.f`` when - ``f`` is a descriptor). descriptor_type: The type of the descriptor attribute being accessed (the type of ``f`` in ``a.f`` when ``f`` is a descriptor). - context: The node defining the context of this inference. + mx: The current member access context. Return: The return type of the appropriate ``__get__`` overload for the descriptor. """ - instance_type = get_proper_type(instance_type) + instance_type = get_proper_type(mx.original_type) descriptor_type = get_proper_type(descriptor_type) if isinstance(descriptor_type, UnionType): # Map the access over union types return make_simplified_union([ - analyze_descriptor_access(instance_type, typ, builtin_type, - msg, context, chk=chk) + analyze_descriptor_access(typ, mx) for typ in descriptor_type.items ]) elif not isinstance(descriptor_type, Instance): @@ -470,13 +477,15 @@ def analyze_descriptor_access(instance_type: Type, return descriptor_type dunder_get = descriptor_type.type.get_method('__get__') - if dunder_get is None: - msg.fail(message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format(descriptor_type), context) + mx.msg.fail(message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format(descriptor_type), + mx.context) return AnyType(TypeOfAny.from_error) - function = function_type(dunder_get, builtin_type('builtins.function')) - bound_method = bind_self(function, descriptor_type) + bound_method = analyze_decorator_or_funcbase_access( + defn=dunder_get, itype=descriptor_type, info=descriptor_type.type, + self_type=descriptor_type, name='__set__', mx=mx) + typ = map_instance_to_supertype(descriptor_type, dunder_get.info) dunder_get_type = expand_type_by_instance(bound_method, typ) @@ -489,19 +498,19 @@ def analyze_descriptor_access(instance_type: Type, else: owner_type = instance_type - callable_name = chk.expr_checker.method_fullname(descriptor_type, "__get__") - dunder_get_type = chk.expr_checker.transform_callee_type( + callable_name = mx.chk.expr_checker.method_fullname(descriptor_type, "__get__") + dunder_get_type = mx.chk.expr_checker.transform_callee_type( callable_name, dunder_get_type, - [TempNode(instance_type, context=context), - TempNode(TypeType.make_normalized(owner_type), context=context)], - [ARG_POS, ARG_POS], context, object_type=descriptor_type, + [TempNode(instance_type, context=mx.context), + TempNode(TypeType.make_normalized(owner_type), context=mx.context)], + [ARG_POS, ARG_POS], mx.context, object_type=descriptor_type, ) - _, inferred_dunder_get_type = chk.expr_checker.check_call( + _, inferred_dunder_get_type = mx.chk.expr_checker.check_call( dunder_get_type, - [TempNode(instance_type, context=context), - TempNode(TypeType.make_normalized(owner_type), context=context)], - [ARG_POS, ARG_POS], context, object_type=descriptor_type, + [TempNode(instance_type, context=mx.context), + TempNode(TypeType.make_normalized(owner_type), context=mx.context)], + [ARG_POS, ARG_POS], mx.context, object_type=descriptor_type, callable_name=callable_name) inferred_dunder_get_type = get_proper_type(inferred_dunder_get_type) @@ -510,14 +519,15 @@ def analyze_descriptor_access(instance_type: Type, return inferred_dunder_get_type if not isinstance(inferred_dunder_get_type, CallableType): - msg.fail(message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format(descriptor_type), context) + mx.msg.fail(message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format(descriptor_type), + mx.context) return AnyType(TypeOfAny.from_error) return inferred_dunder_get_type.ret_type def instance_alias_type(alias: TypeAlias, - builtin_type: Callable[[str], Instance]) -> Type: + named_type: Callable[[str], Instance]) -> Type: """Type of a type alias node targeting an instance, when appears in runtime context. As usual, we first erase any unbound type variables to Any. @@ -527,21 +537,10 @@ def instance_alias_type(alias: TypeAlias, Instance), "Must be called only with aliases to classes" target = get_proper_type(set_any_tvars(alias, alias.line, alias.column)) assert isinstance(target, Instance) - tp = type_object_type(target.type, builtin_type) + tp = type_object_type(target.type, named_type) return expand_type_by_instance(tp, target) -def is_instance_var(var: Var, info: TypeInfo) -> bool: - """Return if var is an instance variable according to PEP 526.""" - return ( - # check the type_info node is the var (not a decorated function, etc.) - var.name in info.names and info.names[var.name].node is var - and not var.is_classvar - # variables without annotations are treated as classvar - and not var.is_inferred - ) - - def analyze_var(name: str, var: Var, itype: Instance, @@ -570,12 +569,7 @@ def analyze_var(name: str, t = get_proper_type(expand_type_by_instance(typ, itype)) result: Type = t typ = get_proper_type(typ) - if ( - var.is_initialized_in_class - and not is_instance_var(var, info) - and isinstance(typ, FunctionLike) - and not typ.is_type_obj() - ): + if var.is_initialized_in_class and isinstance(typ, FunctionLike) and not typ.is_type_obj(): if mx.is_lvalue: if var.is_property: if not var.is_settable_property: @@ -615,8 +609,7 @@ def analyze_var(name: str, fullname = '{}.{}'.format(var.info.fullname, name) hook = mx.chk.plugin.get_attribute_hook(fullname) if result and not mx.is_lvalue and not implicit: - result = analyze_descriptor_access(mx.original_type, result, mx.builtin_type, - mx.msg, mx.context, chk=mx.chk) + result = analyze_descriptor_access(result, mx) if hook: result = hook(AttributeContext(get_proper_type(mx.original_type), result, mx.context, mx.chk)) @@ -681,6 +674,9 @@ def f(self: S) -> T: ... selfarg = item.arg_types[0] if subtypes.is_subtype(dispatched_arg_type, erase_typevars(erase_to_bound(selfarg))): new_items.append(item) + elif isinstance(selfarg, ParamSpecType): + # TODO: This is not always right. What's the most reasonable thing to do here? + new_items.append(item) if not new_items: # Choose first item for the message (it may be not very helpful for overloads). msg.incompatible_self_argument(name, dispatched_arg_type, items[0], @@ -792,8 +788,7 @@ def analyze_class_attribute_access(itype: Instance, result = add_class_tvars(t, isuper, is_classmethod, mx.self_type, original_vars=original_vars) if not mx.is_lvalue: - result = analyze_descriptor_access(mx.original_type, result, mx.builtin_type, - mx.msg, mx.context, chk=mx.chk) + result = analyze_descriptor_access(result, mx) return result elif isinstance(node.node, Var): mx.not_ready_callback(name, mx.context) @@ -805,15 +800,15 @@ def analyze_class_attribute_access(itype: Instance, return AnyType(TypeOfAny.from_error) if isinstance(node.node, TypeInfo): - return type_object_type(node.node, mx.builtin_type) + return type_object_type(node.node, mx.named_type) if isinstance(node.node, MypyFile): # Reference to a module object. - return mx.builtin_type('types.ModuleType') + return mx.named_type('types.ModuleType') if (isinstance(node.node, TypeAlias) and isinstance(get_proper_type(node.node.target), Instance)): - return instance_alias_type(node.node, mx.builtin_type) + return instance_alias_type(node.node, mx.named_type) if is_decorated: assert isinstance(node.node, Decorator) @@ -824,7 +819,7 @@ def analyze_class_attribute_access(itype: Instance, return AnyType(TypeOfAny.from_error) else: assert isinstance(node.node, FuncBase) - typ = function_type(node.node, mx.builtin_type('builtins.function')) + typ = function_type(node.node, mx.named_type('builtins.function')) # Note: if we are accessing class method on class object, the cls argument is bound. # Annotated and/or explicit class methods go through other code paths above, for # unannotated implicit class methods we do this here. @@ -855,6 +850,40 @@ def analyze_enum_class_attribute_access(itype: Instance, return itype.copy_modified(erased=False, last_known_value=enum_literal) +def analyze_typeddict_access(name: str, typ: TypedDictType, + mx: MemberContext, override_info: Optional[TypeInfo]) -> Type: + if name == '__setitem__': + if isinstance(mx.context, IndexExpr): + # Since we can get this during `a['key'] = ...` + # it is safe to assume that the context is `IndexExpr`. + item_type = mx.chk.expr_checker.visit_typeddict_index_expr( + typ, mx.context.index) + else: + # It can also be `a.__setitem__(...)` direct call. + # In this case `item_type` can be `Any`, + # because we don't have args available yet. + # TODO: check in `default` plugin that `__setitem__` is correct. + item_type = AnyType(TypeOfAny.implementation_artifact) + return CallableType( + arg_types=[mx.chk.named_type('builtins.str'), item_type], + arg_kinds=[ARG_POS, ARG_POS], + arg_names=[None, None], + ret_type=NoneType(), + fallback=mx.chk.named_type('builtins.function'), + name=name, + ) + elif name == '__delitem__': + return CallableType( + arg_types=[mx.chk.named_type('builtins.str')], + arg_kinds=[ARG_POS], + arg_names=[None], + ret_type=NoneType(), + fallback=mx.chk.named_type('builtins.function'), + name=name, + ) + return _analyze_member_access(name, typ.fallback, mx, override_info) + + def add_class_tvars(t: ProperType, isuper: Optional[Instance], is_classmethod: bool, original_type: Type, @@ -913,7 +942,7 @@ class B(A[str]): pass return t -def type_object_type(info: TypeInfo, builtin_type: Callable[[str], Instance]) -> ProperType: +def type_object_type(info: TypeInfo, named_type: Callable[[str], Instance]) -> ProperType: """Return the type of a type object. For a generic type G with type variables T and S the type is generally of form @@ -945,7 +974,7 @@ def type_object_type(info: TypeInfo, builtin_type: Callable[[str], Instance]) -> init_index = info.mro.index(init_method.node.info) new_index = info.mro.index(new_method.node.info) - fallback = info.metaclass_type or builtin_type('builtins.type') + fallback = info.metaclass_type or named_type('builtins.type') if init_index < new_index: method: Union[FuncBase, Decorator] = init_method.node is_new = False @@ -963,7 +992,7 @@ def type_object_type(info: TypeInfo, builtin_type: Callable[[str], Instance]) -> arg_kinds=[ARG_STAR, ARG_STAR2], arg_names=["_args", "_kwds"], ret_type=any_type, - fallback=builtin_type('builtins.function')) + fallback=named_type('builtins.function')) return class_callable(sig, info, fallback, None, is_new=False) # Otherwise prefer __init__ in a tie. It isn't clear that this @@ -982,6 +1011,27 @@ def type_object_type(info: TypeInfo, builtin_type: Callable[[str], Instance]) -> return type_object_type_from_function(t, info, method.info, fallback, is_new) +def analyze_decorator_or_funcbase_access( + defn: Union[Decorator, FuncBase], + itype: Instance, + info: TypeInfo, + self_type: Optional[Type], + name: str, + mx: MemberContext, +) -> Type: + """Analyzes the type behind method access. + + The function itself can possibly be decorated. + See: https://github.com/python/mypy/issues/10409 + """ + if isinstance(defn, Decorator): + return analyze_var(name, defn.var, itype, info, mx) + return bind_self( + function_type(defn, mx.chk.named_type('builtins.function')), + original_type=self_type, + ) + + def is_valid_constructor(n: Optional[SymbolNode]) -> bool: """Does this node represents a valid constructor method? diff --git a/mypy/checkstrformat.py b/mypy/checkstrformat.py index e1c4f71fa61b..dcb711150870 100644 --- a/mypy/checkstrformat.py +++ b/mypy/checkstrformat.py @@ -15,7 +15,7 @@ from typing import ( cast, List, Tuple, Dict, Callable, Union, Optional, Pattern, Match, Set ) -from typing_extensions import Final, TYPE_CHECKING +from typing_extensions import Final, TYPE_CHECKING, TypeAlias as _TypeAlias from mypy.types import ( Type, AnyType, TupleType, Instance, UnionType, TypeOfAny, get_proper_type, TypeVarType, @@ -39,9 +39,9 @@ from mypy.subtypes import is_subtype from mypy.parse import parse -FormatStringExpr = Union[StrExpr, BytesExpr, UnicodeExpr] -Checkers = Tuple[Callable[[Expression], None], Callable[[Type], bool]] -MatchMap = Dict[Tuple[int, int], Match[str]] # span -> match +FormatStringExpr: _TypeAlias = Union[StrExpr, BytesExpr, UnicodeExpr] +Checkers: _TypeAlias = Tuple[Callable[[Expression], None], Callable[[Type], bool]] +MatchMap: _TypeAlias = Dict[Tuple[int, int], Match[str]] # span -> match def compile_format_re() -> Pattern[str]: @@ -380,8 +380,9 @@ def perform_special_format_checks(self, spec: ConversionSpecifier, call: CallExp if (has_type_component(actual_type, 'builtins.bytes') and not custom_special_method(actual_type, '__str__')): self.msg.fail( - "On Python 3 '{}'.format(b'abc') produces \"b'abc'\", not 'abc'; " - "use '{!r}'.format(b'abc') if this is desired behavior", + 'On Python 3 formatting "b\'abc\'" with "{}" ' + 'produces "b\'abc\'", not "abc"; ' + 'use "{!r}" if this is desired behavior', call, code=codes.STR_BYTES_PY3) if spec.flags: numeric_types = UnionType([self.named_type('builtins.int'), @@ -659,7 +660,12 @@ def check_simple_str_interpolation(self, specifiers: List[ConversionSpecifier], rep_types = [rhs_type] if len(checkers) > len(rep_types): - self.msg.too_few_string_formatting_arguments(replacements) + # Only check the fix-length Tuple type. Other Iterable types would skip. + if (is_subtype(rhs_type, self.chk.named_type("typing.Iterable")) and + not isinstance(rhs_type, TupleType)): + return + else: + self.msg.too_few_string_formatting_arguments(replacements) elif len(checkers) < len(rep_types): self.msg.too_many_string_formatting_arguments(replacements) else: @@ -836,8 +842,9 @@ def check_s_special_cases(self, expr: FormatStringExpr, typ: Type, context: Cont if self.chk.options.python_version >= (3, 0): if has_type_component(typ, 'builtins.bytes'): self.msg.fail( - "On Python 3 '%s' % b'abc' produces \"b'abc'\", not 'abc'; " - "use '%r' % b'abc' if this is desired behavior", + 'On Python 3 formatting "b\'abc\'" with "%s" ' + 'produces "b\'abc\'", not "abc"; ' + 'use "%r" if this is desired behavior', context, code=codes.STR_BYTES_PY3) return False if self.chk.options.python_version < (3, 0): diff --git a/mypy/config_parser.py b/mypy/config_parser.py index d5552186ecc7..24e61df0441c 100644 --- a/mypy/config_parser.py +++ b/mypy/config_parser.py @@ -9,13 +9,15 @@ import tomli from typing import (Any, Callable, Dict, List, Mapping, MutableMapping, Optional, Sequence, TextIO, Tuple, Union) -from typing_extensions import Final +from typing_extensions import Final, TypeAlias as _TypeAlias from mypy import defaults from mypy.options import Options, PER_MODULE_OPTIONS -_CONFIG_VALUE_TYPES = Union[str, bool, int, float, Dict[str, str], List[str], Tuple[int, int]] -_INI_PARSER_CALLABLE = Callable[[Any], _CONFIG_VALUE_TYPES] +_CONFIG_VALUE_TYPES: _TypeAlias = Union[ + str, bool, int, float, Dict[str, str], List[str], Tuple[int, int], +] +_INI_PARSER_CALLABLE: _TypeAlias = Callable[[Any], _CONFIG_VALUE_TYPES] def parse_version(v: str) -> Tuple[int, int]: @@ -124,6 +126,7 @@ def check_follow_imports(choice: str) -> str: 'cache_dir': expand_path, 'python_executable': expand_path, 'strict': bool, + 'exclude': lambda s: [p.strip() for p in s.split('\n') if p.strip()], } # Reuse the ini_config_types and overwrite the diff @@ -169,7 +172,7 @@ def parse_config_file(options: Options, set_strict_flags: Callable[[], None], try: if is_toml(config_file): with open(config_file, encoding="utf-8") as f: - toml_data = tomli.load(f) + toml_data = tomli.loads(f.read()) # Filter down to just mypy relevant toml keys toml_data = toml_data.get('tool', {}) if 'mypy' not in toml_data: diff --git a/mypy/constraints.py b/mypy/constraints.py index d8dad95a3430..5a78cdb94e93 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -1,13 +1,14 @@ """Type inference constraints.""" -from typing import Iterable, List, Optional, Sequence +from typing import TYPE_CHECKING, Iterable, List, Optional, Sequence from typing_extensions import Final from mypy.types import ( CallableType, Type, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarType, Instance, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, TypeVarId, TypeQuery, is_named_instance, TypeOfAny, LiteralType, - ProperType, get_proper_type, TypeAliasType + ProperType, ParamSpecType, get_proper_type, TypeAliasType, is_union_with_any, + callable_with_ellipsis ) from mypy.maptype import map_instance_to_supertype import mypy.subtypes @@ -18,6 +19,9 @@ from mypy.argmap import ArgTypeExpander from mypy.typestate import TypeState +if TYPE_CHECKING: + from mypy.infer import ArgumentInferContext + SUBTYPE_OF: Final = 0 SUPERTYPE_OF: Final = 1 @@ -45,14 +49,17 @@ def __repr__(self) -> str: def infer_constraints_for_callable( - callee: CallableType, arg_types: Sequence[Optional[Type]], arg_kinds: List[ArgKind], - formal_to_actual: List[List[int]]) -> List[Constraint]: + callee: CallableType, + arg_types: Sequence[Optional[Type]], + arg_kinds: List[ArgKind], + formal_to_actual: List[List[int]], + context: 'ArgumentInferContext') -> List[Constraint]: """Infer type variable constraints for a callable and actual arguments. Return a list of constraints. """ constraints: List[Constraint] = [] - mapper = ArgTypeExpander() + mapper = ArgTypeExpander(context) for i, actuals in enumerate(formal_to_actual): for actual in actuals: @@ -195,6 +202,32 @@ def infer_constraints_if_possible(template: Type, actual: Type, return infer_constraints(template, actual, direction) +def select_trivial(options: Sequence[Optional[List[Constraint]]]) -> List[List[Constraint]]: + """Select only those lists where each item is a constraint against Any.""" + res = [] + for option in options: + if option is None: + continue + if all(isinstance(get_proper_type(c.target), AnyType) for c in option): + res.append(option) + return res + + +def merge_with_any(constraint: Constraint) -> Constraint: + """Transform a constraint target into a union with given Any type.""" + target = constraint.target + if is_union_with_any(target): + # Do not produce redundant unions. + return constraint + # TODO: if we will support multiple sources Any, use this here instead. + any_type = AnyType(TypeOfAny.implementation_artifact) + return Constraint( + constraint.type_var, + constraint.op, + UnionType.make_union([target, any_type], target.line, target.column), + ) + + def any_constraints(options: List[Optional[List[Constraint]]], eager: bool) -> List[Constraint]: """Deduce what we can from a collection of constraint lists. @@ -207,26 +240,36 @@ def any_constraints(options: List[Optional[List[Constraint]]], eager: bool) -> L valid_options = [option for option in options if option] else: valid_options = [option for option in options if option is not None] + + if not valid_options: + return [] + if len(valid_options) == 1: return valid_options[0] - elif (len(valid_options) > 1 and - all(is_same_constraints(valid_options[0], c) - for c in valid_options[1:])): + + if all(is_same_constraints(valid_options[0], c) for c in valid_options[1:]): # Multiple sets of constraints that are all the same. Just pick any one of them. - # TODO: More generally, if a given (variable, direction) pair appears in - # every option, combine the bounds with meet/join. return valid_options[0] - elif len(valid_options) > 1: - # Drop constraints that only refer to "Any" and try again. This way Any types - # in unions don't interfere with type inference. - narrowed_options = [option - for option in valid_options - if not (option and - all(isinstance(get_proper_type(c.target), AnyType) - for c in option))] - if len(narrowed_options) < len(valid_options): - return any_constraints([option for option in narrowed_options], eager) + if all(is_similar_constraints(valid_options[0], c) for c in valid_options[1:]): + # All options have same structure. In this case we can merge-in trivial + # options (i.e. those that only have Any) and try again. + # TODO: More generally, if a given (variable, direction) pair appears in + # every option, combine the bounds with meet/join always, not just for Any. + trivial_options = select_trivial(valid_options) + if trivial_options and len(trivial_options) < len(valid_options): + merged_options = [] + for option in valid_options: + if option in trivial_options: + continue + if option is not None: + merged_option: Optional[List[Constraint]] = [ + merge_with_any(c) for c in option + ] + else: + merged_option = None + merged_options.append(merged_option) + return any_constraints([option for option in merged_options], eager) # Otherwise, there are either no valid options or multiple, inconsistent valid # options. Give up and deduce nothing. return [] @@ -243,11 +286,47 @@ def is_same_constraints(x: List[Constraint], y: List[Constraint]) -> bool: def is_same_constraint(c1: Constraint, c2: Constraint) -> bool: + # Ignore direction when comparing constraints against Any. + skip_op_check = ( + isinstance(get_proper_type(c1.target), AnyType) and + isinstance(get_proper_type(c2.target), AnyType) + ) return (c1.type_var == c2.type_var - and c1.op == c2.op + and (c1.op == c2.op or skip_op_check) and mypy.sametypes.is_same_type(c1.target, c2.target)) +def is_similar_constraints(x: List[Constraint], y: List[Constraint]) -> bool: + """Check that two lists of constraints have similar structure. + + This means that each list has same type variable plus direction pairs (i.e we + ignore the target). Except for constraints where target is Any type, there + we ignore direction as well. + """ + return _is_similar_constraints(x, y) and _is_similar_constraints(y, x) + + +def _is_similar_constraints(x: List[Constraint], y: List[Constraint]) -> bool: + """Check that every constraint in the first list has a similar one in the second. + + See docstring above for definition of similarity. + """ + for c1 in x: + has_similar = False + for c2 in y: + # Ignore direction when either constraint is against Any. + skip_op_check = ( + isinstance(get_proper_type(c1.target), AnyType) or + isinstance(get_proper_type(c2.target), AnyType) + ) + if c1.type_var == c2.type_var and (c1.op == c2.op or skip_op_check): + has_similar = True + break + if not has_similar: + return False + return True + + def simplify_away_incomplete_types(types: Iterable[Type]) -> List[Type]: complete = [typ for typ in types if is_complete_type(typ)] if complete: @@ -320,6 +399,10 @@ def visit_type_var(self, template: TypeVarType) -> List[Constraint]: assert False, ("Unexpected TypeVarType in ConstraintBuilderVisitor" " (should have been handled in infer_constraints)") + def visit_param_spec(self, template: ParamSpecType) -> List[Constraint]: + # Can't infer ParamSpecs from component values (only via Callable[P, T]). + return [] + # Non-leaf types def visit_instance(self, template: Instance) -> List[Constraint]: @@ -360,14 +443,16 @@ def visit_instance(self, template: Instance) -> List[Constraint]: # N.B: We use zip instead of indexing because the lengths might have # mismatches during daemon reprocessing. for tvar, mapped_arg, instance_arg in zip(tvars, mapped.args, instance.args): - # The constraints for generic type parameters depend on variance. - # Include constraints from both directions if invariant. - if tvar.variance != CONTRAVARIANT: - res.extend(infer_constraints( - mapped_arg, instance_arg, self.direction)) - if tvar.variance != COVARIANT: - res.extend(infer_constraints( - mapped_arg, instance_arg, neg_op(self.direction))) + # TODO: ParamSpecType + if isinstance(tvar, TypeVarType): + # The constraints for generic type parameters depend on variance. + # Include constraints from both directions if invariant. + if tvar.variance != CONTRAVARIANT: + res.extend(infer_constraints( + mapped_arg, instance_arg, self.direction)) + if tvar.variance != COVARIANT: + res.extend(infer_constraints( + mapped_arg, instance_arg, neg_op(self.direction))) return res elif (self.direction == SUPERTYPE_OF and instance.type.has_base(template.type.fullname)): @@ -376,19 +461,21 @@ def visit_instance(self, template: Instance) -> List[Constraint]: # N.B: We use zip instead of indexing because the lengths might have # mismatches during daemon reprocessing. for tvar, mapped_arg, template_arg in zip(tvars, mapped.args, template.args): - # The constraints for generic type parameters depend on variance. - # Include constraints from both directions if invariant. - if tvar.variance != CONTRAVARIANT: - res.extend(infer_constraints( - template_arg, mapped_arg, self.direction)) - if tvar.variance != COVARIANT: - res.extend(infer_constraints( - template_arg, mapped_arg, neg_op(self.direction))) + # TODO: ParamSpecType + if isinstance(tvar, TypeVarType): + # The constraints for generic type parameters depend on variance. + # Include constraints from both directions if invariant. + if tvar.variance != CONTRAVARIANT: + res.extend(infer_constraints( + template_arg, mapped_arg, self.direction)) + if tvar.variance != COVARIANT: + res.extend(infer_constraints( + template_arg, mapped_arg, neg_op(self.direction))) return res if (template.type.is_protocol and self.direction == SUPERTYPE_OF and # We avoid infinite recursion for structural subtypes by checking # whether this type already appeared in the inference chain. - # This is a conservative way break the inference cycles. + # This is a conservative way to break the inference cycles. # It never produces any "false" constraints but gives up soon # on purely structural inference cycles, see #3829. # Note that we use is_protocol_implementation instead of is_subtype @@ -398,8 +485,8 @@ def visit_instance(self, template: Instance) -> List[Constraint]: for t in template.type.inferring) and mypy.subtypes.is_protocol_implementation(instance, erased)): template.type.inferring.append(template) - self.infer_constraints_from_protocol_members(res, instance, template, - original_actual, template) + res.extend(self.infer_constraints_from_protocol_members( + instance, template, original_actual, template)) template.type.inferring.pop() return res elif (instance.type.is_protocol and self.direction == SUBTYPE_OF and @@ -408,12 +495,11 @@ def visit_instance(self, template: Instance) -> List[Constraint]: for i in instance.type.inferring) and mypy.subtypes.is_protocol_implementation(erased, instance)): instance.type.inferring.append(instance) - self.infer_constraints_from_protocol_members(res, instance, template, - template, instance) + res.extend(self.infer_constraints_from_protocol_members( + instance, template, template, instance)) instance.type.inferring.pop() return res if isinstance(actual, AnyType): - # IDEA: Include both ways, i.e. add negation as well? return self.infer_against_any(template.args, actual) if (isinstance(actual, TupleType) and (is_named_instance(template, 'typing.Iterable') or @@ -432,19 +518,22 @@ def visit_instance(self, template: Instance) -> List[Constraint]: else: return [] - def infer_constraints_from_protocol_members(self, res: List[Constraint], + def infer_constraints_from_protocol_members(self, instance: Instance, template: Instance, - subtype: Type, protocol: Instance) -> None: + subtype: Type, protocol: Instance, + ) -> List[Constraint]: """Infer constraints for situations where either 'template' or 'instance' is a protocol. The 'protocol' is the one of two that is an instance of protocol type, 'subtype' is the type used to bind self during inference. Currently, we just infer constrains for every protocol member type (both ways for settable members). """ + res = [] for member in protocol.type.protocol_members: inst = mypy.subtypes.find_member(member, instance, subtype) temp = mypy.subtypes.find_member(member, template, subtype) - assert inst is not None and temp is not None + if inst is None or temp is None: + return [] # See #11020 # The above is safe since at this point we know that 'instance' is a subtype # of (erased) 'template', therefore it defines all protocol members res.extend(infer_constraints(temp, inst, self.direction)) @@ -452,33 +541,50 @@ def infer_constraints_from_protocol_members(self, res: List[Constraint], mypy.subtypes.get_member_flags(member, protocol.type)): # Settable members are invariant, add opposite constraints res.extend(infer_constraints(temp, inst, neg_op(self.direction))) + return res def visit_callable_type(self, template: CallableType) -> List[Constraint]: if isinstance(self.actual, CallableType): - cactual = self.actual - # FIX verify argument counts - # FIX what if one of the functions is generic res: List[Constraint] = [] + cactual = self.actual + param_spec = template.param_spec() + if param_spec is None: + # FIX verify argument counts + # FIX what if one of the functions is generic + + # We can't infer constraints from arguments if the template is Callable[..., T] + # (with literal '...'). + if not template.is_ellipsis_args: + # The lengths should match, but don't crash (it will error elsewhere). + for t, a in zip(template.arg_types, cactual.arg_types): + # Negate direction due to function argument type contravariance. + res.extend(infer_constraints(t, a, neg_op(self.direction))) + else: + # TODO: Direction + # TODO: Deal with arguments that come before param spec ones? + res.append(Constraint(param_spec.id, + SUBTYPE_OF, + cactual.copy_modified(ret_type=NoneType()))) - # We can't infer constraints from arguments if the template is Callable[..., T] (with - # literal '...'). - if not template.is_ellipsis_args: - # The lengths should match, but don't crash (it will error elsewhere). - for t, a in zip(template.arg_types, cactual.arg_types): - # Negate direction due to function argument type contravariance. - res.extend(infer_constraints(t, a, neg_op(self.direction))) template_ret_type, cactual_ret_type = template.ret_type, cactual.ret_type if template.type_guard is not None: template_ret_type = template.type_guard if cactual.type_guard is not None: cactual_ret_type = cactual.type_guard + res.extend(infer_constraints(template_ret_type, cactual_ret_type, self.direction)) return res elif isinstance(self.actual, AnyType): - # FIX what if generic - res = self.infer_against_any(template.arg_types, self.actual) + param_spec = template.param_spec() any_type = AnyType(TypeOfAny.from_another_any, source_any=self.actual) + if param_spec is None: + # FIX what if generic + res = self.infer_against_any(template.arg_types, self.actual) + else: + res = [Constraint(param_spec.id, + SUBTYPE_OF, + callable_with_ellipsis(any_type, any_type, template.fallback))] res.extend(infer_constraints(template.ret_type, any_type, self.direction)) return res elif isinstance(self.actual, Overloaded): @@ -547,6 +653,9 @@ def visit_type_alias_type(self, template: TypeAliasType) -> List[Constraint]: def infer_against_any(self, types: Iterable[Type], any_type: AnyType) -> List[Constraint]: res: List[Constraint] = [] for t in types: + # Note that we ignore variance and simply always use the + # original direction. This is because for Any targets direction is + # irrelevant in most cases, see e.g. is_same_constraint(). res.extend(infer_constraints(t, any_type, self.direction)) return res diff --git a/mypy/erasetype.py b/mypy/erasetype.py index 7a56eceacf5f..8acebbd783d8 100644 --- a/mypy/erasetype.py +++ b/mypy/erasetype.py @@ -4,7 +4,7 @@ Type, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarId, Instance, TypeVarType, CallableType, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType, TypeTranslator, UninhabitedType, TypeType, TypeOfAny, LiteralType, ProperType, - get_proper_type, TypeAliasType + get_proper_type, TypeAliasType, ParamSpecType ) from mypy.nodes import ARG_STAR, ARG_STAR2 @@ -57,6 +57,9 @@ def visit_instance(self, t: Instance) -> ProperType: def visit_type_var(self, t: TypeVarType) -> ProperType: return AnyType(TypeOfAny.special_form) + def visit_param_spec(self, t: ParamSpecType) -> ProperType: + return AnyType(TypeOfAny.special_form) + def visit_callable_type(self, t: CallableType) -> ProperType: # We must preserve the fallback type for overload resolution to work. any_type = AnyType(TypeOfAny.special_form) @@ -125,6 +128,11 @@ def visit_type_var(self, t: TypeVarType) -> Type: return self.replacement return t + def visit_param_spec(self, t: ParamSpecType) -> Type: + if self.erase_id(t.id): + return self.replacement + return t + def visit_type_alias_type(self, t: TypeAliasType) -> Type: # Type alias target can't contain bound type variables, so # it is safe to just erase the arguments. diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index d9e11a044a18..2a07bbb8597b 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -30,7 +30,7 @@ def __str__(self) -> str: ATTR_DEFINED: Final = ErrorCode("attr-defined", "Check that attribute exists", "General") NAME_DEFINED: Final = ErrorCode("name-defined", "Check that name is defined", "General") -CALL_ARG: Final = ErrorCode( +CALL_ARG: Final[ErrorCode] = ErrorCode( "call-arg", "Check number, names and kinds of arguments in calls", "General" ) ARG_TYPE: Final = ErrorCode("arg-type", "Check argument types in calls", "General") @@ -44,8 +44,10 @@ def __str__(self) -> str: OVERRIDE: Final = ErrorCode( "override", "Check that method override is compatible with base class", "General" ) -RETURN: Final = ErrorCode("return", "Check that function always returns a value", "General") -RETURN_VALUE: Final = ErrorCode( +RETURN: Final[ErrorCode] = ErrorCode( + "return", "Check that function always returns a value", "General" +) +RETURN_VALUE: Final[ErrorCode] = ErrorCode( "return-value", "Check that return value is compatible with signature", "General" ) ASSIGNMENT: Final = ErrorCode( @@ -94,11 +96,11 @@ def __str__(self) -> str: ) # These error codes aren't enabled by default. -NO_UNTYPED_DEF: Final = ErrorCode( +NO_UNTYPED_DEF: Final[ErrorCode] = ErrorCode( "no-untyped-def", "Check that every function has an annotation", "General" ) NO_UNTYPED_CALL: Final = ErrorCode( - 'no-untyped-call', + "no-untyped-call", "Disallow calling functions without type annotations from annotated functions", "General", ) @@ -122,11 +124,11 @@ def __str__(self) -> str: REDUNDANT_EXPR: Final = ErrorCode( "redundant-expr", "Warn about redundant expressions", "General", default_enabled=False ) -TRUTHY_BOOL: Final = ErrorCode( - 'truthy-bool', +TRUTHY_BOOL: Final[ErrorCode] = ErrorCode( + "truthy-bool", "Warn about expressions that could always evaluate to true in boolean contexts", - 'General', - default_enabled=False + "General", + default_enabled=False, ) NAME_MATCH: Final = ErrorCode( "name-match", "Check that type definition has consistent naming", "General" diff --git a/mypy/errors.py b/mypy/errors.py index cc66653aeca3..c711456468ed 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -11,6 +11,7 @@ from mypy.options import Options from mypy.version import __version__ as mypy_version from mypy.errorcodes import ErrorCode, IMPORT +from mypy.message_registry import ErrorMessage from mypy import errorcodes as codes from mypy.util import DEFAULT_SOURCE_OFFSET, is_typeshed_file @@ -145,7 +146,7 @@ class Errors: ignored_lines: Dict[str, Dict[int, List[str]]] # Lines on which an error was actually ignored. - used_ignored_lines: Dict[str, Set[int]] + used_ignored_lines: Dict[str, Dict[int, List[str]]] # Files where all errors should be ignored. ignored_files: Set[str] @@ -200,7 +201,7 @@ def initialize(self) -> None: self.import_ctx = [] self.function_or_member = [None] self.ignored_lines = OrderedDict() - self.used_ignored_lines = defaultdict(set) + self.used_ignored_lines = defaultdict(lambda: defaultdict(list)) self.ignored_files = set() self.only_once_messages = set() self.scope = None @@ -369,7 +370,8 @@ def add_error_info(self, info: ErrorInfo) -> None: for scope_line in range(line, end_line + 1): if self.is_ignored_error(scope_line, info, self.ignored_lines[file]): # Annotation requests us to ignore all errors on this line. - self.used_ignored_lines[file].add(scope_line) + self.used_ignored_lines[file][scope_line].append( + (info.code or codes.MISC).code) return if file in self.ignored_files: return @@ -461,10 +463,25 @@ def clear_errors_in_targets(self, path: str, targets: Set[str]) -> None: def generate_unused_ignore_errors(self, file: str) -> None: ignored_lines = self.ignored_lines[file] if not is_typeshed_file(file) and file not in self.ignored_files: - for line in set(ignored_lines) - self.used_ignored_lines[file]: + ignored_lines = self.ignored_lines[file] + used_ignored_lines = self.used_ignored_lines[file] + for line, ignored_codes in ignored_lines.items(): + used_ignored_codes = used_ignored_lines[line] + unused_ignored_codes = set(ignored_codes) - set(used_ignored_codes) + # `ignore` is used + if len(ignored_codes) == 0 and len(used_ignored_codes) > 0: + continue + # All codes appearing in `ignore[...]` are used + if len(ignored_codes) > 0 and len(unused_ignored_codes) == 0: + continue + # Display detail only when `ignore[...]` specifies more than one error code + unused_codes_message = "" + if len(ignored_codes) > 1 and len(unused_ignored_codes) > 0: + unused_codes_message = f"[{', '.join(sorted(unused_ignored_codes))}]" + message = f'Unused "type: ignore{unused_codes_message}" comment' # Don't use report since add_error_info will ignore the error! info = ErrorInfo(self.import_context(), file, self.current_module(), None, - None, line, -1, 'error', 'unused "type: ignore" comment', + None, line, -1, 'error', message, None, False, False, False) self._add_error_info(file, info) @@ -661,7 +678,12 @@ def render_messages(self, result.append((file, -1, -1, 'note', 'In class "{}":'.format(e.type), e.allow_dups, None)) - result.append((file, e.line, e.column, e.severity, e.message, e.allow_dups, e.code)) + if isinstance(e.message, ErrorMessage): + result.append( + (file, e.line, e.column, e.severity, e.message.value, e.allow_dups, e.code)) + else: + result.append( + (file, e.line, e.column, e.severity, e.message, e.allow_dups, e.code)) prev_import_context = e.import_ctx prev_function_or_member = e.function_or_member diff --git a/mypy/expandtype.py b/mypy/expandtype.py index 8b7d434d1e31..ca1bac71cc52 100644 --- a/mypy/expandtype.py +++ b/mypy/expandtype.py @@ -2,10 +2,10 @@ from mypy.types import ( Type, Instance, CallableType, TypeVisitor, UnboundType, AnyType, - NoneType, TypeVarType, Overloaded, TupleType, TypedDictType, UnionType, + NoneType, Overloaded, TupleType, TypedDictType, UnionType, ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, TypeVarId, FunctionLike, TypeVarType, LiteralType, get_proper_type, ProperType, - TypeAliasType, ParamSpecType + TypeAliasType, ParamSpecType, TypeVarLikeType ) @@ -41,11 +41,12 @@ def freshen_function_type_vars(callee: F) -> F: tvs = [] tvmap: Dict[TypeVarId, Type] = {} for v in callee.variables: - # TODO(shantanu): fix for ParamSpecType - if isinstance(v, ParamSpecType): - continue - assert isinstance(v, TypeVarType) - tv = TypeVarType.new_unification_variable(v) + # TODO(PEP612): fix for ParamSpecType + if isinstance(v, TypeVarType): + tv: TypeVarLikeType = TypeVarType.new_unification_variable(v) + else: + assert isinstance(v, ParamSpecType) + tv = ParamSpecType.new_unification_variable(v) tvs.append(tv) tvmap[v.id] = tv fresh = cast(CallableType, expand_type(callee, tvmap)).copy_modified(variables=tvs) @@ -98,7 +99,37 @@ def visit_type_var(self, t: TypeVarType) -> Type: else: return repl + def visit_param_spec(self, t: ParamSpecType) -> Type: + repl = get_proper_type(self.variables.get(t.id, t)) + if isinstance(repl, Instance): + inst = repl + # Return copy of instance with type erasure flag on. + return Instance(inst.type, inst.args, line=inst.line, + column=inst.column, erased=True) + elif isinstance(repl, ParamSpecType): + return repl.with_flavor(t.flavor) + else: + return repl + def visit_callable_type(self, t: CallableType) -> Type: + param_spec = t.param_spec() + if param_spec is not None: + repl = get_proper_type(self.variables.get(param_spec.id)) + # If a ParamSpec in a callable type is substituted with a + # callable type, we can't use normal substitution logic, + # since ParamSpec is actually split into two components + # *P.args and **P.kwargs in the original type. Instead, we + # must expand both of them with all the argument types, + # kinds and names in the replacement. The return type in + # the replacement is ignored. + if isinstance(repl, CallableType): + # Substitute *args: P.args, **kwargs: P.kwargs + t = t.expand_param_spec(repl) + # TODO: Substitute remaining arg types + return t.copy_modified(ret_type=t.ret_type.accept(self), + type_guard=(t.type_guard.accept(self) + if t.type_guard is not None else None)) + return t.copy_modified(arg_types=self.expand_types(t.arg_types), ret_type=t.ret_type.accept(self), type_guard=(t.type_guard.accept(self) diff --git a/mypy/fastparse.py b/mypy/fastparse.py index 3108d4602a8a..34fe2c0da32d 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -1,11 +1,12 @@ from mypy.util import unnamed_function +import copy import re import sys import warnings import typing # for typing.Type, which conflicts with types.Type from typing import ( - Tuple, Union, TypeVar, Callable, Sequence, Optional, Any, Dict, cast, List, overload + Tuple, Union, TypeVar, Callable, Sequence, Optional, Any, Dict, cast, List ) from typing_extensions import Final, Literal, overload @@ -130,7 +131,7 @@ def ast3_parse(source: Union[str, bytes], filename: str, mode: str, INVALID_TYPE_IGNORE: Final = 'Invalid "type: ignore" comment' -TYPE_IGNORE_PATTERN = re.compile(r'[^#]*#\s*type:\s*ignore\s*(.*)') +TYPE_IGNORE_PATTERN: Final = re.compile(r'[^#]*#\s*type:\s*ignore\s*(.*)') def parse(source: Union[str, bytes], @@ -358,7 +359,8 @@ def translate_stmt_list(self, # ignores the whole module: if (ismodule and stmts and self.type_ignores and min(self.type_ignores) < self.get_lineno(stmts[0])): - self.errors.used_ignored_lines[self.errors.file].add(min(self.type_ignores)) + self.errors.used_ignored_lines[self.errors.file][min(self.type_ignores)].append( + codes.MISC.code) block = Block(self.fix_function_overloads(self.translate_stmt_list(stmts))) mark_block_unreachable(block) return [block] @@ -1284,6 +1286,12 @@ def visit_Index(self, n: Index) -> Node: # cast for mypyc's benefit on Python 3.9 return self.visit(cast(Any, n).value) + def visit_Match(self, n: Any) -> Node: + self.fail("Match statement is not supported", + line=n.lineno, column=n.col_offset, blocker=True) + # Just return some valid node + return PassStmt() + class TypeConverter: def __init__(self, @@ -1551,22 +1559,38 @@ def visit_Bytes(self, n: Bytes) -> Type: contents = bytes_to_human_readable_repr(n.s) return RawExpressionType(contents, 'builtins.bytes', self.line, column=n.col_offset) + def visit_Index(self, n: ast3.Index) -> Type: + # cast for mypyc's benefit on Python 3.9 + return self.visit(cast(Any, n).value) + + def visit_Slice(self, n: ast3.Slice) -> Type: + return self.invalid_type( + n, note="did you mean to use ',' instead of ':' ?" + ) + # Subscript(expr value, slice slice, expr_context ctx) # Python 3.8 and before # Subscript(expr value, expr slice, expr_context ctx) # Python 3.9 and later def visit_Subscript(self, n: ast3.Subscript) -> Type: if sys.version_info >= (3, 9): # Really 3.9a5 or later sliceval: Any = n.slice - if (isinstance(sliceval, ast3.Slice) or - (isinstance(sliceval, ast3.Tuple) and - any(isinstance(x, ast3.Slice) for x in sliceval.elts))): - self.fail(TYPE_COMMENT_SYNTAX_ERROR, self.line, getattr(n, 'col_offset', -1)) - return AnyType(TypeOfAny.from_error) + # Python 3.8 or earlier use a different AST structure for subscripts + elif isinstance(n.slice, ast3.Index): + sliceval: Any = n.slice.value + elif isinstance(n.slice, ast3.Slice): + sliceval = copy.deepcopy(n.slice) # so we don't mutate passed AST + if getattr(sliceval, "col_offset", None) is None: + # Fix column information so that we get Python 3.9+ message order + sliceval.col_offset = sliceval.lower.col_offset else: - # Python 3.8 or earlier use a different AST structure for subscripts - if not isinstance(n.slice, Index): - self.fail(TYPE_COMMENT_SYNTAX_ERROR, self.line, getattr(n, 'col_offset', -1)) - return AnyType(TypeOfAny.from_error) - sliceval = n.slice.value + assert isinstance(n.slice, ast3.ExtSlice) + dims = copy.deepcopy(n.slice.dims) + for s in dims: + if getattr(s, "col_offset", None) is None: + if isinstance(s, ast3.Index): + s.col_offset = s.value.col_offset # type: ignore + elif isinstance(s, ast3.Slice): + s.col_offset = s.lower.col_offset # type: ignore + sliceval = ast3.Tuple(dims, n.ctx) empty_tuple_index = False if isinstance(sliceval, ast3.Tuple): diff --git a/mypy/fastparse2.py b/mypy/fastparse2.py index bf5ec9663a78..2d288bf158e5 100644 --- a/mypy/fastparse2.py +++ b/mypy/fastparse2.py @@ -215,7 +215,8 @@ def translate_stmt_list(self, # ignores the whole module: if (module and stmts and self.type_ignores and min(self.type_ignores) < self.get_lineno(stmts[0])): - self.errors.used_ignored_lines[self.errors.file].add(min(self.type_ignores)) + self.errors.used_ignored_lines[self.errors.file][min(self.type_ignores)].append( + codes.MISC.code) block = Block(self.fix_function_overloads(self.translate_stmt_list(stmts))) mark_block_unreachable(block) return [block] diff --git a/mypy/fixup.py b/mypy/fixup.py index b8c494292d28..da54c40e733f 100644 --- a/mypy/fixup.py +++ b/mypy/fixup.py @@ -4,14 +4,13 @@ from typing_extensions import Final from mypy.nodes import ( - MypyFile, SymbolNode, SymbolTable, SymbolTableNode, - TypeInfo, FuncDef, OverloadedFuncDef, Decorator, Var, - TypeVarExpr, ClassDef, Block, TypeAlias, + MypyFile, SymbolTable, TypeInfo, FuncDef, OverloadedFuncDef, + Decorator, Var, TypeVarExpr, ClassDef, Block, TypeAlias, ) from mypy.types import ( CallableType, Instance, Overloaded, TupleType, TypedDictType, TypeVarType, UnboundType, UnionType, TypeVisitor, LiteralType, - TypeType, NOT_READY, TypeAliasType, AnyType, TypeOfAny + TypeType, NOT_READY, TypeAliasType, AnyType, TypeOfAny, ParamSpecType ) from mypy.visitor import NodeVisitor from mypy.lookup import lookup_fully_qualified @@ -58,7 +57,8 @@ def visit_type_info(self, info: TypeInfo) -> None: if info.metaclass_type: info.metaclass_type.accept(self.type_fixer) if info._mro_refs: - info.mro = [lookup_qualified_typeinfo(self.modules, name, self.allow_missing) + info.mro = [lookup_fully_qualified_typeinfo(self.modules, name, + allow_missing=self.allow_missing) for name in info._mro_refs] info._mro_refs = None finally: @@ -74,8 +74,8 @@ def visit_symbol_table(self, symtab: SymbolTable, table_fullname: str) -> None: if cross_ref in self.modules: value.node = self.modules[cross_ref] else: - stnode = lookup_qualified_stnode(self.modules, cross_ref, - self.allow_missing) + stnode = lookup_fully_qualified(cross_ref, self.modules, + raise_on_missing=not self.allow_missing) if stnode is not None: assert stnode.node is not None, (table_fullname + "." + key, cross_ref) value.node = stnode.node @@ -121,9 +121,10 @@ def visit_decorator(self, d: Decorator) -> None: def visit_class_def(self, c: ClassDef) -> None: for v in c.type_vars: - for value in v.values: - value.accept(self.type_fixer) - v.upper_bound.accept(self.type_fixer) + if isinstance(v, TypeVarType): + for value in v.values: + value.accept(self.type_fixer) + v.upper_bound.accept(self.type_fixer) def visit_type_var_expr(self, tv: TypeVarExpr) -> None: for value in tv.values: @@ -151,7 +152,8 @@ def visit_instance(self, inst: Instance) -> None: if type_ref is None: return # We've already been here. inst.type_ref = None - inst.type = lookup_qualified_typeinfo(self.modules, type_ref, self.allow_missing) + inst.type = lookup_fully_qualified_typeinfo(self.modules, type_ref, + allow_missing=self.allow_missing) # TODO: Is this needed or redundant? # Also fix up the bases, just in case. for base in inst.type.bases: @@ -167,7 +169,8 @@ def visit_type_alias_type(self, t: TypeAliasType) -> None: if type_ref is None: return # We've already been here. t.type_ref = None - t.alias = lookup_qualified_alias(self.modules, type_ref, self.allow_missing) + t.alias = lookup_fully_qualified_alias(self.modules, type_ref, + allow_missing=self.allow_missing) for a in t.args: a.accept(self) @@ -228,8 +231,8 @@ def visit_typeddict_type(self, tdt: TypedDictType) -> None: it.accept(self) if tdt.fallback is not None: if tdt.fallback.type_ref is not None: - if lookup_qualified(self.modules, tdt.fallback.type_ref, - self.allow_missing) is None: + if lookup_fully_qualified(tdt.fallback.type_ref, self.modules, + raise_on_missing=not self.allow_missing) is None: # We reject fake TypeInfos for TypedDict fallbacks because # the latter are used in type checking and must be valid. tdt.fallback.type_ref = 'typing._TypedDict' @@ -245,6 +248,9 @@ def visit_type_var(self, tvt: TypeVarType) -> None: if tvt.upper_bound is not None: tvt.upper_bound.accept(self) + def visit_param_spec(self, p: ParamSpecType) -> None: + p.upper_bound.accept(self) + def visit_unbound_type(self, o: UnboundType) -> None: for a in o.args: a.accept(self) @@ -261,9 +267,10 @@ def visit_type_type(self, t: TypeType) -> None: t.item.accept(self) -def lookup_qualified_typeinfo(modules: Dict[str, MypyFile], name: str, - allow_missing: bool) -> TypeInfo: - node = lookup_qualified(modules, name, allow_missing) +def lookup_fully_qualified_typeinfo(modules: Dict[str, MypyFile], name: str, *, + allow_missing: bool) -> TypeInfo: + stnode = lookup_fully_qualified(name, modules, raise_on_missing=not allow_missing) + node = stnode.node if stnode else None if isinstance(node, TypeInfo): return node else: @@ -275,9 +282,10 @@ def lookup_qualified_typeinfo(modules: Dict[str, MypyFile], name: str, return missing_info(modules) -def lookup_qualified_alias(modules: Dict[str, MypyFile], name: str, - allow_missing: bool) -> TypeAlias: - node = lookup_qualified(modules, name, allow_missing) +def lookup_fully_qualified_alias(modules: Dict[str, MypyFile], name: str, *, + allow_missing: bool) -> TypeAlias: + stnode = lookup_fully_qualified(name, modules, raise_on_missing=not allow_missing) + node = stnode.node if stnode else None if isinstance(node, TypeAlias): return node else: @@ -289,20 +297,6 @@ def lookup_qualified_alias(modules: Dict[str, MypyFile], name: str, return missing_alias() -def lookup_qualified(modules: Dict[str, MypyFile], name: str, - allow_missing: bool) -> Optional[SymbolNode]: - stnode = lookup_qualified_stnode(modules, name, allow_missing) - if stnode is None: - return None - else: - return stnode.node - - -def lookup_qualified_stnode(modules: Dict[str, MypyFile], name: str, - allow_missing: bool) -> Optional[SymbolTableNode]: - return lookup_fully_qualified(name, modules, raise_on_missing=not allow_missing) - - _SUGGESTION: Final = "" @@ -312,8 +306,7 @@ def missing_info(modules: Dict[str, MypyFile]) -> TypeInfo: dummy_def.fullname = suggestion info = TypeInfo(SymbolTable(), dummy_def, "") - obj_type = lookup_qualified(modules, 'builtins.object', False) - assert isinstance(obj_type, TypeInfo) + obj_type = lookup_fully_qualified_typeinfo(modules, 'builtins.object', allow_missing=False) info.bases = [Instance(obj_type, [])] info.mro = [info, obj_type] return info diff --git a/mypy/fscache.py b/mypy/fscache.py index 37f50f6228a4..ea71577b5f86 100644 --- a/mypy/fscache.py +++ b/mypy/fscache.py @@ -30,7 +30,6 @@ import os import stat -import sys from typing import Dict, List, Set from mypy.util import hash_digest from mypy_extensions import mypyc_attr @@ -107,6 +106,9 @@ def init_under_package_root(self, path: str) -> bool: dirname, basename = os.path.split(path) if basename != '__init__.py': return False + 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: @@ -199,9 +201,6 @@ def isfile_case(self, path: str, prefix: str) -> bool: The caller must ensure that prefix is a valid file system prefix of path. """ - if sys.platform == "linux": - # Assume that the file system on Linux is case sensitive - return self.isfile(path) if not self.isfile(path): # Fast path return False @@ -220,12 +219,14 @@ def isfile_case(self, path: str, prefix: str) -> bool: res = False if res: # Also recursively check the other path components in case sensitive way. - res = self._exists_case(head, prefix) + res = self.exists_case(head, prefix) self.isfile_case_cache[path] = res return res - def _exists_case(self, path: str, prefix: str) -> bool: - """Helper to check path components in case sensitive fashion, up to prefix.""" + def exists_case(self, path: str, prefix: str) -> bool: + """Return whether path exists - checking path components in case sensitive + fashion, up to prefix. + """ if path in self.exists_case_cache: return self.exists_case_cache[path] head, tail = os.path.split(path) @@ -242,7 +243,7 @@ def _exists_case(self, path: str, prefix: str) -> bool: res = False if res: # Also recursively check other path components. - res = self._exists_case(head, prefix) + res = self.exists_case(head, prefix) self.exists_case_cache[path] = res return res diff --git a/mypy/indirection.py b/mypy/indirection.py index 96992285c90f..238f46c8830f 100644 --- a/mypy/indirection.py +++ b/mypy/indirection.py @@ -64,6 +64,9 @@ def visit_deleted_type(self, t: types.DeletedType) -> Set[str]: def visit_type_var(self, t: types.TypeVarType) -> Set[str]: return self._visit(t.values) | self._visit(t.upper_bound) + def visit_param_spec(self, t: types.ParamSpecType) -> Set[str]: + return set() + def visit_instance(self, t: types.Instance) -> Set[str]: out = self._visit(t.args) if t.type: diff --git a/mypy/infer.py b/mypy/infer.py index da8acf31e1e1..ca521e211493 100644 --- a/mypy/infer.py +++ b/mypy/infer.py @@ -1,19 +1,34 @@ """Utilities for type argument inference.""" -from typing import List, Optional, Sequence +from typing import List, Optional, Sequence, NamedTuple from mypy.constraints import ( infer_constraints, infer_constraints_for_callable, SUBTYPE_OF, SUPERTYPE_OF ) -from mypy.types import Type, TypeVarId, CallableType +from mypy.types import Type, TypeVarId, CallableType, Instance from mypy.nodes import ArgKind from mypy.solve import solve_constraints +class ArgumentInferContext(NamedTuple): + """Type argument inference context. + + We need this because we pass around ``Mapping`` and ``Iterable`` types. + These types are only known by ``TypeChecker`` itself. + It is required for ``*`` and ``**`` argument inference. + + https://github.com/python/mypy/issues/11144 + """ + + mapping_type: Instance + iterable_type: Instance + + def infer_function_type_arguments(callee_type: CallableType, arg_types: Sequence[Optional[Type]], arg_kinds: List[ArgKind], formal_to_actual: List[List[int]], + context: ArgumentInferContext, strict: bool = True) -> List[Optional[Type]]: """Infer the type arguments of a generic function. @@ -30,7 +45,7 @@ def infer_function_type_arguments(callee_type: CallableType, """ # Infer constraints. constraints = infer_constraints_for_callable( - callee_type, arg_types, arg_kinds, formal_to_actual) + callee_type, arg_types, arg_kinds, formal_to_actual, context) # Solve constraints. type_vars = callee_type.type_var_ids() diff --git a/mypy/join.py b/mypy/join.py index e18bc6281fde..e0d926f3fcf4 100644 --- a/mypy/join.py +++ b/mypy/join.py @@ -7,7 +7,7 @@ Type, AnyType, NoneType, TypeVisitor, Instance, UnboundType, TypeVarType, CallableType, TupleType, TypedDictType, ErasedType, UnionType, FunctionLike, Overloaded, LiteralType, PartialType, DeletedType, UninhabitedType, TypeType, TypeOfAny, get_proper_type, - ProperType, get_proper_types, TypeAliasType, PlaceholderType + ProperType, get_proper_types, TypeAliasType, PlaceholderType, ParamSpecType ) from mypy.maptype import map_instance_to_supertype from mypy.subtypes import ( @@ -17,7 +17,6 @@ from mypy.nodes import INVARIANT, COVARIANT, CONTRAVARIANT import mypy.typeops from mypy import state -from mypy import meet class InstanceJoiner: @@ -30,7 +29,7 @@ def join_instances(self, t: Instance, s: Instance) -> ProperType: self.seen_instances.append((t, s)) - """Calculate the join of two instance types.""" + # Calculate the join of two instance types if t.type == s.type: # Simplest case: join two types with the same base type (but # potentially different arguments). @@ -47,26 +46,29 @@ def join_instances(self, t: Instance, s: Instance) -> ProperType: new_type = AnyType(TypeOfAny.from_another_any, ta_proper) elif isinstance(sa_proper, AnyType): new_type = AnyType(TypeOfAny.from_another_any, sa_proper) - elif type_var.variance == COVARIANT: - new_type = join_types(ta, sa, self) - if len(type_var.values) != 0 and new_type not in type_var.values: - self.seen_instances.pop() - return object_from_instance(t) - if not is_subtype(new_type, type_var.upper_bound): - self.seen_instances.pop() - return object_from_instance(t) - elif type_var.variance == CONTRAVARIANT: - new_type = meet.meet_types(ta, sa) - if len(type_var.values) != 0 and new_type not in type_var.values: - self.seen_instances.pop() - return object_from_instance(t) - # No need to check subtype, as ta and sa already have to be subtypes of - # upper_bound - elif type_var.variance == INVARIANT: - new_type = join_types(ta, sa) + elif isinstance(type_var, TypeVarType): + if type_var.variance == COVARIANT: + new_type = join_types(ta, sa, self) + if len(type_var.values) != 0 and new_type not in type_var.values: + self.seen_instances.pop() + return object_from_instance(t) + if not is_subtype(new_type, type_var.upper_bound): + self.seen_instances.pop() + return object_from_instance(t) + # TODO: contravariant case should use meet but pass seen instances as + # an argument to keep track of recursive checks. + elif type_var.variance in (INVARIANT, CONTRAVARIANT): + if not is_equivalent(ta, sa): + self.seen_instances.pop() + return object_from_instance(t) + # If the types are different but equivalent, then an Any is involved + # so using a join in the contravariant case is also OK. + new_type = join_types(ta, sa, self) + else: + # ParamSpec type variables behave the same, independent of variance if not is_equivalent(ta, sa): - self.seen_instances.pop() - return object_from_instance(t) + return get_proper_type(type_var.upper_bound) + new_type = join_types(ta, sa, self) assert new_type is not None args.append(new_type) result: ProperType = Instance(t.type, args) @@ -249,6 +251,11 @@ def visit_type_var(self, t: TypeVarType) -> ProperType: else: return self.default(self.s) + def visit_param_spec(self, t: ParamSpecType) -> ProperType: + if self.s == t: + return t + return self.default(self.s) + def visit_instance(self, t: Instance) -> ProperType: if isinstance(self.s, Instance): if self.instance_joiner is None: @@ -449,6 +456,8 @@ def default(self, typ: Type) -> ProperType: return self.default(typ.fallback) elif isinstance(typ, TypeVarType): return self.default(typ.upper_bound) + elif isinstance(typ, ParamSpecType): + return self.default(typ.upper_bound) else: return AnyType(TypeOfAny.special_form) diff --git a/mypy/literals.py b/mypy/literals.py index 16288433b460..00cf5916bec2 100644 --- a/mypy/literals.py +++ b/mypy/literals.py @@ -61,6 +61,9 @@ def literal(e: Expression) -> int: elif isinstance(e, (MemberExpr, UnaryExpr, StarExpr)): return literal(e.expr) + elif isinstance(e, AssignmentExpr): + return literal(e.target) + elif isinstance(e, IndexExpr): if literal(e.index) == LITERAL_YES: return literal(e.base) @@ -160,8 +163,8 @@ def visit_index_expr(self, e: IndexExpr) -> Optional[Key]: return ('Index', literal_hash(e.base), literal_hash(e.index)) return None - def visit_assignment_expr(self, e: AssignmentExpr) -> None: - return None + def visit_assignment_expr(self, e: AssignmentExpr) -> Optional[Key]: + return literal_hash(e.target) def visit_call_expr(self, e: CallExpr) -> None: return None diff --git a/mypy/lookup.py b/mypy/lookup.py index 41464d83dc5e..fcb2f1607393 100644 --- a/mypy/lookup.py +++ b/mypy/lookup.py @@ -9,7 +9,7 @@ # TODO: gradually move existing lookup functions to this module. -def lookup_fully_qualified(name: str, modules: Dict[str, MypyFile], +def lookup_fully_qualified(name: str, modules: Dict[str, MypyFile], *, raise_on_missing: bool = False) -> Optional[SymbolTableNode]: """Find a symbol using it fully qualified name. diff --git a/mypy/main.py b/mypy/main.py index 9ecd345126f4..d765781838cf 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -48,13 +48,16 @@ def main(script_path: Optional[str], stdout: TextIO, stderr: TextIO, args: Optional[List[str]] = None, + clean_exit: bool = False, ) -> None: """Main entry point to the type checker. Args: script_path: Path to the 'mypy' script (used for finding data files). args: Custom command-line arguments. If not given, sys.argv[1:] will - be used. + be used. + clean_exit: Don't hard kill the process on exit. This allows catching + SystemExit. """ util.check_python_version('mypy') t0 = time.time() @@ -66,6 +69,8 @@ def main(script_path: Optional[str], fscache = FileSystemCache() sources, options = process_options(args, stdout=stdout, stderr=stderr, fscache=fscache) + if clean_exit: + options.fast_exit = False formatter = util.FancyFormatter(stdout, stderr, options.show_error_codes) @@ -80,8 +85,12 @@ def main(script_path: Optional[str], fail("error: --install-types not supported with incremental mode disabled", stderr, options) + if options.install_types and options.python_executable is None: + fail("error: --install-types not supported without python executable or site packages", + stderr, options) + if options.install_types and not sources: - install_types(options.cache_dir, formatter, non_interactive=options.non_interactive) + install_types(formatter, options, non_interactive=options.non_interactive) return res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr) @@ -90,7 +99,7 @@ def main(script_path: Optional[str], missing_pkgs = read_types_packages_to_install(options.cache_dir, after_run=True) if missing_pkgs: # Install missing type packages and rerun build. - install_types(options.cache_dir, formatter, after_run=True, non_interactive=True) + install_types(formatter, options, after_run=True, non_interactive=True) fscache.flush() print() res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr) @@ -117,8 +126,7 @@ def main(script_path: Optional[str], stdout.flush() if options.install_types and not options.non_interactive: - result = install_types(options.cache_dir, formatter, after_run=True, - non_interactive=False) + result = install_types(formatter, options, after_run=True, non_interactive=False) if result: print() print("note: Run mypy again for up-to-date results with installed types") @@ -769,7 +777,7 @@ def add_invertible_flag(flag: str, dest='shadow_file', action='append', help="When encountering SOURCE_FILE, read and type check " "the contents of SHADOW_FILE instead.") - add_invertible_flag('--fast-exit', default=False, help=argparse.SUPPRESS, + add_invertible_flag('--fast-exit', default=True, help=argparse.SUPPRESS, group=internals_group) report_group = parser.add_argument_group( @@ -864,11 +872,13 @@ def add_invertible_flag(flag: str, group=code_group) code_group.add_argument( "--exclude", + action="append", metavar="PATTERN", - default="", + default=[], help=( "Regular expression to match file names, directory names or paths which mypy should " - "ignore while recursively discovering files to check, e.g. --exclude '/setup\\.py$'" + "ignore while recursively discovering files to check, e.g. --exclude '/setup\\.py$'. " + "May be specified more than once, eg. --exclude a --exclude b" ) ) code_group.add_argument( @@ -1008,7 +1018,7 @@ def set_strict_flags() -> None: process_cache_map(parser, special_opts, options) # An explicitly specified cache_fine_grained implies local_partial_types - # (because otherwise the cache is not compatiable with dmypy) + # (because otherwise the cache is not compatible with dmypy) if options.cache_fine_grained: options.local_partial_types = True @@ -1144,20 +1154,21 @@ def read_types_packages_to_install(cache_dir: str, after_run: bool) -> List[str] return [line.strip() for line in f.readlines()] -def install_types(cache_dir: str, - formatter: util.FancyFormatter, +def install_types(formatter: util.FancyFormatter, + options: Options, *, after_run: bool = False, non_interactive: bool = False) -> bool: """Install stub packages using pip if some missing stubs were detected.""" - packages = read_types_packages_to_install(cache_dir, after_run) + packages = read_types_packages_to_install(options.cache_dir, after_run) if not packages: # If there are no missing stubs, generate no output. return False if after_run and not non_interactive: print() print('Installing missing stub packages:') - cmd = [sys.executable, '-m', 'pip', 'install'] + packages + assert options.python_executable, 'Python executable required to install types' + cmd = [options.python_executable, '-m', 'pip', 'install'] + packages print(formatter.style(' '.join(cmd), 'none', bold=True)) print() if not non_interactive: diff --git a/mypy/meet.py b/mypy/meet.py index f89c1fc7b16f..644b57afbcbe 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -5,7 +5,8 @@ Type, AnyType, TypeVisitor, UnboundType, NoneType, TypeVarType, Instance, CallableType, TupleType, TypedDictType, ErasedType, UnionType, PartialType, DeletedType, UninhabitedType, TypeType, TypeOfAny, Overloaded, FunctionLike, LiteralType, - ProperType, get_proper_type, get_proper_types, TypeAliasType, TypeGuardedType + ProperType, get_proper_type, get_proper_types, TypeAliasType, TypeGuardedType, + ParamSpecType ) from mypy.subtypes import is_equivalent, is_subtype, is_callable_compatible, is_proper_subtype from mypy.erasetype import erase_type @@ -499,6 +500,12 @@ def visit_type_var(self, t: TypeVarType) -> ProperType: else: return self.default(self.s) + def visit_param_spec(self, t: ParamSpecType) -> ProperType: + if self.s == t: + return self.s + else: + return self.default(self.s) + def visit_instance(self, t: Instance) -> ProperType: if isinstance(self.s, Instance): si = self.s diff --git a/mypy/message_registry.py b/mypy/message_registry.py index 48b53336f15d..77dff1154833 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -6,37 +6,53 @@ add a method to MessageBuilder and call this instead. """ +from typing import NamedTuple, Optional from typing_extensions import Final +from mypy import errorcodes as codes + + +class ErrorMessage(NamedTuple): + value: str + code: Optional[codes.ErrorCode] = None + + def format(self, *args: object, **kwargs: object) -> "ErrorMessage": + return ErrorMessage(self.value.format(*args, **kwargs), code=self.code) + + # Invalid types INVALID_TYPE_RAW_ENUM_VALUE: Final = "Invalid type: try using Literal[{}.{}] instead?" # Type checker error message constants -NO_RETURN_VALUE_EXPECTED: Final = "No return value expected" -MISSING_RETURN_STATEMENT: Final = "Missing return statement" -INVALID_IMPLICIT_RETURN: Final = "Implicit return in function which does not return" -INCOMPATIBLE_RETURN_VALUE_TYPE: Final = "Incompatible return value type" -RETURN_VALUE_EXPECTED: Final = "Return value expected" -NO_RETURN_EXPECTED: Final = "Return statement in function which does not return" -INVALID_EXCEPTION: Final = "Exception must be derived from BaseException" -INVALID_EXCEPTION_TYPE: Final = "Exception type must be derived from BaseException" -RETURN_IN_ASYNC_GENERATOR: Final = '"return" with value in async generator is not allowed' -INVALID_RETURN_TYPE_FOR_GENERATOR: Final = ( +NO_RETURN_VALUE_EXPECTED: Final = ErrorMessage("No return value expected", codes.RETURN_VALUE) +MISSING_RETURN_STATEMENT: Final = ErrorMessage("Missing return statement", codes.RETURN) +INVALID_IMPLICIT_RETURN: Final = ErrorMessage("Implicit return in function which does not return") +INCOMPATIBLE_RETURN_VALUE_TYPE: Final = ErrorMessage( + "Incompatible return value type", codes.RETURN_VALUE +) +RETURN_VALUE_EXPECTED: Final = ErrorMessage("Return value expected", codes.RETURN_VALUE) +NO_RETURN_EXPECTED: Final = ErrorMessage("Return statement in function which does not return") +INVALID_EXCEPTION: Final = ErrorMessage("Exception must be derived from BaseException") +INVALID_EXCEPTION_TYPE: Final = ErrorMessage("Exception type must be derived from BaseException") +RETURN_IN_ASYNC_GENERATOR: Final = ErrorMessage( + '"return" with value in async generator is not allowed' +) +INVALID_RETURN_TYPE_FOR_GENERATOR: Final = ErrorMessage( 'The return type of a generator function should be "Generator"' " or one of its supertypes" ) -INVALID_RETURN_TYPE_FOR_ASYNC_GENERATOR: Final = ( +INVALID_RETURN_TYPE_FOR_ASYNC_GENERATOR: Final = ErrorMessage( 'The return type of an async generator function should be "AsyncGenerator" or one of its ' "supertypes" ) -INVALID_GENERATOR_RETURN_ITEM_TYPE: Final = ( +INVALID_GENERATOR_RETURN_ITEM_TYPE: Final = ErrorMessage( "The return type of a generator function must be None in" " its third type parameter in Python 2" ) -YIELD_VALUE_EXPECTED: Final = "Yield value expected" +YIELD_VALUE_EXPECTED: Final = ErrorMessage("Yield value expected") INCOMPATIBLE_TYPES: Final = "Incompatible types" INCOMPATIBLE_TYPES_IN_ASSIGNMENT: Final = "Incompatible types in assignment" -INCOMPATIBLE_REDEFINITION: Final = "Incompatible redefinition" -INCOMPATIBLE_TYPES_IN_AWAIT: Final = 'Incompatible types in "await"' +INCOMPATIBLE_TYPES_IN_AWAIT: Final = ErrorMessage('Incompatible types in "await"') +INCOMPATIBLE_REDEFINITION: Final = ErrorMessage("Incompatible redefinition") INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AENTER: Final = ( 'Incompatible types in "async with" for "__aenter__"' ) @@ -45,52 +61,85 @@ ) INCOMPATIBLE_TYPES_IN_ASYNC_FOR: Final = 'Incompatible types in "async for"' -INCOMPATIBLE_TYPES_IN_YIELD: Final = 'Incompatible types in "yield"' -INCOMPATIBLE_TYPES_IN_YIELD_FROM: Final = 'Incompatible types in "yield from"' +INCOMPATIBLE_TYPES_IN_YIELD: Final = ErrorMessage('Incompatible types in "yield"') +INCOMPATIBLE_TYPES_IN_YIELD_FROM: Final = ErrorMessage('Incompatible types in "yield from"') INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION: Final = "Incompatible types in string interpolation" -MUST_HAVE_NONE_RETURN_TYPE: Final = 'The return type of "{}" must be None' -INVALID_TUPLE_INDEX_TYPE: Final = "Invalid tuple index type" -TUPLE_INDEX_OUT_OF_RANGE: Final = "Tuple index out of range" -INVALID_SLICE_INDEX: Final = "Slice index must be an integer or None" -CANNOT_INFER_LAMBDA_TYPE: Final = "Cannot infer type of lambda" +MUST_HAVE_NONE_RETURN_TYPE: Final = ErrorMessage('The return type of "{}" must be None') +INVALID_TUPLE_INDEX_TYPE: Final = ErrorMessage("Invalid tuple index type") +TUPLE_INDEX_OUT_OF_RANGE: Final = ErrorMessage("Tuple index out of range") +INVALID_SLICE_INDEX: Final = ErrorMessage("Slice index must be an integer or None") +CANNOT_INFER_LAMBDA_TYPE: Final = ErrorMessage("Cannot infer type of lambda") CANNOT_ACCESS_INIT: Final = 'Cannot access "__init__" directly' -NON_INSTANCE_NEW_TYPE: Final = '"__new__" must return a class instance (got {})' -INVALID_NEW_TYPE: Final = 'Incompatible return type for "__new__"' -BAD_CONSTRUCTOR_TYPE: Final = "Unsupported decorated constructor type" +NON_INSTANCE_NEW_TYPE: Final = ErrorMessage('"__new__" must return a class instance (got {})') +INVALID_NEW_TYPE: Final = ErrorMessage('Incompatible return type for "__new__"') +BAD_CONSTRUCTOR_TYPE: Final = ErrorMessage("Unsupported decorated constructor type") CANNOT_ASSIGN_TO_METHOD: Final = "Cannot assign to a method" CANNOT_ASSIGN_TO_TYPE: Final = "Cannot assign to a type" -INCONSISTENT_ABSTRACT_OVERLOAD: Final = ( +INCONSISTENT_ABSTRACT_OVERLOAD: Final = ErrorMessage( "Overloaded method has both abstract and non-abstract variants" ) -MULTIPLE_OVERLOADS_REQUIRED: Final = "Single overload definition, multiple required" -READ_ONLY_PROPERTY_OVERRIDES_READ_WRITE: Final = ( +MULTIPLE_OVERLOADS_REQUIRED: Final = ErrorMessage("Single overload definition, multiple required") +READ_ONLY_PROPERTY_OVERRIDES_READ_WRITE: Final = ErrorMessage( "Read-only property cannot override read-write property" ) FORMAT_REQUIRES_MAPPING: Final = "Format requires a mapping" -RETURN_TYPE_CANNOT_BE_CONTRAVARIANT: Final = ( +RETURN_TYPE_CANNOT_BE_CONTRAVARIANT: Final = ErrorMessage( "Cannot use a contravariant type variable as return type" ) -FUNCTION_PARAMETER_CANNOT_BE_COVARIANT: Final = ( +FUNCTION_PARAMETER_CANNOT_BE_COVARIANT: Final = ErrorMessage( "Cannot use a covariant type variable as a parameter" ) INCOMPATIBLE_IMPORT_OF: Final = "Incompatible import of" -FUNCTION_TYPE_EXPECTED: Final = "Function is missing a type annotation" -ONLY_CLASS_APPLICATION: Final = "Type application is only supported for generic classes" -RETURN_TYPE_EXPECTED: Final = "Function is missing a return type annotation" -ARGUMENT_TYPE_EXPECTED: Final = "Function is missing a type annotation for one or more arguments" -KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE: Final = ( +FUNCTION_TYPE_EXPECTED: Final = ErrorMessage( + "Function is missing a type annotation", codes.NO_UNTYPED_DEF +) +ONLY_CLASS_APPLICATION: Final = ErrorMessage( + "Type application is only supported for generic classes" +) +RETURN_TYPE_EXPECTED: Final = ErrorMessage( + "Function is missing a return type annotation", codes.NO_UNTYPED_DEF +) +ARGUMENT_TYPE_EXPECTED: Final = ErrorMessage( + "Function is missing a type annotation for one or more arguments", codes.NO_UNTYPED_DEF +) +KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE: Final = ErrorMessage( 'Keyword argument only valid with "str" key type in call to "dict"' ) -ALL_MUST_BE_SEQ_STR: Final = "Type of __all__ must be {}, not {}" -INVALID_TYPEDDICT_ARGS: Final = ( +ALL_MUST_BE_SEQ_STR: Final = ErrorMessage("Type of __all__ must be {}, not {}") +INVALID_TYPEDDICT_ARGS: Final = ErrorMessage( "Expected keyword arguments, {...}, or dict(...) in TypedDict constructor" ) -TYPEDDICT_KEY_MUST_BE_STRING_LITERAL: Final = "Expected TypedDict key to be string literal" -MALFORMED_ASSERT: Final = "Assertion is always true, perhaps remove parentheses?" +TYPEDDICT_KEY_MUST_BE_STRING_LITERAL: Final = ErrorMessage( + "Expected TypedDict key to be string literal" +) +MALFORMED_ASSERT: Final = ErrorMessage("Assertion is always true, perhaps remove parentheses?") DUPLICATE_TYPE_SIGNATURES: Final = "Function has duplicate type signatures" -DESCRIPTOR_SET_NOT_CALLABLE: Final = "{}.__set__ is not callable" +DESCRIPTOR_SET_NOT_CALLABLE: Final = ErrorMessage("{}.__set__ is not callable") DESCRIPTOR_GET_NOT_CALLABLE: Final = "{}.__get__ is not callable" -MODULE_LEVEL_GETATTRIBUTE: Final = "__getattribute__ is not valid at the module level" +MODULE_LEVEL_GETATTRIBUTE: Final = ErrorMessage( + "__getattribute__ is not valid at the module level" +) +NAME_NOT_IN_SLOTS: Final = ErrorMessage( + 'Trying to assign name "{}" that is not in "__slots__" of type "{}"' +) +TYPE_ALWAYS_TRUE: Final = ErrorMessage( + "{} which does not implement __bool__ or __len__ " + "so it could always be true in boolean context", + code=codes.TRUTHY_BOOL, +) +TYPE_ALWAYS_TRUE_UNIONTYPE: Final = ErrorMessage( + "{} of which no members implement __bool__ or __len__ " + "so it could always be true in boolean context", + code=codes.TRUTHY_BOOL, +) +FUNCTION_ALWAYS_TRUE: Final = ErrorMessage( + 'Function {} could always be true in boolean context', + code=codes.TRUTHY_BOOL, +) +NOT_CALLABLE: Final = '{} not callable' +PYTHON2_PRINT_FILE_TYPE: Final = ( + 'Argument "file" to "print" has incompatible type "{}"; expected "{}"' +) # Generic GENERIC_INSTANCE_VAR_CLASS_ACCESS: Final = ( @@ -105,55 +154,78 @@ # TypeVar INCOMPATIBLE_TYPEVAR_VALUE: Final = 'Value of type variable "{}" of {} cannot be {}' CANNOT_USE_TYPEVAR_AS_EXPRESSION: Final = 'Type variable "{}.{}" cannot be used as an expression' +INVALID_TYPEVAR_AS_TYPEARG: Final = 'Type variable "{}" not valid as type argument value for "{}"' +INVALID_TYPEVAR_ARG_BOUND: Final = 'Type argument {} of "{}" must be a subtype of {}' +INVALID_TYPEVAR_ARG_VALUE: Final = 'Invalid type argument value for "{}"' +TYPEVAR_VARIANCE_DEF: Final = 'TypeVar "{}" may only be a literal bool' +TYPEVAR_BOUND_MUST_BE_TYPE: Final = 'TypeVar "bound" must be a type' +TYPEVAR_UNEXPECTED_ARGUMENT: Final = 'Unexpected argument to "TypeVar()"' # Super -TOO_MANY_ARGS_FOR_SUPER: Final = 'Too many arguments for "super"' -TOO_FEW_ARGS_FOR_SUPER: Final = 'Too few arguments for "super"' -SUPER_WITH_SINGLE_ARG_NOT_SUPPORTED: Final = '"super" with a single argument not supported' -UNSUPPORTED_ARG_1_FOR_SUPER: Final = 'Unsupported argument 1 for "super"' -UNSUPPORTED_ARG_2_FOR_SUPER: Final = 'Unsupported argument 2 for "super"' -SUPER_VARARGS_NOT_SUPPORTED: Final = 'Varargs not supported with "super"' -SUPER_POSITIONAL_ARGS_REQUIRED: Final = '"super" only accepts positional arguments' -SUPER_ARG_2_NOT_INSTANCE_OF_ARG_1: Final = 'Argument 2 for "super" not an instance of argument 1' -TARGET_CLASS_HAS_NO_BASE_CLASS: Final = "Target class has no base class" -SUPER_OUTSIDE_OF_METHOD_NOT_SUPPORTED: Final = "super() outside of a method is not supported" -SUPER_ENCLOSING_POSITIONAL_ARGS_REQUIRED: Final = ( +TOO_MANY_ARGS_FOR_SUPER: Final = ErrorMessage('Too many arguments for "super"') +TOO_FEW_ARGS_FOR_SUPER: Final = ErrorMessage('Too few arguments for "super"', codes.CALL_ARG) +SUPER_WITH_SINGLE_ARG_NOT_SUPPORTED: Final = ErrorMessage( + '"super" with a single argument not supported' +) +UNSUPPORTED_ARG_1_FOR_SUPER: Final = ErrorMessage('Unsupported argument 1 for "super"') +UNSUPPORTED_ARG_2_FOR_SUPER: Final = ErrorMessage('Unsupported argument 2 for "super"') +SUPER_VARARGS_NOT_SUPPORTED: Final = ErrorMessage('Varargs not supported with "super"') +SUPER_POSITIONAL_ARGS_REQUIRED: Final = ErrorMessage('"super" only accepts positional arguments') +SUPER_ARG_2_NOT_INSTANCE_OF_ARG_1: Final = ErrorMessage( + 'Argument 2 for "super" not an instance of argument 1' +) +TARGET_CLASS_HAS_NO_BASE_CLASS: Final = ErrorMessage("Target class has no base class") +SUPER_OUTSIDE_OF_METHOD_NOT_SUPPORTED: Final = ErrorMessage( + "super() outside of a method is not supported" +) +SUPER_ENCLOSING_POSITIONAL_ARGS_REQUIRED: Final = ErrorMessage( "super() requires one or more positional arguments in enclosing function" ) # Self-type -MISSING_OR_INVALID_SELF_TYPE: Final = ( +MISSING_OR_INVALID_SELF_TYPE: Final = ErrorMessage( "Self argument missing for a non-static method (or an invalid type for self)" ) -ERASED_SELF_TYPE_NOT_SUPERTYPE: Final = ( +ERASED_SELF_TYPE_NOT_SUPERTYPE: Final = ErrorMessage( 'The erased type of self "{}" is not a supertype of its class "{}"' ) -INVALID_SELF_TYPE_OR_EXTRA_ARG: Final = ( +INVALID_SELF_TYPE_OR_EXTRA_ARG: Final = ErrorMessage( "Invalid type for self, or extra argument type in function annotation" ) # Final -CANNOT_INHERIT_FROM_FINAL: Final = 'Cannot inherit from final class "{}"' -DEPENDENT_FINAL_IN_CLASS_BODY: Final = ( +CANNOT_INHERIT_FROM_FINAL: Final = ErrorMessage('Cannot inherit from final class "{}"') +DEPENDENT_FINAL_IN_CLASS_BODY: Final = ErrorMessage( "Final name declared in class body cannot depend on type variables" ) CANNOT_ACCESS_FINAL_INSTANCE_ATTR: Final = ( 'Cannot access final instance attribute "{}" on class object' ) -CANNOT_MAKE_DELETABLE_FINAL: Final = "Deletable attribute cannot be final" +CANNOT_MAKE_DELETABLE_FINAL: Final = ErrorMessage("Deletable attribute cannot be final") # ClassVar -CANNOT_OVERRIDE_INSTANCE_VAR: Final = ( +CANNOT_OVERRIDE_INSTANCE_VAR: Final = ErrorMessage( 'Cannot override instance variable (previously declared on base class "{}") with class ' "variable" ) -CANNOT_OVERRIDE_CLASS_VAR: Final = ( +CANNOT_OVERRIDE_CLASS_VAR: Final = ErrorMessage( 'Cannot override class variable (previously declared on base class "{}") with instance ' "variable" ) +CLASS_VAR_WITH_TYPEVARS: Final = 'ClassVar cannot contain type variables' +CLASS_VAR_OUTSIDE_OF_CLASS: Final = ( + 'ClassVar can only be used for assignments in class body' +) # Protocol -RUNTIME_PROTOCOL_EXPECTED: Final = ( +RUNTIME_PROTOCOL_EXPECTED: Final = ErrorMessage( "Only @runtime_checkable protocols can be used with instance and class checks" ) -CANNOT_INSTANTIATE_PROTOCOL: Final = 'Cannot instantiate protocol class "{}"' +CANNOT_INSTANTIATE_PROTOCOL: Final = ErrorMessage('Cannot instantiate protocol class "{}"') +TOO_MANY_UNION_COMBINATIONS: Final = ErrorMessage( + "Not all union combinations were tried because there are too many unions" +) + +CONTIGUOUS_ITERABLE_EXPECTED: Final = ErrorMessage("Contiguous iterable with same type expected") +ITERABLE_TYPE_EXPECTED: Final = ErrorMessage("Invalid type '{}' for *expr (iterable expected)") +TYPE_GUARD_POS_ARG_REQUIRED: Final = ErrorMessage("Type guard requires positional argument") diff --git a/mypy/messages.py b/mypy/messages.py index 92a5487162fc..da284cc88ba4 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -22,9 +22,9 @@ from mypy.errors import Errors from mypy.types import ( Type, CallableType, Instance, TypeVarType, TupleType, TypedDictType, LiteralType, - UnionType, NoneType, AnyType, Overloaded, FunctionLike, DeletedType, TypeType, TypeVarType, + UnionType, NoneType, AnyType, Overloaded, FunctionLike, DeletedType, TypeType, UninhabitedType, TypeOfAny, UnboundType, PartialType, get_proper_type, ProperType, - get_proper_types + ParamSpecType, get_proper_types ) from mypy.typetraverser import TypeTraverserVisitor from mypy.nodes import ( @@ -289,8 +289,8 @@ def has_no_attr(self, # Explain that the problem is that the type of the function is not known. self.fail('Cannot call function of unknown type', context, code=codes.OPERATOR) else: - self.fail('{} not callable'.format(format_type(original_type)), context, - code=codes.OPERATOR) + self.fail(message_registry.NOT_CALLABLE.format( + format_type(original_type)), context, code=codes.OPERATOR) else: # The non-special case: a missing ordinary attribute. extra = '' @@ -397,7 +397,7 @@ def unsupported_left_operand(self, op: str, typ: Type, self.fail(msg, context, code=codes.OPERATOR) def not_callable(self, typ: Type, context: Context) -> Type: - self.fail('{} not callable'.format(format_type(typ)), context) + self.fail(message_registry.NOT_CALLABLE.format(format_type(typ)), context) return AnyType(TypeOfAny.from_error) def untyped_function_call(self, callee: CallableType, context: Context) -> Type: @@ -649,6 +649,7 @@ def missing_named_argument(self, callee: CallableType, context: Context, name: s def too_many_arguments(self, callee: CallableType, context: Context) -> None: msg = 'Too many arguments' + for_function(callee) self.fail(msg, context, code=codes.CALL_ARG) + self.maybe_note_about_special_args(callee, context) def too_many_arguments_from_typed_dict(self, callee: CallableType, @@ -668,6 +669,18 @@ def too_many_positional_arguments(self, callee: CallableType, context: Context) -> None: msg = 'Too many positional arguments' + for_function(callee) self.fail(msg, context) + self.maybe_note_about_special_args(callee, context) + + def maybe_note_about_special_args(self, callee: CallableType, context: Context) -> None: + # https://github.com/python/mypy/issues/11309 + first_arg = callee.def_extras.get('first_arg') + if first_arg and first_arg not in {'self', 'cls', 'mcs'}: + self.note( + 'Looks like the first special argument in a method ' + 'is not named "self", "cls", or "mcs", ' + 'maybe it is missing?', + context, + ) def unexpected_keyword_argument(self, callee: CallableType, name: str, arg_type: Type, context: Context) -> None: @@ -739,7 +752,6 @@ def deleted_as_lvalue(self, typ: DeletedType, context: Context) -> None: self.fail('Assignment to variable{} outside except: block'.format(s), context) def no_variant_matches_arguments(self, - plausible_targets: List[CallableType], overload: Overloaded, arg_types: List[Type], context: Context, @@ -763,8 +775,11 @@ def no_variant_matches_arguments(self, self.fail('No overload variant{} matches argument types {}' .format(name_str, arg_types_str), context, code=code) - self.pretty_overload_matches(plausible_targets, overload, context, offset=2, max_items=2, - code=code) + self.note( + 'Possible overload variant{}:'.format(plural_s(len(overload.items))), + context, code=code) + for item in overload.items: + self.note(pretty_callable(item), context, offset=4, code=code) def wrong_number_values_to_unpack(self, provided: int, expected: int, context: Context) -> None: @@ -783,7 +798,7 @@ def unpacking_strings_disallowed(self, context: Context) -> None: self.fail("Unpacking a string is disallowed", context) def type_not_iterable(self, type: Type, context: Context) -> None: - self.fail('"{}" object is not iterable'.format(type), context) + self.fail('{} object is not iterable'.format(format_type(type)), context) def incompatible_operator_assignment(self, op: str, context: Context) -> None: @@ -811,7 +826,6 @@ def signature_incompatible_with_supertype( INCLUDE_DECORATOR = True # Include @classmethod and @staticmethod decorators, if any ALLOW_DUPS = True # Allow duplicate notes, needed when signatures are duplicates - MAX_ITEMS = 3 # Display a max of three items for Overloaded types ALIGN_OFFSET = 1 # One space, to account for the difference between error and note OFFSET = 4 # Four spaces, so that notes will look like this: # error: Signature of "f" incompatible with supertype "A" @@ -824,14 +838,12 @@ def signature_incompatible_with_supertype( self.note('Superclass:', context, offset=ALIGN_OFFSET + OFFSET, code=code) self.pretty_callable_or_overload(original, context, offset=ALIGN_OFFSET + 2 * OFFSET, add_class_or_static_decorator=INCLUDE_DECORATOR, - overload_max_items=MAX_ITEMS, allow_dups=ALLOW_DUPS, - code=code) + allow_dups=ALLOW_DUPS, code=code) self.note('Subclass:', context, offset=ALIGN_OFFSET + OFFSET, code=code) self.pretty_callable_or_overload(override, context, offset=ALIGN_OFFSET + 2 * OFFSET, add_class_or_static_decorator=INCLUDE_DECORATOR, - overload_max_items=MAX_ITEMS, allow_dups=ALLOW_DUPS, - code=code) + allow_dups=ALLOW_DUPS, code=code) def pretty_callable_or_overload(self, tp: Union[CallableType, Overloaded], @@ -839,7 +851,6 @@ def pretty_callable_or_overload(self, *, offset: int = 0, add_class_or_static_decorator: bool = False, - overload_max_items: int = 1, allow_dups: bool = False, code: Optional[ErrorCode] = None) -> None: if isinstance(tp, CallableType): @@ -850,7 +861,7 @@ def pretty_callable_or_overload(self, self.note(pretty_callable(tp), context, offset=offset, allow_dups=allow_dups, code=code) elif isinstance(tp, Overloaded): - self.pretty_overload(tp, context, offset, overload_max_items, + self.pretty_overload(tp, context, offset, add_class_or_static_decorator=add_class_or_static_decorator, allow_dups=allow_dups, code=code) @@ -1140,11 +1151,12 @@ def yield_from_invalid_operand_type(self, expr: Type, context: Context) -> Type: return AnyType(TypeOfAny.from_error) def invalid_signature(self, func_type: Type, context: Context) -> None: - self.fail('Invalid signature "{}"'.format(func_type), context) + self.fail('Invalid signature {}'.format(format_type(func_type)), context) def invalid_signature_for_special_method( self, func_type: Type, context: Context, method_name: str) -> None: - self.fail('Invalid signature "{}" for "{}"'.format(func_type, method_name), context) + self.fail('Invalid signature {} for "{}"'.format(format_type(func_type), method_name), + context) def reveal_type(self, typ: Type, context: Context) -> None: self.note('Revealed type is "{}"'.format(typ), context) @@ -1479,13 +1491,13 @@ def report_protocol_problems(self, self.note(pretty_callable(exp), context, offset=2 * OFFSET, code=code) else: assert isinstance(exp, Overloaded) - self.pretty_overload(exp, context, 2 * OFFSET, MAX_ITEMS, code=code) + self.pretty_overload(exp, context, 2 * OFFSET, code=code) self.note('Got:', context, offset=OFFSET, code=code) if isinstance(got, CallableType): self.note(pretty_callable(got), context, offset=2 * OFFSET, code=code) else: assert isinstance(got, Overloaded) - self.pretty_overload(got, context, 2 * OFFSET, MAX_ITEMS, code=code) + self.pretty_overload(got, context, 2 * OFFSET, code=code) self.print_more(conflict_types, context, OFFSET, MAX_ITEMS, code=code) # Report flag conflicts (i.e. settable vs read-only etc.) @@ -1517,12 +1529,11 @@ def pretty_overload(self, tp: Overloaded, context: Context, offset: int, - max_items: int, *, add_class_or_static_decorator: bool = False, allow_dups: bool = False, code: Optional[ErrorCode] = None) -> None: - for item in tp.items[:max_items]: + for item in tp.items: self.note('@overload', context, offset=offset, allow_dups=allow_dups, code=code) if add_class_or_static_decorator: @@ -1532,46 +1543,6 @@ def pretty_overload(self, self.note(pretty_callable(item), context, offset=offset, allow_dups=allow_dups, code=code) - left = len(tp.items) - max_items - if left > 0: - msg = '<{} more overload{} not shown>'.format(left, plural_s(left)) - self.note(msg, context, offset=offset, allow_dups=allow_dups, code=code) - - def pretty_overload_matches(self, - targets: List[CallableType], - func: Overloaded, - context: Context, - offset: int, - max_items: int, - code: ErrorCode) -> None: - if not targets: - targets = func.items - - shown = min(max_items, len(targets)) - max_matching = len(targets) - max_available = len(func.items) - - # If there are 3 matches but max_items == 2, we might as well show - # all three items instead of having the 3rd item be an error message. - if shown + 1 == max_matching: - shown = max_matching - - self.note('Possible overload variant{}:'.format(plural_s(shown)), context, code=code) - for item in targets[:shown]: - self.note(pretty_callable(item), context, offset=2 * offset, code=code) - - assert shown <= max_matching <= max_available - if shown < max_matching <= max_available: - left = max_matching - shown - msg = '<{} more similar overload{} not shown, out of {} total overloads>'.format( - left, plural_s(left), max_available) - self.note(msg, context, offset=2 * offset, code=code) - elif shown == max_matching < max_available: - left = max_available - shown - msg = '<{} more non-matching overload{} not shown>'.format(left, plural_s(left)) - self.note(msg, context, offset=2 * offset, code=code) - else: - assert shown == max_matching == max_available def print_more(self, conflicts: Sequence[Any], @@ -1643,8 +1614,8 @@ def generate_incompatible_tuple_error(self, for i, (lhs_t, rhs_t) in enumerate(zip(lhs_types, rhs_types)): if not is_subtype(lhs_t, rhs_t): if error_cnt < 3: - notes.append('Expression tuple item {} has type "{}"; "{}" expected; ' - .format(str(i), format_type_bare(rhs_t), format_type_bare(lhs_t))) + notes.append('Expression tuple item {} has type {}; {} expected; ' + .format(str(i), format_type(rhs_t), format_type(lhs_t))) error_cnt += 1 error_msg = msg + ' ({} tuple items are incompatible'.format(str(error_cnt)) @@ -1722,6 +1693,8 @@ def format(typ: Type) -> str: elif isinstance(typ, TypeVarType): # This is similar to non-generic instance types. return typ.name + elif isinstance(typ, ParamSpecType): + return typ.name_with_suffix() elif isinstance(typ, TupleType): # Prefer the name of the fallback class (if not tuple), as it's more informative. if typ.partial_fallback.type.fullname != 'builtins.tuple': @@ -1783,9 +1756,15 @@ def format(typ: Type) -> str: # return type (this always works). return format(TypeType.make_normalized(erase_type(func.items[0].ret_type))) elif isinstance(func, CallableType): - return_type = format(func.ret_type) + if func.type_guard is not None: + return_type = f'TypeGuard[{format(func.type_guard)}]' + else: + return_type = format(func.ret_type) if func.is_ellipsis_args: return 'Callable[..., {}]'.format(return_type) + param_spec = func.param_spec() + if param_spec is not None: + return f'Callable[{param_spec.name}, {return_type}]' arg_strings = [] for arg_name, arg_type, arg_kind in zip( func.arg_names, func.arg_types, func.arg_kinds): @@ -2145,11 +2124,6 @@ def find_defining_module(modules: Dict[str, MypyFile], typ: CallableType) -> Opt return None -def temp_message_builder() -> MessageBuilder: - """Return a message builder usable for throwaway errors (which may not format properly).""" - return MessageBuilder(Errors(), {}) - - # For hard-coding suggested missing member alternatives. COMMON_MISTAKES: Final[Dict[str, Sequence[str]]] = { 'add': ('append', 'extend'), diff --git a/mypy/modulefinder.py b/mypy/modulefinder.py index 828b763148b1..8dcaee6f99d6 100644 --- a/mypy/modulefinder.py +++ b/mypy/modulefinder.py @@ -10,10 +10,10 @@ import re import subprocess import sys -from enum import Enum +from enum import Enum, unique from typing import Dict, Iterator, List, NamedTuple, Optional, Set, Tuple, Union -from typing_extensions import Final +from typing_extensions import Final, TypeAlias as _TypeAlias from mypy.fscache import FileSystemCache from mypy.options import Options @@ -33,6 +33,9 @@ OnePackageDir = Tuple[str, bool] PackageDirs = List[OnePackageDir] +# Minimum and maximum Python versions for modules in stdlib as (major, minor) +StdlibVersions: _TypeAlias = Dict[str, Tuple[Tuple[int, int], Optional[Tuple[int, int]]]] + PYTHON_EXTENSIONS: Final = [".pyi", ".py"] PYTHON2_STUB_DIR: Final = "@python2" @@ -41,6 +44,7 @@ # TODO: Consider adding more reasons here? # E.g. if we deduce a module would likely be found if the user were # to set the --namespace-packages flag. +@unique class ModuleNotFoundReason(Enum): # The module was not found: we found neither stubs nor a plausible code # implementation (with or without a py.typed file). @@ -69,7 +73,10 @@ def error_message_templates(self, daemon: bool) -> Tuple[str, List[str]]: notes = ["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 = 'Skipping analyzing "{module}": found module but no type hints or library stubs' + msg = ( + 'Skipping analyzing "{module}": module is installed, but missing library stubs ' + 'or py.typed marker' + ) notes = [doc_link] elif self is ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED: msg = ( @@ -122,7 +129,8 @@ class FindModuleCache: def __init__(self, search_paths: SearchPaths, fscache: Optional[FileSystemCache], - options: Optional[Options]) -> None: + options: Optional[Options], + stdlib_py_versions: Optional[StdlibVersions] = None) -> None: self.search_paths = search_paths self.fscache = fscache or FileSystemCache() # Cache for get_toplevel_possibilities: @@ -135,7 +143,9 @@ def __init__(self, custom_typeshed_dir = None if options: custom_typeshed_dir = options.custom_typeshed_dir - self.stdlib_py_versions = load_stdlib_py_versions(custom_typeshed_dir) + self.stdlib_py_versions = ( + stdlib_py_versions or load_stdlib_py_versions(custom_typeshed_dir) + ) self.python_major_ver = 3 if options is None else options.python_version[0] def clear(self) -> None: @@ -257,7 +267,12 @@ def _can_find_module_in_parent_dir(self, id: str) -> bool: of the current working directory. """ working_dir = os.getcwd() - parent_search = FindModuleCache(SearchPaths((), (), (), ()), self.fscache, self.options) + parent_search = FindModuleCache( + SearchPaths((), (), (), ()), + self.fscache, + self.options, + stdlib_py_versions=self.stdlib_py_versions + ) while any(file.endswith(("__init__.py", "__init__.pyi")) for file in os.listdir(working_dir)): working_dir = os.path.dirname(working_dir) @@ -372,7 +387,7 @@ def _find_module(self, id: str, use_typeshed: bool) -> ModuleSearchResult: # In namespace mode, register a potential namespace package if self.options and self.options.namespace_packages: - if fscache.isdir(base_path) and not has_init: + if fscache.exists_case(base_path, dir_prefix) and not has_init: near_misses.append((base_path, dir_prefix)) # No package, look for module. @@ -436,8 +451,8 @@ def _is_compatible_stub_package(self, stub_dir: str) -> bool: if os.path.isfile(metadata_fnam): # Delay import for a possible minor performance win. import tomli - with open(metadata_fnam, 'r', encoding="utf-8") as f: - metadata = tomli.load(f) + with open(metadata_fnam, encoding="utf-8") as f: + metadata = tomli.loads(f.read()) if self.python_major_ver == 2: return bool(metadata.get('python2', False)) else: @@ -496,16 +511,21 @@ def find_modules_recursive(self, module: str) -> List[BuildSource]: return sources -def matches_exclude(subpath: str, exclude: str, fscache: FileSystemCache, verbose: bool) -> bool: - if not exclude: +def matches_exclude(subpath: str, + excludes: List[str], + fscache: FileSystemCache, + verbose: bool) -> bool: + if not excludes: return False subpath_str = os.path.relpath(subpath).replace(os.sep, "/") if fscache.isdir(subpath): subpath_str += "/" - if re.search(exclude, subpath_str): - if verbose: - print("TRACE: Excluding {}".format(subpath_str), file=sys.stderr) - return True + for exclude in excludes: + if re.search(exclude, subpath_str): + if verbose: + print("TRACE: Excluding {} (matches pattern {})".format(subpath_str, exclude), + file=sys.stderr) + return True return False @@ -782,8 +802,7 @@ def compute_search_paths(sources: List[BuildSource], typeshed_path=tuple(lib_path)) -def load_stdlib_py_versions(custom_typeshed_dir: Optional[str] - ) -> Dict[str, Tuple[Tuple[int, int], Optional[Tuple[int, int]]]]: +def load_stdlib_py_versions(custom_typeshed_dir: Optional[str]) -> StdlibVersions: """Return dict with minimum and maximum Python versions of stdlib modules. The contents look like diff --git a/mypy/nodes.py b/mypy/nodes.py index e34a7f2add58..78a018f94a78 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -1,14 +1,14 @@ """Abstract syntax tree node classes (i.e. parse tree).""" import os -from enum import Enum +from enum import Enum, unique from abc import abstractmethod from mypy.backports import OrderedDict from collections import defaultdict from typing import ( Any, TypeVar, List, Tuple, cast, Set, Dict, Union, Optional, Callable, Sequence, Iterator ) -from typing_extensions import DefaultDict, Final, TYPE_CHECKING +from typing_extensions import DefaultDict, Final, TYPE_CHECKING, TypeAlias as _TypeAlias from mypy_extensions import trait import mypy.strconv @@ -64,7 +64,7 @@ def get_column(self) -> int: T = TypeVar('T') -JsonDict = Dict[str, Any] +JsonDict: _TypeAlias = Dict[str, Any] # Symbol table node kinds @@ -135,6 +135,12 @@ def get_column(self) -> int: 'typing.OrderedDict': (3, 7), } +# This keeps track of aliases in `typing_extensions`, which we treat specially. +typing_extensions_aliases: Final = { + # See: https://github.com/python/mypy/issues/11528 + 'typing_extensions.OrderedDict': 'collections.OrderedDict', +} + reverse_builtin_aliases: Final = { 'builtins.list': 'typing.List', 'builtins.dict': 'typing.Dict', @@ -201,13 +207,14 @@ class FakeExpression(Expression): We need a dummy expression in one place, and can't instantiate Expression because it is a trait and mypyc barfs. """ - pass + + __slots__ = () # TODO: # Lvalue = Union['NameExpr', 'MemberExpr', 'IndexExpr', 'SuperExpr', 'StarExpr' # 'TupleExpr']; see #1783. -Lvalue = Expression +Lvalue: _TypeAlias = Expression @trait @@ -240,22 +247,26 @@ def deserialize(cls, data: JsonDict) -> 'SymbolNode': # Items: fullname, related symbol table node, surrounding type (if any) -Definition = Tuple[str, 'SymbolTableNode', Optional['TypeInfo']] +Definition: _TypeAlias = Tuple[str, 'SymbolTableNode', Optional['TypeInfo']] class MypyFile(SymbolNode): """The abstract syntax tree of a single source file.""" + __slots__ = ('_fullname', 'path', 'defs', 'alias_deps', + 'is_bom', 'names', 'imports', 'ignored_lines', 'is_stub', + 'is_cache_skeleton', 'is_partial_stub_package', 'plugin_deps') + # Fully qualified module name _fullname: Bogus[str] # Path to the file (empty string if not known) - path = '' + path: str # Top-level definitions and statements defs: List[Statement] # Type alias dependencies as mapping from target to set of alias full names alias_deps: DefaultDict[str, Set[str]] # Is there a UTF-8 BOM at the start? - is_bom = False + is_bom: bool names: "SymbolTable" # All import nodes within the file (also ones within functions etc.) imports: List["ImportBase"] @@ -264,13 +275,13 @@ class MypyFile(SymbolNode): # error codes to ignore. ignored_lines: Dict[int, List[str]] # Is this file represented by a stub file (.pyi)? - is_stub = False + is_stub: bool # Is this loaded from the cache and thus missing the actual body of the file? - is_cache_skeleton = False + is_cache_skeleton: bool # Does this represent an __init__.pyi stub with a module __getattr__ # (i.e. a partial stub package), for such packages we suppress any missing # module errors in addition to missing attribute errors. - is_partial_stub_package = False + is_partial_stub_package: bool # Plugin-created dependencies plugin_deps: Dict[str, Set[str]] @@ -291,6 +302,11 @@ def __init__(self, else: self.ignored_lines = {} + self.path = '' + self.is_stub = False + self.is_cache_skeleton = False + self.is_partial_stub_package = False + def local_definitions(self) -> Iterator[Definition]: """Return all definitions within the module (including nested). @@ -337,9 +353,11 @@ def deserialize(cls, data: JsonDict) -> 'MypyFile': class ImportBase(Statement): """Base class for all import statements.""" - is_unreachable = False # Set by semanal.SemanticAnalyzerPass1 if inside `if False` etc. - is_top_level = False # Ditto if outside any class or def - is_mypy_only = False # Ditto if inside `if TYPE_CHECKING` or `if MYPY` + __slots__ = ('is_unreachable', 'is_top_level', 'is_mypy_only', 'assignments') + + is_unreachable: bool # Set by semanal.SemanticAnalyzerPass1 if inside `if False` etc. + is_top_level: bool # Ditto if outside any class or def + is_mypy_only: bool # Ditto if inside `if TYPE_CHECKING` or `if MYPY` # If an import replaces existing definitions, we construct dummy assignment # statements that assign the imported names to the names in the current scope, @@ -352,11 +370,16 @@ class ImportBase(Statement): def __init__(self) -> None: super().__init__() self.assignments = [] + self.is_unreachable = False + self.is_top_level = False + self.is_mypy_only = False class Import(ImportBase): """import m [as n]""" + __slots__ = ('ids',) + ids: List[Tuple[str, Optional[str]]] # (module id, as id) def __init__(self, ids: List[Tuple[str, Optional[str]]]) -> None: @@ -370,6 +393,8 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class ImportFrom(ImportBase): """from m import x [as y], ...""" + __slots__ = ('id', 'names', 'relative') + id: str relative: int names: List[Tuple[str, Optional[str]]] # Tuples (name, as name) @@ -387,6 +412,8 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class ImportAll(ImportBase): """from m import *""" + __slots__ = ('id', 'relative', 'imported_names') + id: str relative: int # NOTE: Only filled and used by old semantic analyzer. @@ -414,6 +441,8 @@ class ImportedName(SymbolNode): can't be visited. """ + __slots__ = ('target_fullname',) + def __init__(self, target_fullname: str) -> None: super().__init__() self.target_fullname = target_fullname @@ -491,7 +520,7 @@ def fullname(self) -> Bogus[str]: return self._fullname -OverloadPart = Union['FuncDef', 'Decorator'] +OverloadPart: _TypeAlias = Union['FuncDef', 'Decorator'] class OverloadedFuncDef(FuncBase, SymbolNode, Statement): @@ -504,9 +533,11 @@ class OverloadedFuncDef(FuncBase, SymbolNode, Statement): Overloaded variants must be consecutive in the source file. """ + __slots__ = ('items', 'unanalyzed_items', 'impl') + items: List[OverloadPart] unanalyzed_items: List[OverloadPart] - impl: Optional[OverloadPart] = None + impl: Optional[OverloadPart] def __init__(self, items: List['OverloadPart']) -> None: super().__init__() @@ -745,13 +776,15 @@ class Decorator(SymbolNode, Statement): A single Decorator object can include any number of function decorators. """ + __slots__ = ('func', 'decorators', 'original_decorators', 'var', 'is_overload') + func: FuncDef # Decorated function decorators: List[Expression] # Decorators (may be empty) # Some decorators are removed by semanal, keep the original here. original_decorators: List[Expression] # TODO: This is mostly used for the type; consider replacing with a 'type' attribute var: "Var" # Represents the decorated function obj - is_overload = False + is_overload: bool def __init__(self, func: FuncDef, decorators: List[Expression], var: 'Var') -> None: @@ -807,6 +840,7 @@ def deserialize(cls, data: JsonDict) -> 'Decorator': 'is_classmethod', 'is_property', 'is_settable_property', 'is_suppressed_import', 'is_classvar', 'is_abstract_var', 'is_final', 'final_unset_in_class', 'final_set_in_init', 'explicit_self_type', 'is_ready', 'from_module_getattr', + 'has_explicit_value', ] @@ -837,6 +871,7 @@ class Var(SymbolNode): 'is_suppressed_import', 'explicit_self_type', 'from_module_getattr', + 'has_explicit_value', ) def __init__(self, name: str, type: 'Optional[mypy.types.Type]' = None) -> None: @@ -881,6 +916,9 @@ def __init__(self, name: str, type: 'Optional[mypy.types.Type]' = None) -> None: self.explicit_self_type = False # If True, this is an implicit Var created due to module-level __getattr__. self.from_module_getattr = False + # Var can be created with an explicit value `a = 1` or without one `a: int`, + # we need a way to tell which one is which. + self.has_explicit_value = False @property def name(self) -> str: @@ -922,30 +960,36 @@ def deserialize(cls, data: JsonDict) -> 'Var': class ClassDef(Statement): """Class definition""" + + __slots__ = ('name', 'fullname', 'defs', 'type_vars', 'base_type_exprs', + 'removed_base_type_exprs', 'info', 'metaclass', 'decorators', + 'keywords', 'analyzed', 'has_incompatible_baseclass') + name: str # Name of the class without module prefix - fullname: Bogus[str] = None # type: ignore # Fully qualified name of the class + fullname: Bogus[str] # Fully qualified name of the class defs: "Block" - type_vars: List["mypy.types.TypeVarType"] + type_vars: List["mypy.types.TypeVarLikeType"] # Base class expressions (not semantically analyzed -- can be arbitrary expressions) base_type_exprs: List[Expression] # Special base classes like Generic[...] get moved here during semantic analysis removed_base_type_exprs: List[Expression] info: "TypeInfo" # Related TypeInfo - metaclass: Optional[Expression] = None + metaclass: Optional[Expression] decorators: List[Expression] keywords: "OrderedDict[str, Expression]" - analyzed: Optional[Expression] = None - has_incompatible_baseclass = False + analyzed: Optional[Expression] + has_incompatible_baseclass: bool def __init__(self, name: str, defs: 'Block', - type_vars: Optional[List['mypy.types.TypeVarType']] = None, + type_vars: Optional[List['mypy.types.TypeVarLikeType']] = None, base_type_exprs: Optional[List[Expression]] = None, metaclass: Optional[Expression] = None, keywords: Optional[List[Tuple[str, Expression]]] = None) -> None: super().__init__() self.name = name + self.fullname = None # type: ignore self.defs = defs self.type_vars = type_vars or [] self.base_type_exprs = base_type_exprs or [] @@ -954,6 +998,8 @@ def __init__(self, self.metaclass = metaclass self.decorators = [] self.keywords = OrderedDict(keywords or []) + self.analyzed = None + self.has_incompatible_baseclass = False def accept(self, visitor: StatementVisitor[T]) -> T: return visitor.visit_class_def(self) @@ -984,6 +1030,8 @@ def deserialize(self, data: JsonDict) -> 'ClassDef': class GlobalDecl(Statement): """Declaration global x, y, ...""" + __slots__ = ('names',) + names: List[str] def __init__(self, names: List[str]) -> None: @@ -997,6 +1045,8 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class NonlocalDecl(Statement): """Declaration nonlocal x, y, ...""" + __slots__ = ('names',) + names: List[str] def __init__(self, names: List[str]) -> None: @@ -1030,6 +1080,8 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class ExpressionStmt(Statement): """An expression as a statement, such as print(s).""" + __slots__ = ('expr',) + expr: Expression def __init__(self, expr: Expression) -> None: @@ -1051,24 +1103,27 @@ class AssignmentStmt(Statement): An lvalue can be NameExpr, TupleExpr, ListExpr, MemberExpr, or IndexExpr. """ + __slots__ = ('lvalues', 'rvalue', 'type', 'unanalyzed_type', 'new_syntax', + 'is_alias_def', 'is_final_def') + lvalues: List[Lvalue] # This is a TempNode if and only if no rvalue (x: t). rvalue: Expression # Declared type in a comment, may be None. - type: Optional["mypy.types.Type"] = None + type: Optional["mypy.types.Type"] # Original, not semantically analyzed type in annotation (used for reprocessing) - unanalyzed_type: Optional["mypy.types.Type"] = None + unanalyzed_type: Optional["mypy.types.Type"] # This indicates usage of PEP 526 type annotation syntax in assignment. - new_syntax: bool = False + new_syntax: bool # Does this assignment define a type alias? - is_alias_def = False + is_alias_def: bool # Is this a final definition? # Final attributes can't be re-assigned once set, and can't be overridden # in a subclass. This flag is not set if an attempted declaration was found to # be invalid during semantic analysis. It is still set to `True` if # a final declaration overrides another final declaration (this is checked # during type checking when MROs are known). - is_final_def = False + is_final_def: bool def __init__(self, lvalues: List[Lvalue], rvalue: Expression, type: 'Optional[mypy.types.Type]' = None, new_syntax: bool = False) -> None: @@ -1078,6 +1133,8 @@ def __init__(self, lvalues: List[Lvalue], rvalue: Expression, self.type = type self.unanalyzed_type = type self.new_syntax = new_syntax + self.is_alias_def = False + self.is_final_def = False def accept(self, visitor: StatementVisitor[T]) -> T: return visitor.visit_assignment_stmt(self) @@ -1086,7 +1143,9 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class OperatorAssignmentStmt(Statement): """Operator assignment statement such as x += 1""" - op = '' + __slots__ = ('op', 'lvalue', 'rvalue') + + op: str # TODO: Enum? lvalue: Lvalue rvalue: Expression @@ -1101,9 +1160,11 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class WhileStmt(Statement): + __slots__ = ('expr', 'body', 'else_body') + expr: Expression body: Block - else_body: Optional[Block] = None + else_body: Optional[Block] def __init__(self, expr: Expression, body: Block, else_body: Optional[Block]) -> None: super().__init__() @@ -1116,21 +1177,25 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class ForStmt(Statement): + __slots__ = ('index', 'index_type', 'unanalyzed_index_type', + 'inferred_item_type', 'inferred_iterator_type', + 'expr', 'body', 'else_body', 'is_async') + # Index variables index: Lvalue # Type given by type comments for index, can be None - index_type: Optional["mypy.types.Type"] = None + index_type: Optional["mypy.types.Type"] # Original, not semantically analyzed type in annotation (used for reprocessing) - unanalyzed_index_type: Optional["mypy.types.Type"] = None + unanalyzed_index_type: Optional["mypy.types.Type"] # Inferred iterable item type - inferred_item_type: Optional["mypy.types.Type"] = None + inferred_item_type: Optional["mypy.types.Type"] # Inferred iterator type - inferred_iterator_type: Optional["mypy.types.Type"] = None + inferred_iterator_type: Optional["mypy.types.Type"] # Expression to iterate expr: Expression body: Block - else_body: Optional[Block] = None - is_async = False # True if `async for ...` (PEP 492, Python 3.5) + else_body: Optional[Block] + is_async: bool # True if `async for ...` (PEP 492, Python 3.5) def __init__(self, index: Lvalue, @@ -1142,16 +1207,21 @@ def __init__(self, self.index = index self.index_type = index_type self.unanalyzed_index_type = index_type + self.inferred_item_type = None + self.inferred_iterator_type = None self.expr = expr self.body = body self.else_body = else_body + self.is_async = False def accept(self, visitor: StatementVisitor[T]) -> T: return visitor.visit_for_stmt(self) class ReturnStmt(Statement): - expr: Optional[Expression] = None + __slots__ = ('expr',) + + expr: Optional[Expression] def __init__(self, expr: Optional[Expression]) -> None: super().__init__() @@ -1162,8 +1232,10 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class AssertStmt(Statement): + __slots__ = ('expr', 'msg') + expr: Expression - msg: Optional[Expression] = None + msg: Optional[Expression] def __init__(self, expr: Expression, msg: Optional[Expression] = None) -> None: super().__init__() @@ -1175,6 +1247,8 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class DelStmt(Statement): + __slots__ = ('expr',) + expr: Lvalue def __init__(self, expr: Lvalue) -> None: @@ -1186,24 +1260,32 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class BreakStmt(Statement): + __slots__ = () + def accept(self, visitor: StatementVisitor[T]) -> T: return visitor.visit_break_stmt(self) class ContinueStmt(Statement): + __slots__ = () + def accept(self, visitor: StatementVisitor[T]) -> T: return visitor.visit_continue_stmt(self) class PassStmt(Statement): + __slots__ = () + def accept(self, visitor: StatementVisitor[T]) -> T: return visitor.visit_pass_stmt(self) class IfStmt(Statement): + __slots__ = ('expr', 'body', 'else_body') + expr: List[Expression] body: List[Block] - else_body: Optional[Block] = None + else_body: Optional[Block] def __init__(self, expr: List[Expression], body: List[Block], else_body: Optional[Block]) -> None: @@ -1217,9 +1299,11 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class RaiseStmt(Statement): + __slots__ = ('expr', 'from_expr') + # Plain 'raise' is a valid statement. - expr: Optional[Expression] = None - from_expr: Optional[Expression] = None + expr: Optional[Expression] + from_expr: Optional[Expression] def __init__(self, expr: Optional[Expression], from_expr: Optional[Expression]) -> None: super().__init__() @@ -1231,13 +1315,15 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class TryStmt(Statement): + __slots__ = ('body', 'types', 'vars', 'handlers', 'else_body', 'finally_body') + body: Block # Try body # Plain 'except:' also possible types: List[Optional[Expression]] # Except type expressions vars: List[Optional["NameExpr"]] # Except variable names handlers: List[Block] # Except bodies - else_body: Optional[Block] = None - finally_body: Optional[Block] = None + else_body: Optional[Block] + finally_body: Optional[Block] def __init__(self, body: Block, vars: List['Optional[NameExpr]'], types: List[Optional[Expression]], @@ -1256,14 +1342,17 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class WithStmt(Statement): + __slots__ = ('expr', 'target', 'unanalyzed_type', + 'analyzed_types', 'body', 'is_async') + expr: List[Expression] target: List[Optional[Lvalue]] # Type given by type comments for target, can be None - unanalyzed_type: Optional["mypy.types.Type"] = None + unanalyzed_type: Optional["mypy.types.Type"] # Semantically analyzed types from type comment (TypeList type expanded) analyzed_types: List["mypy.types.Type"] body: Block - is_async = False # True if `async with ...` (PEP 492, Python 3.5) + is_async: bool # True if `async with ...` (PEP 492, Python 3.5) def __init__(self, expr: List[Expression], target: List[Optional[Lvalue]], body: Block, target_type: 'Optional[mypy.types.Type]' = None) -> None: @@ -1273,6 +1362,7 @@ def __init__(self, expr: List[Expression], target: List[Optional[Lvalue]], self.unanalyzed_type = target_type self.analyzed_types = [] self.body = body + self.is_async = False def accept(self, visitor: StatementVisitor[T]) -> T: return visitor.visit_with_stmt(self) @@ -1281,10 +1371,12 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class PrintStmt(Statement): """Python 2 print statement""" + __slots__ = ('args', 'newline', 'target') + args: List[Expression] - newline = False + newline: bool # The file-like target object (given using >>). - target: Optional[Expression] = None + target: Optional[Expression] def __init__(self, args: List[Expression], @@ -1302,9 +1394,11 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class ExecStmt(Statement): """Python 2 exec statement""" + __slots__ = ('expr', 'globals', 'locals') + expr: Expression - globals: Optional[Expression] = None - locals: Optional[Expression] = None + globals: Optional[Expression] + locals: Optional[Expression] def __init__(self, expr: Expression, globals: Optional[Expression], @@ -1324,7 +1418,9 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class IntExpr(Expression): """Integer literal""" - value = 0 + __slots__ = ('value',) + + value: int # 0 by default def __init__(self, value: int) -> None: super().__init__() @@ -1348,7 +1444,9 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class StrExpr(Expression): """String literal""" - value = '' + __slots__ = ('value', 'from_python_3') + + value: str # '' by default # Keeps track of whether this string originated from Python 2 source code vs # Python 3 source code. We need to keep track of this information so we can @@ -1362,7 +1460,7 @@ class StrExpr(Expression): # is meant to be `Literal[u'foo']` or `Literal[b'foo']`. # # This field keeps track of that information. - from_python_3 = True + from_python_3: bool def __init__(self, value: str, from_python_3: bool = False) -> None: super().__init__() @@ -1376,6 +1474,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class BytesExpr(Expression): """Bytes literal""" + __slots__ = ('value',) + # Note: we deliberately do NOT use bytes here because it ends up # unnecessarily complicating a lot of the result logic. For example, # we'd have to worry about converting the bytes into a format we can @@ -1385,7 +1485,7 @@ class BytesExpr(Expression): # # It's more convenient to just store the human-readable representation # from the very start. - value = '' + value: str def __init__(self, value: str) -> None: super().__init__() @@ -1398,7 +1498,9 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class UnicodeExpr(Expression): """Unicode literal (Python 2.x)""" - value = '' + __slots__ = ('value',) + + value: str def __init__(self, value: str) -> None: super().__init__() @@ -1411,7 +1513,9 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class FloatExpr(Expression): """Float literal""" - value = 0.0 + __slots__ = ('value',) + + value: float # 0.0 by default def __init__(self, value: float) -> None: super().__init__() @@ -1424,6 +1528,10 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class ComplexExpr(Expression): """Complex literal""" + __slots__ = ('value',) + + value: complex + def __init__(self, value: complex) -> None: super().__init__() self.value = value @@ -1435,6 +1543,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class EllipsisExpr(Expression): """Ellipsis (...)""" + __slots__ = () + def accept(self, visitor: ExpressionVisitor[T]) -> T: return visitor.visit_ellipsis(self) @@ -1442,7 +1552,10 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class StarExpr(Expression): """Star expression""" + __slots__ = ('expr', 'valid') + expr: Expression + valid: bool def __init__(self, expr: Expression) -> None: super().__init__() @@ -1521,7 +1634,7 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: # Kinds of arguments - +@unique class ArgKind(Enum): # Positional argument ARG_POS = 0 @@ -1601,6 +1714,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class YieldFromExpr(Expression): + __slots__ = ('expr',) + expr: Expression def __init__(self, expr: Expression) -> None: @@ -1612,7 +1727,9 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class YieldExpr(Expression): - expr: Optional[Expression] = None + __slots__ = ('expr',) + + expr: Optional[Expression] def __init__(self, expr: Optional[Expression]) -> None: super().__init__() @@ -1628,10 +1745,12 @@ class IndexExpr(Expression): Also wraps type application such as List[int] as a special form. """ + __slots__ = ('base', 'index', 'method_type', 'analyzed') + base: Expression index: Expression # Inferred __getitem__ method type - method_type: Optional["mypy.types.Type"] = None + method_type: Optional["mypy.types.Type"] # If not None, this is actually semantically a type application # Class[type, ...] or a type alias initializer. analyzed: Union["TypeApplication", "TypeAliasExpr", None] @@ -1640,6 +1759,7 @@ def __init__(self, base: Expression, index: Expression) -> None: super().__init__() self.base = base self.index = index + self.method_type = None self.analyzed = None def accept(self, visitor: ExpressionVisitor[T]) -> T: @@ -1649,15 +1769,18 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class UnaryExpr(Expression): """Unary operation""" - op = '' + __slots__ = ('op', 'expr', 'method_type') + + op: str # TODO: Enum? expr: Expression # Inferred operator method type - method_type: Optional["mypy.types.Type"] = None + method_type: Optional["mypy.types.Type"] def __init__(self, op: str, expr: Expression) -> None: super().__init__() self.op = op self.expr = expr + self.method_type = None def accept(self, visitor: ExpressionVisitor[T]) -> T: return visitor.visit_unary_expr(self) @@ -1665,6 +1788,9 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class AssignmentExpr(Expression): """Assignment expressions in Python 3.8+, like "a := 2".""" + + __slots__ = ('target', 'value') + def __init__(self, target: Expression, value: Expression) -> None: super().__init__() self.target = target @@ -1678,21 +1804,27 @@ class OpExpr(Expression): """Binary operation (other than . or [] or comparison operators, which have specific nodes).""" - op = '' + __slots__ = ('op', 'left', 'right', + 'method_type', 'right_always', 'right_unreachable') + + op: str # TODO: Enum? left: Expression right: Expression # Inferred type for the operator method type (when relevant). - method_type: Optional["mypy.types.Type"] = None + method_type: Optional["mypy.types.Type"] # Per static analysis only: Is the right side going to be evaluated every time? - right_always = False + right_always: bool # Per static analysis only: Is the right side unreachable? - right_unreachable = False + right_unreachable: bool def __init__(self, op: str, left: Expression, right: Expression) -> None: super().__init__() self.op = op self.left = left self.right = right + self.method_type = None + self.right_always = False + self.right_unreachable = False def accept(self, visitor: ExpressionVisitor[T]) -> T: return visitor.visit_op_expr(self) @@ -1701,6 +1833,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class ComparisonExpr(Expression): """Comparison expression (e.g. a < b > c < d).""" + __slots__ = ('operators', 'operands', 'method_types') + operators: List[str] operands: List[Expression] # Inferred type for the operator methods (when relevant; None for 'is'). @@ -1729,9 +1863,11 @@ class SliceExpr(Expression): This is only valid as index in index expressions. """ - begin_index: Optional[Expression] = None - end_index: Optional[Expression] = None - stride: Optional[Expression] = None + __slots__ = ('begin_index', 'end_index', 'stride') + + begin_index: Optional[Expression] + end_index: Optional[Expression] + stride: Optional[Expression] def __init__(self, begin_index: Optional[Expression], end_index: Optional[Expression], @@ -1748,6 +1884,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class CastExpr(Expression): """Cast expression cast(type, expr).""" + __slots__ = ('expr', 'type') + expr: Expression type: "mypy.types.Type" @@ -1763,9 +1901,11 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class RevealExpr(Expression): """Reveal type expression reveal_type(expr) or reveal_locals() expression.""" - expr: Optional[Expression] = None - kind: int = 0 - local_nodes: Optional[List[Var]] = None + __slots__ = ('expr', 'kind', 'local_nodes') + + expr: Optional[Expression] + kind: int + local_nodes: Optional[List[Var]] def __init__( self, kind: int, @@ -1783,14 +1923,17 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class SuperExpr(Expression): """Expression super().name""" - name = '' - info: Optional["TypeInfo"] = None # Type that contains this super expression + __slots__ = ('name', 'info', 'call') + + name: str + info: Optional["TypeInfo"] # Type that contains this super expression call: CallExpr # The expression super(...) def __init__(self, name: str, call: CallExpr) -> None: super().__init__() self.name = name self.call = call + self.info = None def accept(self, visitor: ExpressionVisitor[T]) -> T: return visitor.visit_super_expr(self) @@ -1820,6 +1963,8 @@ def is_dynamic(self) -> bool: class ListExpr(Expression): """List literal expression [...].""" + __slots__ = ('items',) + items: List[Expression] def __init__(self, items: List[Expression]) -> None: @@ -1833,6 +1978,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class DictExpr(Expression): """Dictionary literal expression {key: value, ...}.""" + __slots__ = ('items',) + items: List[Tuple[Optional[Expression], Expression]] def __init__(self, items: List[Tuple[Optional[Expression], Expression]]) -> None: @@ -1848,6 +1995,8 @@ class TupleExpr(Expression): Also lvalue sequences (..., ...) and [..., ...]""" + __slots__ = ('items',) + items: List[Expression] def __init__(self, items: List[Expression]) -> None: @@ -1861,6 +2010,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class SetExpr(Expression): """Set literal expression {value, ...}.""" + __slots__ = ('items',) + items: List[Expression] def __init__(self, items: List[Expression]) -> None: @@ -1874,6 +2025,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class GeneratorExpr(Expression): """Generator expression ... for ... in ... [ for ... in ... ] [ if ... ].""" + __slots__ = ('left_expr', 'sequences', 'condlists', 'is_async', 'indices') + left_expr: Expression sequences: List[Expression] condlists: List[List[Expression]] @@ -1897,6 +2050,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class ListComprehension(Expression): """List comprehension (e.g. [x + 1 for x in a])""" + __slots__ = ('generator',) + generator: GeneratorExpr def __init__(self, generator: GeneratorExpr) -> None: @@ -1910,6 +2065,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class SetComprehension(Expression): """Set comprehension (e.g. {x + 1 for x in a})""" + __slots__ = ('generator',) + generator: GeneratorExpr def __init__(self, generator: GeneratorExpr) -> None: @@ -1923,6 +2080,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class DictionaryComprehension(Expression): """Dictionary comprehension (e.g. {k: v for k, v in a}""" + __slots__ = ('key', 'value', 'sequences', 'condlists', 'is_async', 'indices') + key: Expression value: Expression sequences: List[Expression] @@ -1948,6 +2107,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class ConditionalExpr(Expression): """Conditional expression (e.g. x if y else z)""" + __slots__ = ('cond', 'if_expr', 'else_expr') + cond: Expression if_expr: Expression else_expr: Expression @@ -1965,6 +2126,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class BackquoteExpr(Expression): """Python 2 expression `...`.""" + __slots__ = ('expr',) + expr: Expression def __init__(self, expr: Expression) -> None: @@ -1978,6 +2141,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class TypeApplication(Expression): """Type application expr[type, ...]""" + __slots__ = ('expr', 'types') + expr: Expression types: List["mypy.types.Type"] @@ -2006,8 +2171,11 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class TypeVarLikeExpr(SymbolNode, Expression): """Base class for TypeVarExpr and ParamSpecExpr.""" - _name = '' - _fullname = '' + + __slots__ = ('_name', '_fullname', 'upper_bound', 'variance') + + _name: str + _fullname: str # Upper bound: only subtypes of upper_bound are valid as values. By default # this is 'object', meaning no restriction. upper_bound: "mypy.types.Type" @@ -2015,7 +2183,7 @@ class TypeVarLikeExpr(SymbolNode, Expression): # TypeVar(..., covariant=True) defines a covariant type variable. # TypeVar(..., contravariant=True) defines a contravariant type # variable. - variance = INVARIANT + variance: int def __init__( self, name: str, fullname: str, upper_bound: 'mypy.types.Type', variance: int = INVARIANT @@ -2046,6 +2214,9 @@ class TypeVarExpr(TypeVarLikeExpr): 1. a generic class that uses the type variable as a type argument or 2. a generic function that refers to the type variable in its signature. """ + + __slots__ = ('values',) + # Value restriction: only types in the list are valid as values. If the # list is empty, there is no restriction. values: List["mypy.types.Type"] @@ -2080,6 +2251,8 @@ def deserialize(cls, data: JsonDict) -> 'TypeVarExpr': class ParamSpecExpr(TypeVarLikeExpr): + __slots__ = () + def accept(self, visitor: ExpressionVisitor[T]) -> T: return visitor.visit_paramspec_expr(self) @@ -2106,6 +2279,8 @@ def deserialize(cls, data: JsonDict) -> 'ParamSpecExpr': class TypeAliasExpr(Expression): """Type alias expression (rvalue).""" + __slots__ = ('type', 'tvars', 'no_args', 'node') + # The target type. type: "mypy.types.Type" # Names of unbound type variables used to define the alias @@ -2115,7 +2290,8 @@ class TypeAliasExpr(Expression): # A = List # and # A = List[Any] - no_args: bool = False + no_args: bool + node: 'TypeAlias' def __init__(self, node: 'TypeAlias') -> None: super().__init__() @@ -2131,10 +2307,12 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class NamedTupleExpr(Expression): """Named tuple expression namedtuple(...) or NamedTuple(...).""" + __slots__ = ('info', 'is_typed') + # The class representation of this named tuple (its tuple_type attribute contains # the tuple item types) info: "TypeInfo" - is_typed = False # whether this class was created with typing.NamedTuple + is_typed: bool # whether this class was created with typing.NamedTuple def __init__(self, info: 'TypeInfo', is_typed: bool = False) -> None: super().__init__() @@ -2148,6 +2326,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class TypedDictExpr(Expression): """Typed dict expression TypedDict(...).""" + __slots__ = ('info',) + # The class representation of this typed dict info: "TypeInfo" @@ -2162,6 +2342,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class EnumCallExpr(Expression): """Named tuple expression Enum('name', 'val1 val2 ...').""" + __slots__ = ('info', 'items', 'values') + # The class representation of this enumerated type info: "TypeInfo" # The item names (for debugging) @@ -2182,6 +2364,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class PromoteExpr(Expression): """Ducktype class decorator expression _promote(...).""" + __slots__ = ('type',) + type: "mypy.types.Type" def __init__(self, type: 'mypy.types.Type') -> None: @@ -2195,19 +2379,20 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class NewTypeExpr(Expression): """NewType expression NewType(...).""" + __slots__ = ('name', 'old_type', 'info') + name: str # The base type (the second argument to NewType) - old_type: Optional["mypy.types.Type"] = None + old_type: Optional["mypy.types.Type"] # The synthesized class representing the new type (inherits old_type) - info: Optional["TypeInfo"] = None + info: Optional["TypeInfo"] def __init__(self, name: str, old_type: 'Optional[mypy.types.Type]', line: int, column: int) -> None: - super().__init__() + super().__init__(line=line, column=column) self.name = name self.old_type = old_type - self.line = line - self.column = column + self.info = None def accept(self, visitor: ExpressionVisitor[T]) -> T: return visitor.visit_newtype_expr(self) @@ -2216,6 +2401,8 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class AwaitExpr(Expression): """Await expression (await ...).""" + __slots__ = ('expr',) + expr: Expression def __init__(self, expr: Expression) -> None: @@ -2237,10 +2424,12 @@ class TempNode(Expression): some fixed type. """ + __slots__ = ('type', 'no_rhs') + type: "mypy.types.Type" # Is this TempNode used to indicate absence of a right hand side in an annotated assignment? # (e.g. for 'x: int' the rvalue is TempNode(AnyType(TypeOfAny.special_form), no_rhs=True)) - no_rhs: bool = False + no_rhs: bool def __init__(self, typ: 'mypy.types.Type', @@ -2275,7 +2464,17 @@ class is generic then it will be a type constructor of higher kind. the appropriate number of arguments. """ - _fullname: Bogus[str] = None # type: ignore # Fully qualified name + __slots__ = ( + '_fullname', 'module_name', 'defn', 'mro', '_mro_refs', 'bad_mro', 'is_final', + 'declared_metaclass', 'metaclass_type', 'names', 'is_abstract', + 'is_protocol', 'runtime_protocol', 'abstract_attributes', + 'deletable_attributes', 'slots', 'assuming', 'assuming_proper', + 'inferring', 'is_enum', 'fallback_to_any', 'type_vars', 'bases', + '_promote', 'tuple_type', 'is_named_tuple', 'typeddict_type', + 'is_newtype', 'is_intersection', 'metadata', + ) + + _fullname: Bogus[str] # Fully qualified name # Fully qualified name for the module this type was defined in. This # information is also in the fullname, but is harder to extract in the # case of nested class definitions. @@ -2286,16 +2485,17 @@ class is generic then it will be a type constructor of higher kind. mro: List["TypeInfo"] # Used to stash the names of the mro classes temporarily between # deserialization and fixup. See deserialize() for why. - _mro_refs: Optional[List[str]] = None - bad_mro = False # Could not construct full MRO + _mro_refs: Optional[List[str]] + bad_mro: bool # Could not construct full MRO + is_final: bool - declared_metaclass: Optional["mypy.types.Instance"] = None - metaclass_type: Optional["mypy.types.Instance"] = None + declared_metaclass: Optional["mypy.types.Instance"] + metaclass_type: Optional["mypy.types.Instance"] names: "SymbolTable" # Names defined directly in this type - is_abstract = False # Does the class have any abstract attributes? - is_protocol = False # Is this a protocol class? - runtime_protocol = False # Does this protocol support isinstance checks? + is_abstract: bool # Does the class have any abstract attributes? + is_protocol: bool # Is this a protocol class? + runtime_protocol: bool # Does this protocol support isinstance checks? abstract_attributes: List[str] deletable_attributes: List[str] # Used by mypyc only # Does this type have concrete `__slots__` defined? @@ -2340,13 +2540,13 @@ class is generic then it will be a type constructor of higher kind. # Classes inheriting from Enum shadow their true members with a __getattr__, so we # have to treat them as a special case. - is_enum = False + is_enum: bool # If true, any unknown attributes should have type 'Any' instead # of generating a type error. This would be true if there is a # base class with type 'Any', but other use cases may be # possible. This is similar to having __getattr__ that returns Any # (and __setattr__), but without the __getattr__ method. - fallback_to_any = False + fallback_to_any: bool # Information related to type annotations. @@ -2360,27 +2560,27 @@ class is generic then it will be a type constructor of higher kind. # even though it's not a subclass in Python. The non-standard # `@_promote` decorator introduces this, and there are also # several builtin examples, in particular `int` -> `float`. - _promote: Optional["mypy.types.Type"] = None + _promote: Optional["mypy.types.Type"] # Representation of a Tuple[...] base class, if the class has any # (e.g., for named tuples). If this is not None, the actual Type # object used for this class is not an Instance but a TupleType; # the corresponding Instance is set as the fallback type of the # tuple type. - tuple_type: Optional["mypy.types.TupleType"] = None + tuple_type: Optional["mypy.types.TupleType"] # Is this a named tuple type? - is_named_tuple = False + is_named_tuple: bool # If this class is defined by the TypedDict type constructor, # then this is not None. - typeddict_type: Optional["mypy.types.TypedDictType"] = None + typeddict_type: Optional["mypy.types.TypedDictType"] # Is this a newtype type? - is_newtype = False + is_newtype: bool # Is this a synthesized intersection type? - is_intersection = False + is_intersection: bool # This is a dictionary that will be serialized and un-serialized as is. # It is useful for plugins to add their data to save in the cache. @@ -2395,13 +2595,17 @@ class is generic then it will be a type constructor of higher kind. def __init__(self, names: 'SymbolTable', defn: ClassDef, module_name: str) -> None: """Initialize a TypeInfo.""" super().__init__() + self._fullname = defn.fullname self.names = names self.defn = defn self.module_name = module_name self.type_vars = [] self.bases = [] self.mro = [] - self._fullname = defn.fullname + self._mro_refs = None + self.bad_mro = False + self.declared_metaclass = None + self.metaclass_type = None self.is_abstract = False self.abstract_attributes = [] self.deletable_attributes = [] @@ -2409,9 +2613,19 @@ def __init__(self, names: 'SymbolTable', defn: ClassDef, module_name: str) -> No self.assuming = [] self.assuming_proper = [] self.inferring = [] + self.is_protocol = False + self.runtime_protocol = False self.add_type_vars() - self.metadata = {} self.is_final = False + self.is_enum = False + self.fallback_to_any = False + self._promote = None + self.tuple_type = None + self.is_named_tuple = False + self.typeddict_type = None + self.is_newtype = False + self.is_intersection = False + self.metadata = {} def add_type_vars(self) -> None: if self.defn.type_vars: @@ -2475,12 +2689,14 @@ def __bool__(self) -> bool: def has_readable_member(self, name: str) -> bool: return self.get(name) is not None - def get_method(self, name: str) -> Optional[FuncBase]: + def get_method(self, name: str) -> Union[FuncBase, Decorator, None]: for cls in self.mro: if name in cls.names: node = cls.names[name].node if isinstance(node, FuncBase): return node + elif isinstance(node, Decorator): # Two `if`s make `mypyc` happy + return node else: return None return None @@ -2631,6 +2847,9 @@ def deserialize(cls, data: JsonDict) -> 'TypeInfo': class FakeInfo(TypeInfo): + + __slots__ = ('msg',) + # types.py defines a single instance of this class, called types.NOT_READY. # This instance is used as a temporary placeholder in the process of de-serialization # of 'Instance' types. The de-serialization happens in two steps: In the first step, @@ -2864,6 +3083,8 @@ class C(Sequence[C]): ... something that can support general recursive types. """ + __slots__ = ('_fullname', 'node', 'line', 'becomes_typeinfo') + def __init__(self, fullname: str, node: Node, line: int, *, becomes_typeinfo: bool = False) -> None: self._fullname = fullname @@ -3075,6 +3296,8 @@ class SymbolTable(Dict[str, SymbolTableNode]): This is used for module, class and function namespaces. """ + __slots__ = () + def __str__(self) -> str: a: List[str] = [] for key, value in self.items(): diff --git a/mypy/options.py b/mypy/options.py index 3a56add0d0ad..58278b1580e8 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -100,7 +100,7 @@ def __init__(self) -> None: # top-level __init__.py to your packages. self.explicit_package_bases = False # File names, directory names or subpaths to avoid checking - self.exclude: str = "" + self.exclude: List[str] = [] # disallow_any options self.disallow_any_generics = False @@ -286,7 +286,7 @@ def __init__(self) -> None: self.package_root: List[str] = [] self.cache_map: Dict[str, Tuple[str, str]] = {} # Don't properly free objects on exit, just kill the current process. - self.fast_exit = False + self.fast_exit = True # Used to transform source code before parsing if not None # TODO: Make the type precise (AnyStr -> AnyStr) self.transform_source: Optional[Callable[[Any], Any]] = None diff --git a/mypy/plugin.py b/mypy/plugin.py index 4cd769427ce1..3772d7039b05 100644 --- a/mypy/plugin.py +++ b/mypy/plugin.py @@ -120,7 +120,7 @@ class C: pass """ from abc import abstractmethod -from typing import Any, Callable, List, Tuple, Optional, NamedTuple, TypeVar, Dict +from typing import Any, Callable, List, Tuple, Optional, NamedTuple, TypeVar, Dict, Union from mypy_extensions import trait, mypyc_attr from mypy.nodes import ( @@ -134,6 +134,7 @@ class C: pass from mypy.options import Options from mypy.lookup import lookup_fully_qualified from mypy.errorcodes import ErrorCode +from mypy.message_registry import ErrorMessage @trait @@ -223,7 +224,8 @@ def type_context(self) -> List[Optional[Type]]: raise NotImplementedError @abstractmethod - def fail(self, msg: str, ctx: Context, *, code: Optional[ErrorCode] = None) -> None: + def fail(self, msg: Union[str, ErrorMessage], ctx: Context, *, + code: Optional[ErrorCode] = None) -> None: """Emit an error message at given location.""" raise NotImplementedError @@ -250,13 +252,13 @@ class SemanticAnalyzerPluginInterface: msg: MessageBuilder @abstractmethod - def named_type(self, qualified_name: str, args: Optional[List[Type]] = None) -> Instance: + def named_type(self, fullname: str, + args: Optional[List[Type]] = None) -> Instance: """Construct an instance of a builtin type with given type arguments.""" raise NotImplementedError @abstractmethod - def named_type_or_none(self, - qualified_name: str, + def named_type_or_none(self, fullname: str, args: Optional[List[Type]] = None) -> Optional[Instance]: """Construct an instance of a type with given type arguments. @@ -297,11 +299,6 @@ def class_type(self, self_type: Type) -> Type: """Generate type of first argument of class methods from type of self.""" raise NotImplementedError - @abstractmethod - def builtin_type(self, fully_qualified_name: str) -> Instance: - """Deprecated: use named_type instead.""" - raise NotImplementedError - @abstractmethod def lookup_fully_qualified(self, name: str) -> SymbolTableNode: """Lookup a symbol by its fully qualified name. diff --git a/mypy/plugins/attrs.py b/mypy/plugins/attrs.py index 0e9174758d38..051dae18b96c 100644 --- a/mypy/plugins/attrs.py +++ b/mypy/plugins/attrs.py @@ -7,7 +7,7 @@ import mypy.plugin # To avoid circular imports. from mypy.exprtotype import expr_to_unanalyzed_type, TypeTranslationError -from mypy.fixup import lookup_qualified_stnode +from mypy.lookup import lookup_fully_qualified from mypy.nodes import ( Context, Argument, Var, ARG_OPT, ARG_POS, TypeInfo, AssignmentStmt, TupleExpr, ListExpr, NameExpr, CallExpr, RefExpr, FuncDef, @@ -87,7 +87,8 @@ def argument(self, ctx: 'mypy.plugin.ClassDefContext') -> Argument: if self.converter.name: # When a converter is set the init_type is overridden by the first argument # of the converter method. - converter = lookup_qualified_stnode(ctx.api.modules, self.converter.name, True) + converter = lookup_fully_qualified(self.converter.name, ctx.api.modules, + raise_on_missing=False) if not converter: # The converter may be a local variable. Check there too. converter = ctx.api.lookup_qualified(self.converter.name, self.info, True) @@ -96,7 +97,7 @@ def argument(self, ctx: 'mypy.plugin.ClassDefContext') -> Argument: converter_type: Optional[Type] = None if converter and isinstance(converter.node, TypeInfo): from mypy.checkmember import type_object_type # To avoid import cycle. - converter_type = type_object_type(converter.node, ctx.api.builtin_type) + converter_type = type_object_type(converter.node, ctx.api.named_type) elif converter and isinstance(converter.node, OverloadedFuncDef): converter_type = converter.node.type elif converter and converter.type: @@ -271,6 +272,7 @@ def attr_class_maker_callback(ctx: 'mypy.plugin.ClassDefContext', init = _get_decorator_bool_argument(ctx, 'init', True) frozen = _get_frozen(ctx, frozen_default) order = _determine_eq_order(ctx) + slots = _get_decorator_bool_argument(ctx, 'slots', False) auto_attribs = _get_decorator_optional_bool_argument(ctx, 'auto_attribs', auto_attribs_default) kw_only = _get_decorator_bool_argument(ctx, 'kw_only', False) @@ -301,6 +303,8 @@ def attr_class_maker_callback(ctx: 'mypy.plugin.ClassDefContext', return _add_attrs_magic_attribute(ctx, raw_attr_types=[info[attr.name].type for attr in attributes]) + if slots: + _add_slots(ctx, attributes) # Save the attributes so that subclasses can reuse them. ctx.cls.info.metadata['attrs'] = { @@ -639,8 +643,8 @@ def _parse_assignments( def _add_order(ctx: 'mypy.plugin.ClassDefContext', adder: 'MethodAdder') -> None: """Generate all the ordering methods for this class.""" - bool_type = ctx.api.named_type('__builtins__.bool') - object_type = ctx.api.named_type('__builtins__.object') + bool_type = ctx.api.named_type('builtins.bool') + object_type = ctx.api.named_type('builtins.object') # Make the types be: # AT = TypeVar('AT') # def __lt__(self: AT, other: AT) -> bool @@ -713,7 +717,7 @@ def _add_attrs_magic_attribute(ctx: 'mypy.plugin.ClassDefContext', ctx.api.named_type_or_none('attr.Attribute', [attr_type or any_type]) or any_type for attr_type in raw_attr_types ] - fallback_type = ctx.api.named_type('__builtins__.tuple', [ + fallback_type = ctx.api.named_type('builtins.tuple', [ ctx.api.named_type_or_none('attr.Attribute', [any_type]) or any_type, ]) var = Var(name=attr_name, type=TupleType(attributes_types, fallback=fallback_type)) @@ -726,6 +730,12 @@ def _add_attrs_magic_attribute(ctx: 'mypy.plugin.ClassDefContext', ) +def _add_slots(ctx: 'mypy.plugin.ClassDefContext', + attributes: List[Attribute]) -> None: + # Unlike `@dataclasses.dataclass`, `__slots__` is rewritten here. + ctx.cls.info.slots = {attr.name for attr in attributes} + + class MethodAdder: """Helper to add methods to a TypeInfo. diff --git a/mypy/plugins/common.py b/mypy/plugins/common.py index df21718d9949..1beb53849327 100644 --- a/mypy/plugins/common.py +++ b/mypy/plugins/common.py @@ -122,13 +122,8 @@ def add_method_to_class( cls.defs.body.remove(sym.node) self_type = self_type or fill_typevars(info) - # TODO: semanal.py and checker.py seem to have subtly different implementations of - # named_type/named_generic_type (starting with the fact that we have to use different names - # for builtins), so it's easier to just check which one we're dealing with here and pick the - # correct function to use than to try to add a named_type method that behaves the same for - # both. We should probably combine those implementations at some point. if isinstance(api, SemanticAnalyzerPluginInterface): - function_type = api.named_type('__builtins__.function') + function_type = api.named_type('builtins.function') else: function_type = api.named_generic_type('builtins.function', []) diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index 9c615f857731..6d78bc17e615 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -24,6 +24,11 @@ 'dataclass', 'dataclasses.dataclass', } +# The set of functions that generate dataclass fields. +field_makers: Final = { + 'dataclasses.field', +} + SELF_TVAR_NAME: Final = "_DT" @@ -125,7 +130,9 @@ def transform(self) -> None: 'eq': _get_decorator_bool_argument(self._ctx, 'eq', True), 'order': _get_decorator_bool_argument(self._ctx, 'order', False), 'frozen': _get_decorator_bool_argument(self._ctx, 'frozen', False), + 'slots': _get_decorator_bool_argument(self._ctx, 'slots', False), } + py_version = self._ctx.api.options.python_version # If there are no attributes, it may be that the semantic analyzer has not # processed them yet. In order to work around this, we can simply skip generating @@ -145,7 +152,7 @@ def transform(self) -> None: if (decorator_arguments['eq'] and info.get('__eq__') is None or decorator_arguments['order']): # Type variable for self types in generated methods. - obj_type = ctx.api.named_type('__builtins__.object') + obj_type = ctx.api.named_type('builtins.object') self_tvar_expr = TypeVarExpr(SELF_TVAR_NAME, info.fullname + '.' + SELF_TVAR_NAME, [], obj_type) info.names[SELF_TVAR_NAME] = SymbolTableNode(MDEF, self_tvar_expr) @@ -158,10 +165,10 @@ def transform(self) -> None: for method_name in ['__lt__', '__gt__', '__le__', '__ge__']: # Like for __eq__ and __ne__, we want "other" to match # the self type. - obj_type = ctx.api.named_type('__builtins__.object') + obj_type = ctx.api.named_type('builtins.object') order_tvar_def = TypeVarType(SELF_TVAR_NAME, info.fullname + '.' + SELF_TVAR_NAME, -1, [], obj_type) - order_return_type = ctx.api.named_type('__builtins__.bool') + order_return_type = ctx.api.named_type('builtins.bool') order_args = [ Argument(Var('other', order_tvar_def), order_tvar_def, None, ARG_POS) ] @@ -188,6 +195,9 @@ def transform(self) -> None: else: self._propertize_callables(attributes) + if decorator_arguments['slots']: + self.add_slots(info, attributes, correct_version=py_version >= (3, 10)) + self.reset_init_only_vars(info, attributes) self._add_dataclass_fields_magic_attribute() @@ -197,6 +207,35 @@ def transform(self) -> None: 'frozen': decorator_arguments['frozen'], } + def add_slots(self, + info: TypeInfo, + attributes: List[DataclassAttribute], + *, + correct_version: bool) -> None: + if not correct_version: + # This means that version is lower than `3.10`, + # it is just a non-existent argument for `dataclass` function. + self._ctx.api.fail( + 'Keyword argument "slots" for "dataclass" ' + 'is only valid in Python 3.10 and higher', + self._ctx.reason, + ) + return + if info.slots is not None or info.names.get('__slots__'): + # This means we have a slots conflict. + # Class explicitly specifies `__slots__` field. + # And `@dataclass(slots=True)` is used. + # In runtime this raises a type error. + self._ctx.api.fail( + '"{}" both defines "__slots__" and is used with "slots=True"'.format( + self._ctx.cls.name, + ), + self._ctx.cls, + ) + return + + info.slots = {attr.name for attr in attributes} + def reset_init_only_vars(self, info: TypeInfo, attributes: List[DataclassAttribute]) -> None: """Remove init-only vars from the class and reset init var declarations.""" for attr in attributes: @@ -426,8 +465,8 @@ def _add_dataclass_fields_magic_attribute(self) -> None: attr_name = '__dataclass_fields__' any_type = AnyType(TypeOfAny.explicit) field_type = self._ctx.api.named_type_or_none('dataclasses.Field', [any_type]) or any_type - attr_type = self._ctx.api.named_type('__builtins__.dict', [ - self._ctx.api.named_type('__builtins__.str'), + attr_type = self._ctx.api.named_type('builtins.dict', [ + self._ctx.api.named_type('builtins.str'), field_type, ]) var = Var(name=attr_name, type=attr_type) @@ -456,20 +495,22 @@ def _collect_field_args(expr: Expression, if ( isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr) and - expr.callee.fullname == 'dataclasses.field' + expr.callee.fullname in field_makers ): # field() only takes keyword arguments. args = {} - for name, arg in zip(expr.arg_names, expr.args): - if name is None: - # This means that `field` is used with `**` unpacking, - # the best we can do for now is not to fail. - # TODO: we can infer what's inside `**` and try to collect it. - ctx.api.fail( - 'Unpacking **kwargs in "field()" is not supported', - expr, - ) + for name, arg, kind in zip(expr.arg_names, expr.args, expr.arg_kinds): + if not kind.is_named(): + if kind.is_named(star=True): + # This means that `field` is used with `**` unpacking, + # the best we can do for now is not to fail. + # TODO: we can infer what's inside `**` and try to collect it. + message = 'Unpacking **kwargs in "field()" is not supported' + else: + message = '"field()" does not accept positional arguments' + ctx.api.fail(message, expr) return True, {} + assert name is not None args[name] = arg return True, args return False, {} diff --git a/mypy/plugins/default.py b/mypy/plugins/default.py index f151d3da669d..67587090e0ba 100644 --- a/mypy/plugins/default.py +++ b/mypy/plugins/default.py @@ -15,6 +15,7 @@ from mypy.subtypes import is_subtype from mypy.typeops import make_simplified_union from mypy.checkexpr import is_literal_type_like +from mypy.checker import detach_callable class DefaultPlugin(Plugin): @@ -24,7 +25,7 @@ def get_function_hook(self, fullname: str ) -> Optional[Callable[[FunctionContext], Type]]: from mypy.plugins import ctypes, singledispatch - if fullname == 'contextlib.contextmanager': + if fullname in ('contextlib.contextmanager', 'contextlib.asynccontextmanager'): return contextmanager_callback elif fullname == 'builtins.open' and self.python_version[0] == 3: return open_callback @@ -46,8 +47,6 @@ def get_method_signature_hook(self, fullname: str return typed_dict_pop_signature_callback elif fullname in set(n + '.update' for n in TPDICT_FB_NAMES): return typed_dict_update_signature_callback - elif fullname in set(n + '.__delitem__' for n in TPDICT_FB_NAMES): - return typed_dict_delitem_signature_callback elif fullname == 'ctypes.Array.__setitem__': return ctypes.array_setitem_callback elif fullname == singledispatch.SINGLEDISPATCH_CALLABLE_CALL_METHOD: @@ -193,12 +192,12 @@ def contextmanager_callback(ctx: FunctionContext) -> Type: and isinstance(default_return, CallableType)): # The stub signature doesn't preserve information about arguments so # add them back here. - return default_return.copy_modified( + return detach_callable(default_return.copy_modified( arg_types=arg_type.arg_types, arg_kinds=arg_type.arg_kinds, arg_names=arg_type.arg_names, variables=arg_type.variables, - is_ellipsis_args=arg_type.is_ellipsis_args) + is_ellipsis_args=arg_type.is_ellipsis_args)) return ctx.default_return_type @@ -390,12 +389,6 @@ def typed_dict_setdefault_callback(ctx: MethodContext) -> Type: return ctx.default_return_type -def typed_dict_delitem_signature_callback(ctx: MethodSigContext) -> CallableType: - # Replace NoReturn as the argument type. - str_type = ctx.api.named_generic_type('builtins.str', []) - return ctx.default_signature.copy_modified(arg_types=[str_type]) - - def typed_dict_delitem_callback(ctx: MethodContext) -> Type: """Type check TypedDict.__delitem__.""" if (isinstance(ctx.type, TypedDictType) diff --git a/mypy/plugins/enums.py b/mypy/plugins/enums.py index 1b22c09fe7bb..ea9a02f5b41e 100644 --- a/mypy/plugins/enums.py +++ b/mypy/plugins/enums.py @@ -10,21 +10,21 @@ we actually bake some of it directly in to the semantic analysis layer (see semanal_enum.py). """ -from typing import Iterable, Optional, TypeVar +from typing import Iterable, Optional, Sequence, TypeVar, cast from typing_extensions import Final import mypy.plugin # To avoid circular imports. from mypy.types import Type, Instance, LiteralType, CallableType, ProperType, get_proper_type +from mypy.typeops import make_simplified_union from mypy.nodes import TypeInfo +from mypy.subtypes import is_equivalent +from mypy.semanal_enum import ENUM_BASES -# 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. -ENUM_PREFIXES: Final = {"enum.Enum", "enum.IntEnum", "enum.Flag", "enum.IntFlag"} -ENUM_NAME_ACCESS: Final = {"{}.name".format(prefix) for prefix in ENUM_PREFIXES} | { - "{}._name_".format(prefix) for prefix in ENUM_PREFIXES +ENUM_NAME_ACCESS: Final = {"{}.name".format(prefix) for prefix in ENUM_BASES} | { + "{}._name_".format(prefix) for prefix in ENUM_BASES } -ENUM_VALUE_ACCESS: Final = {"{}.value".format(prefix) for prefix in ENUM_PREFIXES} | { - "{}._value_".format(prefix) for prefix in ENUM_PREFIXES +ENUM_VALUE_ACCESS: Final = {"{}.value".format(prefix) for prefix in ENUM_BASES} | { + "{}._value_".format(prefix) for prefix in ENUM_BASES } @@ -165,19 +165,44 @@ class SomeEnum: get_proper_type(n.type) if n else None for n in stnodes if n is None or not n.implicit) - proper_types = ( + proper_types = list( _infer_value_type_with_auto_fallback(ctx, t) for t in node_types if t is None or not isinstance(t, CallableType)) underlying_type = _first(proper_types) if underlying_type is None: return ctx.default_attr_type + + # At first we try to predict future `value` type if all other items + # have the same type. For example, `int`. + # If this is the case, we simply return this type. + # See https://github.com/python/mypy/pull/9443 all_same_value_type = all( proper_type is not None and proper_type == underlying_type for proper_type in proper_types) if all_same_value_type: if underlying_type is not None: return underlying_type + + # But, after we started treating all `Enum` values as `Final`, + # we start to infer types in + # `item = 1` as `Literal[1]`, not just `int`. + # So, for example types in this `Enum` will all be different: + # + # class Ordering(IntEnum): + # one = 1 + # two = 2 + # three = 3 + # + # We will infer three `Literal` types here. + # They are not the same, but they are equivalent. + # So, we unify them to make sure `.value` prediction still works. + # Result will be `Literal[1] | Literal[2] | Literal[3]` for this case. + all_equivalent_types = all( + proper_type is not None and is_equivalent(proper_type, underlying_type) + for proper_type in proper_types) + if all_equivalent_types: + return make_simplified_union(cast(Sequence[Type], proper_types)) return ctx.default_attr_type assert isinstance(ctx.type, Instance) diff --git a/mypy/plugins/functools.py b/mypy/plugins/functools.py index 0984abe80cee..e52d478927e8 100644 --- a/mypy/plugins/functools.py +++ b/mypy/plugins/functools.py @@ -1,5 +1,6 @@ """Plugin for supporting the functools standard library module.""" from typing import Dict, NamedTuple, Optional +from typing_extensions import Final import mypy.plugin from mypy.nodes import ARG_POS, ARG_STAR2, Argument, FuncItem, Var @@ -7,11 +8,11 @@ from mypy.types import AnyType, CallableType, get_proper_type, Type, TypeOfAny, UnboundType -functools_total_ordering_makers = { +functools_total_ordering_makers: Final = { 'functools.total_ordering', } -_ORDERING_METHODS = { +_ORDERING_METHODS: Final = { '__lt__', '__le__', '__gt__', @@ -44,9 +45,9 @@ def functools_total_ordering_maker_callback(ctx: mypy.plugin.ClassDefContext, return other_type = _find_other_type(root_method) - bool_type = ctx.api.named_type('__builtins__.bool') + bool_type = ctx.api.named_type('builtins.bool') ret_type: Type = bool_type - if root_method.type.ret_type != ctx.api.named_type('__builtins__.bool'): + if root_method.type.ret_type != ctx.api.named_type('builtins.bool'): proper_ret_type = get_proper_type(root_method.type.ret_type) if not (isinstance(proper_ret_type, UnboundType) and proper_ret_type.name.split('.')[-1] == 'bool'): diff --git a/mypy/plugins/singledispatch.py b/mypy/plugins/singledispatch.py index a6877c3c3cde..104faa38d1ce 100644 --- a/mypy/plugins/singledispatch.py +++ b/mypy/plugins/singledispatch.py @@ -22,11 +22,11 @@ ('singledispatch_obj', Instance), ]) -SINGLEDISPATCH_TYPE = 'functools._SingleDispatchCallable' +SINGLEDISPATCH_TYPE: Final = 'functools._SingleDispatchCallable' -SINGLEDISPATCH_REGISTER_METHOD = '{}.register'.format(SINGLEDISPATCH_TYPE) # type: Final +SINGLEDISPATCH_REGISTER_METHOD: Final = '{}.register'.format(SINGLEDISPATCH_TYPE) -SINGLEDISPATCH_CALLABLE_CALL_METHOD = '{}.__call__'.format(SINGLEDISPATCH_TYPE) # type: Final +SINGLEDISPATCH_CALLABLE_CALL_METHOD: Final = '{}.__call__'.format(SINGLEDISPATCH_TYPE) def get_singledispatch_info(typ: Instance) -> Optional[SingledispatchTypeVars]: @@ -45,11 +45,11 @@ def get_first_arg(args: List[List[T]]) -> Optional[T]: return None -REGISTER_RETURN_CLASS = '_SingleDispatchRegisterCallable' +REGISTER_RETURN_CLASS: Final = '_SingleDispatchRegisterCallable' -REGISTER_CALLABLE_CALL_METHOD = 'functools.{}.__call__'.format( +REGISTER_CALLABLE_CALL_METHOD: Final = 'functools.{}.__call__'.format( REGISTER_RETURN_CLASS -) # type: Final +) def make_fake_register_class_instance(api: CheckerPluginInterface, type_args: Sequence[Type] @@ -123,7 +123,7 @@ def singledispatch_register_callback(ctx: MethodContext) -> Type: # TODO: check that there's only one argument first_arg_type = get_proper_type(get_first_arg(ctx.arg_types)) if isinstance(first_arg_type, (CallableType, Overloaded)) and first_arg_type.is_type_obj(): - # HACK: We receieved a class as an argument to register. We need to be able + # HACK: We received a class as an argument to register. We need to be able # to access the function that register is being applied to, and the typeshed definition # of register has it return a generic Callable, so we create a new # SingleDispatchRegisterCallable class, define a __call__ method, and then add a diff --git a/mypy/pyinfo.py b/mypy/pyinfo.py index 7da94e0a1fb9..3834c04e218e 100644 --- a/mypy/pyinfo.py +++ b/mypy/pyinfo.py @@ -24,12 +24,16 @@ def getprefixes(): def getsitepackages(): # type: () -> List[str] - if hasattr(site, 'getusersitepackages') and hasattr(site, 'getsitepackages'): - user_dir = site.getusersitepackages() - return site.getsitepackages() + [user_dir] + res = [] + if hasattr(site, 'getsitepackages'): + res.extend(site.getsitepackages()) + + if hasattr(site, 'getusersitepackages') and site.ENABLE_USER_SITE: + res.insert(0, site.getusersitepackages()) else: from distutils.sysconfig import get_python_lib - return [get_python_lib()] + res = [get_python_lib()] + return res if __name__ == '__main__': diff --git a/mypy/report.py b/mypy/report.py index 18cbe13138e9..380a8c6b6441 100644 --- a/mypy/report.py +++ b/mypy/report.py @@ -14,7 +14,7 @@ import typing from typing import Any, Callable, Dict, List, Optional, Tuple, cast, Iterator -from typing_extensions import Final +from typing_extensions import Final, TypeAlias as _TypeAlias from mypy.nodes import MypyFile, Expression, FuncDef from mypy import stats @@ -25,10 +25,7 @@ from mypy.defaults import REPORTER_NAMES try: - # mypyc doesn't properly handle import from of submodules that we - # don't have stubs for, hence the hacky double import - import lxml.etree # type: ignore # noqa: F401 - from lxml import etree + from lxml import etree # type: ignore LXML_INSTALLED = True except ImportError: LXML_INSTALLED = False @@ -45,7 +42,10 @@ ] ) -ReporterClasses = Dict[str, Tuple[Callable[['Reports', str], 'AbstractReporter'], bool]] +ReporterClasses: _TypeAlias = Dict[ + str, + Tuple[Callable[['Reports', str], 'AbstractReporter'], bool], +] reporter_classes: Final[ReporterClasses] = {} @@ -466,8 +466,8 @@ def on_file(self, except ValueError: return - if should_skip_path(path): - return + if should_skip_path(path) or os.path.isdir(path): + return # `path` can sometimes be a directory, see #11334 visitor = stats.StatisticsVisitor(inferred=True, filename=tree.fullname, diff --git a/mypy/sametypes.py b/mypy/sametypes.py index 020bda775b59..33cd7f0606cf 100644 --- a/mypy/sametypes.py +++ b/mypy/sametypes.py @@ -4,7 +4,8 @@ Type, UnboundType, AnyType, NoneType, TupleType, TypedDictType, UnionType, CallableType, TypeVarType, Instance, TypeVisitor, ErasedType, Overloaded, PartialType, DeletedType, UninhabitedType, TypeType, LiteralType, - ProperType, get_proper_type, TypeAliasType) + ProperType, get_proper_type, TypeAliasType, ParamSpecType +) from mypy.typeops import tuple_fallback, make_simplified_union @@ -96,6 +97,11 @@ def visit_type_var(self, left: TypeVarType) -> bool: return (isinstance(self.right, TypeVarType) and left.id == self.right.id) + def visit_param_spec(self, left: ParamSpecType) -> bool: + # Ignore upper bound since it's derived from flavor. + return (isinstance(self.right, ParamSpecType) and + left.id == self.right.id and left.flavor == self.right.flavor) + def visit_callable_type(self, left: CallableType) -> bool: # FIX generics if isinstance(self.right, CallableType): diff --git a/mypy/scope.py b/mypy/scope.py index 12952e9c28f8..fdc1c1a314fc 100644 --- a/mypy/scope.py +++ b/mypy/scope.py @@ -5,12 +5,13 @@ from contextlib import contextmanager from typing import List, Optional, Iterator, Tuple +from typing_extensions import TypeAlias as _TypeAlias from mypy.backports import nullcontext from mypy.nodes import TypeInfo, FuncBase -SavedScope = Tuple[str, Optional[TypeInfo], Optional[FuncBase]] +SavedScope: _TypeAlias = Tuple[str, Optional[TypeInfo], Optional[FuncBase]] class Scope: diff --git a/mypy/semanal.py b/mypy/semanal.py index 6e32586720c5..f29965f6ff8f 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -53,7 +53,7 @@ from typing import ( List, Dict, Set, Tuple, cast, TypeVar, Union, Optional, Callable, Iterator, Iterable ) -from typing_extensions import Final +from typing_extensions import Final, TypeAlias as _TypeAlias from mypy.nodes import ( MypyFile, TypeInfo, Node, AssignmentStmt, FuncDef, OverloadedFuncDef, @@ -75,8 +75,9 @@ PlaceholderNode, COVARIANT, CONTRAVARIANT, INVARIANT, get_nongen_builtins, get_member_expr_fullname, REVEAL_TYPE, REVEAL_LOCALS, is_final_node, TypedDictExpr, type_aliases_source_versions, + typing_extensions_aliases, EnumCallExpr, RUNTIME_PROTOCOL_DECOS, FakeExpression, Statement, AssignmentExpr, - ParamSpecExpr, EllipsisExpr + ParamSpecExpr, EllipsisExpr, TypeVarLikeExpr, FuncBase, implicit_module_attrs, ) from mypy.tvar_scope import TypeVarLikeScope from mypy.typevars import fill_typevars @@ -91,11 +92,10 @@ FunctionLike, UnboundType, TypeVarType, TupleType, UnionType, StarType, CallableType, Overloaded, Instance, Type, AnyType, LiteralType, LiteralValue, TypeTranslator, TypeOfAny, TypeType, NoneType, PlaceholderType, TPDICT_NAMES, ProperType, - get_proper_type, get_proper_types, TypeAliasType + get_proper_type, get_proper_types, TypeAliasType, TypeVarLikeType ) -from mypy.typeops import function_type +from mypy.typeops import function_type, get_type_vars from mypy.type_visitor import TypeQuery -from mypy.nodes import implicit_module_attrs from mypy.typeanal import ( TypeAnalyser, analyze_type_alias, no_subscript_builtin_alias, TypeVarLikeQuery, TypeVarLikeList, remove_dups, has_any_from_unimported_type, @@ -116,7 +116,7 @@ ) from mypy.semanal_namedtuple import NamedTupleAnalyzer from mypy.semanal_typeddict import TypedDictAnalyzer -from mypy.semanal_enum import EnumCallAnalyzer +from mypy.semanal_enum import EnumCallAnalyzer, ENUM_BASES from mypy.semanal_newtype import NewTypeAnalyzer from mypy.reachability import ( infer_reachability_of_if_statement, infer_condition_value, ALWAYS_FALSE, ALWAYS_TRUE, @@ -147,7 +147,7 @@ # Used for tracking incomplete references -Tag = int +Tag: _TypeAlias = int class SemanticAnalyzer(NodeVisitor[None], @@ -312,9 +312,12 @@ def prepare_file(self, file_node: MypyFile) -> None: if file_node.fullname == 'builtins': self.prepare_builtins_namespace(file_node) if file_node.fullname == 'typing': - self.prepare_typing_namespace(file_node) + self.prepare_typing_namespace(file_node, type_aliases) + if file_node.fullname == 'typing_extensions': + self.prepare_typing_namespace(file_node, typing_extensions_aliases) - def prepare_typing_namespace(self, file_node: MypyFile) -> None: + def prepare_typing_namespace(self, file_node: MypyFile, + aliases: Dict[str, str]) -> None: """Remove dummy alias definitions such as List = TypeAlias(object) from typing. They will be replaced with real aliases when corresponding targets are ready. @@ -336,7 +339,7 @@ def helper(defs: List[Statement]) -> None: if (isinstance(stmt, AssignmentStmt) and len(stmt.lvalues) == 1 and isinstance(stmt.lvalues[0], NameExpr)): # Assignment to a simple name, remove it if it is a dummy alias. - if 'typing.' + stmt.lvalues[0].name in type_aliases: + if f'{file_node.fullname}.{stmt.lvalues[0].name}' in aliases: defs.remove(stmt) helper(file_node.defs) @@ -413,6 +416,8 @@ def refresh_top_level(self, file_node: MypyFile) -> None: self.accept(d) if file_node.fullname == 'typing': self.add_builtin_aliases(file_node) + if file_node.fullname == 'typing_extensions': + self.add_typing_extension_aliases(file_node) self.adjust_public_exports() self.export_map[self.cur_mod_id] = self.all_exports self.all_exports = [] @@ -474,30 +479,53 @@ def add_builtin_aliases(self, tree: MypyFile) -> None: name = alias.split('.')[-1] if name in tree.names and not isinstance(tree.names[name].node, PlaceholderNode): continue - tag = self.track_incomplete_refs() - n = self.lookup_fully_qualified_or_none(target_name) - if n: - if isinstance(n.node, PlaceholderNode): - self.mark_incomplete(name, tree) - else: - # Found built-in class target. Create alias. - target = self.named_type_or_none(target_name, []) - assert target is not None - # Transform List to List[Any], etc. - fix_instance_types(target, self.fail, self.note, self.options.python_version) - alias_node = TypeAlias(target, alias, - line=-1, column=-1, # there is no context - no_args=True, normalized=True) - self.add_symbol(name, alias_node, tree) - elif self.found_incomplete_ref(tag): - # Built-in class target may not ready yet -- defer. + self.create_alias(tree, target_name, alias, name) + + def add_typing_extension_aliases(self, tree: MypyFile) -> None: + """Typing extensions module does contain some type aliases. + + We need to analyze them as such, because in typeshed + they are just defined as `_Alias()` call. + Which is not supported natively. + """ + assert tree.fullname == 'typing_extensions' + + for alias, target_name in typing_extensions_aliases.items(): + name = alias.split('.')[-1] + if name in tree.names and isinstance(tree.names[name].node, TypeAlias): + continue # Do not reset TypeAliases on the second pass. + + # We need to remove any node that is there at the moment. It is invalid. + tree.names.pop(name, None) + + # Now, create a new alias. + self.create_alias(tree, target_name, alias, name) + + def create_alias(self, tree: MypyFile, target_name: str, alias: str, name: str) -> None: + tag = self.track_incomplete_refs() + n = self.lookup_fully_qualified_or_none(target_name) + if n: + if isinstance(n.node, PlaceholderNode): self.mark_incomplete(name, tree) else: - # Test fixtures may be missing some builtin classes, which is okay. - # Kill the placeholder if there is one. - if name in tree.names: - assert isinstance(tree.names[name].node, PlaceholderNode) - del tree.names[name] + # Found built-in class target. Create alias. + target = self.named_type_or_none(target_name, []) + assert target is not None + # Transform List to List[Any], etc. + fix_instance_types(target, self.fail, self.note, self.options.python_version) + alias_node = TypeAlias(target, alias, + line=-1, column=-1, # there is no context + no_args=True, normalized=True) + self.add_symbol(name, alias_node, tree) + elif self.found_incomplete_ref(tag): + # Built-in class target may not ready yet -- defer. + self.mark_incomplete(name, tree) + else: + # Test fixtures may be missing some builtin classes, which is okay. + # Kill the placeholder if there is one. + if name in tree.names: + assert isinstance(tree.names[name].node, PlaceholderNode) + del tree.names[name] def adjust_public_exports(self) -> None: """Adjust the module visibility of globals due to __all__.""" @@ -732,7 +760,7 @@ def analyze_overloaded_func_def(self, defn: OverloadedFuncDef) -> None: # This is a property. first_item.func.is_overload = True self.analyze_property_with_multi_part_definition(defn) - typ = function_type(first_item.func, self.builtin_type('builtins.function')) + typ = function_type(first_item.func, self.named_type('builtins.function')) assert isinstance(typ, CallableType) types = [typ] else: @@ -789,7 +817,7 @@ def analyze_overload_sigs_and_impl( item.accept(self) # TODO: support decorated overloaded functions properly if isinstance(item, Decorator): - callable = function_type(item.func, self.builtin_type('builtins.function')) + callable = function_type(item.func, self.named_type('builtins.function')) assert isinstance(callable, CallableType) if not any(refers_to_fullname(dec, 'typing.overload') for dec in item.decorators): @@ -953,18 +981,17 @@ def analyze_function_body(self, defn: FuncItem) -> None: a = self.type_analyzer() a.bind_function_type_variables(cast(CallableType, defn.type), defn) self.function_stack.append(defn) - self.enter(defn) - for arg in defn.arguments: - self.add_local(arg.variable, defn) + with self.enter(defn): + for arg in defn.arguments: + self.add_local(arg.variable, defn) - # The first argument of a non-static, non-class method is like 'self' - # (though the name could be different), having the enclosing class's - # instance type. - if is_method and not defn.is_static and not defn.is_class and defn.arguments: - defn.arguments[0].variable.is_self = True + # The first argument of a non-static, non-class method is like 'self' + # (though the name could be different), having the enclosing class's + # instance type. + if is_method and not defn.is_static and not defn.is_class and defn.arguments: + defn.arguments[0].variable.is_self = True - defn.body.accept(self) - self.leave() + defn.body.accept(self) self.function_stack.pop() def check_classvar_in_signature(self, typ: ProperType) -> None: @@ -1097,11 +1124,12 @@ def analyze_class(self, defn: ClassDef) -> None: self.update_metaclass(defn) bases = defn.base_type_exprs - bases, tvar_defs, is_protocol = self.clean_up_bases_and_infer_type_variables(defn, bases, - context=defn) + bases, tvar_defs, is_protocol = self.clean_up_bases_and_infer_type_variables( + defn, bases, context=defn) for tvd in tvar_defs: - if any(has_placeholder(t) for t in [tvd.upper_bound] + tvd.values): + if (isinstance(tvd, TypeVarType) + and any(has_placeholder(t) for t in [tvd.upper_bound] + tvd.values)): # Some type variable bounds or values are not ready, we need # to re-analyze this class. self.defer() @@ -1263,7 +1291,7 @@ def clean_up_bases_and_infer_type_variables( defn: ClassDef, base_type_exprs: List[Expression], context: Context) -> Tuple[List[Expression], - List[TypeVarType], + List[TypeVarLikeType], bool]: """Remove extra base classes such as Generic and infer type vars. @@ -1324,12 +1352,9 @@ 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[TypeVarType] = [] + tvar_defs: List[TypeVarLikeType] = [] for name, tvar_expr in declared_tvars: tvar_def = self.tvar_scope.bind_new(name, tvar_expr) - assert isinstance(tvar_def, TypeVarType), ( - "mypy does not currently support ParamSpec use in generic classes" - ) tvar_defs.append(tvar_def) return base_type_exprs, tvar_defs, is_protocol @@ -1367,13 +1392,18 @@ def analyze_class_typevar_declaration( return tvars, is_proto return None - def analyze_unbound_tvar(self, t: Type) -> Optional[Tuple[str, TypeVarExpr]]: + def analyze_unbound_tvar(self, t: Type) -> Optional[Tuple[str, TypeVarLikeExpr]]: if not isinstance(t, UnboundType): return None unbound = t sym = self.lookup_qualified(unbound.name, unbound) if sym and isinstance(sym.node, PlaceholderNode): self.record_incomplete_ref() + if sym and isinstance(sym.node, ParamSpecExpr): + if sym.fullname and not self.tvar_scope.allow_binding(sym.fullname): + # It's bound by our type variable scope + return None + return unbound.name, sym.node if sym is None or not isinstance(sym.node, TypeVarExpr): return None elif sym.fullname and not self.tvar_scope.allow_binding(sym.fullname): @@ -1522,6 +1552,13 @@ def configure_base_classes(self, elif isinstance(base, Instance): if base.type.is_newtype: self.fail('Cannot subclass "NewType"', defn) + if self.enum_has_final_values(base): + # This means that are trying to subclass a non-default + # Enum class, with defined members. This is not possible. + # In runtime, it will raise. We need to mark this type as final. + # However, methods can be defined on a type: only values can't. + # We also don't count values with annotations only. + base.type.is_final = True base_types.append(base) elif isinstance(base, AnyType): if self.options.disallow_subclassing_any: @@ -1559,6 +1596,25 @@ def configure_base_classes(self, return self.calculate_class_mro(defn, self.object_type) + def enum_has_final_values(self, base: Instance) -> bool: + if ( + base.type.is_enum + and base.type.fullname not in ENUM_BASES + and base.type.names + and base.type.defn + ): + for sym in base.type.names.values(): + if isinstance(sym.node, (FuncBase, Decorator)): + continue # A method + if not isinstance(sym.node, Var): + return True # Can be a class + if self.is_stub_file or sym.node.has_explicit_value: + # Corner case: assignments like `x: int` are fine in `.py` files. + # But, not is `.pyi` files, because we don't know + # if there's aactually a value or not. + return True + return False + def configure_tuple_base_class(self, defn: ClassDef, base: TupleType, @@ -1796,6 +1852,12 @@ def visit_import_from(self, imp: ImportFrom) -> None: missing_submodule = False imported_id = as_id or id + # Modules imported in a stub file without using 'from Y import X as X' will + # not get exported. + # When implicit re-exporting is disabled, we have the same behavior as stubs. + use_implicit_reexport = not self.is_stub_file and self.options.implicit_reexport + module_public = use_implicit_reexport or (as_id is not None and id == as_id) + # If the module does not contain a symbol with the name 'id', # try checking if it's a module instead. if not node: @@ -1813,15 +1875,12 @@ def visit_import_from(self, imp: ImportFrom) -> None: fullname = module_id + '.' + id gvar = self.create_getattr_var(module.names['__getattr__'], imported_id, fullname) if gvar: - self.add_symbol(imported_id, gvar, imp) + self.add_symbol( + imported_id, gvar, imp, module_public=module_public, + module_hidden=not module_public + ) continue - # Modules imported in a stub file without using 'from Y import X as X' will - # not get exported. - # When implicit re-exporting is disabled, we have the same behavior as stubs. - use_implicit_reexport = not self.is_stub_file and self.options.implicit_reexport - module_public = use_implicit_reexport or (as_id is not None and id == as_id) - if node and not node.module_hidden: self.process_imported_symbol( node, module_id, id, imported_id, fullname, module_public, context=imp @@ -1887,7 +1946,9 @@ def report_missing_module_attribute( if self.is_incomplete_namespace(import_id): # We don't know whether the name will be there, since the namespace # is incomplete. Defer the current target. - self.mark_incomplete(imported_id, context) + self.mark_incomplete( + imported_id, context, module_public=module_public, module_hidden=module_hidden + ) return message = 'Module "{}" has no attribute "{}"'.format(import_id, source_id) # Suggest alternatives, if any match is found. @@ -1993,7 +2054,7 @@ def visit_import_all(self, i: ImportAll) -> None: def visit_assignment_expr(self, s: AssignmentExpr) -> None: s.value.accept(self) - self.analyze_lvalue(s.target, escape_comprehensions=True) + self.analyze_lvalue(s.target, escape_comprehensions=True, has_explicit_value=True) def visit_assignment_stmt(self, s: AssignmentStmt) -> None: self.statement = s @@ -2032,9 +2093,13 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> None: special_form = True elif self.analyze_enum_assign(s): special_form = True + if special_form: self.record_special_form_lvalue(s) return + # Clear the alias flag if assignment turns out not a special form after all. It + # may be set to True while there were still placeholders due to forward refs. + s.is_alias_def = False # OK, this is a regular assignment, perform the necessary analysis steps. s.is_final_def = self.unwrap_final(s) @@ -2282,31 +2347,49 @@ def analyze_lvalues(self, s: AssignmentStmt) -> None: assert isinstance(s.unanalyzed_type, UnboundType) if not s.unanalyzed_type.args: explicit = False + + if s.rvalue: + if isinstance(s.rvalue, TempNode): + has_explicit_value = not s.rvalue.no_rhs + else: + has_explicit_value = True + else: + has_explicit_value = False + for lval in s.lvalues: self.analyze_lvalue(lval, explicit_type=explicit, - is_final=s.is_final_def) + is_final=s.is_final_def, + has_explicit_value=has_explicit_value) def apply_dynamic_class_hook(self, s: AssignmentStmt) -> None: - if len(s.lvalues) > 1: - return - lval = s.lvalues[0] - if not isinstance(lval, NameExpr) or not isinstance(s.rvalue, CallExpr): + if not isinstance(s.rvalue, CallExpr): return - call = s.rvalue fname = None - if isinstance(call.callee, RefExpr): - fname = call.callee.fullname - # check if method call - if fname is None and isinstance(call.callee, MemberExpr): - callee_expr = call.callee.expr - if isinstance(callee_expr, RefExpr) and callee_expr.fullname: - method_name = call.callee.name - fname = callee_expr.fullname + '.' + method_name - if fname: - hook = self.plugin.get_dynamic_class_hook(fname) - if hook: - hook(DynamicClassDefContext(call, lval.name, self)) + call = s.rvalue + while True: + if isinstance(call.callee, RefExpr): + fname = call.callee.fullname + # check if method call + if fname is None and isinstance(call.callee, MemberExpr): + callee_expr = call.callee.expr + if isinstance(callee_expr, RefExpr) and callee_expr.fullname: + method_name = call.callee.name + fname = callee_expr.fullname + '.' + method_name + elif isinstance(callee_expr, CallExpr): + # check if chain call + call = callee_expr + continue + break + if not fname: + return + hook = self.plugin.get_dynamic_class_hook(fname) + if not hook: + return + for lval in s.lvalues: + if not isinstance(lval, NameExpr): + continue + hook(DynamicClassDefContext(call, lval.name, self)) def unwrap_final(self, s: AssignmentStmt) -> bool: """Strip Final[...] if present in an assignment. @@ -2392,10 +2475,30 @@ def store_final_status(self, s: AssignmentStmt) -> None: (isinstance(s.rvalue, TempNode) and s.rvalue.no_rhs)): node.final_unset_in_class = True else: - # Special case: deferred initialization of a final attribute in __init__. - # In this case we just pretend this is a valid final definition to suppress - # errors about assigning to final attribute. for lval in self.flatten_lvalues(s.lvalues): + # Special case: we are working with an `Enum`: + # + # class MyEnum(Enum): + # key = 'some value' + # + # Here `key` is implicitly final. In runtime, code like + # + # MyEnum.key = 'modified' + # + # will fail with `AttributeError: Cannot reassign members.` + # That's why we need to replicate this. + if (isinstance(lval, NameExpr) and + isinstance(self.type, TypeInfo) and + self.type.is_enum): + cur_node = self.type.names.get(lval.name, None) + if (cur_node and isinstance(cur_node.node, Var) and + not (isinstance(s.rvalue, TempNode) and s.rvalue.no_rhs)): + cur_node.node.is_final = True + s.is_final_def = True + + # Special case: deferred initialization of a final attribute in __init__. + # In this case we just pretend this is a valid final definition to suppress + # errors about assigning to final attribute. if isinstance(lval, MemberExpr) and self.is_self_member_ref(lval): assert self.type, "Self member outside a class" cur_node = self.type.names.get(lval.name, None) @@ -2555,8 +2658,15 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool: if len(s.lvalues) > 1 or not isinstance(lvalue, NameExpr): # First rule: Only simple assignments like Alias = ... create aliases. return False - if s.unanalyzed_type is not None: + + pep_613 = False + if s.unanalyzed_type is not None and isinstance(s.unanalyzed_type, UnboundType): + lookup = self.lookup(s.unanalyzed_type.name, s, suppress_errors=True) + if lookup and lookup.fullname in ("typing.TypeAlias", "typing_extensions.TypeAlias"): + pep_613 = True + if s.unanalyzed_type is not None and not pep_613: # Second rule: Explicit type (cls: Type[A] = A) always creates variable, not alias. + # unless using PEP 613 `cls: TypeAlias = A` return False existing = self.current_symbol_table().get(lvalue.name) @@ -2581,7 +2691,7 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool: return False non_global_scope = self.type or self.is_func_scope() - if isinstance(s.rvalue, RefExpr) and non_global_scope: + if isinstance(s.rvalue, RefExpr) and non_global_scope and not pep_613: # Fourth rule (special case): Non-subscripted right hand side creates a variable # at class and function scopes. For example: # @@ -2594,7 +2704,7 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool: # annotations (see the second rule). return False rvalue = s.rvalue - if not self.can_be_type_alias(rvalue): + if not self.can_be_type_alias(rvalue) and not pep_613: return False if existing and not isinstance(existing.node, (PlaceholderNode, TypeAlias)): @@ -2690,7 +2800,8 @@ def analyze_lvalue(self, nested: bool = False, explicit_type: bool = False, is_final: bool = False, - escape_comprehensions: bool = False) -> None: + escape_comprehensions: bool = False, + has_explicit_value: bool = False) -> None: """Analyze an lvalue or assignment target. Args: @@ -2704,7 +2815,11 @@ def analyze_lvalue(self, if escape_comprehensions: assert isinstance(lval, NameExpr), "assignment expression target must be NameExpr" if isinstance(lval, NameExpr): - self.analyze_name_lvalue(lval, explicit_type, is_final, escape_comprehensions) + self.analyze_name_lvalue( + lval, explicit_type, is_final, + escape_comprehensions, + has_explicit_value=has_explicit_value, + ) elif isinstance(lval, MemberExpr): self.analyze_member_lvalue(lval, explicit_type, is_final) if explicit_type and not self.is_self_member_ref(lval): @@ -2728,7 +2843,8 @@ def analyze_name_lvalue(self, lvalue: NameExpr, explicit_type: bool, is_final: bool, - escape_comprehensions: bool) -> None: + escape_comprehensions: bool, + has_explicit_value: bool) -> None: """Analyze an lvalue that targets a name expression. Arguments are similar to "analyze_lvalue". @@ -2745,13 +2861,20 @@ def analyze_name_lvalue(self, self.msg.cant_assign_to_final(name, self.type is not None, lvalue) kind = self.current_symbol_kind() - names = self.current_symbol_table() + names = self.current_symbol_table(escape_comprehensions=escape_comprehensions) existing = names.get(name) outer = self.is_global_or_nonlocal(name) + if kind == MDEF and isinstance(self.type, TypeInfo) and self.type.is_enum: + # Special case: we need to be sure that `Enum` keys are unique. + if existing: + self.fail('Attempted to reuse member name "{}" in Enum definition "{}"'.format( + name, self.type.name, + ), 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) + var = self.make_name_lvalue_var(lvalue, kind, not explicit_type, has_explicit_value) added = self.add_symbol(name, var, lvalue, escape_comprehensions=escape_comprehensions) # Only bind expression if we successfully added name to symbol table. if added: @@ -2802,7 +2925,9 @@ def is_alias_for_final_name(self, name: str) -> bool: existing = self.globals.get(orig_name) return existing is not None and is_final_node(existing.node) - def make_name_lvalue_var(self, lvalue: NameExpr, kind: int, inferred: bool) -> Var: + def make_name_lvalue_var( + self, lvalue: NameExpr, kind: int, inferred: bool, has_explicit_value: bool, + ) -> Var: """Return a Var node for an lvalue that is a name expression.""" v = Var(lvalue.name) v.set_line(lvalue) @@ -2817,6 +2942,7 @@ def make_name_lvalue_var(self, lvalue: NameExpr, kind: int, inferred: bool) -> V # fullanme should never stay None v._fullname = lvalue.name v.is_ready = False # Type not inferred yet + v.has_explicit_value = has_explicit_value return v def make_name_lvalue_point_to_existing_def( @@ -2860,7 +2986,14 @@ def analyze_tuple_or_list_lvalue(self, lval: TupleExpr, if len(star_exprs) == 1: star_exprs[0].valid = True for i in items: - self.analyze_lvalue(i, nested=True, explicit_type=explicit_type) + self.analyze_lvalue( + lval=i, + nested=True, + explicit_type=explicit_type, + # Lists and tuples always have explicit values defined: + # `a, b, c = value` + has_explicit_value=True, + ) def analyze_member_lvalue(self, lval: MemberExpr, explicit_type: bool, is_final: bool) -> None: """Analyze lvalue that is a member expression. @@ -3081,28 +3214,24 @@ def process_typevar_parameters(self, args: List[Expression], contravariant = False upper_bound: Type = self.object_type() for param_value, param_name, param_kind in zip(args, names, kinds): - if not param_kind == ARG_NAMED: - self.fail("Unexpected argument to TypeVar()", context) + if not param_kind.is_named(): + self.fail(message_registry.TYPEVAR_UNEXPECTED_ARGUMENT, context) return None if param_name == 'covariant': - if isinstance(param_value, NameExpr): - if param_value.name == 'True': - covariant = True - else: - self.fail("TypeVar 'covariant' may only be 'True'", context) - return None + if (isinstance(param_value, NameExpr) + and param_value.name in ('True', 'False')): + covariant = param_value.name == 'True' else: - self.fail("TypeVar 'covariant' may only be 'True'", context) + self.fail(message_registry.TYPEVAR_VARIANCE_DEF.format( + 'covariant'), context) return None elif param_name == 'contravariant': - if isinstance(param_value, NameExpr): - if param_value.name == 'True': - contravariant = True - else: - self.fail("TypeVar 'contravariant' may only be 'True'", context) - return None + if (isinstance(param_value, NameExpr) + and param_value.name in ('True', 'False')): + contravariant = param_value.name == 'True' else: - self.fail("TypeVar 'contravariant' may only be 'True'", context) + self.fail(message_registry.TYPEVAR_VARIANCE_DEF.format( + 'contravariant'), context) return None elif param_name == 'bound': if has_values: @@ -3124,11 +3253,11 @@ def process_typevar_parameters(self, args: List[Expression], analyzed = PlaceholderType(None, [], context.line) upper_bound = get_proper_type(analyzed) if isinstance(upper_bound, AnyType) and upper_bound.is_from_error: - self.fail('TypeVar "bound" must be a type', param_value) + self.fail(message_registry.TYPEVAR_BOUND_MUST_BE_TYPE, param_value) # Note: we do not return 'None' here -- we want to continue # using the AnyType as the upper bound. except TypeTranslationError: - self.fail('TypeVar "bound" must be a type', param_value) + self.fail(message_registry.TYPEVAR_BOUND_MUST_BE_TYPE, param_value) return None elif param_name == 'values': # Probably using obsolete syntax with values=(...). Explain the current syntax. @@ -3137,7 +3266,9 @@ def process_typevar_parameters(self, args: List[Expression], context) return None else: - self.fail('Unexpected argument to TypeVar(): "{}"'.format(param_name), context) + self.fail('{}: "{}"'.format( + message_registry.TYPEVAR_UNEXPECTED_ARGUMENT, param_name, + ), context) return None if covariant and contravariant: @@ -3247,6 +3378,12 @@ def check_classvar(self, s: AssignmentStmt) -> None: node = lvalue.node if isinstance(node, Var): node.is_classvar = True + analyzed = self.anal_type(s.type) + if analyzed is not None and get_type_vars(analyzed): + # This means that we have a type var defined inside of a ClassVar. + # This is not allowed by PEP526. + # See https://github.com/python/mypy/issues/11538 + self.fail(message_registry.CLASS_VAR_WITH_TYPEVARS, s) elif not isinstance(lvalue, MemberExpr) or self.is_self_member_ref(lvalue): # In case of member access, report error only when assigning to self # Other kinds of member assignments should be already reported @@ -3269,7 +3406,7 @@ def is_final_type(self, typ: Optional[Type]) -> bool: return sym.node.fullname in ('typing.Final', 'typing_extensions.Final') def fail_invalid_classvar(self, context: Context) -> None: - self.fail('ClassVar can only be used for assignments in class body', context) + self.fail(message_registry.CLASS_VAR_OUTSIDE_OF_CLASS, context) def process_module_assignment(self, lvals: List[Lvalue], rval: Expression, ctx: AssignmentStmt) -> None: @@ -4027,18 +4164,16 @@ def visit_set_comprehension(self, expr: SetComprehension) -> None: expr.generator.accept(self) def visit_dictionary_comprehension(self, expr: DictionaryComprehension) -> None: - self.enter(expr) - self.analyze_comp_for(expr) - expr.key.accept(self) - expr.value.accept(self) - self.leave() + with self.enter(expr): + self.analyze_comp_for(expr) + expr.key.accept(self) + expr.value.accept(self) self.analyze_comp_for_2(expr) def visit_generator_expr(self, expr: GeneratorExpr) -> None: - self.enter(expr) - self.analyze_comp_for(expr) - expr.left_expr.accept(self) - self.leave() + with self.enter(expr): + self.analyze_comp_for(expr) + expr.left_expr.accept(self) self.analyze_comp_for_2(expr) def analyze_comp_for(self, expr: Union[GeneratorExpr, @@ -4365,22 +4500,10 @@ def create_getattr_var(self, getattr_defn: SymbolTableNode, return v return None - def lookup_fully_qualified(self, name: str) -> SymbolTableNode: - """Lookup a fully qualified name. - - Assume that the name is defined. This happens in the global namespace -- - the local module namespace is ignored. - - Note that this doesn't support visibility, module-level __getattr__, or - nested classes. - """ - parts = name.split('.') - n = self.modules[parts[0]] - for i in range(1, len(parts) - 1): - next_sym = n.names[parts[i]] - assert isinstance(next_sym.node, MypyFile) - n = next_sym.node - return n.names[parts[-1]] + def lookup_fully_qualified(self, fullname: str) -> SymbolTableNode: + ret = self.lookup_fully_qualified_or_none(fullname) + assert ret is not None + return ret def lookup_fully_qualified_or_none(self, fullname: str) -> Optional[SymbolTableNode]: """Lookup a fully qualified name that refers to a module-level definition. @@ -4405,20 +4528,14 @@ def lookup_fully_qualified_or_none(self, fullname: str) -> Optional[SymbolTableN self.record_incomplete_ref() return result - def builtin_type(self, fully_qualified_name: str) -> Instance: - sym = self.lookup_fully_qualified(fully_qualified_name) - node = sym.node - assert isinstance(node, TypeInfo) - return Instance(node, [AnyType(TypeOfAny.special_form)] * len(node.defn.type_vars)) - def object_type(self) -> Instance: - return self.named_type('__builtins__.object') + return self.named_type('builtins.object') def str_type(self) -> Instance: - return self.named_type('__builtins__.str') + return self.named_type('builtins.str') - def named_type(self, qualified_name: str, args: Optional[List[Type]] = None) -> Instance: - sym = self.lookup_qualified(qualified_name, Context()) + def named_type(self, fullname: str, args: Optional[List[Type]] = None) -> Instance: + sym = self.lookup_fully_qualified(fullname) assert sym, "Internal error: attempted to construct unknown type" node = sym.node assert isinstance(node, TypeInfo) @@ -4427,9 +4544,9 @@ def named_type(self, qualified_name: str, args: Optional[List[Type]] = None) -> return Instance(node, args) return Instance(node, [AnyType(TypeOfAny.special_form)] * len(node.defn.type_vars)) - def named_type_or_none(self, qualified_name: str, + def named_type_or_none(self, fullname: str, args: Optional[List[Type]] = None) -> Optional[Instance]: - sym = self.lookup_fully_qualified_or_none(qualified_name) + sym = self.lookup_fully_qualified_or_none(fullname) if not sym or isinstance(sym.node, PlaceholderNode): return None node = sym.node @@ -4534,7 +4651,11 @@ def add_symbol_table_node(self, names = self.current_symbol_table(escape_comprehensions=escape_comprehensions) existing = names.get(name) if isinstance(symbol.node, PlaceholderNode) and can_defer: - self.defer(context) + if context is not None: + self.process_placeholder(name, 'name', context) + else: + # see note in docstring describing None contexts + self.defer() if (existing is not None and context is not None and not is_valid_replacement(existing, symbol)): @@ -4772,7 +4893,9 @@ def qualified_name(self, name: str) -> str: else: return self.cur_mod_id + '.' + name - def enter(self, function: Union[FuncItem, GeneratorExpr, DictionaryComprehension]) -> None: + @contextmanager + def enter(self, + function: Union[FuncItem, GeneratorExpr, DictionaryComprehension]) -> Iterator[None]: """Enter a function, generator or comprehension scope.""" names = self.saved_locals.setdefault(function, SymbolTable()) self.locals.append(names) @@ -4783,14 +4906,15 @@ def enter(self, function: Union[FuncItem, GeneratorExpr, DictionaryComprehension # -1 since entering block will increment this to 0. self.block_depth.append(-1) self.missing_names.append(set()) - - def leave(self) -> None: - self.locals.pop() - self.is_comprehension_stack.pop() - self.global_decls.pop() - self.nonlocal_decls.pop() - self.block_depth.pop() - self.missing_names.pop() + try: + yield + finally: + self.locals.pop() + self.is_comprehension_stack.pop() + self.global_decls.pop() + self.nonlocal_decls.pop() + self.block_depth.pop() + self.missing_names.pop() def is_func_scope(self) -> bool: return self.locals[-1] is not None @@ -4953,6 +5077,35 @@ def is_local_name(self, name: str) -> bool: """Does name look like reference to a definition in the current module?""" return self.is_defined_in_current_module(name) or '.' not in name + def in_checked_function(self) -> bool: + """Should we type-check the current function? + + - Yes if --check-untyped-defs is set. + - Yes outside functions. + - Yes in annotated functions. + - No otherwise. + """ + if self.options.check_untyped_defs or not self.function_stack: + return True + + current_index = len(self.function_stack) - 1 + while current_index >= 0: + current_func = self.function_stack[current_index] + if ( + isinstance(current_func, FuncItem) + and not isinstance(current_func, LambdaExpr) + ): + return not current_func.is_dynamic() + + # Special case, `lambda` inherits the "checked" state from its parent. + # Because `lambda` itself cannot be annotated. + # `lambdas` can be deeply nested, so we try to find at least one other parent. + current_index -= 1 + + # This means that we only have a stack of `lambda` functions, + # no regular functions. + return True + def fail(self, msg: str, ctx: Context, @@ -4960,10 +5113,7 @@ def fail(self, *, code: Optional[ErrorCode] = None, blocker: bool = False) -> None: - if (not serious and - not self.options.check_untyped_defs and - self.function_stack and - self.function_stack[-1].is_dynamic()): + if not serious and not self.in_checked_function(): return # In case it's a bug and we don't really have context assert ctx is not None, msg @@ -4973,9 +5123,7 @@ def fail_blocker(self, msg: str, ctx: Context) -> None: self.fail(msg, ctx, blocker=True) def note(self, msg: str, ctx: Context, code: Optional[ErrorCode] = None) -> None: - if (not self.options.check_untyped_defs and - self.function_stack and - self.function_stack[-1].is_dynamic()): + if not self.in_checked_function(): return self.errors.report(ctx.get_line(), ctx.get_column(), msg, severity='note', code=code) @@ -5022,6 +5170,7 @@ def type_analyzer(self, *, allow_tuple_literal: bool = False, allow_unbound_tvars: bool = False, allow_placeholder: bool = False, + allow_required: bool = False, report_invalid_types: bool = True) -> TypeAnalyser: if tvar_scope is None: tvar_scope = self.tvar_scope @@ -5033,8 +5182,9 @@ def type_analyzer(self, *, allow_unbound_tvars=allow_unbound_tvars, allow_tuple_literal=allow_tuple_literal, report_invalid_types=report_invalid_types, - allow_new_syntax=self.is_stub_file, - allow_placeholder=allow_placeholder) + allow_placeholder=allow_placeholder, + allow_required=allow_required, + allow_new_syntax=self.is_stub_file) tpan.in_dynamic_func = bool(self.function_stack and self.function_stack[-1].is_dynamic()) tpan.global_scope = not self.type and not self.function_stack return tpan @@ -5048,6 +5198,7 @@ def anal_type(self, allow_tuple_literal: bool = False, allow_unbound_tvars: bool = False, allow_placeholder: bool = False, + allow_required: bool = False, report_invalid_types: bool = True, third_pass: bool = False) -> Optional[Type]: """Semantically analyze a type. @@ -5074,6 +5225,7 @@ def anal_type(self, allow_unbound_tvars=allow_unbound_tvars, allow_tuple_literal=allow_tuple_literal, allow_placeholder=allow_placeholder, + allow_required=allow_required, report_invalid_types=report_invalid_types) tag = self.track_incomplete_refs() typ = typ.accept(a) diff --git a/mypy/semanal_enum.py b/mypy/semanal_enum.py index 07e8e048decd..5682f66298f6 100644 --- a/mypy/semanal_enum.py +++ b/mypy/semanal_enum.py @@ -4,6 +4,7 @@ """ from typing import List, Tuple, Optional, Union, cast +from typing_extensions import Final from mypy.nodes import ( Expression, Context, TypeInfo, AssignmentStmt, NameExpr, CallExpr, RefExpr, StrExpr, @@ -13,6 +14,15 @@ from mypy.semanal_shared import SemanticAnalyzerInterface from mypy.options import Options +# 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. +ENUM_BASES: Final = frozenset(( + 'enum.Enum', 'enum.IntEnum', 'enum.Flag', 'enum.IntFlag', +)) +ENUM_SPECIAL_PROPS: Final = frozenset(( + 'name', 'value', '_name_', '_value_', '_order_', '__order__', +)) + class EnumCallAnalyzer: def __init__(self, options: Options, api: SemanticAnalyzerInterface) -> None: @@ -62,7 +72,7 @@ class A(enum.Enum): if not isinstance(callee, RefExpr): return None fullname = callee.fullname - if fullname not in ('enum.Enum', 'enum.IntEnum', 'enum.Flag', 'enum.IntFlag'): + if fullname not in ENUM_BASES: return None items, values, ok = self.parse_enum_call_args(call, fullname.split('.')[-1]) if not ok: diff --git a/mypy/semanal_infer.py b/mypy/semanal_infer.py index 25244169b2c4..73a1077c5788 100644 --- a/mypy/semanal_infer.py +++ b/mypy/semanal_infer.py @@ -30,7 +30,7 @@ def infer_decorator_signature_if_simple(dec: Decorator, [ARG_POS], [None], AnyType(TypeOfAny.special_form), - analyzer.named_type('__builtins__.function'), + analyzer.named_type('builtins.function'), name=dec.var.name) elif isinstance(dec.func.type, CallableType): dec.var.type = dec.func.type @@ -47,7 +47,7 @@ def infer_decorator_signature_if_simple(dec: Decorator, if decorator_preserves_type: # No non-identity decorators left. We can trivially infer the type # of the function here. - dec.var.type = function_type(dec.func, analyzer.named_type('__builtins__.function')) + dec.var.type = function_type(dec.func, analyzer.named_type('builtins.function')) if dec.decorators: return_type = calculate_return_type(dec.decorators[0]) if return_type and isinstance(return_type, AnyType): @@ -58,7 +58,7 @@ def infer_decorator_signature_if_simple(dec: Decorator, if sig: # The outermost decorator always returns the same kind of function, # so we know that this is the type of the decorated function. - orig_sig = function_type(dec.func, analyzer.named_type('__builtins__.function')) + orig_sig = function_type(dec.func, analyzer.named_type('builtins.function')) sig.name = orig_sig.items[0].name dec.var.type = sig diff --git a/mypy/semanal_main.py b/mypy/semanal_main.py index 3e7a27f80a2f..7e187945da48 100644 --- a/mypy/semanal_main.py +++ b/mypy/semanal_main.py @@ -24,10 +24,10 @@ will be incomplete. """ -import contextlib -from typing import List, Tuple, Optional, Union, Callable, Iterator -from typing_extensions import TYPE_CHECKING +from typing import List, Tuple, Optional, Union, Callable +from typing_extensions import TYPE_CHECKING, Final, TypeAlias as _TypeAlias +from mypy.backports import nullcontext from mypy.nodes import ( MypyFile, TypeInfo, FuncDef, Decorator, OverloadedFuncDef, Var ) @@ -51,16 +51,16 @@ from mypy.build import Graph, State -Patches = List[Tuple[int, Callable[[], None]]] +Patches: _TypeAlias = List[Tuple[int, Callable[[], None]]] # If we perform this many iterations, raise an exception since we are likely stuck. -MAX_ITERATIONS = 20 +MAX_ITERATIONS: Final = 20 # Number of passes over core modules before going on to the rest of the builtin SCC. -CORE_WARMUP = 2 -core_modules = ['typing', 'builtins', 'abc', 'collections'] +CORE_WARMUP: Final = 2 +core_modules: Final = ['typing', 'builtins', 'abc', 'collections'] def semantic_analysis_for_scc(graph: 'Graph', scc: List[str], errors: Errors) -> None: @@ -249,7 +249,7 @@ def process_top_level_function(analyzer: 'SemanticAnalyzer', """Analyze single top-level function or method. Process the body of the function (including nested functions) again and again, - until all names have been resolved (ot iteration limit reached). + until all names have been resolved (or iteration limit reached). """ # We need one more iteration after incomplete is False (e.g. to report errors, if any). final_iteration = False @@ -377,7 +377,7 @@ def check_type_arguments_in_targets(targets: List[FineGrainedDeferredNode], stat if isinstance(target.node, (FuncDef, OverloadedFuncDef)): func = target.node saved = (state.id, target.active_typeinfo, func) # module, class, function - with errors.scope.saved_scope(saved) if errors.scope else nothing(): + with errors.scope.saved_scope(saved) if errors.scope else nullcontext(): analyzer.recurse_into_functions = func is not None target.node.accept(analyzer) @@ -389,7 +389,7 @@ def calculate_class_properties(graph: 'Graph', scc: List[str], errors: Errors) - for _, node, _ in tree.local_definitions(): if isinstance(node.node, TypeInfo): saved = (module, node.node, None) # module, class, function - with errors.scope.saved_scope(saved) if errors.scope else nothing(): + with errors.scope.saved_scope(saved) if errors.scope else nullcontext(): calculate_class_abstract_status(node.node, tree.is_stub, errors) check_protocol_status(node.node, errors) calculate_class_vars(node.node) @@ -399,8 +399,3 @@ def calculate_class_properties(graph: 'Graph', scc: List[str], errors: Errors) - def check_blockers(graph: 'Graph', scc: List[str]) -> None: for module in scc: graph[module].check_blockers() - - -@contextlib.contextmanager -def nothing() -> Iterator[None]: - yield diff --git a/mypy/semanal_namedtuple.py b/mypy/semanal_namedtuple.py index 968a7d502ebe..8930c63d2bef 100644 --- a/mypy/semanal_namedtuple.py +++ b/mypy/semanal_namedtuple.py @@ -262,16 +262,17 @@ def parse_namedtuple_args(self, call: CallExpr, fullname: str Return None if the definition didn't typecheck. """ + type_name = 'NamedTuple' if fullname == 'typing.NamedTuple' else 'namedtuple' # TODO: Share code with check_argument_count in checkexpr.py? args = call.args if len(args) < 2: - self.fail("Too few arguments for namedtuple()", call) + self.fail('Too few arguments for "{}()"'.format(type_name), call) return None defaults: List[Expression] = [] if len(args) > 2: # Typed namedtuple doesn't support additional arguments. if fullname == 'typing.NamedTuple': - self.fail("Too many arguments for NamedTuple()", call) + self.fail('Too many arguments for "NamedTuple()"', call) return None for i, arg_name in enumerate(call.arg_names[2:], 2): if arg_name == 'defaults': @@ -283,16 +284,16 @@ def parse_namedtuple_args(self, call: CallExpr, fullname: str else: self.fail( "List or tuple literal expected as the defaults argument to " - "namedtuple()", + "{}()".format(type_name), arg ) break if call.arg_kinds[:2] != [ARG_POS, ARG_POS]: - self.fail("Unexpected arguments to namedtuple()", call) + self.fail('Unexpected arguments to "{}()"'.format(type_name), call) return None if not isinstance(args[0], (StrExpr, BytesExpr, UnicodeExpr)): self.fail( - "namedtuple() expects a string literal as the first argument", call) + '"{}()" expects a string literal as the first argument'.format(type_name), call) return None typename = cast(Union[StrExpr, BytesExpr, UnicodeExpr], call.args[0]).value types: List[Type] = [] @@ -303,7 +304,11 @@ def parse_namedtuple_args(self, call: CallExpr, fullname: str items = str_expr.value.replace(',', ' ').split() else: self.fail( - "List or tuple literal expected as the second argument to namedtuple()", call) + 'List or tuple literal expected as the second argument to "{}()"'.format( + type_name, + ), + call, + ) return None else: listexpr = args[1] @@ -311,7 +316,7 @@ def parse_namedtuple_args(self, call: CallExpr, fullname: str # The fields argument contains just names, with implicit Any types. if any(not isinstance(item, (StrExpr, BytesExpr, UnicodeExpr)) for item in listexpr.items): - self.fail("String literal expected as namedtuple() item", call) + self.fail('String literal expected as "namedtuple()" item', call) return None items = [cast(Union[StrExpr, BytesExpr, UnicodeExpr], item).value for item in listexpr.items] @@ -328,10 +333,10 @@ def parse_namedtuple_args(self, call: CallExpr, fullname: str types = [AnyType(TypeOfAny.unannotated) for _ in items] underscore = [item for item in items if item.startswith('_')] if underscore: - self.fail("namedtuple() field names cannot start with an underscore: " + self.fail('"{}()" field names cannot start with an underscore: '.format(type_name) + ', '.join(underscore), call) if len(defaults) > len(items): - self.fail("Too many defaults given in call to namedtuple()", call) + self.fail('Too many defaults given in call to "{}()"'.format(type_name), call) defaults = defaults[:len(items)] return items, types, defaults, typename, True @@ -347,13 +352,13 @@ def parse_namedtuple_fields_with_types(self, nodes: List[Expression], context: C for item in nodes: if isinstance(item, TupleExpr): if len(item.items) != 2: - self.fail("Invalid NamedTuple field definition", item) + self.fail('Invalid "NamedTuple()" field definition', item) return None name, type_node = item.items if isinstance(name, (StrExpr, BytesExpr, UnicodeExpr)): items.append(name.value) else: - self.fail("Invalid NamedTuple() field name", item) + self.fail('Invalid "NamedTuple()" field name', item) return None try: type = expr_to_unanalyzed_type(type_node, self.options, self.api.is_stub_file) @@ -369,7 +374,7 @@ def parse_namedtuple_fields_with_types(self, nodes: List[Expression], context: C return [], [], [], False types.append(analyzed) else: - self.fail("Tuple expected as NamedTuple() field", item) + self.fail('Tuple expected as "NamedTuple()" field', item) return None return items, types, [], True @@ -379,19 +384,19 @@ def build_namedtuple_typeinfo(self, types: List[Type], default_items: Mapping[str, Expression], line: int) -> TypeInfo: - strtype = self.api.named_type('__builtins__.str') + strtype = self.api.named_type('builtins.str') implicit_any = AnyType(TypeOfAny.special_form) - basetuple_type = self.api.named_type('__builtins__.tuple', [implicit_any]) + basetuple_type = self.api.named_type('builtins.tuple', [implicit_any]) dictype = (self.api.named_type_or_none('builtins.dict', [strtype, implicit_any]) - or self.api.named_type('__builtins__.object')) + or self.api.named_type('builtins.object')) # Actual signature should return OrderedDict[str, Union[types]] ordereddictype = (self.api.named_type_or_none('builtins.dict', [strtype, implicit_any]) - or self.api.named_type('__builtins__.object')) - fallback = self.api.named_type('__builtins__.tuple', [implicit_any]) + or self.api.named_type('builtins.object')) + fallback = self.api.named_type('builtins.tuple', [implicit_any]) # Note: actual signature should accept an invariant version of Iterable[UnionType[types]]. # but it can't be expressed. 'new' and 'len' should be callable types. iterable_type = self.api.named_type_or_none('typing.Iterable', [implicit_any]) - function_type = self.api.named_type('__builtins__.function') + function_type = self.api.named_type('builtins.function') info = self.api.basic_new_typeinfo(name, fallback, line) info.is_named_tuple = True diff --git a/mypy/semanal_newtype.py b/mypy/semanal_newtype.py index 4d5077dbfe43..047df3d85b83 100644 --- a/mypy/semanal_newtype.py +++ b/mypy/semanal_newtype.py @@ -84,7 +84,7 @@ def process_newtype_declaration(self, s: AssignmentStmt) -> bool: self.fail(message.format(format_type(old_type)), s, code=codes.VALID_NEWTYPE) # Otherwise the error was already reported. old_type = AnyType(TypeOfAny.from_error) - object_type = self.api.named_type('__builtins__.object') + object_type = self.api.named_type('builtins.object') newtype_class_info = self.build_newtype_typeinfo(name, old_type, object_type, s.line) newtype_class_info.fallback_to_any = True @@ -194,7 +194,7 @@ def build_newtype_typeinfo(self, name: str, old_type: Type, base_type: Instance, arg_kinds=[arg.kind for arg in args], arg_names=['self', 'item'], ret_type=NoneType(), - fallback=self.api.named_type('__builtins__.function'), + fallback=self.api.named_type('builtins.function'), name=name) init_func = FuncDef('__init__', args, Block([]), typ=signature) init_func.info = info diff --git a/mypy/semanal_shared.py b/mypy/semanal_shared.py index 6b0fe1251693..3638d0878d8f 100644 --- a/mypy/semanal_shared.py +++ b/mypy/semanal_shared.py @@ -101,11 +101,12 @@ def lookup(self, name: str, ctx: Context, raise NotImplementedError @abstractmethod - def named_type(self, qualified_name: str, args: Optional[List[Type]] = None) -> Instance: + def named_type(self, fullname: str, + args: Optional[List[Type]] = None) -> Instance: raise NotImplementedError @abstractmethod - def named_type_or_none(self, qualified_name: str, + def named_type_or_none(self, fullname: str, args: Optional[List[Type]] = None) -> Optional[Instance]: raise NotImplementedError @@ -118,6 +119,7 @@ def anal_type(self, t: Type, *, tvar_scope: Optional[TypeVarLikeScope] = None, allow_tuple_literal: bool = False, allow_unbound_tvars: bool = False, + allow_required: bool = False, report_invalid_types: bool = True) -> Optional[Type]: raise NotImplementedError diff --git a/mypy/semanal_typeargs.py b/mypy/semanal_typeargs.py index 58edeef98407..50e01145d60a 100644 --- a/mypy/semanal_typeargs.py +++ b/mypy/semanal_typeargs.py @@ -9,7 +9,8 @@ from mypy.nodes import TypeInfo, Context, MypyFile, FuncItem, ClassDef, Block, FakeInfo from mypy.types import ( - Type, Instance, TypeVarType, AnyType, get_proper_types, TypeAliasType, get_proper_type + Type, Instance, TypeVarType, AnyType, get_proper_types, TypeAliasType, ParamSpecType, + get_proper_type ) from mypy.mixedtraverser import MixedTraverserVisitor from mypy.subtypes import is_subtype @@ -19,6 +20,7 @@ from mypy.options import Options from mypy.errorcodes import ErrorCode from mypy import message_registry, errorcodes as codes +from mypy.messages import format_type class TypeArgumentAnalyzer(MixedTraverserVisitor): @@ -69,21 +71,28 @@ def visit_instance(self, t: Instance) -> None: if isinstance(info, FakeInfo): return # https://github.com/python/mypy/issues/11079 for (i, arg), tvar in zip(enumerate(t.args), info.defn.type_vars): - if tvar.values: - if isinstance(arg, TypeVarType): - arg_values = arg.values - if not arg_values: - self.fail('Type variable "{}" not valid as type ' - 'argument value for "{}"'.format( - arg.name, info.name), t, code=codes.TYPE_VAR) - continue - else: - arg_values = [arg] - self.check_type_var_values(info, arg_values, tvar.name, tvar.values, i + 1, t) - if not is_subtype(arg, tvar.upper_bound): - self.fail('Type argument "{}" of "{}" must be ' - 'a subtype of "{}"'.format( - arg, info.name, tvar.upper_bound), t, code=codes.TYPE_VAR) + if isinstance(tvar, TypeVarType): + if isinstance(arg, ParamSpecType): + # TODO: Better message + self.fail(f'Invalid location for ParamSpec "{arg.name}"', t) + continue + if tvar.values: + if isinstance(arg, TypeVarType): + arg_values = arg.values + if not arg_values: + self.fail( + message_registry.INVALID_TYPEVAR_AS_TYPEARG.format( + arg.name, info.name), + t, code=codes.TYPE_VAR) + continue + else: + arg_values = [arg] + self.check_type_var_values(info, arg_values, tvar.name, tvar.values, i + 1, t) + if not is_subtype(arg, tvar.upper_bound): + self.fail( + message_registry.INVALID_TYPEVAR_ARG_BOUND.format( + format_type(arg), info.name, format_type(tvar.upper_bound)), + t, code=codes.TYPE_VAR) super().visit_instance(t) def check_type_var_values(self, type: TypeInfo, actuals: List[Type], arg_name: str, @@ -93,8 +102,9 @@ def check_type_var_values(self, type: TypeInfo, actuals: List[Type], arg_name: s not any(is_same_type(actual, value) for value in valids)): if len(actuals) > 1 or not isinstance(actual, Instance): - self.fail('Invalid type argument value for "{}"'.format( - type.name), context, code=codes.TYPE_VAR) + self.fail( + message_registry.INVALID_TYPEVAR_ARG_VALUE.format(type.name), + context, code=codes.TYPE_VAR) else: class_name = '"{}"'.format(type.name) actual_type_name = '"{}"'.format(actual.type.name) diff --git a/mypy/semanal_typeddict.py b/mypy/semanal_typeddict.py index f70bbe427124..ffc6a7df3931 100644 --- a/mypy/semanal_typeddict.py +++ b/mypy/semanal_typeddict.py @@ -4,7 +4,9 @@ from typing import Optional, List, Set, Tuple from typing_extensions import Final -from mypy.types import Type, AnyType, TypeOfAny, TypedDictType, TPDICT_NAMES +from mypy.types import ( + Type, AnyType, TypeOfAny, TypedDictType, TPDICT_NAMES, RequiredType, +) from mypy.nodes import ( CallExpr, TypedDictExpr, Expression, NameExpr, Context, StrExpr, BytesExpr, UnicodeExpr, ClassDef, RefExpr, TypeInfo, AssignmentStmt, PassStmt, ExpressionStmt, EllipsisExpr, TempNode, @@ -67,16 +69,30 @@ def analyze_typeddict_classdef(self, defn: ClassDef) -> Tuple[bool, Optional[Typ defn.analyzed.line = defn.line defn.analyzed.column = defn.column return True, info + # Extending/merging existing TypedDicts - if any(not isinstance(expr, RefExpr) or - expr.fullname not in TPDICT_NAMES and - not self.is_typeddict(expr) for expr in defn.base_type_exprs): - self.fail("All bases of a new TypedDict must be TypedDict types", defn) - typeddict_bases = list(filter(self.is_typeddict, defn.base_type_exprs)) + typeddict_bases = [] + typeddict_bases_set = set() + for expr in defn.base_type_exprs: + if isinstance(expr, RefExpr) and expr.fullname in TPDICT_NAMES: + if 'TypedDict' not in typeddict_bases_set: + typeddict_bases_set.add('TypedDict') + else: + self.fail('Duplicate base class "TypedDict"', defn) + elif isinstance(expr, RefExpr) and self.is_typeddict(expr): + assert expr.fullname + if expr.fullname not in typeddict_bases_set: + typeddict_bases_set.add(expr.fullname) + typeddict_bases.append(expr) + else: + assert isinstance(expr.node, TypeInfo) + self.fail('Duplicate base class "%s"' % expr.node.name, defn) + else: + self.fail("All bases of a new TypedDict must be TypedDict types", defn) + keys: List[str] = [] types = [] required_keys = set() - # Iterate over bases in reverse order so that leftmost base class' keys take precedence for base in reversed(typeddict_bases): assert isinstance(base, RefExpr) @@ -147,7 +163,7 @@ def analyze_typeddict_classdef_fields( if stmt.type is None: types.append(AnyType(TypeOfAny.unannotated)) else: - analyzed = self.api.anal_type(stmt.type) + analyzed = self.api.anal_type(stmt.type, allow_required=True) if analyzed is None: return None, [], set() # Need to defer types.append(analyzed) @@ -163,7 +179,22 @@ def analyze_typeddict_classdef_fields( if total is None: self.fail('Value of "total" must be True or False', defn) total = True - required_keys = set(fields) if total else set() + required_keys = { + field + for (field, t) in zip(fields, types) + if (total or ( + isinstance(t, RequiredType) and # type: ignore[misc] + t.required + )) and not ( + isinstance(t, RequiredType) and # type: ignore[misc] + not t.required + ) + } + types = [ # unwrap Required[T] to just T + t.item if isinstance(t, RequiredType) else t # type: ignore[misc] + for t in types + ] + return fields, types, required_keys def check_typeddict(self, @@ -207,7 +238,21 @@ def check_typeddict(self, if name != var_name or is_func_scope: # Give it a unique name derived from the line number. name += '@' + str(call.line) - required_keys = set(items) if total else set() + required_keys = { + field + for (field, t) in zip(items, types) + if (total or ( + isinstance(t, RequiredType) and # type: ignore[misc] + t.required + )) and not ( + isinstance(t, RequiredType) and # type: ignore[misc] + not t.required + ) + } + types = [ # unwrap Required[T] to just T + t.item if isinstance(t, RequiredType) else t # type: ignore[misc] + for t in types + ] info = self.build_typeddict_typeinfo(name, items, types, required_keys, call.line) info.line = node.line # Store generated TypeInfo under both names, see semanal_namedtuple for more details. @@ -293,9 +338,16 @@ def parse_typeddict_fields_with_types( type = expr_to_unanalyzed_type(field_type_expr, self.options, self.api.is_stub_file) except TypeTranslationError: - self.fail_typeddict_arg('Invalid field type', field_type_expr) + if (isinstance(field_type_expr, CallExpr) and + isinstance(field_type_expr.callee, RefExpr) and + field_type_expr.callee.fullname in TPDICT_NAMES): + self.fail_typeddict_arg( + 'Inline TypedDict types not supported; use assignment to define TypedDict', + field_type_expr) + else: + self.fail_typeddict_arg('Invalid field type', field_type_expr) return [], [], False - analyzed = self.api.anal_type(type) + analyzed = self.api.anal_type(type, allow_required=True) if analyzed is None: return None types.append(analyzed) @@ -328,3 +380,6 @@ def is_typeddict(self, expr: Expression) -> bool: def fail(self, msg: str, ctx: Context, *, code: Optional[ErrorCode] = None) -> None: self.api.fail(msg, ctx, code=code) + + def note(self, msg: str, ctx: Context) -> None: + self.api.note(msg, ctx) diff --git a/mypy/server/astdiff.py b/mypy/server/astdiff.py index 789c7c909911..12add8efcb3a 100644 --- a/mypy/server/astdiff.py +++ b/mypy/server/astdiff.py @@ -54,12 +54,12 @@ class level -- these are handled at attribute level (say, 'mod.Cls.method' from mypy.nodes import ( SymbolTable, TypeInfo, Var, SymbolNode, Decorator, TypeVarExpr, TypeAlias, - FuncBase, OverloadedFuncDef, FuncItem, MypyFile, UNBOUND_IMPORTED + FuncBase, OverloadedFuncDef, FuncItem, MypyFile, ParamSpecExpr, UNBOUND_IMPORTED ) from mypy.types import ( Type, TypeVisitor, UnboundType, AnyType, NoneType, UninhabitedType, ErasedType, DeletedType, Instance, TypeVarType, CallableType, TupleType, TypedDictType, - UnionType, Overloaded, PartialType, TypeType, LiteralType, TypeAliasType + UnionType, Overloaded, PartialType, TypeType, LiteralType, TypeAliasType, ParamSpecType ) from mypy.util import get_prefix @@ -151,6 +151,10 @@ def snapshot_symbol_table(name_prefix: str, table: SymbolTable) -> Dict[str, Sna node.normalized, node.no_args, snapshot_optional_type(node.target)) + elif isinstance(node, ParamSpecExpr): + result[name] = ('ParamSpec', + node.variance, + snapshot_type(node.upper_bound)) else: assert symbol.kind != UNBOUND_IMPORTED if node and get_prefix(node.fullname) != name_prefix: @@ -306,6 +310,13 @@ def visit_type_var(self, typ: TypeVarType) -> SnapshotItem: snapshot_type(typ.upper_bound), typ.variance) + def visit_param_spec(self, typ: ParamSpecType) -> SnapshotItem: + return ('ParamSpec', + typ.id.raw_id, + typ.id.meta_level, + typ.flavor, + snapshot_type(typ.upper_bound)) + def visit_callable_type(self, typ: CallableType) -> SnapshotItem: # FIX generics return ('CallableType', diff --git a/mypy/server/astmerge.py b/mypy/server/astmerge.py index 5d6a810264b6..8db2b302b844 100644 --- a/mypy/server/astmerge.py +++ b/mypy/server/astmerge.py @@ -57,9 +57,9 @@ from mypy.traverser import TraverserVisitor from mypy.types import ( Type, SyntheticTypeVisitor, Instance, AnyType, NoneType, CallableType, ErasedType, DeletedType, - TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType, + TupleType, TypeType, TypedDictType, UnboundType, UninhabitedType, UnionType, Overloaded, TypeVarType, TypeList, CallableArgument, EllipsisType, StarType, LiteralType, - RawExpressionType, PartialType, PlaceholderType, TypeAliasType + RawExpressionType, PartialType, PlaceholderType, TypeAliasType, ParamSpecType ) from mypy.util import get_prefix, replace_object_state from mypy.typestate import TypeState @@ -173,7 +173,8 @@ def visit_class_def(self, node: ClassDef) -> None: node.defs.body = self.replace_statements(node.defs.body) info = node.info for tv in node.type_vars: - self.process_type_var_def(tv) + if isinstance(tv, TypeVarType): + self.process_type_var_def(tv) if info: if info.is_named_tuple: self.process_synthetic_type_info(info) @@ -407,6 +408,9 @@ def visit_type_var(self, typ: TypeVarType) -> None: for value in typ.values: value.accept(self) + def visit_param_spec(self, typ: ParamSpecType) -> None: + pass + def visit_typeddict_type(self, typ: TypedDictType) -> None: for value_type in typ.items.values(): value_type.accept(self) diff --git a/mypy/server/aststrip.py b/mypy/server/aststrip.py index 3af7efe7e142..4363223c1cf0 100644 --- a/mypy/server/aststrip.py +++ b/mypy/server/aststrip.py @@ -34,6 +34,7 @@ import contextlib from typing import Union, Iterator, Optional, Dict, Tuple +from mypy.backports import nullcontext from mypy.nodes import ( FuncDef, NameExpr, MemberExpr, RefExpr, MypyFile, ClassDef, AssignmentStmt, ImportFrom, CallExpr, Decorator, OverloadedFuncDef, Node, TupleExpr, ListExpr, @@ -138,7 +139,7 @@ def visit_func_def(self, node: FuncDef) -> None: # See also #4814. assert isinstance(node.type, CallableType) node.type.variables = [] - with self.enter_method(node.info) if node.info else nothing(): + with self.enter_method(node.info) if node.info else nullcontext(): super().visit_func_def(node) def visit_decorator(self, node: Decorator) -> None: @@ -247,8 +248,3 @@ def enter_method(self, info: TypeInfo) -> Iterator[None]: yield self.type = old_type self.is_class_body = old_is_class_body - - -@contextlib.contextmanager -def nothing() -> Iterator[None]: - yield diff --git a/mypy/server/deps.py b/mypy/server/deps.py index f80673fdb7d4..cee12c9f8aab 100644 --- a/mypy/server/deps.py +++ b/mypy/server/deps.py @@ -99,7 +99,7 @@ class 'mod.Cls'. This can also refer to an attribute inherited from a Type, Instance, AnyType, NoneType, TypeVisitor, CallableType, DeletedType, PartialType, TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType, FunctionLike, Overloaded, TypeOfAny, LiteralType, ErasedType, get_proper_type, ProperType, - TypeAliasType + TypeAliasType, ParamSpecType ) from mypy.server.trigger import make_trigger, make_wildcard_trigger from mypy.util import correct_relative_import @@ -481,8 +481,11 @@ def get_non_partial_lvalue_type(self, lvalue: RefExpr) -> Type: return UninhabitedType() lvalue_type = get_proper_type(self.type_map[lvalue]) if isinstance(lvalue_type, PartialType): - if isinstance(lvalue.node, Var) and lvalue.node.type: - lvalue_type = get_proper_type(lvalue.node.type) + if isinstance(lvalue.node, Var): + if lvalue.node.type: + lvalue_type = get_proper_type(lvalue.node.type) + else: + lvalue_type = UninhabitedType() else: # Probably a secondary, non-definition assignment that doesn't # result in a non-partial type. We won't be able to infer any @@ -951,6 +954,13 @@ def visit_type_var(self, typ: TypeVarType) -> List[str]: triggers.extend(self.get_type_triggers(val)) return triggers + def visit_param_spec(self, typ: ParamSpecType) -> List[str]: + triggers = [] + if typ.fullname: + triggers.append(make_trigger(typ.fullname)) + triggers.extend(self.get_type_triggers(typ.upper_bound)) + return triggers + def visit_typeddict_type(self, typ: TypedDictType) -> List[str]: triggers = [] for item in typ.items.values(): diff --git a/mypy/server/update.py b/mypy/server/update.py index 03d79b8af7fb..e82064c63a11 100644 --- a/mypy/server/update.py +++ b/mypy/server/update.py @@ -1077,7 +1077,7 @@ def not_found() -> None: # A ClassDef target covers the body of the class and everything defined # within it. To get the body we include the entire surrounding target, # typically a module top-level, since we don't support processing class - # bodies as separate entitites for simplicity. + # bodies as separate entities for simplicity. assert file is not None if node.fullname != target: # This is a reference to a different TypeInfo, likely due to a stale dependency. diff --git a/mypy/sharedparse.py b/mypy/sharedparse.py index 7dbaffcbee97..d8bde1bd253b 100644 --- a/mypy/sharedparse.py +++ b/mypy/sharedparse.py @@ -44,6 +44,7 @@ "__init_subclass__", "__new__", "__call__", + "__setattr__", } BINARY_MAGIC_METHODS: Final = { diff --git a/mypy/stubgen.py b/mypy/stubgen.py index 49527fac70d9..b0a2c4e64587 100755 --- a/mypy/stubgen.py +++ b/mypy/stubgen.py @@ -255,7 +255,7 @@ def visit_unbound_type(self, t: UnboundType) -> str: s = t.name self.stubgen.import_tracker.require_name(s) if t.args: - s += '[{}]'.format(self.list_str(t.args)) + s += '[{}]'.format(self.args_str(t.args)) return s def visit_none_type(self, t: NoneType) -> str: @@ -264,6 +264,22 @@ def visit_none_type(self, t: NoneType) -> str: def visit_type_list(self, t: TypeList) -> str: return '[{}]'.format(self.list_str(t.items)) + def args_str(self, args: Iterable[Type]) -> str: + """Convert an array of arguments to strings and join the results with commas. + + The main difference from list_str is the preservation of quotes for string + arguments + """ + types = ['builtins.bytes', 'builtins.unicode'] + res = [] + for arg in args: + arg_str = arg.accept(self) + if isinstance(arg, UnboundType) and arg.original_str_fallback in types: + res.append("'{}'".format(arg_str)) + else: + res.append(arg_str) + return ', '.join(res) + class AliasPrinter(NodeVisitor[str]): """Visitor used to collect type aliases _and_ type variable definitions. @@ -1061,7 +1077,7 @@ def visit_import_from(self, o: ImportFrom) -> None: self.record_name(alias or name) if self._all_: - # Include import froms that import names defined in __all__. + # Include "import from"s that import names defined in __all__. names = [name for name, alias in o.names if name in self._all_ and alias is None and name not in IGNORED_DUNDERS] exported_names.update(names) @@ -1645,7 +1661,7 @@ def parse_options(args: List[str]) -> Options: ns = parser.parse_args(args) - pyversion = defaults.PYTHON2_VERSION if ns.py2 else defaults.PYTHON3_VERSION + pyversion = defaults.PYTHON2_VERSION if ns.py2 else sys.version_info[:2] if not ns.interpreter: ns.interpreter = sys.executable if pyversion[0] == 3 else default_py2_interpreter() if ns.modules + ns.packages and ns.files: diff --git a/mypy/stubgenc.py b/mypy/stubgenc.py index 39b4ac13ec0b..0eeb39f102dc 100755 --- a/mypy/stubgenc.py +++ b/mypy/stubgenc.py @@ -10,6 +10,7 @@ import re from typing import List, Dict, Tuple, Optional, Mapping, Any, Set from types import ModuleType +from typing_extensions import Final from mypy.moduleinspect import is_c_module from mypy.stubdoc import ( @@ -19,7 +20,7 @@ ) # Members of the typing module to consider for importing by default. -_DEFAULT_TYPING_IMPORTS = ( +_DEFAULT_TYPING_IMPORTS: Final = ( 'Any', 'Callable', 'ClassVar', diff --git a/mypy/stubtest.py b/mypy/stubtest.py index 138f126c9d1a..7228afaed446 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -200,23 +200,34 @@ def verify_mypyfile( yield Error(object_path, "is not a module", stub, runtime) return - # Check things in the stub that are public + # Check things in the stub to_check = set( m for m, o in stub.names.items() - # TODO: change `o.module_public` to `not o.module_hidden` - if o.module_public and (not m.startswith("_") or hasattr(runtime, m)) + if not o.module_hidden and (not m.startswith("_") or hasattr(runtime, m)) ) - runtime_public_contents = [ - m - for m in dir(runtime) - if not m.startswith("_") - # Ensure that the object's module is `runtime`, since in the absence of __all__ we don't - # have a good way to detect re-exports at runtime. - and getattr(getattr(runtime, m), "__module__", None) == runtime.__name__ - ] - # Check all things declared in module's __all__, falling back to runtime_public_contents - to_check.update(getattr(runtime, "__all__", runtime_public_contents)) + + def _belongs_to_runtime(r: types.ModuleType, attr: str) -> bool: + obj = getattr(r, attr) + obj_mod = getattr(obj, "__module__", None) + if obj_mod is not None: + return obj_mod == r.__name__ + return not isinstance(obj, types.ModuleType) + + runtime_public_contents = ( + runtime.__all__ + if hasattr(runtime, "__all__") + else [ + m + for m in dir(runtime) + if not m.startswith("_") + # Ensure that the object's module is `runtime`, since in the absence of __all__ we + # don't have a good way to detect re-exports at runtime. + and _belongs_to_runtime(runtime, m) + ] + ) + # Check all things declared in module's __all__, falling back to our best guess + to_check.update(runtime_public_contents) to_check.difference_update({"__file__", "__doc__", "__name__", "__builtins__", "__package__"}) for entry in sorted(to_check): @@ -1229,7 +1240,11 @@ def parse_options(args: List[str]) -> argparse.Namespace: description="Compares stubs to objects introspected from the runtime." ) parser.add_argument("modules", nargs="*", help="Modules to test") - parser.add_argument("--concise", action="store_true", help="Make output concise") + parser.add_argument( + "--concise", + action="store_true", + help="Makes stubtest's output more concise, one line per error", + ) parser.add_argument( "--ignore-missing-stub", action="store_true", @@ -1240,12 +1255,6 @@ def parse_options(args: List[str]) -> argparse.Namespace: action="store_true", help="Ignore errors for whether an argument should or shouldn't be positional-only", ) - parser.add_argument( - "--custom-typeshed-dir", metavar="DIR", help="Use the custom typeshed in DIR" - ) - parser.add_argument( - "--check-typeshed", action="store_true", help="Check all stdlib modules in typeshed" - ) parser.add_argument( "--allowlist", "--whitelist", @@ -1254,7 +1263,8 @@ def parse_options(args: List[str]) -> argparse.Namespace: default=[], help=( "Use file as an allowlist. Can be passed multiple times to combine multiple " - "allowlists. Allowlists can be created with --generate-allowlist" + "allowlists. Allowlists can be created with --generate-allowlist. Allowlists " + "support regular expressions." ), ) parser.add_argument( @@ -1269,19 +1279,20 @@ def parse_options(args: List[str]) -> argparse.Namespace: action="store_true", help="Ignore unused allowlist entries", ) - config_group = parser.add_argument_group( - title='mypy config file', - description="Use a config file instead of command line arguments. " - "Plugins and mypy path are the only supported " - "configurations.", - ) - config_group.add_argument( - '--mypy-config-file', + parser.add_argument( + "--mypy-config-file", + metavar="FILE", help=( - "An existing mypy configuration file, currently used by stubtest to help " - "determine mypy path and plugins" + "Use specified mypy config file to determine mypy plugins " + "and mypy path" ), ) + parser.add_argument( + "--custom-typeshed-dir", metavar="DIR", help="Use the custom typeshed in DIR" + ) + parser.add_argument( + "--check-typeshed", action="store_true", help="Check all stdlib modules in typeshed" + ) return parser.parse_args(args) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 63cebc8aa483..f90009445b09 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -1,13 +1,13 @@ from contextlib import contextmanager from typing import Any, List, Optional, Callable, Tuple, Iterator, Set, Union, cast, TypeVar -from typing_extensions import Final +from typing_extensions import Final, TypeAlias as _TypeAlias from mypy.types import ( Type, AnyType, UnboundType, TypeVisitor, FormalArgument, NoneType, Instance, TypeVarType, CallableType, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, is_named_instance, - FunctionLike, TypeOfAny, LiteralType, get_proper_type, TypeAliasType + FunctionLike, TypeOfAny, LiteralType, get_proper_type, TypeAliasType, ParamSpecType ) import mypy.applytype import mypy.constraints @@ -30,7 +30,7 @@ IS_CLASSVAR: Final = 2 IS_CLASS_OR_STATIC: Final = 3 -TypeParameterChecker = Callable[[Type, Type, int], bool] +TypeParameterChecker: _TypeAlias = Callable[[Type, Type, int], bool] def check_type_parameter(lefta: Type, righta: Type, variance: int) -> bool: @@ -125,7 +125,10 @@ def _is_subtype(left: Type, right: Type, # of a union of all enum items as literal types. Only do it if # the previous check didn't succeed, since recombining can be # expensive. - if not is_subtype_of_item and isinstance(left, Instance) and left.type.is_enum: + # `bool` is a special case, because `bool` is `Literal[True, False]`. + if (not is_subtype_of_item + and isinstance(left, Instance) + and (left.type.is_enum or left.type.fullname == 'builtins.bool')): right = UnionType(mypy.typeops.try_contracting_literals_in_union(right.items)) is_subtype_of_item = any(is_subtype(orig_left, item, ignore_type_params=ignore_type_params, @@ -263,13 +266,23 @@ def visit_instance(self, left: Instance) -> bool: rname = right.type.fullname # Always try a nominal check if possible, # there might be errors that a user wants to silence *once*. - if ((left.type.has_base(rname) or rname == 'builtins.object') and - not self.ignore_declared_variance): + # NamedTuples are a special case, because `NamedTuple` is not listed + # in `TypeInfo.mro`, so when `(a: NamedTuple) -> None` is used, + # we need to check for `is_named_tuple` property + if ((left.type.has_base(rname) or rname == 'builtins.object' + or (rname == 'typing.NamedTuple' + and any(l.is_named_tuple for l in left.type.mro))) + and not self.ignore_declared_variance): # Map left type to corresponding right instances. t = map_instance_to_supertype(left, right.type) - nominal = all(self.check_type_parameter(lefta, righta, tvar.variance) - for lefta, righta, tvar in - zip(t.args, right.args, right.type.defn.type_vars)) + nominal = True + for lefta, righta, tvar in zip(t.args, right.args, right.type.defn.type_vars): + if isinstance(tvar, TypeVarType): + if not self.check_type_parameter(lefta, righta, tvar.variance): + nominal = False + else: + if not is_equivalent(lefta, righta): + nominal = False if nominal: TypeState.record_subtype_cache_entry(self._subtype_kind, left, right) return nominal @@ -287,6 +300,8 @@ def visit_instance(self, left: Instance) -> bool: return True if isinstance(item, Instance): 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. call = find_member('__call__', left, left, is_operator=True) @@ -305,9 +320,26 @@ def visit_type_var(self, left: TypeVarType) -> bool: return True return self._is_subtype(left.upper_bound, self.right) + def visit_param_spec(self, left: ParamSpecType) -> bool: + right = self.right + if ( + isinstance(right, ParamSpecType) + and right.id == left.id + and right.flavor == left.flavor + ): + return True + return self._is_subtype(left.upper_bound, self.right) + def visit_callable_type(self, left: CallableType) -> bool: right = self.right if isinstance(right, CallableType): + if left.type_guard is not None and right.type_guard is not None: + if not self._is_subtype(left.type_guard, right.type_guard): + return False + elif right.type_guard is not None and left.type_guard is None: + # This means that one function has `TypeGuard` and other does not. + # They are not compatible. See https://github.com/python/mypy/issues/11307 + return False return is_callable_compatible( left, right, is_compat=self._is_subtype, @@ -621,6 +653,8 @@ def find_member(name: str, info = itype.type method = info.get_method(name) if method: + if isinstance(method, Decorator): + return find_node_type(method.var, itype, subtype) if method.is_property: assert isinstance(method, OverloadedFuncDef) dec = method.items[0] @@ -630,12 +664,7 @@ def find_member(name: str, else: # don't have such method, maybe variable or decorator? node = info.get(name) - if not node: - v = None - else: - v = node.node - if isinstance(v, Decorator): - v = v.var + v = node.node if node else None if isinstance(v, Var): return find_node_type(v, itype, subtype) if (not v and name not in ['__getattr__', '__setattr__', '__getattribute__'] and @@ -647,9 +676,13 @@ def find_member(name: str, # structural subtyping. method = info.get_method(method_name) if method and method.info.fullname != 'builtins.object': - getattr_type = get_proper_type(find_node_type(method, itype, subtype)) + if isinstance(method, Decorator): + getattr_type = get_proper_type(find_node_type(method.var, itype, subtype)) + else: + getattr_type = get_proper_type(find_node_type(method, itype, subtype)) if isinstance(getattr_type, CallableType): return getattr_type.ret_type + return getattr_type if itype.type.fallback_to_any: return AnyType(TypeOfAny.special_form) return None @@ -669,8 +702,10 @@ def get_member_flags(name: str, info: TypeInfo) -> Set[int]: method = info.get_method(name) setattr_meth = info.get_method('__setattr__') if method: - # this could be settable property - if method.is_property: + if isinstance(method, Decorator): + if method.var.is_staticmethod or method.var.is_classmethod: + return {IS_CLASS_OR_STATIC} + elif method.is_property: # this could be settable property assert isinstance(method, OverloadedFuncDef) dec = method.items[0] assert isinstance(dec, Decorator) @@ -683,9 +718,6 @@ def get_member_flags(name: str, info: TypeInfo) -> Set[int]: return {IS_SETTABLE} return set() v = node.node - if isinstance(v, Decorator): - if v.var.is_staticmethod or v.var.is_classmethod: - return {IS_CLASS_OR_STATIC} # just a variable if isinstance(v, Var) and not v.is_property: flags = {IS_SETTABLE} @@ -716,7 +748,8 @@ def find_node_type(node: Union[Var, FuncBase], itype: Instance, subtype: Type) - and node.is_initialized_in_class and not node.is_staticmethod)): assert isinstance(typ, FunctionLike) - signature = bind_self(typ, subtype) + signature = bind_self(typ, subtype, + is_classmethod=isinstance(node, Var) and node.is_classmethod) if node.is_property: assert isinstance(signature, CallableType) typ = signature.ret_type @@ -1129,6 +1162,8 @@ def restrict_subtype_away(t: Type, s: Type, *, ignore_promotions: bool = False) if (isinstance(get_proper_type(item), AnyType) or not covers_at_runtime(item, s, ignore_promotions))] return UnionType.make_union(new_items) + elif covers_at_runtime(t, s, ignore_promotions): + return UninhabitedType() else: return t @@ -1289,8 +1324,13 @@ def check_argument(leftarg: Type, rightarg: Type, variance: int) -> bool: assert isinstance(erased, Instance) left = erased - nominal = all(check_argument(ta, ra, tvar.variance) for ta, ra, tvar in - zip(left.args, right.args, right.type.defn.type_vars)) + nominal = True + for ta, ra, tvar in zip(left.args, right.args, right.type.defn.type_vars): + if isinstance(tvar, TypeVarType): + nominal = nominal and check_argument(ta, ra, tvar.variance) + else: + nominal = nominal and mypy.sametypes.is_same_type(ta, ra) + if nominal: TypeState.record_subtype_cache_entry(self._subtype_kind, left, right) return nominal @@ -1313,6 +1353,16 @@ def visit_type_var(self, left: TypeVarType) -> bool: return True return self._is_proper_subtype(left.upper_bound, self.right) + def visit_param_spec(self, left: ParamSpecType) -> bool: + right = self.right + if ( + isinstance(right, ParamSpecType) + and right.id == left.id + and right.flavor == left.flavor + ): + return True + return self._is_proper_subtype(left.upper_bound, self.right) + def visit_callable_type(self, left: CallableType) -> bool: right = self.right if isinstance(right, CallableType): diff --git a/mypy/suggestions.py b/mypy/suggestions.py index 08063cc05451..87b54814c637 100644 --- a/mypy/suggestions.py +++ b/mypy/suggestions.py @@ -288,7 +288,7 @@ def get_trivial_type(self, fdef: FuncDef) -> CallableType: fdef.arg_kinds, fdef.arg_names, AnyType(TypeOfAny.suggestion_engine), - self.builtin_type('builtins.function')) + self.named_type('builtins.function')) def get_starting_type(self, fdef: FuncDef) -> CallableType: if isinstance(fdef.type, CallableType): @@ -351,7 +351,7 @@ def get_default_arg_types(self, state: State, fdef: FuncDef) -> List[Optional[Ty def add_adjustments(self, typs: List[Type]) -> List[Type]: if not self.try_text or self.manager.options.python_version[0] != 2: return typs - translator = StrToText(self.builtin_type) + translator = StrToText(self.named_type) return dedup(typs + [tp.accept(translator) for tp in typs]) def get_guesses(self, is_method: bool, base: CallableType, defaults: List[Optional[Type]], @@ -648,8 +648,8 @@ def ensure_loaded(self, state: State, force: bool = False) -> MypyFile: assert state.tree is not None return state.tree - def builtin_type(self, s: str) -> Instance: - return self.manager.semantic_analyzer.builtin_type(s) + def named_type(self, s: str) -> Instance: + return self.manager.semantic_analyzer.named_type(s) def json_suggestion(self, mod: str, func_name: str, node: FuncDef, suggestion: PyAnnotateSignature) -> str: @@ -850,8 +850,8 @@ def visit_callable_type(self, t: CallableType) -> str: class StrToText(TypeTranslator): - def __init__(self, builtin_type: Callable[[str], Instance]) -> None: - self.text_type = builtin_type('builtins.unicode') + def __init__(self, named_type: Callable[[str], Instance]) -> None: + self.text_type = named_type('builtins.unicode') def visit_type_alias_type(self, t: TypeAliasType) -> Type: exp_t = get_proper_type(t) diff --git a/mypy/test/data.py b/mypy/test/data.py index a04c87f60a8d..e886b11ffa8e 100644 --- a/mypy/test/data.py +++ b/mypy/test/data.py @@ -18,7 +18,7 @@ # File modify/create operation: copy module contents from source_path. UpdateFile = NamedTuple('UpdateFile', [('module', str), - ('source_path', str), + ('content', str), ('target_path', str)]) # File delete operation: delete module file. @@ -114,9 +114,11 @@ def parse_test_case(case: 'DataDrivenTestCase') -> None: if arg == 'skip-path-normalization': normalize_output = False if arg.startswith("version"): - if arg[7:9] != ">=": + compare_op = arg[7:9] + if compare_op not in {">=", "=="}: raise ValueError( - "{}, line {}: Only >= version checks are currently supported".format( + "{}, line {}: Only >= and == version checks are currently supported" + .format( case.file, item.line ) ) @@ -127,9 +129,17 @@ def parse_test_case(case: 'DataDrivenTestCase') -> None: raise ValueError( '{}, line {}: "{}" is not a valid python version'.format( case.file, item.line, version_str)) - if not sys.version_info >= version: - version_check = False - + if compare_op == ">=": + version_check = sys.version_info >= version + elif compare_op == "==": + if not 1 < len(version) < 4: + raise ValueError( + '{}, line {}: Only minor or patch version checks ' + 'are currently supported with "==": "{}"'.format( + case.file, item.line, version_str + ) + ) + version_check = sys.version_info[:len(version)] == version if version_check: tmp_output = [expand_variables(line) for line in item.data] if os.path.sep == '\\' and normalize_output: @@ -247,7 +257,9 @@ def runtest(self) -> None: # TODO: add a better error message for when someone uses skip and xfail at the same time elif self.xfail: self.add_marker(pytest.mark.xfail) - suite = self.parent.obj() + parent = self.getparent(DataSuiteCollector) + assert parent is not None, 'Should not happen' + suite = parent.obj() suite.setup() try: suite.run_case(self) @@ -270,11 +282,35 @@ def setup(self) -> None: self.tmpdir = tempfile.TemporaryDirectory(prefix='mypy-test-') os.chdir(self.tmpdir.name) os.mkdir(test_temp_dir) + + # Precalculate steps for find_steps() + steps: Dict[int, List[FileOperation]] = {} + for path, content in self.files: - dir = os.path.dirname(path) - os.makedirs(dir, exist_ok=True) - with open(path, 'w', encoding='utf8') as f: - f.write(content) + m = re.match(r'.*\.([0-9]+)$', path) + if m: + # Skip writing subsequent incremental steps - rather + # store them as operations. + num = int(m.group(1)) + assert num >= 2 + target_path = re.sub(r'\.[0-9]+$', '', path) + module = module_from_path(target_path) + operation = UpdateFile(module, content, target_path) + steps.setdefault(num, []).append(operation) + else: + # Write the first incremental steps + dir = os.path.dirname(path) + os.makedirs(dir, exist_ok=True) + with open(path, 'w', encoding='utf8') as f: + f.write(content) + + for num, paths in self.deleted_paths.items(): + assert num >= 2 + for path in paths: + module = module_from_path(path) + steps.setdefault(num, []).append(DeleteFile(module, path)) + max_step = max(steps) if steps else 2 + self.steps = [steps.get(num, []) for num in range(2, max_step + 1)] def teardown(self) -> None: assert self.old_cwd is not None and self.tmpdir is not None, \ @@ -312,23 +348,7 @@ def find_steps(self) -> List[List[FileOperation]]: Defaults to having two steps if there aern't any operations. """ - steps: Dict[int, List[FileOperation]] = {} - for path, _ in self.files: - m = re.match(r'.*\.([0-9]+)$', path) - if m: - num = int(m.group(1)) - assert num >= 2 - target_path = re.sub(r'\.[0-9]+$', '', path) - module = module_from_path(target_path) - operation = UpdateFile(module, path, target_path) - steps.setdefault(num, []).append(operation) - for num, paths in self.deleted_paths.items(): - assert num >= 2 - for path in paths: - module = module_from_path(path) - steps.setdefault(num, []).append(DeleteFile(module, path)) - max_step = max(steps) if steps else 2 - return [steps.get(num, []) for num in range(2, max_step + 1)] + return self.steps def module_from_path(path: str) -> str: @@ -542,12 +562,12 @@ def pytest_pycollect_makeitem(collector: Any, name: str, # The collect method of the returned DataSuiteCollector instance will be called later, # with self.obj being obj. return DataSuiteCollector.from_parent( # type: ignore[no-untyped-call] - parent=collector, name=name + parent=collector, name=name, ) return None -def split_test_cases(parent: 'DataSuiteCollector', suite: 'DataSuite', +def split_test_cases(parent: 'DataFileCollector', suite: 'DataSuite', file: str) -> Iterator['DataDrivenTestCase']: """Iterate over raw test cases in file, at collection time, ignoring sub items. @@ -568,8 +588,13 @@ def split_test_cases(parent: 'DataSuiteCollector', suite: 'DataSuite', data, flags=re.DOTALL | re.MULTILINE) line_no = cases[0].count('\n') + 1 + test_names = set() for i in range(1, len(cases), NUM_GROUPS): name, writescache, only_when, platform_flag, skip, xfail, data = cases[i:i + NUM_GROUPS] + if name in test_names: + raise RuntimeError('Found a duplicate test name "{}" in {} on line {}'.format( + name, parent.name, line_no, + )) platform = platform_flag[1:] if platform_flag else None yield DataDrivenTestCase.from_parent( parent=parent, @@ -586,9 +611,12 @@ def split_test_cases(parent: 'DataSuiteCollector', suite: 'DataSuite', ) line_no += data.count('\n') + 1 + # Record existing tests to prevent duplicates: + test_names.update({name}) + class DataSuiteCollector(pytest.Class): - def collect(self) -> Iterator[pytest.Item]: + def collect(self) -> Iterator['DataFileCollector']: """Called by pytest on each of the object returned from pytest_pycollect_makeitem""" # obj is the object for which pytest_pycollect_makeitem returned self. @@ -597,8 +625,32 @@ def collect(self) -> Iterator[pytest.Item]: assert os.path.isdir(suite.data_prefix), \ 'Test data prefix ({}) not set correctly'.format(suite.data_prefix) - for f in suite.files: - yield from split_test_cases(self, suite, os.path.join(suite.data_prefix, f)) + for data_file in suite.files: + yield DataFileCollector.from_parent(parent=self, name=data_file) + + +class DataFileCollector(pytest.Collector): + """Represents a single `.test` data driven test file. + + More context: https://github.com/python/mypy/issues/11662 + """ + parent: DataSuiteCollector + + @classmethod # We have to fight with pytest here: + def from_parent( # type: ignore[override] + cls, + parent: DataSuiteCollector, + *, + name: str, + ) -> 'DataFileCollector': + return super().from_parent(parent, name=name) + + def collect(self) -> Iterator['DataDrivenTestCase']: + yield from split_test_cases( + parent=self, + suite=self.parent.obj, + file=os.path.join(self.parent.obj.data_prefix, self.name), + ) def add_test_name_suffix(name: str, suffix: str) -> str: diff --git a/mypy/test/helpers.py b/mypy/test/helpers.py index 2d7d5e59430c..fbd44bca868b 100644 --- a/mypy/test/helpers.py +++ b/mypy/test/helpers.py @@ -406,7 +406,7 @@ def split_lines(*streams: bytes) -> List[str]: ] -def copy_and_fudge_mtime(source_path: str, target_path: str) -> None: +def write_and_fudge_mtime(content: str, target_path: str) -> None: # In some systems, mtime has a resolution of 1 second which can # cause annoying-to-debug issues when a file has the same size # after a change. We manually set the mtime to circumvent this. @@ -418,8 +418,10 @@ def copy_and_fudge_mtime(source_path: str, target_path: str) -> None: if os.path.isfile(target_path): new_time = os.stat(target_path).st_mtime + 1 - # Use retries to work around potential flakiness on Windows (AppVeyor). - retry_on_error(lambda: shutil.copy(source_path, target_path)) + dir = os.path.dirname(target_path) + os.makedirs(dir, exist_ok=True) + with open(target_path, "w", encoding="utf-8") as target: + target.write(content) if new_time: os.utime(target_path, times=(new_time, new_time)) @@ -430,7 +432,7 @@ def perform_file_operations( for op in operations: if isinstance(op, UpdateFile): # Modify/create file - copy_and_fudge_mtime(op.source_path, op.target_path) + write_and_fudge_mtime(op.content, op.target_path) else: # Delete file/directory if os.path.isdir(op.path): diff --git a/mypy/test/test_find_sources.py b/mypy/test/test_find_sources.py index ba5b613a0948..53da9c384bd2 100644 --- a/mypy/test/test_find_sources.py +++ b/mypy/test/test_find_sources.py @@ -7,7 +7,6 @@ from mypy.find_sources import InvalidSourceList, SourceFinder, create_source_list from mypy.fscache import FileSystemCache -from mypy.modulefinder import BuildSource from mypy.options import Options from mypy.modulefinder import BuildSource @@ -299,7 +298,7 @@ def test_find_sources_exclude(self) -> None: } # file name - options.exclude = r"/f\.py$" + options.exclude = [r"/f\.py$"] fscache = FakeFSCache(files) assert find_sources(["/"], options, fscache) == [ ("a2", "/pkg"), @@ -310,7 +309,7 @@ def test_find_sources_exclude(self) -> None: assert find_sources(["/pkg/a2/b/f.py"], options, fscache) == [('a2.b.f', '/pkg')] # directory name - options.exclude = "/a1/" + options.exclude = ["/a1/"] fscache = FakeFSCache(files) assert find_sources(["/"], options, fscache) == [ ("a2", "/pkg"), @@ -324,13 +323,13 @@ def test_find_sources_exclude(self) -> None: with pytest.raises(InvalidSourceList): find_sources(["/pkg/a1/b"], options, fscache) - options.exclude = "/a1/$" + options.exclude = ["/a1/$"] assert find_sources(["/pkg/a1"], options, fscache) == [ ('e', '/pkg/a1/b/c/d'), ('f', '/pkg/a1/b') ] # paths - options.exclude = "/pkg/a1/" + options.exclude = ["/pkg/a1/"] fscache = FakeFSCache(files) assert find_sources(["/"], options, fscache) == [ ("a2", "/pkg"), @@ -340,15 +339,17 @@ def test_find_sources_exclude(self) -> None: with pytest.raises(InvalidSourceList): find_sources(["/pkg/a1"], options, fscache) - options.exclude = "/(a1|a3)/" - fscache = FakeFSCache(files) - assert find_sources(["/"], options, fscache) == [ - ("a2", "/pkg"), - ("a2.b.c.d.e", "/pkg"), - ("a2.b.f", "/pkg"), - ] + # OR two patterns together + for orred in [["/(a1|a3)/"], ["a1", "a3"], ["a3", "a1"]]: + options.exclude = orred + fscache = FakeFSCache(files) + assert find_sources(["/"], options, fscache) == [ + ("a2", "/pkg"), + ("a2.b.c.d.e", "/pkg"), + ("a2.b.f", "/pkg"), + ] - options.exclude = "b/c/" + options.exclude = ["b/c/"] fscache = FakeFSCache(files) assert find_sources(["/"], options, fscache) == [ ("a2", "/pkg"), @@ -357,19 +358,22 @@ def test_find_sources_exclude(self) -> None: ] # nothing should be ignored as a result of this - options.exclude = "|".join(( + big_exclude1 = [ "/pkg/a/", "/2", "/1", "/pk/", "/kg", "/g.py", "/bc", "/xxx/pkg/a2/b/f.py" "xxx/pkg/a2/b/f.py", - )) - fscache = FakeFSCache(files) - assert len(find_sources(["/"], options, fscache)) == len(files) - - files = { - "pkg/a1/b/c/d/e.py", - "pkg/a1/b/f.py", - "pkg/a2/__init__.py", - "pkg/a2/b/c/d/e.py", - "pkg/a2/b/f.py", - } - fscache = FakeFSCache(files) - assert len(find_sources(["."], options, fscache)) == len(files) + ] + big_exclude2 = ["|".join(big_exclude1)] + for big_exclude in [big_exclude1, big_exclude2]: + options.exclude = big_exclude + fscache = FakeFSCache(files) + assert len(find_sources(["/"], options, fscache)) == len(files) + + files = { + "pkg/a1/b/c/d/e.py", + "pkg/a1/b/f.py", + "pkg/a2/__init__.py", + "pkg/a2/b/c/d/e.py", + "pkg/a2/b/f.py", + } + fscache = FakeFSCache(files) + assert len(find_sources(["."], options, fscache)) == len(files) diff --git a/mypy/test/testcheck.py b/mypy/test/testcheck.py index c71b9aeea626..355a400168f6 100644 --- a/mypy/test/testcheck.py +++ b/mypy/test/testcheck.py @@ -96,6 +96,7 @@ 'check-functools.test', 'check-singledispatch.test', 'check-slots.test', + 'check-formatting.test', ] # Tests that use Python 3.8-only AST features (like expression-scoped ignores): @@ -103,6 +104,8 @@ typecheck_files.append('check-python38.test') if sys.version_info >= (3, 9): typecheck_files.append('check-python39.test') +if sys.version_info >= (3, 10): + typecheck_files.append('check-python310.test') # Special tests for platforms with case-insensitive filesystems. if sys.platform in ('darwin', 'win32'): diff --git a/mypy/test/testmodulefinder.py b/mypy/test/testmodulefinder.py index 4f839f641e7b..d26e7c1efe0c 100644 --- a/mypy/test/testmodulefinder.py +++ b/mypy/test/testmodulefinder.py @@ -184,6 +184,13 @@ def test__packages_with_ns(self) -> None: ("ns_pkg_untyped.b.c", ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS), ("ns_pkg_untyped.a.a_var", ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS), + # Namespace package without stub package + ("ns_pkg_w_stubs", self.path("ns_pkg_w_stubs")), + ("ns_pkg_w_stubs.typed", self.path("ns_pkg_w_stubs-stubs", "typed", "__init__.pyi")), + ("ns_pkg_w_stubs.typed_inline", + self.path("ns_pkg_w_stubs", "typed_inline", "__init__.py")), + ("ns_pkg_w_stubs.untyped", ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS), + # Regular package with py.typed ("pkg_typed", self.path("pkg_typed", "__init__.py")), ("pkg_typed.a", self.path("pkg_typed", "a.py")), @@ -239,6 +246,13 @@ def test__packages_without_ns(self) -> None: ("ns_pkg_untyped.b.c", ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS), ("ns_pkg_untyped.a.a_var", ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS), + # Namespace package without stub package + ("ns_pkg_w_stubs", ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS), + ("ns_pkg_w_stubs.typed", ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS), + ("ns_pkg_w_stubs.typed_inline", + self.path("ns_pkg_w_stubs", "typed_inline", "__init__.py")), + ("ns_pkg_w_stubs.untyped", ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS), + # Regular package with py.typed ("pkg_typed", self.path("pkg_typed", "__init__.py")), ("pkg_typed.a", self.path("pkg_typed", "a.py")), diff --git a/mypy/test/testpep561.py b/mypy/test/testpep561.py index d1f7148ab18c..d30d94c49bee 100644 --- a/mypy/test/testpep561.py +++ b/mypy/test/testpep561.py @@ -62,7 +62,7 @@ def install_package(pkg: str, working_dir = os.path.join(package_path, pkg) with tempfile.TemporaryDirectory() as dir: if use_pip: - install_cmd = [python_executable, '-m', 'pip', 'install', '-b', '{}'.format(dir)] + install_cmd = [python_executable, '-m', 'pip', 'install'] if editable: install_cmd.append('-e') install_cmd.append('.') @@ -72,16 +72,22 @@ def install_package(pkg: str, install_cmd.append('develop') else: install_cmd.append('install') - proc = subprocess.run(install_cmd, cwd=working_dir, stdout=PIPE, stderr=PIPE) + # Note that newer versions of pip (21.3+) don't + # follow this env variable, but this is for compatibility + env = {'PIP_BUILD': dir} + # Inherit environment for Windows + env.update(os.environ) + proc = subprocess.run(install_cmd, + cwd=working_dir, + stdout=PIPE, + stderr=PIPE, + env=env) if proc.returncode != 0: raise Exception(proc.stdout.decode('utf-8') + proc.stderr.decode('utf-8')) def test_pep561(testcase: DataDrivenTestCase) -> None: """Test running mypy on files that depend on PEP 561 packages.""" - if (sys.platform == 'darwin' and hasattr(sys, 'base_prefix') and - sys.base_prefix != sys.prefix): - pytest.skip() assert testcase.old_cwd is not None, "test was not properly set up" if 'python2' in testcase.name.lower(): python = try_find_python2_interpreter() diff --git a/mypy/test/testsemanal.py b/mypy/test/testsemanal.py index 8ef702741784..a71bac53619d 100644 --- a/mypy/test/testsemanal.py +++ b/mypy/test/testsemanal.py @@ -20,19 +20,22 @@ # Semantic analyzer test cases: dump parse tree # Semantic analysis test case description files. -semanal_files = ['semanal-basic.test', - 'semanal-expressions.test', - 'semanal-classes.test', - 'semanal-types.test', - 'semanal-typealiases.test', - 'semanal-modules.test', - 'semanal-statements.test', - 'semanal-abstractclasses.test', - 'semanal-namedtuple.test', - 'semanal-typeddict.test', - 'semenal-literal.test', - 'semanal-classvar.test', - 'semanal-python2.test'] +semanal_files = [ + 'semanal-basic.test', + 'semanal-expressions.test', + 'semanal-classes.test', + 'semanal-types.test', + 'semanal-typealiases.test', + 'semanal-modules.test', + 'semanal-statements.test', + 'semanal-abstractclasses.test', + 'semanal-namedtuple.test', + 'semanal-typeddict.test', + 'semenal-literal.test', + 'semanal-classvar.test', + 'semanal-python2.test', + 'semanal-lambda.test', +] def get_semanal_options(program_text: str, testcase: DataDrivenTestCase) -> Options: diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index 7275037a9246..e6eb8465c665 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -52,6 +52,8 @@ class bool(int): ... class str: ... class bytes: ... +class list(Sequence[T]): ... + def property(f: T) -> T: ... def classmethod(f: T) -> T: ... def staticmethod(f: T) -> T: ... @@ -648,7 +650,7 @@ def h(x: str): ... runtime="", error="h", ) - yield Case("", "__all__ = []", None) # dummy case + yield Case(stub="", runtime="__all__ = []", error=None) # 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 @@ -660,6 +662,20 @@ def h(x: str): ... def test_missing_no_runtime_all(self) -> Iterator[Case]: yield Case(stub="", runtime="import sys", error=None) yield Case(stub="", runtime="def g(): ...", error="g") + yield Case(stub="", runtime="CONSTANT = 0", error="CONSTANT") + + @collect_cases + def test_non_public_1(self) -> Iterator[Case]: + yield Case(stub="__all__: list[str]", runtime="", error=None) # dummy case + yield Case(stub="_f: int", runtime="def _f(): ...", error="_f") + + @collect_cases + def test_non_public_2(self) -> Iterator[Case]: + yield Case( + stub="__all__: list[str] = ['f']", runtime="__all__ = ['f']", error=None + ) + yield Case(stub="f: int", runtime="def f(): ...", error="f") + yield Case(stub="g: int", runtime="def g(): ...", error="g") @collect_cases def test_special_dunders(self) -> Iterator[Case]: diff --git a/mypy/test/testtypes.py b/mypy/test/testtypes.py index 0600c333944d..0d37fe795bbc 100644 --- a/mypy/test/testtypes.py +++ b/mypy/test/testtypes.py @@ -653,8 +653,8 @@ def test_generics_covariant(self) -> None: def test_generics_contravariant(self) -> None: self.assert_join(self.fx_contra.ga, self.fx_contra.ga, self.fx_contra.ga) - self.assert_join(self.fx_contra.ga, self.fx_contra.gb, self.fx_contra.gb) - self.assert_join(self.fx_contra.ga, self.fx_contra.gd, self.fx_contra.gn) + # TODO: this can be more precise than "object", see a comment in mypy/join.py + self.assert_join(self.fx_contra.ga, self.fx_contra.gb, self.fx_contra.o) self.assert_join(self.fx_contra.ga, self.fx_contra.g2a, self.fx_contra.o) def test_generics_with_multiple_args(self) -> None: diff --git a/mypy/test/typefixture.py b/mypy/test/typefixture.py index 4e929225fc3f..1a5dd8164136 100644 --- a/mypy/test/typefixture.py +++ b/mypy/test/typefixture.py @@ -7,8 +7,9 @@ from mypy.semanal_shared import set_callable_name from mypy.types import ( - Type, TypeVarType, AnyType, NoneType, Instance, CallableType, TypeVarType, TypeType, - UninhabitedType, TypeOfAny, TypeAliasType, UnionType, LiteralType + Type, AnyType, NoneType, Instance, CallableType, TypeVarType, TypeType, + UninhabitedType, TypeOfAny, TypeAliasType, UnionType, LiteralType, + TypeVarLikeType ) from mypy.nodes import ( TypeInfo, ClassDef, FuncDef, Block, ARG_POS, ARG_OPT, ARG_STAR, SymbolTable, @@ -234,7 +235,7 @@ def make_type_info(self, name: str, module_name = '__main__' if typevars: - v: List[TypeVarType] = [] + v: List[TypeVarLikeType] = [] for id, n in enumerate(typevars, 1): if variances: variance = variances[id - 1] diff --git a/mypy/tvar_scope.py b/mypy/tvar_scope.py index 9b5c1ebfb654..0d8be7845e52 100644 --- a/mypy/tvar_scope.py +++ b/mypy/tvar_scope.py @@ -1,5 +1,5 @@ from typing import Optional, Dict, Union -from mypy.types import TypeVarLikeType, TypeVarType, ParamSpecType +from mypy.types import TypeVarLikeType, TypeVarType, ParamSpecType, ParamSpecFlavor from mypy.nodes import ParamSpecExpr, TypeVarExpr, TypeVarLikeExpr, SymbolTableNode @@ -78,6 +78,8 @@ def bind_new(self, name: str, tvar_expr: TypeVarLikeExpr) -> TypeVarLikeType: name, tvar_expr.fullname, i, + flavor=ParamSpecFlavor.BARE, + upper_bound=tvar_expr.upper_bound, line=tvar_expr.line, column=tvar_expr.column ) diff --git a/mypy/type_visitor.py b/mypy/type_visitor.py index 2b4ebffb93e0..99821fa62640 100644 --- a/mypy/type_visitor.py +++ b/mypy/type_visitor.py @@ -23,7 +23,7 @@ RawExpressionType, Instance, NoneType, TypeType, UnionType, TypeVarType, PartialType, DeletedType, UninhabitedType, TypeVarLikeType, UnboundType, ErasedType, StarType, EllipsisType, TypeList, CallableArgument, - PlaceholderType, TypeAliasType, get_proper_type + PlaceholderType, TypeAliasType, ParamSpecType, get_proper_type ) @@ -63,6 +63,10 @@ def visit_deleted_type(self, t: DeletedType) -> T: def visit_type_var(self, t: TypeVarType) -> T: pass + @abstractmethod + def visit_param_spec(self, t: ParamSpecType) -> T: + pass + @abstractmethod def visit_instance(self, t: Instance) -> T: pass @@ -179,6 +183,9 @@ def visit_instance(self, t: Instance) -> Type: def visit_type_var(self, t: TypeVarType) -> Type: return t + def visit_param_spec(self, t: ParamSpecType) -> Type: + return t + def visit_partial_type(self, t: PartialType) -> Type: return t @@ -291,6 +298,9 @@ def visit_deleted_type(self, t: DeletedType) -> T: def visit_type_var(self, t: TypeVarType) -> T: return self.query_types([t.upper_bound] + t.values) + def visit_param_spec(self, t: ParamSpecType) -> T: + return self.strategy([]) + def visit_partial_type(self, t: PartialType) -> T: return self.strategy([]) diff --git a/mypy/typeanal.py b/mypy/typeanal.py index 6e2cb350f6e6..f7b584eadae8 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -12,11 +12,12 @@ from mypy.messages import MessageBuilder, quote_type_string, format_type_bare from mypy.options import Options from mypy.types import ( - Type, UnboundType, TypeVarType, TupleType, TypedDictType, UnionType, Instance, AnyType, + Type, UnboundType, TupleType, TypedDictType, UnionType, Instance, AnyType, CallableType, NoneType, ErasedType, DeletedType, TypeList, TypeVarType, SyntheticTypeVisitor, - StarType, PartialType, EllipsisType, UninhabitedType, TypeType, TypeVarLikeType, - CallableArgument, TypeQuery, union_items, TypeOfAny, LiteralType, RawExpressionType, - PlaceholderType, Overloaded, get_proper_type, TypeAliasType, TypeVarLikeType, ParamSpecType + StarType, PartialType, EllipsisType, UninhabitedType, TypeType, CallableArgument, + TypeQuery, union_items, TypeOfAny, LiteralType, RawExpressionType, + PlaceholderType, Overloaded, get_proper_type, TypeAliasType, RequiredType, + TypeVarLikeType, ParamSpecType, ParamSpecFlavor, callable_with_ellipsis ) from mypy.nodes import ( @@ -129,6 +130,7 @@ def __init__(self, allow_new_syntax: bool = False, allow_unbound_tvars: bool = False, allow_placeholder: bool = False, + allow_required: bool = False, report_invalid_types: bool = True) -> None: self.api = api self.lookup_qualified = api.lookup_qualified @@ -148,6 +150,8 @@ def __init__(self, self.allow_unbound_tvars = allow_unbound_tvars or defining_alias # If false, record incomplete ref if we generate PlaceholderType. self.allow_placeholder = allow_placeholder + # Are we in a context where Required[] is allowed? + self.allow_required = allow_required # Should we report an error whenever we encounter a RawExpressionType outside # of a Literal context: e.g. whenever we encounter an invalid type? Normally, # we want to report an error, but the caller may want to do more specialized @@ -208,13 +212,14 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool) if tvar_def is None: self.fail('ParamSpec "{}" is unbound'.format(t.name), t) return AnyType(TypeOfAny.from_error) - self.fail('Invalid location for ParamSpec "{}"'.format(t.name), t) - self.note( - 'You can use ParamSpec as the first argument to Callable, e.g., ' - "'Callable[{}, int]'".format(t.name), - t + assert isinstance(tvar_def, ParamSpecType) + if len(t.args) > 0: + self.fail('ParamSpec "{}" used with arguments'.format(t.name), t) + # Change the line number + return ParamSpecType( + tvar_def.name, tvar_def.fullname, tvar_def.id, tvar_def.flavor, + tvar_def.upper_bound, line=t.line, column=t.column, ) - return AnyType(TypeOfAny.from_error) if isinstance(sym.node, TypeVarExpr) and tvar_def is not None and self.defining_alias: self.fail('Can\'t use bound type variable "{}"' ' to define generic alias'.format(t.name), t) @@ -257,6 +262,8 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool) return res elif isinstance(node, TypeInfo): return self.analyze_type_with_type_info(node, t.args, t) + elif node.fullname in ("typing_extensions.TypeAlias", "typing.TypeAlias"): + return AnyType(TypeOfAny.special_form) else: return self.analyze_unbound_type_without_type_info(t, sym, defining_literal) else: # sym is None @@ -329,8 +336,8 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Opt # To prevent assignment of 'builtins.type' inferred as 'builtins.object' # See https://github.com/python/mypy/issues/9476 for more information return None - type_str = 'Type[...]' if fullname == 'typing.Type' else 'type[...]' if len(t.args) != 1: + type_str = 'Type[...]' if fullname == 'typing.Type' else 'type[...]' self.fail(type_str + ' must have exactly one type argument', t) item = self.anal_type(t.args[0]) return TypeType.make_normalized(item, line=t.line) @@ -353,6 +360,22 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Opt " and at least one annotation", t) return AnyType(TypeOfAny.from_error) return self.anal_type(t.args[0]) + elif fullname in ('typing_extensions.Required', 'typing.Required'): + if not self.allow_required: + self.fail("Required[] can be only used in a TypedDict definition", t) + return AnyType(TypeOfAny.from_error) + if len(t.args) != 1: + self.fail("Required[] must have exactly one type argument", t) + return AnyType(TypeOfAny.from_error) + return RequiredType(self.anal_type(t.args[0]), required=True) + elif fullname in ('typing_extensions.NotRequired', 'typing.NotRequired'): + if not self.allow_required: + self.fail("NotRequired[] can be only used in a TypedDict definition", t) + return AnyType(TypeOfAny.from_error) + if len(t.args) != 1: + self.fail("NotRequired[] must have exactly one type argument", t) + return AnyType(TypeOfAny.from_error) + return RequiredType(self.anal_type(t.args[0]), required=False) elif self.anal_type_guard_arg(t, fullname) is not None: # In most contexts, TypeGuard[...] acts as an alias for bool (ignoring its args) return self.named_type('builtins.bool') @@ -378,7 +401,8 @@ def analyze_type_with_type_info( # checked only later, since we do not always know the # valid count at this point. Thus we may construct an # Instance with an invalid number of type arguments. - instance = Instance(info, self.anal_array(args), ctx.line, ctx.column) + instance = Instance(info, self.anal_array(args, allow_param_spec=True), + ctx.line, ctx.column) # Check type argument count. if len(instance.args) != len(info.type_vars) and not self.defining_alias: fix_instance(instance, self.fail, self.note, @@ -528,6 +552,9 @@ def visit_type_alias_type(self, t: TypeAliasType) -> Type: def visit_type_var(self, t: TypeVarType) -> Type: return t + def visit_param_spec(self, t: ParamSpecType) -> Type: + return t + def visit_callable_type(self, t: CallableType, nested: bool = True) -> Type: # Every Callable can bind its own type variables, if they're not in the outer scope with self.tvar_scope_frame(): @@ -536,7 +563,15 @@ def visit_callable_type(self, t: CallableType, nested: bool = True) -> Type: else: variables = self.bind_function_type_variables(t, t) special = self.anal_type_guard(t.ret_type) - ret = t.copy_modified(arg_types=self.anal_array(t.arg_types, nested=nested), + arg_kinds = t.arg_kinds + if len(arg_kinds) >= 2 and arg_kinds[-2] == ARG_STAR and arg_kinds[-1] == ARG_STAR2: + arg_types = self.anal_array(t.arg_types[:-2], nested=nested) + [ + self.anal_star_arg_type(t.arg_types[-2], ARG_STAR, nested=nested), + self.anal_star_arg_type(t.arg_types[-1], ARG_STAR2, nested=nested), + ] + else: + arg_types = self.anal_array(t.arg_types, nested=nested) + ret = t.copy_modified(arg_types=arg_types, ret_type=self.anal_type(t.ret_type, nested=nested), # If the fallback isn't filled in yet, # its type will be the falsey FakeInfo @@ -563,6 +598,26 @@ def anal_type_guard_arg(self, t: UnboundType, fullname: str) -> Optional[Type]: return self.anal_type(t.args[0]) return None + def anal_star_arg_type(self, t: Type, kind: ArgKind, nested: bool) -> Type: + """Analyze signature argument type for *args and **kwargs argument.""" + # TODO: Check that suffix and kind match + if isinstance(t, UnboundType) and t.name and '.' in t.name and not t.args: + components = t.name.split('.') + sym = self.lookup_qualified('.'.join(components[:-1]), t) + if sym is not None and isinstance(sym.node, ParamSpecExpr): + tvar_def = self.tvar_scope.get_binding(sym) + if isinstance(tvar_def, ParamSpecType): + if kind == ARG_STAR: + flavor = ParamSpecFlavor.ARGS + elif kind == ARG_STAR2: + flavor = ParamSpecFlavor.KWARGS + else: + assert False, kind + return ParamSpecType(tvar_def.name, tvar_def.fullname, tvar_def.id, flavor, + upper_bound=self.named_type('builtins.object'), + line=t.line, column=t.column) + return self.anal_type(t, nested=nested) + def visit_overloaded(self, t: Overloaded) -> Type: # Overloaded types are manually constructed in semanal.py by analyzing the # AST and combining together the Callable types this visitor converts. @@ -691,14 +746,17 @@ def analyze_callable_args_for_paramspec( if not isinstance(tvar_def, ParamSpecType): return None - # TODO(shantanu): construct correct type for paramspec + # TODO: Use tuple[...] or Mapping[..] instead? + obj = self.named_type('builtins.object') return CallableType( - [AnyType(TypeOfAny.explicit), AnyType(TypeOfAny.explicit)], + [ParamSpecType(tvar_def.name, tvar_def.fullname, tvar_def.id, ParamSpecFlavor.ARGS, + upper_bound=obj), + ParamSpecType(tvar_def.name, tvar_def.fullname, tvar_def.id, ParamSpecFlavor.KWARGS, + upper_bound=obj)], [nodes.ARG_STAR, nodes.ARG_STAR2], [None, None], ret_type=ret_type, fallback=fallback, - is_ellipsis_args=True ) def analyze_callable_type(self, t: UnboundType) -> Type: @@ -706,12 +764,7 @@ def analyze_callable_type(self, t: UnboundType) -> Type: if len(t.args) == 0: # Callable (bare). Treat as Callable[..., Any]. any_type = self.get_omitted_any(t) - ret = CallableType([any_type, any_type], - [nodes.ARG_STAR, nodes.ARG_STAR2], - [None, None], - ret_type=any_type, - fallback=fallback, - is_ellipsis_args=True) + ret = callable_with_ellipsis(any_type, any_type, fallback) elif len(t.args) == 2: callable_args = t.args[0] ret_type = t.args[1] @@ -728,13 +781,9 @@ def analyze_callable_type(self, t: UnboundType) -> Type: fallback=fallback) elif isinstance(callable_args, EllipsisType): # Callable[..., RET] (with literal ellipsis; accept arbitrary arguments) - ret = CallableType([AnyType(TypeOfAny.explicit), - AnyType(TypeOfAny.explicit)], - [nodes.ARG_STAR, nodes.ARG_STAR2], - [None, None], - ret_type=ret_type, - fallback=fallback, - is_ellipsis_args=True) + ret = callable_with_ellipsis(AnyType(TypeOfAny.explicit), + ret_type=ret_type, + fallback=fallback) else: # Callable[P, RET] (where P is ParamSpec) maybe_ret = self.analyze_callable_args_for_paramspec( @@ -744,7 +793,7 @@ def analyze_callable_type(self, t: UnboundType) -> Type: ) if maybe_ret is None: # Callable[?, RET] (where ? is something invalid) - # TODO(shantanu): change error to mention paramspec, once we actually have some + # TODO(PEP612): change error to mention paramspec, once we actually have some # support for it self.fail('The first argument to Callable must be a list of types or "..."', t) return AnyType(TypeOfAny.from_error) @@ -834,7 +883,7 @@ def analyze_literal_param(self, idx: int, arg: Type, ctx: Context) -> Optional[L # # 1. If the user attempts use an explicit Any as a parameter # 2. If the user is trying to use an enum value imported from a module with - # no type hints, giving it an an implicit type of 'Any' + # no type hints, giving it an implicit type of 'Any' # 3. If there's some other underlying problem with the parameter. # # We report an error in only the first two cases. In the third case, we assume @@ -953,20 +1002,36 @@ def is_defined_type_var(self, tvar: str, context: Context) -> bool: return False return self.tvar_scope.get_binding(tvar_node) is not None - def anal_array(self, a: Iterable[Type], nested: bool = True) -> List[Type]: + def anal_array(self, + a: Iterable[Type], + nested: bool = True, *, + allow_param_spec: bool = False) -> List[Type]: res: List[Type] = [] for t in a: - res.append(self.anal_type(t, nested)) + res.append(self.anal_type(t, nested, allow_param_spec=allow_param_spec)) return res - def anal_type(self, t: Type, nested: bool = True) -> Type: + def anal_type(self, t: Type, nested: bool = True, *, allow_param_spec: bool = False) -> Type: if nested: self.nesting_level += 1 + old_allow_required = self.allow_required + self.allow_required = False try: - return t.accept(self) + analyzed = t.accept(self) finally: if nested: self.nesting_level -= 1 + self.allow_required = old_allow_required + if (not allow_param_spec + and isinstance(analyzed, ParamSpecType) + and analyzed.flavor == ParamSpecFlavor.BARE): + self.fail('Invalid location for ParamSpec "{}"'.format(analyzed.name), t) + self.note( + 'You can use ParamSpec as the first argument to Callable, e.g., ' + "'Callable[{}, int]'".format(analyzed.name), + t + ) + return analyzed def anal_var_def(self, var_def: TypeVarLikeType) -> TypeVarLikeType: if isinstance(var_def, TypeVarType): @@ -1184,6 +1249,7 @@ def flatten_tvars(ll: Iterable[List[T]]) -> List[T]: class TypeVarLikeQuery(TypeQuery[TypeVarLikeList]): + """Find TypeVar and ParamSpec references in an unbound type.""" def __init__(self, lookup: Callable[[str, Context], Optional[SymbolTableNode]], @@ -1206,7 +1272,17 @@ def _seems_like_callable(self, type: UnboundType) -> bool: def visit_unbound_type(self, t: UnboundType) -> TypeVarLikeList: name = t.name - node = self.lookup(name, t) + node = None + # Special case P.args and P.kwargs for ParamSpecs only. + if name.endswith('args'): + if name.endswith('.args') or name.endswith('.kwargs'): + base = '.'.join(name.split('.')[:-1]) + n = self.lookup(base, t) + if n is not None and isinstance(n.node, ParamSpecExpr): + node = n + name = base + if node is None: + node = self.lookup(name, t) if node and isinstance(node.node, TypeVarLikeExpr) and ( self.include_bound_tvars or self.scope.get_binding(node) is None): assert isinstance(node.node, TypeVarLikeExpr) @@ -1215,6 +1291,9 @@ def visit_unbound_type(self, t: UnboundType) -> TypeVarLikeList: return [] elif node and node.fullname in ('typing_extensions.Literal', 'typing.Literal'): return [] + elif node and node.fullname in ('typing_extensions.Annotated', 'typing.Annotated'): + # Don't query the second argument to Annotated for TypeVars + return self.query_types([t.args[0]]) else: return super().visit_unbound_type(t) diff --git a/mypy/typeops.py b/mypy/typeops.py index fc0dee538d79..9ba170b4b822 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -17,7 +17,7 @@ copy_type, TypeAliasType, TypeQuery, ParamSpecType ) from mypy.nodes import ( - FuncBase, FuncItem, OverloadedFuncDef, TypeInfo, ARG_STAR, ARG_STAR2, ARG_POS, + FuncBase, FuncItem, FuncDef, OverloadedFuncDef, TypeInfo, ARG_STAR, ARG_STAR2, ARG_POS, Expression, StrExpr, Var, Decorator, SYMBOL_FUNCBASE_TYPES ) from mypy.maptype import map_instance_to_supertype @@ -209,8 +209,6 @@ class B(A): pass b = B().copy() # type: B """ - from mypy.infer import infer_type_arguments - if isinstance(method, Overloaded): return cast(F, Overloaded([bind_self(c, original_type, is_classmethod) for c in method.items])) @@ -230,6 +228,8 @@ class B(A): pass variables: Sequence[TypeVarLikeType] = [] if func.variables and supported_self_type(self_param_type): + from mypy.infer import infer_type_arguments + if original_type is None: # TODO: type check method override (see #7861). original_type = erase_to_bound(self_param_type) @@ -511,7 +511,7 @@ def true_or_false(t: Type) -> ProperType: def erase_def_to_union_or_bound(tdef: TypeVarLikeType) -> Type: - # TODO(shantanu): fix for ParamSpecType + # TODO(PEP612): fix for ParamSpecType if isinstance(tdef, ParamSpecType): return AnyType(TypeOfAny.from_error) assert isinstance(tdef, TypeVarType) @@ -572,6 +572,8 @@ def callable_type(fdef: FuncItem, fallback: Instance, line=fdef.line, column=fdef.column, implicit=True, + # We need this for better error messages, like missing `self` note: + definition=fdef if isinstance(fdef, FuncDef) else None, ) @@ -699,7 +701,7 @@ def is_singleton_type(typ: Type) -> bool: ) -def try_expanding_enum_to_union(typ: Type, target_fullname: str) -> ProperType: +def try_expanding_sum_type_to_union(typ: Type, target_fullname: str) -> ProperType: """Attempts to recursively expand any enum Instances with the given target_fullname into a Union of all of its component LiteralTypes. @@ -721,28 +723,34 @@ class Status(Enum): typ = get_proper_type(typ) if isinstance(typ, UnionType): - items = [try_expanding_enum_to_union(item, target_fullname) for item in typ.items] + items = [try_expanding_sum_type_to_union(item, target_fullname) for item in typ.items] return make_simplified_union(items, contract_literals=False) - elif isinstance(typ, Instance) and typ.type.is_enum and typ.type.fullname == target_fullname: - new_items = [] - for name, symbol in typ.type.names.items(): - if not isinstance(symbol.node, Var): - continue - # Skip "_order_" and "__order__", since Enum will remove it - if name in ("_order_", "__order__"): - continue - new_items.append(LiteralType(name, typ)) - # SymbolTables are really just dicts, and dicts are guaranteed to preserve - # insertion order only starting with Python 3.7. So, we sort these for older - # versions of Python to help make tests deterministic. - # - # We could probably skip the sort for Python 3.6 since people probably run mypy - # only using CPython, but we might as well for the sake of full correctness. - if sys.version_info < (3, 7): - new_items.sort(key=lambda lit: lit.value) - return make_simplified_union(new_items, contract_literals=False) - else: - return typ + elif isinstance(typ, Instance) and typ.type.fullname == target_fullname: + if typ.type.is_enum: + new_items = [] + for name, symbol in typ.type.names.items(): + if not isinstance(symbol.node, Var): + continue + # Skip "_order_" and "__order__", since Enum will remove it + if name in ("_order_", "__order__"): + continue + new_items.append(LiteralType(name, typ)) + # SymbolTables are really just dicts, and dicts are guaranteed to preserve + # insertion order only starting with Python 3.7. So, we sort these for older + # versions of Python to help make tests deterministic. + # + # We could probably skip the sort for Python 3.6 since people probably run mypy + # only using CPython, but we might as well for the sake of full correctness. + if sys.version_info < (3, 7): + new_items.sort(key=lambda lit: lit.value) + 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 + ) + + return typ def try_contracting_literals_in_union(types: Sequence[Type]) -> List[ProperType]: @@ -751,8 +759,10 @@ def try_contracting_literals_in_union(types: Sequence[Type]) -> List[ProperType] Will replace the first instance of the literal with the sum type and remove all others. - if we call `try_contracting_union(Literal[Color.RED, Color.BLUE, Color.YELLOW])`, + If we call `try_contracting_union(Literal[Color.RED, Color.BLUE, Color.YELLOW])`, this function will return Color. + + We also treat `Literal[True, False]` as `bool`. """ proper_types = [get_proper_type(typ) for typ in types] sum_types: Dict[str, Tuple[Set[Any], List[int]]] = {} @@ -760,9 +770,12 @@ def try_contracting_literals_in_union(types: Sequence[Type]) -> List[ProperType] for idx, typ in enumerate(proper_types): if isinstance(typ, LiteralType): fullname = typ.fallback.type.fullname - if typ.fallback.type.is_enum: + if typ.fallback.type.is_enum or isinstance(typ.value, bool): if fullname not in sum_types: - sum_types[fullname] = (set(get_enum_values(typ.fallback)), []) + sum_types[fullname] = (set(get_enum_values(typ.fallback)) + if typ.fallback.type.is_enum + else set((True, False)), + []) literals, indexes = sum_types[fullname] literals.discard(typ.value) indexes.append(idx) diff --git a/mypy/types.py b/mypy/types.py index 685d6af26db9..14eefea7dd81 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -3,14 +3,14 @@ import copy import sys from abc import abstractmethod -from mypy.backports import OrderedDict from typing import ( Any, TypeVar, Dict, List, Tuple, cast, Set, Optional, Union, Iterable, NamedTuple, - Sequence, Iterator, overload + Sequence ) -from typing_extensions import ClassVar, Final, TYPE_CHECKING, overload +from typing_extensions import ClassVar, Final, TYPE_CHECKING, overload, TypeAlias as _TypeAlias +from mypy.backports import OrderedDict import mypy.nodes from mypy import state from mypy.nodes import ( @@ -23,7 +23,7 @@ T = TypeVar('T') -JsonDict = Dict[str, Any] +JsonDict: _TypeAlias = Dict[str, Any] # The set of all valid expressions that can currently be contained # inside of a Literal[...]. @@ -52,7 +52,7 @@ # Note: Although "Literal[None]" is a valid type, we internally always convert # such a type directly into "None". So, "None" is not a valid parameter of # LiteralType and is omitted from this list. -LiteralValue = Union[int, str, bool] +LiteralValue: _TypeAlias = Union[int, str, bool] # If we only import type_visitor in the middle of the file, mypy @@ -89,6 +89,9 @@ class TypeOfAny: """ This class describes different types of Any. Each 'Any' can be of only one type at a time. """ + + __slots__ = () + # Was this Any type inferred without a type annotation? unannotated: Final = 1 # Does this Any come from an explicit type annotation? @@ -127,6 +130,15 @@ class Type(mypy.nodes.Context): """Abstract base class for all types.""" __slots__ = ('can_be_true', 'can_be_false') + # 'can_be_true' and 'can_be_false' mean whether the value of the + # expression can be true or false in a boolean context. They are useful + # when inferring the type of logic expressions like `x and y`. + # + # For example: + # * the literal `False` can't be true while `True` can. + # * a value with type `bool` can be true or false. + # * `None` can't be true + # * ... def __init__(self, line: int = -1, column: int = -1) -> None: super().__init__(line, column) @@ -277,7 +289,10 @@ def copy_modified(self, *, class TypeGuardedType(Type): - """Only used by find_instance_check() etc.""" + """Only used by find_isinstance_check() etc.""" + + __slots__ = ('type_guard',) + def __init__(self, type_guard: Type): super().__init__(line=type_guard.line, column=type_guard.column) self.type_guard = type_guard @@ -286,12 +301,29 @@ def __repr__(self) -> str: return "TypeGuard({})".format(self.type_guard) +class RequiredType(Type): + """Required[T] or NotRequired[T]. Only usable at top-level of a TypedDict definition.""" + + def __init__(self, item: Type, *, required: bool) -> None: + super().__init__(line=item.line, column=item.column) + self.item = item + self.required = required + + def __repr__(self) -> str: + if self.required: + return "Required[{}]".format(self.item) + else: + return "NotRequired[{}]".format(self.item) + + class ProperType(Type): """Not a type alias. Every type except TypeAliasType must inherit from this type. """ + __slots__ = () + class TypeVarId: # A type variable is uniquely identified by its raw id and meta level. @@ -345,12 +377,17 @@ def is_meta_var(self) -> bool: class TypeVarLikeType(ProperType): - name = '' # Name (may be qualified) - fullname = '' # Fully qualified name + + __slots__ = ('name', 'fullname', 'id', 'upper_bound') + + name: str # Name (may be qualified) + fullname: str # Fully qualified name id: TypeVarId + upper_bound: Type def __init__( - self, name: str, fullname: str, id: Union[TypeVarId, int], line: int = -1, column: int = -1 + self, name: str, fullname: str, id: Union[TypeVarId, int], upper_bound: Type, + line: int = -1, column: int = -1 ) -> None: super().__init__(line, column) self.name = name @@ -358,6 +395,7 @@ def __init__( if isinstance(id, int): id = TypeVarId(id) self.id = id + self.upper_bound = upper_bound def serialize(self) -> JsonDict: raise NotImplementedError @@ -368,19 +406,19 @@ def deserialize(cls, data: JsonDict) -> 'TypeVarLikeType': class TypeVarType(TypeVarLikeType): - """Definition of a single type variable.""" + """Type that refers to a type variable.""" + + __slots__ = ('values', 'variance') values: List[Type] # Value restriction, empty list if no restriction - upper_bound: Type - variance: int = INVARIANT + variance: int def __init__(self, name: str, fullname: str, id: Union[TypeVarId, int], values: List[Type], upper_bound: Type, variance: int = INVARIANT, line: int = -1, column: int = -1) -> None: - super().__init__(name, fullname, id, line, column) + super().__init__(name, fullname, id, upper_bound, line, column) assert values is not None, "No restrictions must be represented by empty list" self.values = values - self.upper_bound = upper_bound self.variance = variance @staticmethod @@ -424,11 +462,73 @@ def deserialize(cls, data: JsonDict) -> 'TypeVarType': ) +class ParamSpecFlavor: + # Simple ParamSpec reference such as "P" + BARE: Final = 0 + # P.args + ARGS: Final = 1 + # P.kwargs + KWARGS: Final = 2 + + class ParamSpecType(TypeVarLikeType): - """Definition of a single ParamSpec variable.""" + """Type that refers to a ParamSpec. - def __repr__(self) -> str: - return self.name + A ParamSpec is a type variable that represents the parameter + types, names and kinds of a callable (i.e., the signature without + the return type). + + This can be one of these forms + * P (ParamSpecFlavor.BARE) + * P.args (ParamSpecFlavor.ARGS) + * P.kwargs (ParamSpecFLavor.KWARGS) + + The upper_bound is really used as a fallback type -- it's shared + with TypeVarType for simplicity. It can't be specified by the user + and the value is directly derived from the flavor (currently + always just 'object'). + """ + + __slots__ = ('flavor',) + + flavor: int + + def __init__( + self, name: str, fullname: str, id: Union[TypeVarId, int], flavor: int, + upper_bound: Type, *, line: int = -1, column: int = -1 + ) -> None: + super().__init__(name, fullname, id, upper_bound, line=line, column=column) + self.flavor = flavor + + @staticmethod + def new_unification_variable(old: 'ParamSpecType') -> 'ParamSpecType': + new_id = TypeVarId.new(meta_level=1) + return ParamSpecType(old.name, old.fullname, new_id, old.flavor, old.upper_bound, + line=old.line, column=old.column) + + def with_flavor(self, flavor: int) -> 'ParamSpecType': + return ParamSpecType(self.name, self.fullname, self.id, flavor, + upper_bound=self.upper_bound) + + def accept(self, visitor: 'TypeVisitor[T]') -> T: + return visitor.visit_param_spec(self) + + def name_with_suffix(self) -> str: + n = self.name + if self.flavor == ParamSpecFlavor.ARGS: + return f'{n}.args' + elif self.flavor == ParamSpecFlavor.KWARGS: + return f'{n}.kwargs' + return n + + def __hash__(self) -> int: + return hash((self.id, self.flavor)) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, ParamSpecType): + return NotImplemented + # Upper bound can be ignored, since it's determined by flavor. + return self.id == other.id and self.flavor == other.flavor def serialize(self) -> JsonDict: assert not self.id.is_meta_var() @@ -437,6 +537,8 @@ def serialize(self) -> JsonDict: 'name': self.name, 'fullname': self.fullname, 'id': self.id.raw_id, + 'flavor': self.flavor, + 'upper_bound': self.upper_bound.serialize(), } @classmethod @@ -446,6 +548,8 @@ def deserialize(cls, data: JsonDict) -> 'ParamSpecType': data['name'], data['fullname'], data['id'], + data['flavor'], + deserialize_type(data['upper_bound']), ) @@ -544,9 +648,11 @@ class CallableArgument(ProperType): Note that this is a synthetic type for helping parse ASTs, not a real type. """ + __slots__ = ('typ', 'name', 'constructor') + typ: Type - name: Optional[str] = None - constructor: Optional[str] = None + name: Optional[str] + constructor: Optional[str] def __init__(self, typ: Type, name: Optional[str], constructor: Optional[str], line: int = -1, column: int = -1) -> None: @@ -572,6 +678,8 @@ class TypeList(ProperType): types before they are processed into Callable types. """ + __slots__ = ('items',) + items: List[Type] def __init__(self, items: List[Type], line: int = -1, column: int = -1) -> None: @@ -672,15 +780,18 @@ class UninhabitedType(ProperType): is_subtype(UninhabitedType, T) = True """ - is_noreturn = False # Does this come from a NoReturn? Purely for error messages. + __slots__ = ('ambiguous', 'is_noreturn',) + + is_noreturn: bool # Does this come from a NoReturn? Purely for error messages. # It is important to track whether this is an actual NoReturn type, or just a result # of ambiguous type inference, in the latter case we don't want to mark a branch as # unreachable in binder. - ambiguous = False # Is this a result of inference for a variable without constraints? + ambiguous: bool # Is this a result of inference for a variable without constraints? def __init__(self, is_noreturn: bool = False, line: int = -1, column: int = -1) -> None: super().__init__(line, column) self.is_noreturn = is_noreturn + self.ambiguous = False def can_be_true_default(self) -> bool: return False @@ -751,6 +862,8 @@ class ErasedType(ProperType): it is ignored during type inference. """ + __slots__ = () + def accept(self, visitor: 'TypeVisitor[T]') -> T: return visitor.visit_erased_type(self) @@ -761,7 +874,9 @@ class DeletedType(ProperType): These can be used as lvalues but not rvalues. """ - source: Optional[str] = "" # May be None; name that generated this value + __slots__ = ('source',) + + source: Optional[str] # May be None; name that generated this value def __init__(self, source: Optional[str] = None, line: int = -1, column: int = -1) -> None: super().__init__(line, column) @@ -921,9 +1036,7 @@ class FunctionLike(ProperType): def __init__(self, line: int = -1, column: int = -1) -> None: super().__init__(line, column) self.can_be_false = False - if TYPE_CHECKING: # we don't want a runtime None value - # Corresponding instance type (e.g. builtins.type) - self.fallback = cast(Instance, None) + self.fallback: Instance @abstractmethod def is_type_obj(self) -> bool: pass @@ -1024,9 +1137,16 @@ def __init__(self, # after serialization, but it is useful in error messages. # TODO: decide how to add more info here (file, line, column) # without changing interface hash. - self.def_extras = {'first_arg': definition.arguments[0].variable.name - if definition.arg_names and definition.info and - not definition.is_static else None} + self.def_extras = { + 'first_arg': ( + definition.arguments[0].variable.name + if (getattr(definition, 'arguments', None) + and definition.arg_names + and definition.info + and not definition.is_static) + else None + ), + } else: self.def_extras = {} self.type_guard = type_guard @@ -1126,7 +1246,7 @@ def max_possible_positional_args(self) -> int: return sys.maxsize return sum([kind.is_positional() for kind in self.arg_kinds]) - def formal_arguments(self, include_star_args: bool = False) -> Iterator[FormalArgument]: + def formal_arguments(self, include_star_args: bool = False) -> List[FormalArgument]: """Yields the formal arguments corresponding to this callable, ignoring *arg and **kwargs. To handle *args and **kwargs, use the 'callable.var_args' and 'callable.kw_args' fields, @@ -1134,6 +1254,7 @@ def formal_arguments(self, include_star_args: bool = False) -> Iterator[FormalAr If you really want to include star args in the yielded output, set the 'include_star_args' parameter to 'True'.""" + args = [] done_with_positional = False for i in range(len(self.arg_types)): kind = self.arg_kinds[i] @@ -1144,11 +1265,14 @@ def formal_arguments(self, include_star_args: bool = False) -> Iterator[FormalAr required = kind.is_required() pos = None if done_with_positional else i - yield FormalArgument( + arg = FormalArgument( self.arg_names[i], pos, self.arg_types[i], - required) + required + ) + args.append(arg) + return args def argument_by_name(self, name: Optional[str]) -> Optional[FormalArgument]: if name is None: @@ -1210,6 +1334,27 @@ def type_var_ids(self) -> List[TypeVarId]: a.append(tv.id) return a + def param_spec(self) -> Optional[ParamSpecType]: + """Return ParamSpec if callable can be called with one. + + A Callable accepting ParamSpec P args (*args, **kwargs) must have the + two final parameters like this: *args: P.args, **kwargs: P.kwargs. + """ + if len(self.arg_types) < 2: + return None + if self.arg_kinds[-2] != ARG_STAR or self.arg_kinds[-1] != ARG_STAR2: + return None + arg_type = self.arg_types[-2] + if not isinstance(arg_type, ParamSpecType): + return None + return ParamSpecType(arg_type.name, arg_type.fullname, arg_type.id, ParamSpecFlavor.BARE, + arg_type.upper_bound) + + def expand_param_spec(self, c: 'CallableType') -> 'CallableType': + return self.copy_modified(arg_types=self.arg_types[:-2] + c.arg_types, + arg_kinds=self.arg_kinds[:-2] + c.arg_kinds, + arg_names=self.arg_names[:-2] + c.arg_names) + def __hash__(self) -> int: return hash((self.ret_type, self.is_type_obj(), self.is_ellipsis_args, self.name, @@ -1277,6 +1422,8 @@ class Overloaded(FunctionLike): implementation. """ + __slots__ = ('_items', 'fallback') + _items: List[CallableType] # Must not be empty def __init__(self, items: List[CallableType]) -> None: @@ -1345,9 +1492,11 @@ class TupleType(ProperType): implicit: If True, derived from a tuple expression (t,....) instead of Tuple[t, ...] """ + __slots__ = ('items', 'partial_fallback', 'implicit') + items: List[Type] partial_fallback: Instance - implicit = False + implicit: bool def __init__(self, items: List[Type], fallback: Instance, line: int = -1, column: int = -1, implicit: bool = False) -> None: @@ -1420,6 +1569,8 @@ class TypedDictType(ProperType): TODO: The fallback structure is perhaps overly complicated. """ + __slots__ = ('items', 'required_keys', 'fallback') + items: "OrderedDict[str, Type]" # item_name -> item_type required_keys: Set[str] fallback: Instance @@ -1557,6 +1708,9 @@ class RawExpressionType(ProperType): ], ) """ + + __slots__ = ('literal_value', 'base_type_name', 'note') + def __init__(self, literal_value: Optional[LiteralValue], base_type_name: str, @@ -1684,6 +1838,8 @@ class StarType(ProperType): This is not a real type but a syntactic AST construct. """ + __slots__ = ('type',) + type: Type def __init__(self, type: Type, line: int = -1, column: int = -1) -> None: @@ -1789,12 +1945,14 @@ class PartialType(ProperType): x = 1 # Infer actual type int for x """ + __slots__ = ('type', 'var', 'value_type') + # None for the 'None' partial type; otherwise a generic class - type: Optional[mypy.nodes.TypeInfo] = None + type: Optional[mypy.nodes.TypeInfo] var: mypy.nodes.Var # For partial defaultdict[K, V], the type V (K is unknown). If V is generic, # the type argument is Any and will be replaced later. - value_type: Optional[Instance] = None + value_type: Optional[Instance] def __init__(self, type: 'Optional[mypy.nodes.TypeInfo]', @@ -1817,6 +1975,8 @@ class EllipsisType(ProperType): A semantically analyzed type will never have ellipsis types. """ + __slots__ = () + def accept(self, visitor: 'TypeVisitor[T]') -> T: assert isinstance(visitor, SyntheticTypeVisitor) return visitor.visit_ellipsis_type(self) @@ -1853,6 +2013,8 @@ class TypeType(ProperType): assumption). """ + __slots__ = ('item',) + # This can't be everything, but it can be a class reference, # a generic class instance, a union, Any, a type variable... item: ProperType @@ -1912,6 +2074,8 @@ class str(Sequence[str]): ... exist. """ + __slots__ = ('fullname', 'args') + def __init__(self, fullname: Optional[str], args: List[Type], line: int) -> None: super().__init__(line) self.fullname = fullname # Must be a valid full name of an actual node (or None). @@ -2055,10 +2219,25 @@ def visit_type_var(self, t: TypeVarType) -> str: s += '(upper_bound={})'.format(t.upper_bound.accept(self)) return s + def visit_param_spec(self, t: ParamSpecType) -> str: + if t.name is None: + # Anonymous type variable type (only numeric id). + s = f'`{t.id}' + else: + # Named type variable type. + s = f'{t.name_with_suffix()}`{t.id}' + return s + def visit_callable_type(self, t: CallableType) -> str: + param_spec = t.param_spec() + if param_spec is not None: + num_skip = 2 + else: + num_skip = 0 + s = '' bare_asterisk = False - for i in range(len(t.arg_types)): + for i in range(len(t.arg_types) - num_skip): if s != '': s += ', ' if t.arg_kinds[i].is_named() and not bare_asterisk: @@ -2075,6 +2254,12 @@ def visit_callable_type(self, t: CallableType) -> str: if t.arg_kinds[i].is_optional(): s += ' =' + if param_spec is not None: + n = param_spec.name + if s: + s += ', ' + s += f'*{n}.args, **{n}.kwargs' + s = '({})'.format(s) if not isinstance(get_proper_type(t.ret_type), NoneType): @@ -2096,8 +2281,8 @@ def visit_callable_type(self, t: CallableType) -> str: else: vs.append(var.name) else: - # For other TypeVarLikeTypes, just use the repr - vs.append(repr(var)) + # For other TypeVarLikeTypes, just use the name + vs.append(var.name) s = '{} {}'.format('[{}]'.format(', '.join(vs)), s) return 'def {}'.format(s) @@ -2283,6 +2468,7 @@ def flatten_nested_unions(types: Iterable[Type], flat_items: List[Type] = [] if handle_type_alias_type: types = get_proper_types(types) + # TODO: avoid duplicate types in unions (e.g. using hash) for tp in types: if isinstance(tp, ProperType) and isinstance(tp, UnionType): flat_items.extend(flatten_nested_unions(tp.items, @@ -2307,6 +2493,16 @@ def union_items(typ: Type) -> List[ProperType]: return [typ] +def is_union_with_any(tp: Type) -> bool: + """Is this a union with Any or a plain Any type?""" + tp = get_proper_type(tp) + if isinstance(tp, AnyType): + return True + if not isinstance(tp, UnionType): + return False + return any(is_union_with_any(t) for t in get_proper_types(tp.items)) + + def is_generic_instance(tp: Type) -> bool: tp = get_proper_type(tp) return isinstance(tp, Instance) and bool(tp.args) @@ -2345,3 +2541,15 @@ def is_literal_type(typ: ProperType, fallback_fullname: str, value: LiteralValue for key, obj in names.items() if isinstance(obj, type) and issubclass(obj, Type) and obj is not Type } + + +def callable_with_ellipsis(any_type: AnyType, + ret_type: Type, + fallback: Instance) -> CallableType: + """Construct type Callable[..., ret_type].""" + return CallableType([any_type, any_type], + [ARG_STAR, ARG_STAR2], + [None, None], + ret_type=ret_type, + fallback=fallback, + is_ellipsis_args=True) diff --git a/mypy/typeshed/stdlib/@python2/__builtin__.pyi b/mypy/typeshed/stdlib/@python2/__builtin__.pyi index ebe9cdd95038..fad8b2b4e7d8 100644 --- a/mypy/typeshed/stdlib/@python2/__builtin__.pyi +++ b/mypy/typeshed/stdlib/@python2/__builtin__.pyi @@ -121,7 +121,7 @@ class type(object): def __new__(cls, name: str, bases: Tuple[type, ...], namespace: Dict[str, Any]) -> type: ... def __call__(self, *args: Any, **kwds: Any) -> Any: ... def __subclasses__(self: _TT) -> List[_TT]: ... - # Note: the documentation doesnt specify what the return type is, the standard + # Note: the documentation doesn't specify what the return type is, the standard # implementation seems to be returning a list. def mro(self) -> List[type]: ... def __instancecheck__(self, instance: Any) -> bool: ... @@ -850,13 +850,18 @@ def format(__value: object, __format_spec: str = ...) -> str: ... # TODO unicod @overload def getattr(__o: Any, name: Text) -> Any: ... -# While technically covered by the last overload, spelling out the types for None and bool -# help mypy out in some tricky situations involving type context (aka bidirectional inference) +# While technically covered by the last overload, spelling out the types for None, bool +# and basic containers help mypy out in some tricky situations involving type context +# (aka bidirectional inference) @overload def getattr(__o: Any, name: Text, __default: None) -> Any | None: ... @overload def getattr(__o: Any, name: Text, __default: bool) -> Any | bool: ... @overload +def getattr(__o: object, name: str, __default: list[Any]) -> Any | list[Any]: ... +@overload +def getattr(__o: object, name: str, __default: dict[Any, Any]) -> Any | dict[Any, Any]: ... +@overload def getattr(__o: Any, name: Text, __default: _T) -> Any | _T: ... def globals() -> Dict[str, Any]: ... def hasattr(__obj: Any, __name: Text) -> bool: ... @@ -952,7 +957,7 @@ def min(__iterable: Iterable[_T], *, key: Callable[[_T], Any] = ...) -> _T: ... @overload def next(__i: Iterator[_T]) -> _T: ... @overload -def next(__i: Iterator[_T], default: _VT) -> _T | _VT: ... +def next(__i: Iterator[_T], __default: _VT) -> _T | _VT: ... def oct(__number: int | _SupportsIndex) -> str: ... def open(name: unicode | int, mode: unicode = ..., buffering: int = ...) -> BinaryIO: ... def ord(__c: Text | bytes) -> int: ... diff --git a/mypy/typeshed/stdlib/@python2/ast.pyi b/mypy/typeshed/stdlib/@python2/ast.pyi index ec370e1a6c08..b86e38dce4c5 100644 --- a/mypy/typeshed/stdlib/@python2/ast.pyi +++ b/mypy/typeshed/stdlib/@python2/ast.pyi @@ -4,10 +4,9 @@ # from _ast below when loaded in an unorthodox way by the Dropbox # internal Bazel integration. import typing as _typing -from typing import Any, Iterator - from _ast import * from _ast import AST, Module +from typing import Any, Iterator def parse(source: str | unicode, filename: str | unicode = ..., mode: str | unicode = ...) -> Module: ... def copy_location(new_node: AST, old_node: AST) -> AST: ... diff --git a/mypy/typeshed/stdlib/@python2/builtins.pyi b/mypy/typeshed/stdlib/@python2/builtins.pyi index ebe9cdd95038..fad8b2b4e7d8 100644 --- a/mypy/typeshed/stdlib/@python2/builtins.pyi +++ b/mypy/typeshed/stdlib/@python2/builtins.pyi @@ -121,7 +121,7 @@ class type(object): def __new__(cls, name: str, bases: Tuple[type, ...], namespace: Dict[str, Any]) -> type: ... def __call__(self, *args: Any, **kwds: Any) -> Any: ... def __subclasses__(self: _TT) -> List[_TT]: ... - # Note: the documentation doesnt specify what the return type is, the standard + # Note: the documentation doesn't specify what the return type is, the standard # implementation seems to be returning a list. def mro(self) -> List[type]: ... def __instancecheck__(self, instance: Any) -> bool: ... @@ -850,13 +850,18 @@ def format(__value: object, __format_spec: str = ...) -> str: ... # TODO unicod @overload def getattr(__o: Any, name: Text) -> Any: ... -# While technically covered by the last overload, spelling out the types for None and bool -# help mypy out in some tricky situations involving type context (aka bidirectional inference) +# While technically covered by the last overload, spelling out the types for None, bool +# and basic containers help mypy out in some tricky situations involving type context +# (aka bidirectional inference) @overload def getattr(__o: Any, name: Text, __default: None) -> Any | None: ... @overload def getattr(__o: Any, name: Text, __default: bool) -> Any | bool: ... @overload +def getattr(__o: object, name: str, __default: list[Any]) -> Any | list[Any]: ... +@overload +def getattr(__o: object, name: str, __default: dict[Any, Any]) -> Any | dict[Any, Any]: ... +@overload def getattr(__o: Any, name: Text, __default: _T) -> Any | _T: ... def globals() -> Dict[str, Any]: ... def hasattr(__obj: Any, __name: Text) -> bool: ... @@ -952,7 +957,7 @@ def min(__iterable: Iterable[_T], *, key: Callable[[_T], Any] = ...) -> _T: ... @overload def next(__i: Iterator[_T]) -> _T: ... @overload -def next(__i: Iterator[_T], default: _VT) -> _T | _VT: ... +def next(__i: Iterator[_T], __default: _VT) -> _T | _VT: ... def oct(__number: int | _SupportsIndex) -> str: ... def open(name: unicode | int, mode: unicode = ..., buffering: int = ...) -> BinaryIO: ... def ord(__c: Text | bytes) -> int: ... diff --git a/mypy/typeshed/stdlib/@python2/ctypes/__init__.pyi b/mypy/typeshed/stdlib/@python2/ctypes/__init__.pyi index 149e9f281647..33184cc2ff88 100644 --- a/mypy/typeshed/stdlib/@python2/ctypes/__init__.pyi +++ b/mypy/typeshed/stdlib/@python2/ctypes/__init__.pyi @@ -166,7 +166,7 @@ def POINTER(type: Type[_CT]) -> Type[pointer[_CT]]: ... # ctypes._Pointer in that it is the base class for all pointer types. Unlike the real _Pointer, # it can be instantiated directly (to mimic the behavior of the real pointer function). class pointer(Generic[_CT], _PointerLike, _CData): - _type_: ClassVar[Type[_CT]] = ... + _type_: Type[_CT] = ... contents: _CT = ... def __init__(self, arg: _CT = ...) -> None: ... @overload @@ -262,8 +262,8 @@ class BigEndianStructure(Structure): ... class LittleEndianStructure(Structure): ... class Array(Generic[_CT], _CData): - _length_: ClassVar[int] = ... - _type_: ClassVar[Type[_CT]] = ... + _length_: int = ... + _type_: Type[_CT] = ... raw: bytes = ... # Note: only available if _CT == c_char value: Any = ... # Note: bytes if _CT == c_char, Text if _CT == c_wchar, unavailable otherwise # TODO These methods cannot be annotated correctly at the moment. diff --git a/mypy/typeshed/stdlib/@python2/logging/__init__.pyi b/mypy/typeshed/stdlib/@python2/logging/__init__.pyi index 9cca9b51f753..f981e2400624 100644 --- a/mypy/typeshed/stdlib/@python2/logging/__init__.pyi +++ b/mypy/typeshed/stdlib/@python2/logging/__init__.pyi @@ -1,8 +1,24 @@ import threading -from _typeshed import StrPath +from _typeshed import StrPath, SupportsWrite from time import struct_time from types import FrameType, TracebackType -from typing import IO, Any, Callable, Dict, List, Mapping, MutableMapping, Optional, Sequence, Text, Tuple, Union, overload +from typing import ( + IO, + Any, + Callable, + Dict, + Generic, + List, + Mapping, + MutableMapping, + Optional, + Sequence, + Text, + Tuple, + TypeVar, + Union, + overload, +) _SysExcInfoType = Union[Tuple[type, BaseException, Optional[TracebackType]], Tuple[None, None, None]] _ExcInfoType = Union[None, bool, _SysExcInfoType] @@ -159,10 +175,12 @@ class LogRecord: ) -> None: ... def getMessage(self) -> str: ... -class LoggerAdapter: - logger: Logger +_L = TypeVar("_L", Logger, LoggerAdapter[Logger], LoggerAdapter[Any]) + +class LoggerAdapter(Generic[_L]): + logger: _L extra: Mapping[str, Any] - def __init__(self, logger: Logger, extra: Mapping[str, Any]) -> None: ... + def __init__(self, logger: _L, extra: Mapping[str, Any]) -> None: ... def process(self, msg: Any, kwargs: MutableMapping[str, Any]) -> Tuple[Any, MutableMapping[str, Any]]: ... def debug( self, msg: Any, *args: Any, exc_info: _ExcInfoType = ..., extra: Dict[str, Any] | None = ..., **kwargs: Any @@ -227,9 +245,14 @@ def shutdown(handlerList: Sequence[Any] = ...) -> None: ... # handlerList is un def setLoggerClass(klass: type) -> None: ... def captureWarnings(capture: bool) -> None: ... -class StreamHandler(Handler): - stream: IO[str] # undocumented - def __init__(self, stream: IO[str] | None = ...) -> None: ... +_StreamT = TypeVar("_StreamT", bound=SupportsWrite[str]) + +class StreamHandler(Handler, Generic[_StreamT]): + stream: _StreamT # undocumented + @overload + def __init__(self: StreamHandler[IO[str]], stream: None = ...) -> None: ... + @overload + def __init__(self: StreamHandler[_StreamT], stream: _StreamT) -> None: ... class FileHandler(StreamHandler): baseFilename: str # undocumented diff --git a/mypy/typeshed/stdlib/@python2/sqlite3/dbapi2.pyi b/mypy/typeshed/stdlib/@python2/sqlite3/dbapi2.pyi index fadfcc8f5884..023a0506f4aa 100644 --- a/mypy/typeshed/stdlib/@python2/sqlite3/dbapi2.pyi +++ b/mypy/typeshed/stdlib/@python2/sqlite3/dbapi2.pyi @@ -135,7 +135,7 @@ class Cursor(Iterator[Any]): description: Any lastrowid: Any row_factory: Any - rowcount: Any + rowcount: int # TODO: Cursor class accepts exactly 1 argument # required type is sqlite3.Connection (which is imported as _Connection) # however, the name of the __init__ variable is unknown diff --git a/mypy/typeshed/stdlib/@python2/warnings.pyi b/mypy/typeshed/stdlib/@python2/warnings.pyi index e3540ed60b0c..0d187bf70c33 100644 --- a/mypy/typeshed/stdlib/@python2/warnings.pyi +++ b/mypy/typeshed/stdlib/@python2/warnings.pyi @@ -1,9 +1,8 @@ +from _warnings import warn as warn, warn_explicit as warn_explicit from types import ModuleType, TracebackType from typing import List, TextIO, Type, overload from typing_extensions import Literal -from _warnings import warn as warn, warn_explicit as warn_explicit - def showwarning( message: Warning | str, category: Type[Warning], filename: str, lineno: int, file: TextIO | None = ..., line: str | None = ... ) -> None: ... diff --git a/mypy/typeshed/stdlib/_codecs.pyi b/mypy/typeshed/stdlib/_codecs.pyi index aa30309cb53c..5e4a9ad6da3d 100644 --- a/mypy/typeshed/stdlib/_codecs.pyi +++ b/mypy/typeshed/stdlib/_codecs.pyi @@ -16,51 +16,51 @@ def lookup_error(__name: str) -> _Handler: ... def decode(obj: Any, encoding: str = ..., errors: str | None = ...) -> Any: ... def encode(obj: Any, encoding: str = ..., errors: str | None = ...) -> Any: ... def charmap_build(__map: str) -> _MapT: ... -def ascii_decode(__data: bytes, __errors: str | None = ...) -> Tuple[str, int]: ... -def ascii_encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... -def charmap_decode(__data: bytes, __errors: str | None = ..., __mapping: _MapT | None = ...) -> Tuple[str, int]: ... -def charmap_encode(__str: str, __errors: str | None = ..., __mapping: _MapT | None = ...) -> Tuple[bytes, int]: ... -def escape_decode(__data: str | bytes, __errors: str | None = ...) -> Tuple[str, int]: ... -def escape_encode(__data: bytes, __errors: str | None = ...) -> Tuple[bytes, int]: ... -def latin_1_decode(__data: bytes, __errors: str | None = ...) -> Tuple[str, int]: ... -def latin_1_encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... -def raw_unicode_escape_decode(__data: str | bytes, __errors: str | None = ...) -> Tuple[str, int]: ... -def raw_unicode_escape_encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... -def readbuffer_encode(__data: str | bytes, __errors: str | None = ...) -> Tuple[bytes, int]: ... -def unicode_escape_decode(__data: str | bytes, __errors: str | None = ...) -> Tuple[str, int]: ... -def unicode_escape_encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... +def ascii_decode(__data: bytes, __errors: str | None = ...) -> tuple[str, int]: ... +def ascii_encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... +def charmap_decode(__data: bytes, __errors: str | None = ..., __mapping: _MapT | None = ...) -> tuple[str, int]: ... +def charmap_encode(__str: str, __errors: str | None = ..., __mapping: _MapT | None = ...) -> tuple[bytes, int]: ... +def escape_decode(__data: str | bytes, __errors: str | None = ...) -> tuple[str, int]: ... +def escape_encode(__data: bytes, __errors: str | None = ...) -> tuple[bytes, int]: ... +def latin_1_decode(__data: bytes, __errors: str | None = ...) -> tuple[str, int]: ... +def latin_1_encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... +def raw_unicode_escape_decode(__data: str | bytes, __errors: str | None = ...) -> tuple[str, int]: ... +def raw_unicode_escape_encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... +def readbuffer_encode(__data: str | bytes, __errors: str | None = ...) -> tuple[bytes, int]: ... +def unicode_escape_decode(__data: str | bytes, __errors: str | None = ...) -> tuple[str, int]: ... +def unicode_escape_encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... if sys.version_info < (3, 8): - def unicode_internal_decode(__obj: str | bytes, __errors: str | None = ...) -> Tuple[str, int]: ... - def unicode_internal_encode(__obj: str | bytes, __errors: str | None = ...) -> Tuple[bytes, int]: ... + def unicode_internal_decode(__obj: str | bytes, __errors: str | None = ...) -> tuple[str, int]: ... + def unicode_internal_encode(__obj: str | bytes, __errors: str | None = ...) -> tuple[bytes, int]: ... -def utf_16_be_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> Tuple[str, int]: ... -def utf_16_be_encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... -def utf_16_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> Tuple[str, int]: ... -def utf_16_encode(__str: str, __errors: str | None = ..., __byteorder: int = ...) -> Tuple[bytes, int]: ... +def utf_16_be_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> tuple[str, int]: ... +def utf_16_be_encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... +def utf_16_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> tuple[str, int]: ... +def utf_16_encode(__str: str, __errors: str | None = ..., __byteorder: int = ...) -> tuple[bytes, int]: ... def utf_16_ex_decode( __data: bytes, __errors: str | None = ..., __byteorder: int = ..., __final: int = ... -) -> Tuple[str, int, int]: ... -def utf_16_le_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> Tuple[str, int]: ... -def utf_16_le_encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... -def utf_32_be_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> Tuple[str, int]: ... -def utf_32_be_encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... -def utf_32_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> Tuple[str, int]: ... -def utf_32_encode(__str: str, __errors: str | None = ..., __byteorder: int = ...) -> Tuple[bytes, int]: ... +) -> tuple[str, int, int]: ... +def utf_16_le_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> tuple[str, int]: ... +def utf_16_le_encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... +def utf_32_be_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> tuple[str, int]: ... +def utf_32_be_encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... +def utf_32_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> tuple[str, int]: ... +def utf_32_encode(__str: str, __errors: str | None = ..., __byteorder: int = ...) -> tuple[bytes, int]: ... def utf_32_ex_decode( __data: bytes, __errors: str | None = ..., __byteorder: int = ..., __final: int = ... -) -> Tuple[str, int, int]: ... -def utf_32_le_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> Tuple[str, int]: ... -def utf_32_le_encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... -def utf_7_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> Tuple[str, int]: ... -def utf_7_encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... -def utf_8_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> Tuple[str, int]: ... -def utf_8_encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... +) -> tuple[str, int, int]: ... +def utf_32_le_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> tuple[str, int]: ... +def utf_32_le_encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... +def utf_7_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> tuple[str, int]: ... +def utf_7_encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... +def utf_8_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> tuple[str, int]: ... +def utf_8_encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... if sys.platform == "win32": - def mbcs_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> Tuple[str, int]: ... - def mbcs_encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... - def code_page_decode(__codepage: int, __data: bytes, __errors: str | None = ..., __final: int = ...) -> Tuple[str, int]: ... - def code_page_encode(__code_page: int, __str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... - def oem_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> Tuple[str, int]: ... - def oem_encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... + def mbcs_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> tuple[str, int]: ... + def mbcs_encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... + def code_page_decode(__codepage: int, __data: bytes, __errors: str | None = ..., __final: int = ...) -> tuple[str, int]: ... + def code_page_encode(__code_page: int, __str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... + def oem_decode(__data: bytes, __errors: str | None = ..., __final: int = ...) -> tuple[str, int]: ... + def oem_encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... diff --git a/mypy/typeshed/stdlib/_collections_abc.pyi b/mypy/typeshed/stdlib/_collections_abc.pyi index 27d5234432f3..223b5fb8d62e 100644 --- a/mypy/typeshed/stdlib/_collections_abc.pyi +++ b/mypy/typeshed/stdlib/_collections_abc.pyi @@ -1,3 +1,5 @@ +import sys +from types import MappingProxyType from typing import ( AbstractSet as Set, AsyncGenerator as AsyncGenerator, @@ -10,6 +12,7 @@ from typing import ( Container as Container, Coroutine as Coroutine, Generator as Generator, + Generic, Hashable as Hashable, ItemsView as ItemsView, Iterable as Iterable, @@ -23,8 +26,10 @@ from typing import ( Reversible as Reversible, Sequence as Sequence, Sized as Sized, + TypeVar, ValuesView as ValuesView, ) +from typing_extensions import final __all__ = [ "Awaitable", @@ -53,3 +58,21 @@ __all__ = [ "MutableSequence", "ByteString", ] + +_KT_co = TypeVar("_KT_co", covariant=True) # Key type covariant containers. +_VT_co = TypeVar("_VT_co", covariant=True) # Value type covariant containers. + +@final +class dict_keys(KeysView[_KT_co], Generic[_KT_co, _VT_co]): # undocumented + if sys.version_info >= (3, 10): + mapping: MappingProxyType[_KT_co, _VT_co] + +@final +class dict_values(ValuesView[_VT_co], Generic[_KT_co, _VT_co]): # undocumented + if sys.version_info >= (3, 10): + mapping: MappingProxyType[_KT_co, _VT_co] + +@final +class dict_items(ItemsView[_KT_co, _VT_co], Generic[_KT_co, _VT_co]): # undocumented + if sys.version_info >= (3, 10): + mapping: MappingProxyType[_KT_co, _VT_co] diff --git a/mypy/typeshed/stdlib/_compat_pickle.pyi b/mypy/typeshed/stdlib/_compat_pickle.pyi index ba6c88a03035..76aba3020321 100644 --- a/mypy/typeshed/stdlib/_compat_pickle.pyi +++ b/mypy/typeshed/stdlib/_compat_pickle.pyi @@ -1,10 +1,10 @@ from typing import Tuple IMPORT_MAPPING: dict[str, str] -NAME_MAPPING: dict[Tuple[str, str], Tuple[str, str]] +NAME_MAPPING: dict[tuple[str, str], tuple[str, str]] PYTHON2_EXCEPTIONS: Tuple[str, ...] MULTIPROCESSING_EXCEPTIONS: Tuple[str, ...] REVERSE_IMPORT_MAPPING: dict[str, str] -REVERSE_NAME_MAPPING: dict[Tuple[str, str], Tuple[str, str]] +REVERSE_NAME_MAPPING: dict[tuple[str, str], tuple[str, str]] PYTHON3_OSERROR_EXCEPTIONS: Tuple[str, ...] PYTHON3_IMPORTERROR_EXCEPTIONS: Tuple[str, ...] diff --git a/mypy/typeshed/stdlib/_curses.pyi b/mypy/typeshed/stdlib/_curses.pyi index e4fc2a8f68f0..d2eb1e1a4efb 100644 --- a/mypy/typeshed/stdlib/_curses.pyi +++ b/mypy/typeshed/stdlib/_curses.pyi @@ -1,5 +1,6 @@ import sys -from typing import IO, Any, BinaryIO, NamedTuple, Tuple, Union, overload +from _typeshed import SupportsRead +from typing import IO, Any, NamedTuple, Union, overload _chtype = Union[str, bytes, int] @@ -273,7 +274,7 @@ def baudrate() -> int: ... def beep() -> None: ... def can_change_color() -> bool: ... def cbreak(__flag: bool = ...) -> None: ... -def color_content(__color_number: int) -> Tuple[int, int, int]: ... +def color_content(__color_number: int) -> tuple[int, int, int]: ... # Changed in Python 3.8.8 and 3.9.2 if sys.version_info >= (3, 8): @@ -293,9 +294,14 @@ def erasechar() -> bytes: ... def filter() -> None: ... def flash() -> None: ... def flushinp() -> None: ... -def getmouse() -> Tuple[int, int, int, int, int]: ... -def getsyx() -> Tuple[int, int]: ... -def getwin(__file: BinaryIO) -> _CursesWindow: ... + +if sys.version_info >= (3, 9): + def get_escdelay() -> int: ... + def get_tabsize() -> int: ... + +def getmouse() -> tuple[int, int, int, int, int]: ... +def getsyx() -> tuple[int, int]: ... +def getwin(__file: SupportsRead[bytes]) -> _CursesWindow: ... def halfdelay(__tenths: int) -> None: ... def has_colors() -> bool: ... @@ -316,7 +322,7 @@ def killchar() -> bytes: ... def longname() -> bytes: ... def meta(__yes: bool) -> None: ... def mouseinterval(__interval: int) -> None: ... -def mousemask(__newmask: int) -> Tuple[int, int]: ... +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: ... @@ -326,7 +332,7 @@ def noecho() -> None: ... def nonl() -> None: ... def noqiflush() -> None: ... def noraw() -> None: ... -def pair_content(__pair_number: int) -> Tuple[int, int]: ... +def pair_content(__pair_number: int) -> tuple[int, int]: ... def pair_number(__attr: int) -> int: ... def putp(__string: bytes) -> None: ... def qiflush(__flag: bool = ...) -> None: ... @@ -337,6 +343,11 @@ def resetty() -> None: ... def resize_term(__nlines: int, __ncols: int) -> None: ... def resizeterm(__nlines: int, __ncols: int) -> None: ... def savetty() -> None: ... + +if sys.version_info >= (3, 9): + def set_escdelay(__ms: int) -> None: ... + def set_tabsize(__size: int) -> None: ... + def setsyx(__y: int, __x: int) -> None: ... def setupterm(term: str | None = ..., fd: int = ...) -> None: ... def start_color() -> None: ... @@ -344,7 +355,7 @@ def termattrs() -> int: ... def termname() -> bytes: ... def tigetflag(__capname: str) -> int: ... def tigetnum(__capname: str) -> int: ... -def tigetstr(__capname: str) -> bytes: ... +def tigetstr(__capname: str) -> bytes | None: ... def tparm( __str: bytes, __i1: int = ..., @@ -362,7 +373,7 @@ def unctrl(__ch: _chtype) -> bytes: ... def unget_wch(__ch: int | str) -> None: ... def ungetch(__ch: _chtype) -> None: ... def ungetmouse(__id: int, __x: int, __y: int, __z: int, __bstate: int) -> None: ... -def update_lines_cols() -> int: ... +def update_lines_cols() -> None: ... def use_default_colors() -> None: ... def use_env(__flag: bool) -> None: ... @@ -427,8 +438,8 @@ class _CursesWindow: def echochar(self, __ch: _chtype, __attr: int = ...) -> None: ... def enclose(self, __y: int, __x: int) -> bool: ... def erase(self) -> None: ... - def getbegyx(self) -> Tuple[int, int]: ... - def getbkgd(self) -> Tuple[int, int]: ... + def getbegyx(self) -> tuple[int, int]: ... + def getbkgd(self) -> tuple[int, int]: ... @overload def getch(self) -> int: ... @overload @@ -441,17 +452,17 @@ class _CursesWindow: def getkey(self) -> str: ... @overload def getkey(self, y: int, x: int) -> str: ... - def getmaxyx(self) -> Tuple[int, int]: ... - def getparyx(self) -> Tuple[int, int]: ... + def getmaxyx(self) -> tuple[int, int]: ... + def getparyx(self) -> tuple[int, int]: ... @overload - def getstr(self) -> _chtype: ... + def getstr(self) -> bytes: ... @overload - def getstr(self, n: int) -> _chtype: ... + def getstr(self, n: int) -> bytes: ... @overload - def getstr(self, y: int, x: int) -> _chtype: ... + def getstr(self, y: int, x: int) -> bytes: ... @overload - def getstr(self, y: int, x: int, n: int) -> _chtype: ... - def getyx(self) -> Tuple[int, int]: ... + def getstr(self, y: int, x: int, n: int) -> bytes: ... + def getyx(self) -> tuple[int, int]: ... @overload def hline(self, ch: _chtype, n: int) -> None: ... @overload @@ -460,9 +471,9 @@ class _CursesWindow: def idlok(self, yes: bool) -> None: ... def immedok(self, flag: bool) -> None: ... @overload - def inch(self) -> _chtype: ... + def inch(self) -> int: ... @overload - def inch(self, y: int, x: int) -> _chtype: ... + def inch(self, y: int, x: int) -> int: ... @overload def insch(self, ch: _chtype, attr: int = ...) -> None: ... @overload @@ -478,9 +489,9 @@ class _CursesWindow: @overload def insstr(self, y: int, x: int, str: str, attr: int = ...) -> None: ... @overload - def instr(self, n: int = ...) -> _chtype: ... + def instr(self, n: int = ...) -> bytes: ... @overload - def instr(self, y: int, x: int, n: int = ...) -> _chtype: ... + def instr(self, y: int, x: int, n: int = ...) -> bytes: ... def is_linetouched(self, __line: int) -> bool: ... def is_wintouched(self) -> bool: ... def keypad(self, yes: bool) -> None: ... diff --git a/mypy/typeshed/stdlib/_json.pyi b/mypy/typeshed/stdlib/_json.pyi index f807a85b93f4..7395288afdbc 100644 --- a/mypy/typeshed/stdlib/_json.pyi +++ b/mypy/typeshed/stdlib/_json.pyi @@ -1,4 +1,4 @@ -from typing import Any, Callable, Tuple +from typing import Any, Callable class make_encoder: sort_keys: Any @@ -32,7 +32,7 @@ class make_scanner: strict: bool # TODO: 'context' needs the attrs above (ducktype), but not __call__. def __init__(self, context: make_scanner) -> None: ... - def __call__(self, string: str, index: int) -> Tuple[Any, int]: ... + def __call__(self, string: str, index: int) -> tuple[Any, int]: ... def encode_basestring_ascii(s: str) -> str: ... -def scanstring(string: str, end: int, strict: bool = ...) -> Tuple[str, int]: ... +def scanstring(string: str, end: int, strict: bool = ...) -> tuple[str, int]: ... diff --git a/mypy/typeshed/stdlib/_markupbase.pyi b/mypy/typeshed/stdlib/_markupbase.pyi index d8bc79f34e8c..368d32bd5b4c 100644 --- a/mypy/typeshed/stdlib/_markupbase.pyi +++ b/mypy/typeshed/stdlib/_markupbase.pyi @@ -1,8 +1,6 @@ -from typing import Tuple - class ParserBase: def __init__(self) -> None: ... def error(self, message: str) -> None: ... def reset(self) -> None: ... - def getpos(self) -> Tuple[int, int]: ... + def getpos(self) -> tuple[int, int]: ... def unknown_decl(self, data: str) -> None: ... diff --git a/mypy/typeshed/stdlib/_osx_support.pyi b/mypy/typeshed/stdlib/_osx_support.pyi index f03c37d1011a..ce1fffc00e8c 100644 --- a/mypy/typeshed/stdlib/_osx_support.pyi +++ b/mypy/typeshed/stdlib/_osx_support.pyi @@ -30,4 +30,4 @@ def customize_config_vars(_config_vars: dict[str, str]) -> dict[str, str]: ... def customize_compiler(_config_vars: dict[str, str]) -> dict[str, str]: ... def get_platform_osx( _config_vars: dict[str, str], osname: _T, release: _K, machine: _V -) -> Tuple[str | _T, str | _K, str | _V]: ... +) -> tuple[str | _T, str | _K, str | _V]: ... diff --git a/mypy/typeshed/stdlib/_posixsubprocess.pyi b/mypy/typeshed/stdlib/_posixsubprocess.pyi index 05209ba05b9b..0eae723e7a67 100644 --- a/mypy/typeshed/stdlib/_posixsubprocess.pyi +++ b/mypy/typeshed/stdlib/_posixsubprocess.pyi @@ -1,8 +1,8 @@ # NOTE: These are incomplete! -from typing import Callable, Sequence, Tuple +from typing import Callable, Sequence -def cloexec_pipe() -> Tuple[int, int]: ... +def cloexec_pipe() -> tuple[int, int]: ... def fork_exec( args: Sequence[str], executable_list: Sequence[bytes], diff --git a/mypy/typeshed/stdlib/_socket.pyi b/mypy/typeshed/stdlib/_socket.pyi index 7945c662e820..846f64d5a433 100644 --- a/mypy/typeshed/stdlib/_socket.pyi +++ b/mypy/typeshed/stdlib/_socket.pyi @@ -325,6 +325,7 @@ if sys.platform == "linux" and sys.version_info >= (3, 7): if sys.platform == "linux" and sys.version_info >= (3, 9): CAN_J1939: int + CAN_RAW_JOIN_FILTERS: int J1939_MAX_UNICAST_ADDR: int J1939_IDLE_ADDR: int diff --git a/mypy/typeshed/stdlib/_thread.pyi b/mypy/typeshed/stdlib/_thread.pyi index 2425703121b5..2f4252981b68 100644 --- a/mypy/typeshed/stdlib/_thread.pyi +++ b/mypy/typeshed/stdlib/_thread.pyi @@ -2,6 +2,7 @@ import sys from threading import Thread from types import TracebackType from typing import Any, Callable, NoReturn, Optional, Tuple, Type +from typing_extensions import final error = RuntimeError @@ -9,6 +10,7 @@ def _count() -> int: ... _dangling: Any +@final class LockType: def acquire(self, blocking: bool = ..., timeout: float = ...) -> bool: ... def release(self) -> None: ... @@ -29,6 +31,7 @@ TIMEOUT_MAX: float if sys.version_info >= (3, 8): def get_native_id() -> int: ... # only available on some platforms + @final class _ExceptHookArgs(Tuple[Type[BaseException], Optional[BaseException], Optional[TracebackType], Optional[Thread]]): @property def exc_type(self) -> Type[BaseException]: ... diff --git a/mypy/typeshed/stdlib/_threading_local.pyi b/mypy/typeshed/stdlib/_threading_local.pyi index 461459d694dd..bab69a7c2e7d 100644 --- a/mypy/typeshed/stdlib/_threading_local.pyi +++ b/mypy/typeshed/stdlib/_threading_local.pyi @@ -1,11 +1,11 @@ -from typing import Any, Dict, Tuple +from typing import Any, Dict from weakref import ReferenceType localdict = Dict[Any, Any] class _localimpl: key: str - dicts: dict[int, Tuple[ReferenceType[Any], localdict]] + dicts: dict[int, tuple[ReferenceType[Any], localdict]] def __init__(self) -> None: ... def get_dict(self) -> localdict: ... def create_dict(self) -> localdict: ... diff --git a/mypy/typeshed/stdlib/_tkinter.pyi b/mypy/typeshed/stdlib/_tkinter.pyi index 378b04202c4f..e97edf5b4fae 100644 --- a/mypy/typeshed/stdlib/_tkinter.pyi +++ b/mypy/typeshed/stdlib/_tkinter.pyi @@ -1,5 +1,5 @@ from typing import Any -from typing_extensions import Literal +from typing_extensions import Literal, final # _tkinter is meant to be only used internally by tkinter, but some tkinter # functions e.g. return _tkinter.Tcl_Obj objects. Tcl_Obj represents a Tcl @@ -14,6 +14,7 @@ from typing_extensions import Literal # >>> text.tag_add('foo', '1.0', 'end') # >>> text.tag_ranges('foo') # (, ) +@final class Tcl_Obj: string: str # str(tclobj) returns this typename: str @@ -37,6 +38,7 @@ class TclError(Exception): ... # # eval always returns str because _tkinter_tkapp_eval_impl in _tkinter.c calls # Tkapp_UnicodeResult, and it returns a string when it succeeds. +@final class TkappType: # Please keep in sync with tkinter.Tk def call(self, __command: Any, *args: Any) -> Any: ... diff --git a/mypy/typeshed/stdlib/_tracemalloc.pyi b/mypy/typeshed/stdlib/_tracemalloc.pyi index 27637637f6c5..fd159dc586cb 100644 --- a/mypy/typeshed/stdlib/_tracemalloc.pyi +++ b/mypy/typeshed/stdlib/_tracemalloc.pyi @@ -1,12 +1,12 @@ import sys from tracemalloc import _FrameTupleT, _TraceTupleT -from typing import Sequence, Tuple +from typing import Sequence def _get_object_traceback(__obj: object) -> Sequence[_FrameTupleT] | None: ... def _get_traces() -> Sequence[_TraceTupleT]: ... def clear_traces() -> None: ... def get_traceback_limit() -> int: ... -def get_traced_memory() -> Tuple[int, int]: ... +def get_traced_memory() -> tuple[int, int]: ... def get_tracemalloc_memory() -> int: ... def is_tracing() -> bool: ... diff --git a/mypy/typeshed/stdlib/_typeshed/__init__.pyi b/mypy/typeshed/stdlib/_typeshed/__init__.pyi index 3f8978a64623..0d4c42afc285 100644 --- a/mypy/typeshed/stdlib/_typeshed/__init__.pyi +++ b/mypy/typeshed/stdlib/_typeshed/__init__.pyi @@ -3,10 +3,11 @@ # See the README.md file in this directory for more information. import array +import ctypes import mmap import sys from os import PathLike -from typing import AbstractSet, Any, Awaitable, Container, Iterable, Protocol, Tuple, TypeVar, Union +from typing import AbstractSet, Any, Awaitable, Container, Iterable, Protocol, TypeVar, Union from typing_extensions import Literal, final _KT = TypeVar("_KT") @@ -39,6 +40,31 @@ class SupportsLessThan(Protocol): SupportsLessThanT = TypeVar("SupportsLessThanT", bound=SupportsLessThan) # noqa: Y001 +class SupportsGreaterThan(Protocol): + def __gt__(self, __other: Any) -> bool: ... + +SupportsGreaterThanT = TypeVar("SupportsGreaterThanT", bound=SupportsGreaterThan) # noqa: Y001 + +# Comparison protocols + +class SupportsDunderLT(Protocol): + def __lt__(self, __other: Any) -> Any: ... + +class SupportsDunderGT(Protocol): + def __gt__(self, __other: Any) -> Any: ... + +class SupportsDunderLE(Protocol): + def __le__(self, __other: Any) -> Any: ... + +class SupportsDunderGE(Protocol): + def __ge__(self, __other: Any) -> Any: ... + +class SupportsAllComparisons(SupportsDunderLT, SupportsDunderGT, SupportsDunderLE, SupportsDunderGE, Protocol): ... + +SupportsRichComparison = Union[SupportsDunderLT, SupportsDunderGT] +SupportsRichComparisonT = TypeVar("SupportsRichComparisonT", bound=SupportsRichComparison) # noqa: Y001 +SupportsAnyComparison = Union[SupportsDunderLE, SupportsDunderGE, SupportsDunderGT, SupportsDunderLT] + class SupportsDivMod(Protocol[_T_contra, _T_co]): def __divmod__(self, __other: _T_contra) -> _T_co: ... @@ -56,7 +82,7 @@ class SupportsTrunc(Protocol): # stable class SupportsItems(Protocol[_KT_co, _VT_co]): - def items(self) -> AbstractSet[Tuple[_KT_co, _VT_co]]: ... + def items(self) -> AbstractSet[tuple[_KT_co, _VT_co]]: ... # stable class SupportsKeysAndGetItem(Protocol[_KT, _VT_co]): @@ -167,8 +193,13 @@ class SupportsNoArgReadline(Protocol[_T_co]): class SupportsWrite(Protocol[_T_contra]): def write(self, __s: _T_contra) -> Any: ... -ReadableBuffer = Union[bytes, bytearray, memoryview, array.array[Any], mmap.mmap] # stable -WriteableBuffer = Union[bytearray, memoryview, array.array[Any], mmap.mmap] # stable +ReadOnlyBuffer = bytes # stable +# Anything that implements the read-write buffer interface. +# The buffer interface is defined purely on the C level, so we cannot define a normal Protocol +# for it. Instead we have to list the most common stdlib buffer classes in a Union. +WriteableBuffer = Union[bytearray, memoryview, array.array[Any], mmap.mmap, ctypes._CData] # stable +# Same as _WriteableBuffer, but also includes read-only buffer types (like bytes). +ReadableBuffer = Union[ReadOnlyBuffer, WriteableBuffer] # stable # stable if sys.version_info >= (3, 10): diff --git a/mypy/typeshed/stdlib/_typeshed/wsgi.pyi b/mypy/typeshed/stdlib/_typeshed/wsgi.pyi index ddb32b78332a..658b0fed2c6c 100644 --- a/mypy/typeshed/stdlib/_typeshed/wsgi.pyi +++ b/mypy/typeshed/stdlib/_typeshed/wsgi.pyi @@ -3,12 +3,12 @@ # See the README.md file in this directory for more information. from sys import _OptExcInfo -from typing import Any, Callable, Dict, Iterable, Protocol, Tuple +from typing import Any, Callable, Dict, Iterable, Protocol # stable 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], Any]: ... WSGIEnvironment = Dict[str, Any] # stable diff --git a/mypy/typeshed/stdlib/_warnings.pyi b/mypy/typeshed/stdlib/_warnings.pyi index fef73e69c626..e5b180b14fea 100644 --- a/mypy/typeshed/stdlib/_warnings.pyi +++ b/mypy/typeshed/stdlib/_warnings.pyi @@ -1,4 +1,4 @@ -from typing import Any, Tuple, Type, overload +from typing import Any, Type, overload _defaultaction: str _onceregistry: dict[Any, Any] @@ -15,7 +15,7 @@ def warn_explicit( filename: str, lineno: int, module: str | None = ..., - registry: dict[str | Tuple[str, Type[Warning], int], int] | None = ..., + registry: dict[str | tuple[str, Type[Warning], int], int] | None = ..., module_globals: dict[str, Any] | None = ..., source: Any | None = ..., ) -> None: ... @@ -26,7 +26,7 @@ def warn_explicit( filename: str, lineno: int, module: str | None = ..., - registry: dict[str | Tuple[str, Type[Warning], int], int] | None = ..., + registry: dict[str | tuple[str, Type[Warning], int], int] | None = ..., module_globals: dict[str, Any] | None = ..., source: Any | None = ..., ) -> None: ... diff --git a/mypy/typeshed/stdlib/_weakref.pyi b/mypy/typeshed/stdlib/_weakref.pyi index 006836f85055..dcaef25b3f0f 100644 --- a/mypy/typeshed/stdlib/_weakref.pyi +++ b/mypy/typeshed/stdlib/_weakref.pyi @@ -1,5 +1,6 @@ import sys from typing import Any, Callable, Generic, TypeVar, overload +from typing_extensions import final if sys.version_info >= (3, 9): from types import GenericAlias @@ -7,9 +8,11 @@ if sys.version_info >= (3, 9): _C = TypeVar("_C", bound=Callable[..., Any]) _T = TypeVar("_T") +@final class CallableProxyType(Generic[_C]): # "weakcallableproxy" def __getattr__(self, attr: str) -> Any: ... +@final class ProxyType(Generic[_T]): # "weakproxy" def __getattr__(self, attr: str) -> Any: ... diff --git a/mypy/typeshed/stdlib/_winapi.pyi b/mypy/typeshed/stdlib/_winapi.pyi index eabbad312abc..83089d485c17 100644 --- a/mypy/typeshed/stdlib/_winapi.pyi +++ b/mypy/typeshed/stdlib/_winapi.pyi @@ -1,6 +1,6 @@ import sys -from typing import Any, NoReturn, Sequence, Tuple, overload -from typing_extensions import Literal +from typing import Any, NoReturn, Sequence, overload +from typing_extensions import Literal, final CREATE_NEW_CONSOLE: int CREATE_NEW_PROCESS_GROUP: int @@ -73,7 +73,7 @@ def CreateNamedPipe( __default_timeout: int, __security_attributes: int, ) -> int: ... -def CreatePipe(__pipe_attrs: Any, __size: int) -> Tuple[int, int]: ... +def CreatePipe(__pipe_attrs: Any, __size: int) -> tuple[int, int]: ... def CreateProcess( __application_name: str | None, __command_line: str | None, @@ -84,7 +84,7 @@ def CreateProcess( __env_mapping: dict[str, str], __current_directory: str | None, __startup_info: Any, -) -> Tuple[int, int, int, int]: ... +) -> tuple[int, int, int, int]: ... def DuplicateHandle( __source_process_handle: int, __source_handle: int, @@ -106,13 +106,13 @@ def GetModuleFileName(__module_handle: int) -> str: ... def GetStdHandle(__std_handle: int) -> int: ... def GetVersion() -> int: ... def OpenProcess(__desired_access: int, __inherit_handle: bool, __process_id: int) -> int: ... -def PeekNamedPipe(__handle: int, __size: int = ...) -> Tuple[int, int] | Tuple[bytes, int, int]: ... +def PeekNamedPipe(__handle: int, __size: int = ...) -> tuple[int, int] | tuple[bytes, int, int]: ... @overload -def ReadFile(handle: int, size: int, overlapped: Literal[True]) -> Tuple[Overlapped, int]: ... +def ReadFile(handle: int, size: int, overlapped: Literal[True]) -> tuple[Overlapped, int]: ... @overload -def ReadFile(handle: int, size: int, overlapped: Literal[False] = ...) -> Tuple[bytes, int]: ... +def ReadFile(handle: int, size: int, overlapped: Literal[False] = ...) -> tuple[bytes, int]: ... @overload -def ReadFile(handle: int, size: int, overlapped: int | bool) -> Tuple[Any, int]: ... +def ReadFile(handle: int, size: int, overlapped: int | bool) -> tuple[Any, int]: ... def SetNamedPipeHandleState( __named_pipe: int, __mode: int | None, __max_collection_count: int | None, __collect_data_timeout: int | None ) -> None: ... @@ -121,14 +121,14 @@ def WaitForMultipleObjects(__handle_seq: Sequence[int], __wait_flag: bool, __mil def WaitForSingleObject(__handle: int, __milliseconds: int) -> int: ... def WaitNamedPipe(__name: str, __timeout: int) -> None: ... @overload -def WriteFile(handle: int, buffer: bytes, overlapped: Literal[True]) -> Tuple[Overlapped, int]: ... +def WriteFile(handle: int, buffer: bytes, overlapped: Literal[True]) -> tuple[Overlapped, int]: ... @overload -def WriteFile(handle: int, buffer: bytes, overlapped: Literal[False] = ...) -> Tuple[int, int]: ... +def WriteFile(handle: int, buffer: bytes, overlapped: Literal[False] = ...) -> tuple[int, int]: ... @overload -def WriteFile(handle: int, buffer: bytes, overlapped: int | bool) -> Tuple[Any, int]: ... - +def WriteFile(handle: int, buffer: bytes, overlapped: int | bool) -> tuple[Any, int]: ... +@final class Overlapped: event: int - def GetOverlappedResult(self, __wait: bool) -> Tuple[int, int]: ... + def GetOverlappedResult(self, __wait: bool) -> tuple[int, int]: ... def cancel(self) -> None: ... def getbuffer(self) -> bytes | None: ... diff --git a/mypy/typeshed/stdlib/aifc.pyi b/mypy/typeshed/stdlib/aifc.pyi index 7d7c6b21f341..79f470a366bb 100644 --- a/mypy/typeshed/stdlib/aifc.pyi +++ b/mypy/typeshed/stdlib/aifc.pyi @@ -61,7 +61,7 @@ class Aifc_write: def setcomptype(self, comptype: bytes, compname: bytes) -> None: ... def getcomptype(self) -> bytes: ... def getcompname(self) -> bytes: ... - def setparams(self, params: Tuple[int, int, int, int, bytes, bytes]) -> None: ... + def setparams(self, params: tuple[int, int, int, int, bytes, bytes]) -> None: ... def getparams(self) -> _aifc_params: ... def setmark(self, id: int, pos: int, name: bytes) -> None: ... def getmark(self, id: int) -> _Marker: ... diff --git a/mypy/typeshed/stdlib/argparse.pyi b/mypy/typeshed/stdlib/argparse.pyi index 631030e94923..b9a09f56a812 100644 --- a/mypy/typeshed/stdlib/argparse.pyi +++ b/mypy/typeshed/stdlib/argparse.pyi @@ -1,8 +1,24 @@ import sys -from typing import IO, Any, Callable, Generator, Iterable, NoReturn, Pattern, Protocol, Sequence, Tuple, Type, TypeVar, overload +from typing import ( + IO, + Any, + Callable, + Generator, + Generic, + Iterable, + NoReturn, + Pattern, + Protocol, + Sequence, + Tuple, + Type, + TypeVar, + overload, +) _T = TypeVar("_T") _ActionT = TypeVar("_ActionT", bound=Action) +_ArgumentParserT = TypeVar("_ArgumentParserT", bound=ArgumentParser) _N = TypeVar("_N") ONE_OR_MORE: str @@ -20,7 +36,7 @@ class ArgumentError(Exception): # undocumented class _AttributeHolder: - def _get_kwargs(self) -> list[Tuple[str, Any]]: ... + def _get_kwargs(self) -> list[tuple[str, Any]]: ... def _get_args(self) -> list[Any]: ... # undocumented @@ -67,10 +83,10 @@ class _ActionsContainer: def _get_positional_kwargs(self, dest: str, **kwargs: Any) -> dict[str, Any]: ... def _get_optional_kwargs(self, *args: Any, **kwargs: Any) -> dict[str, Any]: ... def _pop_action_class(self, kwargs: Any, default: Type[Action] | None = ...) -> Type[Action]: ... - def _get_handler(self) -> Callable[[Action, Iterable[Tuple[str, Action]]], Any]: ... + def _get_handler(self) -> Callable[[Action, Iterable[tuple[str, Action]]], Any]: ... def _check_conflict(self, action: Action) -> None: ... - def _handle_conflict_error(self, action: Action, conflicting_actions: Iterable[Tuple[str, Action]]) -> NoReturn: ... - def _handle_conflict_resolve(self, action: Action, conflicting_actions: Iterable[Tuple[str, Action]]) -> None: ... + def _handle_conflict_error(self, action: Action, conflicting_actions: Iterable[tuple[str, Action]]) -> NoReturn: ... + def _handle_conflict_resolve(self, action: Action, conflicting_actions: Iterable[tuple[str, Action]]) -> None: ... class _FormatterClass(Protocol): def __call__(self, prog: str) -> HelpFormatter: ... @@ -135,41 +151,70 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): @overload def parse_args(self, *, namespace: _N) -> _N: ... if sys.version_info >= (3, 7): + @overload + def add_subparsers( + self: _ArgumentParserT, + *, + title: str = ..., + description: str | None = ..., + prog: str = ..., + action: Type[Action] = ..., + option_string: str = ..., + dest: str | None = ..., + required: bool = ..., + help: str | None = ..., + metavar: str | None = ..., + ) -> _SubParsersAction[_ArgumentParserT]: ... + @overload def add_subparsers( self, *, title: str = ..., description: str | None = ..., prog: str = ..., - parser_class: Type[ArgumentParser] = ..., + parser_class: Type[_ArgumentParserT] = ..., action: Type[Action] = ..., option_string: str = ..., dest: str | None = ..., required: bool = ..., help: str | None = ..., metavar: str | None = ..., - ) -> _SubParsersAction: ... + ) -> _SubParsersAction[_ArgumentParserT]: ... else: + @overload + def add_subparsers( + self: _ArgumentParserT, + *, + title: str = ..., + description: str | None = ..., + prog: str = ..., + action: Type[Action] = ..., + option_string: str = ..., + dest: str | None = ..., + help: str | None = ..., + metavar: str | None = ..., + ) -> _SubParsersAction[_ArgumentParserT]: ... + @overload def add_subparsers( self, *, title: str = ..., description: str | None = ..., prog: str = ..., - parser_class: Type[ArgumentParser] = ..., + parser_class: Type[_ArgumentParserT] = ..., action: Type[Action] = ..., option_string: str = ..., dest: str | None = ..., help: str | None = ..., metavar: str | None = ..., - ) -> _SubParsersAction: ... + ) -> _SubParsersAction[_ArgumentParserT]: ... def print_usage(self, file: IO[str] | None = ...) -> None: ... def print_help(self, file: IO[str] | None = ...) -> None: ... def format_usage(self) -> str: ... def format_help(self) -> str: ... def parse_known_args( self, args: Sequence[str] | None = ..., namespace: Namespace | None = ... - ) -> Tuple[Namespace, list[str]]: ... + ) -> tuple[Namespace, list[str]]: ... def convert_arg_line_to_args(self, arg_line: str) -> list[str]: ... def exit(self, status: int = ..., message: str | None = ...) -> NoReturn: ... def error(self, message: str) -> NoReturn: ... @@ -177,16 +222,16 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): def parse_intermixed_args(self, args: Sequence[str] | None = ..., namespace: Namespace | None = ...) -> Namespace: ... def parse_known_intermixed_args( self, args: Sequence[str] | None = ..., namespace: Namespace | None = ... - ) -> Tuple[Namespace, list[str]]: ... + ) -> tuple[Namespace, list[str]]: ... # undocumented def _get_optional_actions(self) -> list[Action]: ... def _get_positional_actions(self) -> list[Action]: ... - def _parse_known_args(self, arg_strings: list[str], namespace: Namespace) -> Tuple[Namespace, list[str]]: ... + def _parse_known_args(self, arg_strings: list[str], namespace: Namespace) -> tuple[Namespace, list[str]]: ... def _read_args_from_files(self, arg_strings: list[str]) -> list[str]: ... def _match_argument(self, action: Action, arg_strings_pattern: str) -> int: ... def _match_arguments_partial(self, actions: Sequence[Action], arg_strings_pattern: str) -> list[int]: ... - def _parse_optional(self, arg_string: str) -> Tuple[Action | None, str, str | None] | None: ... - def _get_option_tuples(self, option_string: str) -> list[Tuple[Action, str, str | None]]: ... + def _parse_optional(self, arg_string: str) -> tuple[Action | None, str, str | None] | None: ... + def _get_option_tuples(self, option_string: str) -> list[tuple[Action, str, str | None]]: ... def _get_nargs_pattern(self, action: Action) -> str: ... def _get_values(self, action: Action, arg_strings: list[str]) -> Any: ... def _get_value(self, action: Action, arg_string: str) -> Any: ... @@ -379,19 +424,19 @@ class _VersionAction(Action): ) -> None: ... # undocumented -class _SubParsersAction(Action): +class _SubParsersAction(Action, Generic[_ArgumentParserT]): _ChoicesPseudoAction: Type[Any] # nested class _prog_prefix: str - _parser_class: Type[ArgumentParser] - _name_parser_map: dict[str, ArgumentParser] - choices: dict[str, ArgumentParser] + _parser_class: Type[_ArgumentParserT] + _name_parser_map: dict[str, _ArgumentParserT] + choices: dict[str, _ArgumentParserT] _choices_actions: list[Action] if sys.version_info >= (3, 7): def __init__( self, option_strings: Sequence[str], prog: str, - parser_class: Type[ArgumentParser], + parser_class: Type[_ArgumentParserT], dest: str = ..., required: bool = ..., help: str | None = ..., @@ -402,13 +447,13 @@ class _SubParsersAction(Action): self, option_strings: Sequence[str], prog: str, - parser_class: Type[ArgumentParser], + parser_class: Type[_ArgumentParserT], dest: str = ..., help: str | None = ..., metavar: str | Tuple[str, ...] | None = ..., ) -> None: ... # TODO: Type keyword args properly. - def add_parser(self, name: str, **kwargs: Any) -> ArgumentParser: ... + def add_parser(self, name: str, **kwargs: Any) -> _ArgumentParserT: ... def _get_subactions(self) -> list[Action]: ... # undocumented diff --git a/mypy/typeshed/stdlib/array.pyi b/mypy/typeshed/stdlib/array.pyi index c32136d559bf..6f4444b10f96 100644 --- a/mypy/typeshed/stdlib/array.pyi +++ b/mypy/typeshed/stdlib/array.pyi @@ -1,5 +1,5 @@ import sys -from typing import Any, BinaryIO, Generic, Iterable, MutableSequence, Tuple, TypeVar, Union, overload +from typing import Any, BinaryIO, Generic, Iterable, MutableSequence, TypeVar, Union, overload from typing_extensions import Literal _IntTypeCode = Literal["b", "B", "h", "H", "i", "I", "l", "L", "q", "Q"] @@ -15,15 +15,15 @@ class array(MutableSequence[_T], Generic[_T]): typecode: _TypeCode itemsize: int @overload - def __init__(self: array[int], typecode: _IntTypeCode, __initializer: bytes | Iterable[_T] = ...) -> None: ... + def __init__(self: array[int], __typecode: _IntTypeCode, __initializer: bytes | Iterable[_T] = ...) -> None: ... @overload - def __init__(self: array[float], typecode: _FloatTypeCode, __initializer: bytes | Iterable[_T] = ...) -> None: ... + def __init__(self: array[float], __typecode: _FloatTypeCode, __initializer: bytes | Iterable[_T] = ...) -> None: ... @overload - def __init__(self: array[str], typecode: _UnicodeTypeCode, __initializer: bytes | Iterable[_T] = ...) -> None: ... + def __init__(self: array[str], __typecode: _UnicodeTypeCode, __initializer: bytes | Iterable[_T] = ...) -> None: ... @overload def __init__(self, typecode: str, __initializer: bytes | Iterable[_T] = ...) -> None: ... def append(self, __v: _T) -> None: ... - def buffer_info(self) -> Tuple[int, int]: ... + def buffer_info(self) -> tuple[int, int]: ... def byteswap(self) -> None: ... def count(self, __v: Any) -> int: ... def extend(self, __bb: Iterable[_T]) -> None: ... @@ -48,22 +48,22 @@ class array(MutableSequence[_T], Generic[_T]): def tostring(self) -> bytes: ... def __len__(self) -> int: ... @overload - def __getitem__(self, i: int) -> _T: ... + def __getitem__(self, __i: int) -> _T: ... @overload - def __getitem__(self, s: slice) -> array[_T]: ... + def __getitem__(self, __s: slice) -> array[_T]: ... @overload # type: ignore # Overrides MutableSequence - def __setitem__(self, i: int, o: _T) -> None: ... + def __setitem__(self, __i: int, __o: _T) -> None: ... @overload - def __setitem__(self, s: slice, o: array[_T]) -> None: ... - def __delitem__(self, i: int | slice) -> None: ... - def __add__(self, x: array[_T]) -> array[_T]: ... - def __ge__(self, other: array[_T]) -> bool: ... - def __gt__(self, other: array[_T]) -> bool: ... - def __iadd__(self, x: array[_T]) -> array[_T]: ... # type: ignore # Overrides MutableSequence - def __imul__(self, n: int) -> array[_T]: ... - def __le__(self, other: array[_T]) -> bool: ... - def __lt__(self, other: array[_T]) -> bool: ... - def __mul__(self, n: int) -> array[_T]: ... - def __rmul__(self, n: int) -> array[_T]: ... + def __setitem__(self, __s: slice, __o: array[_T]) -> None: ... + def __delitem__(self, __i: int | slice) -> None: ... + def __add__(self, __x: array[_T]) -> array[_T]: ... + def __ge__(self, __other: array[_T]) -> bool: ... + def __gt__(self, __other: array[_T]) -> bool: ... + def __iadd__(self, __x: array[_T]) -> array[_T]: ... # type: ignore # Overrides MutableSequence + def __imul__(self, __n: int) -> array[_T]: ... + def __le__(self, __other: array[_T]) -> bool: ... + def __lt__(self, __other: array[_T]) -> bool: ... + def __mul__(self, __n: int) -> array[_T]: ... + def __rmul__(self, __n: int) -> array[_T]: ... ArrayType = array diff --git a/mypy/typeshed/stdlib/ast.pyi b/mypy/typeshed/stdlib/ast.pyi index 1649e4ab41be..00c62c30c037 100644 --- a/mypy/typeshed/stdlib/ast.pyi +++ b/mypy/typeshed/stdlib/ast.pyi @@ -8,11 +8,10 @@ # sys. import sys import typing as _typing +from _ast import * # type: ignore from typing import Any, Iterator, TypeVar, overload from typing_extensions import Literal -from _ast import * # type: ignore - if sys.version_info >= (3, 8): class Num(Constant): value: complex diff --git a/mypy/typeshed/stdlib/asyncio/base_events.pyi b/mypy/typeshed/stdlib/asyncio/base_events.pyi index 349050258a16..15471f54483f 100644 --- a/mypy/typeshed/stdlib/asyncio/base_events.pyi +++ b/mypy/typeshed/stdlib/asyncio/base_events.pyi @@ -89,8 +89,8 @@ class BaseEventLoop(AbstractEventLoop, metaclass=ABCMeta): # Network I/O methods returning Futures. async def getaddrinfo( self, host: str | None, port: str | int | None, *, family: int = ..., type: int = ..., proto: int = ..., flags: int = ... - ) -> list[Tuple[AddressFamily, SocketKind, int, str, Tuple[str, int] | Tuple[str, int, int, int]]]: ... - async def getnameinfo(self, sockaddr: Tuple[str, int] | Tuple[str, int, int, int], flags: int = ...) -> Tuple[str, str]: ... + ) -> list[tuple[AddressFamily, SocketKind, int, str, tuple[str, int] | tuple[str, int, int, int]]]: ... + async def getnameinfo(self, sockaddr: tuple[str, int] | tuple[str, int, int, int], flags: int = ...) -> tuple[str, str]: ... if sys.version_info >= (3, 8): @overload async def create_connection( @@ -104,7 +104,7 @@ class BaseEventLoop(AbstractEventLoop, metaclass=ABCMeta): proto: int = ..., flags: int = ..., sock: None = ..., - local_addr: Tuple[str, int] | None = ..., + local_addr: tuple[str, int] | None = ..., server_hostname: str | None = ..., ssl_handshake_timeout: float | None = ..., happy_eyeballs_delay: float | None = ..., @@ -141,7 +141,7 @@ class BaseEventLoop(AbstractEventLoop, metaclass=ABCMeta): proto: int = ..., flags: int = ..., sock: None = ..., - local_addr: Tuple[str, int] | None = ..., + local_addr: tuple[str, int] | None = ..., server_hostname: str | None = ..., ssl_handshake_timeout: float | None = ..., ) -> _TransProtPair: ... @@ -174,7 +174,7 @@ class BaseEventLoop(AbstractEventLoop, metaclass=ABCMeta): proto: int = ..., flags: int = ..., sock: None = ..., - local_addr: Tuple[str, int] | None = ..., + local_addr: tuple[str, int] | None = ..., server_hostname: str | None = ..., ) -> _TransProtPair: ... @overload @@ -288,8 +288,8 @@ class BaseEventLoop(AbstractEventLoop, metaclass=ABCMeta): async def create_datagram_endpoint( self, protocol_factory: _ProtocolFactory, - local_addr: Tuple[str, int] | None = ..., - remote_addr: Tuple[str, int] | None = ..., + local_addr: tuple[str, int] | None = ..., + remote_addr: tuple[str, int] | None = ..., *, family: int = ..., proto: int = ..., @@ -343,12 +343,12 @@ class BaseEventLoop(AbstractEventLoop, metaclass=ABCMeta): async def sock_recv_into(self, sock: socket, buf: bytearray) -> int: ... async def sock_sendall(self, sock: socket, data: bytes) -> None: ... async def sock_connect(self, sock: socket, address: _Address) -> None: ... - async def sock_accept(self, sock: socket) -> Tuple[socket, _RetAddress]: ... + async def sock_accept(self, sock: socket) -> tuple[socket, _RetAddress]: ... else: def sock_recv(self, sock: socket, nbytes: int) -> Future[bytes]: ... def sock_sendall(self, sock: socket, data: bytes) -> Future[None]: ... def sock_connect(self, sock: socket, address: _Address) -> Future[None]: ... - def sock_accept(self, sock: socket) -> Future[Tuple[socket, _RetAddress]]: ... + def sock_accept(self, sock: socket) -> Future[tuple[socket, _RetAddress]]: ... # Signal handling. def add_signal_handler(self, sig: int, callback: Callable[..., Any], *args: Any) -> None: ... def remove_signal_handler(self, sig: int) -> bool: ... diff --git a/mypy/typeshed/stdlib/asyncio/base_futures.pyi b/mypy/typeshed/stdlib/asyncio/base_futures.pyi index 1c5f03e8ea72..72ba6163e9d3 100644 --- a/mypy/typeshed/stdlib/asyncio/base_futures.pyi +++ b/mypy/typeshed/stdlib/asyncio/base_futures.pyi @@ -1,5 +1,5 @@ import sys -from typing import Any, Callable, Sequence, Tuple +from typing import Any, Callable, Sequence from typing_extensions import Literal if sys.version_info >= (3, 7): @@ -14,7 +14,7 @@ _FINISHED: Literal["FINISHED"] # undocumented def isfuture(obj: object) -> bool: ... if sys.version_info >= (3, 7): - def _format_callbacks(cb: Sequence[Tuple[Callable[[futures.Future[Any]], None], Context]]) -> str: ... # undocumented + def _format_callbacks(cb: Sequence[tuple[Callable[[futures.Future[Any]], None], Context]]) -> str: ... # undocumented else: def _format_callbacks(cb: Sequence[Callable[[futures.Future[Any]], None]]) -> str: ... # undocumented diff --git a/mypy/typeshed/stdlib/asyncio/base_subprocess.pyi b/mypy/typeshed/stdlib/asyncio/base_subprocess.pyi index 6165e0bb88d0..23034790a4a9 100644 --- a/mypy/typeshed/stdlib/asyncio/base_subprocess.pyi +++ b/mypy/typeshed/stdlib/asyncio/base_subprocess.pyi @@ -1,5 +1,6 @@ import subprocess -from typing import IO, Any, Callable, Deque, Optional, Sequence, Tuple, Union +from collections import deque +from typing import IO, Any, Callable, Optional, Sequence, Tuple, Union from . import events, futures, protocols, transports @@ -14,7 +15,7 @@ class BaseSubprocessTransport(transports.SubprocessTransport): _pid: int | None # undocumented _returncode: int | None # undocumented _exit_waiters: list[futures.Future[Any]] # undocumented - _pending_calls: Deque[Tuple[Callable[..., Any], Tuple[Any, ...]]] # undocumented + _pending_calls: deque[tuple[Callable[..., Any], Tuple[Any, ...]]] # undocumented _pipes: dict[int, _File] # undocumented _finished: bool # undocumented def __init__( diff --git a/mypy/typeshed/stdlib/asyncio/coroutines.pyi b/mypy/typeshed/stdlib/asyncio/coroutines.pyi index e514b884c201..df94d5ba156a 100644 --- a/mypy/typeshed/stdlib/asyncio/coroutines.pyi +++ b/mypy/typeshed/stdlib/asyncio/coroutines.pyi @@ -1,7 +1,16 @@ -from typing import Any, Callable, TypeVar +import sys +import types +from collections.abc import Callable, Coroutine +from typing import Any, TypeVar +from typing_extensions import TypeGuard _F = TypeVar("_F", bound=Callable[..., Any]) def coroutine(func: _F) -> _F: ... def iscoroutinefunction(func: object) -> bool: ... -def iscoroutine(obj: object) -> bool: ... + +if sys.version_info < (3, 8): + def iscoroutine(obj: object) -> TypeGuard[types.GeneratorType[Any, Any, Any] | Coroutine[Any, Any, Any]]: ... + +else: + def iscoroutine(obj: object) -> TypeGuard[Coroutine[Any, Any, Any]]: ... diff --git a/mypy/typeshed/stdlib/asyncio/events.pyi b/mypy/typeshed/stdlib/asyncio/events.pyi index 9b77a915e5c9..6ef9117b6491 100644 --- a/mypy/typeshed/stdlib/asyncio/events.pyi +++ b/mypy/typeshed/stdlib/asyncio/events.pyi @@ -113,16 +113,16 @@ class AbstractEventLoop(metaclass=ABCMeta): @abstractmethod def call_soon_threadsafe(self, callback: Callable[..., Any], *args: Any) -> Handle: ... @abstractmethod - def run_in_executor(self, executor: Any, func: Callable[..., _T], *args: Any) -> Awaitable[_T]: ... + def run_in_executor(self, executor: Any, func: Callable[..., _T], *args: Any) -> Future[_T]: ... @abstractmethod def set_default_executor(self, executor: Any) -> None: ... # Network I/O methods returning Futures. @abstractmethod async def getaddrinfo( self, host: str | None, port: str | int | None, *, family: int = ..., type: int = ..., proto: int = ..., flags: int = ... - ) -> list[Tuple[AddressFamily, SocketKind, int, str, Tuple[str, int] | Tuple[str, int, int, int]]]: ... + ) -> list[tuple[AddressFamily, SocketKind, int, str, tuple[str, int] | tuple[str, int, int, int]]]: ... @abstractmethod - async def getnameinfo(self, sockaddr: Tuple[str, int] | Tuple[str, int, int, int], flags: int = ...) -> Tuple[str, str]: ... + async def getnameinfo(self, sockaddr: tuple[str, int] | tuple[str, int, int, int], flags: int = ...) -> tuple[str, str]: ... if sys.version_info >= (3, 8): @overload @abstractmethod @@ -137,7 +137,7 @@ class AbstractEventLoop(metaclass=ABCMeta): proto: int = ..., flags: int = ..., sock: None = ..., - local_addr: Tuple[str, int] | None = ..., + local_addr: tuple[str, int] | None = ..., server_hostname: str | None = ..., ssl_handshake_timeout: float | None = ..., happy_eyeballs_delay: float | None = ..., @@ -176,7 +176,7 @@ class AbstractEventLoop(metaclass=ABCMeta): proto: int = ..., flags: int = ..., sock: None = ..., - local_addr: Tuple[str, int] | None = ..., + local_addr: tuple[str, int] | None = ..., server_hostname: str | None = ..., ssl_handshake_timeout: float | None = ..., ) -> _TransProtPair: ... @@ -211,7 +211,7 @@ class AbstractEventLoop(metaclass=ABCMeta): proto: int = ..., flags: int = ..., sock: None = ..., - local_addr: Tuple[str, int] | None = ..., + local_addr: tuple[str, int] | None = ..., server_hostname: str | None = ..., ) -> _TransProtPair: ... @overload @@ -362,8 +362,8 @@ class AbstractEventLoop(metaclass=ABCMeta): async def create_datagram_endpoint( self, protocol_factory: _ProtocolFactory, - local_addr: Tuple[str, int] | None = ..., - remote_addr: Tuple[str, int] | None = ..., + local_addr: tuple[str, int] | None = ..., + remote_addr: tuple[str, int] | None = ..., *, family: int = ..., proto: int = ..., @@ -430,7 +430,7 @@ class AbstractEventLoop(metaclass=ABCMeta): @abstractmethod async def sock_connect(self, sock: socket, address: _Address) -> None: ... @abstractmethod - async def sock_accept(self, sock: socket) -> Tuple[socket, _RetAddress]: ... + async def sock_accept(self, sock: socket) -> tuple[socket, _RetAddress]: ... else: @abstractmethod def sock_recv(self, sock: socket, nbytes: int) -> Future[bytes]: ... @@ -439,7 +439,7 @@ class AbstractEventLoop(metaclass=ABCMeta): @abstractmethod def sock_connect(self, sock: socket, address: _Address) -> Future[None]: ... @abstractmethod - def sock_accept(self, sock: socket) -> Future[Tuple[socket, _RetAddress]]: ... + def sock_accept(self, sock: socket) -> Future[tuple[socket, _RetAddress]]: ... # Signal handling. @abstractmethod def add_signal_handler(self, sig: int, callback: Callable[..., Any], *args: Any) -> None: ... diff --git a/mypy/typeshed/stdlib/asyncio/format_helpers.pyi b/mypy/typeshed/stdlib/asyncio/format_helpers.pyi index 29cb8839716e..be80efe266b1 100644 --- a/mypy/typeshed/stdlib/asyncio/format_helpers.pyi +++ b/mypy/typeshed/stdlib/asyncio/format_helpers.pyi @@ -2,7 +2,7 @@ import functools import sys import traceback from types import FrameType, FunctionType -from typing import Any, Iterable, Tuple, Union, overload +from typing import Any, Iterable, Union, overload class _HasWrapper: __wrapper__: _HasWrapper | FunctionType @@ -11,9 +11,9 @@ _FuncType = Union[FunctionType, _HasWrapper, functools.partial[Any], functools.p if sys.version_info >= (3, 7): @overload - def _get_function_source(func: _FuncType) -> Tuple[str, int]: ... + def _get_function_source(func: _FuncType) -> tuple[str, int]: ... @overload - def _get_function_source(func: object) -> Tuple[str, int] | None: ... + def _get_function_source(func: object) -> tuple[str, int] | None: ... def _format_callback_source(func: object, args: Iterable[Any]) -> str: ... def _format_args_and_kwargs(args: Iterable[Any], kwargs: dict[str, Any]) -> str: ... def _format_callback(func: object, args: Iterable[Any], kwargs: dict[str, Any], suffix: str = ...) -> str: ... diff --git a/mypy/typeshed/stdlib/asyncio/futures.pyi b/mypy/typeshed/stdlib/asyncio/futures.pyi index 4942796b88ae..9788123f427e 100644 --- a/mypy/typeshed/stdlib/asyncio/futures.pyi +++ b/mypy/typeshed/stdlib/asyncio/futures.pyi @@ -1,6 +1,6 @@ import sys from concurrent.futures._base import Error, Future as _ConcurrentFuture -from typing import Any, Awaitable, Callable, Generator, Iterable, Tuple, TypeVar +from typing import Any, Awaitable, Callable, Generator, Iterable, TypeVar from .events import AbstractEventLoop @@ -38,7 +38,7 @@ class Future(Awaitable[_T], Iterable[_T]): def __del__(self) -> None: ... if sys.version_info >= (3, 7): def get_loop(self) -> AbstractEventLoop: ... - def _callbacks(self: _S) -> list[Tuple[Callable[[_S], Any], Context]]: ... + def _callbacks(self: _S) -> list[tuple[Callable[[_S], Any], Context]]: ... def add_done_callback(self: _S, __fn: Callable[[_S], Any], *, context: Context | None = ...) -> None: ... else: @property diff --git a/mypy/typeshed/stdlib/asyncio/locks.pyi b/mypy/typeshed/stdlib/asyncio/locks.pyi index 901232740773..7c4f40d9e4ca 100644 --- a/mypy/typeshed/stdlib/asyncio/locks.pyi +++ b/mypy/typeshed/stdlib/asyncio/locks.pyi @@ -1,6 +1,7 @@ import sys +from collections import deque from types import TracebackType -from typing import Any, Awaitable, Callable, Deque, Generator, Type, TypeVar +from typing import Any, Awaitable, Callable, Generator, Type, TypeVar from .events import AbstractEventLoop from .futures import Future @@ -57,7 +58,7 @@ class Condition(_ContextManagerMixin): class Semaphore(_ContextManagerMixin): _value: int - _waiters: Deque[Future[Any]] + _waiters: deque[Future[Any]] def __init__(self, value: int = ..., *, loop: AbstractEventLoop | None = ...) -> None: ... def locked(self) -> bool: ... async def acquire(self) -> bool: ... diff --git a/mypy/typeshed/stdlib/asyncio/protocols.pyi b/mypy/typeshed/stdlib/asyncio/protocols.pyi index ec8131b02e3d..754f02c8bb4b 100644 --- a/mypy/typeshed/stdlib/asyncio/protocols.pyi +++ b/mypy/typeshed/stdlib/asyncio/protocols.pyi @@ -1,6 +1,5 @@ import sys from asyncio import transports -from typing import Tuple class BaseProtocol: def connection_made(self, transport: transports.BaseTransport) -> None: ... @@ -18,8 +17,8 @@ if sys.version_info >= (3, 7): def buffer_updated(self, nbytes: int) -> None: ... class DatagramProtocol(BaseProtocol): - def connection_made(self, transport: transports.DatagramTransport) -> None: ... # type: ignore - def datagram_received(self, data: bytes, addr: Tuple[str, int]) -> None: ... + def connection_made(self, transport: transports.DatagramTransport) -> None: ... # type: ignore[override] + def datagram_received(self, data: bytes, addr: tuple[str, int]) -> None: ... def error_received(self, exc: Exception) -> None: ... class SubprocessProtocol(BaseProtocol): diff --git a/mypy/typeshed/stdlib/asyncio/sslproto.pyi b/mypy/typeshed/stdlib/asyncio/sslproto.pyi index 9dda54cc84bb..082e96dc0233 100644 --- a/mypy/typeshed/stdlib/asyncio/sslproto.pyi +++ b/mypy/typeshed/stdlib/asyncio/sslproto.pyi @@ -1,6 +1,7 @@ import ssl import sys -from typing import Any, Callable, ClassVar, Deque, Tuple +from collections import deque +from typing import Any, Callable, ClassVar from typing_extensions import Literal from . import constants, events, futures, protocols, transports @@ -38,8 +39,8 @@ class _SSLPipe: def do_handshake(self, callback: Callable[[BaseException | None], None] | None = ...) -> list[bytes]: ... def shutdown(self, callback: Callable[[], None] | None = ...) -> list[bytes]: ... def feed_eof(self) -> None: ... - def feed_ssldata(self, data: bytes, only_handshake: bool = ...) -> Tuple[list[bytes], list[bytes]]: ... - def feed_appdata(self, data: bytes, offset: int = ...) -> Tuple[list[bytes], int]: ... + def feed_ssldata(self, data: bytes, only_handshake: bool = ...) -> tuple[list[bytes], list[bytes]]: ... + def feed_appdata(self, data: bytes, offset: int = ...) -> tuple[list[bytes], int]: ... class _SSLProtocolTransport(transports._FlowControlMixin, transports.Transport): @@ -73,7 +74,7 @@ class SSLProtocol(protocols.Protocol): _server_hostname: str | None _sslcontext: ssl.SSLContext _extra: dict[str, Any] - _write_backlog: Deque[Tuple[bytes, int]] + _write_backlog: deque[tuple[bytes, int]] _write_buffer_size: int _waiter: futures.Future[Any] _loop: events.AbstractEventLoop diff --git a/mypy/typeshed/stdlib/asyncio/staggered.pyi b/mypy/typeshed/stdlib/asyncio/staggered.pyi index 6ac405ab77fd..1d76d382555d 100644 --- a/mypy/typeshed/stdlib/asyncio/staggered.pyi +++ b/mypy/typeshed/stdlib/asyncio/staggered.pyi @@ -1,9 +1,9 @@ import sys -from typing import Any, Awaitable, Callable, Iterable, Tuple +from typing import Any, Awaitable, Callable, Iterable from . import events if sys.version_info >= (3, 8): async def staggered_race( coro_fns: Iterable[Callable[[], Awaitable[Any]]], delay: float | None, *, loop: events.AbstractEventLoop | None = ... - ) -> Tuple[Any, int | None, list[Exception | None]]: ... + ) -> tuple[Any, int | None, list[Exception | None]]: ... diff --git a/mypy/typeshed/stdlib/asyncio/streams.pyi b/mypy/typeshed/stdlib/asyncio/streams.pyi index 6598110f87f9..595222280d58 100644 --- a/mypy/typeshed/stdlib/asyncio/streams.pyi +++ b/mypy/typeshed/stdlib/asyncio/streams.pyi @@ -1,6 +1,6 @@ import sys from _typeshed import StrPath -from typing import Any, AsyncIterator, Awaitable, Callable, Iterable, Optional, Tuple +from typing import Any, AsyncIterator, Awaitable, Callable, Iterable, Optional from . import events, protocols, transports from .base_events import Server @@ -24,7 +24,7 @@ async def open_connection( limit: int = ..., ssl_handshake_timeout: float | None = ..., **kwds: Any, -) -> Tuple[StreamReader, StreamWriter]: ... +) -> tuple[StreamReader, StreamWriter]: ... async def start_server( client_connected_cb: _ClientConnectedCallback, host: str | None = ..., @@ -43,7 +43,7 @@ if sys.platform != "win32": _PathType = str async def open_unix_connection( path: _PathType | None = ..., *, loop: events.AbstractEventLoop | None = ..., limit: int = ..., **kwds: Any - ) -> Tuple[StreamReader, StreamWriter]: ... + ) -> tuple[StreamReader, StreamWriter]: ... async def start_unix_server( client_connected_cb: _ClientConnectedCallback, path: _PathType | None = ..., diff --git a/mypy/typeshed/stdlib/asyncio/subprocess.pyi b/mypy/typeshed/stdlib/asyncio/subprocess.pyi index 428260af5465..d835c12af3d8 100644 --- a/mypy/typeshed/stdlib/asyncio/subprocess.pyi +++ b/mypy/typeshed/stdlib/asyncio/subprocess.pyi @@ -2,7 +2,7 @@ import subprocess import sys from _typeshed import StrOrBytesPath from asyncio import events, protocols, streams, transports -from typing import IO, Any, Callable, Tuple, Union +from typing import IO, Any, Callable, Union from typing_extensions import Literal if sys.version_info >= (3, 8): @@ -38,7 +38,7 @@ class Process: def send_signal(self, signal: int) -> None: ... def terminate(self) -> None: ... def kill(self) -> None: ... - async def communicate(self, input: bytes | None = ...) -> Tuple[bytes, bytes]: ... + async def communicate(self, input: bytes | None = ...) -> tuple[bytes, bytes]: ... if sys.version_info >= (3, 10): async def create_subprocess_shell( diff --git a/mypy/typeshed/stdlib/asyncio/tasks.pyi b/mypy/typeshed/stdlib/asyncio/tasks.pyi index 8cedc1ef0884..15c12909f3c3 100644 --- a/mypy/typeshed/stdlib/asyncio/tasks.pyi +++ b/mypy/typeshed/stdlib/asyncio/tasks.pyi @@ -2,7 +2,7 @@ import concurrent.futures import sys from collections.abc import Awaitable, Generator, Iterable, Iterator from types import FrameType -from typing import Any, Generic, Optional, Set, TextIO, Tuple, TypeVar, Union, overload +from typing import Any, Generic, Optional, TextIO, TypeVar, Union, overload from typing_extensions import Literal from .events import AbstractEventLoop @@ -47,11 +47,11 @@ def ensure_future(coro_or_future: Awaitable[_T], *, loop: AbstractEventLoop | No # typing PR #1550 for discussion. if sys.version_info >= (3, 10): @overload - def gather(coro_or_future1: _FutureT[_T1], *, return_exceptions: Literal[False] = ...) -> Future[Tuple[_T1]]: ... + def gather(coro_or_future1: _FutureT[_T1], *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], coro_or_future2: _FutureT[_T2], *, return_exceptions: Literal[False] = ... - ) -> Future[Tuple[_T1, _T2]]: ... + ) -> Future[tuple[_T1, _T2]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], @@ -59,7 +59,7 @@ if sys.version_info >= (3, 10): coro_or_future3: _FutureT[_T3], *, return_exceptions: Literal[False] = ..., - ) -> Future[Tuple[_T1, _T2, _T3]]: ... + ) -> Future[tuple[_T1, _T2, _T3]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], @@ -68,7 +68,7 @@ if sys.version_info >= (3, 10): coro_or_future4: _FutureT[_T4], *, return_exceptions: Literal[False] = ..., - ) -> Future[Tuple[_T1, _T2, _T3, _T4]]: ... + ) -> Future[tuple[_T1, _T2, _T3, _T4]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], @@ -78,7 +78,7 @@ if sys.version_info >= (3, 10): coro_or_future5: _FutureT[_T5], *, return_exceptions: Literal[False] = ..., - ) -> Future[Tuple[_T1, _T2, _T3, _T4, _T5]]: ... + ) -> Future[tuple[_T1, _T2, _T3, _T4, _T5]]: ... @overload def gather( coro_or_future1: _FutureT[Any], @@ -91,11 +91,11 @@ if sys.version_info >= (3, 10): return_exceptions: bool = ..., ) -> Future[list[Any]]: ... @overload - def gather(coro_or_future1: _FutureT[_T1], *, return_exceptions: bool = ...) -> Future[Tuple[_T1 | BaseException]]: ... + def gather(coro_or_future1: _FutureT[_T1], *, return_exceptions: bool = ...) -> Future[tuple[_T1 | BaseException]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], coro_or_future2: _FutureT[_T2], *, return_exceptions: bool = ... - ) -> Future[Tuple[_T1 | BaseException, _T2 | BaseException]]: ... + ) -> Future[tuple[_T1 | BaseException, _T2 | BaseException]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], @@ -103,7 +103,7 @@ if sys.version_info >= (3, 10): coro_or_future3: _FutureT[_T3], *, return_exceptions: bool = ..., - ) -> Future[Tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException]]: ... + ) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], @@ -112,7 +112,7 @@ if sys.version_info >= (3, 10): coro_or_future4: _FutureT[_T4], *, return_exceptions: bool = ..., - ) -> Future[Tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException]]: ... + ) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], @@ -123,14 +123,14 @@ if sys.version_info >= (3, 10): *, return_exceptions: bool = ..., ) -> Future[ - Tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException] + tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException] ]: ... else: @overload def gather( coro_or_future1: _FutureT[_T1], *, loop: AbstractEventLoop | None = ..., return_exceptions: Literal[False] = ... - ) -> Future[Tuple[_T1]]: ... + ) -> Future[tuple[_T1]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], @@ -138,7 +138,7 @@ else: *, loop: AbstractEventLoop | None = ..., return_exceptions: Literal[False] = ..., - ) -> Future[Tuple[_T1, _T2]]: ... + ) -> Future[tuple[_T1, _T2]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], @@ -147,7 +147,7 @@ else: *, loop: AbstractEventLoop | None = ..., return_exceptions: Literal[False] = ..., - ) -> Future[Tuple[_T1, _T2, _T3]]: ... + ) -> Future[tuple[_T1, _T2, _T3]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], @@ -157,7 +157,7 @@ else: *, loop: AbstractEventLoop | None = ..., return_exceptions: Literal[False] = ..., - ) -> Future[Tuple[_T1, _T2, _T3, _T4]]: ... + ) -> Future[tuple[_T1, _T2, _T3, _T4]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], @@ -168,7 +168,7 @@ else: *, loop: AbstractEventLoop | None = ..., return_exceptions: Literal[False] = ..., - ) -> Future[Tuple[_T1, _T2, _T3, _T4, _T5]]: ... + ) -> Future[tuple[_T1, _T2, _T3, _T4, _T5]]: ... @overload def gather( coro_or_future1: _FutureT[Any], @@ -184,7 +184,7 @@ else: @overload def gather( coro_or_future1: _FutureT[_T1], *, loop: AbstractEventLoop | None = ..., return_exceptions: bool = ... - ) -> Future[Tuple[_T1 | BaseException]]: ... + ) -> Future[tuple[_T1 | BaseException]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], @@ -192,7 +192,7 @@ else: *, loop: AbstractEventLoop | None = ..., return_exceptions: bool = ..., - ) -> Future[Tuple[_T1 | BaseException, _T2 | BaseException]]: ... + ) -> Future[tuple[_T1 | BaseException, _T2 | BaseException]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], @@ -201,7 +201,7 @@ else: *, loop: AbstractEventLoop | None = ..., return_exceptions: bool = ..., - ) -> Future[Tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException]]: ... + ) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], @@ -211,7 +211,7 @@ else: *, loop: AbstractEventLoop | None = ..., return_exceptions: bool = ..., - ) -> Future[Tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException]]: ... + ) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException]]: ... @overload def gather( coro_or_future1: _FutureT[_T1], @@ -223,7 +223,7 @@ else: loop: AbstractEventLoop | None = ..., return_exceptions: bool = ..., ) -> Future[ - Tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException] + tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException] ]: ... def run_coroutine_threadsafe(coro: _FutureT[_T], loop: AbstractEventLoop) -> concurrent.futures.Future[_T]: ... @@ -232,22 +232,22 @@ if sys.version_info >= (3, 10): def shield(arg: _FutureT[_T]) -> Future[_T]: ... def sleep(delay: float, result: _T = ...) -> Future[_T]: ... @overload - def wait(fs: Iterable[_FT], *, timeout: float | None = ..., return_when: str = ...) -> Future[Tuple[Set[_FT], Set[_FT]]]: ... # type: ignore + def wait(fs: Iterable[_FT], *, timeout: float | None = ..., return_when: str = ...) -> Future[tuple[set[_FT], set[_FT]]]: ... # type: ignore @overload def wait( fs: Iterable[Awaitable[_T]], *, timeout: float | None = ..., return_when: str = ... - ) -> Future[Tuple[Set[Task[_T]], Set[Task[_T]]]]: ... + ) -> Future[tuple[set[Task[_T]], set[Task[_T]]]]: ... def wait_for(fut: _FutureT[_T], timeout: float | None) -> Future[_T]: ... else: def shield(arg: _FutureT[_T], *, loop: AbstractEventLoop | None = ...) -> Future[_T]: ... def sleep(delay: float, result: _T = ..., *, loop: AbstractEventLoop | None = ...) -> Future[_T]: ... @overload - def wait(fs: Iterable[_FT], *, loop: AbstractEventLoop | None = ..., timeout: float | None = ..., return_when: str = ...) -> Future[Tuple[Set[_FT], Set[_FT]]]: ... # type: ignore + def wait(fs: Iterable[_FT], *, loop: AbstractEventLoop | None = ..., timeout: float | None = ..., return_when: str = ...) -> Future[tuple[set[_FT], set[_FT]]]: ... # type: ignore @overload def wait( fs: Iterable[Awaitable[_T]], *, loop: AbstractEventLoop | None = ..., timeout: float | None = ..., return_when: str = ... - ) -> Future[Tuple[Set[Task[_T]], Set[Task[_T]]]]: ... + ) -> Future[tuple[set[Task[_T]], set[Task[_T]]]]: ... def wait_for(fut: _FutureT[_T], timeout: float | None, *, loop: AbstractEventLoop | None = ...) -> Future[_T]: ... class Task(Future[_T], Generic[_T]): @@ -278,14 +278,14 @@ class Task(Future[_T], Generic[_T]): @classmethod def current_task(cls, loop: AbstractEventLoop | None = ...) -> Task[Any] | None: ... @classmethod - def all_tasks(cls, loop: AbstractEventLoop | None = ...) -> Set[Task[Any]]: ... + def all_tasks(cls, loop: AbstractEventLoop | None = ...) -> set[Task[Any]]: ... if sys.version_info < (3, 7): def _wakeup(self, fut: Future[Any]) -> None: ... if sys.version_info >= (3, 9): def __class_getitem__(cls, item: Any) -> GenericAlias: ... if sys.version_info >= (3, 7): - def all_tasks(loop: AbstractEventLoop | None = ...) -> Set[Task[Any]]: ... + def all_tasks(loop: AbstractEventLoop | None = ...) -> set[Task[Any]]: ... if sys.version_info >= (3, 8): def create_task(coro: Generator[_TaskYieldType, None, _T] | Awaitable[_T], *, name: str | None = ...) -> Task[_T]: ... else: diff --git a/mypy/typeshed/stdlib/asyncio/transports.pyi b/mypy/typeshed/stdlib/asyncio/transports.pyi index 51bf22b882b7..acca0e4c28b4 100644 --- a/mypy/typeshed/stdlib/asyncio/transports.pyi +++ b/mypy/typeshed/stdlib/asyncio/transports.pyi @@ -2,7 +2,7 @@ import sys from asyncio.events import AbstractEventLoop from asyncio.protocols import BaseProtocol from socket import _Address -from typing import Any, Mapping, Tuple +from typing import Any, Mapping class BaseTransport: def __init__(self, extra: Mapping[Any, Any] | None = ...) -> None: ... @@ -43,4 +43,4 @@ class SubprocessTransport(BaseTransport): class _FlowControlMixin(Transport): def __init__(self, extra: Mapping[Any, Any] | None = ..., loop: AbstractEventLoop | None = ...) -> None: ... - def get_write_buffer_limits(self) -> Tuple[int, int]: ... + def get_write_buffer_limits(self) -> tuple[int, int]: ... diff --git a/mypy/typeshed/stdlib/asyncio/trsock.pyi b/mypy/typeshed/stdlib/asyncio/trsock.pyi index 16c65d5683f6..33ec5d67aaf9 100644 --- a/mypy/typeshed/stdlib/asyncio/trsock.pyi +++ b/mypy/typeshed/stdlib/asyncio/trsock.pyi @@ -34,14 +34,14 @@ if sys.version_info >= (3, 8): def getpeername(self) -> _RetAddress: ... def getsockname(self) -> _RetAddress: ... def getsockbyname(self) -> NoReturn: ... # This method doesn't exist on socket, yet is passed through? - def accept(self) -> Tuple[socket.socket, _RetAddress]: ... + def accept(self) -> tuple[socket.socket, _RetAddress]: ... def connect(self, address: _Address | bytes) -> None: ... def connect_ex(self, address: _Address | bytes) -> int: ... def bind(self, address: _Address | bytes) -> None: ... if sys.platform == "win32": - def ioctl(self, control: int, option: int | Tuple[int, int, int] | bool) -> None: ... + def ioctl(self, control: int, option: int | tuple[int, int, int] | bool) -> None: ... else: - def ioctl(self, control: int, option: int | Tuple[int, int, int] | bool) -> NoReturn: ... + def ioctl(self, control: int, option: int | tuple[int, int, int] | bool) -> NoReturn: ... def listen(self, __backlog: int = ...) -> None: ... def makefile(self) -> BinaryIO: ... def sendfile(self, file: BinaryIO, offset: int = ..., count: int | None = ...) -> int: ... @@ -70,12 +70,12 @@ if sys.version_info >= (3, 8): else: def share(self, process_id: int) -> NoReturn: ... def recv_into(self, buffer: _WriteBuffer, nbytes: int = ..., flags: int = ...) -> int: ... - def recvfrom_into(self, buffer: _WriteBuffer, nbytes: int = ..., flags: int = ...) -> Tuple[int, _RetAddress]: ... + def recvfrom_into(self, buffer: _WriteBuffer, nbytes: int = ..., flags: int = ...) -> tuple[int, _RetAddress]: ... def recvmsg_into( self, __buffers: Iterable[_WriteBuffer], __ancbufsize: int = ..., __flags: int = ... - ) -> Tuple[int, list[_CMSG], int, Any]: ... - def recvmsg(self, __bufsize: int, __ancbufsize: int = ..., __flags: int = ...) -> Tuple[bytes, list[_CMSG], int, Any]: ... - def recvfrom(self, bufsize: int, flags: int = ...) -> Tuple[bytes, _RetAddress]: ... + ) -> tuple[int, list[_CMSG], int, Any]: ... + def recvmsg(self, __bufsize: int, __ancbufsize: int = ..., __flags: int = ...) -> tuple[bytes, list[_CMSG], int, Any]: ... + def recvfrom(self, bufsize: int, flags: int = ...) -> tuple[bytes, _RetAddress]: ... def recv(self, bufsize: int, flags: int = ...) -> bytes: ... def settimeout(self, value: float | None) -> None: ... def gettimeout(self) -> float | None: ... diff --git a/mypy/typeshed/stdlib/asyncio/windows_events.pyi b/mypy/typeshed/stdlib/asyncio/windows_events.pyi index 19e456138394..f0a206a4e139 100644 --- a/mypy/typeshed/stdlib/asyncio/windows_events.pyi +++ b/mypy/typeshed/stdlib/asyncio/windows_events.pyi @@ -1,7 +1,7 @@ import socket import sys from _typeshed import WriteableBuffer -from typing import IO, Any, Callable, ClassVar, NoReturn, Tuple, Type +from typing import IO, Any, Callable, ClassVar, NoReturn, Type from . import events, futures, proactor_events, selector_events, streams, windows_utils @@ -33,7 +33,7 @@ class ProactorEventLoop(proactor_events.BaseProactorEventLoop): def __init__(self, proactor: IocpProactor | None = ...) -> None: ... async def create_pipe_connection( self, protocol_factory: Callable[[], streams.StreamReaderProtocol], address: str - ) -> Tuple[proactor_events._ProactorDuplexPipeTransport, streams.StreamReaderProtocol]: ... + ) -> tuple[proactor_events._ProactorDuplexPipeTransport, streams.StreamReaderProtocol]: ... async def start_serving_pipe( self, protocol_factory: Callable[[], streams.StreamReaderProtocol], address: str ) -> list[PipeServer]: ... diff --git a/mypy/typeshed/stdlib/asyncio/windows_utils.pyi b/mypy/typeshed/stdlib/asyncio/windows_utils.pyi index f32ed3c80389..bf9cdde25a78 100644 --- a/mypy/typeshed/stdlib/asyncio/windows_utils.pyi +++ b/mypy/typeshed/stdlib/asyncio/windows_utils.pyi @@ -1,7 +1,7 @@ import sys from _typeshed import Self from types import TracebackType -from typing import Callable, Protocol, Tuple, Type +from typing import Callable, Protocol, Type class _WarnFunction(Protocol): def __call__(self, message: str, category: Type[Warning] = ..., stacklevel: int = ..., source: PipeHandle = ...) -> None: ... @@ -10,7 +10,7 @@ BUFSIZE: int PIPE: int STDOUT: int -def pipe(*, duplex: bool = ..., overlapped: Tuple[bool, bool] = ..., bufsize: int = ...) -> Tuple[int, int]: ... +def pipe(*, duplex: bool = ..., overlapped: tuple[bool, bool] = ..., bufsize: int = ...) -> tuple[int, int]: ... class PipeHandle: def __init__(self, handle: int) -> None: ... diff --git a/mypy/typeshed/stdlib/asyncore.pyi b/mypy/typeshed/stdlib/asyncore.pyi index 146d91f807f2..e135221134a5 100644 --- a/mypy/typeshed/stdlib/asyncore.pyi +++ b/mypy/typeshed/stdlib/asyncore.pyi @@ -43,7 +43,7 @@ class dispatcher: def listen(self, num: int) -> None: ... def bind(self, addr: Tuple[Any, ...] | str) -> None: ... def connect(self, address: Tuple[Any, ...] | str) -> None: ... - def accept(self) -> Tuple[_socket, Any] | None: ... + def accept(self) -> tuple[_socket, Any] | None: ... def send(self, data: bytes) -> int: ... def recv(self, buffer_size: int) -> bytes: ... def close(self) -> None: ... @@ -68,7 +68,7 @@ class dispatcher_with_send(dispatcher): # incompatible signature: # def send(self, data: bytes) -> int | None: ... -def compact_traceback() -> Tuple[Tuple[str, str, str], type, type, str]: ... +def compact_traceback() -> tuple[tuple[str, str, str], type, type, str]: ... def close_all(map: _maptype | None = ..., ignore_all: bool = ...) -> None: ... if sys.platform != "win32": diff --git a/mypy/typeshed/stdlib/audioop.pyi b/mypy/typeshed/stdlib/audioop.pyi index 71671afe487e..321bfe55c4b0 100644 --- a/mypy/typeshed/stdlib/audioop.pyi +++ b/mypy/typeshed/stdlib/audioop.pyi @@ -6,7 +6,7 @@ RatecvState = Tuple[int, Tuple[Tuple[int, int], ...]] class error(Exception): ... def add(__fragment1: bytes, __fragment2: bytes, __width: int) -> bytes: ... -def adpcm2lin(__fragment: bytes, __width: int, __state: AdpcmState | None) -> Tuple[bytes, AdpcmState]: ... +def adpcm2lin(__fragment: bytes, __width: int, __state: AdpcmState | None) -> tuple[bytes, AdpcmState]: ... def alaw2lin(__fragment: bytes, __width: int) -> bytes: ... def avg(__fragment: bytes, __width: int) -> int: ... def avgpp(__fragment: bytes, __width: int) -> int: ... @@ -14,16 +14,16 @@ def bias(__fragment: bytes, __width: int, __bias: int) -> bytes: ... def byteswap(__fragment: bytes, __width: int) -> bytes: ... def cross(__fragment: bytes, __width: int) -> int: ... def findfactor(__fragment: bytes, __reference: bytes) -> float: ... -def findfit(__fragment: bytes, __reference: bytes) -> Tuple[int, float]: ... +def findfit(__fragment: bytes, __reference: bytes) -> tuple[int, float]: ... def findmax(__fragment: bytes, __length: int) -> int: ... def getsample(__fragment: bytes, __width: int, __index: int) -> int: ... -def lin2adpcm(__fragment: bytes, __width: int, __state: AdpcmState | None) -> Tuple[bytes, AdpcmState]: ... +def lin2adpcm(__fragment: bytes, __width: int, __state: AdpcmState | None) -> tuple[bytes, AdpcmState]: ... def lin2alaw(__fragment: bytes, __width: int) -> bytes: ... def lin2lin(__fragment: bytes, __width: int, __newwidth: int) -> bytes: ... def lin2ulaw(__fragment: bytes, __width: int) -> bytes: ... def max(__fragment: bytes, __width: int) -> int: ... def maxpp(__fragment: bytes, __width: int) -> int: ... -def minmax(__fragment: bytes, __width: int) -> Tuple[int, int]: ... +def minmax(__fragment: bytes, __width: int) -> tuple[int, int]: ... def mul(__fragment: bytes, __width: int, __factor: float) -> bytes: ... def ratecv( __fragment: bytes, @@ -34,7 +34,7 @@ def ratecv( __state: RatecvState | None, __weightA: int = ..., __weightB: int = ..., -) -> Tuple[bytes, RatecvState]: ... +) -> tuple[bytes, RatecvState]: ... def reverse(__fragment: bytes, __width: int) -> bytes: ... def rms(__fragment: bytes, __width: int) -> int: ... def tomono(__fragment: bytes, __width: int, __lfactor: float, __rfactor: float) -> bytes: ... diff --git a/mypy/typeshed/stdlib/bdb.pyi b/mypy/typeshed/stdlib/bdb.pyi index 34eb989573aa..1d03ddf19a0e 100644 --- a/mypy/typeshed/stdlib/bdb.pyi +++ b/mypy/typeshed/stdlib/bdb.pyi @@ -1,5 +1,5 @@ from types import CodeType, FrameType, TracebackType -from typing import IO, Any, Callable, Iterable, Mapping, Set, SupportsInt, Tuple, Type, TypeVar +from typing import IO, Any, Callable, Iterable, Mapping, SupportsInt, Tuple, Type, TypeVar _T = TypeVar("_T") _TraceDispatch = Callable[[FrameType, str, Any], Any] # TODO: Recursive type @@ -11,7 +11,7 @@ class BdbQuit(Exception): ... class Bdb: - skip: Set[str] | None + skip: set[str] | None breaks: dict[str, list[int]] fncache: dict[str, str] frame_returning: FrameType | None @@ -56,7 +56,7 @@ class Bdb: def get_breaks(self, filename: str, lineno: int) -> list[Breakpoint]: ... def get_file_breaks(self, filename: str) -> list[Breakpoint]: ... def get_all_breaks(self) -> list[Breakpoint]: ... - def get_stack(self, f: FrameType | None, t: TracebackType | None) -> Tuple[list[Tuple[FrameType, int]], int]: ... + def get_stack(self, f: FrameType | None, t: TracebackType | None) -> tuple[list[tuple[FrameType, int]], int]: ... def format_stack_entry(self, frame_lineno: int, lprefix: str = ...) -> str: ... def run(self, cmd: str | CodeType, globals: dict[str, Any] | None = ..., locals: Mapping[str, Any] | None = ...) -> None: ... def runeval(self, expr: str, globals: dict[str, Any] | None = ..., locals: Mapping[str, Any] | None = ...) -> None: ... @@ -66,7 +66,7 @@ class Bdb: class Breakpoint: next: int - bplist: dict[Tuple[str, int], list[Breakpoint]] + bplist: dict[tuple[str, int], list[Breakpoint]] bpbynumber: list[Breakpoint | None] funcname: str | None @@ -90,5 +90,5 @@ class Breakpoint: def __str__(self) -> str: ... def checkfuncname(b: Breakpoint, frame: FrameType) -> bool: ... -def effective(file: str, line: int, frame: FrameType) -> Tuple[Breakpoint, bool] | Tuple[None, None]: ... +def effective(file: str, line: int, frame: FrameType) -> tuple[Breakpoint, bool] | tuple[None, None]: ... def set_trace() -> None: ... diff --git a/mypy/typeshed/stdlib/builtins.pyi b/mypy/typeshed/stdlib/builtins.pyi index 3ea823af4a5b..71efda9b979a 100644 --- a/mypy/typeshed/stdlib/builtins.pyi +++ b/mypy/typeshed/stdlib/builtins.pyi @@ -1,5 +1,7 @@ import sys import types +from _ast import AST +from _collections_abc import dict_items, dict_keys, dict_values from _typeshed import ( OpenBinaryMode, OpenBinaryModeReading, @@ -13,13 +15,13 @@ from _typeshed import ( SupportsDivMod, SupportsKeysAndGetItem, SupportsLenAndGetItem, - SupportsLessThan, - SupportsLessThanT, SupportsNext, SupportsRDivMod, + SupportsRichComparison, + SupportsRichComparisonT, + SupportsTrunc, SupportsWrite, ) -from ast import AST, mod from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper from types import CodeType, TracebackType from typing import ( @@ -31,12 +33,9 @@ from typing import ( BinaryIO, ByteString, Callable, - FrozenSet, Generic, - ItemsView, Iterable, Iterator, - KeysView, Mapping, MutableMapping, MutableSequence, @@ -45,7 +44,6 @@ from typing import ( Protocol, Reversible, Sequence, - Set, Sized, SupportsAbs, SupportsBytes, @@ -57,17 +55,13 @@ from typing import ( Type, TypeVar, Union, - ValuesView, overload, ) -from typing_extensions import Literal, SupportsIndex, final +from typing_extensions import Literal, SupportsIndex, TypeGuard, final if sys.version_info >= (3, 9): from types import GenericAlias -class _SupportsTrunc(Protocol): - def __trunc__(self) -> int: ... - _T = TypeVar("_T") _T_co = TypeVar("_T_co", covariant=True) _T_contra = TypeVar("_T_contra", contravariant=True) @@ -81,6 +75,7 @@ _T4 = TypeVar("_T4") _T5 = TypeVar("_T5") _TT = TypeVar("_TT", bound="type") _TBE = TypeVar("_TBE", bound="BaseException") +_R = TypeVar("_R") # Return-type TypeVar class object: __doc__: str | None @@ -95,37 +90,46 @@ class object: def __class__(self, __type: Type[object]) -> None: ... # type: ignore # noqa: F811 def __init__(self) -> None: ... def __new__(cls: Type[_T]) -> _T: ... - def __setattr__(self, name: str, value: Any) -> None: ... - def __eq__(self, o: object) -> bool: ... - def __ne__(self, o: object) -> bool: ... + def __setattr__(self, __name: str, __value: Any) -> None: ... + def __eq__(self, __o: object) -> bool: ... + def __ne__(self, __o: object) -> bool: ... def __str__(self) -> str: ... def __repr__(self) -> str: ... def __hash__(self) -> int: ... - def __format__(self, format_spec: str) -> str: ... - def __getattribute__(self, name: str) -> Any: ... - def __delattr__(self, name: str) -> None: ... + def __format__(self, __format_spec: str) -> str: ... + def __getattribute__(self, __name: str) -> Any: ... + def __delattr__(self, __name: str) -> None: ... def __sizeof__(self) -> int: ... - def __reduce__(self) -> str | Tuple[Any, ...]: ... + def __reduce__(self) -> str | Tuple[object, ...]: ... if sys.version_info >= (3, 8): - def __reduce_ex__(self, protocol: SupportsIndex) -> str | Tuple[Any, ...]: ... + def __reduce_ex__(self, __protocol: SupportsIndex) -> str | Tuple[object, ...]: ... else: - def __reduce_ex__(self, protocol: int) -> str | Tuple[Any, ...]: ... + def __reduce_ex__(self, __protocol: int) -> str | Tuple[object, ...]: ... def __dir__(self) -> Iterable[str]: ... def __init_subclass__(cls) -> None: ... -class staticmethod(object): # Special, only valid as a decorator. - __func__: Callable[..., Any] +class staticmethod(Generic[_R]): # Special, only valid as a decorator. + __func__: Callable[..., _R] __isabstractmethod__: bool - def __init__(self, f: Callable[..., Any]) -> None: ... + def __init__(self: staticmethod[_R], __f: Callable[..., _R]) -> None: ... def __new__(cls: Type[_T], *args: Any, **kwargs: Any) -> _T: ... - def __get__(self, obj: _T, type: Type[_T] | None = ...) -> Callable[..., Any]: ... + def __get__(self, __obj: _T, __type: Type[_T] | None = ...) -> Callable[..., _R]: ... + if sys.version_info >= (3, 10): + __name__: str + __qualname__: str + __wrapped__: Callable[..., _R] + def __call__(self, *args: Any, **kwargs: Any) -> _R: ... -class classmethod(object): # Special, only valid as a decorator. - __func__: Callable[..., Any] +class classmethod(Generic[_R]): # Special, only valid as a decorator. + __func__: Callable[..., _R] __isabstractmethod__: bool - def __init__(self, f: Callable[..., Any]) -> None: ... + def __init__(self: classmethod[_R], __f: Callable[..., _R]) -> None: ... def __new__(cls: Type[_T], *args: Any, **kwargs: Any) -> _T: ... - def __get__(self, obj: _T, type: Type[_T] | None = ...) -> Callable[..., Any]: ... + def __get__(self, __obj: _T, __type: Type[_T] | None = ...) -> Callable[..., _R]: ... + if sys.version_info >= (3, 10): + __name__: str + __qualname__: str + __wrapped__: Callable[..., _R] class type(object): __base__: type @@ -142,41 +146,44 @@ class type(object): __text_signature__: str | None __weakrefoffset__: int @overload - def __init__(self, o: object) -> None: ... + def __init__(self, __o: object) -> None: ... @overload - def __init__(self, name: str, bases: Tuple[type, ...], dict: dict[str, Any], **kwds: Any) -> None: ... + def __init__(self, __name: str, __bases: Tuple[type, ...], __dict: dict[str, Any], **kwds: Any) -> None: ... @overload - def __new__(cls, o: object) -> type: ... + def __new__(cls, __o: object) -> type: ... @overload - def __new__(cls: Type[_TT], name: str, bases: Tuple[type, ...], namespace: dict[str, Any], **kwds: Any) -> _TT: ... + def __new__(cls: Type[_TT], __name: str, __bases: Tuple[type, ...], __namespace: dict[str, Any], **kwds: Any) -> _TT: ... def __call__(self, *args: Any, **kwds: Any) -> Any: ... def __subclasses__(self: _TT) -> list[_TT]: ... - # Note: the documentation doesnt specify what the return type is, the standard + # Note: the documentation doesn't specify what the return type is, the standard # implementation seems to be returning a list. def mro(self) -> list[type]: ... - def __instancecheck__(self, instance: Any) -> bool: ... - def __subclasscheck__(self, subclass: type) -> bool: ... + def __instancecheck__(self, __instance: Any) -> bool: ... + def __subclasscheck__(self, __subclass: type) -> bool: ... @classmethod - def __prepare__(metacls, __name: str, __bases: Tuple[type, ...], **kwds: Any) -> Mapping[str, Any]: ... + def __prepare__(metacls, __name: str, __bases: Tuple[type, ...], **kwds: Any) -> Mapping[str, object]: ... if sys.version_info >= (3, 10): - def __or__(self, t: Any) -> types.UnionType: ... - def __ror__(self, t: Any) -> types.UnionType: ... + def __or__(self, __t: Any) -> types.UnionType: ... + def __ror__(self, __t: Any) -> types.UnionType: ... class super(object): @overload - def __init__(self, t: Any, obj: Any) -> None: ... + def __init__(self, __t: Any, __obj: Any) -> None: ... @overload - def __init__(self, t: Any) -> None: ... + def __init__(self, __t: Any) -> None: ... @overload def __init__(self) -> None: ... +_PositiveInteger = Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] +_NegativeInteger = Literal[-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, -20] + class int: @overload - def __new__(cls: Type[_T], x: str | bytes | SupportsInt | SupportsIndex | _SupportsTrunc = ...) -> _T: ... + def __new__(cls: Type[_T], __x: str | bytes | SupportsInt | SupportsIndex | SupportsTrunc = ...) -> _T: ... @overload - def __new__(cls: Type[_T], x: str | bytes | bytearray, base: SupportsIndex) -> _T: ... + def __new__(cls: Type[_T], __x: str | bytes | bytearray, base: SupportsIndex) -> _T: ... if sys.version_info >= (3, 8): - def as_integer_ratio(self) -> Tuple[int, Literal[1]]: ... + def as_integer_ratio(self) -> tuple[int, Literal[1]]: ... @property def real(self) -> int: ... @property @@ -194,49 +201,57 @@ class int: def from_bytes( cls, bytes: Iterable[SupportsIndex] | SupportsBytes, byteorder: Literal["little", "big"], *, signed: bool = ... ) -> int: ... # TODO buffer object argument - def __add__(self, x: int) -> int: ... - def __sub__(self, x: int) -> int: ... - def __mul__(self, x: int) -> int: ... - def __floordiv__(self, x: int) -> int: ... - def __truediv__(self, x: int) -> float: ... - def __mod__(self, x: int) -> int: ... - def __divmod__(self, x: int) -> Tuple[int, int]: ... - def __radd__(self, x: int) -> int: ... - def __rsub__(self, x: int) -> int: ... - def __rmul__(self, x: int) -> int: ... - def __rfloordiv__(self, x: int) -> int: ... - def __rtruediv__(self, x: int) -> float: ... - def __rmod__(self, x: int) -> int: ... - def __rdivmod__(self, x: int) -> Tuple[int, int]: ... - @overload - def __pow__(self, __x: Literal[2], __modulo: int | None = ...) -> int: ... - @overload - def __pow__(self, __x: int, __modulo: int | None = ...) -> Any: ... # Return type can be int or float, depending on x. - def __rpow__(self, x: int, mod: int | None = ...) -> Any: ... - def __and__(self, n: int) -> int: ... - def __or__(self, n: int) -> int: ... - def __xor__(self, n: int) -> int: ... - def __lshift__(self, n: int) -> int: ... - def __rshift__(self, n: int) -> int: ... - def __rand__(self, n: int) -> int: ... - def __ror__(self, n: int) -> int: ... - def __rxor__(self, n: int) -> int: ... - def __rlshift__(self, n: int) -> int: ... - def __rrshift__(self, n: int) -> int: ... + def __add__(self, __x: int) -> int: ... + def __sub__(self, __x: int) -> int: ... + def __mul__(self, __x: int) -> int: ... + def __floordiv__(self, __x: int) -> int: ... + def __truediv__(self, __x: int) -> float: ... + def __mod__(self, __x: int) -> int: ... + def __divmod__(self, __x: int) -> tuple[int, int]: ... + def __radd__(self, __x: int) -> int: ... + def __rsub__(self, __x: int) -> int: ... + def __rmul__(self, __x: int) -> int: ... + def __rfloordiv__(self, __x: int) -> int: ... + def __rtruediv__(self, __x: int) -> float: ... + def __rmod__(self, __x: int) -> int: ... + def __rdivmod__(self, __x: int) -> tuple[int, int]: ... + @overload + def __pow__(self, __x: int, __modulo: Literal[0]) -> NoReturn: ... + @overload + def __pow__(self, __x: int, __modulo: int) -> int: ... + @overload + def __pow__(self, __x: _PositiveInteger, __modulo: None = ...) -> int: ... + @overload + def __pow__(self, __x: _NegativeInteger, __modulo: None = ...) -> float: ... + # positive x -> int; negative x -> float + # return type must be Any as `int | float` causes too many false-positive errors + @overload + def __pow__(self, __x: int, __modulo: None = ...) -> Any: ... + def __rpow__(self, __x: int, __mod: int | None = ...) -> Any: ... + def __and__(self, __n: int) -> int: ... + def __or__(self, __n: int) -> int: ... + def __xor__(self, __n: int) -> int: ... + def __lshift__(self, __n: int) -> int: ... + def __rshift__(self, __n: int) -> int: ... + def __rand__(self, __n: int) -> int: ... + def __ror__(self, __n: int) -> int: ... + def __rxor__(self, __n: int) -> int: ... + def __rlshift__(self, __n: int) -> int: ... + def __rrshift__(self, __n: int) -> int: ... def __neg__(self) -> int: ... def __pos__(self) -> int: ... def __invert__(self) -> int: ... def __trunc__(self) -> int: ... def __ceil__(self) -> int: ... def __floor__(self) -> int: ... - def __round__(self, ndigits: SupportsIndex = ...) -> int: ... - def __getnewargs__(self) -> Tuple[int]: ... - def __eq__(self, x: object) -> bool: ... - def __ne__(self, x: object) -> bool: ... - def __lt__(self, x: int) -> bool: ... - def __le__(self, x: int) -> bool: ... - def __gt__(self, x: int) -> bool: ... - def __ge__(self, x: int) -> bool: ... + def __round__(self, __ndigits: SupportsIndex = ...) -> int: ... + def __getnewargs__(self) -> tuple[int]: ... + def __eq__(self, __x: object) -> bool: ... + def __ne__(self, __x: object) -> bool: ... + def __lt__(self, __x: int) -> bool: ... + def __le__(self, __x: int) -> bool: ... + def __gt__(self, __x: int) -> bool: ... + def __ge__(self, __x: int) -> bool: ... def __str__(self) -> str: ... def __float__(self) -> float: ... def __int__(self) -> int: ... @@ -247,7 +262,7 @@ class int: class float: def __new__(cls: Type[_T], x: SupportsFloat | SupportsIndex | str | bytes | bytearray = ...) -> _T: ... - def as_integer_ratio(self) -> Tuple[int, int]: ... + def as_integer_ratio(self) -> tuple[int, int]: ... def hex(self) -> str: ... def is_integer(self) -> bool: ... @classmethod @@ -257,39 +272,42 @@ class float: @property def imag(self) -> float: ... def conjugate(self) -> float: ... - def __add__(self, x: float) -> float: ... - def __sub__(self, x: float) -> float: ... - def __mul__(self, x: float) -> float: ... - def __floordiv__(self, x: float) -> float: ... - def __truediv__(self, x: float) -> float: ... - def __mod__(self, x: float) -> float: ... - def __divmod__(self, x: float) -> Tuple[float, float]: ... - def __pow__( - self, x: float, mod: None = ... - ) -> float: ... # In Python 3, returns complex if self is negative and x is not whole - def __radd__(self, x: float) -> float: ... - def __rsub__(self, x: float) -> float: ... - def __rmul__(self, x: float) -> float: ... - def __rfloordiv__(self, x: float) -> float: ... - def __rtruediv__(self, x: float) -> float: ... - def __rmod__(self, x: float) -> float: ... - def __rdivmod__(self, x: float) -> Tuple[float, float]: ... - def __rpow__(self, x: float, mod: None = ...) -> float: ... - def __getnewargs__(self) -> Tuple[float]: ... + def __add__(self, __x: float) -> float: ... + def __sub__(self, __x: float) -> float: ... + def __mul__(self, __x: float) -> float: ... + def __floordiv__(self, __x: float) -> float: ... + def __truediv__(self, __x: float) -> float: ... + def __mod__(self, __x: float) -> float: ... + def __divmod__(self, __x: float) -> tuple[float, float]: ... + @overload + def __pow__(self, __x: int, __mod: None = ...) -> float: ... + # positive x -> float; negative x -> complex + # return type must be Any as `float | complex` causes too many false-positive errors + @overload + def __pow__(self, __x: float, __mod: None = ...) -> Any: ... + def __radd__(self, __x: float) -> float: ... + def __rsub__(self, __x: float) -> float: ... + def __rmul__(self, __x: float) -> float: ... + def __rfloordiv__(self, __x: float) -> float: ... + def __rtruediv__(self, __x: float) -> float: ... + def __rmod__(self, __x: float) -> float: ... + def __rdivmod__(self, __x: float) -> tuple[float, float]: ... + def __rpow__(self, __x: float, __mod: None = ...) -> float: ... + def __getnewargs__(self) -> tuple[float]: ... def __trunc__(self) -> int: ... if sys.version_info >= (3, 9): def __ceil__(self) -> int: ... def __floor__(self) -> int: ... @overload - def __round__(self, ndigits: None = ...) -> int: ... + def __round__(self, __ndigits: None = ...) -> int: ... @overload - def __round__(self, ndigits: SupportsIndex) -> float: ... - def __eq__(self, x: object) -> bool: ... - def __ne__(self, x: object) -> bool: ... - def __lt__(self, x: float) -> bool: ... - def __le__(self, x: float) -> bool: ... - def __gt__(self, x: float) -> bool: ... - def __ge__(self, x: float) -> bool: ... + def __round__(self, __ndigits: SupportsIndex) -> float: ... + def __eq__(self, __x: object) -> bool: ... + def __ne__(self, __x: object) -> bool: ... + def __lt__(self, __x: float) -> bool: ... + def __le__(self, __x: float) -> bool: ... + def __gt__(self, __x: float) -> bool: ... + def __ge__(self, __x: float) -> bool: ... def __neg__(self) -> float: ... def __pos__(self) -> float: ... def __str__(self) -> str: ... @@ -309,18 +327,18 @@ class complex: @property def imag(self) -> float: ... def conjugate(self) -> complex: ... - def __add__(self, x: complex) -> complex: ... - def __sub__(self, x: complex) -> complex: ... - def __mul__(self, x: complex) -> complex: ... - def __pow__(self, x: complex, mod: None = ...) -> complex: ... - def __truediv__(self, x: complex) -> complex: ... - def __radd__(self, x: complex) -> complex: ... - def __rsub__(self, x: complex) -> complex: ... - def __rmul__(self, x: complex) -> complex: ... - def __rpow__(self, x: complex, mod: None = ...) -> complex: ... - def __rtruediv__(self, x: complex) -> complex: ... - def __eq__(self, x: object) -> bool: ... - def __ne__(self, x: object) -> bool: ... + def __add__(self, __x: complex) -> complex: ... + def __sub__(self, __x: complex) -> complex: ... + def __mul__(self, __x: complex) -> complex: ... + def __pow__(self, __x: complex, mod: None = ...) -> complex: ... + def __truediv__(self, __x: complex) -> complex: ... + def __radd__(self, __x: complex) -> complex: ... + def __rsub__(self, __x: complex) -> complex: ... + def __rmul__(self, __x: complex) -> complex: ... + def __rpow__(self, __x: complex, __mod: None = ...) -> complex: ... + def __rtruediv__(self, __x: complex) -> complex: ... + def __eq__(self, __x: object) -> bool: ... + def __ne__(self, __x: object) -> bool: ... def __neg__(self) -> complex: ... def __pos__(self) -> complex: ... def __str__(self) -> str: ... @@ -333,7 +351,7 @@ class _FormatMapMapping(Protocol): class str(Sequence[str]): @overload - def __new__(cls: Type[_T], o: object = ...) -> _T: ... + def __new__(cls: Type[_T], object: object = ...) -> _T: ... @overload def __new__(cls: Type[_T], o: bytes, encoding: str = ..., errors: str = ...) -> _T: ... def capitalize(self) -> str: ... @@ -369,7 +387,7 @@ class str(Sequence[str]): def ljust(self, __width: SupportsIndex, __fillchar: str = ...) -> str: ... def lower(self) -> str: ... def lstrip(self, __chars: str | None = ...) -> str: ... - def partition(self, __sep: str) -> Tuple[str, str, str]: ... + def partition(self, __sep: str) -> tuple[str, str, str]: ... def replace(self, __old: str, __new: str, __count: SupportsIndex = ...) -> str: ... if sys.version_info >= (3, 9): def removeprefix(self, __prefix: str) -> str: ... @@ -377,7 +395,7 @@ class str(Sequence[str]): def rfind(self, __sub: str, __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ...) -> int: ... def rindex(self, __sub: str, __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ...) -> int: ... def rjust(self, __width: SupportsIndex, __fillchar: str = ...) -> str: ... - def rpartition(self, __sep: str) -> Tuple[str, str, str]: ... + def rpartition(self, __sep: str) -> tuple[str, str, str]: ... def rsplit(self, sep: str | None = ..., maxsplit: SupportsIndex = ...) -> list[str]: ... def rstrip(self, __chars: str | None = ...) -> str: ... def split(self, sep: str | None = ..., maxsplit: SupportsIndex = ...) -> list[str]: ... @@ -397,37 +415,37 @@ class str(Sequence[str]): @staticmethod @overload def maketrans(__x: str, __y: str, __z: str | None = ...) -> dict[int, int | None]: ... - def __add__(self, s: str) -> str: ... + def __add__(self, __s: str) -> str: ... # Incompatible with Sequence.__contains__ - def __contains__(self, o: str) -> bool: ... # type: ignore - def __eq__(self, x: object) -> bool: ... - def __ge__(self, x: str) -> bool: ... - def __getitem__(self, i: int | slice) -> str: ... - def __gt__(self, x: str) -> bool: ... + def __contains__(self, __o: str) -> bool: ... # type: ignore[override] + def __eq__(self, __x: object) -> bool: ... + def __ge__(self, __x: str) -> bool: ... + def __getitem__(self, __i: int | slice) -> str: ... + def __gt__(self, __x: str) -> bool: ... def __hash__(self) -> int: ... def __iter__(self) -> Iterator[str]: ... - def __le__(self, x: str) -> bool: ... + def __le__(self, __x: str) -> bool: ... def __len__(self) -> int: ... - def __lt__(self, x: str) -> bool: ... - def __mod__(self, x: Any) -> str: ... - def __mul__(self, n: SupportsIndex) -> str: ... - def __ne__(self, x: object) -> bool: ... + def __lt__(self, __x: str) -> bool: ... + def __mod__(self, __x: Any) -> str: ... + def __mul__(self, __n: SupportsIndex) -> str: ... + def __ne__(self, __x: object) -> bool: ... def __repr__(self) -> str: ... def __rmul__(self, n: SupportsIndex) -> str: ... def __str__(self) -> str: ... - def __getnewargs__(self) -> Tuple[str]: ... + def __getnewargs__(self) -> tuple[str]: ... class bytes(ByteString): @overload - def __new__(cls: Type[_T], ints: Iterable[SupportsIndex]) -> _T: ... + def __new__(cls: Type[_T], __ints: Iterable[SupportsIndex]) -> _T: ... @overload - def __new__(cls: Type[_T], string: str, encoding: str, errors: str = ...) -> _T: ... + def __new__(cls: Type[_T], __string: str, encoding: str, errors: str = ...) -> _T: ... @overload - def __new__(cls: Type[_T], length: SupportsIndex) -> _T: ... + def __new__(cls: Type[_T], __length: SupportsIndex) -> _T: ... @overload def __new__(cls: Type[_T]) -> _T: ... @overload - def __new__(cls: Type[_T], o: SupportsBytes) -> _T: ... + def __new__(cls: Type[_T], __o: SupportsBytes) -> _T: ... def capitalize(self) -> bytes: ... def center(self, __width: SupportsIndex, __fillchar: bytes = ...) -> bytes: ... def count( @@ -464,7 +482,7 @@ class bytes(ByteString): def ljust(self, __width: SupportsIndex, __fillchar: bytes = ...) -> bytes: ... def lower(self) -> bytes: ... def lstrip(self, __bytes: bytes | None = ...) -> bytes: ... - def partition(self, __sep: bytes) -> Tuple[bytes, bytes, bytes]: ... + def partition(self, __sep: bytes) -> tuple[bytes, bytes, bytes]: ... def replace(self, __old: bytes, __new: bytes, __count: SupportsIndex = ...) -> bytes: ... if sys.version_info >= (3, 9): def removeprefix(self, __prefix: bytes) -> bytes: ... @@ -476,7 +494,7 @@ class bytes(ByteString): self, __sub: bytes | SupportsIndex, __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ... ) -> int: ... def rjust(self, __width: SupportsIndex, __fillchar: bytes = ...) -> bytes: ... - def rpartition(self, __sep: bytes) -> Tuple[bytes, bytes, bytes]: ... + def rpartition(self, __sep: bytes) -> tuple[bytes, bytes, bytes]: ... def rsplit(self, sep: bytes | None = ..., maxsplit: SupportsIndex = ...) -> list[bytes]: ... def rstrip(self, __bytes: bytes | None = ...) -> bytes: ... def split(self, sep: bytes | None = ..., maxsplit: SupportsIndex = ...) -> list[bytes]: ... @@ -491,7 +509,7 @@ class bytes(ByteString): def upper(self) -> bytes: ... def zfill(self, __width: SupportsIndex) -> bytes: ... @classmethod - def fromhex(cls, __s: str) -> bytes: ... + def fromhex(cls: Type[_T], __s: str) -> _T: ... @staticmethod def maketrans(__frm: bytes, __to: bytes) -> bytes: ... def __len__(self) -> int: ... @@ -500,32 +518,32 @@ class bytes(ByteString): def __repr__(self) -> str: ... def __hash__(self) -> int: ... @overload - def __getitem__(self, i: SupportsIndex) -> int: ... + def __getitem__(self, __i: SupportsIndex) -> int: ... @overload - def __getitem__(self, s: slice) -> bytes: ... - def __add__(self, s: bytes) -> bytes: ... - def __mul__(self, n: SupportsIndex) -> bytes: ... - def __rmul__(self, n: SupportsIndex) -> bytes: ... - def __mod__(self, value: Any) -> bytes: ... + def __getitem__(self, __s: slice) -> bytes: ... + def __add__(self, __s: bytes) -> bytes: ... + def __mul__(self, __n: SupportsIndex) -> bytes: ... + def __rmul__(self, __n: SupportsIndex) -> bytes: ... + def __mod__(self, __value: Any) -> bytes: ... # Incompatible with Sequence.__contains__ - def __contains__(self, o: SupportsIndex | bytes) -> bool: ... # type: ignore - def __eq__(self, x: object) -> bool: ... - def __ne__(self, x: object) -> bool: ... - def __lt__(self, x: bytes) -> bool: ... - def __le__(self, x: bytes) -> bool: ... - def __gt__(self, x: bytes) -> bool: ... - def __ge__(self, x: bytes) -> bool: ... - def __getnewargs__(self) -> Tuple[bytes]: ... + def __contains__(self, __o: SupportsIndex | bytes) -> bool: ... # type: ignore[override] + def __eq__(self, __x: object) -> bool: ... + def __ne__(self, __x: object) -> bool: ... + def __lt__(self, __x: bytes) -> bool: ... + def __le__(self, __x: bytes) -> bool: ... + def __gt__(self, __x: bytes) -> bool: ... + def __ge__(self, __x: bytes) -> bool: ... + def __getnewargs__(self) -> tuple[bytes]: ... class bytearray(MutableSequence[int], ByteString): @overload def __init__(self) -> None: ... @overload - def __init__(self, ints: Iterable[SupportsIndex]) -> None: ... + def __init__(self, __ints: Iterable[SupportsIndex]) -> None: ... @overload - def __init__(self, string: str, encoding: str, errors: str = ...) -> None: ... + def __init__(self, __string: str, encoding: str, errors: str = ...) -> None: ... @overload - def __init__(self, length: SupportsIndex) -> None: ... + def __init__(self, __length: SupportsIndex) -> None: ... def append(self, __item: SupportsIndex) -> None: ... def capitalize(self) -> bytearray: ... def center(self, __width: SupportsIndex, __fillchar: bytes = ...) -> bytearray: ... @@ -566,7 +584,7 @@ class bytearray(MutableSequence[int], ByteString): def ljust(self, __width: SupportsIndex, __fillchar: bytes = ...) -> bytearray: ... def lower(self) -> bytearray: ... def lstrip(self, __bytes: bytes | None = ...) -> bytearray: ... - def partition(self, __sep: bytes) -> Tuple[bytearray, bytearray, bytearray]: ... + def partition(self, __sep: bytes) -> tuple[bytearray, bytearray, bytearray]: ... if sys.version_info >= (3, 9): def removeprefix(self, __prefix: bytes) -> bytearray: ... def removesuffix(self, __suffix: bytes) -> bytearray: ... @@ -578,7 +596,7 @@ class bytearray(MutableSequence[int], ByteString): self, __sub: bytes | SupportsIndex, __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ... ) -> int: ... def rjust(self, __width: SupportsIndex, __fillchar: bytes = ...) -> bytearray: ... - def rpartition(self, __sep: bytes) -> Tuple[bytearray, bytearray, bytearray]: ... + def rpartition(self, __sep: bytes) -> tuple[bytearray, bytearray, bytearray]: ... def rsplit(self, sep: bytes | None = ..., maxsplit: SupportsIndex = ...) -> list[bytearray]: ... def rstrip(self, __bytes: bytes | None = ...) -> bytearray: ... def split(self, sep: bytes | None = ..., maxsplit: SupportsIndex = ...) -> list[bytearray]: ... @@ -600,31 +618,32 @@ class bytearray(MutableSequence[int], ByteString): def __iter__(self) -> Iterator[int]: ... def __str__(self) -> str: ... def __repr__(self) -> str: ... - __hash__: None # type: ignore + __hash__: None # type: ignore[assignment] @overload - def __getitem__(self, i: SupportsIndex) -> int: ... + def __getitem__(self, __i: SupportsIndex) -> int: ... @overload - def __getitem__(self, s: slice) -> bytearray: ... + def __getitem__(self, __s: slice) -> bytearray: ... @overload - def __setitem__(self, i: SupportsIndex, x: SupportsIndex) -> None: ... + def __setitem__(self, __i: SupportsIndex, x: SupportsIndex) -> None: ... @overload - def __setitem__(self, s: slice, x: Iterable[SupportsIndex] | bytes) -> None: ... - def __delitem__(self, i: SupportsIndex | slice) -> None: ... - def __add__(self, s: bytes) -> bytearray: ... - def __iadd__(self, s: Iterable[int]) -> bytearray: ... - def __mul__(self, n: SupportsIndex) -> bytearray: ... - def __rmul__(self, n: SupportsIndex) -> bytearray: ... - def __imul__(self, n: SupportsIndex) -> bytearray: ... - def __mod__(self, value: Any) -> bytes: ... + def __setitem__(self, __s: slice, __x: Iterable[SupportsIndex] | bytes) -> None: ... + def __delitem__(self, __i: SupportsIndex | slice) -> None: ... + def __add__(self, __s: bytes) -> bytearray: ... + def __iadd__(self, __s: Iterable[int]) -> bytearray: ... + def __mul__(self, __n: SupportsIndex) -> bytearray: ... + def __rmul__(self, __n: SupportsIndex) -> bytearray: ... + def __imul__(self, __n: SupportsIndex) -> bytearray: ... + def __mod__(self, __value: Any) -> bytes: ... # Incompatible with Sequence.__contains__ - def __contains__(self, o: SupportsIndex | bytes) -> bool: ... # type: ignore - def __eq__(self, x: object) -> bool: ... - def __ne__(self, x: object) -> bool: ... - def __lt__(self, x: bytes) -> bool: ... - def __le__(self, x: bytes) -> bool: ... - def __gt__(self, x: bytes) -> bool: ... - def __ge__(self, x: bytes) -> bool: ... + def __contains__(self, __o: SupportsIndex | bytes) -> bool: ... # type: ignore[override] + def __eq__(self, __x: object) -> bool: ... + def __ne__(self, __x: object) -> bool: ... + def __lt__(self, __x: bytes) -> bool: ... + def __le__(self, __x: bytes) -> bool: ... + def __gt__(self, __x: bytes) -> bool: ... + def __ge__(self, __x: bytes) -> bool: ... +@final class memoryview(Sized, Sequence[int]): format: str itemsize: int @@ -642,20 +661,20 @@ class memoryview(Sized, Sequence[int]): def __init__(self, obj: ReadableBuffer) -> None: ... def __enter__(self: Self) -> Self: ... def __exit__( - self, exc_type: Type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None + self, __exc_type: Type[BaseException] | None, __exc_val: BaseException | None, __exc_tb: TracebackType | None ) -> None: ... def cast(self, format: str, shape: list[int] | Tuple[int, ...] = ...) -> memoryview: ... @overload - def __getitem__(self, i: SupportsIndex) -> int: ... + def __getitem__(self, __i: SupportsIndex) -> int: ... @overload - def __getitem__(self, s: slice) -> memoryview: ... - def __contains__(self, x: object) -> bool: ... + def __getitem__(self, __s: slice) -> memoryview: ... + def __contains__(self, __x: object) -> bool: ... def __iter__(self) -> Iterator[int]: ... def __len__(self) -> int: ... @overload - def __setitem__(self, s: slice, o: bytes) -> None: ... + def __setitem__(self, __s: slice, __o: bytes) -> None: ... @overload - def __setitem__(self, i: SupportsIndex, o: SupportsIndex) -> None: ... + def __setitem__(self, __i: SupportsIndex, __o: SupportsIndex) -> None: ... if sys.version_info >= (3, 8): def tobytes(self, order: Literal["C", "F", "A"] | None = ...) -> bytes: ... else: @@ -673,65 +692,66 @@ class memoryview(Sized, Sequence[int]): class bool(int): def __new__(cls: Type[_T], __o: object = ...) -> _T: ... @overload - def __and__(self, x: bool) -> bool: ... + def __and__(self, __x: bool) -> bool: ... @overload - def __and__(self, x: int) -> int: ... + def __and__(self, __x: int) -> int: ... @overload - def __or__(self, x: bool) -> bool: ... + def __or__(self, __x: bool) -> bool: ... @overload - def __or__(self, x: int) -> int: ... + def __or__(self, __x: int) -> int: ... @overload - def __xor__(self, x: bool) -> bool: ... + def __xor__(self, __x: bool) -> bool: ... @overload - def __xor__(self, x: int) -> int: ... + def __xor__(self, __x: int) -> int: ... @overload - def __rand__(self, x: bool) -> bool: ... + def __rand__(self, __x: bool) -> bool: ... @overload - def __rand__(self, x: int) -> int: ... + def __rand__(self, __x: int) -> int: ... @overload - def __ror__(self, x: bool) -> bool: ... + def __ror__(self, __x: bool) -> bool: ... @overload - def __ror__(self, x: int) -> int: ... + def __ror__(self, __x: int) -> int: ... @overload - def __rxor__(self, x: bool) -> bool: ... + def __rxor__(self, __x: bool) -> bool: ... @overload - def __rxor__(self, x: int) -> int: ... - def __getnewargs__(self) -> Tuple[int]: ... + def __rxor__(self, __x: int) -> int: ... + def __getnewargs__(self) -> tuple[int]: ... +@final class slice(object): start: Any step: Any stop: Any @overload - def __init__(self, stop: Any) -> None: ... + def __init__(self, __stop: Any) -> None: ... @overload - def __init__(self, start: Any, stop: Any, step: Any = ...) -> None: ... - __hash__: None # type: ignore - def indices(self, len: SupportsIndex) -> Tuple[int, int, int]: ... + def __init__(self, __start: Any, __stop: Any, __step: Any = ...) -> None: ... + __hash__: None # type: ignore[assignment] + def indices(self, __len: SupportsIndex) -> tuple[int, int, int]: ... class tuple(Sequence[_T_co], Generic[_T_co]): - def __new__(cls: Type[_T], iterable: Iterable[_T_co] = ...) -> _T: ... + def __new__(cls: Type[_T], __iterable: Iterable[_T_co] = ...) -> _T: ... def __len__(self) -> int: ... - def __contains__(self, x: object) -> bool: ... + def __contains__(self, __x: object) -> bool: ... @overload - def __getitem__(self, x: int) -> _T_co: ... + def __getitem__(self, __x: int) -> _T_co: ... @overload - def __getitem__(self, x: slice) -> Tuple[_T_co, ...]: ... + def __getitem__(self, __x: slice) -> Tuple[_T_co, ...]: ... def __iter__(self) -> Iterator[_T_co]: ... - def __lt__(self, x: Tuple[_T_co, ...]) -> bool: ... - def __le__(self, x: Tuple[_T_co, ...]) -> bool: ... - def __gt__(self, x: Tuple[_T_co, ...]) -> bool: ... - def __ge__(self, x: Tuple[_T_co, ...]) -> bool: ... + def __lt__(self, __x: Tuple[_T_co, ...]) -> bool: ... + def __le__(self, __x: Tuple[_T_co, ...]) -> bool: ... + def __gt__(self, __x: Tuple[_T_co, ...]) -> bool: ... + def __ge__(self, __x: Tuple[_T_co, ...]) -> bool: ... @overload - def __add__(self, x: Tuple[_T_co, ...]) -> Tuple[_T_co, ...]: ... + def __add__(self, __x: Tuple[_T_co, ...]) -> Tuple[_T_co, ...]: ... @overload - def __add__(self, x: Tuple[_T, ...]) -> Tuple[_T_co | _T, ...]: ... - def __mul__(self, n: SupportsIndex) -> Tuple[_T_co, ...]: ... - def __rmul__(self, n: SupportsIndex) -> Tuple[_T_co, ...]: ... + def __add__(self, __x: Tuple[_T, ...]) -> Tuple[_T_co | _T, ...]: ... + def __mul__(self, __n: SupportsIndex) -> Tuple[_T_co, ...]: ... + def __rmul__(self, __n: SupportsIndex) -> Tuple[_T_co, ...]: ... def count(self, __value: Any) -> int: ... def index(self, __value: Any, __start: SupportsIndex = ..., __stop: SupportsIndex = ...) -> int: ... if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any) -> GenericAlias: ... + def __class_getitem__(cls, __item: Any) -> GenericAlias: ... class function: # TODO not defined in builtins! @@ -745,7 +765,7 @@ class list(MutableSequence[_T], Generic[_T]): @overload def __init__(self) -> None: ... @overload - def __init__(self, iterable: Iterable[_T]) -> None: ... + def __init__(self, __iterable: Iterable[_T]) -> None: ... def clear(self) -> None: ... def copy(self) -> list[_T]: ... def append(self, __object: _T) -> None: ... @@ -757,35 +777,35 @@ class list(MutableSequence[_T], Generic[_T]): def remove(self, __value: _T) -> None: ... def reverse(self) -> None: ... @overload - def sort(self: list[SupportsLessThanT], *, key: None = ..., reverse: bool = ...) -> None: ... + def sort(self: list[SupportsRichComparisonT], *, key: None = ..., reverse: bool = ...) -> None: ... @overload - def sort(self, *, key: Callable[[_T], SupportsLessThan], reverse: bool = ...) -> None: ... + def sort(self, *, key: Callable[[_T], SupportsRichComparison], reverse: bool = ...) -> None: ... def __len__(self) -> int: ... def __iter__(self) -> Iterator[_T]: ... def __str__(self) -> str: ... - __hash__: None # type: ignore + __hash__: None # type: ignore[assignment] @overload - def __getitem__(self, i: SupportsIndex) -> _T: ... + def __getitem__(self, __i: SupportsIndex) -> _T: ... @overload - def __getitem__(self, s: slice) -> list[_T]: ... + def __getitem__(self, __s: slice) -> list[_T]: ... @overload - def __setitem__(self, i: SupportsIndex, o: _T) -> None: ... + def __setitem__(self, __i: SupportsIndex, __o: _T) -> None: ... @overload - def __setitem__(self, s: slice, o: Iterable[_T]) -> None: ... - def __delitem__(self, i: SupportsIndex | slice) -> None: ... - def __add__(self, x: list[_T]) -> list[_T]: ... - def __iadd__(self: _S, x: Iterable[_T]) -> _S: ... - def __mul__(self, n: SupportsIndex) -> list[_T]: ... - def __rmul__(self, n: SupportsIndex) -> list[_T]: ... - def __imul__(self: _S, n: SupportsIndex) -> _S: ... - def __contains__(self, o: object) -> bool: ... + def __setitem__(self, __s: slice, __o: Iterable[_T]) -> None: ... + def __delitem__(self, __i: SupportsIndex | slice) -> None: ... + def __add__(self, __x: list[_T]) -> list[_T]: ... + def __iadd__(self: _S, __x: Iterable[_T]) -> _S: ... + def __mul__(self, __n: SupportsIndex) -> list[_T]: ... + def __rmul__(self, __n: SupportsIndex) -> list[_T]: ... + def __imul__(self: _S, __n: SupportsIndex) -> _S: ... + def __contains__(self, __o: object) -> bool: ... def __reversed__(self) -> Iterator[_T]: ... - def __gt__(self, x: list[_T]) -> bool: ... - def __ge__(self, x: list[_T]) -> bool: ... - def __lt__(self, x: list[_T]) -> bool: ... - def __le__(self, x: list[_T]) -> bool: ... + def __gt__(self, __x: list[_T]) -> bool: ... + def __ge__(self, __x: list[_T]) -> bool: ... + def __lt__(self, __x: list[_T]) -> bool: ... + def __le__(self, __x: list[_T]) -> bool: ... if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any) -> GenericAlias: ... + def __class_getitem__(cls, __item: Any) -> GenericAlias: ... class dict(MutableMapping[_KT, _VT], Generic[_KT, _VT]): @overload @@ -793,23 +813,27 @@ class dict(MutableMapping[_KT, _VT], Generic[_KT, _VT]): @overload def __init__(self: dict[str, _VT], **kwargs: _VT) -> None: ... @overload - def __init__(self, map: SupportsKeysAndGetItem[_KT, _VT], **kwargs: _VT) -> None: ... + def __init__(self, __map: SupportsKeysAndGetItem[_KT, _VT], **kwargs: _VT) -> None: ... + @overload + def __init__(self, __iterable: Iterable[tuple[_KT, _VT]], **kwargs: _VT) -> None: ... + # Next overload is for dict(string.split(sep) for string in iterable) + # Cannot be Iterable[Sequence[_T]] or otherwise dict(["foo", "bar", "baz"]) is not an error @overload - def __init__(self, iterable: Iterable[Tuple[_KT, _VT]], **kwargs: _VT) -> None: ... + def __init__(self: dict[str, str], __iterable: Iterable[list[str]]) -> None: ... def __new__(cls: Type[_T1], *args: Any, **kwargs: Any) -> _T1: ... def clear(self) -> None: ... def copy(self) -> dict[_KT, _VT]: ... - def popitem(self) -> Tuple[_KT, _VT]: ... + def popitem(self) -> tuple[_KT, _VT]: ... def setdefault(self, __key: _KT, __default: _VT = ...) -> _VT: ... @overload def update(self, __m: Mapping[_KT, _VT], **kwargs: _VT) -> None: ... @overload - def update(self, __m: Iterable[Tuple[_KT, _VT]], **kwargs: _VT) -> None: ... + def update(self, __m: Iterable[tuple[_KT, _VT]], **kwargs: _VT) -> None: ... @overload def update(self, **kwargs: _VT) -> None: ... - def keys(self) -> KeysView[_KT]: ... - def values(self) -> ValuesView[_VT]: ... - def items(self) -> ItemsView[_KT, _VT]: ... + def keys(self) -> dict_keys[_KT, _VT]: ... + def values(self) -> dict_values[_KT, _VT]: ... + def items(self) -> dict_items[_KT, _VT]: ... @classmethod @overload def fromkeys(cls, __iterable: Iterable[_T], __value: None = ...) -> dict[_T, Any | None]: ... @@ -817,108 +841,109 @@ class dict(MutableMapping[_KT, _VT], Generic[_KT, _VT]): @overload def fromkeys(cls, __iterable: Iterable[_T], __value: _S) -> dict[_T, _S]: ... def __len__(self) -> int: ... - def __getitem__(self, k: _KT) -> _VT: ... - def __setitem__(self, k: _KT, v: _VT) -> None: ... - def __delitem__(self, v: _KT) -> None: ... + def __getitem__(self, __k: _KT) -> _VT: ... + def __setitem__(self, __k: _KT, v: _VT) -> None: ... + def __delitem__(self, __v: _KT) -> None: ... def __iter__(self) -> Iterator[_KT]: ... if sys.version_info >= (3, 8): def __reversed__(self) -> Iterator[_KT]: ... def __str__(self) -> str: ... - __hash__: None # type: ignore + __hash__: None # type: ignore[assignment] if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any) -> GenericAlias: ... + def __class_getitem__(cls, __item: Any) -> GenericAlias: ... def __or__(self, __value: Mapping[_T1, _T2]) -> dict[_KT | _T1, _VT | _T2]: ... def __ror__(self, __value: Mapping[_T1, _T2]) -> dict[_KT | _T1, _VT | _T2]: ... - def __ior__(self, __value: Mapping[_KT, _VT]) -> dict[_KT, _VT]: ... # type: ignore + def __ior__(self, __value: Mapping[_KT, _VT]) -> dict[_KT, _VT]: ... # type: ignore[misc] class set(MutableSet[_T], Generic[_T]): - def __init__(self, iterable: Iterable[_T] = ...) -> None: ... - def add(self, element: _T) -> None: ... + def __init__(self, __iterable: Iterable[_T] = ...) -> None: ... + def add(self, __element: _T) -> None: ... def clear(self) -> None: ... - def copy(self) -> Set[_T]: ... - def difference(self, *s: Iterable[Any]) -> Set[_T]: ... + def copy(self) -> set[_T]: ... + def difference(self, *s: Iterable[Any]) -> set[_T]: ... def difference_update(self, *s: Iterable[Any]) -> None: ... - def discard(self, element: _T) -> None: ... - def intersection(self, *s: Iterable[Any]) -> Set[_T]: ... + def discard(self, __element: _T) -> None: ... + def intersection(self, *s: Iterable[Any]) -> set[_T]: ... def intersection_update(self, *s: Iterable[Any]) -> None: ... - def isdisjoint(self, s: Iterable[Any]) -> bool: ... - def issubset(self, s: Iterable[Any]) -> bool: ... - def issuperset(self, s: Iterable[Any]) -> bool: ... + def isdisjoint(self, __s: Iterable[Any]) -> bool: ... + def issubset(self, __s: Iterable[Any]) -> bool: ... + def issuperset(self, __s: Iterable[Any]) -> bool: ... def pop(self) -> _T: ... - def remove(self, element: _T) -> None: ... - def symmetric_difference(self, s: Iterable[_T]) -> Set[_T]: ... - def symmetric_difference_update(self, s: Iterable[_T]) -> None: ... - def union(self, *s: Iterable[_T]) -> Set[_T]: ... + def remove(self, __element: _T) -> None: ... + def symmetric_difference(self, __s: Iterable[_T]) -> set[_T]: ... + def symmetric_difference_update(self, __s: Iterable[_T]) -> None: ... + def union(self, *s: Iterable[_S]) -> set[_T | _S]: ... def update(self, *s: Iterable[_T]) -> None: ... def __len__(self) -> int: ... - def __contains__(self, o: object) -> bool: ... + def __contains__(self, __o: object) -> bool: ... def __iter__(self) -> Iterator[_T]: ... def __str__(self) -> str: ... - def __and__(self, s: AbstractSet[object]) -> Set[_T]: ... - def __iand__(self, s: AbstractSet[object]) -> Set[_T]: ... - def __or__(self, s: AbstractSet[_S]) -> Set[_T | _S]: ... - def __ior__(self, s: AbstractSet[_S]) -> Set[_T | _S]: ... - def __sub__(self, s: AbstractSet[_T | None]) -> Set[_T]: ... - def __isub__(self, s: AbstractSet[_T | None]) -> Set[_T]: ... - def __xor__(self, s: AbstractSet[_S]) -> Set[_T | _S]: ... - def __ixor__(self, s: AbstractSet[_S]) -> Set[_T | _S]: ... - def __le__(self, s: AbstractSet[object]) -> bool: ... - def __lt__(self, s: AbstractSet[object]) -> bool: ... - def __ge__(self, s: AbstractSet[object]) -> bool: ... - def __gt__(self, s: AbstractSet[object]) -> bool: ... - __hash__: None # type: ignore + def __and__(self, __s: AbstractSet[object]) -> set[_T]: ... + def __iand__(self, __s: AbstractSet[object]) -> set[_T]: ... + def __or__(self, __s: AbstractSet[_S]) -> set[_T | _S]: ... + def __ior__(self, __s: AbstractSet[_S]) -> set[_T | _S]: ... + def __sub__(self, __s: AbstractSet[_T | None]) -> set[_T]: ... + def __isub__(self, __s: AbstractSet[_T | None]) -> set[_T]: ... + def __xor__(self, __s: AbstractSet[_S]) -> set[_T | _S]: ... + def __ixor__(self, __s: AbstractSet[_S]) -> set[_T | _S]: ... + def __le__(self, __s: AbstractSet[object]) -> bool: ... + def __lt__(self, __s: AbstractSet[object]) -> bool: ... + def __ge__(self, __s: AbstractSet[object]) -> bool: ... + def __gt__(self, __s: AbstractSet[object]) -> bool: ... + __hash__: None # type: ignore[assignment] if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any) -> GenericAlias: ... + def __class_getitem__(cls, __item: Any) -> GenericAlias: ... class frozenset(AbstractSet[_T_co], Generic[_T_co]): - def __init__(self, iterable: Iterable[_T_co] = ...) -> None: ... - def copy(self) -> FrozenSet[_T_co]: ... - def difference(self, *s: Iterable[object]) -> FrozenSet[_T_co]: ... - def intersection(self, *s: Iterable[object]) -> FrozenSet[_T_co]: ... - def isdisjoint(self, s: Iterable[_T_co]) -> bool: ... - def issubset(self, s: Iterable[object]) -> bool: ... - def issuperset(self, s: Iterable[object]) -> bool: ... - def symmetric_difference(self, s: Iterable[_T_co]) -> FrozenSet[_T_co]: ... - def union(self, *s: Iterable[_T_co]) -> FrozenSet[_T_co]: ... + def __init__(self, __iterable: Iterable[_T_co] = ...) -> None: ... + def copy(self) -> frozenset[_T_co]: ... + def difference(self, *s: Iterable[object]) -> frozenset[_T_co]: ... + def intersection(self, *s: Iterable[object]) -> frozenset[_T_co]: ... + def isdisjoint(self, __s: Iterable[_T_co]) -> bool: ... + def issubset(self, __s: Iterable[object]) -> bool: ... + def issuperset(self, __s: Iterable[object]) -> bool: ... + def symmetric_difference(self, __s: Iterable[_T_co]) -> frozenset[_T_co]: ... + def union(self, *s: Iterable[_S]) -> frozenset[_T_co | _S]: ... def __len__(self) -> int: ... - def __contains__(self, o: object) -> bool: ... + def __contains__(self, __o: object) -> bool: ... def __iter__(self) -> Iterator[_T_co]: ... def __str__(self) -> str: ... - def __and__(self, s: AbstractSet[_T_co]) -> FrozenSet[_T_co]: ... - def __or__(self, s: AbstractSet[_S]) -> FrozenSet[_T_co | _S]: ... - def __sub__(self, s: AbstractSet[_T_co]) -> FrozenSet[_T_co]: ... - def __xor__(self, s: AbstractSet[_S]) -> FrozenSet[_T_co | _S]: ... - def __le__(self, s: AbstractSet[object]) -> bool: ... - def __lt__(self, s: AbstractSet[object]) -> bool: ... - def __ge__(self, s: AbstractSet[object]) -> bool: ... - def __gt__(self, s: AbstractSet[object]) -> bool: ... + def __and__(self, __s: AbstractSet[_T_co]) -> frozenset[_T_co]: ... + def __or__(self, __s: AbstractSet[_S]) -> frozenset[_T_co | _S]: ... + def __sub__(self, __s: AbstractSet[_T_co]) -> frozenset[_T_co]: ... + def __xor__(self, __s: AbstractSet[_S]) -> frozenset[_T_co | _S]: ... + def __le__(self, __s: AbstractSet[object]) -> bool: ... + def __lt__(self, __s: AbstractSet[object]) -> bool: ... + def __ge__(self, __s: AbstractSet[object]) -> bool: ... + def __gt__(self, __s: AbstractSet[object]) -> bool: ... if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any) -> GenericAlias: ... + def __class_getitem__(cls, __item: Any) -> GenericAlias: ... class enumerate(Iterator[Tuple[int, _T]], Generic[_T]): def __init__(self, iterable: Iterable[_T], start: int = ...) -> None: ... - def __iter__(self) -> Iterator[Tuple[int, _T]]: ... - def __next__(self) -> Tuple[int, _T]: ... + def __iter__(self) -> Iterator[tuple[int, _T]]: ... + def __next__(self) -> tuple[int, _T]: ... if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any) -> GenericAlias: ... + def __class_getitem__(cls, __item: Any) -> GenericAlias: ... +@final class range(Sequence[int]): start: int stop: int step: int @overload - def __init__(self, stop: SupportsIndex) -> None: ... + def __init__(self, __stop: SupportsIndex) -> None: ... @overload - def __init__(self, start: SupportsIndex, stop: SupportsIndex, step: SupportsIndex = ...) -> None: ... - def count(self, value: int) -> int: ... - def index(self, value: int) -> int: ... # type: ignore + def __init__(self, __start: SupportsIndex, __stop: SupportsIndex, __step: SupportsIndex = ...) -> None: ... + def count(self, __value: int) -> int: ... + def index(self, __value: int) -> int: ... # type: ignore[override] def __len__(self) -> int: ... - def __contains__(self, o: object) -> bool: ... + def __contains__(self, __o: object) -> bool: ... def __iter__(self) -> Iterator[int]: ... @overload - def __getitem__(self, i: SupportsIndex) -> int: ... + def __getitem__(self, __i: SupportsIndex) -> int: ... @overload - def __getitem__(self, s: slice) -> range: ... + def __getitem__(self, __s: slice) -> range: ... def __repr__(self) -> str: ... def __reversed__(self) -> Iterator[int]: ... @@ -933,17 +958,18 @@ class property(object): fdel: Callable[[Any], None] | None = ..., doc: str | None = ..., ) -> None: ... - def getter(self, fget: Callable[[Any], Any]) -> property: ... - def setter(self, fset: Callable[[Any, Any], None]) -> property: ... - def deleter(self, fdel: Callable[[Any], None]) -> property: ... - def __get__(self, obj: Any, type: type | None = ...) -> Any: ... - def __set__(self, obj: Any, value: Any) -> None: ... - def __delete__(self, obj: Any) -> None: ... - -class _NotImplementedType(Any): # type: ignore + def getter(self, __fget: Callable[[Any], Any]) -> property: ... + def setter(self, __fset: Callable[[Any, Any], None]) -> property: ... + def deleter(self, __fdel: Callable[[Any], None]) -> property: ... + def __get__(self, __obj: Any, __type: type | None = ...) -> Any: ... + def __set__(self, __obj: Any, __value: Any) -> None: ... + def __delete__(self, __obj: Any) -> None: ... + +@final +class _NotImplementedType(Any): # type: ignore[misc] # A little weird, but typing the __call__ as NotImplemented makes the error message # for NotImplemented() much better - __call__: NotImplemented # type: ignore + __call__: NotImplemented # type: ignore[valid-type] NotImplemented: _NotImplementedType @@ -956,7 +982,7 @@ def bin(__number: int | SupportsIndex) -> str: ... if sys.version_info >= (3, 7): def breakpoint(*args: Any, **kws: Any) -> None: ... -def callable(__obj: object) -> bool: ... +def callable(__obj: object) -> TypeGuard[Callable[..., object]]: ... def chr(__i: int) -> str: ... # We define this here instead of using os.PathLike to avoid import cycle issues. @@ -973,9 +999,10 @@ if sys.version_info >= (3, 10): @overload async def anext(__i: SupportsAnext[_T], default: _VT) -> _T | _VT: ... +# TODO: `compile` has a more precise return type in reality; work on a way of expressing that? if sys.version_info >= (3, 8): def compile( - source: str | bytes | mod | AST, + source: str | bytes | AST, filename: str | bytes | _PathLike[Any], mode: str, flags: int = ..., @@ -987,7 +1014,7 @@ if sys.version_info >= (3, 8): else: def compile( - source: str | bytes | mod | AST, + source: str | bytes | AST, filename: str | bytes | _PathLike[Any], mode: str, flags: int = ..., @@ -997,18 +1024,23 @@ else: def copyright() -> None: ... def credits() -> None: ... -def delattr(__obj: Any, __name: str) -> None: ... +def delattr(__obj: object, __name: str) -> None: ... def dir(__o: object = ...) -> list[str]: ... @overload def divmod(__x: SupportsDivMod[_T_contra, _T_co], __y: _T_contra) -> _T_co: ... @overload def divmod(__x: _T_contra, __y: SupportsRDivMod[_T_contra, _T_co]) -> _T_co: ... + +# The `globals` argument to `eval` has to be `dict[str, Any]` rather than `dict[str, object]` due to invariance. +# (The `globals` argument has to be a "real dict", rather than any old mapping, unlike the `locals` argument.) def eval( - __source: str | bytes | CodeType, __globals: dict[str, Any] | None = ..., __locals: Mapping[str, Any] | None = ... + __source: str | bytes | CodeType, __globals: dict[str, Any] | None = ..., __locals: Mapping[str, object] | None = ... ) -> Any: ... + +# Comment above regarding `eval` applies to `exec` as well def exec( - __source: str | bytes | CodeType, __globals: dict[str, Any] | None = ..., __locals: Mapping[str, Any] | None = ... -) -> Any: ... + __source: str | bytes | CodeType, __globals: dict[str, Any] | None = ..., __locals: Mapping[str, object] | None = ... +) -> None: ... def exit(code: object = ...) -> NoReturn: ... class filter(Iterator[_T], Generic[_T]): @@ -1021,30 +1053,36 @@ class filter(Iterator[_T], Generic[_T]): def format(__value: object, __format_spec: str = ...) -> str: ... # TODO unicode @overload -def getattr(__o: object, name: str) -> Any: ... +def getattr(__o: object, __name: str) -> Any: ... -# While technically covered by the last overload, spelling out the types for None and bool -# help mypy out in some tricky situations involving type context (aka bidirectional inference) +# While technically covered by the last overload, spelling out the types for None, bool +# and basic containers help mypy out in some tricky situations involving type context +# (aka bidirectional inference) +@overload +def getattr(__o: object, __name: str, __default: None) -> Any | None: ... @overload -def getattr(__o: object, name: str, __default: None) -> Any | None: ... +def getattr(__o: object, __name: str, __default: bool) -> Any | bool: ... @overload -def getattr(__o: object, name: str, __default: bool) -> Any | bool: ... +def getattr(__o: object, name: str, __default: list[Any]) -> Any | list[Any]: ... @overload -def getattr(__o: object, name: str, __default: _T) -> Any | _T: ... +def getattr(__o: object, name: str, __default: dict[Any, Any]) -> Any | dict[Any, Any]: ... +@overload +def getattr(__o: object, __name: str, __default: _T) -> Any | _T: ... def globals() -> dict[str, Any]: ... def hasattr(__obj: object, __name: str) -> bool: ... def hash(__obj: object) -> int: ... def help(*args: Any, **kwds: Any) -> None: ... def hex(__number: int | SupportsIndex) -> str: ... def id(__obj: object) -> int: ... -def input(__prompt: Any = ...) -> str: ... +def input(__prompt: object = ...) -> str: ... @overload def iter(__iterable: Iterable[_T]) -> Iterator[_T]: ... @overload def iter(__function: Callable[[], _T | None], __sentinel: None) -> Iterator[_T]: ... @overload -def iter(__function: Callable[[], _T], __sentinel: Any) -> Iterator[_T]: ... +def iter(__function: Callable[[], _T], __sentinel: object) -> Iterator[_T]: ... +# We need recursive types to express the type of the second argument to `isinstance` properly, hence the use of `Any` if sys.version_info >= (3, 10): def isinstance( __obj: object, __class_or_tuple: type | types.UnionType | Tuple[type | types.UnionType | Tuple[Any, ...], ...] @@ -1106,36 +1144,36 @@ class map(Iterator[_S], Generic[_S]): @overload def max( - __arg1: SupportsLessThanT, __arg2: SupportsLessThanT, *_args: SupportsLessThanT, key: None = ... -) -> SupportsLessThanT: ... + __arg1: SupportsRichComparisonT, __arg2: SupportsRichComparisonT, *_args: SupportsRichComparisonT, key: None = ... +) -> SupportsRichComparisonT: ... @overload -def max(__arg1: _T, __arg2: _T, *_args: _T, key: Callable[[_T], SupportsLessThan]) -> _T: ... +def max(__arg1: _T, __arg2: _T, *_args: _T, key: Callable[[_T], SupportsRichComparison]) -> _T: ... @overload -def max(__iterable: Iterable[SupportsLessThanT], *, key: None = ...) -> SupportsLessThanT: ... +def max(__iterable: Iterable[SupportsRichComparisonT], *, key: None = ...) -> SupportsRichComparisonT: ... @overload -def max(__iterable: Iterable[_T], *, key: Callable[[_T], SupportsLessThan]) -> _T: ... +def max(__iterable: Iterable[_T], *, key: Callable[[_T], SupportsRichComparison]) -> _T: ... @overload -def max(__iterable: Iterable[SupportsLessThanT], *, key: None = ..., default: _T) -> SupportsLessThanT | _T: ... +def max(__iterable: Iterable[SupportsRichComparisonT], *, key: None = ..., default: _T) -> SupportsRichComparisonT | _T: ... @overload -def max(__iterable: Iterable[_T1], *, key: Callable[[_T1], SupportsLessThan], default: _T2) -> _T1 | _T2: ... +def max(__iterable: Iterable[_T1], *, key: Callable[[_T1], SupportsRichComparison], default: _T2) -> _T1 | _T2: ... @overload def min( - __arg1: SupportsLessThanT, __arg2: SupportsLessThanT, *_args: SupportsLessThanT, key: None = ... -) -> SupportsLessThanT: ... + __arg1: SupportsRichComparisonT, __arg2: SupportsRichComparisonT, *_args: SupportsRichComparisonT, key: None = ... +) -> SupportsRichComparisonT: ... @overload -def min(__arg1: _T, __arg2: _T, *_args: _T, key: Callable[[_T], SupportsLessThan]) -> _T: ... +def min(__arg1: _T, __arg2: _T, *_args: _T, key: Callable[[_T], SupportsRichComparison]) -> _T: ... @overload -def min(__iterable: Iterable[SupportsLessThanT], *, key: None = ...) -> SupportsLessThanT: ... +def min(__iterable: Iterable[SupportsRichComparisonT], *, key: None = ...) -> SupportsRichComparisonT: ... @overload -def min(__iterable: Iterable[_T], *, key: Callable[[_T], SupportsLessThan]) -> _T: ... +def min(__iterable: Iterable[_T], *, key: Callable[[_T], SupportsRichComparison]) -> _T: ... @overload -def min(__iterable: Iterable[SupportsLessThanT], *, key: None = ..., default: _T) -> SupportsLessThanT | _T: ... +def min(__iterable: Iterable[SupportsRichComparisonT], *, key: None = ..., default: _T) -> SupportsRichComparisonT | _T: ... @overload -def min(__iterable: Iterable[_T1], *, key: Callable[[_T1], SupportsLessThan], default: _T2) -> _T1 | _T2: ... +def min(__iterable: Iterable[_T1], *, key: Callable[[_T1], SupportsRichComparison], default: _T2) -> _T1 | _T2: ... @overload def next(__i: SupportsNext[_T]) -> _T: ... @overload -def next(__i: SupportsNext[_T], default: _VT) -> _T | _VT: ... +def next(__i: SupportsNext[_T], __default: _VT) -> _T | _VT: ... def oct(__number: int | SupportsIndex) -> str: ... _OpenFile = Union[StrOrBytesPath, int] @@ -1228,8 +1266,21 @@ def open( opener: _Opener | None = ..., ) -> IO[Any]: ... def ord(__c: str | bytes) -> int: ... + +class _SupportsWriteAndFlush(SupportsWrite[_T_contra], Protocol[_T_contra]): + def flush(self) -> None: ... + +@overload def print( - *values: object, sep: str | None = ..., end: str | None = ..., file: SupportsWrite[str] | None = ..., flush: bool = ... + *values: object, + sep: str | None = ..., + end: str | None = ..., + file: SupportsWrite[str] | None = ..., + flush: Literal[False] = ..., +) -> None: ... +@overload +def print( + *values: object, sep: str | None = ..., end: str | None = ..., file: _SupportsWriteAndFlush[str] | None = ..., flush: bool ) -> None: ... _E = TypeVar("_E", contravariant=True) @@ -1238,34 +1289,74 @@ _M = TypeVar("_M", contravariant=True) class _SupportsPow2(Protocol[_E, _T_co]): def __pow__(self, __other: _E) -> _T_co: ... +class _SupportsPow3NoneOnly(Protocol[_E, _T_co]): + def __pow__(self, __other: _E, __modulo: None = ...) -> _T_co: ... + class _SupportsPow3(Protocol[_E, _M, _T_co]): def __pow__(self, __other: _E, __modulo: _M) -> _T_co: ... +_SupportsSomeKindOfPow = Union[_SupportsPow2[Any, Any], _SupportsPow3NoneOnly[Any, Any], _SupportsPow3[Any, Any, Any]] + if sys.version_info >= (3, 8): @overload - def pow(base: int, exp: int, mod: None = ...) -> Any: ... # returns int or float depending on whether exp is non-negative + def pow(base: int, exp: int, mod: Literal[0]) -> NoReturn: ... @overload def pow(base: int, exp: int, mod: int) -> int: ... @overload - def pow(base: float, exp: float, mod: None = ...) -> float: ... + def pow(base: int, exp: _PositiveInteger, mod: None = ...) -> int: ... # type: ignore[misc] + @overload + def pow(base: int, exp: _NegativeInteger, mod: None = ...) -> float: ... # type: ignore[misc] + # int base & positive-int exp -> int; int base & negative-int exp -> float + # return type must be Any as `int | float` causes too many false-positive errors + @overload + def pow(base: int, exp: int, mod: None = ...) -> Any: ... + @overload + def pow(base: float, exp: int, mod: None = ...) -> float: ... + # float base & float exp could return float or complex + # return type must be Any (same as complex base, complex exp), + # as `float | complex` causes too many false-positive errors + @overload + def pow(base: float, exp: complex | _SupportsSomeKindOfPow, mod: None = ...) -> Any: ... + @overload + def pow(base: complex, exp: complex | _SupportsSomeKindOfPow, mod: None = ...) -> complex: ... + @overload + def pow(base: _SupportsPow2[_E, _T_co], exp: _E, mod: None = ...) -> _T_co: ... + @overload + def pow(base: _SupportsPow3NoneOnly[_E, _T_co], exp: _E, mod: None = ...) -> _T_co: ... @overload - def pow(base: _SupportsPow2[_E, _T_co], exp: _E) -> _T_co: ... + def pow(base: _SupportsPow3[_E, _M, _T_co], exp: _E, mod: _M = ...) -> _T_co: ... @overload - def pow(base: _SupportsPow3[_E, _M, _T_co], exp: _E, mod: _M) -> _T_co: ... + def pow(base: _SupportsSomeKindOfPow, exp: float, mod: None = ...) -> Any: ... + @overload + def pow(base: _SupportsSomeKindOfPow, exp: complex, mod: None = ...) -> complex: ... else: @overload - def pow( - __base: int, __exp: int, __mod: None = ... - ) -> Any: ... # returns int or float depending on whether exp is non-negative + def pow(__base: int, __exp: int, __mod: Literal[0]) -> NoReturn: ... @overload def pow(__base: int, __exp: int, __mod: int) -> int: ... @overload - def pow(__base: float, __exp: float, __mod: None = ...) -> float: ... + def pow(__base: int, __exp: _PositiveInteger, __mod: None = ...) -> int: ... # type: ignore[misc] + @overload + def pow(__base: int, __exp: _NegativeInteger, __mod: None = ...) -> float: ... # type: ignore[misc] + @overload + def pow(__base: int, __exp: int, __mod: None = ...) -> Any: ... + @overload + def pow(__base: float, __exp: int, __mod: None = ...) -> float: ... + @overload + def pow(__base: float, __exp: complex | _SupportsSomeKindOfPow, __mod: None = ...) -> Any: ... + @overload + def pow(__base: complex, __exp: complex | _SupportsSomeKindOfPow, __mod: None = ...) -> complex: ... + @overload + def pow(__base: _SupportsPow2[_E, _T_co], __exp: _E, __mod: None = ...) -> _T_co: ... + @overload + def pow(__base: _SupportsPow3NoneOnly[_E, _T_co], __exp: _E, __mod: None = ...) -> _T_co: ... @overload - def pow(__base: _SupportsPow2[_E, _T_co], __exp: _E) -> _T_co: ... + def pow(__base: _SupportsPow3[_E, _M, _T_co], __exp: _E, __mod: _M = ...) -> _T_co: ... @overload - def pow(__base: _SupportsPow3[_E, _M, _T_co], __exp: _E, __mod: _M) -> _T_co: ... + def pow(__base: _SupportsSomeKindOfPow, __exp: float, __mod: None = ...) -> Any: ... + @overload + def pow(__base: _SupportsSomeKindOfPow, __exp: complex, __mod: None = ...) -> complex: ... def quit(code: object = ...) -> NoReturn: ... @@ -1284,11 +1375,14 @@ def round(number: SupportsRound[Any]) -> int: ... def round(number: SupportsRound[Any], ndigits: None) -> int: ... @overload def round(number: SupportsRound[_T], ndigits: SupportsIndex) -> _T: ... + +# See https://github.com/python/typeshed/pull/6292#discussion_r748875189 +# for why arg 3 of `setattr` should be annotated with `Any` and not `object` def setattr(__obj: object, __name: str, __value: Any) -> None: ... @overload -def sorted(__iterable: Iterable[SupportsLessThanT], *, key: None = ..., reverse: bool = ...) -> list[SupportsLessThanT]: ... +def sorted(__iterable: Iterable[SupportsRichComparisonT], *, key: None = ..., reverse: bool = ...) -> list[SupportsRichComparisonT]: ... @overload -def sorted(__iterable: Iterable[_T], *, key: Callable[[_T], SupportsLessThan], reverse: bool = ...) -> list[_T]: ... +def sorted(__iterable: Iterable[_T], *, key: Callable[[_T], SupportsRichComparison], reverse: bool = ...) -> list[_T]: ... if sys.version_info >= (3, 8): @overload @@ -1302,52 +1396,100 @@ else: @overload def sum(__iterable: Iterable[_T], __start: _S) -> _T | _S: ... +# The argument to `vars()` has to have a `__dict__` attribute, so can't be annotated with `object` +# (A "SupportsDunderDict" protocol doesn't work) def vars(__object: Any = ...) -> dict[str, Any]: ... class zip(Iterator[_T_co], Generic[_T_co]): - @overload - def __new__(cls, __iter1: Iterable[_T1]) -> zip[Tuple[_T1]]: ... - @overload - def __new__(cls, __iter1: Iterable[_T1], __iter2: Iterable[_T2]) -> zip[Tuple[_T1, _T2]]: ... - @overload - def __new__(cls, __iter1: Iterable[_T1], __iter2: Iterable[_T2], __iter3: Iterable[_T3]) -> zip[Tuple[_T1, _T2, _T3]]: ... - @overload - def __new__( - cls, __iter1: Iterable[_T1], __iter2: Iterable[_T2], __iter3: Iterable[_T3], __iter4: Iterable[_T4] - ) -> zip[Tuple[_T1, _T2, _T3, _T4]]: ... - @overload - def __new__( - cls, - __iter1: Iterable[_T1], - __iter2: Iterable[_T2], - __iter3: Iterable[_T3], - __iter4: Iterable[_T4], - __iter5: Iterable[_T5], - ) -> zip[Tuple[_T1, _T2, _T3, _T4, _T5]]: ... - @overload - def __new__( - cls, - __iter1: Iterable[Any], - __iter2: Iterable[Any], - __iter3: Iterable[Any], - __iter4: Iterable[Any], - __iter5: Iterable[Any], - __iter6: Iterable[Any], - *iterables: Iterable[Any], - ) -> zip[Tuple[Any, ...]]: ... + if sys.version_info >= (3, 10): + @overload + def __new__(cls, __iter1: Iterable[_T1], *, strict: bool = ...) -> zip[tuple[_T1]]: ... + @overload + def __new__(cls, __iter1: Iterable[_T1], __iter2: Iterable[_T2], *, strict: bool = ...) -> zip[tuple[_T1, _T2]]: ... + @overload + def __new__( + cls, __iter1: Iterable[_T1], __iter2: Iterable[_T2], __iter3: Iterable[_T3], *, strict: bool = ... + ) -> zip[tuple[_T1, _T2, _T3]]: ... + @overload + def __new__( + cls, + __iter1: Iterable[_T1], + __iter2: Iterable[_T2], + __iter3: Iterable[_T3], + __iter4: Iterable[_T4], + *, + strict: bool = ..., + ) -> zip[tuple[_T1, _T2, _T3, _T4]]: ... + @overload + def __new__( + cls, + __iter1: Iterable[_T1], + __iter2: Iterable[_T2], + __iter3: Iterable[_T3], + __iter4: Iterable[_T4], + __iter5: Iterable[_T5], + *, + strict: bool = ..., + ) -> zip[tuple[_T1, _T2, _T3, _T4, _T5]]: ... + @overload + def __new__( + cls, + __iter1: Iterable[Any], + __iter2: Iterable[Any], + __iter3: Iterable[Any], + __iter4: Iterable[Any], + __iter5: Iterable[Any], + __iter6: Iterable[Any], + *iterables: Iterable[Any], + strict: bool = ..., + ) -> zip[Tuple[Any, ...]]: ... + else: + @overload + def __new__(cls, __iter1: Iterable[_T1]) -> zip[tuple[_T1]]: ... + @overload + def __new__(cls, __iter1: Iterable[_T1], __iter2: Iterable[_T2]) -> zip[tuple[_T1, _T2]]: ... + @overload + def __new__(cls, __iter1: Iterable[_T1], __iter2: Iterable[_T2], __iter3: Iterable[_T3]) -> zip[tuple[_T1, _T2, _T3]]: ... + @overload + def __new__( + cls, __iter1: Iterable[_T1], __iter2: Iterable[_T2], __iter3: Iterable[_T3], __iter4: Iterable[_T4] + ) -> zip[tuple[_T1, _T2, _T3, _T4]]: ... + @overload + def __new__( + cls, + __iter1: Iterable[_T1], + __iter2: Iterable[_T2], + __iter3: Iterable[_T3], + __iter4: Iterable[_T4], + __iter5: Iterable[_T5], + ) -> zip[tuple[_T1, _T2, _T3, _T4, _T5]]: ... + @overload + def __new__( + cls, + __iter1: Iterable[Any], + __iter2: Iterable[Any], + __iter3: Iterable[Any], + __iter4: Iterable[Any], + __iter5: Iterable[Any], + __iter6: Iterable[Any], + *iterables: Iterable[Any], + ) -> zip[Tuple[Any, ...]]: ... def __iter__(self) -> Iterator[_T_co]: ... def __next__(self) -> _T_co: ... +# Signature of `builtins.__import__` should be kept identical to `importlib.__import__` +# Return type of `__import__` should be kept the same as return type of `importlib.import_module` def __import__( name: str, - globals: Mapping[str, Any] | None = ..., - locals: Mapping[str, Any] | None = ..., + globals: Mapping[str, object] | None = ..., + locals: Mapping[str, object] | None = ..., fromlist: Sequence[str] = ..., level: int = ..., -) -> Any: ... +) -> types.ModuleType: ... # Actually the type of Ellipsis is , but since it's # not exposed anywhere under that name, we make it private here. +@final class ellipsis: ... Ellipsis: ellipsis @@ -1361,7 +1503,7 @@ class BaseException(object): def __init__(self, *args: object) -> None: ... def __str__(self) -> str: ... def __repr__(self) -> str: ... - def with_traceback(self: _TBE, tb: TracebackType | None) -> _TBE: ... + def with_traceback(self: _TBE, __tb: TracebackType | None) -> _TBE: ... class GeneratorExit(BaseException): ... class KeyboardInterrupt(BaseException): ... diff --git a/mypy/typeshed/stdlib/bz2.pyi b/mypy/typeshed/stdlib/bz2.pyi index e7b57ec54db0..c49832759fa8 100644 --- a/mypy/typeshed/stdlib/bz2.pyi +++ b/mypy/typeshed/stdlib/bz2.pyi @@ -3,7 +3,7 @@ import sys from _compression import BaseStream from _typeshed import ReadableBuffer, Self, StrOrBytesPath, WriteableBuffer from typing import IO, Any, Iterable, Protocol, TextIO, TypeVar, overload -from typing_extensions import Literal, SupportsIndex +from typing_extensions import Literal, SupportsIndex, final # The following attributes and methods are optional: # def fileno(self) -> int: ... @@ -118,11 +118,13 @@ class BZ2File(BaseStream, IO[bytes]): def write(self, data: ReadableBuffer) -> int: ... def writelines(self, seq: Iterable[ReadableBuffer]) -> None: ... +@final class BZ2Compressor(object): def __init__(self, compresslevel: int = ...) -> None: ... def compress(self, __data: bytes) -> bytes: ... def flush(self) -> bytes: ... +@final class BZ2Decompressor(object): def decompress(self, data: bytes, max_length: int = ...) -> bytes: ... @property diff --git a/mypy/typeshed/stdlib/calendar.pyi b/mypy/typeshed/stdlib/calendar.pyi index 9d701a788a80..26073fb7281b 100644 --- a/mypy/typeshed/stdlib/calendar.pyi +++ b/mypy/typeshed/stdlib/calendar.pyi @@ -16,7 +16,7 @@ class IllegalWeekdayError(ValueError): def isleap(year: int) -> bool: ... def leapdays(y1: int, y2: int) -> int: ... def weekday(year: int, month: int, day: int) -> int: ... -def monthrange(year: int, month: int) -> Tuple[int, int]: ... +def monthrange(year: int, month: int) -> tuple[int, int]: ... class Calendar: firstweekday: int @@ -25,17 +25,17 @@ class Calendar: def setfirstweekday(self, firstweekday: int) -> None: ... def iterweekdays(self) -> Iterable[int]: ... def itermonthdates(self, year: int, month: int) -> Iterable[datetime.date]: ... - def itermonthdays2(self, year: int, month: int) -> Iterable[Tuple[int, int]]: ... + def itermonthdays2(self, year: int, month: int) -> Iterable[tuple[int, int]]: ... def itermonthdays(self, year: int, month: int) -> Iterable[int]: ... def monthdatescalendar(self, year: int, month: int) -> list[list[datetime.date]]: ... - def monthdays2calendar(self, year: int, month: int) -> list[list[Tuple[int, int]]]: ... + def monthdays2calendar(self, year: int, month: int) -> list[list[tuple[int, int]]]: ... def monthdayscalendar(self, year: int, month: int) -> list[list[int]]: ... def yeardatescalendar(self, year: int, width: int = ...) -> list[list[int]]: ... - def yeardays2calendar(self, year: int, width: int = ...) -> list[list[Tuple[int, int]]]: ... + def yeardays2calendar(self, year: int, width: int = ...) -> list[list[tuple[int, int]]]: ... def yeardayscalendar(self, year: int, width: int = ...) -> list[list[int]]: ... if sys.version_info >= (3, 7): - def itermonthdays3(self, year: int, month: int) -> Iterable[Tuple[int, int, int]]: ... - def itermonthdays4(self, year: int, month: int) -> Iterable[Tuple[int, int, int, int]]: ... + def itermonthdays3(self, year: int, month: int) -> Iterable[tuple[int, int, int]]: ... + def itermonthdays4(self, year: int, month: int) -> Iterable[tuple[int, int, int, int]]: ... class TextCalendar(Calendar): def prweek(self, theweek: int, width: int) -> None: ... diff --git a/mypy/typeshed/stdlib/cgitb.pyi b/mypy/typeshed/stdlib/cgitb.pyi index 90226dc134e8..7576740fc1c0 100644 --- a/mypy/typeshed/stdlib/cgitb.pyi +++ b/mypy/typeshed/stdlib/cgitb.pyi @@ -8,10 +8,10 @@ def reset() -> str: ... # undocumented def small(text: str) -> str: ... # undocumented def strong(text: str) -> str: ... # undocumented def grey(text: str) -> str: ... # undocumented -def lookup(name: str, frame: FrameType, locals: dict[str, Any]) -> Tuple[str | None, Any]: ... # undocumented +def lookup(name: str, frame: FrameType, locals: dict[str, Any]) -> tuple[str | None, Any]: ... # undocumented def scanvars( reader: Callable[[], bytes], frame: FrameType, locals: dict[str, Any] -) -> list[Tuple[str, str | None, Any]]: ... # undocumented +) -> list[tuple[str, str | None, Any]]: ... # undocumented def html(einfo: _ExcInfo, context: int = ...) -> str: ... def text(einfo: _ExcInfo, context: int = ...) -> str: ... diff --git a/mypy/typeshed/stdlib/cmath.pyi b/mypy/typeshed/stdlib/cmath.pyi index 8d67e6c47bb4..04c2b632d411 100644 --- a/mypy/typeshed/stdlib/cmath.pyi +++ b/mypy/typeshed/stdlib/cmath.pyi @@ -1,4 +1,8 @@ -from typing import SupportsComplex, SupportsFloat, Tuple, Union +import sys +from typing import SupportsComplex, SupportsFloat, Union + +if sys.version_info >= (3, 8): + from typing import SupportsIndex e: float pi: float @@ -8,7 +12,10 @@ nan: float nanj: complex tau: float -_C = Union[SupportsFloat, SupportsComplex, complex] +if sys.version_info >= (3, 8): + _C = Union[SupportsFloat, SupportsComplex, SupportsIndex, complex] +else: + _C = Union[SupportsFloat, SupportsComplex, complex] def acos(__z: _C) -> complex: ... def acosh(__z: _C) -> complex: ... @@ -25,7 +32,7 @@ def isnan(__z: _C) -> bool: ... def log(__x: _C, __y_obj: _C = ...) -> complex: ... def log10(__z: _C) -> complex: ... def phase(__z: _C) -> float: ... -def polar(__z: _C) -> Tuple[float, float]: ... +def polar(__z: _C) -> tuple[float, float]: ... def rect(__r: float, __phi: float) -> complex: ... def sin(__z: _C) -> complex: ... def sinh(__z: _C) -> complex: ... diff --git a/mypy/typeshed/stdlib/cmd.pyi b/mypy/typeshed/stdlib/cmd.pyi index 9f2593d3bfdf..f6d818591a4e 100644 --- a/mypy/typeshed/stdlib/cmd.pyi +++ b/mypy/typeshed/stdlib/cmd.pyi @@ -1,4 +1,4 @@ -from typing import IO, Any, Callable, Tuple +from typing import IO, Any, Callable class Cmd: prompt: str @@ -23,7 +23,7 @@ class Cmd: def postcmd(self, stop: bool, line: str) -> bool: ... def preloop(self) -> None: ... def postloop(self) -> None: ... - def parseline(self, line: str) -> Tuple[str | None, str | None, str]: ... + def parseline(self, line: str) -> tuple[str | None, str | None, str]: ... def onecmd(self, line: str) -> bool: ... def emptyline(self) -> bool: ... def default(self, line: str) -> bool: ... diff --git a/mypy/typeshed/stdlib/codecs.pyi b/mypy/typeshed/stdlib/codecs.pyi index 9f27cfebf099..ebd6911c3e63 100644 --- a/mypy/typeshed/stdlib/codecs.pyi +++ b/mypy/typeshed/stdlib/codecs.pyi @@ -12,10 +12,10 @@ from typing_extensions import Literal # They are much more common in Python 2 than in Python 3. class _Encoder(Protocol): - def __call__(self, input: str, errors: str = ...) -> Tuple[bytes, int]: ... # signature of Codec().encode + def __call__(self, input: str, errors: str = ...) -> tuple[bytes, int]: ... # signature of Codec().encode class _Decoder(Protocol): - def __call__(self, input: bytes, errors: str = ...) -> Tuple[str, int]: ... # signature of Codec().decode + def __call__(self, input: bytes, errors: str = ...) -> tuple[str, int]: ... # signature of Codec().decode class _StreamReader(Protocol): def __call__(self, stream: IO[bytes], errors: str = ...) -> StreamReader: ... @@ -63,8 +63,8 @@ def decode(obj: str, encoding: Literal["rot13", "rot_13"] = ..., errors: str = . @overload def decode(obj: bytes, encoding: str = ..., errors: str = ...) -> str: ... def lookup(__encoding: str) -> CodecInfo: ... -def utf_16_be_decode(__data: bytes, __errors: str | None = ..., __final: bool = ...) -> Tuple[str, int]: ... # undocumented -def utf_16_be_encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... # undocumented +def utf_16_be_decode(__data: bytes, __errors: str | None = ..., __final: bool = ...) -> tuple[str, int]: ... # undocumented +def utf_16_be_encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... # undocumented class CodecInfo(Tuple[_Encoder, _Decoder, _StreamReader, _StreamWriter]): @property @@ -124,19 +124,19 @@ BOM_UTF32_LE: bytes # It is expected that different actions be taken depending on which of the # three subclasses of `UnicodeError` is actually ...ed. However, the Union # is still needed for at least one of the cases. -def register_error(__errors: str, __handler: Callable[[UnicodeError], Tuple[str | bytes, int]]) -> None: ... -def lookup_error(__name: str) -> Callable[[UnicodeError], Tuple[str | bytes, int]]: ... -def strict_errors(exception: UnicodeError) -> Tuple[str | bytes, int]: ... -def replace_errors(exception: UnicodeError) -> Tuple[str | bytes, int]: ... -def ignore_errors(exception: UnicodeError) -> Tuple[str | bytes, int]: ... -def xmlcharrefreplace_errors(exception: UnicodeError) -> Tuple[str | bytes, int]: ... -def backslashreplace_errors(exception: UnicodeError) -> Tuple[str | bytes, int]: ... +def register_error(__errors: str, __handler: Callable[[UnicodeError], tuple[str | bytes, int]]) -> None: ... +def lookup_error(__name: str) -> Callable[[UnicodeError], tuple[str | bytes, int]]: ... +def strict_errors(exception: UnicodeError) -> tuple[str | bytes, int]: ... +def replace_errors(exception: UnicodeError) -> tuple[str | bytes, int]: ... +def ignore_errors(exception: UnicodeError) -> tuple[str | bytes, int]: ... +def xmlcharrefreplace_errors(exception: UnicodeError) -> tuple[str | bytes, int]: ... +def backslashreplace_errors(exception: UnicodeError) -> tuple[str | bytes, int]: ... class Codec: # These are sort of @abstractmethod but sort of not. # The StreamReader and StreamWriter subclasses only implement one. - def encode(self, input: str, errors: str = ...) -> Tuple[bytes, int]: ... - def decode(self, input: bytes, errors: str = ...) -> Tuple[str, int]: ... + def encode(self, input: str, errors: str = ...) -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = ...) -> tuple[str, int]: ... class IncrementalEncoder: errors: str @@ -154,8 +154,8 @@ class IncrementalDecoder: @abstractmethod def decode(self, input: bytes, final: bool = ...) -> str: ... def reset(self) -> None: ... - def getstate(self) -> Tuple[bytes, int]: ... - def setstate(self, state: Tuple[bytes, int]) -> None: ... + def getstate(self) -> tuple[bytes, int]: ... + def setstate(self, state: tuple[bytes, int]) -> None: ... # These are not documented but used in encodings/*.py implementations. class BufferedIncrementalEncoder(IncrementalEncoder): @@ -169,7 +169,7 @@ class BufferedIncrementalDecoder(IncrementalDecoder): buffer: bytes def __init__(self, errors: str = ...) -> None: ... @abstractmethod - def _buffer_decode(self, input: bytes, errors: str, final: bool) -> Tuple[str, int]: ... + def _buffer_decode(self, input: bytes, errors: str, final: bool) -> tuple[str, int]: ... def decode(self, input: bytes, final: bool = ...) -> str: ... # TODO: it is not possible to specify the requirement that all other diff --git a/mypy/typeshed/stdlib/collections/__init__.pyi b/mypy/typeshed/stdlib/collections/__init__.pyi index 253e06077496..66a76941beee 100644 --- a/mypy/typeshed/stdlib/collections/__init__.pyi +++ b/mypy/typeshed/stdlib/collections/__init__.pyi @@ -1,21 +1,11 @@ import sys +from _collections_abc import dict_items, dict_keys, dict_values from _typeshed import Self from typing import Any, Dict, Generic, NoReturn, Tuple, Type, TypeVar, overload +from typing_extensions import final if sys.version_info >= (3, 10): - from typing import ( - Callable, - ItemsView, - Iterable, - Iterator, - KeysView, - Mapping, - MutableMapping, - MutableSequence, - Reversible, - Sequence, - ValuesView, - ) + from typing import Callable, Iterable, Iterator, Mapping, MutableMapping, MutableSequence, Reversible, Sequence else: from _collections_abc import * @@ -23,6 +13,8 @@ _S = TypeVar("_S") _T = TypeVar("_T") _KT = TypeVar("_KT") _VT = TypeVar("_VT") +_KT_co = TypeVar("_KT_co", covariant=True) +_VT_co = TypeVar("_VT_co", covariant=True) # namedtuple is special-cased in the type checker; the initializer is ignored. if sys.version_info >= (3, 7): @@ -49,9 +41,9 @@ class UserDict(MutableMapping[_KT, _VT]): def __delitem__(self, key: _KT) -> None: ... def __iter__(self) -> Iterator[_KT]: ... def __contains__(self, key: object) -> bool: ... - def copy(self: _S) -> _S: ... + def copy(self: Self) -> Self: ... @classmethod - def fromkeys(cls: Type[_S], iterable: Iterable[_KT], value: _VT | None = ...) -> _S: ... + def fromkeys(cls: Type[Self], iterable: Iterable[_KT], value: _VT | None = ...) -> Self: ... class UserList(MutableSequence[_T]): data: list[_T] @@ -95,7 +87,7 @@ class UserString(Sequence[str]): def __int__(self) -> int: ... def __float__(self) -> float: ... def __complex__(self) -> complex: ... - def __getnewargs__(self) -> Tuple[str]: ... + def __getnewargs__(self) -> tuple[str]: ... def __lt__(self, string: str | UserString) -> bool: ... def __le__(self, string: str | UserString) -> bool: ... def __gt__(self, string: str | UserString) -> bool: ... @@ -144,7 +136,7 @@ class UserString(Sequence[str]): @staticmethod @overload def maketrans(x: str, y: str, z: str = ...) -> dict[int, int | None]: ... - def partition(self, sep: str) -> Tuple[str, str, str]: ... + def partition(self, sep: str) -> tuple[str, str, str]: ... if sys.version_info >= (3, 9): def removeprefix(self: _UserStringT, __prefix: str | UserString) -> _UserStringT: ... def removesuffix(self: _UserStringT, __suffix: str | UserString) -> _UserStringT: ... @@ -152,7 +144,7 @@ class UserString(Sequence[str]): def rfind(self, sub: str | UserString, start: int = ..., end: int = ...) -> int: ... def rindex(self, sub: str | UserString, start: int = ..., end: int = ...) -> int: ... def rjust(self: _UserStringT, width: int, *args: Any) -> _UserStringT: ... - def rpartition(self, sep: str) -> Tuple[str, str, str]: ... + def rpartition(self, sep: str) -> tuple[str, str, str]: ... def rstrip(self: _UserStringT, chars: str | None = ...) -> _UserStringT: ... def split(self, sep: str | None = ..., maxsplit: int = ...) -> list[str]: ... def rsplit(self, sep: str | None = ..., maxsplit: int = ...) -> list[str]: ... @@ -169,43 +161,45 @@ class deque(MutableSequence[_T], Generic[_T]): @property def maxlen(self) -> int | None: ... def __init__(self, iterable: Iterable[_T] = ..., maxlen: int | None = ...) -> None: ... - def append(self, x: _T) -> None: ... - def appendleft(self, x: _T) -> None: ... + def append(self, __x: _T) -> None: ... + def appendleft(self, __x: _T) -> None: ... def clear(self) -> None: ... - def copy(self) -> deque[_T]: ... - def count(self, x: _T) -> int: ... - def extend(self, iterable: Iterable[_T]) -> None: ... - def extendleft(self, iterable: Iterable[_T]) -> None: ... - def insert(self, i: int, x: _T) -> None: ... - def index(self, x: _T, start: int = ..., stop: int = ...) -> int: ... + def copy(self: _S) -> _S: ... + def count(self, __x: _T) -> int: ... + def extend(self, __iterable: Iterable[_T]) -> None: ... + def extendleft(self, __iterable: Iterable[_T]) -> None: ... + def insert(self, __i: int, __x: _T) -> None: ... + def index(self, __x: _T, __start: int = ..., __stop: int = ...) -> int: ... def pop(self) -> _T: ... # type: ignore def popleft(self) -> _T: ... - def remove(self, value: _T) -> None: ... + def remove(self, __value: _T) -> None: ... def reverse(self) -> None: ... - def rotate(self, n: int = ...) -> None: ... + def rotate(self, __n: int = ...) -> None: ... + def __copy__(self: _S) -> _S: ... def __len__(self) -> int: ... def __iter__(self) -> Iterator[_T]: ... def __str__(self) -> str: ... # These methods of deque don't really take slices, but we need to # define them as taking a slice to satisfy MutableSequence. @overload - def __getitem__(self, index: int) -> _T: ... + def __getitem__(self, __index: int) -> _T: ... @overload - def __getitem__(self, s: slice) -> MutableSequence[_T]: ... + def __getitem__(self, __s: slice) -> MutableSequence[_T]: ... @overload - def __setitem__(self, i: int, x: _T) -> None: ... + def __setitem__(self, __i: int, __x: _T) -> None: ... @overload - def __setitem__(self, s: slice, o: Iterable[_T]) -> None: ... + def __setitem__(self, __s: slice, __o: Iterable[_T]) -> None: ... @overload - def __delitem__(self, i: int) -> None: ... + def __delitem__(self, __i: int) -> None: ... @overload - def __delitem__(self, s: slice) -> None: ... - def __contains__(self, o: object) -> bool: ... + def __delitem__(self, __s: slice) -> None: ... + def __contains__(self, __o: object) -> bool: ... + def __reduce__(self: Self) -> tuple[Type[Self], tuple[()], None, Iterator[_T]]: ... def __reversed__(self) -> Iterator[_T]: ... - def __iadd__(self: _S, iterable: Iterable[_T]) -> _S: ... - def __add__(self, other: deque[_T]) -> deque[_T]: ... - def __mul__(self, other: int) -> deque[_T]: ... - def __imul__(self, other: int) -> None: ... + def __iadd__(self: _S, __iterable: Iterable[_T]) -> _S: ... + def __add__(self: _S, __other: _S) -> _S: ... + def __mul__(self: _S, __other: int) -> _S: ... + def __imul__(self: _S, __other: int) -> _S: ... class Counter(Dict[_T, int], Generic[_T]): @overload @@ -214,9 +208,9 @@ class Counter(Dict[_T, int], Generic[_T]): def __init__(self, __mapping: Mapping[_T, int]) -> None: ... @overload def __init__(self, __iterable: Iterable[_T]) -> None: ... - def copy(self: _S) -> _S: ... + def copy(self: Self) -> Self: ... def elements(self) -> Iterator[_T]: ... - def most_common(self, n: int | None = ...) -> list[Tuple[_T, int]]: ... + def most_common(self, n: int | None = ...) -> list[tuple[_T, int]]: ... @classmethod def fromkeys(cls, iterable: Any, v: int | None = ...) -> NoReturn: ... # type: ignore @overload @@ -233,7 +227,7 @@ class Counter(Dict[_T, int], Generic[_T]): @overload def update(self, __m: Mapping[_T, int], **kwargs: int) -> None: ... @overload - def update(self, __m: Iterable[_T] | Iterable[Tuple[_T, int]], **kwargs: int) -> None: ... + def update(self, __m: Iterable[_T] | Iterable[tuple[_T, int]], **kwargs: int) -> None: ... @overload def update(self, __m: None = ..., **kwargs: int) -> None: ... def __add__(self, other: Counter[_T]) -> Counter[_T]: ... @@ -247,48 +241,53 @@ class Counter(Dict[_T, int], Generic[_T]): def __iand__(self, other: Counter[_T]) -> Counter[_T]: ... def __ior__(self, other: Counter[_T]) -> Counter[_T]: ... # type: ignore -class _OrderedDictKeysView(KeysView[_KT], Reversible[_KT]): - def __reversed__(self) -> Iterator[_KT]: ... +@final +class _OrderedDictKeysView(dict_keys[_KT_co, _VT_co], Reversible[_KT_co]): # type: ignore[misc] + def __reversed__(self) -> Iterator[_KT_co]: ... -class _OrderedDictItemsView(ItemsView[_KT, _VT], Reversible[Tuple[_KT, _VT]]): - def __reversed__(self) -> Iterator[Tuple[_KT, _VT]]: ... +@final +class _OrderedDictItemsView(dict_items[_KT_co, _VT_co], Reversible[Tuple[_KT_co, _VT_co]]): # type: ignore[misc] + def __reversed__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ... -class _OrderedDictValuesView(ValuesView[_VT], Reversible[_VT]): - def __reversed__(self) -> Iterator[_VT]: ... +@final +class _OrderedDictValuesView(dict_values[_KT_co, _VT_co], Reversible[_VT_co], Generic[_KT_co, _VT_co]): # type: ignore[misc] + def __reversed__(self) -> Iterator[_VT_co]: ... class OrderedDict(Dict[_KT, _VT], Reversible[_KT], Generic[_KT, _VT]): - def popitem(self, last: bool = ...) -> Tuple[_KT, _VT]: ... + def popitem(self, last: bool = ...) -> tuple[_KT, _VT]: ... def move_to_end(self, key: _KT, last: bool = ...) -> None: ... - def copy(self: _S) -> _S: ... + def copy(self: Self) -> Self: ... def __reversed__(self) -> Iterator[_KT]: ... - def keys(self) -> _OrderedDictKeysView[_KT]: ... + def keys(self) -> _OrderedDictKeysView[_KT, _VT]: ... def items(self) -> _OrderedDictItemsView[_KT, _VT]: ... - def values(self) -> _OrderedDictValuesView[_VT]: ... + def values(self) -> _OrderedDictValuesView[_KT, _VT]: ... class defaultdict(Dict[_KT, _VT], Generic[_KT, _VT]): default_factory: Callable[[], _VT] | None @overload def __init__(self, **kwargs: _VT) -> None: ... @overload - def __init__(self, default_factory: Callable[[], _VT] | None) -> None: ... + def __init__(self, __default_factory: Callable[[], _VT] | None) -> None: ... @overload - def __init__(self, default_factory: Callable[[], _VT] | None, **kwargs: _VT) -> None: ... + def __init__(self, __default_factory: Callable[[], _VT] | None, **kwargs: _VT) -> None: ... @overload - def __init__(self, default_factory: Callable[[], _VT] | None, map: Mapping[_KT, _VT]) -> None: ... + def __init__(self, __default_factory: Callable[[], _VT] | None, __map: Mapping[_KT, _VT]) -> None: ... @overload - def __init__(self, default_factory: Callable[[], _VT] | None, map: Mapping[_KT, _VT], **kwargs: _VT) -> None: ... + def __init__(self, __default_factory: Callable[[], _VT] | None, __map: Mapping[_KT, _VT], **kwargs: _VT) -> None: ... @overload - def __init__(self, default_factory: Callable[[], _VT] | None, iterable: Iterable[Tuple[_KT, _VT]]) -> None: ... + def __init__(self, __default_factory: Callable[[], _VT] | None, __iterable: Iterable[tuple[_KT, _VT]]) -> None: ... @overload - def __init__(self, default_factory: Callable[[], _VT] | None, iterable: Iterable[Tuple[_KT, _VT]], **kwargs: _VT) -> None: ... - def __missing__(self, key: _KT) -> _VT: ... - # TODO __reversed__ + def __init__( + self, __default_factory: Callable[[], _VT] | None, __iterable: Iterable[tuple[_KT, _VT]], **kwargs: _VT + ) -> None: ... + def __missing__(self, __key: _KT) -> _VT: ... + def __copy__(self: _S) -> _S: ... def copy(self: _S) -> _S: ... class ChainMap(MutableMapping[_KT, _VT], Generic[_KT, _VT]): - maps: list[Mapping[_KT, _VT]] - def __init__(self, *maps: Mapping[_KT, _VT]) -> None: ... - def new_child(self: Self, m: Mapping[_KT, _VT] | None = ...) -> Self: ... + maps: list[MutableMapping[_KT, _VT]] + def __init__(self, *maps: MutableMapping[_KT, _VT]) -> None: ... + def new_child(self: Self, m: MutableMapping[_KT, _VT] | None = ...) -> Self: ... @property def parents(self: Self) -> Self: ... def __setitem__(self, k: _KT, v: _VT) -> None: ... @@ -297,3 +296,8 @@ class ChainMap(MutableMapping[_KT, _VT], Generic[_KT, _VT]): def __iter__(self) -> Iterator[_KT]: ... def __len__(self) -> int: ... def __missing__(self, key: _KT) -> _VT: ... # undocumented + def setdefault(self, key: _KT, default: _VT = ...) -> _VT: ... + @overload + def pop(self, key: _KT) -> _VT: ... + @overload + def pop(self, key: _KT, default: _VT | _T = ...) -> _VT | _T: ... diff --git a/mypy/typeshed/stdlib/colorsys.pyi b/mypy/typeshed/stdlib/colorsys.pyi index 8db2e2c9ab3a..00c5f9d22cb1 100644 --- a/mypy/typeshed/stdlib/colorsys.pyi +++ b/mypy/typeshed/stdlib/colorsys.pyi @@ -1,11 +1,9 @@ -from typing import Tuple - -def rgb_to_yiq(r: float, g: float, b: float) -> Tuple[float, float, float]: ... -def yiq_to_rgb(y: float, i: float, q: float) -> Tuple[float, float, float]: ... -def rgb_to_hls(r: float, g: float, b: float) -> Tuple[float, float, float]: ... -def hls_to_rgb(h: float, l: float, s: float) -> Tuple[float, float, float]: ... -def rgb_to_hsv(r: float, g: float, b: float) -> Tuple[float, float, float]: ... -def hsv_to_rgb(h: float, s: float, v: float) -> Tuple[float, float, float]: ... +def rgb_to_yiq(r: float, g: float, b: float) -> tuple[float, float, float]: ... +def yiq_to_rgb(y: float, i: float, q: float) -> tuple[float, float, float]: ... +def rgb_to_hls(r: float, g: float, b: float) -> tuple[float, float, float]: ... +def hls_to_rgb(h: float, l: float, s: float) -> tuple[float, float, float]: ... +def rgb_to_hsv(r: float, g: float, b: float) -> tuple[float, float, float]: ... +def hsv_to_rgb(h: float, s: float, v: float) -> tuple[float, float, float]: ... # TODO undocumented ONE_SIXTH: float diff --git a/mypy/typeshed/stdlib/concurrent/futures/process.pyi b/mypy/typeshed/stdlib/concurrent/futures/process.pyi index 4ae791361bb1..cc48f48f0023 100644 --- a/mypy/typeshed/stdlib/concurrent/futures/process.pyi +++ b/mypy/typeshed/stdlib/concurrent/futures/process.pyi @@ -85,7 +85,7 @@ if sys.version_info >= (3, 7): def _on_queue_feeder_error(self, e: Exception, obj: _CallItem) -> None: ... def _get_chunks(*iterables: Any, chunksize: int) -> Generator[Tuple[Any, ...], None, None]: ... -def _process_chunk(fn: Callable[..., Any], chunk: Tuple[Any, None, None]) -> Generator[Any, None, None]: ... +def _process_chunk(fn: Callable[..., Any], chunk: tuple[Any, None, None]) -> Generator[Any, None, None]: ... def _sendback_result( result_queue: SimpleQueue[_WorkItem[Any]], work_id: int, result: Any | None = ..., exception: Exception | None = ... ) -> None: ... diff --git a/mypy/typeshed/stdlib/concurrent/futures/thread.pyi b/mypy/typeshed/stdlib/concurrent/futures/thread.pyi index 7a35bfc6ed77..5ad5b65d3bec 100644 --- a/mypy/typeshed/stdlib/concurrent/futures/thread.pyi +++ b/mypy/typeshed/stdlib/concurrent/futures/thread.pyi @@ -1,6 +1,6 @@ import queue import sys -from collections.abc import Iterable, Mapping, Set +from collections.abc import Iterable, Mapping, Set # equivalent to typing.AbstractSet, not builtins.set from threading import Lock, Semaphore, Thread from typing import Any, Callable, Generic, Tuple, TypeVar from weakref import ref diff --git a/mypy/typeshed/stdlib/configparser.pyi b/mypy/typeshed/stdlib/configparser.pyi index c278b82a6823..a0efa30416dd 100644 --- a/mypy/typeshed/stdlib/configparser.pyi +++ b/mypy/typeshed/stdlib/configparser.pyi @@ -1,7 +1,7 @@ import sys from _typeshed import StrOrBytesPath, StrPath, SupportsWrite from collections.abc import Callable, ItemsView, Iterable, Iterator, Mapping, MutableMapping, Sequence -from typing import Any, ClassVar, Dict, Optional, Pattern, Tuple, Type, TypeVar, overload +from typing import Any, ClassVar, Dict, Optional, Pattern, Type, TypeVar, overload from typing_extensions import Literal # Internal type aliases @@ -220,7 +220,7 @@ class InterpolationSyntaxError(InterpolationError): ... class ParsingError(Error): source: str - errors: list[Tuple[int, str]] + errors: list[tuple[int, str]] def __init__(self, source: str | None = ..., filename: str | None = ...) -> None: ... def append(self, lineno: int, line: str) -> None: ... diff --git a/mypy/typeshed/stdlib/contextlib.pyi b/mypy/typeshed/stdlib/contextlib.pyi index 69f62575633c..9d968e092ca5 100644 --- a/mypy/typeshed/stdlib/contextlib.pyi +++ b/mypy/typeshed/stdlib/contextlib.pyi @@ -1,14 +1,14 @@ import sys -from _typeshed import Self +from _typeshed import Self, StrOrBytesPath from types import TracebackType from typing import ( IO, Any, - AsyncContextManager, AsyncIterator, Awaitable, Callable, ContextManager, + Generic, Iterator, Optional, Type, @@ -19,6 +19,8 @@ from typing_extensions import ParamSpec, Protocol AbstractContextManager = ContextManager if sys.version_info >= (3, 7): + from typing import AsyncContextManager + AbstractAsyncContextManager = AsyncContextManager _T = TypeVar("_T") @@ -28,55 +30,55 @@ _F = TypeVar("_F", bound=Callable[..., Any]) _P = ParamSpec("_P") _ExitFunc = Callable[[Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]], bool] -_CM_EF = TypeVar("_CM_EF", ContextManager[Any], _ExitFunc) +_CM_EF = TypeVar("_CM_EF", AbstractContextManager[Any], _ExitFunc) -class _GeneratorContextManager(ContextManager[_T_co]): +class _GeneratorContextManager(AbstractContextManager[_T_co]): def __call__(self, func: _F) -> _F: ... # type ignore to deal with incomplete ParamSpec support in mypy def contextmanager(func: Callable[_P, Iterator[_T]]) -> Callable[_P, _GeneratorContextManager[_T]]: ... # type: ignore if sys.version_info >= (3, 7): - def asynccontextmanager(func: Callable[_P, AsyncIterator[_T]]) -> Callable[_P, AsyncContextManager[_T]]: ... # type: ignore + def asynccontextmanager(func: Callable[_P, AsyncIterator[_T]]) -> Callable[_P, AbstractAsyncContextManager[_T]]: ... # type: ignore class _SupportsClose(Protocol): def close(self) -> object: ... _SupportsCloseT = TypeVar("_SupportsCloseT", bound=_SupportsClose) -class closing(ContextManager[_SupportsCloseT]): +class closing(AbstractContextManager[_SupportsCloseT]): def __init__(self, thing: _SupportsCloseT) -> None: ... if sys.version_info >= (3, 10): class _SupportsAclose(Protocol): def aclose(self) -> Awaitable[object]: ... _SupportsAcloseT = TypeVar("_SupportsAcloseT", bound=_SupportsAclose) - class aclosing(AsyncContextManager[_SupportsAcloseT]): + class aclosing(AbstractAsyncContextManager[_SupportsAcloseT]): def __init__(self, thing: _SupportsAcloseT) -> None: ... _AF = TypeVar("_AF", bound=Callable[..., Awaitable[Any]]) class AsyncContextDecorator: def __call__(self, func: _AF) -> _AF: ... -class suppress(ContextManager[None]): +class suppress(AbstractContextManager[None]): def __init__(self, *exceptions: Type[BaseException]) -> None: ... def __exit__( self, exctype: Type[BaseException] | None, excinst: BaseException | None, exctb: TracebackType | None ) -> bool: ... -class redirect_stdout(ContextManager[_T_io]): +class redirect_stdout(AbstractContextManager[_T_io]): def __init__(self, new_target: _T_io) -> None: ... -class redirect_stderr(ContextManager[_T_io]): +class redirect_stderr(AbstractContextManager[_T_io]): def __init__(self, new_target: _T_io) -> None: ... class ContextDecorator: def __call__(self, func: _F) -> _F: ... -class ExitStack(ContextManager[ExitStack]): +class ExitStack(AbstractContextManager[ExitStack]): def __init__(self) -> None: ... - def enter_context(self, cm: ContextManager[_T]) -> _T: ... + def enter_context(self, cm: AbstractContextManager[_T]) -> _T: ... def push(self, exit: _CM_EF) -> _CM_EF: ... - def callback(self, callback: Callable[..., Any], *args: Any, **kwds: Any) -> Callable[..., Any]: ... + def callback(self, __callback: Callable[..., Any], *args: Any, **kwds: Any) -> Callable[..., Any]: ... def pop_all(self: Self) -> Self: ... def close(self) -> None: ... def __enter__(self: Self) -> Self: ... @@ -87,15 +89,15 @@ class ExitStack(ContextManager[ExitStack]): if sys.version_info >= (3, 7): _ExitCoroFunc = Callable[[Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]], Awaitable[bool]] _CallbackCoroFunc = Callable[..., Awaitable[Any]] - _ACM_EF = TypeVar("_ACM_EF", AsyncContextManager[Any], _ExitCoroFunc) - class AsyncExitStack(AsyncContextManager[AsyncExitStack]): + _ACM_EF = TypeVar("_ACM_EF", AbstractAsyncContextManager[Any], _ExitCoroFunc) + class AsyncExitStack(AbstractAsyncContextManager[AsyncExitStack]): def __init__(self) -> None: ... - def enter_context(self, cm: ContextManager[_T]) -> _T: ... - def enter_async_context(self, cm: AsyncContextManager[_T]) -> Awaitable[_T]: ... + def enter_context(self, cm: AbstractContextManager[_T]) -> _T: ... + def enter_async_context(self, cm: AbstractAsyncContextManager[_T]) -> Awaitable[_T]: ... def push(self, exit: _CM_EF) -> _CM_EF: ... def push_async_exit(self, exit: _ACM_EF) -> _ACM_EF: ... - def callback(self, callback: Callable[..., Any], *args: Any, **kwds: Any) -> Callable[..., Any]: ... - def push_async_callback(self, callback: _CallbackCoroFunc, *args: Any, **kwds: Any) -> _CallbackCoroFunc: ... + def callback(self, __callback: Callable[..., Any], *args: Any, **kwds: Any) -> Callable[..., Any]: ... + def push_async_callback(self, __callback: _CallbackCoroFunc, *args: Any, **kwds: Any) -> _CallbackCoroFunc: ... def pop_all(self: Self) -> Self: ... def aclose(self) -> Awaitable[None]: ... def __aenter__(self: Self) -> Awaitable[Self]: ... @@ -124,3 +126,11 @@ elif sys.version_info >= (3, 7): def __init__(self: nullcontext[_T], enter_result: _T) -> None: ... def __enter__(self) -> _T: ... def __exit__(self, *exctype: Any) -> None: ... + +if sys.version_info >= (3, 11): + _T_fd_or_any_path = TypeVar("_T_fd_or_any_path", bound=int | StrOrBytesPath) + class chdir(AbstractContextManager[None], Generic[_T_fd_or_any_path]): + path: _T_fd_or_any_path + def __init__(self, path: _T_fd_or_any_path) -> None: ... + def __enter__(self) -> None: ... + def __exit__(self, *excinfo: object) -> None: ... diff --git a/mypy/typeshed/stdlib/ctypes/__init__.pyi b/mypy/typeshed/stdlib/ctypes/__init__.pyi index 03e9affd5267..bbe083f5d4c4 100644 --- a/mypy/typeshed/stdlib/ctypes/__init__.pyi +++ b/mypy/typeshed/stdlib/ctypes/__init__.pyi @@ -1,5 +1,5 @@ import sys -from array import array +from _typeshed import ReadableBuffer, WriteableBuffer from typing import ( Any, Callable, @@ -72,13 +72,6 @@ if sys.platform == "win32": pydll: LibraryLoader[PyDLL] pythonapi: PyDLL -# Anything that implements the read-write buffer interface. -# The buffer interface is defined purely on the C level, so we cannot define a normal Protocol -# for it. Instead we have to list the most common stdlib buffer classes in a Union. -_WritableBuffer = _UnionT[bytearray, memoryview, array[Any], _CData] -# Same as _WritableBuffer, but also includes read-only buffer types (like bytes). -_ReadOnlyBuffer = _UnionT[_WritableBuffer, bytes] - 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 @@ -91,9 +84,9 @@ class _CData(metaclass=_CDataMeta): _b_needsfree_: bool _objects: Mapping[Any, int] | None @classmethod - def from_buffer(cls: Type[_CT], source: _WritableBuffer, offset: int = ...) -> _CT: ... + def from_buffer(cls: Type[_CT], source: WriteableBuffer, offset: int = ...) -> _CT: ... @classmethod - def from_buffer_copy(cls: Type[_CT], source: _ReadOnlyBuffer, offset: int = ...) -> _CT: ... + def from_buffer_copy(cls: Type[_CT], source: ReadableBuffer, offset: int = ...) -> _CT: ... @classmethod def from_address(cls: Type[_CT], address: int) -> _CT: ... @classmethod @@ -116,7 +109,7 @@ class _FuncPointer(_PointerLike, _CData): @overload def __init__(self, callable: Callable[..., Any]) -> None: ... @overload - def __init__(self, func_spec: Tuple[str | int, CDLL], paramflags: Tuple[_PF, ...] = ...) -> None: ... + def __init__(self, func_spec: tuple[str | int, CDLL], paramflags: Tuple[_PF, ...] = ...) -> None: ... @overload def __init__(self, vtlb_index: int, name: str, paramflags: Tuple[_PF, ...] = ..., iid: pointer[c_int] = ...) -> None: ... def __call__(self, *args: Any, **kwargs: Any) -> Any: ... @@ -180,7 +173,7 @@ def POINTER(type: Type[_CT]) -> Type[pointer[_CT]]: ... # ctypes._Pointer in that it is the base class for all pointer types. Unlike the real _Pointer, # it can be instantiated directly (to mimic the behavior of the real pointer function). class pointer(Generic[_CT], _PointerLike, _CData): - _type_: ClassVar[Type[_CT]] + _type_: Type[_CT] contents: _CT def __init__(self, arg: _CT = ...) -> None: ... @overload @@ -259,7 +252,7 @@ class _CField: size: int class _StructUnionMeta(_CDataMeta): - _fields_: Sequence[Tuple[str, Type[_CData]] | Tuple[str, Type[_CData], int]] + _fields_: Sequence[tuple[str, Type[_CData]] | tuple[str, Type[_CData], int]] _pack_: int _anonymous_: Sequence[str] def __getattr__(self, name: str) -> _CField: ... @@ -275,8 +268,8 @@ class BigEndianStructure(Structure): ... class LittleEndianStructure(Structure): ... class Array(Generic[_CT], _CData): - _length_: ClassVar[int] - _type_: ClassVar[Type[_CT]] + _length_: int + _type_: Type[_CT] raw: bytes # Note: only available if _CT == c_char value: Any # Note: bytes if _CT == c_char, str if _CT == c_wchar, unavailable otherwise # TODO These methods cannot be annotated correctly at the moment. diff --git a/mypy/typeshed/stdlib/dataclasses.pyi b/mypy/typeshed/stdlib/dataclasses.pyi index b6b76af979f9..59efbe77aed6 100644 --- a/mypy/typeshed/stdlib/dataclasses.pyi +++ b/mypy/typeshed/stdlib/dataclasses.pyi @@ -19,7 +19,7 @@ if sys.version_info >= (3, 10): @overload def asdict(obj: Any) -> dict[str, Any]: ... @overload -def asdict(obj: Any, *, dict_factory: Callable[[list[Tuple[str, Any]]], _T]) -> _T: ... +def asdict(obj: Any, *, dict_factory: Callable[[list[tuple[str, Any]]], _T]) -> _T: ... @overload def astuple(obj: Any) -> Tuple[Any, ...]: ... @overload @@ -190,7 +190,7 @@ class InitVar(Generic[_T]): if sys.version_info >= (3, 10): def make_dataclass( cls_name: str, - fields: Iterable[str | Tuple[str, type] | Tuple[str, type, Field[Any]]], + fields: Iterable[str | tuple[str, type] | tuple[str, type, Field[Any]]], *, bases: Tuple[type, ...] = ..., namespace: dict[str, Any] | None = ..., @@ -207,7 +207,7 @@ if sys.version_info >= (3, 10): else: def make_dataclass( cls_name: str, - fields: Iterable[str | Tuple[str, type] | Tuple[str, type, Field[Any]]], + fields: Iterable[str | tuple[str, type] | tuple[str, type, Field[Any]]], *, bases: Tuple[type, ...] = ..., namespace: dict[str, Any] | None = ..., diff --git a/mypy/typeshed/stdlib/datetime.pyi b/mypy/typeshed/stdlib/datetime.pyi index 22782d9d46e4..bd4d47e051ec 100644 --- a/mypy/typeshed/stdlib/datetime.pyi +++ b/mypy/typeshed/stdlib/datetime.pyi @@ -1,21 +1,24 @@ import sys from time import struct_time -from typing import ClassVar, NamedTuple, SupportsAbs, Tuple, Type, TypeVar, overload +from typing import ClassVar, NamedTuple, NoReturn, SupportsAbs, Type, TypeVar, overload +from typing_extensions import final _S = TypeVar("_S") +_D = TypeVar("_D", bound=date) MINYEAR: int MAXYEAR: int class tzinfo: - def tzname(self, dt: datetime | None) -> str | None: ... - def utcoffset(self, dt: datetime | None) -> timedelta | None: ... - def dst(self, dt: datetime | None) -> timedelta | None: ... - def fromutc(self, dt: datetime) -> datetime: ... + def tzname(self, __dt: datetime | None) -> str | None: ... + def utcoffset(self, __dt: datetime | None) -> timedelta | None: ... + def dst(self, __dt: datetime | None) -> timedelta | None: ... + def fromutc(self, __dt: datetime) -> datetime: ... # Alias required to avoid name conflicts with date(time).tzinfo. _tzinfo = tzinfo +@final class timezone(tzinfo): utc: ClassVar[timezone] min: ClassVar[timezone] @@ -39,10 +42,10 @@ class date: @classmethod def today(cls: Type[_S]) -> _S: ... @classmethod - def fromordinal(cls: Type[_S], n: int) -> _S: ... + def fromordinal(cls: Type[_S], __n: int) -> _S: ... if sys.version_info >= (3, 7): @classmethod - def fromisoformat(cls: Type[_S], date_string: str) -> _S: ... + def fromisoformat(cls: Type[_S], __date_string: str) -> _S: ... if sys.version_info >= (3, 8): @classmethod def fromisocalendar(cls: Type[_S], year: int, week: int, day: int) -> _S: ... @@ -54,32 +57,41 @@ class date: def day(self) -> int: ... def ctime(self) -> str: ... def strftime(self, fmt: str) -> str: ... - def __format__(self, fmt: str) -> str: ... + def __format__(self, __fmt: str) -> str: ... def isoformat(self) -> str: ... def timetuple(self) -> struct_time: ... def toordinal(self) -> int: ... def replace(self, year: int = ..., month: int = ..., day: int = ...) -> date: ... - def __le__(self, other: date) -> bool: ... - def __lt__(self, other: date) -> bool: ... - def __ge__(self, other: date) -> bool: ... - def __gt__(self, other: date) -> bool: ... + def __le__(self, __other: date) -> bool: ... + def __lt__(self, __other: date) -> bool: ... + def __ge__(self, __other: date) -> bool: ... + def __gt__(self, __other: date) -> bool: ... if sys.version_info >= (3, 8): - def __add__(self: _S, other: timedelta) -> _S: ... - def __radd__(self: _S, other: timedelta) -> _S: ... + def __add__(self: _S, __other: timedelta) -> _S: ... + def __radd__(self: _S, __other: timedelta) -> _S: ... + @overload + def __sub__(self: _D, __other: timedelta) -> _D: ... + @overload + def __sub__(self, __other: datetime) -> NoReturn: ... + @overload + def __sub__(self: _D, __other: _D) -> timedelta: ... else: - def __add__(self, other: timedelta) -> date: ... - def __radd__(self, other: timedelta) -> date: ... - @overload - def __sub__(self, other: timedelta) -> date: ... - @overload - def __sub__(self, other: date) -> timedelta: ... + # Prior to Python 3.8, arithmetic operations always returned `date`, even in subclasses + def __add__(self, __other: timedelta) -> date: ... + def __radd__(self, __other: timedelta) -> date: ... + @overload + def __sub__(self, __other: timedelta) -> date: ... + @overload + def __sub__(self, __other: datetime) -> NoReturn: ... + @overload + def __sub__(self, __other: date) -> timedelta: ... def __hash__(self) -> int: ... def weekday(self) -> int: ... def isoweekday(self) -> int: ... if sys.version_info >= (3, 9): def isocalendar(self) -> _IsoCalendarDate: ... else: - def isocalendar(self) -> Tuple[int, int, int]: ... + def isocalendar(self) -> tuple[int, int, int]: ... class time: min: ClassVar[time] @@ -107,17 +119,17 @@ class time: def tzinfo(self) -> _tzinfo | None: ... @property def fold(self) -> int: ... - def __le__(self, other: time) -> bool: ... - def __lt__(self, other: time) -> bool: ... - def __ge__(self, other: time) -> bool: ... - def __gt__(self, other: time) -> bool: ... + def __le__(self, __other: time) -> bool: ... + def __lt__(self, __other: time) -> bool: ... + def __ge__(self, __other: time) -> bool: ... + def __gt__(self, __other: time) -> bool: ... def __hash__(self) -> int: ... def isoformat(self, timespec: str = ...) -> str: ... if sys.version_info >= (3, 7): @classmethod - def fromisoformat(cls: Type[_S], time_string: str) -> _S: ... + def fromisoformat(cls: Type[_S], __time_string: str) -> _S: ... def strftime(self, fmt: str) -> str: ... - def __format__(self, fmt: str) -> str: ... + def __format__(self, __fmt: str) -> str: ... def utcoffset(self) -> timedelta | None: ... def tzname(self) -> str | None: ... def dst(self) -> timedelta | None: ... @@ -156,29 +168,29 @@ class timedelta(SupportsAbs[timedelta]): @property def microseconds(self) -> int: ... def total_seconds(self) -> float: ... - def __add__(self, other: timedelta) -> timedelta: ... - def __radd__(self, other: timedelta) -> timedelta: ... - def __sub__(self, other: timedelta) -> timedelta: ... - def __rsub__(self, other: timedelta) -> timedelta: ... + def __add__(self, __other: timedelta) -> timedelta: ... + def __radd__(self, __other: timedelta) -> timedelta: ... + def __sub__(self, __other: timedelta) -> timedelta: ... + def __rsub__(self, __other: timedelta) -> timedelta: ... def __neg__(self) -> timedelta: ... def __pos__(self) -> timedelta: ... def __abs__(self) -> timedelta: ... - def __mul__(self, other: float) -> timedelta: ... - def __rmul__(self, other: float) -> timedelta: ... + def __mul__(self, __other: float) -> timedelta: ... + def __rmul__(self, __other: float) -> timedelta: ... @overload - def __floordiv__(self, other: timedelta) -> int: ... + def __floordiv__(self, __other: timedelta) -> int: ... @overload - def __floordiv__(self, other: int) -> timedelta: ... + def __floordiv__(self, __other: int) -> timedelta: ... @overload - def __truediv__(self, other: timedelta) -> float: ... + def __truediv__(self, __other: timedelta) -> float: ... @overload - def __truediv__(self, other: float) -> timedelta: ... - def __mod__(self, other: timedelta) -> timedelta: ... - def __divmod__(self, other: timedelta) -> Tuple[int, timedelta]: ... - def __le__(self, other: timedelta) -> bool: ... - def __lt__(self, other: timedelta) -> bool: ... - def __ge__(self, other: timedelta) -> bool: ... - def __gt__(self, other: timedelta) -> bool: ... + def __truediv__(self, __other: float) -> timedelta: ... + def __mod__(self, __other: timedelta) -> timedelta: ... + def __divmod__(self, __other: timedelta) -> tuple[int, timedelta]: ... + def __le__(self, __other: timedelta) -> bool: ... + def __lt__(self, __other: timedelta) -> bool: ... + def __ge__(self, __other: timedelta) -> bool: ... + def __gt__(self, __other: timedelta) -> bool: ... def __bool__(self) -> bool: ... def __hash__(self) -> int: ... @@ -200,12 +212,6 @@ class datetime(date): fold: int = ..., ) -> _S: ... @property - def year(self) -> int: ... - @property - def month(self) -> int: ... - @property - def day(self) -> int: ... - @property def hour(self) -> int: ... @property def minute(self) -> int: ... @@ -217,14 +223,13 @@ class datetime(date): def tzinfo(self) -> _tzinfo | None: ... @property def fold(self) -> int: ... + # The first parameter in `fromtimestamp` is actually positional-or-keyword, + # but it is named "timestamp" in the C implementation and "t" in the Python implementation, + # so it is only truly *safe* to pass it as a positional argument. @classmethod - def fromtimestamp(cls: Type[_S], t: float, tz: _tzinfo | None = ...) -> _S: ... - @classmethod - def utcfromtimestamp(cls: Type[_S], t: float) -> _S: ... - @classmethod - def today(cls: Type[_S]) -> _S: ... + def fromtimestamp(cls: Type[_S], __timestamp: float, tz: _tzinfo | None = ...) -> _S: ... @classmethod - def fromordinal(cls: Type[_S], n: int) -> _S: ... + def utcfromtimestamp(cls: Type[_S], __t: float) -> _S: ... if sys.version_info >= (3, 8): @classmethod def now(cls: Type[_S], tz: _tzinfo | None = ...) -> _S: ... @@ -241,11 +246,7 @@ class datetime(date): def combine(cls, date: _date, time: _time, tzinfo: _tzinfo | None = ...) -> datetime: ... if sys.version_info >= (3, 7): @classmethod - def fromisoformat(cls: Type[_S], date_string: str) -> _S: ... - def strftime(self, fmt: str) -> str: ... - def __format__(self, fmt: str) -> str: ... - def toordinal(self) -> int: ... - def timetuple(self) -> struct_time: ... + def fromisoformat(cls: Type[_S], __date_string: str) -> _S: ... def timestamp(self) -> float: ... def utctimetuple(self) -> struct_time: ... def date(self) -> _date: ... @@ -271,28 +272,28 @@ class datetime(date): def ctime(self) -> str: ... def isoformat(self, sep: str = ..., timespec: str = ...) -> str: ... @classmethod - def strptime(cls, date_string: str, format: str) -> datetime: ... + def strptime(cls, __date_string: str, __format: str) -> datetime: ... def utcoffset(self) -> timedelta | None: ... def tzname(self) -> str | None: ... def dst(self) -> timedelta | None: ... - def __le__(self, other: datetime) -> bool: ... # type: ignore - def __lt__(self, other: datetime) -> bool: ... # type: ignore - def __ge__(self, other: datetime) -> bool: ... # type: ignore - def __gt__(self, other: datetime) -> bool: ... # type: ignore + def __le__(self, __other: datetime) -> bool: ... # type: ignore + def __lt__(self, __other: datetime) -> bool: ... # type: ignore + def __ge__(self, __other: datetime) -> bool: ... # type: ignore + def __gt__(self, __other: datetime) -> bool: ... # type: ignore if sys.version_info >= (3, 8): - def __add__(self: _S, other: timedelta) -> _S: ... - def __radd__(self: _S, other: timedelta) -> _S: ... + @overload # type: ignore[override] + def __sub__(self: _D, __other: timedelta) -> _D: ... + @overload + def __sub__(self: _D, __other: _D) -> timedelta: ... else: - def __add__(self, other: timedelta) -> datetime: ... - def __radd__(self, other: timedelta) -> datetime: ... - @overload # type: ignore - def __sub__(self, other: datetime) -> timedelta: ... - @overload - def __sub__(self, other: timedelta) -> datetime: ... - def __hash__(self) -> int: ... - def weekday(self) -> int: ... - def isoweekday(self) -> int: ... + # Prior to Python 3.8, arithmetic operations always returned `datetime`, even in subclasses + def __add__(self, __other: timedelta) -> datetime: ... + def __radd__(self, __other: timedelta) -> datetime: ... + @overload # type: ignore[override] + def __sub__(self, __other: datetime) -> timedelta: ... + @overload + def __sub__(self, __other: timedelta) -> datetime: ... if sys.version_info >= (3, 9): def isocalendar(self) -> _IsoCalendarDate: ... else: - def isocalendar(self) -> Tuple[int, int, int]: ... + def isocalendar(self) -> tuple[int, int, int]: ... diff --git a/mypy/typeshed/stdlib/decimal.pyi b/mypy/typeshed/stdlib/decimal.pyi index a21ec92a3d65..30c8e973348d 100644 --- a/mypy/typeshed/stdlib/decimal.pyi +++ b/mypy/typeshed/stdlib/decimal.pyi @@ -54,32 +54,32 @@ class Decimal(object): def compare(self, other: _Decimal, context: Context | None = ...) -> Decimal: ... def __hash__(self) -> int: ... def as_tuple(self) -> DecimalTuple: ... - def as_integer_ratio(self) -> Tuple[int, int]: ... + def as_integer_ratio(self) -> tuple[int, int]: ... def to_eng_string(self, context: Context | None = ...) -> str: ... def __abs__(self) -> Decimal: ... - def __add__(self, other: _Decimal) -> Decimal: ... - def __divmod__(self, other: _Decimal) -> Tuple[Decimal, Decimal]: ... - def __eq__(self, other: object) -> bool: ... - def __floordiv__(self, other: _Decimal) -> Decimal: ... - def __ge__(self, other: _ComparableNum) -> bool: ... - def __gt__(self, other: _ComparableNum) -> bool: ... - def __le__(self, other: _ComparableNum) -> bool: ... - def __lt__(self, other: _ComparableNum) -> bool: ... - def __mod__(self, other: _Decimal) -> Decimal: ... - def __mul__(self, other: _Decimal) -> Decimal: ... + def __add__(self, __other: _Decimal) -> Decimal: ... + def __divmod__(self, __other: _Decimal) -> tuple[Decimal, Decimal]: ... + def __eq__(self, __other: object) -> bool: ... + def __floordiv__(self, __other: _Decimal) -> Decimal: ... + def __ge__(self, __other: _ComparableNum) -> bool: ... + def __gt__(self, __other: _ComparableNum) -> bool: ... + def __le__(self, __other: _ComparableNum) -> bool: ... + def __lt__(self, __other: _ComparableNum) -> bool: ... + def __mod__(self, __other: _Decimal) -> Decimal: ... + def __mul__(self, __other: _Decimal) -> Decimal: ... def __neg__(self) -> Decimal: ... def __pos__(self) -> Decimal: ... - def __pow__(self, other: _Decimal, modulo: _Decimal | None = ...) -> Decimal: ... - def __radd__(self, other: _Decimal) -> Decimal: ... - def __rdivmod__(self, other: _Decimal) -> Tuple[Decimal, Decimal]: ... - def __rfloordiv__(self, other: _Decimal) -> Decimal: ... - def __rmod__(self, other: _Decimal) -> Decimal: ... - def __rmul__(self, other: _Decimal) -> Decimal: ... - def __rsub__(self, other: _Decimal) -> Decimal: ... - def __rtruediv__(self, other: _Decimal) -> Decimal: ... + def __pow__(self, __other: _Decimal, __modulo: _Decimal | None = ...) -> Decimal: ... + def __radd__(self, __other: _Decimal) -> Decimal: ... + def __rdivmod__(self, __other: _Decimal) -> tuple[Decimal, Decimal]: ... + def __rfloordiv__(self, __other: _Decimal) -> Decimal: ... + def __rmod__(self, __other: _Decimal) -> Decimal: ... + def __rmul__(self, __other: _Decimal) -> Decimal: ... + def __rsub__(self, __other: _Decimal) -> Decimal: ... + def __rtruediv__(self, __other: _Decimal) -> Decimal: ... def __str__(self) -> str: ... - def __sub__(self, other: _Decimal) -> Decimal: ... - def __truediv__(self, other: _Decimal) -> Decimal: ... + def __sub__(self, __other: _Decimal) -> Decimal: ... + def __truediv__(self, __other: _Decimal) -> Decimal: ... def remainder_near(self, other: _Decimal, context: Context | None = ...) -> Decimal: ... def __float__(self) -> float: ... def __int__(self) -> int: ... @@ -93,11 +93,11 @@ class Decimal(object): @overload def __round__(self) -> int: ... @overload - def __round__(self, ndigits: int) -> Decimal: ... + def __round__(self, __ndigits: int) -> Decimal: ... def __floor__(self) -> int: ... def __ceil__(self) -> int: ... def fma(self, other: _Decimal, third: _Decimal, context: Context | None = ...) -> Decimal: ... - def __rpow__(self, other: _Decimal, context: Context | None = ...) -> Decimal: ... + def __rpow__(self, __other: _Decimal, __context: Context | None = ...) -> Decimal: ... def normalize(self, context: Context | None = ...) -> Decimal: ... def quantize(self, exp: _Decimal, rounding: str | None = ..., context: Context | None = ...) -> Decimal: ... def same_quantum(self, other: _Decimal, context: Context | None = ...) -> bool: ... @@ -143,10 +143,10 @@ class Decimal(object): def rotate(self, other: _Decimal, context: Context | None = ...) -> Decimal: ... def scaleb(self, other: _Decimal, context: Context | None = ...) -> Decimal: ... def shift(self, other: _Decimal, context: Context | None = ...) -> Decimal: ... - def __reduce__(self) -> Tuple[Type[Decimal], Tuple[str]]: ... + def __reduce__(self) -> tuple[Type[Decimal], tuple[str]]: ... def __copy__(self) -> Decimal: ... - def __deepcopy__(self, memo: Any) -> Decimal: ... - def __format__(self, specifier: str, context: Context | None = ...) -> str: ... + def __deepcopy__(self, __memo: Any) -> Decimal: ... + def __format__(self, __specifier: str, __context: Context | None = ...) -> str: ... class _ContextManager(object): new_context: Context @@ -180,8 +180,8 @@ class Context(object): ) -> None: ... # __setattr__() only allows to set a specific set of attributes, # already defined above. - def __delattr__(self, name: str) -> None: ... - def __reduce__(self) -> Tuple[Type[Context], Tuple[Any, ...]]: ... + def __delattr__(self, __name: str) -> None: ... + def __reduce__(self) -> tuple[Type[Context], Tuple[Any, ...]]: ... def clear_flags(self) -> None: ... def clear_traps(self) -> None: ... def copy(self) -> Context: ... @@ -204,7 +204,7 @@ class Context(object): 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 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: ... diff --git a/mypy/typeshed/stdlib/difflib.pyi b/mypy/typeshed/stdlib/difflib.pyi index 5db947293e42..7c4ae8e2f246 100644 --- a/mypy/typeshed/stdlib/difflib.pyi +++ b/mypy/typeshed/stdlib/difflib.pyi @@ -1,5 +1,5 @@ import sys -from typing import Any, AnyStr, Callable, Generic, Iterable, Iterator, NamedTuple, Sequence, Tuple, TypeVar, Union, overload +from typing import Any, AnyStr, Callable, Generic, Iterable, Iterator, NamedTuple, Sequence, TypeVar, Union, overload if sys.version_info >= (3, 9): from types import GenericAlias @@ -24,8 +24,8 @@ class SequenceMatcher(Generic[_T]): else: def find_longest_match(self, alo: int, ahi: int, blo: int, bhi: int) -> Match: ... def get_matching_blocks(self) -> list[Match]: ... - def get_opcodes(self) -> list[Tuple[str, int, int, int, int]]: ... - def get_grouped_opcodes(self, n: int = ...) -> Iterable[list[Tuple[str, int, int, int, int]]]: ... + def get_opcodes(self) -> list[tuple[str, int, int, int, int]]: ... + def get_grouped_opcodes(self, n: int = ...) -> Iterable[list[tuple[str, int, int, int, int]]]: ... def ratio(self) -> float: ... def quick_ratio(self) -> float: ... def real_quick_ratio(self) -> float: ... diff --git a/mypy/typeshed/stdlib/dis.pyi b/mypy/typeshed/stdlib/dis.pyi index d9e3c7213c84..a6ea3e950b95 100644 --- a/mypy/typeshed/stdlib/dis.pyi +++ b/mypy/typeshed/stdlib/dis.pyi @@ -16,7 +16,7 @@ from opcode import ( opname as opname, stack_effect as stack_effect, ) -from typing import IO, Any, Callable, Iterator, NamedTuple, Tuple, Union +from typing import IO, Any, Callable, Iterator, NamedTuple, Union # Strictly this should not have to include Callable, but mypy doesn't use FunctionType # for functions (python/mypy#3171) @@ -47,7 +47,7 @@ class Bytecode: COMPILER_FLAG_NAMES: dict[int, str] def findlabels(code: _have_code) -> list[int]: ... -def findlinestarts(code: _have_code) -> Iterator[Tuple[int, int]]: ... +def findlinestarts(code: _have_code) -> Iterator[tuple[int, int]]: ... def pretty_flags(flags: int) -> str: ... def code_info(x: _have_code_or_string) -> str: ... diff --git a/mypy/typeshed/stdlib/distutils/cmd.pyi b/mypy/typeshed/stdlib/distutils/cmd.pyi index dd2e1905adf5..875e851bed39 100644 --- a/mypy/typeshed/stdlib/distutils/cmd.pyi +++ b/mypy/typeshed/stdlib/distutils/cmd.pyi @@ -1,9 +1,9 @@ from abc import abstractmethod from distutils.dist import Distribution -from typing import Any, Callable, Iterable, Tuple +from typing import Any, Callable, Iterable class Command: - sub_commands: list[Tuple[str, Callable[[Command], bool] | None]] + sub_commands: list[tuple[str, Callable[[Command], bool] | None]] def __init__(self, dist: Distribution) -> None: ... @abstractmethod def initialize_options(self) -> None: ... @@ -18,7 +18,7 @@ class Command: def ensure_filename(self, option: str) -> None: ... def ensure_dirname(self, option: str) -> None: ... def get_command_name(self) -> str: ... - def set_undefined_options(self, src_cmd: str, *option_pairs: Tuple[str, str]) -> None: ... + def set_undefined_options(self, src_cmd: str, *option_pairs: tuple[str, str]) -> None: ... def get_finalized_command(self, command: str, create: int = ...) -> Command: ... def reinitialize_command(self, command: Command | str, reinit_subcommands: int = ...) -> Command: ... def run_command(self, command: str) -> None: ... @@ -34,7 +34,7 @@ class Command: preserve_times: int = ..., link: str | None = ..., level: Any = ..., - ) -> Tuple[str, bool]: ... # level is not used + ) -> tuple[str, bool]: ... # level is not used def copy_tree( self, infile: str, @@ -57,7 +57,7 @@ class Command: ) -> str: ... def make_file( self, - infiles: str | list[str] | Tuple[str], + infiles: str | list[str] | tuple[str], outfile: str, func: Callable[..., Any], args: list[Any], diff --git a/mypy/typeshed/stdlib/distutils/core.pyi b/mypy/typeshed/stdlib/distutils/core.pyi index dc0870895cf9..fc4cd81c4752 100644 --- a/mypy/typeshed/stdlib/distutils/core.pyi +++ b/mypy/typeshed/stdlib/distutils/core.pyi @@ -1,7 +1,7 @@ from distutils.cmd import Command as Command from distutils.dist import Distribution as Distribution from distutils.extension import Extension as Extension -from typing import Any, Mapping, Tuple, Type +from typing import Any, Mapping, Type def setup( *, @@ -28,13 +28,13 @@ def setup( keywords: list[str] | str = ..., platforms: list[str] | str = ..., cmdclass: Mapping[str, Type[Command]] = ..., - data_files: list[Tuple[str, list[str]]] = ..., + data_files: list[tuple[str, list[str]]] = ..., package_dir: Mapping[str, str] = ..., obsoletes: list[str] = ..., 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[Any, Any]]] = ..., package_data: Mapping[str, list[str]] = ..., include_package_data: bool = ..., libraries: list[str] = ..., diff --git a/mypy/typeshed/stdlib/distutils/dep_util.pyi b/mypy/typeshed/stdlib/distutils/dep_util.pyi index 595dcb80a38c..929d6ffd0c81 100644 --- a/mypy/typeshed/stdlib/distutils/dep_util.pyi +++ b/mypy/typeshed/stdlib/distutils/dep_util.pyi @@ -1,5 +1,3 @@ -from typing import Tuple - def newer(source: str, target: str) -> bool: ... -def newer_pairwise(sources: list[str], targets: list[str]) -> list[Tuple[str, str]]: ... +def newer_pairwise(sources: list[str], targets: list[str]) -> list[tuple[str, str]]: ... def newer_group(sources: list[str], target: str, missing: str = ...) -> bool: ... diff --git a/mypy/typeshed/stdlib/distutils/dist.pyi b/mypy/typeshed/stdlib/distutils/dist.pyi index ca3f108ab681..5bb04b049995 100644 --- a/mypy/typeshed/stdlib/distutils/dist.pyi +++ b/mypy/typeshed/stdlib/distutils/dist.pyi @@ -1,6 +1,6 @@ from _typeshed import StrOrBytesPath, SupportsWrite from distutils.cmd import Command -from typing import IO, Any, Iterable, Mapping, Tuple, Type +from typing import IO, Any, Iterable, Mapping, Type class DistributionMetadata: def __init__(self, path: int | StrOrBytesPath | None = ...) -> None: ... @@ -53,6 +53,6 @@ class Distribution: cmdclass: dict[str, Type[Command]] metadata: DistributionMetadata def __init__(self, attrs: Mapping[str, Any] | None = ...) -> None: ... - def get_option_dict(self, command: str) -> dict[str, Tuple[str, str]]: ... + def get_option_dict(self, command: str) -> dict[str, tuple[str, str]]: ... def parse_config_files(self, filenames: Iterable[str] | None = ...) -> None: ... def get_command_obj(self, command: str, create: bool = ...) -> Command | None: ... diff --git a/mypy/typeshed/stdlib/distutils/extension.pyi b/mypy/typeshed/stdlib/distutils/extension.pyi index 0941a402e604..655ea1e9e347 100644 --- a/mypy/typeshed/stdlib/distutils/extension.pyi +++ b/mypy/typeshed/stdlib/distutils/extension.pyi @@ -1,12 +1,10 @@ -from typing import Tuple - class Extension: def __init__( self, name: str, sources: list[str], include_dirs: list[str] | None = ..., - define_macros: list[Tuple[str, str | None]] | None = ..., + define_macros: list[tuple[str, str | None]] | None = ..., undef_macros: list[str] | None = ..., library_dirs: list[str] | None = ..., libraries: list[str] | None = ..., diff --git a/mypy/typeshed/stdlib/distutils/fancy_getopt.pyi b/mypy/typeshed/stdlib/distutils/fancy_getopt.pyi index a2c24187a498..06a0847e4687 100644 --- a/mypy/typeshed/stdlib/distutils/fancy_getopt.pyi +++ b/mypy/typeshed/stdlib/distutils/fancy_getopt.pyi @@ -15,7 +15,7 @@ class FancyGetopt: def getopt(self, args: list[str] | None = ...) -> _GR: ... @overload def getopt(self, args: list[str] | None, object: Any) -> list[str]: ... - def get_option_order(self) -> list[Tuple[str, str]]: ... + def get_option_order(self) -> list[tuple[str, str]]: ... def generate_help(self, header: str | None = ...) -> list[str]: ... class OptionDummy: diff --git a/mypy/typeshed/stdlib/distutils/file_util.pyi b/mypy/typeshed/stdlib/distutils/file_util.pyi index cfe840e71040..a7f24105a678 100644 --- a/mypy/typeshed/stdlib/distutils/file_util.pyi +++ b/mypy/typeshed/stdlib/distutils/file_util.pyi @@ -1,4 +1,4 @@ -from typing import Sequence, Tuple +from typing import Sequence def copy_file( src: str, @@ -9,6 +9,6 @@ def copy_file( link: str | None = ..., verbose: bool = ..., dry_run: bool = ..., -) -> Tuple[str, str]: ... +) -> tuple[str, str]: ... def move_file(src: str, dst: str, verbose: bool = ..., dry_run: bool = ...) -> str: ... def write_file(filename: str, contents: Sequence[str]) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/text_file.pyi b/mypy/typeshed/stdlib/distutils/text_file.pyi index 6a0aded5176e..ace642e027cf 100644 --- a/mypy/typeshed/stdlib/distutils/text_file.pyi +++ b/mypy/typeshed/stdlib/distutils/text_file.pyi @@ -1,4 +1,4 @@ -from typing import IO, Tuple +from typing import IO class TextFile: def __init__( @@ -15,7 +15,7 @@ class TextFile: ) -> None: ... def open(self, filename: str) -> None: ... def close(self) -> None: ... - def warn(self, msg: str, line: list[int] | Tuple[int, int] | int | None = ...) -> None: ... + def warn(self, msg: str, line: list[int] | tuple[int, int] | int | None = ...) -> None: ... def readline(self) -> str | None: ... def readlines(self) -> list[str]: ... def unreadline(self, line: str) -> str: ... diff --git a/mypy/typeshed/stdlib/distutils/version.pyi b/mypy/typeshed/stdlib/distutils/version.pyi index 29d72174d8db..9921dde39af6 100644 --- a/mypy/typeshed/stdlib/distutils/version.pyi +++ b/mypy/typeshed/stdlib/distutils/version.pyi @@ -21,8 +21,8 @@ class Version: class StrictVersion(Version): version_re: Pattern[str] - version: Tuple[int, int, int] - prerelease: Tuple[str, int] | None + version: tuple[int, int, int] + prerelease: tuple[str, int] | None def __init__(self, vstring: str | None = ...) -> None: ... def parse(self: _T, vstring: str) -> _T: ... def __str__(self) -> str: ... diff --git a/mypy/typeshed/stdlib/email/_header_value_parser.pyi b/mypy/typeshed/stdlib/email/_header_value_parser.pyi index 04234b482773..f1b08b5d5805 100644 --- a/mypy/typeshed/stdlib/email/_header_value_parser.pyi +++ b/mypy/typeshed/stdlib/email/_header_value_parser.pyi @@ -1,22 +1,22 @@ import sys from email.errors import HeaderParseError, MessageDefect from email.policy import Policy -from typing import Any, Iterable, Iterator, List, Pattern, Set, Tuple, Type, TypeVar, Union +from typing import Any, Iterable, Iterator, List, Pattern, Type, TypeVar, Union from typing_extensions import Final _T = TypeVar("_T") -WSP: Final[Set[str]] -CFWS_LEADER: Final[Set[str]] -SPECIALS: Final[Set[str]] -ATOM_ENDS: Final[Set[str]] -DOT_ATOM_ENDS: Final[Set[str]] -PHRASE_ENDS: Final[Set[str]] -TSPECIALS: Final[Set[str]] -TOKEN_ENDS: Final[Set[str]] -ASPECIALS: Final[Set[str]] -ATTRIBUTE_ENDS: Final[Set[str]] -EXTENDED_ATTRIBUTE_ENDS: Final[Set[str]] +WSP: Final[set[str]] +CFWS_LEADER: Final[set[str]] +SPECIALS: Final[set[str]] +ATOM_ENDS: Final[set[str]] +DOT_ATOM_ENDS: Final[set[str]] +PHRASE_ENDS: Final[set[str]] +TSPECIALS: Final[set[str]] +TOKEN_ENDS: Final[set[str]] +ASPECIALS: Final[set[str]] +ATTRIBUTE_ENDS: Final[set[str]] +EXTENDED_ATTRIBUTE_ENDS: Final[set[str]] def quote_string(value: Any) -> str: ... @@ -281,12 +281,12 @@ class MimeParameters(TokenList): token_type: str syntactic_break: bool @property - def params(self) -> Iterator[Tuple[str, str]]: ... + def params(self) -> Iterator[tuple[str, str]]: ... class ParameterizedHeaderValue(TokenList): syntactic_break: bool @property - def params(self) -> Iterable[Tuple[str, str]]: ... + def params(self) -> Iterable[tuple[str, str]]: ... class ContentType(ParameterizedHeaderValue): token_type: str @@ -334,7 +334,7 @@ class Terminal(str): def pop_trailing_ws(self) -> None: ... @property def comments(self) -> list[str]: ... - def __getnewargs__(self) -> Tuple[str, str]: ... # type: ignore + def __getnewargs__(self) -> tuple[str, str]: ... # type: ignore class WhiteSpaceTerminal(Terminal): @property @@ -356,55 +356,55 @@ DOT: Final[ValueTerminal] ListSeparator: Final[ValueTerminal] RouteComponentMarker: Final[ValueTerminal] -def get_fws(value: str) -> Tuple[WhiteSpaceTerminal, str]: ... -def get_encoded_word(value: str) -> Tuple[EncodedWord, str]: ... +def get_fws(value: str) -> tuple[WhiteSpaceTerminal, str]: ... +def get_encoded_word(value: str) -> tuple[EncodedWord, str]: ... def get_unstructured(value: str) -> UnstructuredTokenList: ... -def get_qp_ctext(value: str) -> Tuple[WhiteSpaceTerminal, str]: ... -def get_qcontent(value: str) -> Tuple[ValueTerminal, str]: ... -def get_atext(value: str) -> Tuple[ValueTerminal, str]: ... -def get_bare_quoted_string(value: str) -> Tuple[BareQuotedString, str]: ... -def get_comment(value: str) -> Tuple[Comment, str]: ... -def get_cfws(value: str) -> Tuple[CFWSList, str]: ... -def get_quoted_string(value: str) -> Tuple[QuotedString, str]: ... -def get_atom(value: str) -> Tuple[Atom, str]: ... -def get_dot_atom_text(value: str) -> Tuple[DotAtomText, str]: ... -def get_dot_atom(value: str) -> Tuple[DotAtom, str]: ... -def get_word(value: str) -> Tuple[Any, str]: ... -def get_phrase(value: str) -> Tuple[Phrase, str]: ... -def get_local_part(value: str) -> Tuple[LocalPart, str]: ... -def get_obs_local_part(value: str) -> Tuple[ObsLocalPart, str]: ... -def get_dtext(value: str) -> Tuple[ValueTerminal, str]: ... -def get_domain_literal(value: str) -> Tuple[DomainLiteral, str]: ... -def get_domain(value: str) -> Tuple[Domain, str]: ... -def get_addr_spec(value: str) -> Tuple[AddrSpec, str]: ... -def get_obs_route(value: str) -> Tuple[ObsRoute, str]: ... -def get_angle_addr(value: str) -> Tuple[AngleAddr, str]: ... -def get_display_name(value: str) -> Tuple[DisplayName, str]: ... -def get_name_addr(value: str) -> Tuple[NameAddr, str]: ... -def get_mailbox(value: str) -> Tuple[Mailbox, str]: ... -def get_invalid_mailbox(value: str, endchars: str) -> Tuple[InvalidMailbox, str]: ... -def get_mailbox_list(value: str) -> Tuple[MailboxList, str]: ... -def get_group_list(value: str) -> Tuple[GroupList, str]: ... -def get_group(value: str) -> Tuple[Group, str]: ... -def get_address(value: str) -> Tuple[Address, str]: ... -def get_address_list(value: str) -> Tuple[AddressList, str]: ... +def get_qp_ctext(value: str) -> tuple[WhiteSpaceTerminal, str]: ... +def get_qcontent(value: str) -> tuple[ValueTerminal, str]: ... +def get_atext(value: str) -> tuple[ValueTerminal, str]: ... +def get_bare_quoted_string(value: str) -> tuple[BareQuotedString, str]: ... +def get_comment(value: str) -> tuple[Comment, str]: ... +def get_cfws(value: str) -> tuple[CFWSList, str]: ... +def get_quoted_string(value: str) -> tuple[QuotedString, str]: ... +def get_atom(value: str) -> tuple[Atom, str]: ... +def get_dot_atom_text(value: str) -> tuple[DotAtomText, str]: ... +def get_dot_atom(value: str) -> tuple[DotAtom, str]: ... +def get_word(value: str) -> tuple[Any, str]: ... +def get_phrase(value: str) -> tuple[Phrase, str]: ... +def get_local_part(value: str) -> tuple[LocalPart, str]: ... +def get_obs_local_part(value: str) -> tuple[ObsLocalPart, str]: ... +def get_dtext(value: str) -> tuple[ValueTerminal, str]: ... +def get_domain_literal(value: str) -> tuple[DomainLiteral, str]: ... +def get_domain(value: str) -> tuple[Domain, str]: ... +def get_addr_spec(value: str) -> tuple[AddrSpec, str]: ... +def get_obs_route(value: str) -> tuple[ObsRoute, str]: ... +def get_angle_addr(value: str) -> tuple[AngleAddr, str]: ... +def get_display_name(value: str) -> tuple[DisplayName, str]: ... +def get_name_addr(value: str) -> tuple[NameAddr, str]: ... +def get_mailbox(value: str) -> tuple[Mailbox, str]: ... +def get_invalid_mailbox(value: str, endchars: str) -> tuple[InvalidMailbox, str]: ... +def get_mailbox_list(value: str) -> tuple[MailboxList, str]: ... +def get_group_list(value: str) -> tuple[GroupList, str]: ... +def get_group(value: str) -> tuple[Group, str]: ... +def get_address(value: str) -> tuple[Address, str]: ... +def get_address_list(value: str) -> tuple[AddressList, str]: ... if sys.version_info >= (3, 8): - def get_no_fold_literal(value: str) -> Tuple[NoFoldLiteral, str]: ... - def get_msg_id(value: str) -> Tuple[MsgID, str]: ... + def get_no_fold_literal(value: str) -> tuple[NoFoldLiteral, str]: ... + def get_msg_id(value: str) -> tuple[MsgID, str]: ... def parse_message_id(value: str) -> MessageID: ... def parse_mime_version(value: str) -> MIMEVersion: ... -def get_invalid_parameter(value: str) -> Tuple[InvalidParameter, str]: ... -def get_ttext(value: str) -> Tuple[ValueTerminal, str]: ... -def get_token(value: str) -> Tuple[Token, str]: ... -def get_attrtext(value: str) -> Tuple[ValueTerminal, str]: ... -def get_attribute(value: str) -> Tuple[Attribute, str]: ... -def get_extended_attrtext(value: str) -> Tuple[ValueTerminal, str]: ... -def get_extended_attribute(value: str) -> Tuple[Attribute, str]: ... -def get_section(value: str) -> Tuple[Section, str]: ... -def get_value(value: str) -> Tuple[Value, str]: ... -def get_parameter(value: str) -> Tuple[Parameter, str]: ... +def get_invalid_parameter(value: str) -> tuple[InvalidParameter, str]: ... +def get_ttext(value: str) -> tuple[ValueTerminal, str]: ... +def get_token(value: str) -> tuple[Token, str]: ... +def get_attrtext(value: str) -> tuple[ValueTerminal, str]: ... +def get_attribute(value: str) -> tuple[Attribute, str]: ... +def get_extended_attrtext(value: str) -> tuple[ValueTerminal, str]: ... +def get_extended_attribute(value: str) -> tuple[Attribute, str]: ... +def get_section(value: str) -> tuple[Section, str]: ... +def get_value(value: str) -> tuple[Value, str]: ... +def get_parameter(value: str) -> tuple[Parameter, str]: ... def parse_mime_parameters(value: str) -> MimeParameters: ... def parse_content_type_header(value: str) -> ContentType: ... def parse_content_disposition_header(value: str) -> ContentDisposition: ... diff --git a/mypy/typeshed/stdlib/email/header.pyi b/mypy/typeshed/stdlib/email/header.pyi index 0d7691a622cb..4bebd50c45e4 100644 --- a/mypy/typeshed/stdlib/email/header.pyi +++ b/mypy/typeshed/stdlib/email/header.pyi @@ -1,5 +1,5 @@ from email.charset import Charset -from typing import Any, Tuple +from typing import Any class Header: def __init__( @@ -17,9 +17,9 @@ class Header: def __eq__(self, other: Any) -> bool: ... def __ne__(self, other: Any) -> bool: ... -def decode_header(header: Header | str) -> list[Tuple[bytes, str | None]]: ... +def decode_header(header: Header | str) -> list[tuple[bytes, str | None]]: ... def make_header( - decoded_seq: list[Tuple[bytes, str | None]], + decoded_seq: list[tuple[bytes, str | None]], maxlinelen: int | None = ..., header_name: str | None = ..., continuation_ws: str = ..., diff --git a/mypy/typeshed/stdlib/email/message.pyi b/mypy/typeshed/stdlib/email/message.pyi index 9ad8c1852199..a1749a4cfc2e 100644 --- a/mypy/typeshed/stdlib/email/message.pyi +++ b/mypy/typeshed/stdlib/email/message.pyi @@ -34,7 +34,7 @@ class Message: def __delitem__(self, name: str) -> None: ... def keys(self) -> list[str]: ... def values(self) -> list[_HeaderType]: ... - def items(self) -> list[Tuple[str, _HeaderType]]: ... + def items(self) -> list[tuple[str, _HeaderType]]: ... def get(self, name: str, failobj: _T = ...) -> _HeaderType | _T: ... def get_all(self, name: str, failobj: _T = ...) -> list[_HeaderType] | _T: ... def add_header(self, _name: str, _value: str, **_params: _ParamsType) -> None: ... @@ -44,7 +44,7 @@ class Message: def get_content_subtype(self) -> str: ... def get_default_type(self) -> str: ... def set_default_type(self, ctype: str) -> None: ... - def get_params(self, failobj: _T = ..., header: str = ..., unquote: bool = ...) -> list[Tuple[str, str]] | _T: ... + def get_params(self, failobj: _T = ..., header: str = ..., unquote: bool = ...) -> list[tuple[str, str]] | _T: ... def get_param(self, param: str, failobj: _T = ..., header: str = ..., unquote: bool = ...) -> _T | _ParamType: ... def del_param(self, param: str, header: str = ..., requote: bool = ...) -> None: ... def set_type(self, type: str, header: str = ..., requote: bool = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/email/policy.pyi b/mypy/typeshed/stdlib/email/policy.pyi index 625e6a5dcdbc..72a54bcfbf08 100644 --- a/mypy/typeshed/stdlib/email/policy.pyi +++ b/mypy/typeshed/stdlib/email/policy.pyi @@ -3,7 +3,7 @@ from email.contentmanager import ContentManager from email.errors import MessageDefect from email.header import Header from email.message import Message -from typing import Any, Callable, Tuple +from typing import Any, Callable class Policy: max_line_length: int | None @@ -17,9 +17,9 @@ class Policy: def register_defect(self, obj: Message, defect: MessageDefect) -> None: ... def header_max_count(self, name: str) -> int | None: ... @abstractmethod - def header_source_parse(self, sourcelines: list[str]) -> Tuple[str, str]: ... + def header_source_parse(self, sourcelines: list[str]) -> tuple[str, str]: ... @abstractmethod - def header_store_parse(self, name: str, value: str) -> Tuple[str, str]: ... + def header_store_parse(self, name: str, value: str) -> tuple[str, str]: ... @abstractmethod def header_fetch_parse(self, name: str, value: str) -> str: ... @abstractmethod @@ -28,8 +28,8 @@ class Policy: def fold_binary(self, name: str, value: str) -> bytes: ... class Compat32(Policy): - 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_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 def fold(self, name: str, value: str) -> str: ... def fold_binary(self, name: str, value: str) -> bytes: ... @@ -41,8 +41,8 @@ class EmailPolicy(Policy): refold_source: str header_factory: Callable[[str, str], str] content_manager: ContentManager - 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_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: ... def fold(self, name: str, value: str) -> str: ... def fold_binary(self, name: str, value: str) -> bytes: ... diff --git a/mypy/typeshed/stdlib/email/utils.pyi b/mypy/typeshed/stdlib/email/utils.pyi index 96d75a63ab12..3c07e98079fc 100644 --- a/mypy/typeshed/stdlib/email/utils.pyi +++ b/mypy/typeshed/stdlib/email/utils.pyi @@ -8,13 +8,13 @@ _PDTZ = Tuple[int, int, int, int, int, int, int, int, int, Optional[int]] def quote(str: str) -> str: ... def unquote(str: str) -> str: ... -def parseaddr(addr: str | None) -> Tuple[str, str]: ... -def formataddr(pair: Tuple[str | None, str], charset: str | Charset = ...) -> str: ... -def getaddresses(fieldvalues: list[str]) -> list[Tuple[str, str]]: ... +def parseaddr(addr: str | None) -> tuple[str, str]: ... +def formataddr(pair: tuple[str | None, str], charset: str | Charset = ...) -> str: ... +def getaddresses(fieldvalues: list[str]) -> list[tuple[str, str]]: ... @overload def parsedate(data: None) -> None: ... @overload -def parsedate(data: str) -> Tuple[int, int, int, int, int, int, int, int, int] | None: ... +def parsedate(data: str) -> tuple[int, int, int, int, int, int, int, int, int] | None: ... @overload def parsedate_tz(data: None) -> None: ... @overload @@ -34,7 +34,7 @@ def formatdate(timeval: float | None = ..., localtime: bool = ..., usegmt: bool def format_datetime(dt: datetime.datetime, usegmt: bool = ...) -> str: ... def localtime(dt: datetime.datetime | None = ..., isdst: int = ...) -> datetime.datetime: ... def make_msgid(idstring: str | None = ..., domain: str | None = ...) -> str: ... -def decode_rfc2231(s: str) -> Tuple[str | None, str | None, str]: ... +def decode_rfc2231(s: str) -> tuple[str | None, str | None, str]: ... def encode_rfc2231(s: str, charset: str | None = ..., language: str | None = ...) -> str: ... def collapse_rfc2231_value(value: _ParamType, errors: str = ..., fallback_charset: str = ...) -> str: ... -def decode_params(params: list[Tuple[str, str]]) -> list[Tuple[str, _ParamType]]: ... +def decode_params(params: list[tuple[str, str]]) -> list[tuple[str, _ParamType]]: ... diff --git a/mypy/typeshed/stdlib/encodings/utf_8.pyi b/mypy/typeshed/stdlib/encodings/utf_8.pyi index 892f2f082af0..568fa6013373 100644 --- a/mypy/typeshed/stdlib/encodings/utf_8.pyi +++ b/mypy/typeshed/stdlib/encodings/utf_8.pyi @@ -1,21 +1,20 @@ import codecs -from typing import Tuple class IncrementalEncoder(codecs.IncrementalEncoder): def encode(self, input: str, final: bool = ...) -> bytes: ... class IncrementalDecoder(codecs.BufferedIncrementalDecoder): @staticmethod - def _buffer_decode(__data: bytes, __errors: str | None = ..., __final: bool = ...) -> Tuple[str, int]: ... + def _buffer_decode(__data: bytes, __errors: str | None = ..., __final: bool = ...) -> tuple[str, int]: ... class StreamWriter(codecs.StreamWriter): @staticmethod - def encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... + def encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... class StreamReader(codecs.StreamReader): @staticmethod - def decode(__data: bytes, __errors: str | None = ..., __final: bool = ...) -> Tuple[str, int]: ... + def decode(__data: bytes, __errors: str | None = ..., __final: bool = ...) -> tuple[str, int]: ... def getregentry() -> codecs.CodecInfo: ... -def encode(__str: str, __errors: str | None = ...) -> Tuple[bytes, int]: ... -def decode(input: bytes, errors: str | None = ...) -> Tuple[str, int]: ... +def encode(__str: str, __errors: str | None = ...) -> tuple[bytes, int]: ... +def decode(input: bytes, errors: str | None = ...) -> tuple[str, int]: ... diff --git a/mypy/typeshed/stdlib/enum.pyi b/mypy/typeshed/stdlib/enum.pyi index 426bda857193..07fea104cec7 100644 --- a/mypy/typeshed/stdlib/enum.pyi +++ b/mypy/typeshed/stdlib/enum.pyi @@ -75,9 +75,9 @@ class IntFlag(int, Flag): def __or__(self: _T, other: int | _T) -> _T: ... def __and__(self: _T, other: int | _T) -> _T: ... def __xor__(self: _T, other: int | _T) -> _T: ... - __ror__ = __or__ - __rand__ = __and__ - __rxor__ = __xor__ + def __ror__(self: _T, n: int | _T) -> _T: ... + def __rand__(self: _T, n: int | _T) -> _T: ... + def __rxor__(self: _T, n: int | _T) -> _T: ... if sys.version_info >= (3, 11): class StrEnum(str, Enum): diff --git a/mypy/typeshed/stdlib/fcntl.pyi b/mypy/typeshed/stdlib/fcntl.pyi index ebaa31749528..141f9ee9360a 100644 --- a/mypy/typeshed/stdlib/fcntl.pyi +++ b/mypy/typeshed/stdlib/fcntl.pyi @@ -1,7 +1,6 @@ import sys -from _typeshed import FileDescriptorLike -from array import array -from typing import Any, Union, overload +from _typeshed import FileDescriptorLike, ReadOnlyBuffer, WriteableBuffer +from typing import Any, overload from typing_extensions import Literal FASYNC: int @@ -85,17 +84,13 @@ LOCK_WRITE: int def fcntl(__fd: FileDescriptorLike, __cmd: int, __arg: int = ...) -> int: ... @overload def fcntl(__fd: FileDescriptorLike, __cmd: int, __arg: bytes) -> bytes: ... - -_ReadOnlyBuffer = bytes -_WritableBuffer = Union[bytearray, memoryview, array[Any]] - @overload def ioctl(__fd: FileDescriptorLike, __request: int, __arg: int = ..., __mutate_flag: bool = ...) -> int: ... @overload -def ioctl(__fd: FileDescriptorLike, __request: int, __arg: _WritableBuffer, __mutate_flag: Literal[True] = ...) -> int: ... +def ioctl(__fd: FileDescriptorLike, __request: int, __arg: WriteableBuffer, __mutate_flag: Literal[True] = ...) -> int: ... @overload -def ioctl(__fd: FileDescriptorLike, __request: int, __arg: _WritableBuffer, __mutate_flag: Literal[False]) -> bytes: ... +def ioctl(__fd: FileDescriptorLike, __request: int, __arg: WriteableBuffer, __mutate_flag: Literal[False]) -> bytes: ... @overload -def ioctl(__fd: FileDescriptorLike, __request: int, __arg: _ReadOnlyBuffer, __mutate_flag: bool = ...) -> bytes: ... +def ioctl(__fd: FileDescriptorLike, __request: int, __arg: ReadOnlyBuffer, __mutate_flag: bool = ...) -> bytes: ... def flock(__fd: FileDescriptorLike, __operation: int) -> None: ... def lockf(__fd: FileDescriptorLike, __cmd: int, __len: int = ..., __start: int = ..., __whence: int = ...) -> Any: ... diff --git a/mypy/typeshed/stdlib/filecmp.pyi b/mypy/typeshed/stdlib/filecmp.pyi index 0cc92ed9e3ed..1c3d0a142a33 100644 --- a/mypy/typeshed/stdlib/filecmp.pyi +++ b/mypy/typeshed/stdlib/filecmp.pyi @@ -1,7 +1,7 @@ import sys from _typeshed import StrOrBytesPath from os import PathLike -from typing import Any, AnyStr, Callable, Generic, Iterable, Sequence, Tuple +from typing import Any, AnyStr, Callable, Generic, Iterable, Sequence if sys.version_info >= (3, 9): from types import GenericAlias @@ -11,7 +11,7 @@ DEFAULT_IGNORES: list[str] def cmp(f1: StrOrBytesPath, f2: StrOrBytesPath, shallow: int | bool = ...) -> bool: ... def cmpfiles( a: AnyStr | PathLike[AnyStr], b: AnyStr | PathLike[AnyStr], common: Iterable[AnyStr], shallow: int | bool = ... -) -> Tuple[list[AnyStr], list[AnyStr], list[AnyStr]]: ... +) -> tuple[list[AnyStr], list[AnyStr], list[AnyStr]]: ... class dircmp(Generic[AnyStr]): def __init__( diff --git a/mypy/typeshed/stdlib/fractions.pyi b/mypy/typeshed/stdlib/fractions.pyi index a5d2e21e9a29..3c6808651275 100644 --- a/mypy/typeshed/stdlib/fractions.pyi +++ b/mypy/typeshed/stdlib/fractions.pyi @@ -1,7 +1,7 @@ import sys from decimal import Decimal from numbers import Integral, Rational, Real -from typing import Tuple, Type, TypeVar, Union, overload +from typing import Type, TypeVar, Union, overload from typing_extensions import Literal _ComparableNum = Union[int, float, Decimal, Real] @@ -30,7 +30,7 @@ class Fraction(Rational): def from_decimal(cls, dec: Decimal) -> Fraction: ... def limit_denominator(self, max_denominator: int = ...) -> Fraction: ... if sys.version_info >= (3, 8): - def as_integer_ratio(self) -> Tuple[int, int]: ... + def as_integer_ratio(self) -> tuple[int, int]: ... @property def numerator(self) -> int: ... @property @@ -100,13 +100,13 @@ class Fraction(Rational): @overload def __rmod__(self, other: float) -> float: ... @overload - def __divmod__(self, other: int | Fraction) -> Tuple[int, Fraction]: ... + def __divmod__(self, other: int | Fraction) -> tuple[int, Fraction]: ... @overload - def __divmod__(self, other: float) -> Tuple[float, Fraction]: ... + def __divmod__(self, other: float) -> tuple[float, Fraction]: ... @overload - def __rdivmod__(self, other: int | Fraction) -> Tuple[int, Fraction]: ... + def __rdivmod__(self, other: int | Fraction) -> tuple[int, Fraction]: ... @overload - def __rdivmod__(self, other: float) -> Tuple[float, Fraction]: ... + def __rdivmod__(self, other: float) -> tuple[float, Fraction]: ... @overload def __pow__(self, other: int) -> Fraction: ... @overload diff --git a/mypy/typeshed/stdlib/ftplib.pyi b/mypy/typeshed/stdlib/ftplib.pyi index 4275888f5fc6..3f4f892bb516 100644 --- a/mypy/typeshed/stdlib/ftplib.pyi +++ b/mypy/typeshed/stdlib/ftplib.pyi @@ -1,3 +1,4 @@ +import sys from _typeshed import Self, SupportsRead, SupportsReadline from socket import socket from ssl import SSLContext @@ -32,22 +33,39 @@ class FTP: lastresp: str file: TextIO | None encoding: str + + # The following variable is intentionally left undocumented. + # See https://bugs.python.org/issue43285 for relevant discussion + # trust_server_pasv_ipv4_address: bool def __enter__(self: Self) -> Self: ... def __exit__( self, exc_type: Type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None ) -> None: ... - source_address: Tuple[str, int] | None - def __init__( - self, - host: str = ..., - user: str = ..., - passwd: str = ..., - acct: str = ..., - timeout: float = ..., - source_address: Tuple[str, int] | None = ..., - ) -> None: ... + source_address: tuple[str, int] | None + if sys.version_info >= (3, 9): + def __init__( + self, + host: str = ..., + user: str = ..., + passwd: str = ..., + acct: str = ..., + timeout: float = ..., + source_address: tuple[str, int] | None = ..., + *, + encoding: str = ..., + ) -> None: ... + else: + def __init__( + self, + host: str = ..., + user: str = ..., + passwd: str = ..., + acct: str = ..., + timeout: float = ..., + source_address: tuple[str, int] | None = ..., + ) -> None: ... def connect( - self, host: str = ..., port: int = ..., timeout: float = ..., source_address: Tuple[str, int] | None = ... + self, host: str = ..., port: int = ..., timeout: float = ..., source_address: tuple[str, int] | None = ... ) -> str: ... def getwelcome(self) -> str: ... def set_debuglevel(self, level: int) -> None: ... @@ -66,10 +84,10 @@ class FTP: def sendport(self, host: str, port: int) -> str: ... def sendeprt(self, host: str, port: int) -> str: ... def makeport(self) -> socket: ... - def makepasv(self) -> Tuple[str, int]: ... + def makepasv(self) -> tuple[str, int]: ... def login(self, user: str = ..., passwd: str = ..., acct: str = ...) -> str: ... # In practice, `rest` rest can actually be anything whose str() is an integer sequence, so to make it simple we allow integers. - def ntransfercmd(self, cmd: str, rest: int | str | None = ...) -> Tuple[socket, int]: ... + def ntransfercmd(self, cmd: str, rest: int | str | None = ...) -> tuple[socket, int]: ... def transfercmd(self, cmd: str, rest: int | str | None = ...) -> socket: ... def retrbinary( self, cmd: str, callback: Callable[[bytes], Any], blocksize: int = ..., rest: int | str | None = ... @@ -88,7 +106,7 @@ class FTP: def nlst(self, *args: str) -> list[str]: ... # Technically only the last arg can be a Callable but ... def dir(self, *args: str | Callable[[str], None]) -> None: ... - def mlsd(self, path: str = ..., facts: Iterable[str] = ...) -> Iterator[Tuple[str, dict[str, str]]]: ... + def mlsd(self, path: str = ..., facts: Iterable[str] = ...) -> Iterator[tuple[str, dict[str, str]]]: ... def rename(self, fromname: str, toname: str) -> str: ... def delete(self, filename: str) -> str: ... def cwd(self, dirname: str) -> str: ... @@ -100,18 +118,34 @@ class FTP: def close(self) -> None: ... class FTP_TLS(FTP): - def __init__( - self, - host: str = ..., - user: str = ..., - passwd: str = ..., - acct: str = ..., - keyfile: str | None = ..., - certfile: str | None = ..., - context: SSLContext | None = ..., - timeout: float = ..., - source_address: Tuple[str, int] | None = ..., - ) -> None: ... + if sys.version_info >= (3, 9): + def __init__( + self, + host: str = ..., + user: str = ..., + passwd: str = ..., + acct: str = ..., + keyfile: str | None = ..., + certfile: str | None = ..., + context: SSLContext | None = ..., + timeout: float = ..., + source_address: tuple[str, int] | None = ..., + *, + encoding: str = ..., + ) -> None: ... + else: + def __init__( + self, + host: str = ..., + user: str = ..., + passwd: str = ..., + acct: str = ..., + keyfile: str | None = ..., + certfile: str | None = ..., + context: SSLContext | None = ..., + timeout: float = ..., + source_address: tuple[str, int] | None = ..., + ) -> None: ... ssl_version: int keyfile: str | None certfile: str | None @@ -123,8 +157,8 @@ class FTP_TLS(FTP): def ccc(self) -> str: ... def parse150(resp: str) -> int | None: ... # undocumented -def parse227(resp: str) -> Tuple[str, int]: ... # undocumented -def parse229(resp: str, peer: Any) -> Tuple[str, int]: ... # undocumented +def parse227(resp: str) -> tuple[str, int]: ... # undocumented +def parse229(resp: str, peer: Any) -> tuple[str, int]: ... # undocumented def parse257(resp: str) -> str: ... # undocumented def ftpcp( source: FTP, sourcename: str, target: FTP, targetname: str = ..., type: Literal["A", "I"] = ... diff --git a/mypy/typeshed/stdlib/functools.pyi b/mypy/typeshed/stdlib/functools.pyi index 6fe4bb6f8e9e..b5e52bf59920 100644 --- a/mypy/typeshed/stdlib/functools.pyi +++ b/mypy/typeshed/stdlib/functools.pyi @@ -1,7 +1,8 @@ import sys import types from _typeshed import SupportsItems, SupportsLessThan -from typing import Any, Callable, Generic, Hashable, Iterable, NamedTuple, Sequence, Set, Sized, Tuple, Type, TypeVar, overload +from typing import Any, Callable, Generic, Hashable, Iterable, NamedTuple, Sequence, Sized, Tuple, Type, TypeVar, overload +from typing_extensions import final if sys.version_info >= (3, 9): from types import GenericAlias @@ -22,6 +23,7 @@ class _CacheInfo(NamedTuple): maxsize: int currsize: int +@final class _lru_cache_wrapper(Generic[_T]): __wrapped__: Callable[..., _T] def __call__(self, *args: Hashable, **kwargs: Hashable) -> _T: ... @@ -122,7 +124,7 @@ def _make_key( kwds: SupportsItems[Any, Any], typed: bool, kwd_mark: Tuple[object, ...] = ..., - fasttypes: Set[type] = ..., + fasttypes: set[type] = ..., tuple: type = ..., type: Any = ..., len: Callable[[Sized], int] = ..., diff --git a/mypy/typeshed/stdlib/gc.pyi b/mypy/typeshed/stdlib/gc.pyi index 6eea01848939..39d2776783ef 100644 --- a/mypy/typeshed/stdlib/gc.pyi +++ b/mypy/typeshed/stdlib/gc.pyi @@ -1,5 +1,5 @@ import sys -from typing import Any, Tuple +from typing import Any DEBUG_COLLECTABLE: int DEBUG_LEAK: int @@ -12,7 +12,7 @@ garbage: list[Any] def collect(generation: int = ...) -> int: ... def disable() -> None: ... def enable() -> None: ... -def get_count() -> Tuple[int, int, int]: ... +def get_count() -> tuple[int, int, int]: ... def get_debug() -> int: ... if sys.version_info >= (3, 8): @@ -29,7 +29,7 @@ if sys.version_info >= (3, 7): def get_referents(*objs: Any) -> list[Any]: ... def get_referrers(*objs: Any) -> list[Any]: ... def get_stats() -> list[dict[str, Any]]: ... -def get_threshold() -> Tuple[int, int, int]: ... +def get_threshold() -> tuple[int, int, int]: ... def is_tracked(__obj: Any) -> bool: ... if sys.version_info >= (3, 9): diff --git a/mypy/typeshed/stdlib/genericpath.pyi b/mypy/typeshed/stdlib/genericpath.pyi index 1c7be922e941..56683e323178 100644 --- a/mypy/typeshed/stdlib/genericpath.pyi +++ b/mypy/typeshed/stdlib/genericpath.pyi @@ -14,16 +14,16 @@ def commonprefix(m: Sequence[BytesPath]) -> bytes | Literal[""]: ... def commonprefix(m: Sequence[list[SupportsLessThanT]]) -> Sequence[SupportsLessThanT]: ... @overload def commonprefix(m: Sequence[Tuple[SupportsLessThanT, ...]]) -> Sequence[SupportsLessThanT]: ... -def exists(path: StrOrBytesPath) -> bool: ... -def getsize(filename: StrOrBytesPath) -> int: ... -def isfile(path: StrOrBytesPath) -> bool: ... -def isdir(s: StrOrBytesPath) -> bool: ... +def exists(path: StrOrBytesPath | int) -> bool: ... +def getsize(filename: StrOrBytesPath | int) -> int: ... +def isfile(path: StrOrBytesPath | int) -> bool: ... +def isdir(s: StrOrBytesPath | int) -> bool: ... # These return float if os.stat_float_times() == True, # but int is a subclass of float. -def getatime(filename: StrOrBytesPath) -> float: ... -def getmtime(filename: StrOrBytesPath) -> float: ... -def getctime(filename: StrOrBytesPath) -> float: ... -def samefile(f1: StrOrBytesPath, f2: StrOrBytesPath) -> bool: ... +def getatime(filename: StrOrBytesPath | int) -> float: ... +def getmtime(filename: StrOrBytesPath | int) -> float: ... +def getctime(filename: StrOrBytesPath | int) -> float: ... +def samefile(f1: StrOrBytesPath | int, f2: StrOrBytesPath | int) -> bool: ... def sameopenfile(fp1: int, fp2: int) -> bool: ... def samestat(s1: os.stat_result, s2: os.stat_result) -> bool: ... diff --git a/mypy/typeshed/stdlib/html/parser.pyi b/mypy/typeshed/stdlib/html/parser.pyi index 1cdaf72ff561..fec3f3509522 100644 --- a/mypy/typeshed/stdlib/html/parser.pyi +++ b/mypy/typeshed/stdlib/html/parser.pyi @@ -6,11 +6,11 @@ class HTMLParser(ParserBase): def feed(self, data: str) -> None: ... def close(self) -> None: ... def reset(self) -> None: ... - def getpos(self) -> Tuple[int, int]: ... + def getpos(self) -> tuple[int, int]: ... def get_starttag_text(self) -> str | None: ... - def handle_starttag(self, tag: str, attrs: list[Tuple[str, str | None]]) -> None: ... + def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None: ... def handle_endtag(self, tag: str) -> None: ... - def handle_startendtag(self, tag: str, attrs: list[Tuple[str, str | None]]) -> None: ... + def handle_startendtag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None: ... def handle_data(self, data: str) -> None: ... def handle_entityref(self, name: str) -> None: ... def handle_charref(self, name: str) -> None: ... diff --git a/mypy/typeshed/stdlib/http/client.pyi b/mypy/typeshed/stdlib/http/client.pyi index 508191556f37..c450db587135 100644 --- a/mypy/typeshed/stdlib/http/client.pyi +++ b/mypy/typeshed/stdlib/http/client.pyi @@ -5,7 +5,7 @@ import sys import types from _typeshed import Self, WriteableBuffer from socket import socket -from typing import IO, Any, BinaryIO, Callable, Iterable, Iterator, Mapping, Protocol, Tuple, Type, TypeVar, Union, overload +from typing import IO, Any, BinaryIO, Callable, Iterable, Iterator, Mapping, Protocol, Type, TypeVar, Union, overload _DataType = Union[bytes, IO[Any], Iterable[bytes], str] _T = TypeVar("_T") @@ -83,9 +83,14 @@ class HTTPResponse(io.BufferedIOBase, BinaryIO): headers: HTTPMessage version: int debuglevel: int + fp: io.BufferedReader closed: bool status: int reason: str + chunked: bool + chunk_left: int | None + length: int | None + will_close: bool def __init__(self, sock: socket, debuglevel: int = ..., method: str | None = ..., url: str | None = ...) -> None: ... def peek(self, n: int = ...) -> bytes: ... def read(self, amt: int | None = ...) -> bytes: ... @@ -96,7 +101,7 @@ class HTTPResponse(io.BufferedIOBase, BinaryIO): def getheader(self, name: str) -> str | None: ... @overload def getheader(self, name: str, default: _T) -> str | _T: ... - def getheaders(self) -> list[Tuple[str, str]]: ... + def getheaders(self) -> list[tuple[str, str]]: ... def fileno(self) -> int: ... def isclosed(self) -> bool: ... def __iter__(self) -> Iterator[bytes]: ... @@ -118,12 +123,12 @@ class _HTTPConnectionProtocol(Protocol): host: str, port: int | None = ..., timeout: float = ..., - source_address: Tuple[str, int] | None = ..., + source_address: tuple[str, int] | None = ..., blocksize: int = ..., ) -> HTTPConnection: ... else: def __call__( - self, host: str, port: int | None = ..., timeout: float = ..., source_address: Tuple[str, int] | None = ... + self, host: str, port: int | None = ..., timeout: float = ..., source_address: tuple[str, int] | None = ... ) -> HTTPConnection: ... class HTTPConnection: @@ -141,12 +146,12 @@ class HTTPConnection: host: str, port: int | None = ..., timeout: float | None = ..., - source_address: Tuple[str, int] | None = ..., + source_address: tuple[str, int] | None = ..., blocksize: int = ..., ) -> None: ... else: def __init__( - self, host: str, port: int | None = ..., timeout: float | None = ..., source_address: Tuple[str, int] | None = ... + self, host: str, port: int | None = ..., timeout: float | None = ..., source_address: tuple[str, int] | None = ... ) -> None: ... def request( self, method: str, url: str, body: _DataType | None = ..., headers: Mapping[str, str] = ..., *, encode_chunked: bool = ... @@ -170,7 +175,7 @@ class HTTPSConnection(HTTPConnection): key_file: str | None = ..., cert_file: str | None = ..., timeout: float | None = ..., - source_address: Tuple[str, int] | None = ..., + source_address: tuple[str, int] | None = ..., *, context: ssl.SSLContext | None = ..., check_hostname: bool | None = ..., @@ -184,7 +189,7 @@ class HTTPSConnection(HTTPConnection): key_file: str | None = ..., cert_file: str | None = ..., timeout: float | None = ..., - source_address: Tuple[str, int] | None = ..., + source_address: tuple[str, int] | None = ..., *, context: ssl.SSLContext | None = ..., check_hostname: bool | None = ..., diff --git a/mypy/typeshed/stdlib/http/cookies.pyi b/mypy/typeshed/stdlib/http/cookies.pyi index 5a88121f5070..7e9513adb1a1 100644 --- a/mypy/typeshed/stdlib/http/cookies.pyi +++ b/mypy/typeshed/stdlib/http/cookies.pyi @@ -1,5 +1,5 @@ import sys -from typing import Any, Dict, Generic, Iterable, Mapping, Tuple, TypeVar, Union, overload +from typing import Any, Dict, Generic, Iterable, Mapping, TypeVar, Union, overload if sys.version_info >= (3, 9): from types import GenericAlias @@ -32,7 +32,7 @@ class Morsel(Dict[str, Any], Generic[_T]): @overload # type: ignore def update(self, values: Mapping[str, str]) -> None: ... @overload - def update(self, values: Iterable[Tuple[str, str]]) -> None: ... + def update(self, values: Iterable[tuple[str, str]]) -> None: ... def isReservedKey(self, K: str) -> bool: ... def output(self, attrs: list[str] | None = ..., header: str = ...) -> str: ... def js_output(self, attrs: list[str] | None = ...) -> str: ... diff --git a/mypy/typeshed/stdlib/http/server.pyi b/mypy/typeshed/stdlib/http/server.pyi index 92350b23a95f..e3d0a8c318f4 100644 --- a/mypy/typeshed/stdlib/http/server.pyi +++ b/mypy/typeshed/stdlib/http/server.pyi @@ -3,7 +3,7 @@ import io import socketserver import sys from _typeshed import StrPath, SupportsRead, SupportsWrite -from typing import Any, AnyStr, BinaryIO, ClassVar, Mapping, Sequence, Tuple +from typing import Any, AnyStr, BinaryIO, ClassVar, Mapping, Sequence class HTTPServer(socketserver.TCPServer): server_name: str @@ -14,7 +14,7 @@ if sys.version_info >= (3, 7): daemon_threads: bool # undocumented class BaseHTTPRequestHandler(socketserver.StreamRequestHandler): - client_address: Tuple[str, int] + client_address: tuple[str, int] server: socketserver.BaseServer close_connection: bool requestline: str @@ -28,11 +28,11 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler): error_content_type: str protocol_version: str MessageClass: type - responses: Mapping[int, Tuple[str, str]] + responses: Mapping[int, tuple[str, str]] default_request_version: str # undocumented weekdayname: ClassVar[Sequence[str]] # undocumented monthname: ClassVar[Sequence[str | None]] # undocumented - def __init__(self, request: bytes, client_address: Tuple[str, int], server: socketserver.BaseServer) -> None: ... + def __init__(self, request: bytes, client_address: tuple[str, int], server: socketserver.BaseServer) -> None: ... def handle(self) -> None: ... def handle_one_request(self) -> None: ... def handle_expect_100(self) -> bool: ... @@ -56,10 +56,10 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler): extensions_map: dict[str, str] if sys.version_info >= (3, 7): def __init__( - self, request: bytes, client_address: Tuple[str, int], server: socketserver.BaseServer, directory: str | None = ... + self, request: bytes, client_address: tuple[str, int], server: socketserver.BaseServer, directory: str | None = ... ) -> None: ... else: - def __init__(self, request: bytes, client_address: Tuple[str, int], server: socketserver.BaseServer) -> None: ... + def __init__(self, request: bytes, client_address: tuple[str, int], server: socketserver.BaseServer) -> None: ... def do_GET(self) -> None: ... def do_HEAD(self) -> None: ... def send_head(self) -> io.BytesIO | BinaryIO | None: ... # undocumented diff --git a/mypy/typeshed/stdlib/imaplib.pyi b/mypy/typeshed/stdlib/imaplib.pyi index 63c57a4d4623..a9f19048c9ae 100644 --- a/mypy/typeshed/stdlib/imaplib.pyi +++ b/mypy/typeshed/stdlib/imaplib.pyi @@ -14,6 +14,8 @@ _CommandResults = Tuple[str, List[Any]] _AnyResponseData = Union[List[None], List[Union[bytes, Tuple[bytes, bytes]]]] +_list = list # conflicts with a method named "list" + class IMAP4: error: Type[Exception] abort: Type[Exception] @@ -22,15 +24,15 @@ class IMAP4: debug: int state: str literal: str | None - tagged_commands: dict[bytes, List[bytes] | None] - untagged_responses: dict[str, List[bytes | Tuple[bytes, bytes]]] + tagged_commands: dict[bytes, _list[bytes] | None] + untagged_responses: dict[str, _list[bytes | tuple[bytes, bytes]]] continuation_response: str is_readonly: bool tagnum: int tagpre: str tagre: Pattern[str] welcome: bytes - capabilities: Tuple[str] + capabilities: tuple[str] PROTOCOL_VERSION: str if sys.version_info >= (3, 9): def __init__(self, host: str = ..., port: int = ..., timeout: float | None = ...) -> None: ... @@ -51,7 +53,7 @@ class IMAP4: def recent(self) -> _CommandResults: ... def response(self, code: str) -> _CommandResults: ... def append(self, mailbox: str, flags: str, date_time: str, message: str) -> str: ... - def authenticate(self, mechanism: str, authobject: Callable[[bytes], bytes | None]) -> Tuple[str, str]: ... + def authenticate(self, mechanism: str, authobject: Callable[[bytes], bytes | None]) -> tuple[str, str]: ... def capability(self) -> _CommandResults: ... def check(self) -> _CommandResults: ... def close(self) -> _CommandResults: ... @@ -63,29 +65,29 @@ class IMAP4: def __enter__(self: Self) -> Self: ... def __exit__(self, t: Type[BaseException] | None, v: BaseException | None, tb: TracebackType | None) -> None: ... def expunge(self) -> _CommandResults: ... - def fetch(self, message_set: str, message_parts: str) -> Tuple[str, _AnyResponseData]: ... + def fetch(self, message_set: str, message_parts: str) -> tuple[str, _AnyResponseData]: ... def getacl(self, mailbox: str) -> _CommandResults: ... def getannotation(self, mailbox: str, entry: str, attribute: str) -> _CommandResults: ... def getquota(self, root: str) -> _CommandResults: ... def getquotaroot(self, mailbox: str) -> _CommandResults: ... - def list(self, directory: str = ..., pattern: str = ...) -> Tuple[str, _AnyResponseData]: ... - def login(self, user: str, password: str) -> Tuple[Literal["OK"], List[bytes]]: ... + def list(self, directory: str = ..., pattern: str = ...) -> tuple[str, _AnyResponseData]: ... + def login(self, user: str, password: str) -> tuple[Literal["OK"], _list[bytes]]: ... def login_cram_md5(self, user: str, password: str) -> _CommandResults: ... - def logout(self) -> Tuple[str, _AnyResponseData]: ... + def logout(self) -> tuple[str, _AnyResponseData]: ... def lsub(self, directory: str = ..., pattern: str = ...) -> _CommandResults: ... def myrights(self, mailbox: str) -> _CommandResults: ... def namespace(self) -> _CommandResults: ... - def noop(self) -> Tuple[str, List[bytes]]: ... + def noop(self) -> tuple[str, _list[bytes]]: ... def partial(self, message_num: str, message_part: str, start: str, length: str) -> _CommandResults: ... def proxyauth(self, user: str) -> _CommandResults: ... def rename(self, oldmailbox: str, newmailbox: str) -> _CommandResults: ... def search(self, charset: str | None, *criteria: str) -> _CommandResults: ... - def select(self, mailbox: str = ..., readonly: bool = ...) -> Tuple[str, List[bytes | None]]: ... + def select(self, mailbox: str = ..., readonly: bool = ...) -> tuple[str, _list[bytes | None]]: ... def setacl(self, mailbox: str, who: str, what: str) -> _CommandResults: ... def setannotation(self, *args: str) -> _CommandResults: ... def setquota(self, root: str, limits: str) -> _CommandResults: ... def sort(self, sort_criteria: str, charset: str, *search_criteria: str) -> _CommandResults: ... - def starttls(self, ssl_context: Any | None = ...) -> Tuple[Literal["OK"], List[None]]: ... + def starttls(self, ssl_context: Any | None = ...) -> tuple[Literal["OK"], _list[None]]: ... def status(self, mailbox: str, names: str) -> _CommandResults: ... def store(self, message_set: str, command: str, flags: str) -> _CommandResults: ... def subscribe(self, mailbox: str) -> _CommandResults: ... @@ -163,5 +165,5 @@ class _Authenticator: def Internaldate2tuple(resp: str) -> time.struct_time: ... def Int2AP(num: int) -> str: ... -def ParseFlags(resp: str) -> Tuple[str]: ... +def ParseFlags(resp: str) -> tuple[str]: ... def Time2Internaldate(date_time: float | time.struct_time | str) -> str: ... diff --git a/mypy/typeshed/stdlib/imp.pyi b/mypy/typeshed/stdlib/imp.pyi index aac16f029424..88f2e789329b 100644 --- a/mypy/typeshed/stdlib/imp.pyi +++ b/mypy/typeshed/stdlib/imp.pyi @@ -1,7 +1,7 @@ import types from _typeshed import StrPath from os import PathLike -from typing import IO, Any, Protocol, Tuple, TypeVar +from typing import IO, Any, Protocol, TypeVar from _imp import ( acquire_lock as acquire_lock, @@ -33,7 +33,7 @@ def get_magic() -> bytes: ... def get_tag() -> str: ... def cache_from_source(path: StrPath, debug_override: bool | None = ...) -> str: ... def source_from_cache(path: StrPath) -> str: ... -def get_suffixes() -> list[Tuple[str, str, int]]: ... +def get_suffixes() -> list[tuple[str, str, int]]: ... class NullImporter: def __init__(self, path: StrPath) -> None: ... @@ -53,12 +53,12 @@ class _FileLike(Protocol): def load_source(name: str, pathname: str, file: _FileLike | None = ...) -> types.ModuleType: ... def load_compiled(name: str, pathname: str, file: _FileLike | None = ...) -> types.ModuleType: ... def load_package(name: str, path: StrPath) -> types.ModuleType: ... -def load_module(name: str, file: _FileLike | None, filename: str, details: Tuple[str, str, int]) -> types.ModuleType: ... +def load_module(name: str, file: _FileLike | None, filename: str, details: tuple[str, str, int]) -> types.ModuleType: ... # IO[Any] is a TextIOWrapper if name is a .py file, and a FileIO otherwise. def find_module( name: str, path: None | list[str] | list[PathLike[str]] | list[StrPath] = ... -) -> Tuple[IO[Any], str, Tuple[str, str, int]]: ... +) -> tuple[IO[Any], str, tuple[str, str, int]]: ... def reload(module: types.ModuleType) -> types.ModuleType: ... def init_builtin(name: str) -> types.ModuleType | None: ... def load_dynamic(name: str, path: str, file: Any = ...) -> types.ModuleType: ... # file argument is ignored diff --git a/mypy/typeshed/stdlib/importlib/__init__.pyi b/mypy/typeshed/stdlib/importlib/__init__.pyi index b7986de57a45..1b91cc55f2df 100644 --- a/mypy/typeshed/stdlib/importlib/__init__.pyi +++ b/mypy/typeshed/stdlib/importlib/__init__.pyi @@ -1,15 +1,18 @@ -import types from importlib.abc import Loader -from typing import Any, Mapping, Sequence +from types import ModuleType +from typing import Mapping, Sequence +# Signature of `builtins.__import__` should be kept identical to `importlib.__import__` def __import__( name: str, - globals: Mapping[str, Any] | None = ..., - locals: Mapping[str, Any] | None = ..., + globals: Mapping[str, object] | None = ..., + locals: Mapping[str, object] | None = ..., fromlist: Sequence[str] = ..., level: int = ..., -) -> types.ModuleType: ... -def import_module(name: str, package: str | None = ...) -> types.ModuleType: ... +) -> ModuleType: ... + +# `importlib.import_module` return type should be kept the same as `builtins.__import__` +def import_module(name: str, package: str | None = ...) -> ModuleType: ... def find_loader(name: str, path: str | None = ...) -> Loader | None: ... def invalidate_caches() -> None: ... -def reload(module: types.ModuleType) -> types.ModuleType: ... +def reload(module: ModuleType) -> ModuleType: ... diff --git a/mypy/typeshed/stdlib/importlib/abc.pyi b/mypy/typeshed/stdlib/importlib/abc.pyi index 69608c57cc4d..2e18f3f899a2 100644 --- a/mypy/typeshed/stdlib/importlib/abc.pyi +++ b/mypy/typeshed/stdlib/importlib/abc.pyi @@ -1,9 +1,18 @@ import sys import types -from _typeshed import StrOrBytesPath +from _typeshed import ( + OpenBinaryMode, + OpenBinaryModeReading, + OpenBinaryModeUpdating, + OpenBinaryModeWriting, + OpenTextMode, + StrOrBytesPath, + StrPath, +) from abc import ABCMeta, abstractmethod from importlib.machinery import ModuleSpec -from typing import IO, Any, Iterator, Mapping, Protocol, Sequence, Tuple, Union +from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper +from typing import IO, Any, BinaryIO, Iterator, Mapping, Protocol, Sequence, Union, overload from typing_extensions import Literal, runtime_checkable _Path = Union[bytes, str] @@ -46,7 +55,7 @@ class MetaPathFinder(Finder): class PathEntryFinder(Finder): def find_module(self, fullname: str) -> Loader | None: ... - def find_loader(self, fullname: str) -> Tuple[Loader | None, Sequence[_Path]]: ... + def find_loader(self, fullname: str) -> tuple[Loader | None, Sequence[_Path]]: ... def invalidate_caches(self) -> None: ... # Not defined on the actual class, but expected to exist. def find_spec(self, fullname: str, target: types.ModuleType | None = ...) -> ModuleSpec | None: ... @@ -84,22 +93,79 @@ if sys.version_info >= (3, 7): if sys.version_info >= (3, 9): @runtime_checkable class Traversable(Protocol): + @abstractmethod + def is_dir(self) -> bool: ... + @abstractmethod + def is_file(self) -> bool: ... @abstractmethod def iterdir(self) -> Iterator[Traversable]: ... @abstractmethod - def read_bytes(self) -> bytes: ... + def joinpath(self, child: StrPath) -> Traversable: ... + # The .open method comes from pathlib.pyi and should be kept in sync. + @overload @abstractmethod - def read_text(self, encoding: str | None = ...) -> str: ... + def open( + self, + mode: OpenTextMode = ..., + buffering: int = ..., + encoding: str | None = ..., + errors: str | None = ..., + newline: str | None = ..., + ) -> TextIOWrapper: ... + # Unbuffered binary mode: returns a FileIO + @overload @abstractmethod - def is_dir(self) -> bool: ... + def open( + self, mode: OpenBinaryMode, buffering: Literal[0], encoding: None = ..., errors: None = ..., newline: None = ... + ) -> FileIO: ... + # Buffering is on: return BufferedRandom, BufferedReader, or BufferedWriter + @overload @abstractmethod - def is_file(self) -> bool: ... + def open( + self, + mode: OpenBinaryModeUpdating, + buffering: Literal[-1, 1] = ..., + encoding: None = ..., + errors: None = ..., + newline: None = ..., + ) -> BufferedRandom: ... + @overload @abstractmethod - def joinpath(self, child: _Path) -> Traversable: ... + def open( + self, + mode: OpenBinaryModeWriting, + buffering: Literal[-1, 1] = ..., + encoding: None = ..., + errors: None = ..., + newline: None = ..., + ) -> BufferedWriter: ... + @overload @abstractmethod - def __truediv__(self, child: _Path) -> Traversable: ... + def open( + self, + mode: OpenBinaryModeReading, + buffering: Literal[-1, 1] = ..., + encoding: None = ..., + errors: None = ..., + newline: None = ..., + ) -> BufferedReader: ... + # Buffering cannot be determined: fall back to BinaryIO + @overload @abstractmethod - def open(self, mode: Literal["r", "rb"] = ..., *args: Any, **kwargs: Any) -> IO[Any]: ... - @property + def open( + self, mode: OpenBinaryMode, buffering: int, encoding: None = ..., errors: None = ..., newline: None = ... + ) -> BinaryIO: ... + # Fallback if mode is not specified + @overload @abstractmethod + def open( + self, mode: str, buffering: int = ..., encoding: str | None = ..., errors: str | None = ..., newline: str | None = ... + ) -> IO[Any]: ... + @property def name(self) -> str: ... + @abstractmethod + def __truediv__(self, key: StrPath) -> Traversable: ... + @abstractmethod + def read_bytes(self) -> bytes: ... + @abstractmethod + def read_text(self, encoding: str | None = ...) -> str: ... diff --git a/mypy/typeshed/stdlib/importlib/machinery.pyi b/mypy/typeshed/stdlib/importlib/machinery.pyi index a2e89bb2d8de..432bec901161 100644 --- a/mypy/typeshed/stdlib/importlib/machinery.pyi +++ b/mypy/typeshed/stdlib/importlib/machinery.pyi @@ -1,8 +1,7 @@ import importlib.abc import types -from typing import Any, Callable, Sequence, Tuple +from typing import Any, Callable, Sequence -# TODO: the loaders seem a bit backwards, attribute is protocol but __init__ arg isn't? class ModuleSpec: def __init__( self, @@ -14,7 +13,7 @@ class ModuleSpec: is_package: bool | None = ..., ) -> None: ... name: str - loader: importlib.abc._LoaderProtocol | None + loader: importlib.abc.Loader | None origin: str | None submodule_search_locations: list[str] | None loader_state: Any @@ -100,10 +99,10 @@ def all_suffixes() -> list[str]: ... class FileFinder(importlib.abc.PathEntryFinder): path: str - def __init__(self, path: str, *loader_details: Tuple[importlib.abc.Loader, list[str]]) -> None: ... + def __init__(self, path: str, *loader_details: tuple[importlib.abc.Loader, list[str]]) -> None: ... @classmethod def path_hook( - cls, *loader_details: Tuple[importlib.abc.Loader, list[str]] + cls, *loader_details: tuple[importlib.abc.Loader, list[str]] ) -> Callable[[str], importlib.abc.PathEntryFinder]: ... class SourceFileLoader(importlib.abc.FileLoader, importlib.abc.SourceLoader): @@ -115,3 +114,7 @@ class ExtensionFileLoader(importlib.abc.ExecutionLoader): def __init__(self, name: str, path: importlib.abc._Path) -> None: ... def get_filename(self, name: str | None = ...) -> importlib.abc._Path: ... def get_source(self, fullname: str) -> None: ... + def create_module(self, spec: ModuleSpec) -> types.ModuleType: ... + def exec_module(self, module: types.ModuleType) -> None: ... + def is_package(self, fullname: str) -> bool: ... + def get_code(self, fullname: str) -> None: ... diff --git a/mypy/typeshed/stdlib/importlib/resources.pyi b/mypy/typeshed/stdlib/importlib/resources.pyi index 075761abf9da..194c0bac2b6a 100644 --- a/mypy/typeshed/stdlib/importlib/resources.pyi +++ b/mypy/typeshed/stdlib/importlib/resources.pyi @@ -4,9 +4,10 @@ from typing import Any # This is a >=3.7 module, so we conditionally include its source. if sys.version_info >= (3, 7): import os + from contextlib import AbstractContextManager from pathlib import Path from types import ModuleType - from typing import BinaryIO, ContextManager, Iterator, TextIO, Union + from typing import BinaryIO, Iterator, TextIO, Union Package = Union[str, ModuleType] Resource = Union[str, os.PathLike[Any]] @@ -14,12 +15,11 @@ if sys.version_info >= (3, 7): def open_text(package: Package, resource: Resource, encoding: str = ..., errors: str = ...) -> TextIO: ... def read_binary(package: Package, resource: Resource) -> bytes: ... def read_text(package: Package, resource: Resource, encoding: str = ..., errors: str = ...) -> str: ... - def path(package: Package, resource: Resource) -> ContextManager[Path]: ... + def path(package: Package, resource: Resource) -> AbstractContextManager[Path]: ... def is_resource(package: Package, name: str) -> bool: ... def contents(package: Package) -> Iterator[str]: ... if sys.version_info >= (3, 9): - from contextlib import AbstractContextManager from importlib.abc import Traversable def files(package: Package) -> Traversable: ... def as_file(path: Traversable) -> AbstractContextManager[Path]: ... diff --git a/mypy/typeshed/stdlib/inspect.pyi b/mypy/typeshed/stdlib/inspect.pyi index 4b53b8745a98..88002cf205b1 100644 --- a/mypy/typeshed/stdlib/inspect.pyi +++ b/mypy/typeshed/stdlib/inspect.pyi @@ -3,20 +3,27 @@ import sys import types from _typeshed import Self from collections import OrderedDict -from collections.abc import Awaitable, Callable, Generator, Mapping, Sequence, Set +from collections.abc import Awaitable, Callable, Generator, Mapping, Sequence, Set as AbstractSet from types import ( AsyncGeneratorType, BuiltinFunctionType, + BuiltinMethodType, CodeType, CoroutineType, FrameType, FunctionType, GeneratorType, + GetSetDescriptorType, + LambdaType, MethodType, ModuleType, TracebackType, ) -from typing import Any, ClassVar, NamedTuple, Tuple, Type, Union + +if sys.version_info >= (3, 7): + from types import ClassMethodDescriptorType, WrapperDescriptorType, MemberDescriptorType, MethodDescriptorType + +from typing import Any, ClassVar, NamedTuple, Protocol, Tuple, Type, TypeVar, Union from typing_extensions import Literal, TypeGuard # @@ -32,7 +39,7 @@ class BlockFinder: indecorator: bool decoratorhasargs: bool last: int - def tokeneater(self, type: int, token: str, srowcol: Tuple[int, int], erowcol: Tuple[int, int], line: str) -> None: ... + def tokeneater(self, type: int, token: str, srowcol: tuple[int, int], erowcol: tuple[int, int], line: str) -> None: ... CO_OPTIMIZED: int CO_NEWLOCALS: int @@ -46,7 +53,7 @@ CO_ITERABLE_COROUTINE: int CO_ASYNC_GENERATOR: int TPFLAGS_IS_ABSTRACT: int -def getmembers(object: object, predicate: Callable[[Any], bool] | None = ...) -> list[Tuple[str, Any]]: ... +def getmembers(object: object, predicate: Callable[[Any], bool] | None = ...) -> list[tuple[str, Any]]: ... def getmodulename(path: str) -> str | None: ... def ismodule(object: object) -> TypeGuard[ModuleType]: ... def isclass(object: object) -> TypeGuard[Type[Any]]: ... @@ -62,7 +69,7 @@ else: def iscoroutinefunction(object: object) -> bool: ... def isgenerator(object: object) -> TypeGuard[GeneratorType[Any, Any, Any]]: ... -def iscoroutine(object: object) -> TypeGuard[CoroutineType]: ... +def iscoroutine(object: object) -> TypeGuard[CoroutineType[Any, Any, Any]]: ... def isawaitable(object: object) -> TypeGuard[Awaitable[Any]]: ... if sys.version_info >= (3, 8): @@ -71,24 +78,54 @@ if sys.version_info >= (3, 8): else: def isasyncgenfunction(object: object) -> bool: ... +_T_cont = TypeVar("_T_cont", contravariant=True) +_V_cont = TypeVar("_V_cont", contravariant=True) + +class _SupportsSet(Protocol[_T_cont, _V_cont]): + def __set__(self, __instance: _T_cont, __value: _V_cont) -> None: ... + +class _SupportsDelete(Protocol[_T_cont]): + def __delete__(self, __instance: _T_cont) -> None: ... + def isasyncgen(object: object) -> TypeGuard[AsyncGeneratorType[Any, Any]]: ... def istraceback(object: object) -> TypeGuard[TracebackType]: ... def isframe(object: object) -> TypeGuard[FrameType]: ... def iscode(object: object) -> TypeGuard[CodeType]: ... def isbuiltin(object: object) -> TypeGuard[BuiltinFunctionType]: ... -def isroutine(object: object) -> bool: ... + +if sys.version_info < (3, 7): + def isroutine( + object: object, + ) -> TypeGuard[FunctionType | LambdaType | MethodType | BuiltinFunctionType | BuiltinMethodType]: ... + def ismethoddescriptor(object: object) -> bool: ... + def ismemberdescriptor(object: object) -> bool: ... + +else: + def isroutine( + object: object, + ) -> TypeGuard[ + FunctionType + | LambdaType + | MethodType + | BuiltinFunctionType + | BuiltinMethodType + | WrapperDescriptorType + | MethodDescriptorType + | ClassMethodDescriptorType + ]: ... + def ismethoddescriptor(object: object) -> TypeGuard[MethodDescriptorType]: ... + def ismemberdescriptor(object: object) -> TypeGuard[MemberDescriptorType]: ... + def isabstract(object: object) -> bool: ... -def ismethoddescriptor(object: object) -> bool: ... -def isdatadescriptor(object: object) -> bool: ... -def isgetsetdescriptor(object: object) -> bool: ... -def ismemberdescriptor(object: object) -> bool: ... +def isgetsetdescriptor(object: object) -> TypeGuard[GetSetDescriptorType]: ... +def isdatadescriptor(object: object) -> TypeGuard[_SupportsSet[Any, Any] | _SupportsDelete[Any]]: ... # # Retrieving source code # _SourceObjectType = Union[ModuleType, Type[Any], MethodType, FunctionType, TracebackType, FrameType, CodeType, Callable[..., Any]] -def findsource(object: _SourceObjectType) -> Tuple[list[str], int]: ... +def findsource(object: _SourceObjectType) -> tuple[list[str], int]: ... def getabsfile(object: _SourceObjectType, _filename: str | None = ...) -> str: ... def getblock(lines: Sequence[str]) -> Sequence[str]: ... def getdoc(object: object) -> str | None: ... @@ -96,7 +133,7 @@ def getcomments(object: object) -> str | None: ... def getfile(object: _SourceObjectType) -> str: ... def getmodule(object: object, _filename: str | None = ...) -> ModuleType | None: ... def getsourcefile(object: _SourceObjectType) -> str | None: ... -def getsourcelines(object: _SourceObjectType) -> Tuple[list[str], int]: ... +def getsourcelines(object: _SourceObjectType) -> tuple[list[str], int]: ... def getsource(object: _SourceObjectType) -> str: ... def cleandoc(doc: str) -> str: ... def indentsize(line: str) -> int: ... @@ -117,10 +154,14 @@ if sys.version_info >= (3, 10): else: def signature(obj: Callable[..., Any], *, follow_wrapped: bool = ...) -> Signature: ... +class _void: ... +class _empty: ... + class Signature: - def __init__(self, parameters: Sequence[Parameter] | None = ..., *, return_annotation: Any = ...) -> None: ... - # TODO: can we be more specific here? - empty: object + def __init__( + self, parameters: Sequence[Parameter] | None = ..., *, return_annotation: Any = ..., __validate_parameters__: bool = ... + ) -> None: ... + empty = _empty @property def parameters(self) -> types.MappingProxyType[str, Parameter]: ... # TODO: can we be more specific here? @@ -128,7 +169,9 @@ class Signature: def return_annotation(self) -> Any: ... def bind(self, *args: Any, **kwargs: Any) -> BoundArguments: ... def bind_partial(self, *args: Any, **kwargs: Any) -> BoundArguments: ... - def replace(self: Self, *, parameters: Sequence[Parameter] | None = ..., return_annotation: Any = ...) -> Self: ... + def replace( + self: Self, *, parameters: Sequence[Parameter] | Type[_void] | None = ..., return_annotation: Any = ... + ) -> Self: ... if sys.version_info >= (3, 10): @classmethod def from_callable( @@ -166,7 +209,7 @@ class _ParameterKind(enum.IntEnum): class Parameter: def __init__(self, name: str, kind: _ParameterKind, *, default: Any = ..., annotation: Any = ...) -> None: ... - empty: Any + empty = _empty name: str default: Any annotation: Any @@ -178,7 +221,12 @@ class Parameter: KEYWORD_ONLY: ClassVar[Literal[_ParameterKind.KEYWORD_ONLY]] VAR_KEYWORD: ClassVar[Literal[_ParameterKind.VAR_KEYWORD]] def replace( - self: Self, *, name: str | None = ..., kind: _ParameterKind | None = ..., default: Any = ..., annotation: Any = ... + self: Self, + *, + name: str | Type[_void] = ..., + kind: _ParameterKind | Type[_void] = ..., + default: Any = ..., + annotation: Any = ..., ) -> Self: ... class BoundArguments: @@ -265,7 +313,7 @@ class ClosureVars(NamedTuple): nonlocals: Mapping[str, Any] globals: Mapping[str, Any] builtins: Mapping[str, Any] - unbound: Set[str] + unbound: AbstractSet[str] def getclosurevars(func: Callable[..., Any]) -> ClosureVars: ... def unwrap(func: Callable[..., Any], *, stop: Callable[[Any], Any] | None = ...) -> Any: ... diff --git a/mypy/typeshed/stdlib/ipaddress.pyi b/mypy/typeshed/stdlib/ipaddress.pyi index 710ad27dd466..0ded1ef19b47 100644 --- a/mypy/typeshed/stdlib/ipaddress.pyi +++ b/mypy/typeshed/stdlib/ipaddress.pyi @@ -1,5 +1,5 @@ import sys -from typing import Any, Container, Generic, Iterable, Iterator, SupportsInt, Tuple, TypeVar, overload +from typing import Any, Container, Generic, Iterable, Iterator, SupportsInt, TypeVar, overload # Undocumented length constants IPV4LENGTH: int @@ -126,7 +126,7 @@ class IPv6Address(_BaseAddress): @property def sixtofour(self) -> IPv4Address | None: ... @property - def teredo(self) -> Tuple[IPv4Address, IPv4Address] | None: ... + def teredo(self) -> tuple[IPv4Address, IPv4Address] | None: ... class IPv6Network(_BaseNetwork[IPv6Address]): @property @@ -142,11 +142,11 @@ def summarize_address_range(first: IPv4Address, last: IPv4Address) -> Iterator[I def summarize_address_range(first: IPv6Address, last: IPv6Address) -> Iterator[IPv6Network]: ... def collapse_addresses(addresses: Iterable[_N]) -> Iterator[_N]: ... @overload -def get_mixed_type_key(obj: _A) -> Tuple[int, _A]: ... +def get_mixed_type_key(obj: _A) -> tuple[int, _A]: ... @overload -def get_mixed_type_key(obj: IPv4Network) -> Tuple[int, IPv4Address, IPv4Address]: ... +def get_mixed_type_key(obj: IPv4Network) -> tuple[int, IPv4Address, IPv4Address]: ... @overload -def get_mixed_type_key(obj: IPv6Network) -> Tuple[int, IPv6Address, IPv6Address]: ... +def get_mixed_type_key(obj: IPv6Network) -> tuple[int, IPv6Address, IPv6Address]: ... class AddressValueError(ValueError): ... class NetmaskValueError(ValueError): ... diff --git a/mypy/typeshed/stdlib/itertools.pyi b/mypy/typeshed/stdlib/itertools.pyi index 4ffa181bfd7d..9d666d681781 100644 --- a/mypy/typeshed/stdlib/itertools.pyi +++ b/mypy/typeshed/stdlib/itertools.pyi @@ -91,8 +91,8 @@ class groupby(Iterator[Tuple[_T, Iterator[_S]]], Generic[_T, _S]): def __new__(cls, iterable: Iterable[_T1], key: None = ...) -> groupby[_T1, _T1]: ... @overload def __new__(cls, iterable: Iterable[_T1], key: Callable[[_T1], _T2]) -> groupby[_T2, _T1]: ... - def __iter__(self) -> Iterator[Tuple[_T, Iterator[_S]]]: ... - def __next__(self) -> Tuple[_T, Iterator[_S]]: ... + def __iter__(self) -> Iterator[tuple[_T, Iterator[_S]]]: ... + def __next__(self) -> tuple[_T, Iterator[_S]]: ... class islice(Iterator[_T], Generic[_T]): @overload @@ -126,15 +126,15 @@ _T6 = TypeVar("_T6") class product(Iterator[_T_co], Generic[_T_co]): @overload - def __new__(cls, __iter1: Iterable[_T1]) -> product[Tuple[_T1]]: ... + def __new__(cls, __iter1: Iterable[_T1]) -> product[tuple[_T1]]: ... @overload - def __new__(cls, __iter1: Iterable[_T1], __iter2: Iterable[_T2]) -> product[Tuple[_T1, _T2]]: ... + def __new__(cls, __iter1: Iterable[_T1], __iter2: Iterable[_T2]) -> product[tuple[_T1, _T2]]: ... @overload - def __new__(cls, __iter1: Iterable[_T1], __iter2: Iterable[_T2], __iter3: Iterable[_T3]) -> product[Tuple[_T1, _T2, _T3]]: ... + def __new__(cls, __iter1: Iterable[_T1], __iter2: Iterable[_T2], __iter3: Iterable[_T3]) -> product[tuple[_T1, _T2, _T3]]: ... @overload def __new__( cls, __iter1: Iterable[_T1], __iter2: Iterable[_T2], __iter3: Iterable[_T3], __iter4: Iterable[_T4] - ) -> product[Tuple[_T1, _T2, _T3, _T4]]: ... + ) -> product[tuple[_T1, _T2, _T3, _T4]]: ... @overload def __new__( cls, @@ -143,7 +143,7 @@ class product(Iterator[_T_co], Generic[_T_co]): __iter3: Iterable[_T3], __iter4: Iterable[_T4], __iter5: Iterable[_T5], - ) -> product[Tuple[_T1, _T2, _T3, _T4, _T5]]: ... + ) -> product[tuple[_T1, _T2, _T3, _T4, _T5]]: ... @overload def __new__( cls, @@ -153,7 +153,7 @@ class product(Iterator[_T_co], Generic[_T_co]): __iter4: Iterable[_T4], __iter5: Iterable[_T5], __iter6: Iterable[_T6], - ) -> product[Tuple[_T1, _T2, _T3, _T4, _T5, _T6]]: ... + ) -> product[tuple[_T1, _T2, _T3, _T4, _T5, _T6]]: ... @overload def __new__( cls, @@ -180,13 +180,13 @@ class permutations(Iterator[Tuple[_T, ...]], Generic[_T]): class combinations(Iterator[_T_co], Generic[_T_co]): @overload - def __new__(cls, iterable: Iterable[_T], r: Literal[2]) -> combinations[Tuple[_T, _T]]: ... + def __new__(cls, iterable: Iterable[_T], r: Literal[2]) -> combinations[tuple[_T, _T]]: ... @overload - def __new__(cls, iterable: Iterable[_T], r: Literal[3]) -> combinations[Tuple[_T, _T, _T]]: ... + def __new__(cls, iterable: Iterable[_T], r: Literal[3]) -> combinations[tuple[_T, _T, _T]]: ... @overload - def __new__(cls, iterable: Iterable[_T], r: Literal[4]) -> combinations[Tuple[_T, _T, _T, _T]]: ... + def __new__(cls, iterable: Iterable[_T], r: Literal[4]) -> combinations[tuple[_T, _T, _T, _T]]: ... @overload - def __new__(cls, iterable: Iterable[_T], r: Literal[5]) -> combinations[Tuple[_T, _T, _T, _T, _T]]: ... + def __new__(cls, iterable: Iterable[_T], r: Literal[5]) -> combinations[tuple[_T, _T, _T, _T, _T]]: ... @overload def __new__(cls, iterable: Iterable[_T], r: int) -> combinations[Tuple[_T, ...]]: ... def __iter__(self) -> Iterator[_T_co]: ... @@ -199,6 +199,6 @@ class combinations_with_replacement(Iterator[Tuple[_T, ...]], Generic[_T]): if sys.version_info >= (3, 10): class pairwise(Iterator[_T_co], Generic[_T_co]): - def __new__(cls, __iterable: Iterable[_T]) -> pairwise[Tuple[_T, _T]]: ... + def __new__(cls, __iterable: Iterable[_T]) -> pairwise[tuple[_T, _T]]: ... def __iter__(self) -> Iterator[_T_co]: ... def __next__(self) -> _T_co: ... diff --git a/mypy/typeshed/stdlib/json/__init__.pyi b/mypy/typeshed/stdlib/json/__init__.pyi index e37e68ca3b99..3e26d1b14f82 100644 --- a/mypy/typeshed/stdlib/json/__init__.pyi +++ b/mypy/typeshed/stdlib/json/__init__.pyi @@ -1,5 +1,5 @@ from _typeshed import SupportsRead -from typing import IO, Any, Callable, Tuple, Type +from typing import IO, Any, Callable, Type from .decoder import JSONDecodeError as JSONDecodeError, JSONDecoder as JSONDecoder from .encoder import JSONEncoder as JSONEncoder @@ -13,7 +13,7 @@ def dumps( allow_nan: bool = ..., cls: Type[JSONEncoder] | None = ..., indent: None | int | str = ..., - separators: Tuple[str, str] | None = ..., + separators: tuple[str, str] | None = ..., default: Callable[[Any], Any] | None = ..., sort_keys: bool = ..., **kwds: Any, @@ -28,7 +28,7 @@ def dump( allow_nan: bool = ..., cls: Type[JSONEncoder] | None = ..., indent: None | int | str = ..., - separators: Tuple[str, str] | None = ..., + separators: tuple[str, str] | None = ..., default: Callable[[Any], Any] | None = ..., sort_keys: bool = ..., **kwds: Any, @@ -41,7 +41,7 @@ def loads( parse_float: Callable[[str], Any] | None = ..., parse_int: Callable[[str], Any] | None = ..., parse_constant: Callable[[str], Any] | None = ..., - object_pairs_hook: Callable[[list[Tuple[Any, Any]]], Any] | None = ..., + object_pairs_hook: Callable[[list[tuple[Any, Any]]], Any] | None = ..., **kwds: Any, ) -> Any: ... def load( @@ -52,7 +52,7 @@ def load( parse_float: Callable[[str], Any] | None = ..., parse_int: Callable[[str], Any] | None = ..., parse_constant: Callable[[str], Any] | None = ..., - object_pairs_hook: Callable[[list[Tuple[Any, Any]]], Any] | None = ..., + object_pairs_hook: Callable[[list[tuple[Any, Any]]], Any] | None = ..., **kwds: Any, ) -> Any: ... def detect_encoding(b: bytes) -> str: ... # undocumented diff --git a/mypy/typeshed/stdlib/json/decoder.pyi b/mypy/typeshed/stdlib/json/decoder.pyi index 5135eb4e3e45..adf09bb4bb7d 100644 --- a/mypy/typeshed/stdlib/json/decoder.pyi +++ b/mypy/typeshed/stdlib/json/decoder.pyi @@ -1,4 +1,4 @@ -from typing import Any, Callable, Tuple +from typing import Any, Callable class JSONDecodeError(ValueError): msg: str @@ -14,7 +14,7 @@ class JSONDecoder: parse_int: Callable[[str], Any] parse_constant: Callable[[str], Any] strict: bool - object_pairs_hook: Callable[[list[Tuple[str, Any]]], Any] + object_pairs_hook: Callable[[list[tuple[str, Any]]], Any] def __init__( self, *, @@ -23,7 +23,7 @@ class JSONDecoder: parse_int: Callable[[str], Any] | None = ..., parse_constant: Callable[[str], Any] | None = ..., strict: bool = ..., - object_pairs_hook: Callable[[list[Tuple[str, Any]]], Any] | None = ..., + object_pairs_hook: Callable[[list[tuple[str, Any]]], Any] | None = ..., ) -> None: ... def decode(self, s: str, _w: Callable[..., Any] = ...) -> Any: ... # _w is undocumented - def raw_decode(self, s: str, idx: int = ...) -> Tuple[Any, int]: ... + def raw_decode(self, s: str, idx: int = ...) -> tuple[Any, int]: ... diff --git a/mypy/typeshed/stdlib/json/encoder.pyi b/mypy/typeshed/stdlib/json/encoder.pyi index 36113ed229ca..9557a96eee78 100644 --- a/mypy/typeshed/stdlib/json/encoder.pyi +++ b/mypy/typeshed/stdlib/json/encoder.pyi @@ -1,4 +1,4 @@ -from typing import Any, Callable, Iterator, Tuple +from typing import Any, Callable, Iterator def py_encode_basestring(s: str) -> str: ... # undocumented def py_encode_basestring_ascii(s: str) -> str: ... # undocumented @@ -22,7 +22,7 @@ class JSONEncoder: allow_nan: bool = ..., sort_keys: bool = ..., indent: int | None = ..., - separators: Tuple[str, str] | None = ..., + separators: tuple[str, str] | None = ..., default: Callable[..., Any] | None = ..., ) -> None: ... def default(self, o: Any) -> Any: ... diff --git a/mypy/typeshed/stdlib/lib2to3/pgen2/parse.pyi b/mypy/typeshed/stdlib/lib2to3/pgen2/parse.pyi index d6e1ec4b72b8..e776ed1e5a61 100644 --- a/mypy/typeshed/stdlib/lib2to3/pgen2/parse.pyi +++ b/mypy/typeshed/stdlib/lib2to3/pgen2/parse.pyi @@ -1,6 +1,6 @@ from lib2to3.pgen2.grammar import _DFAS, Grammar from lib2to3.pytree import _NL, _Convert, _RawNode -from typing import Any, Sequence, Set, Tuple +from typing import Any, Sequence _Context = Sequence[Any] @@ -14,9 +14,9 @@ class ParseError(Exception): class Parser: grammar: Grammar convert: _Convert - stack: list[Tuple[_DFAS, int, _RawNode]] + stack: list[tuple[_DFAS, int, _RawNode]] rootnode: _NL | None - used_names: Set[str] + used_names: set[str] def __init__(self, grammar: Grammar, convert: _Convert | None = ...) -> None: ... def setup(self, start: int | None = ...) -> None: ... def addtoken(self, type: int, value: str | None, context: _Context) -> bool: ... diff --git a/mypy/typeshed/stdlib/lib2to3/pgen2/pgen.pyi b/mypy/typeshed/stdlib/lib2to3/pgen2/pgen.pyi index 87b4a8aad71b..11680157d199 100644 --- a/mypy/typeshed/stdlib/lib2to3/pgen2/pgen.pyi +++ b/mypy/typeshed/stdlib/lib2to3/pgen2/pgen.pyi @@ -1,7 +1,7 @@ from _typeshed import StrPath from lib2to3.pgen2 import grammar from lib2to3.pgen2.tokenize import _TokenInfo -from typing import IO, Any, Iterable, Iterator, NoReturn, Tuple +from typing import IO, Any, Iterable, Iterator, NoReturn class PgenGrammar(grammar.Grammar): ... @@ -16,21 +16,21 @@ class ParserGenerator: def make_label(self, c: PgenGrammar, label: str) -> int: ... def addfirstsets(self) -> None: ... def calcfirst(self, name: str) -> None: ... - def parse(self) -> Tuple[dict[str, list[DFAState]], str]: ... + def parse(self) -> tuple[dict[str, list[DFAState]], str]: ... def make_dfa(self, start: NFAState, finish: NFAState) -> list[DFAState]: ... def dump_nfa(self, name: str, start: NFAState, finish: NFAState) -> list[DFAState]: ... def dump_dfa(self, name: str, dfa: Iterable[DFAState]) -> None: ... def simplify_dfa(self, dfa: list[DFAState]) -> None: ... - def parse_rhs(self) -> Tuple[NFAState, NFAState]: ... - def parse_alt(self) -> Tuple[NFAState, NFAState]: ... - def parse_item(self) -> Tuple[NFAState, NFAState]: ... - def parse_atom(self) -> Tuple[NFAState, NFAState]: ... + def parse_rhs(self) -> tuple[NFAState, NFAState]: ... + def parse_alt(self) -> tuple[NFAState, NFAState]: ... + def parse_item(self) -> tuple[NFAState, NFAState]: ... + def parse_atom(self) -> tuple[NFAState, NFAState]: ... def expect(self, type: int, value: Any | None = ...) -> str: ... def gettoken(self) -> None: ... def raise_error(self, msg: str, *args: Any) -> NoReturn: ... class NFAState: - arcs: list[Tuple[str | None, NFAState]] + arcs: list[tuple[str | None, NFAState]] def __init__(self) -> None: ... def addarc(self, next: NFAState, label: str | None = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/lib2to3/pgen2/tokenize.pyi b/mypy/typeshed/stdlib/lib2to3/pgen2/tokenize.pyi index 467fb0de25b9..e96a0d8c8eb3 100644 --- a/mypy/typeshed/stdlib/lib2to3/pgen2/tokenize.pyi +++ b/mypy/typeshed/stdlib/lib2to3/pgen2/tokenize.pyi @@ -17,7 +17,7 @@ class Untokenizer: def __init__(self) -> None: ... def add_whitespace(self, start: _Coord) -> None: ... def untokenize(self, iterable: Iterable[_TokenInfo]) -> str: ... - def compat(self, token: Tuple[int, str], iterable: Iterable[_TokenInfo]) -> None: ... + def compat(self, token: tuple[int, str], iterable: Iterable[_TokenInfo]) -> None: ... def untokenize(iterable: Iterable[_TokenInfo]) -> str: ... def generate_tokens(readline: Callable[[], str]) -> Iterator[_TokenInfo]: ... diff --git a/mypy/typeshed/stdlib/lib2to3/pytree.pyi b/mypy/typeshed/stdlib/lib2to3/pytree.pyi index f926e6f7f8b3..eab82cbc200d 100644 --- a/mypy/typeshed/stdlib/lib2to3/pytree.pyi +++ b/mypy/typeshed/stdlib/lib2to3/pytree.pyi @@ -68,7 +68,7 @@ class BasePattern: def optimize(self) -> BasePattern: ... # sic, subclasses are free to optimize themselves into different patterns def match(self, node: _NL, results: _Results | None = ...) -> bool: ... def match_seq(self, nodes: list[_NL], results: _Results | None = ...) -> bool: ... - def generate_matches(self, nodes: list[_NL]) -> Iterator[Tuple[int, _Results]]: ... + def generate_matches(self, nodes: list[_NL]) -> Iterator[tuple[int, _Results]]: ... class LeafPattern(BasePattern): def __init__(self, type: int | None = ..., content: str | None = ..., name: str | None = ...) -> None: ... @@ -85,4 +85,4 @@ class WildcardPattern(BasePattern): class NegatedPattern(BasePattern): def __init__(self, content: str | None = ...) -> None: ... -def generate_matches(patterns: list[BasePattern], nodes: list[_NL]) -> Iterator[Tuple[int, _Results]]: ... +def generate_matches(patterns: list[BasePattern], nodes: list[_NL]) -> Iterator[tuple[int, _Results]]: ... diff --git a/mypy/typeshed/stdlib/locale.pyi b/mypy/typeshed/stdlib/locale.pyi index da518575ac7c..1f80c8a62483 100644 --- a/mypy/typeshed/stdlib/locale.pyi +++ b/mypy/typeshed/stdlib/locale.pyi @@ -11,6 +11,8 @@ D_T_FMT: int D_FMT: int T_FMT: int T_FMT_AMPM: int +AM_STR: int +PM_STR: int DAY_1: int DAY_2: int @@ -80,7 +82,7 @@ class Error(Exception): ... def setlocale(category: int, locale: _str | Iterable[_str] | None = ...) -> _str: ... def localeconv() -> Mapping[_str, int | _str | list[int]]: ... def nl_langinfo(__key: int) -> _str: ... -def getdefaultlocale(envvars: Tuple[_str, ...] = ...) -> Tuple[_str | None, _str | None]: ... +def getdefaultlocale(envvars: Tuple[_str, ...] = ...) -> tuple[_str | None, _str | None]: ... def getlocale(category: int = ...) -> Sequence[_str]: ... def getpreferredencoding(do_setlocale: bool = ...) -> _str: ... def normalize(localename: _str) -> _str: ... diff --git a/mypy/typeshed/stdlib/logging/config.pyi b/mypy/typeshed/stdlib/logging/config.pyi index f84865e35f92..8ee9e7b339b5 100644 --- a/mypy/typeshed/stdlib/logging/config.pyi +++ b/mypy/typeshed/stdlib/logging/config.pyi @@ -3,12 +3,14 @@ from _typeshed import StrOrBytesPath, StrPath from collections.abc import Callable from configparser import RawConfigParser from threading import Thread -from typing import IO, Any, Pattern +from typing import IO, Any, Pattern, Sequence + +from . import _Level if sys.version_info >= (3, 8): - from typing import Literal + from typing import Literal, TypedDict else: - from typing_extensions import Literal + from typing_extensions import Literal, TypedDict if sys.version_info >= (3, 7): _Path = StrOrBytesPath @@ -19,7 +21,34 @@ DEFAULT_LOGGING_CONFIG_PORT: int RESET_ERROR: int # undocumented IDENTIFIER: Pattern[str] # undocumented -def dictConfig(config: dict[str, Any]) -> None: ... +class _RootLoggerConfiguration(TypedDict, total=False): + level: _Level + filters: Sequence[str] + handlers: Sequence[str] + +class _LoggerConfiguration(_RootLoggerConfiguration, TypedDict, total=False): + propagate: bool + +class _OptionalDictConfigArgs(TypedDict, total=False): + # these two can have custom factories (key: `()`) which can have extra keys + formatters: dict[str, dict[str, Any]] + filters: dict[str, dict[str, Any]] + # type checkers would warn about extra keys if this was a TypedDict + handlers: dict[str, dict[str, Any]] + loggers: dict[str, _LoggerConfiguration] + root: _RootLoggerConfiguration | None + incremental: bool + disable_existing_loggers: bool + +class _DictConfigArgs(_OptionalDictConfigArgs, TypedDict): + version: Literal[1] + +# Accept dict[str, Any] to avoid false positives if called with a dict +# type, since dict types are not compatible with TypedDicts. +# +# Also accept a TypedDict type, to allow callers to use TypedDict +# types, and for somewhat stricter type checking of dict literals. +def dictConfig(config: _DictConfigArgs | dict[str, Any]) -> None: ... if sys.version_info >= (3, 10): def fileConfig( diff --git a/mypy/typeshed/stdlib/logging/handlers.pyi b/mypy/typeshed/stdlib/logging/handlers.pyi index 762359bc17bb..5be624872a14 100644 --- a/mypy/typeshed/stdlib/logging/handlers.pyi +++ b/mypy/typeshed/stdlib/logging/handlers.pyi @@ -46,7 +46,7 @@ class BaseRotatingHandler(FileHandler): class RotatingFileHandler(BaseRotatingHandler): maxBytes: str # undocumented - backupCount: str # undocumented + backupCount: int # undocumented if sys.version_info >= (3, 9): def __init__( self, @@ -73,7 +73,7 @@ class RotatingFileHandler(BaseRotatingHandler): class TimedRotatingFileHandler(BaseRotatingHandler): when: str # undocumented - backupCount: str # undocumented + backupCount: int # undocumented utc: bool # undocumented atTime: datetime.datetime | None # undocumented interval: int # undocumented diff --git a/mypy/typeshed/stdlib/lzma.pyi b/mypy/typeshed/stdlib/lzma.pyi index 7a26d15292d4..e1da3024c4ac 100644 --- a/mypy/typeshed/stdlib/lzma.pyi +++ b/mypy/typeshed/stdlib/lzma.pyi @@ -1,7 +1,7 @@ import io from _typeshed import ReadableBuffer, Self, StrOrBytesPath from typing import IO, Any, Mapping, Sequence, TextIO, Union, overload -from typing_extensions import Literal +from typing_extensions import Literal, final _OpenBinaryWritingMode = Literal["w", "wb", "x", "xb", "a", "ab"] _OpenTextWritingMode = Literal["wt", "xt", "at"] @@ -40,6 +40,7 @@ PRESET_DEFAULT: int PRESET_EXTREME: int # from _lzma.c +@final class LZMADecompressor(object): def __init__(self, format: int | None = ..., memlimit: int | None = ..., filters: _FilterChain | None = ...) -> None: ... def decompress(self, data: bytes, max_length: int = ...) -> bytes: ... @@ -53,6 +54,7 @@ class LZMADecompressor(object): def needs_input(self) -> bool: ... # from _lzma.c +@final class LZMACompressor(object): def __init__( self, format: int | None = ..., check: int = ..., preset: int | None = ..., filters: _FilterChain | None = ... diff --git a/mypy/typeshed/stdlib/macpath.pyi b/mypy/typeshed/stdlib/macpath.pyi index 5657adde9a84..2512e086b735 100644 --- a/mypy/typeshed/stdlib/macpath.pyi +++ b/mypy/typeshed/stdlib/macpath.pyi @@ -32,7 +32,7 @@ from posixpath import ( splitext as splitext, supports_unicode_filenames as supports_unicode_filenames, ) -from typing import AnyStr, Tuple, overload +from typing import AnyStr, overload altsep: str | None @@ -64,6 +64,6 @@ def join(s: StrPath, *paths: StrPath) -> str: ... @overload def join(s: BytesPath, *paths: BytesPath) -> bytes: ... @overload -def split(s: PathLike[AnyStr]) -> Tuple[AnyStr, AnyStr]: ... +def split(s: PathLike[AnyStr]) -> tuple[AnyStr, AnyStr]: ... @overload -def split(s: AnyStr) -> Tuple[AnyStr, AnyStr]: ... +def split(s: AnyStr) -> tuple[AnyStr, AnyStr]: ... diff --git a/mypy/typeshed/stdlib/mailbox.pyi b/mypy/typeshed/stdlib/mailbox.pyi index 544760cc5e8c..ffd9c3005cec 100644 --- a/mypy/typeshed/stdlib/mailbox.pyi +++ b/mypy/typeshed/stdlib/mailbox.pyi @@ -13,7 +13,6 @@ from typing import ( Mapping, Protocol, Sequence, - Tuple, Type, TypeVar, Union, @@ -29,10 +28,10 @@ _MessageT = TypeVar("_MessageT", bound=Message) _MessageData = Union[email.message.Message, bytes, str, IO[str], IO[bytes]] class _HasIteritems(Protocol): - def iteritems(self) -> Iterator[Tuple[str, _MessageData]]: ... + def iteritems(self) -> Iterator[tuple[str, _MessageData]]: ... class _HasItems(Protocol): - def items(self) -> Iterator[Tuple[str, _MessageData]]: ... + def items(self) -> Iterator[tuple[str, _MessageData]]: ... linesep: bytes @@ -63,8 +62,8 @@ class Mailbox(Generic[_MessageT]): def itervalues(self) -> Iterator[_MessageT]: ... def __iter__(self) -> Iterator[_MessageT]: ... def values(self) -> list[_MessageT]: ... - def iteritems(self) -> Iterator[Tuple[str, _MessageT]]: ... - def items(self) -> list[Tuple[str, _MessageT]]: ... + def iteritems(self) -> Iterator[tuple[str, _MessageT]]: ... + def items(self) -> list[tuple[str, _MessageT]]: ... def __contains__(self, key: str) -> bool: ... def __len__(self) -> int: ... def clear(self) -> None: ... @@ -72,8 +71,8 @@ class Mailbox(Generic[_MessageT]): def pop(self, key: str, default: None = ...) -> _MessageT | None: ... @overload def pop(self, key: str, default: _T = ...) -> _MessageT | _T: ... - def popitem(self) -> Tuple[str, _MessageT]: ... - def update(self, arg: _HasIteritems | _HasItems | Iterable[Tuple[str, _MessageData]] | None = ...) -> None: ... + def popitem(self) -> tuple[str, _MessageT]: ... + def update(self, arg: _HasIteritems | _HasItems | Iterable[tuple[str, _MessageData]] | None = ...) -> None: ... def flush(self) -> None: ... def lock(self) -> None: ... def unlock(self) -> None: ... @@ -149,7 +148,7 @@ class MaildirMessage(Message): class _mboxMMDFMessage(Message): def get_from(self) -> str: ... - def set_from(self, from_: str, time_: bool | Tuple[int, int, int, int, int, int, int, int, int] | None = ...) -> None: ... + def set_from(self, from_: str, time_: bool | tuple[int, int, int, int, int, int, int, int, int] | None = ...) -> None: ... def get_flags(self) -> str: ... def set_flags(self, flags: Iterable[str]) -> None: ... def add_flag(self, flag: str) -> None: ... diff --git a/mypy/typeshed/stdlib/mailcap.pyi b/mypy/typeshed/stdlib/mailcap.pyi index 2d4008f48c6c..9eaa771ed3d3 100644 --- a/mypy/typeshed/stdlib/mailcap.pyi +++ b/mypy/typeshed/stdlib/mailcap.pyi @@ -1,8 +1,8 @@ -from typing import Dict, Mapping, Sequence, Tuple, Union +from typing import Dict, Mapping, Sequence, Union _Cap = Dict[str, Union[str, int]] def findmatch( caps: Mapping[str, list[_Cap]], MIMEtype: str, key: str = ..., filename: str = ..., plist: Sequence[str] = ... -) -> Tuple[str | None, _Cap | None]: ... +) -> tuple[str | None, _Cap | None]: ... def getcaps() -> dict[str, list[_Cap]]: ... diff --git a/mypy/typeshed/stdlib/math.pyi b/mypy/typeshed/stdlib/math.pyi index 1046676bec4a..f92a3d94f978 100644 --- a/mypy/typeshed/stdlib/math.pyi +++ b/mypy/typeshed/stdlib/math.pyi @@ -1,6 +1,12 @@ import sys from _typeshed import SupportsTrunc -from typing import Iterable, SupportsFloat, SupportsInt, Tuple, overload +from typing import Iterable, SupportsFloat, Union, overload +from typing_extensions import SupportsIndex + +if sys.version_info >= (3, 8): + _SupportsFloatOrIndex = Union[SupportsFloat, SupportsIndex] +else: + _SupportsFloatOrIndex = SupportsFloat e: float pi: float @@ -8,94 +14,106 @@ inf: float nan: float tau: float -def acos(__x: SupportsFloat) -> float: ... -def acosh(__x: SupportsFloat) -> float: ... -def asin(__x: SupportsFloat) -> float: ... -def asinh(__x: SupportsFloat) -> float: ... -def atan(__x: SupportsFloat) -> float: ... -def atan2(__y: SupportsFloat, __x: SupportsFloat) -> float: ... -def atanh(__x: SupportsFloat) -> float: ... -def ceil(__x: SupportsFloat) -> int: ... +def acos(__x: _SupportsFloatOrIndex) -> float: ... +def acosh(__x: _SupportsFloatOrIndex) -> float: ... +def asin(__x: _SupportsFloatOrIndex) -> float: ... +def asinh(__x: _SupportsFloatOrIndex) -> float: ... +def atan(__x: _SupportsFloatOrIndex) -> float: ... +def atan2(__y: _SupportsFloatOrIndex, __x: _SupportsFloatOrIndex) -> float: ... +def atanh(__x: _SupportsFloatOrIndex) -> float: ... +def ceil(__x: _SupportsFloatOrIndex) -> int: ... + +if sys.version_info >= (3, 8): + def comb(__n: SupportsIndex, __k: SupportsIndex) -> int: ... + +def copysign(__x: _SupportsFloatOrIndex, __y: _SupportsFloatOrIndex) -> float: ... +def cos(__x: _SupportsFloatOrIndex) -> float: ... +def cosh(__x: _SupportsFloatOrIndex) -> float: ... +def degrees(__x: _SupportsFloatOrIndex) -> float: ... if sys.version_info >= (3, 8): - def comb(__n: int, __k: int) -> int: ... + def dist(__p: Iterable[_SupportsFloatOrIndex], __q: Iterable[_SupportsFloatOrIndex]) -> float: ... -def copysign(__x: SupportsFloat, __y: SupportsFloat) -> float: ... -def cos(__x: SupportsFloat) -> float: ... -def cosh(__x: SupportsFloat) -> float: ... -def degrees(__x: SupportsFloat) -> float: ... +def erf(__x: _SupportsFloatOrIndex) -> float: ... +def erfc(__x: _SupportsFloatOrIndex) -> float: ... +def exp(__x: _SupportsFloatOrIndex) -> float: ... +def expm1(__x: _SupportsFloatOrIndex) -> float: ... +def fabs(__x: _SupportsFloatOrIndex) -> float: ... if sys.version_info >= (3, 8): - def dist(__p: Iterable[SupportsFloat], __q: Iterable[SupportsFloat]) -> float: ... - -def erf(__x: SupportsFloat) -> float: ... -def erfc(__x: SupportsFloat) -> float: ... -def exp(__x: SupportsFloat) -> float: ... -def expm1(__x: SupportsFloat) -> float: ... -def fabs(__x: SupportsFloat) -> float: ... -def factorial(__x: SupportsInt) -> int: ... -def floor(__x: SupportsFloat) -> int: ... -def fmod(__x: SupportsFloat, __y: SupportsFloat) -> float: ... -def frexp(__x: SupportsFloat) -> Tuple[float, int]: ... -def fsum(__seq: Iterable[float]) -> float: ... -def gamma(__x: SupportsFloat) -> float: ... + def factorial(__x: SupportsIndex) -> int: ... + +else: + def factorial(__x: int) -> int: ... + +def floor(__x: _SupportsFloatOrIndex) -> int: ... +def fmod(__x: _SupportsFloatOrIndex, __y: _SupportsFloatOrIndex) -> float: ... +def frexp(__x: _SupportsFloatOrIndex) -> tuple[float, int]: ... +def fsum(__seq: Iterable[_SupportsFloatOrIndex]) -> float: ... +def gamma(__x: _SupportsFloatOrIndex) -> float: ... if sys.version_info >= (3, 9): - def gcd(*integers: int) -> int: ... + def gcd(*integers: SupportsIndex) -> int: ... else: - def gcd(__x: int, __y: int) -> int: ... + def gcd(__x: SupportsIndex, __y: SupportsIndex) -> int: ... if sys.version_info >= (3, 8): - def hypot(*coordinates: SupportsFloat) -> float: ... + def hypot(*coordinates: _SupportsFloatOrIndex) -> float: ... else: - def hypot(__x: SupportsFloat, __y: SupportsFloat) -> float: ... - -def isclose(a: SupportsFloat, b: SupportsFloat, *, rel_tol: SupportsFloat = ..., abs_tol: SupportsFloat = ...) -> bool: ... -def isinf(__x: SupportsFloat) -> bool: ... -def isfinite(__x: SupportsFloat) -> bool: ... -def isnan(__x: SupportsFloat) -> bool: ... + def hypot(__x: _SupportsFloatOrIndex, __y: _SupportsFloatOrIndex) -> float: ... + +def isclose( + a: _SupportsFloatOrIndex, + b: _SupportsFloatOrIndex, + *, + rel_tol: _SupportsFloatOrIndex = ..., + abs_tol: _SupportsFloatOrIndex = ..., +) -> bool: ... +def isinf(__x: _SupportsFloatOrIndex) -> bool: ... +def isfinite(__x: _SupportsFloatOrIndex) -> bool: ... +def isnan(__x: _SupportsFloatOrIndex) -> bool: ... if sys.version_info >= (3, 8): - def isqrt(__n: int) -> int: ... + def isqrt(__n: SupportsIndex) -> int: ... if sys.version_info >= (3, 9): - def lcm(*integers: int) -> int: ... + def lcm(*integers: SupportsIndex) -> int: ... -def ldexp(__x: SupportsFloat, __i: int) -> float: ... -def lgamma(__x: SupportsFloat) -> float: ... -def log(x: SupportsFloat, base: SupportsFloat = ...) -> float: ... -def log10(__x: SupportsFloat) -> float: ... -def log1p(__x: SupportsFloat) -> float: ... -def log2(__x: SupportsFloat) -> float: ... -def modf(__x: SupportsFloat) -> Tuple[float, float]: ... +def ldexp(__x: _SupportsFloatOrIndex, __i: int) -> float: ... +def lgamma(__x: _SupportsFloatOrIndex) -> float: ... +def log(x: _SupportsFloatOrIndex, base: _SupportsFloatOrIndex = ...) -> float: ... +def log10(__x: _SupportsFloatOrIndex) -> float: ... +def log1p(__x: _SupportsFloatOrIndex) -> float: ... +def log2(__x: _SupportsFloatOrIndex) -> float: ... +def modf(__x: _SupportsFloatOrIndex) -> tuple[float, float]: ... if sys.version_info >= (3, 9): - def nextafter(__x: SupportsFloat, __y: SupportsFloat) -> float: ... + def nextafter(__x: _SupportsFloatOrIndex, __y: _SupportsFloatOrIndex) -> float: ... if sys.version_info >= (3, 8): - def perm(__n: int, __k: int | None = ...) -> int: ... + def perm(__n: SupportsIndex, __k: SupportsIndex | None = ...) -> int: ... -def pow(__x: SupportsFloat, __y: SupportsFloat) -> float: ... +def pow(__x: _SupportsFloatOrIndex, __y: _SupportsFloatOrIndex) -> float: ... if sys.version_info >= (3, 8): @overload - def prod(__iterable: Iterable[int], *, start: int = ...) -> int: ... # type: ignore + def prod(__iterable: Iterable[SupportsIndex], *, start: SupportsIndex = ...) -> int: ... # type: ignore @overload - def prod(__iterable: Iterable[SupportsFloat], *, start: SupportsFloat = ...) -> float: ... + def prod(__iterable: Iterable[_SupportsFloatOrIndex], *, start: _SupportsFloatOrIndex = ...) -> float: ... -def radians(__x: SupportsFloat) -> float: ... +def radians(__x: _SupportsFloatOrIndex) -> float: ... if sys.version_info >= (3, 7): - def remainder(__x: SupportsFloat, __y: SupportsFloat) -> float: ... + def remainder(__x: _SupportsFloatOrIndex, __y: _SupportsFloatOrIndex) -> float: ... -def sin(__x: SupportsFloat) -> float: ... -def sinh(__x: SupportsFloat) -> float: ... -def sqrt(__x: SupportsFloat) -> float: ... -def tan(__x: SupportsFloat) -> float: ... -def tanh(__x: SupportsFloat) -> float: ... +def sin(__x: _SupportsFloatOrIndex) -> float: ... +def sinh(__x: _SupportsFloatOrIndex) -> float: ... +def sqrt(__x: _SupportsFloatOrIndex) -> float: ... +def tan(__x: _SupportsFloatOrIndex) -> float: ... +def tanh(__x: _SupportsFloatOrIndex) -> float: ... def trunc(__x: SupportsTrunc) -> int: ... if sys.version_info >= (3, 9): - def ulp(__x: SupportsFloat) -> float: ... + def ulp(__x: _SupportsFloatOrIndex) -> float: ... diff --git a/mypy/typeshed/stdlib/mimetypes.pyi b/mypy/typeshed/stdlib/mimetypes.pyi index 5a3ec91acbcd..90c87d2cf385 100644 --- a/mypy/typeshed/stdlib/mimetypes.pyi +++ b/mypy/typeshed/stdlib/mimetypes.pyi @@ -3,10 +3,10 @@ from _typeshed import StrPath from typing import IO, Sequence, Tuple if sys.version_info >= (3, 8): - def guess_type(url: StrPath, strict: bool = ...) -> Tuple[str | None, str | None]: ... + def guess_type(url: StrPath, strict: bool = ...) -> tuple[str | None, str | None]: ... else: - def guess_type(url: str, strict: bool = ...) -> Tuple[str | None, str | None]: ... + def guess_type(url: str, strict: bool = ...) -> tuple[str | None, str | None]: ... def guess_all_extensions(type: str, strict: bool = ...) -> list[str]: ... def guess_extension(type: str, strict: bool = ...) -> str | None: ... @@ -24,11 +24,11 @@ common_types: dict[str, str] class MimeTypes: suffix_map: dict[str, str] encodings_map: dict[str, str] - types_map: Tuple[dict[str, str], dict[str, str]] - types_map_inv: Tuple[dict[str, str], dict[str, str]] + types_map: tuple[dict[str, str], dict[str, str]] + types_map_inv: tuple[dict[str, str], dict[str, str]] def __init__(self, filenames: Tuple[str, ...] = ..., strict: bool = ...) -> None: ... def guess_extension(self, type: str, strict: bool = ...) -> str | None: ... - def guess_type(self, url: str, strict: bool = ...) -> Tuple[str | None, str | None]: ... + def guess_type(self, url: str, strict: bool = ...) -> tuple[str | None, str | None]: ... def guess_all_extensions(self, type: str, strict: bool = ...) -> list[str]: ... def read(self, filename: str, strict: bool = ...) -> None: ... def readfp(self, fp: IO[str], strict: bool = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/modulefinder.pyi b/mypy/typeshed/stdlib/modulefinder.pyi index 89f8bd45f106..e77a108e9525 100644 --- a/mypy/typeshed/stdlib/modulefinder.pyi +++ b/mypy/typeshed/stdlib/modulefinder.pyi @@ -6,7 +6,7 @@ LOAD_CONST: int # undocumented IMPORT_NAME: int # undocumented STORE_NAME: int # undocumented STORE_GLOBAL: int # undocumented -STORE_OPS: Tuple[int, int] # undocumented +STORE_OPS: tuple[int, int] # undocumented EXTENDED_ARG: int # undocumented packagePathMap: dict[str, list[str]] # undocumented @@ -29,7 +29,7 @@ class ModuleFinder: debug: int # undocumented indent: int # undocumented excludes: Container[str] # undocumented - replace_paths: Sequence[Tuple[str, str]] # undocumented + replace_paths: Sequence[tuple[str, str]] # undocumented if sys.version_info >= (3, 8): def __init__( @@ -37,7 +37,7 @@ class ModuleFinder: path: list[str] | None = ..., debug: int = ..., excludes: Container[str] | None = ..., - replace_paths: Sequence[Tuple[str, str]] | None = ..., + replace_paths: Sequence[tuple[str, str]] | None = ..., ) -> None: ... else: def __init__( @@ -45,7 +45,7 @@ class ModuleFinder: path: list[str] | None = ..., debug: int = ..., excludes: Container[str] = ..., - replace_paths: Sequence[Tuple[str, str]] = ..., + replace_paths: Sequence[tuple[str, str]] = ..., ) -> None: ... def msg(self, level: int, str: str, *args: Any) -> None: ... # undocumented def msgin(self, *args: Any) -> None: ... # undocumented @@ -56,20 +56,20 @@ class ModuleFinder: self, name: str, caller: Module | None = ..., fromlist: list[str] | None = ..., level: int = ... ) -> Module | None: ... # undocumented def determine_parent(self, caller: Module | None, level: int = ...) -> Module | None: ... # undocumented - def find_head_package(self, parent: Module, name: str) -> Tuple[Module, str]: ... # undocumented + def find_head_package(self, parent: Module, name: str) -> tuple[Module, str]: ... # undocumented def load_tail(self, q: Module, tail: str) -> Module: ... # undocumented def ensure_fromlist(self, m: Module, fromlist: Iterable[str], recursive: int = ...) -> None: ... # undocumented def find_all_submodules(self, m: Module) -> Iterable[str]: ... # undocumented def import_module(self, partname: str, fqname: str, parent: Module) -> Module | None: ... # undocumented - def load_module(self, fqname: str, fp: IO[str], pathname: str, file_info: Tuple[str, str, str]) -> Module: ... # undocumented - def scan_opcodes(self, co: CodeType) -> Iterator[Tuple[str, Tuple[Any, ...]]]: ... # undocumented + def load_module(self, fqname: str, fp: IO[str], pathname: str, file_info: tuple[str, str, str]) -> Module: ... # undocumented + def scan_opcodes(self, co: CodeType) -> Iterator[tuple[str, Tuple[Any, ...]]]: ... # undocumented def scan_code(self, co: CodeType, m: Module) -> None: ... # undocumented def load_package(self, fqname: str, pathname: str) -> Module: ... # undocumented def add_module(self, fqname: str) -> Module: ... # undocumented def find_module( self, name: str, path: str | None, parent: Module | None = ... - ) -> Tuple[IO[Any] | None, str | None, Tuple[str, str, int]]: ... # undocumented + ) -> tuple[IO[Any] | None, str | None, tuple[str, str, int]]: ... # undocumented def report(self) -> None: ... def any_missing(self) -> list[str]: ... # undocumented - def any_missing_maybe(self) -> Tuple[list[str], list[str]]: ... # undocumented + def any_missing_maybe(self) -> tuple[list[str], list[str]]: ... # undocumented def replace_paths_in_code(self, co: CodeType) -> CodeType: ... # undocumented diff --git a/mypy/typeshed/stdlib/msilib/__init__.pyi b/mypy/typeshed/stdlib/msilib/__init__.pyi index ca05ee6f4309..4e1a7e6a7c02 100644 --- a/mypy/typeshed/stdlib/msilib/__init__.pyi +++ b/mypy/typeshed/stdlib/msilib/__init__.pyi @@ -1,6 +1,6 @@ import sys from types import ModuleType -from typing import Any, Container, Iterable, Sequence, Set, Tuple, Type +from typing import Any, Container, Iterable, Sequence, Tuple, Type from typing_extensions import Literal if sys.platform == "win32": @@ -25,14 +25,14 @@ if sys.platform == "win32": class Table: name: str - fields: list[Tuple[int, str, int]] + fields: list[tuple[int, str, int]] def __init__(self, name: str) -> None: ... def add_field(self, index: int, name: str, type: int) -> None: ... def sql(self) -> str: ... def create(self, db: _Database) -> None: ... class _Unspecified: ... def change_sequence( - seq: Sequence[Tuple[str, str | None, int]], + seq: Sequence[tuple[str, str | None, int]], action: str, seqno: int | Type[_Unspecified] = ..., cond: str | Type[_Unspecified] = ..., @@ -48,14 +48,14 @@ if sys.platform == "win32": class CAB: name: str - files: list[Tuple[str, str]] - filenames: Set[str] + files: list[tuple[str, str]] + filenames: set[str] index: int def __init__(self, name: str) -> None: ... def gen_id(self, file: str) -> str: ... - def append(self, full: str, file: str, logical: str) -> Tuple[int, str]: ... + def append(self, full: str, file: str, logical: str) -> tuple[int, str]: ... def commit(self, db: _Database) -> None: ... - _directories: Set[str] + _directories: set[str] class Directory: db: _Database @@ -64,8 +64,8 @@ if sys.platform == "win32": physical: str logical: str component: str | None - short_names: Set[str] - ids: Set[str] + short_names: set[str] + ids: set[str] keyfiles: dict[str, str] componentflags: int | None absolute: str diff --git a/mypy/typeshed/stdlib/msilib/schema.pyi b/mypy/typeshed/stdlib/msilib/schema.pyi index df57ade15a2f..4ad9a1783fcd 100644 --- a/mypy/typeshed/stdlib/msilib/schema.pyi +++ b/mypy/typeshed/stdlib/msilib/schema.pyi @@ -1,5 +1,4 @@ import sys -from typing import Tuple if sys.platform == "win32": from . import Table @@ -92,4 +91,4 @@ if sys.platform == "win32": tables: list[Table] - _Validation_records: list[Tuple[str, str, str, int | None, int | None, str | None, int | None, str | None, str | None, str]] + _Validation_records: list[tuple[str, str, str, int | None, int | None, str | None, int | None, str | None, str | None, str]] diff --git a/mypy/typeshed/stdlib/msilib/text.pyi b/mypy/typeshed/stdlib/msilib/text.pyi index fe2dc23830e0..879429ecea85 100644 --- a/mypy/typeshed/stdlib/msilib/text.pyi +++ b/mypy/typeshed/stdlib/msilib/text.pyi @@ -1,9 +1,8 @@ import sys -from typing import Tuple if sys.platform == "win32": - ActionText: list[Tuple[str, str, str | None]] - UIText: list[Tuple[str, str | None]] + ActionText: list[tuple[str, str, str | None]] + UIText: list[tuple[str, str | None]] tables: list[str] diff --git a/mypy/typeshed/stdlib/multiprocessing/__init__.pyi b/mypy/typeshed/stdlib/multiprocessing/__init__.pyi index 53b0c983fbcf..000fed79f3e4 100644 --- a/mypy/typeshed/stdlib/multiprocessing/__init__.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/__init__.pyi @@ -53,7 +53,7 @@ _SemaphoreType = synchronize.Semaphore # multiprocessing.context.BaseContext's methods, so the two signatures should # be identical (modulo self). -# Sychronization primitives +# Synchronization primitives _LockLike = Union[synchronize.Lock, synchronize.RLock] RawValue = context._default_context.RawValue RawArray = context._default_context.RawArray diff --git a/mypy/typeshed/stdlib/multiprocessing/connection.pyi b/mypy/typeshed/stdlib/multiprocessing/connection.pyi index 4f6dc1ba7efa..56ea5c7c0b0b 100644 --- a/mypy/typeshed/stdlib/multiprocessing/connection.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/connection.pyi @@ -60,4 +60,4 @@ def wait( object_list: Iterable[Connection | socket.socket | int], timeout: float | None = ... ) -> list[Connection | socket.socket | int]: ... def Client(address: _Address, family: str | None = ..., authkey: bytes | None = ...) -> Connection: ... -def Pipe(duplex: bool = ...) -> Tuple[Connection, Connection]: ... +def Pipe(duplex: bool = ...) -> tuple[Connection, Connection]: ... diff --git a/mypy/typeshed/stdlib/multiprocessing/context.pyi b/mypy/typeshed/stdlib/multiprocessing/context.pyi index 59ff0afadbc4..e65a387819bc 100644 --- a/mypy/typeshed/stdlib/multiprocessing/context.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/context.pyi @@ -5,6 +5,7 @@ from collections.abc import Callable, Iterable, Sequence from ctypes import _CData from logging import Logger from multiprocessing import queues, synchronize +from multiprocessing.pool import Pool as _Pool from multiprocessing.process import BaseProcess from multiprocessing.sharedctypes import SynchronizedArray, SynchronizedBase from typing import Any, Type, TypeVar, Union, overload @@ -57,7 +58,7 @@ class BaseContext(object): initializer: Callable[..., Any] | None = ..., initargs: Iterable[Any] = ..., maxtasksperchild: int | None = ..., - ) -> multiprocessing.pool.Pool: ... + ) -> _Pool: ... @overload def RawValue(self, typecode_or_type: Type[_CT], *args: Any) -> _CT: ... @overload diff --git a/mypy/typeshed/stdlib/multiprocessing/dummy/connection.pyi b/mypy/typeshed/stdlib/multiprocessing/dummy/connection.pyi index 71e9a50fab21..4ef3d095911f 100644 --- a/mypy/typeshed/stdlib/multiprocessing/dummy/connection.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/dummy/connection.pyi @@ -35,4 +35,4 @@ class Listener(object): def close(self) -> None: ... def Client(address: _Address) -> Connection: ... -def Pipe(duplex: bool = ...) -> Tuple[Connection, Connection]: ... +def Pipe(duplex: bool = ...) -> tuple[Connection, Connection]: ... diff --git a/mypy/typeshed/stdlib/multiprocessing/managers.pyi b/mypy/typeshed/stdlib/multiprocessing/managers.pyi index 568845bfb9e4..22a33f226c0b 100644 --- a/mypy/typeshed/stdlib/multiprocessing/managers.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/managers.pyi @@ -30,12 +30,12 @@ _Namespace = Namespace class Token(object): typeid: str | bytes | None - address: Tuple[str | bytes, int] + address: tuple[str | bytes, int] id: str | bytes | int | None - def __init__(self, typeid: bytes | str | None, address: Tuple[str | bytes, int], id: str | bytes | int | None) -> None: ... + def __init__(self, typeid: bytes | str | None, address: tuple[str | bytes, int], id: str | bytes | int | None) -> None: ... def __repr__(self) -> str: ... - def __getstate__(self) -> Tuple[str | bytes | None, Tuple[str | bytes, int], str | bytes | int | None]: ... - def __setstate__(self, state: Tuple[str | bytes | None, Tuple[str | bytes, int], str | bytes | int | None]) -> None: ... + def __getstate__(self) -> tuple[str | bytes | None, tuple[str | bytes, int], str | bytes | int | None]: ... + def __setstate__(self, state: tuple[str | bytes | None, tuple[str | bytes, int], str | bytes | int | None]) -> None: ... class BaseProxy(object): _address_to_local: dict[Any, Any] @@ -53,7 +53,7 @@ class BaseProxy(object): def __deepcopy__(self, memo: Any | None) -> Any: ... def _callmethod(self, methodname: str, args: Tuple[Any, ...] = ..., kwds: dict[Any, Any] = ...) -> None: ... def _getvalue(self) -> Any: ... - def __reduce__(self) -> Tuple[Any, Tuple[Any, Any, str, dict[Any, Any]]]: ... + def __reduce__(self) -> tuple[Any, tuple[Any, Any, str, dict[Any, Any]]]: ... class ValueProxy(BaseProxy, Generic[_T]): def get(self) -> _T: ... @@ -66,7 +66,7 @@ class ValueProxy(BaseProxy, Generic[_T]): class Server: address: Any def __init__( - self, registry: dict[str, Tuple[Callable[..., Any], Any, Any, Any]], address: Any, authkey: bytes, serializer: str + 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: ... diff --git a/mypy/typeshed/stdlib/multiprocessing/pool.pyi b/mypy/typeshed/stdlib/multiprocessing/pool.pyi index 20cfc59633d5..75583aae8012 100644 --- a/mypy/typeshed/stdlib/multiprocessing/pool.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/pool.pyi @@ -1,6 +1,6 @@ import sys from _typeshed import Self -from typing import Any, Callable, ContextManager, Dict, Generic, Iterable, Iterator, List, Mapping, TypeVar +from typing import Any, Callable, ContextManager, Generic, Iterable, Iterator, List, Mapping, TypeVar if sys.version_info >= (3, 9): from types import GenericAlias @@ -17,7 +17,7 @@ class ApplyResult(Generic[_T]): else: def __init__( self, - cache: Dict[int, ApplyResult[Any]], + cache: dict[int, ApplyResult[Any]], callback: Callable[[_T], None] | None, error_callback: Callable[[BaseException], None] | None, ) -> None: ... @@ -38,16 +38,16 @@ class MapResult(ApplyResult[List[_T]]): pool: Pool, chunksize: int, length: int, - callback: Callable[[List[_T]], None] | None, + callback: Callable[[list[_T]], None] | None, error_callback: Callable[[BaseException], None] | None, ) -> None: ... else: def __init__( self, - cache: Dict[int, ApplyResult[Any]], + cache: dict[int, ApplyResult[Any]], chunksize: int, length: int, - callback: Callable[[List[_T]], None] | None, + callback: Callable[[list[_T]], None] | None, error_callback: Callable[[BaseException], None] | None, ) -> None: ... @@ -55,7 +55,7 @@ class IMapIterator(Iterator[_T]): if sys.version_info >= (3, 8): def __init__(self, pool: Pool) -> None: ... else: - def __init__(self, cache: Dict[int, IMapIterator[Any]]) -> None: ... + def __init__(self, cache: dict[int, IMapIterator[Any]]) -> None: ... def __iter__(self: _S) -> _S: ... def next(self, timeout: float | None = ...) -> _T: ... def __next__(self, timeout: float | None = ...) -> _T: ... diff --git a/mypy/typeshed/stdlib/multiprocessing/process.pyi b/mypy/typeshed/stdlib/multiprocessing/process.pyi index 249ff712e05f..32c22d19f6e5 100644 --- a/mypy/typeshed/stdlib/multiprocessing/process.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/process.pyi @@ -5,6 +5,7 @@ class BaseProcess: name: str daemon: bool authkey: bytes + _identity: Tuple[int, ...] # undocumented def __init__( self, group: None = ..., diff --git a/mypy/typeshed/stdlib/multiprocessing/shared_memory.pyi b/mypy/typeshed/stdlib/multiprocessing/shared_memory.pyi index 47669aa4bcb5..6ffc2542087a 100644 --- a/mypy/typeshed/stdlib/multiprocessing/shared_memory.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/shared_memory.pyi @@ -23,7 +23,7 @@ if sys.version_info >= (3, 8): def __init__(self, sequence: Iterable[_SLT] | None = ..., *, name: str | None = ...) -> None: ... def __getitem__(self, position: int) -> _SLT: ... def __setitem__(self, position: int, value: _SLT) -> None: ... - def __reduce__(self: _S) -> Tuple[_S, Tuple[_SLT, ...]]: ... + def __reduce__(self: _S) -> tuple[_S, Tuple[_SLT, ...]]: ... def __len__(self) -> int: ... @property def format(self) -> str: ... diff --git a/mypy/typeshed/stdlib/nntplib.pyi b/mypy/typeshed/stdlib/nntplib.pyi index 4acb8b210a7a..508b5f679bc3 100644 --- a/mypy/typeshed/stdlib/nntplib.pyi +++ b/mypy/typeshed/stdlib/nntplib.pyi @@ -54,30 +54,30 @@ class _NNTPBase: def getcapabilities(self) -> dict[str, _list[str]]: ... def set_debuglevel(self, level: int) -> None: ... def debug(self, level: int) -> None: ... - def capabilities(self) -> Tuple[str, dict[str, _list[str]]]: ... - def newgroups(self, date: datetime.date | datetime.datetime, *, file: _File = ...) -> Tuple[str, _list[str]]: ... - def newnews(self, group: str, date: datetime.date | datetime.datetime, *, file: _File = ...) -> Tuple[str, _list[str]]: ... - def list(self, group_pattern: str | None = ..., *, file: _File = ...) -> Tuple[str, _list[str]]: ... + def capabilities(self) -> tuple[str, dict[str, _list[str]]]: ... + def newgroups(self, date: datetime.date | datetime.datetime, *, file: _File = ...) -> tuple[str, _list[str]]: ... + def newnews(self, group: str, date: datetime.date | datetime.datetime, *, file: _File = ...) -> tuple[str, _list[str]]: ... + def list(self, group_pattern: str | None = ..., *, file: _File = ...) -> tuple[str, _list[str]]: ... def description(self, group: str) -> str: ... - def descriptions(self, group_pattern: str) -> Tuple[str, dict[str, str]]: ... - def group(self, name: str) -> Tuple[str, int, int, int, str]: ... - def help(self, *, file: _File = ...) -> Tuple[str, _list[str]]: ... - def stat(self, message_spec: Any = ...) -> Tuple[str, int, str]: ... - def next(self) -> Tuple[str, int, str]: ... - def last(self) -> Tuple[str, int, str]: ... - def head(self, message_spec: Any = ..., *, file: _File = ...) -> Tuple[str, ArticleInfo]: ... - def body(self, message_spec: Any = ..., *, file: _File = ...) -> Tuple[str, ArticleInfo]: ... - def article(self, message_spec: Any = ..., *, file: _File = ...) -> Tuple[str, ArticleInfo]: ... + def descriptions(self, group_pattern: str) -> tuple[str, dict[str, str]]: ... + def group(self, name: str) -> tuple[str, int, int, int, str]: ... + def help(self, *, file: _File = ...) -> tuple[str, _list[str]]: ... + def stat(self, message_spec: Any = ...) -> tuple[str, int, str]: ... + def next(self) -> tuple[str, int, str]: ... + def last(self) -> tuple[str, int, str]: ... + def head(self, message_spec: Any = ..., *, file: _File = ...) -> tuple[str, ArticleInfo]: ... + def body(self, message_spec: Any = ..., *, file: _File = ...) -> tuple[str, ArticleInfo]: ... + def article(self, message_spec: Any = ..., *, file: _File = ...) -> tuple[str, ArticleInfo]: ... def slave(self) -> str: ... - def xhdr(self, hdr: str, str: Any, *, file: _File = ...) -> Tuple[str, _list[str]]: ... - def xover(self, start: int, end: int, *, file: _File = ...) -> Tuple[str, _list[Tuple[int, dict[str, str]]]]: ... + def xhdr(self, hdr: str, str: Any, *, file: _File = ...) -> tuple[str, _list[str]]: ... + def xover(self, start: int, end: int, *, file: _File = ...) -> tuple[str, _list[tuple[int, dict[str, str]]]]: ... def over( self, message_spec: None | str | _list[Any] | Tuple[Any, ...], *, file: _File = ... - ) -> Tuple[str, _list[Tuple[int, dict[str, str]]]]: ... + ) -> tuple[str, _list[tuple[int, dict[str, str]]]]: ... if sys.version_info < (3, 9): - def xgtitle(self, group: str, *, file: _File = ...) -> Tuple[str, _list[Tuple[str, str]]]: ... - def xpath(self, id: Any) -> Tuple[str, str]: ... - def date(self) -> Tuple[str, datetime.datetime]: ... + def xgtitle(self, group: str, *, file: _File = ...) -> tuple[str, _list[tuple[str, str]]]: ... + def xpath(self, id: Any) -> tuple[str, str]: ... + def date(self) -> tuple[str, datetime.datetime]: ... def post(self, data: bytes | Iterable[bytes]) -> str: ... def ihave(self, message_id: Any, data: bytes | Iterable[bytes]) -> str: ... def quit(self) -> str: ... diff --git a/mypy/typeshed/stdlib/ntpath.pyi b/mypy/typeshed/stdlib/ntpath.pyi index d454d7f93fbf..45d715704157 100644 --- a/mypy/typeshed/stdlib/ntpath.pyi +++ b/mypy/typeshed/stdlib/ntpath.pyi @@ -42,11 +42,11 @@ from posixpath import ( splitext as splitext, supports_unicode_filenames as supports_unicode_filenames, ) -from typing import AnyStr, Tuple, overload +from typing import AnyStr, overload altsep: str if sys.version_info < (3, 7) and sys.platform == "win32": - def splitunc(p: AnyStr) -> Tuple[AnyStr, AnyStr]: ... # deprecated + def splitunc(p: AnyStr) -> tuple[AnyStr, AnyStr]: ... # deprecated # Similar to posixpath, but have slightly different argument names @overload diff --git a/mypy/typeshed/stdlib/operator.pyi b/mypy/typeshed/stdlib/operator.pyi index c9fe47c4a70f..bb8e23733f87 100644 --- a/mypy/typeshed/stdlib/operator.pyi +++ b/mypy/typeshed/stdlib/operator.pyi @@ -11,6 +11,7 @@ from typing import ( TypeVar, overload, ) +from typing_extensions import final _T = TypeVar("_T") _T_co = TypeVar("_T_co", covariant=True) @@ -115,33 +116,35 @@ 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: Any, __default: int = ...) -> 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]]: ... + 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]]: ... + 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]]: ... + 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: Any) -> itemgetter[Any]: ... @overload - def __new__(cls, item: Any, __item2: Any) -> itemgetter[Tuple[Any, Any]]: ... + def __new__(cls, item: Any, __item2: Any) -> itemgetter[tuple[Any, Any]]: ... @overload - def __new__(cls, item: Any, __item2: Any, __item3: Any) -> itemgetter[Tuple[Any, Any, Any]]: ... + def __new__(cls, item: Any, __item2: Any, __item3: Any) -> itemgetter[tuple[Any, Any, Any]]: ... @overload - def __new__(cls, item: Any, __item2: Any, __item3: Any, __item4: Any) -> itemgetter[Tuple[Any, Any, Any, Any]]: ... + def __new__(cls, item: Any, __item2: Any, __item3: Any, __item4: Any) -> itemgetter[tuple[Any, Any, Any, Any]]: ... @overload def __new__(cls, item: Any, *items: Any) -> itemgetter[Tuple[Any, ...]]: ... def __call__(self, obj: Any) -> _T_co: ... +@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 38c7746a9ff8..b8ea9d2fff38 100644 --- a/mypy/typeshed/stdlib/optparse.pyi +++ b/mypy/typeshed/stdlib/optparse.pyi @@ -201,7 +201,7 @@ class OptionParser(OptionContainer): def add_option_group(self, __opt_group: OptionGroup) -> OptionGroup: ... @overload def add_option_group(self, *args: Any, **kwargs: Any) -> OptionGroup: ... - def check_values(self, values: Values, args: list[str]) -> Tuple[Values, list[str]]: ... + def check_values(self, values: Values, args: list[str]) -> tuple[Values, list[str]]: ... def disable_interspersed_args(self) -> None: ... def enable_interspersed_args(self) -> None: ... def error(self, msg: str) -> None: ... @@ -215,7 +215,7 @@ class OptionParser(OptionContainer): def get_prog_name(self) -> str: ... def get_usage(self) -> str: ... def get_version(self) -> str: ... - def parse_args(self, args: Sequence[AnyStr] | None = ..., values: Values | None = ...) -> Tuple[Values, list[AnyStr]]: ... + def parse_args(self, args: Sequence[AnyStr] | None = ..., values: Values | None = ...) -> tuple[Values, list[AnyStr]]: ... def print_usage(self, file: IO[str] | None = ...) -> None: ... def print_help(self, file: IO[str] | None = ...) -> None: ... def print_version(self, file: IO[str] | None = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/os/__init__.pyi b/mypy/typeshed/stdlib/os/__init__.pyi index 9af9aa34a6ca..d65681a46c3f 100644 --- a/mypy/typeshed/stdlib/os/__init__.pyi +++ b/mypy/typeshed/stdlib/os/__init__.pyi @@ -30,14 +30,13 @@ from typing import ( NoReturn, Protocol, Sequence, - Set, Tuple, TypeVar, Union, overload, runtime_checkable, ) -from typing_extensions import Literal +from typing_extensions import Literal, final from . import path as _path @@ -56,10 +55,10 @@ error = OSError supports_bytes_environ: bool -supports_dir_fd: Set[Callable[..., Any]] -supports_fd: Set[Callable[..., Any]] -supports_effective_ids: Set[Callable[..., Any]] -supports_follow_symlinks: Set[Callable[..., Any]] +supports_dir_fd: set[Callable[..., Any]] +supports_fd: set[Callable[..., Any]] +supports_effective_ids: set[Callable[..., Any]] +supports_follow_symlinks: set[Callable[..., Any]] if sys.platform != "win32": # Unix only @@ -262,6 +261,7 @@ if sys.platform != "win32": TMP_MAX: int # Undocumented, but used by tempfile # ----- os classes (structures) ----- +@final class stat_result: # For backward compatibility, the return value of stat() is also # accessible as a tuple of at least 10 integers giving the most important @@ -309,13 +309,12 @@ class stat_result: @runtime_checkable class PathLike(Protocol[_AnyStr_co]): def __fspath__(self) -> _AnyStr_co: ... - if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any) -> GenericAlias: ... _FdOrAnyPath = Union[int, StrOrBytesPath] +@final class DirEntry(Generic[AnyStr]): - # This is what the scandir interator yields + # This is what the scandir iterator yields # The constructor is hidden name: AnyStr @@ -334,6 +333,7 @@ if sys.platform != "win32": _Tuple11Int = Tuple[int, int, int, int, int, int, int, int, int, int, int] if sys.version_info >= (3, 7): # f_fsid was added in https://github.com/python/cpython/pull/4571 + @final class statvfs_result(_Tuple10Int): # Unix only def __new__(cls, seq: _Tuple10Int | _Tuple11Int, dict: dict[str, int] = ...) -> statvfs_result: ... n_fields: int @@ -398,8 +398,8 @@ if sys.platform != "win32": def getpriority(which: int, who: int) -> int: ... def setpriority(which: int, who: int, priority: int) -> None: ... if sys.platform != "darwin": - def getresuid() -> Tuple[int, int, int]: ... - def getresgid() -> Tuple[int, int, int]: ... + def getresuid() -> tuple[int, int, int]: ... + def getresgid() -> tuple[int, int, int]: ... def getuid() -> int: ... def setegid(__egid: int) -> None: ... def seteuid(__euid: int) -> None: ... @@ -528,7 +528,7 @@ def fstat(fd: int) -> stat_result: ... def fsync(fd: FileDescriptorLike) -> None: ... def lseek(__fd: int, __position: int, __how: int) -> int: ... def open(path: StrOrBytesPath, flags: int, mode: int = ..., *, dir_fd: int | None = ...) -> int: ... -def pipe() -> Tuple[int, int]: ... +def pipe() -> tuple[int, int]: ... def read(__fd: int, __length: int) -> bytes: ... if sys.platform != "win32": @@ -544,9 +544,9 @@ if sys.platform != "win32": def set_blocking(__fd: int, __blocking: bool) -> None: ... def isatty(__fd: int) -> bool: ... def lockf(__fd: int, __command: int, __length: int) -> None: ... - def openpty() -> Tuple[int, int]: ... # some flavors of Unix + def openpty() -> tuple[int, int]: ... # some flavors of Unix if sys.platform != "darwin": - def pipe2(flags: int) -> Tuple[int, int]: ... # some flavors of Unix + def pipe2(flags: int) -> tuple[int, int]: ... # some flavors of Unix def posix_fallocate(fd: int, offset: int, length: int) -> None: ... def posix_fadvise(fd: int, offset: int, length: int, advice: int) -> None: ... def pread(__fd: int, __length: int, __offset: int) -> bytes: ... @@ -566,6 +566,7 @@ if sys.platform != "win32": def readv(__fd: int, __buffers: Sequence[bytearray]) -> int: ... def writev(__fd: int, __buffers: Sequence[bytes]) -> int: ... +@final class terminal_size(Tuple[int, int]): columns: int lines: int @@ -675,9 +676,9 @@ def truncate(path: _FdOrAnyPath, length: int) -> None: ... # Unix only up to ve def unlink(path: StrOrBytesPath, *, dir_fd: int | None = ...) -> None: ... def utime( path: _FdOrAnyPath, - times: Tuple[int, int] | Tuple[float, float] | None = ..., + times: tuple[int, int] | tuple[float, float] | None = ..., *, - ns: Tuple[int, int] = ..., + ns: tuple[int, int] = ..., dir_fd: int | None = ..., follow_symlinks: bool = ..., ) -> None: ... @@ -686,7 +687,7 @@ _OnError = Callable[[OSError], Any] def walk( top: AnyStr | PathLike[AnyStr], topdown: bool = ..., onerror: _OnError | None = ..., followlinks: bool = ... -) -> Iterator[Tuple[AnyStr, list[AnyStr], list[AnyStr]]]: ... +) -> Iterator[tuple[AnyStr, list[AnyStr], list[AnyStr]]]: ... if sys.platform != "win32": if sys.version_info >= (3, 7): @@ -698,7 +699,7 @@ if sys.platform != "win32": *, follow_symlinks: bool = ..., dir_fd: int | None = ..., - ) -> Iterator[Tuple[str, list[str], list[str], int]]: ... + ) -> Iterator[tuple[str, list[str], list[str], int]]: ... @overload def fwalk( top: bytes, @@ -707,7 +708,7 @@ if sys.platform != "win32": *, follow_symlinks: bool = ..., dir_fd: int | None = ..., - ) -> Iterator[Tuple[bytes, list[bytes], list[bytes], int]]: ... + ) -> Iterator[tuple[bytes, list[bytes], list[bytes], int]]: ... else: def fwalk( top: StrPath = ..., @@ -716,7 +717,7 @@ if sys.platform != "win32": *, follow_symlinks: bool = ..., dir_fd: int | None = ..., - ) -> Iterator[Tuple[str, list[str], list[str], int]]: ... + ) -> Iterator[tuple[str, list[str], list[str], int]]: ... if sys.platform == "linux": def getxattr(path: _FdOrAnyPath, attribute: StrOrBytesPath, *, follow_symlinks: bool = ...) -> bytes: ... def listxattr(path: _FdOrAnyPath | None = ..., *, follow_symlinks: bool = ...) -> list[str]: ... @@ -762,7 +763,7 @@ def kill(__pid: int, __signal: int) -> None: ... if sys.platform != "win32": # Unix only def fork() -> int: ... - def forkpty() -> Tuple[int, int]: ... # some flavors of Unix + def forkpty() -> tuple[int, int]: ... # some flavors of Unix def killpg(__pgid: int, __signal: int) -> None: ... def nice(__increment: int) -> int: ... if sys.platform != "darwin": @@ -786,7 +787,7 @@ else: def system(command: StrOrBytesPath) -> int: ... def times() -> times_result: ... -def waitpid(__pid: int, __options: int) -> Tuple[int, int]: ... +def waitpid(__pid: int, __options: int) -> tuple[int, int]: ... if sys.platform == "win32": def startfile(path: StrOrBytesPath, operation: str | None = ...) -> None: ... @@ -797,12 +798,12 @@ else: def spawnlpe(mode: int, file: StrOrBytesPath, arg0: StrOrBytesPath, *args: Any) -> int: ... # Imprecise signature def spawnvp(mode: int, file: StrOrBytesPath, args: _ExecVArgs) -> int: ... def spawnvpe(mode: int, file: StrOrBytesPath, args: _ExecVArgs, env: _ExecEnv) -> int: ... - def wait() -> Tuple[int, int]: ... # Unix only + def wait() -> tuple[int, int]: ... # Unix only if sys.platform != "darwin": from posix import waitid_result def waitid(idtype: int, ident: int, options: int) -> waitid_result: ... - def wait3(options: int) -> Tuple[int, int, Any]: ... - def wait4(pid: int, options: int) -> Tuple[int, int, Any]: ... + def wait3(options: int) -> tuple[int, int, Any]: ... + def wait4(pid: int, options: int) -> tuple[int, int, Any]: ... def WCOREDUMP(__status: int) -> bool: ... def WIFCONTINUED(status: int) -> bool: ... def WIFSTOPPED(status: int) -> bool: ... @@ -826,14 +827,14 @@ if sys.platform != "win32": def sched_setparam(pid: int, param: sched_param) -> None: ... # some flavors of Unix def sched_getparam(pid: int) -> sched_param: ... # some flavors of Unix def sched_setaffinity(pid: int, mask: Iterable[int]) -> None: ... # some flavors of Unix - def sched_getaffinity(pid: int) -> Set[int]: ... # some flavors of Unix + def sched_getaffinity(pid: int) -> set[int]: ... # some flavors of Unix def cpu_count() -> int | None: ... if sys.platform != "win32": # Unix only def confstr(__name: str | int) -> str | None: ... - def getloadavg() -> Tuple[float, float, float]: ... + def getloadavg() -> tuple[float, float, float]: ... def sysconf(__name: str | int) -> int: ... if sys.platform == "linux": diff --git a/mypy/typeshed/stdlib/parser.pyi b/mypy/typeshed/stdlib/parser.pyi index cefcad5b08f1..aecf3244ca8d 100644 --- a/mypy/typeshed/stdlib/parser.pyi +++ b/mypy/typeshed/stdlib/parser.pyi @@ -7,7 +7,7 @@ def suite(source: str) -> STType: ... def sequence2st(sequence: Sequence[Any]) -> STType: ... def tuple2st(sequence: Sequence[Any]) -> STType: ... def st2list(st: STType, line_info: bool = ..., col_info: bool = ...) -> list[Any]: ... -def st2tuple(st: STType, line_info: bool = ..., col_info: bool = ...) -> Tuple[Any]: ... +def st2tuple(st: STType, line_info: bool = ..., col_info: bool = ...) -> Tuple[Any, ...]: ... def compilest(st: STType, filename: StrOrBytesPath = ...) -> CodeType: ... def isexpr(st: STType) -> bool: ... def issuite(st: STType) -> bool: ... @@ -19,4 +19,4 @@ class STType: def isexpr(self) -> bool: ... def issuite(self) -> bool: ... def tolist(self, line_info: bool = ..., col_info: bool = ...) -> list[Any]: ... - def totuple(self, line_info: bool = ..., col_info: bool = ...) -> Tuple[Any]: ... + def totuple(self, line_info: bool = ..., col_info: bool = ...) -> Tuple[Any, ...]: ... diff --git a/mypy/typeshed/stdlib/pathlib.pyi b/mypy/typeshed/stdlib/pathlib.pyi index db1dff36bd8c..7d5f7ff2dba8 100644 --- a/mypy/typeshed/stdlib/pathlib.pyi +++ b/mypy/typeshed/stdlib/pathlib.pyi @@ -68,8 +68,12 @@ class Path(PurePath): ) -> bool | None: ... @classmethod def cwd(cls: Type[_P]) -> _P: ... - def stat(self) -> stat_result: ... - def chmod(self, mode: int) -> None: ... + if sys.version_info >= (3, 10): + def stat(self, *, follow_symlinks: bool = ...) -> stat_result: ... + def chmod(self, mode: int, *, follow_symlinks: bool = ...) -> None: ... + else: + def stat(self) -> stat_result: ... + def chmod(self, mode: int) -> None: ... def exists(self) -> bool: ... def glob(self: _P, pattern: str) -> Generator[_P, None, None]: ... def group(self) -> str: ... @@ -88,6 +92,7 @@ class Path(PurePath): def mkdir(self, mode: int = ..., parents: bool = ..., exist_ok: bool = ...) -> None: ... # Adapted from builtins.open # Text mode: always returns a TextIOWrapper + # The Traversable .open in stdlib/importlib/abc.pyi should be kept in sync with this. @overload def open( self, @@ -153,6 +158,8 @@ class Path(PurePath): def rglob(self: _P, pattern: str) -> Generator[_P, None, None]: ... def rmdir(self) -> None: ... def symlink_to(self, target: str | Path, target_is_directory: bool = ...) -> None: ... + if sys.version_info >= (3, 10): + def hardlink_to(self, target: str | Path) -> None: ... def touch(self, mode: int = ..., exist_ok: bool = ...) -> None: ... if sys.version_info >= (3, 8): def unlink(self, missing_ok: bool = ...) -> None: ... @@ -166,7 +173,12 @@ class Path(PurePath): def read_text(self, encoding: str | None = ..., errors: str | None = ...) -> str: ... def samefile(self, other_path: str | bytes | int | Path) -> bool: ... def write_bytes(self, data: bytes) -> int: ... - def write_text(self, data: str, encoding: str | None = ..., errors: str | None = ...) -> int: ... + if sys.version_info >= (3, 10): + def write_text( + self, data: str, encoding: str | None = ..., errors: str | None = ..., newline: str | None = ... + ) -> int: ... + else: + def write_text(self, data: str, encoding: str | None = ..., errors: str | None = ...) -> int: ... if sys.version_info >= (3, 8): def link_to(self, target: StrPath | bytes) -> None: ... diff --git a/mypy/typeshed/stdlib/pdb.pyi b/mypy/typeshed/stdlib/pdb.pyi index 0a25786d409f..83bd32d76450 100644 --- a/mypy/typeshed/stdlib/pdb.pyi +++ b/mypy/typeshed/stdlib/pdb.pyi @@ -4,7 +4,7 @@ from bdb import Bdb from cmd import Cmd from inspect import _SourceObjectType from types import CodeType, FrameType, TracebackType -from typing import IO, Any, Callable, ClassVar, Iterable, Mapping, Sequence, Tuple, TypeVar +from typing import IO, Any, Callable, ClassVar, Iterable, Mapping, Sequence, TypeVar _T = TypeVar("_T") @@ -41,7 +41,7 @@ class Pdb(Bdb, Cmd): commands_defining: bool commands_bnum: int | None lineno: int | None - stack: list[Tuple[FrameType, int]] + stack: list[tuple[FrameType, int]] curindex: int curframe: FrameType | None curframe_locals: Mapping[str, Any] @@ -62,11 +62,11 @@ class Pdb(Bdb, Cmd): def displayhook(self, obj: object) -> None: ... def handle_command_def(self, line: str) -> bool: ... def defaultFile(self) -> str: ... - def lineinfo(self, identifier: str) -> Tuple[None, None, None] | Tuple[str, str, int]: ... + def lineinfo(self, identifier: str) -> tuple[None, None, None] | tuple[str, str, int]: ... def checkline(self, filename: str, lineno: int) -> int: ... def _getval(self, arg: str) -> object: ... def print_stack_trace(self) -> None: ... - def print_stack_entry(self, frame_lineno: Tuple[FrameType, int], prompt_prefix: str = ...) -> None: ... + def print_stack_entry(self, frame_lineno: tuple[FrameType, int], prompt_prefix: str = ...) -> None: ... def lookupmodule(self, filename: str) -> str | None: ... def _runscript(self, filename: str) -> None: ... def do_commands(self, arg: str) -> bool | None: ... @@ -164,10 +164,10 @@ class Pdb(Bdb, Cmd): # undocumented -def find_function(funcname: str, filename: str) -> Tuple[str, str, int] | None: ... +def find_function(funcname: str, filename: str) -> tuple[str, str, int] | None: ... def main() -> None: ... def help() -> None: ... -def getsourcelines(obj: _SourceObjectType) -> Tuple[list[str], int]: ... +def getsourcelines(obj: _SourceObjectType) -> tuple[list[str], int]: ... def lasti2lineno(code: CodeType, lasti: int) -> int: ... class _rstr(str): diff --git a/mypy/typeshed/stdlib/pickle.pyi b/mypy/typeshed/stdlib/pickle.pyi index 19564f31178e..cef1ffe9eb9b 100644 --- a/mypy/typeshed/stdlib/pickle.pyi +++ b/mypy/typeshed/stdlib/pickle.pyi @@ -1,13 +1,22 @@ import sys -from typing import IO, Any, Callable, ClassVar, Iterable, Iterator, Mapping, Optional, Tuple, Type, Union +from typing import Any, Callable, ClassVar, Iterable, Iterator, Mapping, Optional, Protocol, Tuple, Type, Union +from typing_extensions import final HIGHEST_PROTOCOL: int DEFAULT_PROTOCOL: int bytes_types: Tuple[Type[Any], ...] # undocumented +class _ReadableFileobj(Protocol): + def read(self, __n: int) -> bytes: ... + def readline(self) -> bytes: ... + +class _WritableFileobj(Protocol): + def write(self, __b: bytes) -> Any: ... + if sys.version_info >= (3, 8): # TODO: holistic design for buffer interface (typing.Buffer?) + @final class PickleBuffer: # buffer must be a buffer-providing object def __init__(self, buffer: Any) -> None: ... @@ -15,22 +24,32 @@ if sys.version_info >= (3, 8): def release(self) -> None: ... _BufferCallback = Optional[Callable[[PickleBuffer], Any]] def dump( - obj: Any, file: IO[bytes], protocol: int | None = ..., *, fix_imports: bool = ..., buffer_callback: _BufferCallback = ... + obj: Any, + file: _WritableFileobj, + protocol: int | None = ..., + *, + fix_imports: bool = ..., + buffer_callback: _BufferCallback = ..., ) -> None: ... def dumps( obj: Any, protocol: int | None = ..., *, fix_imports: bool = ..., buffer_callback: _BufferCallback = ... ) -> bytes: ... def load( - file: IO[bytes], *, fix_imports: bool = ..., encoding: str = ..., errors: str = ..., buffers: Iterable[Any] | None = ... + file: _ReadableFileobj, + *, + fix_imports: bool = ..., + encoding: str = ..., + errors: str = ..., + buffers: Iterable[Any] | None = ..., ) -> Any: ... def loads( __data: bytes, *, fix_imports: bool = ..., encoding: str = ..., errors: str = ..., buffers: Iterable[Any] | None = ... ) -> Any: ... else: - def dump(obj: Any, file: IO[bytes], protocol: int | None = ..., *, fix_imports: bool = ...) -> None: ... + def dump(obj: Any, file: _WritableFileobj, protocol: int | None = ..., *, fix_imports: bool = ...) -> None: ... def dumps(obj: Any, protocol: int | None = ..., *, fix_imports: bool = ...) -> bytes: ... - def load(file: IO[bytes], *, fix_imports: bool = ..., encoding: str = ..., errors: str = ...) -> Any: ... + def load(file: _ReadableFileobj, *, fix_imports: bool = ..., encoding: str = ..., errors: str = ...) -> Any: ... def loads(data: bytes, *, fix_imports: bool = ..., encoding: str = ..., errors: str = ...) -> Any: ... class PickleError(Exception): ... @@ -53,11 +72,16 @@ class Pickler: if sys.version_info >= (3, 8): def __init__( - self, file: IO[bytes], protocol: int | None = ..., *, fix_imports: bool = ..., buffer_callback: _BufferCallback = ... + self, + file: _WritableFileobj, + protocol: int | None = ..., + *, + fix_imports: bool = ..., + buffer_callback: _BufferCallback = ..., ) -> None: ... def reducer_override(self, obj: Any) -> Any: ... else: - def __init__(self, file: IO[bytes], protocol: int | None = ..., *, fix_imports: bool = ...) -> None: ... + def __init__(self, file: _WritableFileobj, protocol: int | None = ..., *, fix_imports: bool = ...) -> None: ... def dump(self, __obj: Any) -> None: ... def clear_memo(self) -> None: ... def persistent_id(self, obj: Any) -> Any: ... @@ -68,7 +92,7 @@ class Unpickler: if sys.version_info >= (3, 8): def __init__( self, - file: IO[bytes], + file: _ReadableFileobj, *, fix_imports: bool = ..., encoding: str = ..., @@ -76,7 +100,9 @@ class Unpickler: buffers: Iterable[Any] | None = ..., ) -> None: ... else: - def __init__(self, file: IO[bytes], *, fix_imports: bool = ..., encoding: str = ..., errors: str = ...) -> None: ... + def __init__( + self, file: _ReadableFileobj, *, fix_imports: bool = ..., encoding: str = ..., errors: str = ... + ) -> None: ... def load(self) -> Any: ... def find_class(self, __module_name: str, __global_name: str) -> Any: ... def persistent_load(self, pid: Any) -> Any: ... diff --git a/mypy/typeshed/stdlib/pickletools.pyi b/mypy/typeshed/stdlib/pickletools.pyi index 0f0fb47da5f9..9fa51a3848ee 100644 --- a/mypy/typeshed/stdlib/pickletools.pyi +++ b/mypy/typeshed/stdlib/pickletools.pyi @@ -152,7 +152,7 @@ class OpcodeInfo(object): opcodes: list[OpcodeInfo] -def genops(pickle: bytes | IO[bytes]) -> Iterator[Tuple[OpcodeInfo, Any | None, int | None]]: ... +def genops(pickle: bytes | IO[bytes]) -> Iterator[tuple[OpcodeInfo, Any | None, int | None]]: ... def optimize(p: bytes | IO[bytes]) -> bytes: ... def dis( pickle: bytes | IO[bytes], diff --git a/mypy/typeshed/stdlib/pkgutil.pyi b/mypy/typeshed/stdlib/pkgutil.pyi index 54e0f22e4915..e0f392fd91d8 100644 --- a/mypy/typeshed/stdlib/pkgutil.pyi +++ b/mypy/typeshed/stdlib/pkgutil.pyi @@ -1,7 +1,7 @@ import sys from _typeshed import SupportsRead from importlib.abc import Loader, MetaPathFinder, PathEntryFinder -from typing import IO, Any, Callable, Iterable, Iterator, NamedTuple, Tuple +from typing import IO, Any, Callable, Iterable, Iterator, NamedTuple class ModuleInfo(NamedTuple): module_finder: MetaPathFinder | PathEntryFinder @@ -14,7 +14,7 @@ class ImpImporter: def __init__(self, path: str | None = ...) -> None: ... class ImpLoader: - def __init__(self, fullname: str, file: IO[str], filename: str, etc: Tuple[str, str, int]) -> None: ... + def __init__(self, fullname: str, file: IO[str], filename: str, etc: tuple[str, str, int]) -> None: ... def find_loader(fullname: str) -> Loader | None: ... def get_importer(path_item: str) -> PathEntryFinder | None: ... diff --git a/mypy/typeshed/stdlib/platform.pyi b/mypy/typeshed/stdlib/platform.pyi index d0f08a20fcd6..7db2d59ff7ea 100644 --- a/mypy/typeshed/stdlib/platform.pyi +++ b/mypy/typeshed/stdlib/platform.pyi @@ -7,10 +7,10 @@ if sys.version_info < (3, 8): from typing import NamedTuple, Tuple if sys.version_info >= (3, 8): - def libc_ver(executable: str | None = ..., lib: str = ..., version: str = ..., chunksize: int = ...) -> Tuple[str, str]: ... + def libc_ver(executable: str | None = ..., lib: str = ..., version: str = ..., chunksize: int = ...) -> tuple[str, str]: ... else: - def libc_ver(executable: str = ..., lib: str = ..., version: str = ..., chunksize: int = ...) -> Tuple[str, str]: ... + def libc_ver(executable: str = ..., lib: str = ..., version: str = ..., chunksize: int = ...) -> tuple[str, str]: ... if sys.version_info < (3, 8): def linux_distribution( @@ -19,25 +19,25 @@ if sys.version_info < (3, 8): id: str = ..., supported_dists: Tuple[str, ...] = ..., full_distribution_name: bool = ..., - ) -> Tuple[str, str, str]: ... + ) -> tuple[str, str, str]: ... def dist( distname: str = ..., version: str = ..., id: str = ..., supported_dists: Tuple[str, ...] = ... - ) -> Tuple[str, str, str]: ... + ) -> tuple[str, str, str]: ... -def win32_ver(release: str = ..., version: str = ..., csd: str = ..., ptype: str = ...) -> Tuple[str, str, str, str]: ... +def win32_ver(release: str = ..., version: str = ..., csd: str = ..., ptype: str = ...) -> tuple[str, str, str, str]: ... if sys.version_info >= (3, 8): def win32_edition() -> str: ... def win32_is_iot() -> bool: ... def mac_ver( - release: str = ..., versioninfo: Tuple[str, str, str] = ..., machine: str = ... -) -> Tuple[str, Tuple[str, str, str], str]: ... + release: str = ..., versioninfo: tuple[str, str, str] = ..., machine: str = ... +) -> tuple[str, tuple[str, str, str], str]: ... def java_ver( - release: str = ..., vendor: str = ..., vminfo: Tuple[str, str, str] = ..., osinfo: Tuple[str, str, str] = ... -) -> Tuple[str, str, Tuple[str, str, str], Tuple[str, str, str]]: ... -def system_alias(system: str, release: str, version: str) -> Tuple[str, str, str]: ... -def architecture(executable: str = ..., bits: str = ..., linkage: str = ...) -> Tuple[str, str]: ... + release: str = ..., vendor: str = ..., vminfo: tuple[str, str, str] = ..., osinfo: tuple[str, str, str] = ... +) -> tuple[str, str, tuple[str, str, str], tuple[str, str, str]]: ... +def system_alias(system: str, release: str, version: str) -> tuple[str, str, str]: ... +def architecture(executable: str = ..., bits: str = ..., linkage: str = ...) -> tuple[str, str]: ... class uname_result(NamedTuple): system: str @@ -56,9 +56,9 @@ def machine() -> str: ... def processor() -> str: ... def python_implementation() -> str: ... def python_version() -> str: ... -def python_version_tuple() -> Tuple[str, str, str]: ... +def python_version_tuple() -> tuple[str, str, str]: ... def python_branch() -> str: ... def python_revision() -> str: ... -def python_build() -> Tuple[str, str]: ... +def python_build() -> tuple[str, str]: ... def python_compiler() -> str: ... def platform(aliased: bool = ..., terse: bool = ...) -> str: ... diff --git a/mypy/typeshed/stdlib/plistlib.pyi b/mypy/typeshed/stdlib/plistlib.pyi index 3b5c2b78c81a..07b6963746be 100644 --- a/mypy/typeshed/stdlib/plistlib.pyi +++ b/mypy/typeshed/stdlib/plistlib.pyi @@ -1,6 +1,7 @@ import sys +from datetime import datetime from enum import Enum -from typing import IO, Any, Dict as _Dict, Mapping, MutableMapping, Type +from typing import IO, Any, Dict as _Dict, Mapping, MutableMapping, Tuple, Type class PlistFormat(Enum): FMT_XML: int @@ -30,9 +31,20 @@ else: ) -> Any: ... def dump( - value: Mapping[str, Any], fp: IO[bytes], *, fmt: PlistFormat = ..., sort_keys: bool = ..., skipkeys: bool = ... + value: Mapping[str, Any] | list[Any] | Tuple[Any, ...] | str | bool | float | bytes | datetime, + fp: IO[bytes], + *, + fmt: PlistFormat = ..., + sort_keys: bool = ..., + skipkeys: bool = ..., ) -> None: ... -def dumps(value: Mapping[str, Any], *, fmt: PlistFormat = ..., skipkeys: bool = ..., sort_keys: bool = ...) -> bytes: ... +def dumps( + value: Mapping[str, Any] | list[Any] | Tuple[Any, ...] | str | bool | float | bytes | datetime, + *, + fmt: PlistFormat = ..., + skipkeys: bool = ..., + sort_keys: bool = ..., +) -> bytes: ... if sys.version_info < (3, 9): def readPlist(pathOrFile: str | IO[bytes]) -> Any: ... diff --git a/mypy/typeshed/stdlib/poplib.pyi b/mypy/typeshed/stdlib/poplib.pyi index 8d19067f0445..28fba4ce951f 100644 --- a/mypy/typeshed/stdlib/poplib.pyi +++ b/mypy/typeshed/stdlib/poplib.pyi @@ -12,6 +12,8 @@ CR: bytes LF: bytes CRLF: bytes +_list = list # conflicts with a method named "list" + class POP3: encoding: str host: str @@ -24,7 +26,7 @@ class POP3: def set_debuglevel(self, level: int) -> None: ... def user(self, user: str) -> bytes: ... def pass_(self, pswd: str) -> bytes: ... - def stat(self) -> Tuple[int, int]: ... + def stat(self) -> tuple[int, int]: ... def list(self, which: Any | None = ...) -> _LongResp: ... def retr(self, which: Any) -> _LongResp: ... def dele(self, which: Any) -> bytes: ... @@ -41,7 +43,7 @@ class POP3: @overload def uidl(self, which: Any) -> bytes: ... def utf8(self) -> bytes: ... - def capa(self) -> dict[str, List[str]]: ... + def capa(self) -> dict[str, _list[str]]: ... def stls(self, context: ssl.SSLContext | None = ...) -> bytes: ... class POP3_SSL(POP3): diff --git a/mypy/typeshed/stdlib/posix.pyi b/mypy/typeshed/stdlib/posix.pyi index aef3b54413a4..14cea87cde29 100644 --- a/mypy/typeshed/stdlib/posix.pyi +++ b/mypy/typeshed/stdlib/posix.pyi @@ -2,7 +2,9 @@ import sys from _typeshed import StrOrBytesPath from os import PathLike, _ExecEnv, _ExecVArgs, stat_result as stat_result from typing import Any, Iterable, NamedTuple, Sequence, Tuple, overload +from typing_extensions import final +@final class uname_result(NamedTuple): sysname: str nodename: str @@ -10,6 +12,7 @@ class uname_result(NamedTuple): version: str machine: str +@final class times_result(NamedTuple): user: float system: float @@ -179,7 +182,7 @@ if sys.platform != "win32" and sys.version_info >= (3, 8): setsid: bool = ..., setsigmask: Iterable[int] = ..., setsigdef: Iterable[int] = ..., - scheduler: Tuple[Any, sched_param] | None = ..., + scheduler: tuple[Any, sched_param] | None = ..., ) -> int: ... def posix_spawnp( path: StrOrBytesPath, @@ -192,7 +195,7 @@ if sys.platform != "win32" and sys.version_info >= (3, 8): setsid: bool = ..., setsigmask: Iterable[int] = ..., setsigdef: Iterable[int] = ..., - scheduler: Tuple[Any, sched_param] | None = ..., + scheduler: tuple[Any, sched_param] | None = ..., ) -> int: ... if sys.platform == "win32": diff --git a/mypy/typeshed/stdlib/posixpath.pyi b/mypy/typeshed/stdlib/posixpath.pyi index cc5e5cb8ed50..ae3d0d5cc65f 100644 --- a/mypy/typeshed/stdlib/posixpath.pyi +++ b/mypy/typeshed/stdlib/posixpath.pyi @@ -14,7 +14,7 @@ from genericpath import ( samestat as samestat, ) from os import PathLike -from typing import AnyStr, Sequence, Tuple, overload +from typing import AnyStr, Sequence, overload supports_unicode_filenames: bool # aliases (also in os) @@ -82,18 +82,18 @@ def relpath(path: BytesPath, start: BytesPath | None = ...) -> bytes: ... @overload def relpath(path: StrPath, start: StrPath | None = ...) -> str: ... @overload -def split(p: PathLike[AnyStr]) -> Tuple[AnyStr, AnyStr]: ... +def split(p: PathLike[AnyStr]) -> tuple[AnyStr, AnyStr]: ... @overload -def split(p: AnyStr) -> Tuple[AnyStr, AnyStr]: ... +def split(p: AnyStr) -> tuple[AnyStr, AnyStr]: ... @overload -def splitdrive(p: PathLike[AnyStr]) -> Tuple[AnyStr, AnyStr]: ... +def splitdrive(p: PathLike[AnyStr]) -> tuple[AnyStr, AnyStr]: ... @overload -def splitdrive(p: AnyStr) -> Tuple[AnyStr, AnyStr]: ... +def splitdrive(p: AnyStr) -> tuple[AnyStr, AnyStr]: ... @overload -def splitext(p: PathLike[AnyStr]) -> Tuple[AnyStr, AnyStr]: ... +def splitext(p: PathLike[AnyStr]) -> tuple[AnyStr, AnyStr]: ... @overload -def splitext(p: AnyStr) -> Tuple[AnyStr, AnyStr]: ... +def splitext(p: AnyStr) -> tuple[AnyStr, AnyStr]: ... def isabs(s: StrOrBytesPath) -> bool: ... -def islink(path: StrOrBytesPath) -> bool: ... -def ismount(path: StrOrBytesPath) -> bool: ... -def lexists(path: StrOrBytesPath) -> bool: ... +def islink(path: StrOrBytesPath | int) -> bool: ... +def ismount(path: StrOrBytesPath | int) -> bool: ... +def lexists(path: StrOrBytesPath | int) -> bool: ... diff --git a/mypy/typeshed/stdlib/pprint.pyi b/mypy/typeshed/stdlib/pprint.pyi index dcf3fd6b81da..9e343feb49bc 100644 --- a/mypy/typeshed/stdlib/pprint.pyi +++ b/mypy/typeshed/stdlib/pprint.pyi @@ -1,5 +1,5 @@ import sys -from typing import IO, Any, Tuple +from typing import IO, Any if sys.version_info >= (3, 10): def pformat( @@ -130,4 +130,4 @@ class PrettyPrinter: def pprint(self, object: object) -> None: ... def isreadable(self, object: object) -> bool: ... def isrecursive(self, object: object) -> bool: ... - def format(self, object: object, context: dict[int, Any], maxlevels: int, level: int) -> Tuple[str, bool, bool]: ... + def format(self, object: object, context: dict[int, Any], maxlevels: int, level: int) -> tuple[str, bool, bool]: ... diff --git a/mypy/typeshed/stdlib/pstats.pyi b/mypy/typeshed/stdlib/pstats.pyi index 6811ec94b349..e8256f9f98ab 100644 --- a/mypy/typeshed/stdlib/pstats.pyi +++ b/mypy/typeshed/stdlib/pstats.pyi @@ -21,7 +21,7 @@ if sys.version_info >= (3, 7): TIME: str class Stats: - sort_arg_dict_default: dict[str, Tuple[Any, str]] + sort_arg_dict_default: dict[str, tuple[Any, str]] def __init__( self: _T, __arg: None | str | Profile | _cProfile = ..., @@ -33,7 +33,7 @@ class Stats: def get_top_level_stats(self) -> None: ... def add(self: _T, *arg_list: None | str | Profile | _cProfile | _T) -> _T: ... def dump_stats(self, filename: StrOrBytesPath) -> None: ... - def get_sort_arg_defs(self) -> dict[str, Tuple[Tuple[Tuple[int, int], ...], str]]: ... + def get_sort_arg_defs(self) -> dict[str, tuple[Tuple[tuple[int, int], ...], str]]: ... @overload def sort_stats(self: _T, field: int) -> _T: ... @overload @@ -41,8 +41,8 @@ class Stats: def reverse_order(self: _T) -> _T: ... def strip_dirs(self: _T) -> _T: ... def calc_callees(self) -> None: ... - def eval_print_amount(self, sel: _Selector, list: list[str], msg: str) -> Tuple[list[str], str]: ... - def get_print_list(self, sel_list: Iterable[_Selector]) -> Tuple[int, list[str]]: ... + def eval_print_amount(self, sel: _Selector, list: list[str], msg: str) -> tuple[list[str], str]: ... + def get_print_list(self, sel_list: Iterable[_Selector]) -> tuple[int, list[str]]: ... def print_stats(self: _T, *amount: _Selector) -> _T: ... def print_callees(self: _T, *amount: _Selector) -> _T: ... def print_callers(self: _T, *amount: _Selector) -> _T: ... diff --git a/mypy/typeshed/stdlib/pty.pyi b/mypy/typeshed/stdlib/pty.pyi index ba6b9b40edc0..f943cebdb157 100644 --- a/mypy/typeshed/stdlib/pty.pyi +++ b/mypy/typeshed/stdlib/pty.pyi @@ -1,4 +1,4 @@ -from typing import Callable, Iterable, Tuple +from typing import Callable, Iterable _Reader = Callable[[int], bytes] @@ -8,8 +8,8 @@ STDERR_FILENO: int CHILD: int -def openpty() -> Tuple[int, int]: ... -def master_open() -> Tuple[int, str]: ... +def openpty() -> tuple[int, int]: ... +def master_open() -> tuple[int, str]: ... def slave_open(tty_name: str) -> int: ... -def fork() -> Tuple[int, int]: ... +def fork() -> tuple[int, int]: ... def spawn(argv: str | Iterable[str], master_read: _Reader = ..., stdin_read: _Reader = ...) -> int: ... diff --git a/mypy/typeshed/stdlib/pydoc.pyi b/mypy/typeshed/stdlib/pydoc.pyi index 778a2e535706..97e71f389616 100644 --- a/mypy/typeshed/stdlib/pydoc.pyi +++ b/mypy/typeshed/stdlib/pydoc.pyi @@ -13,7 +13,7 @@ __credits__: str def pathdirs() -> list[str]: ... def getdoc(object: object) -> str: ... -def splitdoc(doc: AnyStr) -> Tuple[AnyStr, AnyStr]: ... +def splitdoc(doc: AnyStr) -> tuple[AnyStr, AnyStr]: ... def classname(object: object, modname: str) -> str: ... def isdata(object: object) -> bool: ... def replace(text: AnyStr, *pairs: AnyStr) -> AnyStr: ... @@ -21,10 +21,10 @@ def cram(text: str, maxlen: int) -> str: ... def stripid(text: str) -> str: ... def allmethods(cl: type) -> MutableMapping[str, MethodType]: ... def visiblename(name: str, all: Container[str] | None = ..., obj: object | None = ...) -> bool: ... -def classify_class_attrs(object: object) -> list[Tuple[str, str, type, str]]: ... +def classify_class_attrs(object: object) -> list[tuple[str, str, type, str]]: ... def ispackage(path: str) -> bool: ... def source_synopsis(file: IO[AnyStr]) -> AnyStr | None: ... -def synopsis(filename: str, cache: MutableMapping[str, Tuple[int, str]] = ...) -> str | None: ... +def synopsis(filename: str, cache: MutableMapping[str, tuple[int, str]] = ...) -> str | None: ... class ErrorDuringImport(Exception): filename: str @@ -86,7 +86,7 @@ class HTMLDoc(Doc): def namelink(self, name: str, *dicts: MutableMapping[str, str]) -> str: ... def classlink(self, object: object, modname: str) -> str: ... def modulelink(self, object: object) -> str: ... - def modpkglink(self, modpkginfo: Tuple[str, str, bool, bool]) -> str: ... + def modpkglink(self, modpkginfo: tuple[str, str, bool, bool]) -> str: ... def markup( self, text: str, @@ -96,7 +96,7 @@ class HTMLDoc(Doc): methods: Mapping[str, str] = ..., ) -> str: ... def formattree( - self, tree: list[Tuple[type, Tuple[type, ...]] | list[Any]], modname: str, parent: type | None = ... + self, tree: list[tuple[type, Tuple[type, ...]] | list[Any]], modname: str, parent: type | None = ... ) -> str: ... def docmodule(self, object: object, name: str | None = ..., mod: str | None = ..., *ignored: Any) -> str: ... def docclass( @@ -148,7 +148,7 @@ class TextDoc(Doc): def indent(self, text: str, prefix: str = ...) -> str: ... def section(self, title: str, contents: str) -> str: ... def formattree( - self, tree: list[Tuple[type, Tuple[type, ...]] | list[Any]], modname: str, parent: type | None = ..., prefix: str = ... + self, tree: list[tuple[type, Tuple[type, ...]] | list[Any]], modname: str, parent: type | None = ..., prefix: str = ... ) -> str: ... def docmodule(self, object: object, name: str | None = ..., mod: Any | None = ..., *ignored: Any) -> str: ... def docclass(self, object: object, name: str | None = ..., mod: str | None = ..., *ignored: Any) -> str: ... @@ -188,7 +188,7 @@ html: HTMLDoc class _OldStyleClass: ... -def resolve(thing: str | object, forceload: bool = ...) -> Tuple[object, str] | None: ... +def resolve(thing: str | object, forceload: bool = ...) -> tuple[object, str] | None: ... def render_doc(thing: str | object, title: str = ..., forceload: bool = ..., renderer: Doc | None = ...) -> str: ... def doc(thing: str | object, title: str = ..., forceload: bool = ..., output: SupportsWrite[str] | None = ...) -> None: ... def writedoc(thing: str | object, forceload: bool = ...) -> None: ... @@ -197,7 +197,7 @@ def writedocs(dir: str, pkgpath: str = ..., done: Any | None = ...) -> None: ... _list = list # "list" conflicts with method name class Helper: - keywords: dict[str, str | Tuple[str, str]] + keywords: dict[str, str | tuple[str, str]] symbols: dict[str, str] topics: dict[str, str | Tuple[str, ...]] def __init__(self, input: IO[str] | None = ..., output: IO[str] | None = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/pyexpat/__init__.pyi b/mypy/typeshed/stdlib/pyexpat/__init__.pyi index 95c1f98d5652..6a3d6cd56791 100644 --- a/mypy/typeshed/stdlib/pyexpat/__init__.pyi +++ b/mypy/typeshed/stdlib/pyexpat/__init__.pyi @@ -2,11 +2,12 @@ import pyexpat.errors as errors import pyexpat.model as model from _typeshed import SupportsRead from typing import Any, Callable, Optional, Tuple +from typing_extensions import final EXPAT_VERSION: str # undocumented -version_info: Tuple[int, int, int] # undocumented +version_info: tuple[int, int, int] # undocumented native_encoding: str # undocumented -features: list[Tuple[str, int]] # undocumented +features: list[tuple[str, int]] # undocumented class ExpatError(Exception): code: int @@ -21,6 +22,7 @@ XML_PARAM_ENTITY_PARSING_ALWAYS: int _Model = Tuple[int, int, Optional[str], Tuple[Any, ...]] +@final class XMLParserType(object): def Parse(self, __data: str | bytes, __isfinal: bool = ...) -> int: ... def ParseFile(self, __file: SupportsRead[bytes]) -> int: ... diff --git a/mypy/typeshed/stdlib/random.pyi b/mypy/typeshed/stdlib/random.pyi index f284fe831b42..73c29d2f78c3 100644 --- a/mypy/typeshed/stdlib/random.pyi +++ b/mypy/typeshed/stdlib/random.pyi @@ -1,6 +1,6 @@ import _random import sys -from collections.abc import Callable, Iterable, MutableSequence, Sequence, Set +from collections.abc import Callable, Iterable, MutableSequence, Sequence, Set as AbstractSet from fractions import Fraction from typing import Any, NoReturn, Tuple, TypeVar @@ -27,9 +27,9 @@ class Random(_random.Random): ) -> list[_T]: ... def shuffle(self, x: MutableSequence[Any], random: Callable[[], float] | None = ...) -> None: ... if sys.version_info >= (3, 9): - def sample(self, population: Sequence[_T] | Set[_T], k: int, *, counts: Iterable[_T] | None = ...) -> list[_T]: ... + def sample(self, population: Sequence[_T] | AbstractSet[_T], k: int, *, counts: Iterable[_T] | None = ...) -> list[_T]: ... else: - def sample(self, population: Sequence[_T] | Set[_T], k: int) -> list[_T]: ... + def sample(self, population: Sequence[_T] | AbstractSet[_T], k: int) -> list[_T]: ... def random(self) -> float: ... def uniform(self, a: float, b: float) -> float: ... def triangular(self, low: float = ..., high: float = ..., mode: float | None = ...) -> float: ... @@ -66,10 +66,10 @@ def choices( def shuffle(x: MutableSequence[Any], random: Callable[[], float] | None = ...) -> None: ... if sys.version_info >= (3, 9): - def sample(population: Sequence[_T] | Set[_T], k: int, *, counts: Iterable[_T] | None = ...) -> list[_T]: ... + def sample(population: Sequence[_T] | AbstractSet[_T], k: int, *, counts: Iterable[_T] | None = ...) -> list[_T]: ... else: - def sample(population: Sequence[_T] | Set[_T], k: int) -> list[_T]: ... + def sample(population: Sequence[_T] | AbstractSet[_T], k: int) -> list[_T]: ... def random() -> float: ... def uniform(a: float, b: float) -> float: ... diff --git a/mypy/typeshed/stdlib/re.pyi b/mypy/typeshed/stdlib/re.pyi index f2869470dfcf..01a60d170c50 100644 --- a/mypy/typeshed/stdlib/re.pyi +++ b/mypy/typeshed/stdlib/re.pyi @@ -1,7 +1,7 @@ import enum import sys from sre_constants import error as error -from typing import Any, AnyStr, Callable, Iterator, Tuple, Union, overload +from typing import Any, AnyStr, Callable, Iterator, Union, overload # ----- re variables and constants ----- if sys.version_info >= (3, 7): @@ -99,19 +99,19 @@ def sub( pattern: Pattern[AnyStr], repl: Callable[[Match[AnyStr]], AnyStr], string: AnyStr, count: int = ..., flags: _FlagsType = ... ) -> AnyStr: ... @overload -def subn(pattern: AnyStr, repl: AnyStr, string: AnyStr, count: int = ..., flags: _FlagsType = ...) -> Tuple[AnyStr, int]: ... +def subn(pattern: AnyStr, repl: AnyStr, string: AnyStr, count: int = ..., flags: _FlagsType = ...) -> tuple[AnyStr, int]: ... @overload def subn( pattern: AnyStr, repl: Callable[[Match[AnyStr]], AnyStr], string: AnyStr, count: int = ..., flags: _FlagsType = ... -) -> Tuple[AnyStr, int]: ... +) -> tuple[AnyStr, int]: ... @overload def subn( pattern: Pattern[AnyStr], repl: AnyStr, string: AnyStr, count: int = ..., flags: _FlagsType = ... -) -> Tuple[AnyStr, int]: ... +) -> tuple[AnyStr, int]: ... @overload def subn( pattern: Pattern[AnyStr], repl: Callable[[Match[AnyStr]], AnyStr], string: AnyStr, count: int = ..., flags: _FlagsType = ... -) -> Tuple[AnyStr, int]: ... +) -> tuple[AnyStr, int]: ... def escape(pattern: AnyStr) -> AnyStr: ... def purge() -> None: ... def template(pattern: AnyStr | Pattern[AnyStr], flags: _FlagsType = ...) -> Pattern[AnyStr]: ... diff --git a/mypy/typeshed/stdlib/reprlib.pyi b/mypy/typeshed/stdlib/reprlib.pyi index 1529220c9bfc..4d400554a4ff 100644 --- a/mypy/typeshed/stdlib/reprlib.pyi +++ b/mypy/typeshed/stdlib/reprlib.pyi @@ -1,5 +1,6 @@ from array import array -from typing import Any, Callable, Deque, FrozenSet, Set, Tuple +from collections import deque +from typing import Any, Callable, Tuple _ReprFunc = Callable[[Any], str] @@ -23,9 +24,9 @@ class Repr: def repr_tuple(self, x: Tuple[Any, ...], level: int) -> str: ... def repr_list(self, x: list[Any], level: int) -> str: ... def repr_array(self, x: array[Any], level: int) -> str: ... - def repr_set(self, x: Set[Any], level: int) -> str: ... - def repr_frozenset(self, x: FrozenSet[Any], level: int) -> str: ... - def repr_deque(self, x: Deque[Any], level: int) -> str: ... + def repr_set(self, x: set[Any], level: int) -> str: ... + def repr_frozenset(self, x: frozenset[Any], level: int) -> str: ... + def repr_deque(self, x: deque[Any], level: int) -> str: ... def repr_dict(self, x: dict[Any, Any], level: int) -> str: ... def repr_str(self, x: str, level: int) -> str: ... def repr_int(self, x: int, level: int) -> str: ... diff --git a/mypy/typeshed/stdlib/resource.pyi b/mypy/typeshed/stdlib/resource.pyi index 742e43814bcc..d7124edcc2fa 100644 --- a/mypy/typeshed/stdlib/resource.pyi +++ b/mypy/typeshed/stdlib/resource.pyi @@ -45,14 +45,14 @@ class struct_rusage(_Tuple16): ru_nivcsw: int def getpagesize() -> int: ... -def getrlimit(__resource: int) -> Tuple[int, int]: ... +def getrlimit(__resource: int) -> tuple[int, int]: ... def getrusage(__who: int) -> struct_rusage: ... -def setrlimit(__resource: int, __limits: Tuple[int, int]) -> None: ... +def setrlimit(__resource: int, __limits: tuple[int, int]) -> None: ... if sys.platform == "linux": @overload - def prlimit(pid: int, resource: int, limits: Tuple[int, int]) -> Tuple[int, int]: ... + def prlimit(pid: int, resource: int, limits: tuple[int, int]) -> tuple[int, int]: ... @overload - def prlimit(pid: int, resource: int) -> Tuple[int, int]: ... + def prlimit(pid: int, resource: int) -> tuple[int, int]: ... error = OSError diff --git a/mypy/typeshed/stdlib/select.pyi b/mypy/typeshed/stdlib/select.pyi index fd503dc0033a..0329dbaa2c11 100644 --- a/mypy/typeshed/stdlib/select.pyi +++ b/mypy/typeshed/stdlib/select.pyi @@ -1,7 +1,7 @@ import sys from _typeshed import FileDescriptorLike, Self from types import TracebackType -from typing import Any, Iterable, Tuple, Type +from typing import Any, Iterable, Type if sys.platform != "win32": PIPE_BUF: int @@ -22,11 +22,11 @@ class poll: def register(self, fd: FileDescriptorLike, eventmask: int = ...) -> None: ... def modify(self, fd: FileDescriptorLike, eventmask: int) -> None: ... def unregister(self, fd: FileDescriptorLike) -> None: ... - def poll(self, timeout: float | None = ...) -> list[Tuple[int, int]]: ... + def poll(self, timeout: float | None = ...) -> list[tuple[int, int]]: ... def select( __rlist: Iterable[Any], __wlist: Iterable[Any], __xlist: Iterable[Any], __timeout: float | None = ... -) -> Tuple[list[Any], list[Any], list[Any]]: ... +) -> tuple[list[Any], list[Any], list[Any]]: ... error = OSError @@ -114,7 +114,7 @@ if sys.platform == "linux": def register(self, fd: FileDescriptorLike, eventmask: int = ...) -> None: ... def modify(self, fd: FileDescriptorLike, eventmask: int) -> None: ... def unregister(self, fd: FileDescriptorLike) -> None: ... - def poll(self, timeout: float | None = ..., maxevents: int = ...) -> list[Tuple[int, int]]: ... + def poll(self, timeout: float | None = ..., maxevents: int = ...) -> list[tuple[int, int]]: ... @classmethod def fromfd(cls, __fd: FileDescriptorLike) -> epoll: ... EPOLLERR: int @@ -140,4 +140,4 @@ if sys.platform != "linux" and sys.platform != "darwin" and sys.platform != "win def register(self, fd: FileDescriptorLike, eventmask: int = ...) -> None: ... def modify(self, fd: FileDescriptorLike, eventmask: int = ...) -> None: ... def unregister(self, fd: FileDescriptorLike) -> None: ... - def poll(self, timeout: float | None = ...) -> list[Tuple[int, int]]: ... + def poll(self, timeout: float | None = ...) -> list[tuple[int, int]]: ... diff --git a/mypy/typeshed/stdlib/selectors.pyi b/mypy/typeshed/stdlib/selectors.pyi index a28dc1d53899..c3fe7ec47ace 100644 --- a/mypy/typeshed/stdlib/selectors.pyi +++ b/mypy/typeshed/stdlib/selectors.pyi @@ -1,7 +1,7 @@ import sys from _typeshed import FileDescriptor, FileDescriptorLike, Self from abc import ABCMeta, abstractmethod -from typing import Any, Mapping, NamedTuple, Tuple +from typing import Any, Mapping, NamedTuple _EventMask = int @@ -21,7 +21,7 @@ class BaseSelector(metaclass=ABCMeta): def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... def modify(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... @abstractmethod - def select(self, timeout: float | None = ...) -> list[Tuple[SelectorKey, _EventMask]]: ... + def select(self, timeout: float | None = ...) -> list[tuple[SelectorKey, _EventMask]]: ... def close(self) -> None: ... def get_key(self, fileobj: FileDescriptorLike) -> SelectorKey: ... @abstractmethod @@ -32,14 +32,14 @@ class BaseSelector(metaclass=ABCMeta): class SelectSelector(BaseSelector): def register(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... - def select(self, timeout: float | None = ...) -> list[Tuple[SelectorKey, _EventMask]]: ... + def select(self, timeout: float | None = ...) -> list[tuple[SelectorKey, _EventMask]]: ... def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... if sys.platform != "win32": class PollSelector(BaseSelector): def register(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... - def select(self, timeout: float | None = ...) -> list[Tuple[SelectorKey, _EventMask]]: ... + def select(self, timeout: float | None = ...) -> list[tuple[SelectorKey, _EventMask]]: ... def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... if sys.platform == "linux": @@ -47,25 +47,25 @@ if sys.platform == "linux": def fileno(self) -> int: ... def register(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... - def select(self, timeout: float | None = ...) -> list[Tuple[SelectorKey, _EventMask]]: ... + def select(self, timeout: float | None = ...) -> list[tuple[SelectorKey, _EventMask]]: ... def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... class DevpollSelector(BaseSelector): def fileno(self) -> int: ... def register(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... - def select(self, timeout: float | None = ...) -> list[Tuple[SelectorKey, _EventMask]]: ... + def select(self, timeout: float | None = ...) -> list[tuple[SelectorKey, _EventMask]]: ... def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... class KqueueSelector(BaseSelector): def fileno(self) -> int: ... def register(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... - def select(self, timeout: float | None = ...) -> list[Tuple[SelectorKey, _EventMask]]: ... + def select(self, timeout: float | None = ...) -> list[tuple[SelectorKey, _EventMask]]: ... def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... class DefaultSelector(BaseSelector): def register(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... - def select(self, timeout: float | None = ...) -> list[Tuple[SelectorKey, _EventMask]]: ... + def select(self, timeout: float | None = ...) -> list[tuple[SelectorKey, _EventMask]]: ... def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... diff --git a/mypy/typeshed/stdlib/shlex.pyi b/mypy/typeshed/stdlib/shlex.pyi index b517d03daf93..dfe554b0a773 100644 --- a/mypy/typeshed/stdlib/shlex.pyi +++ b/mypy/typeshed/stdlib/shlex.pyi @@ -1,5 +1,5 @@ import sys -from typing import Any, Iterable, TextIO, Tuple, TypeVar +from typing import Any, Iterable, TextIO, TypeVar def split(s: str, comments: bool = ..., posix: bool = ...) -> list[str]: ... @@ -36,7 +36,7 @@ class shlex(Iterable[str]): def get_token(self) -> str: ... def push_token(self, tok: str) -> None: ... def read_token(self) -> str: ... - def sourcehook(self, newfile: str) -> Tuple[str, TextIO]: ... + def sourcehook(self, newfile: str) -> tuple[str, TextIO]: ... # TODO argument types def push_source(self, newstream: Any, newfile: Any = ...) -> None: ... def pop_source(self) -> None: ... diff --git a/mypy/typeshed/stdlib/shutil.pyi b/mypy/typeshed/stdlib/shutil.pyi index cd2f28c59825..f4c492caccaf 100644 --- a/mypy/typeshed/stdlib/shutil.pyi +++ b/mypy/typeshed/stdlib/shutil.pyi @@ -1,7 +1,7 @@ import os import sys -from _typeshed import StrPath, SupportsRead, SupportsWrite -from typing import Any, AnyStr, Callable, Iterable, NamedTuple, Sequence, Set, Tuple, TypeVar, Union, overload +from _typeshed import StrOrBytesPath, StrPath, SupportsRead, SupportsWrite +from typing import Any, AnyStr, Callable, Iterable, NamedTuple, Sequence, TypeVar, Union, overload _PathT = TypeVar("_PathT", str, os.PathLike[str]) # Return value of some functions that may either return a path-like object that was passed in or @@ -21,7 +21,7 @@ def copymode(src: StrPath, dst: StrPath, *, follow_symlinks: bool = ...) -> None def copystat(src: StrPath, dst: StrPath, *, follow_symlinks: bool = ...) -> None: ... def copy(src: StrPath, dst: StrPath, *, follow_symlinks: bool = ...) -> _PathReturn: ... def copy2(src: StrPath, dst: StrPath, *, follow_symlinks: bool = ...) -> _PathReturn: ... -def ignore_patterns(*patterns: StrPath) -> Callable[[Any, list[str]], Set[str]]: ... +def ignore_patterns(*patterns: StrPath) -> Callable[[Any, list[str]], set[str]]: ... if sys.version_info >= (3, 8): def copytree( @@ -60,7 +60,7 @@ class _ntuple_diskusage(NamedTuple): used: int free: int -def disk_usage(path: StrPath) -> _ntuple_diskusage: ... +def disk_usage(path: int | StrOrBytesPath) -> _ntuple_diskusage: ... def chown(path: StrPath, user: str | int | None = ..., group: str | int | None = ...) -> None: ... if sys.version_info >= (3, 8): @@ -83,11 +83,11 @@ def make_archive( group: str | None = ..., logger: Any | None = ..., ) -> str: ... -def get_archive_formats() -> list[Tuple[str, str]]: ... +def get_archive_formats() -> list[tuple[str, str]]: ... def register_archive_format( name: str, function: Callable[..., Any], - extra_args: Sequence[Tuple[str, Any] | list[Any]] | None = ..., + extra_args: Sequence[tuple[str, Any] | list[Any]] | None = ..., description: str = ..., ) -> None: ... def unregister_archive_format(name: str) -> None: ... @@ -100,8 +100,8 @@ else: def unpack_archive(filename: str, extract_dir: StrPath | None = ..., format: str | None = ...) -> None: ... def register_unpack_format( - name: str, extensions: list[str], function: Any, extra_args: Sequence[Tuple[str, Any]] | None = ..., description: str = ... + name: str, extensions: list[str], function: Any, extra_args: Sequence[tuple[str, Any]] | None = ..., description: str = ... ) -> None: ... def unregister_unpack_format(name: str) -> None: ... -def get_unpack_formats() -> list[Tuple[str, list[str], str]]: ... -def get_terminal_size(fallback: Tuple[int, int] = ...) -> os.terminal_size: ... +def get_unpack_formats() -> list[tuple[str, list[str], str]]: ... +def get_terminal_size(fallback: tuple[int, int] = ...) -> os.terminal_size: ... diff --git a/mypy/typeshed/stdlib/signal.pyi b/mypy/typeshed/stdlib/signal.pyi index 21ad232c7189..d617e24f227f 100644 --- a/mypy/typeshed/stdlib/signal.pyi +++ b/mypy/typeshed/stdlib/signal.pyi @@ -1,7 +1,7 @@ import sys from enum import IntEnum from types import FrameType -from typing import Any, Callable, Iterable, Optional, Set, Tuple, Union +from typing import Any, Callable, Iterable, Optional, Tuple, Union if sys.platform != "win32": class ItimerError(IOError): ... @@ -161,19 +161,19 @@ if sys.platform != "win32": def default_int_handler(signum: int, frame: FrameType) -> None: ... if sys.platform != "win32": - def getitimer(__which: int) -> Tuple[float, float]: ... + def getitimer(__which: int) -> tuple[float, float]: ... def getsignal(__signalnum: _SIGNUM) -> _HANDLER: ... if sys.version_info >= (3, 8): def strsignal(__signalnum: _SIGNUM) -> str | None: ... - def valid_signals() -> Set[Signals]: ... + def valid_signals() -> set[Signals]: ... def raise_signal(__signalnum: _SIGNUM) -> None: ... if sys.platform != "win32": def pause() -> None: ... def pthread_kill(__thread_id: int, __signalnum: int) -> None: ... - def pthread_sigmask(__how: int, __mask: Iterable[int]) -> Set[_SIGNUM]: ... + def pthread_sigmask(__how: int, __mask: Iterable[int]) -> set[_SIGNUM]: ... if sys.version_info >= (3, 7): def set_wakeup_fd(fd: int, *, warn_on_full_buffer: bool = ...) -> int: ... @@ -182,7 +182,7 @@ else: def set_wakeup_fd(fd: int) -> int: ... if sys.platform != "win32": - def setitimer(__which: int, __seconds: float, __interval: float = ...) -> Tuple[float, float]: ... + def setitimer(__which: int, __seconds: float, __interval: float = ...) -> tuple[float, float]: ... def siginterrupt(__signalnum: int, __flag: bool) -> None: ... def signal(__signalnum: _SIGNUM, __handler: _HANDLER) -> _HANDLER: ... diff --git a/mypy/typeshed/stdlib/site.pyi b/mypy/typeshed/stdlib/site.pyi index fc331c113163..a73d188a7e5c 100644 --- a/mypy/typeshed/stdlib/site.pyi +++ b/mypy/typeshed/stdlib/site.pyi @@ -1,3 +1,4 @@ +from _typeshed import StrPath from typing import Iterable PREFIXES: list[str] @@ -6,7 +7,21 @@ USER_SITE: str | None USER_BASE: str | None def main() -> None: ... -def addsitedir(sitedir: str, known_paths: Iterable[str] | None = ...) -> None: ... +def abs_paths() -> None: ... # undocumented +def addpackage(sitedir: StrPath, name: StrPath, known_paths: set[str] | None) -> set[str] | None: ... # undocumented +def addsitedir(sitedir: str, known_paths: set[str] | None = ...) -> None: ... +def addsitepackages(known_paths: set[str] | None, prefixes: Iterable[str] | None = ...) -> set[str] | None: ... # undocumented +def addusersitepackages(known_paths: set[str] | None) -> set[str] | None: ... # undocumented +def check_enableusersite() -> bool | None: ... # undocumented +def enablerlcompleter() -> None: ... # undocumented +def execsitecustomize() -> None: ... # undocumented +def execusercustomize() -> None: ... # undocumented def getsitepackages(prefixes: Iterable[str] | None = ...) -> list[str]: ... def getuserbase() -> str: ... def getusersitepackages() -> str: ... +def makepath(*paths: StrPath) -> tuple[str, str]: ... # undocumented +def removeduppaths() -> set[str]: ... # undocumented +def setcopyright() -> None: ... # undocumented +def sethelper() -> None: ... # undocumented +def setquit() -> None: ... # undocumented +def venv(known_paths: set[str] | None) -> set[str] | None: ... # undocumented diff --git a/mypy/typeshed/stdlib/smtpd.pyi b/mypy/typeshed/stdlib/smtpd.pyi index 5d9307300c7e..2b6020524827 100644 --- a/mypy/typeshed/stdlib/smtpd.pyi +++ b/mypy/typeshed/stdlib/smtpd.pyi @@ -1,7 +1,8 @@ import asynchat import asyncore import socket -from typing import Any, DefaultDict, Tuple, Type +from collections import defaultdict +from typing import Any, Tuple, Type _Address = Tuple[str, int] # (host, port) @@ -9,7 +10,7 @@ class SMTPChannel(asynchat.async_chat): COMMAND: int DATA: int - command_size_limits: DefaultDict[str, int] + command_size_limits: defaultdict[str, int] smtp_server: SMTPServer conn: socket.socket addr: Any diff --git a/mypy/typeshed/stdlib/smtplib.pyi b/mypy/typeshed/stdlib/smtplib.pyi index 6b3b9bfad704..5dbdf5d44c29 100644 --- a/mypy/typeshed/stdlib/smtplib.pyi +++ b/mypy/typeshed/stdlib/smtplib.pyi @@ -24,19 +24,19 @@ class SMTPServerDisconnected(SMTPException): ... class SMTPResponseException(SMTPException): smtp_code: int smtp_error: bytes | str - args: Tuple[int, bytes | str] | Tuple[int, bytes, str] + args: tuple[int, bytes | str] | tuple[int, bytes, str] def __init__(self, code: int, msg: bytes | str) -> None: ... class SMTPSenderRefused(SMTPResponseException): smtp_code: int smtp_error: bytes sender: str - args: Tuple[int, bytes, str] + args: tuple[int, bytes, str] def __init__(self, code: int, msg: bytes, sender: str) -> None: ... class SMTPRecipientsRefused(SMTPException): recipients: _SendErrs - args: Tuple[_SendErrs] + args: tuple[_SendErrs] def __init__(self, recipients: _SendErrs) -> None: ... class SMTPDataError(SMTPResponseException): ... diff --git a/mypy/typeshed/stdlib/socket.pyi b/mypy/typeshed/stdlib/socket.pyi index f72115301ace..1f5ae6eb76c8 100644 --- a/mypy/typeshed/stdlib/socket.pyi +++ b/mypy/typeshed/stdlib/socket.pyi @@ -341,6 +341,7 @@ if sys.platform == "linux" and sys.version_info >= (3, 8): 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, 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, diff --git a/mypy/typeshed/stdlib/socketserver.pyi b/mypy/typeshed/stdlib/socketserver.pyi index 5966b8d10e32..6f5eeefb84fd 100644 --- a/mypy/typeshed/stdlib/socketserver.pyi +++ b/mypy/typeshed/stdlib/socketserver.pyi @@ -2,7 +2,7 @@ import sys import types from _typeshed import Self from socket import socket as _socket -from typing import Any, BinaryIO, Callable, ClassVar, Set, Tuple, Type, TypeVar, Union +from typing import Any, BinaryIO, Callable, ClassVar, Tuple, Type, TypeVar, Union _T = TypeVar("_T") _RequestType = Union[_socket, Tuple[bytes, _socket]] @@ -88,7 +88,7 @@ if sys.platform != "win32": if sys.platform != "win32": class ForkingMixIn: timeout: float | None # undocumented - active_children: Set[int] | None # undocumented + active_children: set[int] | None # undocumented max_children: int # undocumented if sys.version_info >= (3, 7): block_on_close: bool diff --git a/mypy/typeshed/stdlib/sqlite3/dbapi2.pyi b/mypy/typeshed/stdlib/sqlite3/dbapi2.pyi index abce96305c7b..e2e45d538da9 100644 --- a/mypy/typeshed/stdlib/sqlite3/dbapi2.pyi +++ b/mypy/typeshed/stdlib/sqlite3/dbapi2.pyi @@ -1,7 +1,7 @@ import sys from _typeshed import Self, StrOrBytesPath from datetime import date, datetime, time -from typing import Any, Callable, Generator, Iterable, Iterator, Protocol, Tuple, Type, TypeVar +from typing import Any, Callable, Generator, Iterable, Iterator, Protocol, Type, TypeVar _T = TypeVar("_T") @@ -16,8 +16,8 @@ def DateFromTicks(ticks: float) -> Date: ... def TimeFromTicks(ticks: float) -> Time: ... def TimestampFromTicks(ticks: float) -> Timestamp: ... -version_info: Tuple[int, int, int] -sqlite_version_info: Tuple[int, int, int] +version_info: tuple[int, int, int] +sqlite_version_info: tuple[int, int, int] Binary = memoryview # The remaining definitions are imported from _sqlite3. @@ -35,6 +35,8 @@ SQLITE_CREATE_TEMP_TRIGGER: int SQLITE_CREATE_TEMP_VIEW: int SQLITE_CREATE_TRIGGER: int SQLITE_CREATE_VIEW: int +if sys.version_info >= (3, 7): + SQLITE_CREATE_VTABLE: int SQLITE_DELETE: int SQLITE_DENY: int SQLITE_DETACH: int @@ -46,12 +48,31 @@ SQLITE_DROP_TEMP_TRIGGER: int SQLITE_DROP_TEMP_VIEW: int SQLITE_DROP_TRIGGER: int SQLITE_DROP_VIEW: int +if sys.version_info >= (3, 7): + SQLITE_DROP_VTABLE: int + SQLITE_FUNCTION: int SQLITE_IGNORE: int SQLITE_INSERT: int SQLITE_OK: int +if sys.version_info >= (3, 11): + SQLITE_LIMIT_LENGTH: int + SQLITE_LIMIT_SQL_LENGTH: int + SQLITE_LIMIT_COLUMN: int + SQLITE_LIMIT_EXPR_DEPTH: int + SQLITE_LIMIT_COMPOUND_SELECT: int + SQLITE_LIMIT_VDBE_OP: int + SQLITE_LIMIT_FUNCTION_ARG: int + SQLITE_LIMIT_ATTACHED: int + SQLITE_LIMIT_LIKE_PATTERN_LENGTH: int + SQLITE_LIMIT_VARIABLE_NUMBER: int + SQLITE_LIMIT_TRIGGER_DEPTH: int + SQLITE_LIMIT_WORKER_THREADS: int SQLITE_PRAGMA: int SQLITE_READ: int SQLITE_REINDEX: int +if sys.version_info >= (3, 7): + SQLITE_RECURSIVE: int + SQLITE_SAVEPOINT: int SQLITE_SELECT: int SQLITE_TRANSACTION: int SQLITE_UPDATE: int @@ -167,7 +188,7 @@ class Cursor(Iterator[Any]): description: Any lastrowid: Any row_factory: Any - rowcount: Any + rowcount: int # TODO: Cursor class accepts exactly 1 argument # required type is sqlite3.Connection (which is imported as _Connection) # however, the name of the __init__ variable is unknown diff --git a/mypy/typeshed/stdlib/sre_parse.pyi b/mypy/typeshed/stdlib/sre_parse.pyi index a242ca34afd2..2d00bedc2c81 100644 --- a/mypy/typeshed/stdlib/sre_parse.pyi +++ b/mypy/typeshed/stdlib/sre_parse.pyi @@ -1,16 +1,16 @@ import sys from sre_constants import _NamedIntConstant as _NIC, error as _Error -from typing import Any, FrozenSet, Iterable, List, Match, Optional, Pattern as _Pattern, Tuple, Union, overload +from typing import Any, Iterable, List, Match, Optional, Pattern as _Pattern, Tuple, Union, overload SPECIAL_CHARS: str REPEAT_CHARS: str -DIGITS: FrozenSet[str] -OCTDIGITS: FrozenSet[str] -HEXDIGITS: FrozenSet[str] -ASCIILETTERS: FrozenSet[str] -WHITESPACE: FrozenSet[str] -ESCAPES: dict[str, Tuple[_NIC, int]] -CATEGORIES: dict[str, Tuple[_NIC, _NIC] | Tuple[_NIC, list[Tuple[_NIC, _NIC]]]] +DIGITS: frozenset[str] +OCTDIGITS: frozenset[str] +HEXDIGITS: frozenset[str] +ASCIILETTERS: frozenset[str] +WHITESPACE: frozenset[str] +ESCAPES: dict[str, tuple[_NIC, int]] +CATEGORIES: dict[str, tuple[_NIC, _NIC] | tuple[_NIC, list[tuple[_NIC, _NIC]]]] FLAGS: dict[str, int] GLOBAL_FLAGS: int diff --git a/mypy/typeshed/stdlib/ssl.pyi b/mypy/typeshed/stdlib/ssl.pyi index 759b992f6c1c..689b083d764c 100644 --- a/mypy/typeshed/stdlib/ssl.pyi +++ b/mypy/typeshed/stdlib/ssl.pyi @@ -96,13 +96,13 @@ else: _create_default_https_context: Callable[..., SSLContext] def RAND_bytes(__num: int) -> bytes: ... -def RAND_pseudo_bytes(__num: int) -> Tuple[bytes, bool]: ... +def RAND_pseudo_bytes(__num: int) -> tuple[bytes, bool]: ... def RAND_status() -> bool: ... def RAND_egd(path: str) -> None: ... def RAND_add(__s: bytes, __entropy: float) -> None: ... def match_hostname(cert: _PeerCertRetType, hostname: str) -> None: ... def cert_time_to_seconds(cert_time: str) -> int: ... -def get_server_certificate(addr: Tuple[str, int], ssl_version: int = ..., ca_certs: str | None = ...) -> str: ... +def get_server_certificate(addr: tuple[str, int], ssl_version: int = ..., ca_certs: str | None = ...) -> str: ... def DER_cert_to_PEM_cert(der_cert_bytes: bytes) -> str: ... def PEM_cert_to_DER_cert(pem_cert_string: str) -> bytes: ... @@ -213,7 +213,7 @@ HAS_NPN: bool CHANNEL_BINDING_TYPES: list[str] OPENSSL_VERSION: str -OPENSSL_VERSION_INFO: Tuple[int, int, int, int, int] +OPENSSL_VERSION_INFO: tuple[int, int, int, int, int] OPENSSL_VERSION_NUMBER: int class AlertDescription(enum.IntEnum): @@ -341,13 +341,13 @@ class SSLSocket(socket.socket): def getpeercert(self, binary_form: Literal[True]) -> bytes | None: ... @overload def getpeercert(self, binary_form: bool) -> _PeerCertRetType: ... - def cipher(self) -> Tuple[str, str, int] | None: ... - def shared_ciphers(self) -> list[Tuple[str, str, int]] | None: ... + def cipher(self) -> tuple[str, str, int] | None: ... + def shared_ciphers(self) -> list[tuple[str, str, int]] | None: ... def compression(self) -> str | None: ... def get_channel_binding(self, cb_type: str = ...) -> bytes | None: ... def selected_alpn_protocol(self) -> str | None: ... def selected_npn_protocol(self) -> str | None: ... - def accept(self) -> Tuple[SSLSocket, socket._RetAddress]: ... + def accept(self) -> tuple[SSLSocket, socket._RetAddress]: ... def unwrap(self) -> socket.socket: ... def version(self) -> str | None: ... def pending(self) -> int: ... @@ -442,8 +442,8 @@ class SSLObject: def getpeercert(self, binary_form: bool) -> _PeerCertRetType: ... def selected_alpn_protocol(self) -> str | None: ... def selected_npn_protocol(self) -> str | None: ... - def cipher(self) -> Tuple[str, str, int] | None: ... - def shared_ciphers(self) -> list[Tuple[str, str, int]] | None: ... + def cipher(self) -> tuple[str, str, int] | None: ... + def shared_ciphers(self) -> list[tuple[str, str, int]] | None: ... def compression(self) -> str | None: ... def pending(self) -> int: ... def do_handshake(self) -> None: ... diff --git a/mypy/typeshed/stdlib/string.pyi b/mypy/typeshed/stdlib/string.pyi index ceed38f00931..374d59959ac9 100644 --- a/mypy/typeshed/stdlib/string.pyi +++ b/mypy/typeshed/stdlib/string.pyi @@ -1,4 +1,11 @@ -from typing import Any, Iterable, Mapping, Sequence, Tuple +import sys +from re import RegexFlag +from typing import Any, Iterable, Mapping, Sequence + +if sys.version_info >= (3, 8): + from re import Pattern +else: + from typing import Pattern ascii_letters: str ascii_lowercase: str @@ -14,6 +21,11 @@ def capwords(s: str, sep: str | None = ...) -> str: ... class Template: template: str + delimiter: str + idpattern: str + braceidpattern: str | None + flags: RegexFlag + pattern: Pattern[str] def __init__(self, template: str) -> None: ... def substitute(self, __mapping: Mapping[str, object] = ..., **kwds: object) -> str: ... def safe_substitute(self, __mapping: Mapping[str, object] = ..., **kwds: object) -> str: ... @@ -22,7 +34,7 @@ class Template: class Formatter: def format(self, __format_string: str, *args: Any, **kwargs: Any) -> str: ... def vformat(self, format_string: str, args: Sequence[Any], kwargs: Mapping[str, Any]) -> str: ... - def parse(self, format_string: str) -> Iterable[Tuple[str, str | None, str | None, str | None]]: ... + def parse(self, format_string: str) -> Iterable[tuple[str, str | None, str | None, str | None]]: ... def get_field(self, field_name: str, args: Sequence[Any], kwargs: Mapping[str, Any]) -> Any: ... def get_value(self, key: int | str, args: Sequence[Any], kwargs: Mapping[str, Any]) -> Any: ... def check_unused_args(self, used_args: Sequence[int | str], args: Sequence[Any], kwargs: Mapping[str, Any]) -> None: ... diff --git a/mypy/typeshed/stdlib/subprocess.pyi b/mypy/typeshed/stdlib/subprocess.pyi index ed8dce29363d..fce517745ee6 100644 --- a/mypy/typeshed/stdlib/subprocess.pyi +++ b/mypy/typeshed/stdlib/subprocess.pyi @@ -1,7 +1,7 @@ import sys from _typeshed import Self, StrOrBytesPath from types import TracebackType -from typing import IO, Any, AnyStr, Callable, Generic, Iterable, Mapping, Sequence, Tuple, Type, TypeVar, Union, overload +from typing import IO, Any, AnyStr, Callable, Generic, Iterable, Mapping, Sequence, Type, TypeVar, Union, overload from typing_extensions import Literal if sys.version_info >= (3, 9): @@ -1002,7 +1002,7 @@ class Popen(Generic[AnyStr]): input: AnyStr | None = ..., timeout: float | None = ..., # morally this should be optional - ) -> Tuple[AnyStr, AnyStr]: ... + ) -> tuple[AnyStr, AnyStr]: ... def send_signal(self, sig: int) -> None: ... def terminate(self) -> None: ... def kill(self) -> None: ... @@ -1014,9 +1014,14 @@ class Popen(Generic[AnyStr]): def __class_getitem__(cls, item: Any) -> GenericAlias: ... # The result really is always a str. -def getstatusoutput(cmd: _TXT) -> Tuple[int, str]: ... +def getstatusoutput(cmd: _TXT) -> tuple[int, str]: ... def getoutput(cmd: _TXT) -> str: ... -def list2cmdline(seq: Iterable[str]) -> str: ... # undocumented + +if sys.version_info >= (3, 8): + def list2cmdline(seq: Iterable[StrOrBytesPath]) -> str: ... # undocumented + +else: + def list2cmdline(seq: Iterable[str]) -> str: ... # undocumented if sys.platform == "win32": class STARTUPINFO: diff --git a/mypy/typeshed/stdlib/sys.pyi b/mypy/typeshed/stdlib/sys.pyi index e60a58c02ef2..274e4b90fd6e 100644 --- a/mypy/typeshed/stdlib/sys.pyi +++ b/mypy/typeshed/stdlib/sys.pyi @@ -1,6 +1,6 @@ import sys from builtins import object as _object -from importlib.abc import Loader, PathEntryFinder +from importlib.abc import PathEntryFinder from importlib.machinery import ModuleSpec from io import TextIOWrapper from types import FrameType, ModuleType, TracebackType @@ -8,7 +8,6 @@ from typing import ( Any, AsyncGenerator, Callable, - FrozenSet, NoReturn, Optional, Protocol, @@ -27,12 +26,10 @@ _T = TypeVar("_T") # The following type alias are stub-only and do not exist during runtime _ExcInfo = Tuple[Type[BaseException], BaseException, TracebackType] _OptExcInfo = Union[_ExcInfo, Tuple[None, None, None]] -_PathSequence = Sequence[Union[bytes, str]] -# Unlike importlib.abc.MetaPathFinder, invalidate_caches() might not exist (see python docs) +# Intentionally omits one deprecated and one optional method of `importlib.abc.MetaPathFinder` class _MetaPathFinder(Protocol): - def find_module(self, fullname: str, path: _PathSequence | None) -> Loader | None: ... - def find_spec(self, fullname: str, path: _PathSequence | None, target: ModuleType | None = ...) -> ModuleSpec | None: ... + def find_spec(self, fullname: str, path: Sequence[str] | None, target: ModuleType | None = ...) -> ModuleSpec | None: ... # ----- sys variables ----- if sys.platform != "win32": @@ -47,7 +44,7 @@ if sys.platform == "win32": dllhandle: int dont_write_bytecode: bool displayhook: Callable[[object], Any] -excepthook: Callable[[Type[BaseException], BaseException, TracebackType], Any] +excepthook: Callable[[Type[BaseException], BaseException, TracebackType | None], Any] exec_prefix: str executable: str float_repr_style: str @@ -70,13 +67,13 @@ if sys.version_info >= (3, 9): prefix: str if sys.version_info >= (3, 8): pycache_prefix: str | None -ps1: str -ps2: str +ps1: object +ps2: object stdin: TextIO stdout: TextIO stderr: TextIO if sys.version_info >= (3, 10): - stdlib_module_names: FrozenSet[str] + stdlib_module_names: frozenset[str] __stdin__: TextIOWrapper __stdout__: TextIOWrapper __stderr__: TextIOWrapper @@ -205,7 +202,7 @@ class _WinVersion(Tuple[int, int, int, int, str, int, int, int, int, Tuple[int, service_pack_major: int suite_mast: int product_type: int - platform_version: Tuple[int, int, int] + platform_version: tuple[int, int, int] if sys.platform == "win32": def getwindowsversion() -> _WinVersion: ... diff --git a/mypy/typeshed/stdlib/tabnanny.pyi b/mypy/typeshed/stdlib/tabnanny.pyi index 584c6d4e26bd..4c7be83b0511 100644 --- a/mypy/typeshed/stdlib/tabnanny.pyi +++ b/mypy/typeshed/stdlib/tabnanny.pyi @@ -1,5 +1,5 @@ from _typeshed import StrOrBytesPath -from typing import Iterable, Tuple +from typing import Iterable verbose: int filename_only: int @@ -11,4 +11,4 @@ class NannyNag(Exception): def get_line(self) -> str: ... def check(file: StrOrBytesPath) -> None: ... -def process_tokens(tokens: Iterable[Tuple[int, str, Tuple[int, int], Tuple[int, int], str]]) -> None: ... +def process_tokens(tokens: Iterable[tuple[int, str, tuple[int, int], tuple[int, int], str]]) -> None: ... diff --git a/mypy/typeshed/stdlib/tarfile.pyi b/mypy/typeshed/stdlib/tarfile.pyi index 53c986a3f017..0134316d8107 100644 --- a/mypy/typeshed/stdlib/tarfile.pyi +++ b/mypy/typeshed/stdlib/tarfile.pyi @@ -5,7 +5,7 @@ from _typeshed import Self, StrOrBytesPath, StrPath from collections.abc import Callable, Iterable, Iterator, Mapping from gzip import _ReadableFileobj as _GzipReadableFileobj, _WritableFileobj as _GzipWritableFileobj from types import TracebackType -from typing import IO, Protocol, Set, Tuple, Type, TypeVar, overload +from typing import IO, Protocol, Tuple, Type, TypeVar, overload from typing_extensions import Literal _TF = TypeVar("_TF", bound=TarFile) @@ -67,7 +67,7 @@ REGULAR_TYPES: Tuple[bytes, ...] GNU_TYPES: Tuple[bytes, ...] PAX_FIELDS: Tuple[str, ...] PAX_NUMBER_FIELDS: dict[str, type] -PAX_NAME_FIELDS: Set[str] +PAX_NAME_FIELDS: set[str] ENCODING: str diff --git a/mypy/typeshed/stdlib/telnetlib.pyi b/mypy/typeshed/stdlib/telnetlib.pyi index b9c984550c2c..cf00856d9332 100644 --- a/mypy/typeshed/stdlib/telnetlib.pyi +++ b/mypy/typeshed/stdlib/telnetlib.pyi @@ -1,6 +1,6 @@ import socket from _typeshed import Self -from typing import Any, Callable, Match, Pattern, Sequence, Tuple +from typing import Any, Callable, Match, Pattern, Sequence DEBUGLEVEL: int TELNET_PORT: int @@ -109,6 +109,6 @@ class Telnet: def listener(self) -> None: ... def expect( self, list: Sequence[Pattern[bytes] | bytes], timeout: float | None = ... - ) -> Tuple[int, Match[bytes] | None, bytes]: ... + ) -> tuple[int, Match[bytes] | None, bytes]: ... def __enter__(self: Self) -> Self: ... def __exit__(self, type: Any, value: Any, traceback: Any) -> None: ... diff --git a/mypy/typeshed/stdlib/tempfile.pyi b/mypy/typeshed/stdlib/tempfile.pyi index 270f506ed594..119c111bc4e1 100644 --- a/mypy/typeshed/stdlib/tempfile.pyi +++ b/mypy/typeshed/stdlib/tempfile.pyi @@ -321,10 +321,28 @@ class SpooledTemporaryFile(IO[AnyStr]): class TemporaryDirectory(Generic[AnyStr]): name: AnyStr - @overload - def __init__(self: TemporaryDirectory[str], suffix: None = ..., prefix: None = ..., dir: None = ...) -> None: ... - @overload - def __init__(self, suffix: AnyStr | None = ..., prefix: AnyStr | None = ..., dir: _DirT[AnyStr] | None = ...) -> None: ... + if sys.version_info >= (3, 10): + @overload + def __init__( + self: TemporaryDirectory[str], + suffix: None = ..., + prefix: None = ..., + dir: None = ..., + ignore_cleanup_errors: bool = ..., + ) -> None: ... + @overload + def __init__( + self, + suffix: AnyStr | None = ..., + prefix: AnyStr | None = ..., + dir: _DirT[AnyStr] | None = ..., + ignore_cleanup_errors: bool = ..., + ) -> None: ... + else: + @overload + def __init__(self: TemporaryDirectory[str], suffix: None = ..., prefix: None = ..., dir: None = ...) -> None: ... + @overload + def __init__(self, suffix: AnyStr | None = ..., prefix: AnyStr | None = ..., dir: _DirT[AnyStr] | None = ...) -> None: ... def cleanup(self) -> None: ... def __enter__(self) -> AnyStr: ... def __exit__( @@ -334,11 +352,11 @@ class TemporaryDirectory(Generic[AnyStr]): def __class_getitem__(cls, item: Any) -> GenericAlias: ... @overload -def mkstemp() -> Tuple[int, str]: ... +def mkstemp() -> tuple[int, str]: ... @overload def mkstemp( suffix: AnyStr | None = ..., prefix: AnyStr | None = ..., dir: _DirT[AnyStr] | None = ..., text: bool = ... -) -> Tuple[int, AnyStr]: ... +) -> tuple[int, AnyStr]: ... @overload def mkdtemp() -> str: ... @overload diff --git a/mypy/typeshed/stdlib/time.pyi b/mypy/typeshed/stdlib/time.pyi index 039350c5b7ad..bf370d68e83d 100644 --- a/mypy/typeshed/stdlib/time.pyi +++ b/mypy/typeshed/stdlib/time.pyi @@ -1,13 +1,14 @@ import sys from types import SimpleNamespace from typing import Any, NamedTuple, Tuple +from typing_extensions import final _TimeTuple = Tuple[int, int, int, int, int, int, int, int, int] altzone: int daylight: int timezone: int -tzname: Tuple[str, str] +tzname: tuple[str, str] if sys.version_info >= (3, 7): if sys.platform == "linux": @@ -48,19 +49,20 @@ class _struct_time(NamedTuple): @property def n_unnamed_fields(self) -> int: ... +@final class struct_time(_struct_time): def __init__( self, - o: Tuple[int, int, int, int, int, int, int, int, int] - | Tuple[int, int, int, int, int, int, int, int, int, str] - | Tuple[int, int, int, int, int, int, int, int, int, str, int], + o: tuple[int, int, int, int, int, int, int, int, int] + | tuple[int, int, int, int, int, int, int, int, int, str] + | tuple[int, int, int, int, int, int, int, int, int, str, int], _arg: Any = ..., ) -> None: ... def __new__( cls, - o: Tuple[int, int, int, int, int, int, int, int, int] - | Tuple[int, int, int, int, int, int, int, int, int, str] - | Tuple[int, int, int, int, int, int, int, int, int, str, int], + o: tuple[int, int, int, int, int, int, int, int, int] + | tuple[int, int, int, int, int, int, int, int, int, str] + | tuple[int, int, int, int, int, int, int, int, int, str, int], _arg: Any = ..., ) -> struct_time: ... @property diff --git a/mypy/typeshed/stdlib/timeit.pyi b/mypy/typeshed/stdlib/timeit.pyi index 2a8330d1cee1..d82dd80598dc 100644 --- a/mypy/typeshed/stdlib/timeit.pyi +++ b/mypy/typeshed/stdlib/timeit.pyi @@ -1,4 +1,4 @@ -from typing import IO, Any, Callable, Sequence, Tuple, Union +from typing import IO, Any, Callable, Sequence, Union _Timer = Callable[[], float] _Stmt = Union[str, Callable[[], Any]] @@ -12,7 +12,7 @@ class Timer: def print_exc(self, file: IO[str] | None = ...) -> None: ... def timeit(self, number: int = ...) -> float: ... def repeat(self, repeat: int = ..., number: int = ...) -> list[float]: ... - def autorange(self, callback: Callable[[int, float], Any] | None = ...) -> Tuple[int, float]: ... + def autorange(self, callback: Callable[[int, float], Any] | None = ...) -> tuple[int, float]: ... def timeit( stmt: _Stmt = ..., setup: _Stmt = ..., timer: _Timer = ..., number: int = ..., globals: dict[str, Any] | None = ... diff --git a/mypy/typeshed/stdlib/tkinter/__init__.pyi b/mypy/typeshed/stdlib/tkinter/__init__.pyi index b7a5d3a112cc..bda37b406fc3 100644 --- a/mypy/typeshed/stdlib/tkinter/__init__.pyi +++ b/mypy/typeshed/stdlib/tkinter/__init__.pyi @@ -68,23 +68,20 @@ EXCEPTION = _tkinter.EXCEPTION # something, then you may actually want Callable[something] | str, # because it's often possible to specify a string of Tcl code. # +# - If you think the correct type is Iterable[Foo] or Sequence[Foo], it is +# probably list[Foo] | tuple[Foo, ...], disallowing other sequences such +# as deques: +# +# >>> tkinter.Label(font=('Helvetica', 12, collections.deque(['bold']))) +# Traceback (most recent call last): +# ... +# _tkinter.TclError: unknown font style "deque(['bold'])" +# # - Some options can be set only in __init__, but all options are available # when getting their values with configure's return value or cget. # # - Asks other tkinter users if you haven't worked much with tkinter. -# _TkinterSequence[T] represents a sequence that tkinter understands. It -# differs from typing.Sequence[T]. For example, collections.deque a valid -# Sequence but not a valid _TkinterSequence: -# -# >>> tkinter.Label(font=('Helvetica', 12, collections.deque(['bold']))) -# Traceback (most recent call last): -# ... -# _tkinter.TclError: unknown font style "deque(['bold'])" -_T = TypeVar("_T") -_TkinterSequence = Union[List[_T], Tuple[_T, ...]] -_TkinterSequence2D = Union[List[List[_T]], List[Tuple[_T, ...]], Tuple[List[_T], ...], Tuple[Tuple[_T, ...], ...]] - # Some widgets have an option named -compound that accepts different values # than the _Compound defined here. Many other options have similar things. _Anchor = Literal["nw", "n", "ne", "w", "center", "e", "sw", "s", "se"] # manual page: Tk_GetAnchor @@ -95,7 +92,7 @@ _Color = str # typically '#rrggbb', '#rgb' or color names. _Compound = Literal["top", "left", "center", "right", "bottom", "none"] # -compound in manual page named 'options' _Cursor = Union[str, Tuple[str], Tuple[str, str], Tuple[str, str, str], Tuple[str, str, str, str]] # manual page: Tk_GetCursor _EntryValidateCommand = Union[ - Callable[[], bool], str, _TkinterSequence[str] + Callable[[], bool], str, List[str], Tuple[str, ...] ] # example when it's sequence: entry['invalidcommand'] = [entry.register(print), '%P'] _GridIndex = Union[int, str, Literal["all"]] _ImageSpec = Union[_Image, str] # str can be from e.g. tkinter.image_names() @@ -186,7 +183,7 @@ class Variable: def get(self) -> Any: ... def trace_add(self, mode: _TraceMode, callback: Callable[[str, str, str], Any]) -> str: ... def trace_remove(self, mode: _TraceMode, cbname: str) -> None: ... - def trace_info(self) -> list[Tuple[Tuple[_TraceMode, ...], str]]: ... + def trace_info(self) -> list[tuple[Tuple[_TraceMode, ...], str]]: ... def trace_variable(self, mode, callback): ... # deprecated def trace_vdelete(self, mode, cbname): ... # deprecated def trace_vinfo(self): ... # deprecated @@ -306,11 +303,11 @@ class Misc: def winfo_pathname(self, id: int, displayof: Literal[0] | Misc | None = ...): ... def winfo_pixels(self, number: _ScreenUnits) -> int: ... def winfo_pointerx(self) -> int: ... - def winfo_pointerxy(self) -> Tuple[int, int]: ... + def winfo_pointerxy(self) -> tuple[int, int]: ... def winfo_pointery(self) -> int: ... def winfo_reqheight(self) -> int: ... def winfo_reqwidth(self) -> int: ... - def winfo_rgb(self, color: _Color) -> Tuple[int, int, int]: ... + def winfo_rgb(self, color: _Color) -> tuple[int, int, int]: ... def winfo_rootx(self) -> int: ... def winfo_rooty(self) -> int: ... def winfo_screen(self) -> str: ... @@ -326,7 +323,7 @@ class Misc: def winfo_viewable(self) -> bool: ... def winfo_visual(self) -> str: ... def winfo_visualid(self) -> str: ... - def winfo_visualsavailable(self, includeids: int = ...) -> list[Tuple[str, int]]: ... + def winfo_visualsavailable(self, includeids: int = ...) -> list[tuple[str, int]]: ... def winfo_vrootheight(self) -> int: ... def winfo_vrootwidth(self) -> int: ... def winfo_vrootx(self) -> int: ... @@ -341,30 +338,40 @@ class Misc: # binds do. The default value of func is not str. @overload def bind( - self, sequence: str | None = ..., func: Callable[[Event[Misc]], Any] | None = ..., add: bool | None = ... + self, + sequence: str | None = ..., + func: Callable[[Event[Misc]], Any] | None = ..., + add: Literal["", "+"] | bool | None = ..., ) -> str: ... @overload - def bind(self, sequence: str | None, func: str, add: bool | None = ...) -> None: ... + def bind(self, sequence: str | None, func: str, add: Literal["", "+"] | bool | None = ...) -> None: ... @overload - def bind(self, *, func: str, add: bool | None = ...) -> None: ... + def bind(self, *, func: str, add: Literal["", "+"] | bool | None = ...) -> None: ... # There's no way to know what type of widget bind_all and bind_class # callbacks will get, so those are Misc. @overload def bind_all( - self, sequence: str | None = ..., func: Callable[[Event[Misc]], Any] | None = ..., add: bool | None = ... + self, + sequence: str | None = ..., + func: Callable[[Event[Misc]], Any] | None = ..., + add: Literal["", "+"] | bool | None = ..., ) -> str: ... @overload - def bind_all(self, sequence: str | None, func: str, add: bool | None = ...) -> None: ... + def bind_all(self, sequence: str | None, func: str, add: Literal["", "+"] | bool | None = ...) -> None: ... @overload - def bind_all(self, *, func: str, add: bool | None = ...) -> None: ... + def bind_all(self, *, func: str, add: Literal["", "+"] | bool | None = ...) -> None: ... @overload def bind_class( - self, className: str, sequence: str | None = ..., func: Callable[[Event[Misc]], Any] | None = ..., add: bool | None = ... + self, + className: str, + sequence: str | None = ..., + func: Callable[[Event[Misc]], Any] | None = ..., + add: Literal["", "+"] | bool | None = ..., ) -> str: ... @overload - def bind_class(self, className: str, sequence: str | None, func: str, add: bool | None = ...) -> None: ... + def bind_class(self, className: str, sequence: str | None, func: str, add: Literal["", "+"] | bool | None = ...) -> None: ... @overload - def bind_class(self, className: str, *, func: str, add: bool | None = ...) -> None: ... + def bind_class(self, className: str, *, func: str, add: Literal["", "+"] | bool | None = ...) -> None: ... def unbind(self, sequence: str, funcid: str | None = ...) -> None: ... def unbind_all(self, sequence: str) -> None: ... def unbind_class(self, className: str, sequence: str) -> None: ... @@ -385,11 +392,11 @@ class Misc: @overload def grid_bbox( self, column: None = ..., row: None = ..., col2: None = ..., row2: None = ... - ) -> Tuple[int, int, int, int] | None: ... + ) -> tuple[int, int, int, int] | None: ... @overload - def grid_bbox(self, column: int, row: int, col2: None = ..., row2: None = ...) -> Tuple[int, int, int, int] | None: ... + def grid_bbox(self, column: int, row: int, col2: None = ..., row2: None = ...) -> tuple[int, int, int, int] | None: ... @overload - def grid_bbox(self, column: int, row: int, col2: int, row2: int) -> Tuple[int, int, int, int] | None: ... + def grid_bbox(self, column: int, row: int, col2: int, row2: int) -> tuple[int, int, int, int] | None: ... bbox = grid_bbox def grid_columnconfigure( self, @@ -410,15 +417,15 @@ class Misc: pad: _ScreenUnits = ..., uniform: str = ..., weight: int = ..., - ) -> _GridIndexInfo | Any: ... # can be None but annoyying to check + ) -> _GridIndexInfo | Any: ... # can be None but annoying to check columnconfigure = grid_columnconfigure rowconfigure = grid_rowconfigure - def grid_location(self, x: _ScreenUnits, y: _ScreenUnits) -> Tuple[int, int]: ... + def grid_location(self, x: _ScreenUnits, y: _ScreenUnits) -> tuple[int, int]: ... @overload def grid_propagate(self, flag: bool) -> None: ... @overload def grid_propagate(self) -> bool: ... - def grid_size(self) -> Tuple[int, int]: ... + def grid_size(self) -> tuple[int, int]: ... size = grid_size # Widget because Toplevel or Tk is never a slave def pack_slaves(self) -> list[Widget]: ... @@ -478,7 +485,7 @@ class CallWrapper: class XView: @overload - def xview(self) -> Tuple[float, float]: ... + def xview(self) -> tuple[float, float]: ... @overload def xview(self, *args: Any) -> Any: ... def xview_moveto(self, fraction: float) -> None: ... @@ -489,7 +496,7 @@ class XView: class YView: @overload - def yview(self) -> Tuple[float, float]: ... + def yview(self) -> tuple[float, float]: ... @overload def yview(self, *args: Any) -> Any: ... def yview_moveto(self, fraction: float) -> None: ... @@ -504,7 +511,7 @@ class Wm: @overload def wm_aspect( self, minNumer: None = ..., minDenom: None = ..., maxNumer: None = ..., maxDenom: None = ... - ) -> Tuple[int, int, int, int] | None: ... + ) -> tuple[int, int, int, int] | None: ... aspect = wm_aspect @overload def wm_attributes(self) -> Tuple[Any, ...]: ... @@ -518,7 +525,7 @@ class Wm: @overload def wm_colormapwindows(self) -> list[Misc]: ... @overload - def wm_colormapwindows(self, __wlist: _TkinterSequence[Misc]) -> None: ... + def wm_colormapwindows(self, __wlist: list[Misc] | Tuple[Misc, ...]) -> None: ... @overload def wm_colormapwindows(self, __first_wlist_item: Misc, *other_wlist_items: Misc) -> None: ... colormapwindows = wm_colormapwindows @@ -561,12 +568,12 @@ class Wm: def wm_manage(self, widget): ... manage = wm_manage @overload - def wm_maxsize(self, width: None = ..., height: None = ...) -> Tuple[int, int]: ... + def wm_maxsize(self, width: None = ..., height: None = ...) -> tuple[int, int]: ... @overload def wm_maxsize(self, width: int, height: int) -> None: ... maxsize = wm_maxsize @overload - def wm_minsize(self, width: None = ..., height: None = ...) -> Tuple[int, int]: ... + def wm_minsize(self, width: None = ..., height: None = ...) -> tuple[int, int]: ... @overload def wm_minsize(self, width: int, height: int) -> None: ... minsize = wm_minsize @@ -585,7 +592,7 @@ class Wm: def wm_protocol(self, name: None = ..., func: None = ...) -> Tuple[str, ...]: ... protocol = wm_protocol @overload - def wm_resizable(self, width: None = ..., height: None = ...) -> Tuple[bool, bool]: ... + def wm_resizable(self, width: None = ..., height: None = ...) -> tuple[bool, bool]: ... @overload def wm_resizable(self, width: bool, height: bool) -> None: ... resizable = wm_resizable @@ -610,7 +617,7 @@ class Wm: withdraw = wm_withdraw class _ExceptionReportingCallback(Protocol): - def __call__(self, __exc: Type[BaseException], __val: BaseException, __tb: TracebackType) -> Any: ... + def __call__(self, __exc: Type[BaseException], __val: BaseException, __tb: TracebackType | None) -> Any: ... class Tk(Misc, Wm): master: None @@ -645,9 +652,9 @@ class Tk(Misc, Wm): relief: _Relief = ..., takefocus: _TakeFocusValue = ..., width: _ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def loadtk(self) -> None: ... # differs from _tkinter.TkappType.loadtk def destroy(self) -> None: ... @@ -702,8 +709,8 @@ class _PackInfo(_InMiscTotal): # can be specified in pack(). ipadx: int ipady: int - padx: int | Tuple[int, int] - pady: int | Tuple[int, int] + padx: int | tuple[int, int] + pady: int | tuple[int, int] class Pack: # _PackInfo is not the valid type for cnf because pad stuff accepts any @@ -722,8 +729,8 @@ class Pack: side: Literal["left", "right", "top", "bottom"] = ..., ipadx: _ScreenUnits = ..., ipady: _ScreenUnits = ..., - padx: _ScreenUnits | Tuple[_ScreenUnits, _ScreenUnits] = ..., - pady: _ScreenUnits | Tuple[_ScreenUnits, _ScreenUnits] = ..., + padx: _ScreenUnits | tuple[_ScreenUnits, _ScreenUnits] = ..., + pady: _ScreenUnits | tuple[_ScreenUnits, _ScreenUnits] = ..., in_: Misc = ..., **kw: Any, # allow keyword argument named 'in', see #4836 ) -> None: ... @@ -733,7 +740,7 @@ class Pack: forget = pack_forget propagate = Misc.pack_propagate # commented out to avoid mypy getting confused with multiple - # inheritance and how things get overrided with different things + # inheritance and how things get overridden with different things # info = pack_info # pack_propagate = Misc.pack_propagate # configure = pack_configure @@ -777,7 +784,7 @@ class Place: place = place_configure info = place_info # commented out to avoid mypy getting confused with multiple - # inheritance and how things get overrided with different things + # inheritance and how things get overridden with different things # config = place_configure # configure = place_configure # forget = place_forget @@ -791,8 +798,8 @@ class _GridInfo(_InMiscNonTotal): # empty dict if widget hasn't been gridded rowspan: int ipadx: int ipady: int - padx: int | Tuple[int, int] - pady: int | Tuple[int, int] + padx: int | tuple[int, int] + pady: int | tuple[int, int] sticky: str # consists of letters 'n', 's', 'w', 'e', no repeats, may be empty class Grid: @@ -806,8 +813,8 @@ class Grid: rowspan: int = ..., ipadx: _ScreenUnits = ..., ipady: _ScreenUnits = ..., - padx: _ScreenUnits | Tuple[_ScreenUnits, _ScreenUnits] = ..., - pady: _ScreenUnits | Tuple[_ScreenUnits, _ScreenUnits] = ..., + padx: _ScreenUnits | tuple[_ScreenUnits, _ScreenUnits] = ..., + pady: _ScreenUnits | tuple[_ScreenUnits, _ScreenUnits] = ..., sticky: str = ..., # consists of letters 'n', 's', 'w', 'e', may contain repeats, may be empty in_: Misc = ..., **kw: Any, # allow keyword argument named 'in', see #4836 @@ -819,7 +826,7 @@ class Grid: location = Misc.grid_location size = Misc.grid_size # commented out to avoid mypy getting confused with multiple - # inheritance and how things get overrided with different things + # inheritance and how things get overridden with different things # bbox = Misc.grid_bbox # grid_bbox = Misc.grid_bbox # forget = grid_forget @@ -850,12 +857,15 @@ class Widget(BaseWidget, Pack, Place, Grid): # widgets don't. @overload def bind( - self: _W, sequence: str | None = ..., func: Callable[[Event[_W]], Any] | None = ..., add: bool | None = ... + self: _W, + sequence: str | None = ..., + func: Callable[[Event[_W]], Any] | None = ..., + add: Literal["", "+"] | bool | None = ..., ) -> str: ... @overload - def bind(self, sequence: str | None, func: str, add: bool | None = ...) -> None: ... + def bind(self, sequence: str | None, func: str, add: Literal["", "+"] | bool | None = ...) -> None: ... @overload - def bind(self, *, func: str, add: bool | None = ...) -> None: ... + def bind(self, *, func: str, add: Literal["", "+"] | bool | None = ...) -> None: ... class Toplevel(BaseWidget, Wm): # Toplevel and Tk have the same options because they correspond to the same @@ -887,7 +897,7 @@ class Toplevel(BaseWidget, Wm): screen: str = ..., # can't be changed after creating widget takefocus: _TakeFocusValue = ..., use: int = ..., - visual: str | Tuple[str, int] = ..., + visual: str | tuple[str, int] = ..., width: _ScreenUnits = ..., ) -> None: ... @overload @@ -911,9 +921,9 @@ class Toplevel(BaseWidget, Wm): relief: _Relief = ..., takefocus: _TakeFocusValue = ..., width: _ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure class Button(Widget): @@ -957,7 +967,7 @@ class Button(Widget): state: Literal["normal", "active", "disabled"] = ..., takefocus: _TakeFocusValue = ..., text: float | str = ..., - # We allow the textvariable to be any Variable, not necessarly + # We allow the textvariable to be any Variable, not necessarily # StringVar. This is useful for e.g. a button that displays the value # of an IntVar. textvariable: Variable = ..., @@ -1006,9 +1016,9 @@ class Button(Widget): underline: int = ..., width: _ScreenUnits = ..., wraplength: _ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def flash(self): ... def invoke(self) -> Any: ... @@ -1043,7 +1053,7 @@ class Canvas(Widget, XView, YView): relief: _Relief = ..., # Setting scrollregion to None doesn't reset it back to empty, # but setting it to () does. - scrollregion: Tuple[_ScreenUnits, _ScreenUnits, _ScreenUnits, _ScreenUnits] | Tuple[()] = ..., + scrollregion: tuple[_ScreenUnits, _ScreenUnits, _ScreenUnits, _ScreenUnits] | tuple[()] = ..., selectbackground: _Color = ..., selectborderwidth: _ScreenUnits = ..., selectforeground: _Color = ..., @@ -1080,7 +1090,7 @@ class Canvas(Widget, XView, YView): insertwidth: _ScreenUnits = ..., offset: Any = ..., # undocumented relief: _Relief = ..., - scrollregion: Tuple[_ScreenUnits, _ScreenUnits, _ScreenUnits, _ScreenUnits] | Tuple[()] = ..., + scrollregion: tuple[_ScreenUnits, _ScreenUnits, _ScreenUnits, _ScreenUnits] | tuple[()] = ..., selectbackground: _Color = ..., selectborderwidth: _ScreenUnits = ..., selectforeground: _Color = ..., @@ -1091,9 +1101,9 @@ class Canvas(Widget, XView, YView): xscrollincrement: _ScreenUnits = ..., yscrollcommand: _XYScrollCommand = ..., yscrollincrement: _ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def addtag(self, *args): ... # internal method def addtag_above(self, newtag: str, tagOrId: str | _CanvasItemId) -> None: ... @@ -1125,26 +1135,28 @@ class Canvas(Widget, XView, YView): # Canvas.bbox() args are `str | _CanvasItemId`, but mypy rejects that # description because it's incompatible with Misc.bbox(), an alias for # Misc.grid_bbox(). Yes it is, but there's not much we can do about it. - def bbox(self, *args: str | _CanvasItemId) -> Tuple[int, int, int, int]: ... # type: ignore + def bbox(self, *args: str | _CanvasItemId) -> tuple[int, int, int, int]: ... # type: ignore @overload def tag_bind( self, tagOrId: str | int, sequence: str | None = ..., func: Callable[[Event[Canvas]], Any] | None = ..., - add: bool | None = ..., + add: Literal["", "+"] | bool | None = ..., ) -> str: ... @overload - def tag_bind(self, tagOrId: str | int, sequence: str | None, func: str, add: bool | None = ...) -> None: ... + def tag_bind( + self, tagOrId: str | int, sequence: str | None, func: str, add: Literal["", "+"] | bool | None = ... + ) -> None: ... @overload - def tag_bind(self, tagOrId: str | int, *, func: str, add: bool | None = ...) -> None: ... + def tag_bind(self, tagOrId: str | int, *, func: str, add: Literal["", "+"] | bool | None = ...) -> None: ... def tag_unbind(self, tagOrId: str | int, sequence: str, funcid: str | None = ...) -> None: ... def canvasx(self, screenx, gridspacing: Any | None = ...): ... def canvasy(self, screeny, gridspacing: Any | None = ...): ... @overload def coords(self) -> list[float]: ... @overload - def coords(self, __args: _TkinterSequence[int] | _TkinterSequence[float]) -> None: ... + def coords(self, __args: list[int] | list[float] | Tuple[float, ...]) -> None: ... @overload def coords(self, __x1: float, __y1: float, *args: float) -> None: ... # create_foo() methods accept coords as a list, a tuple, or as separate arguments. @@ -1160,16 +1172,16 @@ class Canvas(Widget, XView, YView): __x1: float, __y1: float, *, - activedash: str | _TkinterSequence[int] = ..., + activedash: str | list[int] | Tuple[int, ...] = ..., activefill: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., arrow: Literal["first", "last", "both"] = ..., - arrowshape: Tuple[float, float, float] = ..., + arrowshape: tuple[float, float, float] = ..., capstyle: Literal["round", "projecting", "butt"] = ..., - dash: str | _TkinterSequence[int] = ..., + dash: str | list[int] | Tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | _TkinterSequence[int] = ..., + disableddash: str | list[int] | Tuple[int, ...] = ..., disabledfill: _Color = ..., disabledstipple: _Bitmap = ..., disabledwidth: _ScreenUnits = ..., @@ -1180,7 +1192,7 @@ class Canvas(Widget, XView, YView): splinesteps: float = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | _TkinterSequence[str] = ..., + tags: str | list[str] | Tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1188,16 +1200,16 @@ class Canvas(Widget, XView, YView): self, __coords: tuple[float, float, float, float] | list[int] | list[float], *, - activedash: str | _TkinterSequence[int] = ..., + activedash: str | list[int] | Tuple[int, ...] = ..., activefill: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., arrow: Literal["first", "last", "both"] = ..., - arrowshape: Tuple[float, float, float] = ..., + arrowshape: tuple[float, float, float] = ..., capstyle: Literal["round", "projecting", "butt"] = ..., - dash: str | _TkinterSequence[int] = ..., + dash: str | list[int] | Tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | _TkinterSequence[int] = ..., + disableddash: str | list[int] | Tuple[int, ...] = ..., disabledfill: _Color = ..., disabledstipple: _Bitmap = ..., disabledwidth: _ScreenUnits = ..., @@ -1208,7 +1220,7 @@ class Canvas(Widget, XView, YView): splinesteps: float = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | _TkinterSequence[str] = ..., + tags: str | list[str] | Tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1219,15 +1231,15 @@ class Canvas(Widget, XView, YView): __x1: float, __y1: float, *, - activedash: str | _TkinterSequence[int] = ..., + activedash: str | list[int] | Tuple[int, ...] = ..., activefill: _Color = ..., activeoutline: _Color = ..., activeoutlinestipple: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., - dash: str | _TkinterSequence[int] = ..., + dash: str | list[int] | Tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | _TkinterSequence[int] = ..., + disableddash: str | list[int] | Tuple[int, ...] = ..., disabledfill: _Color = ..., disabledoutline: _Color = ..., disabledoutlinestipple: _Color = ..., @@ -1240,7 +1252,7 @@ class Canvas(Widget, XView, YView): outlinestipple: _Bitmap = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | _TkinterSequence[str] = ..., + tags: str | list[str] | Tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1248,15 +1260,15 @@ class Canvas(Widget, XView, YView): self, __coords: tuple[float, float, float, float] | list[int] | list[float], *, - activedash: str | _TkinterSequence[int] = ..., + activedash: str | list[int] | Tuple[int, ...] = ..., activefill: _Color = ..., activeoutline: _Color = ..., activeoutlinestipple: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., - dash: str | _TkinterSequence[int] = ..., + dash: str | list[int] | Tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | _TkinterSequence[int] = ..., + disableddash: str | list[int] | Tuple[int, ...] = ..., disabledfill: _Color = ..., disabledoutline: _Color = ..., disabledoutlinestipple: _Color = ..., @@ -1269,7 +1281,7 @@ class Canvas(Widget, XView, YView): outlinestipple: _Bitmap = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | _TkinterSequence[str] = ..., + tags: str | list[str] | Tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1280,15 +1292,15 @@ class Canvas(Widget, XView, YView): __x1: float, __y1: float, *xy_pairs: float, - activedash: str | _TkinterSequence[int] = ..., + activedash: str | list[int] | Tuple[int, ...] = ..., activefill: _Color = ..., activeoutline: _Color = ..., activeoutlinestipple: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., - dash: str | _TkinterSequence[int] = ..., + dash: str | list[int] | Tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | _TkinterSequence[int] = ..., + disableddash: str | list[int] | Tuple[int, ...] = ..., disabledfill: _Color = ..., disabledoutline: _Color = ..., disabledoutlinestipple: _Color = ..., @@ -1304,7 +1316,7 @@ class Canvas(Widget, XView, YView): splinesteps: float = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | _TkinterSequence[str] = ..., + tags: str | list[str] | Tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1312,15 +1324,15 @@ class Canvas(Widget, XView, YView): self, __coords: Tuple[float, ...] | list[int] | list[float], *, - activedash: str | _TkinterSequence[int] = ..., + activedash: str | list[int] | Tuple[int, ...] = ..., activefill: _Color = ..., activeoutline: _Color = ..., activeoutlinestipple: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., - dash: str | _TkinterSequence[int] = ..., + dash: str | list[int] | Tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | _TkinterSequence[int] = ..., + disableddash: str | list[int] | Tuple[int, ...] = ..., disabledfill: _Color = ..., disabledoutline: _Color = ..., disabledoutlinestipple: _Color = ..., @@ -1336,7 +1348,7 @@ class Canvas(Widget, XView, YView): splinesteps: float = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | _TkinterSequence[str] = ..., + tags: str | list[str] | Tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1347,15 +1359,15 @@ class Canvas(Widget, XView, YView): __x1: float, __y1: float, *, - activedash: str | _TkinterSequence[int] = ..., + activedash: str | list[int] | Tuple[int, ...] = ..., activefill: _Color = ..., activeoutline: _Color = ..., activeoutlinestipple: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., - dash: str | _TkinterSequence[int] = ..., + dash: str | list[int] | Tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | _TkinterSequence[int] = ..., + disableddash: str | list[int] | Tuple[int, ...] = ..., disabledfill: _Color = ..., disabledoutline: _Color = ..., disabledoutlinestipple: _Color = ..., @@ -1368,7 +1380,7 @@ class Canvas(Widget, XView, YView): outlinestipple: _Bitmap = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | _TkinterSequence[str] = ..., + tags: str | list[str] | Tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1376,15 +1388,15 @@ class Canvas(Widget, XView, YView): self, __coords: tuple[float, float, float, float] | list[int] | list[float], *, - activedash: str | _TkinterSequence[int] = ..., + activedash: str | list[int] | Tuple[int, ...] = ..., activefill: _Color = ..., activeoutline: _Color = ..., activeoutlinestipple: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., - dash: str | _TkinterSequence[int] = ..., + dash: str | list[int] | Tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | _TkinterSequence[int] = ..., + disableddash: str | list[int] | Tuple[int, ...] = ..., disabledfill: _Color = ..., disabledoutline: _Color = ..., disabledoutlinestipple: _Color = ..., @@ -1397,7 +1409,7 @@ class Canvas(Widget, XView, YView): outlinestipple: _Bitmap = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | _TkinterSequence[str] = ..., + tags: str | list[str] | Tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1417,7 +1429,7 @@ class Canvas(Widget, XView, YView): offset: _ScreenUnits = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | _TkinterSequence[str] = ..., + tags: str | list[str] | Tuple[str, ...] = ..., text: float | str = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @@ -1437,7 +1449,7 @@ class Canvas(Widget, XView, YView): offset: _ScreenUnits = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | _TkinterSequence[str] = ..., + tags: str | list[str] | Tuple[str, ...] = ..., text: float | str = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @@ -1450,7 +1462,7 @@ class Canvas(Widget, XView, YView): anchor: _Anchor = ..., height: _ScreenUnits = ..., state: Literal["normal", "active", "disabled"] = ..., - tags: str | _TkinterSequence[str] = ..., + tags: str | list[str] | Tuple[str, ...] = ..., width: _ScreenUnits = ..., window: Widget = ..., ) -> _CanvasItemId: ... @@ -1462,7 +1474,7 @@ class Canvas(Widget, XView, YView): anchor: _Anchor = ..., height: _ScreenUnits = ..., state: Literal["normal", "active", "disabled"] = ..., - tags: str | _TkinterSequence[str] = ..., + tags: str | list[str] | Tuple[str, ...] = ..., width: _ScreenUnits = ..., window: Widget = ..., ) -> _CanvasItemId: ... @@ -1614,9 +1626,9 @@ class Checkbutton(Widget): variable: Variable | Literal[""] = ..., width: _ScreenUnits = ..., wraplength: _ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def deselect(self): ... def flash(self): ... @@ -1713,9 +1725,9 @@ class Entry(Widget, XView): vcmd: _EntryValidateCommand = ..., width: int = ..., xscrollcommand: _XYScrollCommand = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def delete(self, first: _EntryIndex, last: _EntryIndex | None = ...) -> None: ... def get(self) -> str: ... @@ -1761,7 +1773,7 @@ class Frame(Widget): pady: _ScreenUnits = ..., relief: _Relief = ..., takefocus: _TakeFocusValue = ..., - visual: str | Tuple[str, int] = ..., + visual: str | tuple[str, int] = ..., width: _ScreenUnits = ..., ) -> None: ... @overload @@ -1784,9 +1796,9 @@ class Frame(Widget): relief: _Relief = ..., takefocus: _TakeFocusValue = ..., width: _ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure class Label(Widget): @@ -1864,9 +1876,9 @@ class Label(Widget): underline: int = ..., width: _ScreenUnits = ..., wraplength: _ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure class Listbox(Widget, XView, YView): @@ -1954,9 +1966,9 @@ class Listbox(Widget, XView, YView): width: int = ..., xscrollcommand: _XYScrollCommand = ..., yscrollcommand: _XYScrollCommand = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def activate(self, index): ... def bbox(self, index): ... @@ -2042,9 +2054,9 @@ class Menu(Widget): tearoffcommand: Callable[[str, str], Any] | str = ..., title: str = ..., type: Literal["menubar", "tearoff", "normal"] = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def tk_popup(self, x: int, y: int, entry: _MenuIndex = ...) -> None: ... def activate(self, index: _MenuIndex) -> None: ... @@ -2244,7 +2256,7 @@ class Menu(Widget): def entrycget(self, index: _MenuIndex, option: str) -> Any: ... def entryconfigure( self, index: _MenuIndex, cnf: dict[str, Any] | None = ..., **kw: Any - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... entryconfig = entryconfigure def index(self, index: _MenuIndex) -> int | None: ... def invoke(self, index: _MenuIndex) -> Any: ... @@ -2335,9 +2347,9 @@ class Menubutton(Widget): underline: int = ..., width: _ScreenUnits = ..., wraplength: _ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure class Message(Widget): @@ -2398,9 +2410,9 @@ class Message(Widget): text: float | str = ..., textvariable: Variable = ..., width: _ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure class Radiobutton(Widget): @@ -2498,9 +2510,9 @@ class Radiobutton(Widget): variable: Variable | Literal[""] = ..., width: _ScreenUnits = ..., wraplength: _ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def deselect(self): ... def flash(self): ... @@ -2589,9 +2601,9 @@ class Scale(Widget): troughcolor: _Color = ..., variable: IntVar | DoubleVar = ..., width: _ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def get(self): ... def set(self, value): ... @@ -2615,7 +2627,7 @@ class Scrollbar(Widget): # 'SCROLLING COMMANDS' in scrollbar man page. There doesn't seem to # be any way to specify an overloaded callback function, so we say # that it can take any args while it can't in reality. - command: Callable[..., Tuple[float, float] | None] | str = ..., + command: Callable[..., tuple[float, float] | None] | str = ..., cursor: _Cursor = ..., elementborderwidth: _ScreenUnits = ..., highlightbackground: _Color = ..., @@ -2643,7 +2655,7 @@ class Scrollbar(Widget): bg: _Color = ..., border: _ScreenUnits = ..., borderwidth: _ScreenUnits = ..., - command: Callable[..., Tuple[float, float] | None] | str = ..., + command: Callable[..., tuple[float, float] | None] | str = ..., cursor: _Cursor = ..., elementborderwidth: _ScreenUnits = ..., highlightbackground: _Color = ..., @@ -2657,9 +2669,9 @@ class Scrollbar(Widget): takefocus: _TakeFocusValue = ..., troughcolor: _Color = ..., width: _ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def activate(self, index: Any | None = ...): ... def delta(self, deltax, deltay): ... @@ -2777,11 +2789,11 @@ class Text(Widget, XView, YView): wrap: Literal["none", "char", "word"] = ..., xscrollcommand: _XYScrollCommand = ..., yscrollcommand: _XYScrollCommand = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure - def bbox(self, index: _TextIndex) -> Tuple[int, int, int, int] | None: ... # type: ignore + def bbox(self, index: _TextIndex) -> tuple[int, int, int, int] | None: ... # type: ignore def compare(self, index1: _TextIndex, op: Literal["<", "<=", "==", ">=", ">", "!="], index2: _TextIndex) -> bool: ... def count(self, index1, index2, *args): ... # TODO @overload @@ -2789,7 +2801,7 @@ class Text(Widget, XView, YView): @overload def debug(self, boolean: bool) -> None: ... def delete(self, index1: _TextIndex, index2: _TextIndex | None = ...) -> None: ... - def dlineinfo(self, index: _TextIndex) -> Tuple[int, int, int, int, int] | None: ... + def dlineinfo(self, index: _TextIndex) -> tuple[int, int, int, int, int] | None: ... @overload def dump( self, @@ -2803,7 +2815,7 @@ class Text(Widget, XView, YView): tag: bool = ..., text: bool = ..., window: bool = ..., - ) -> list[Tuple[str, str, str]]: ... + ) -> list[tuple[str, str, str]]: ... @overload def dump( self, @@ -2848,7 +2860,7 @@ class Text(Widget, XView, YView): def image_create(self, index, cnf=..., **kw): ... def image_names(self): ... def index(self, index: _TextIndex) -> str: ... - def insert(self, index: _TextIndex, chars: str, *args: str | _TkinterSequence[str]) -> None: ... + def insert(self, index: _TextIndex, chars: str, *args: str | list[str] | Tuple[str, ...]) -> None: ... @overload def mark_gravity(self, markName: str, direction: None = ...) -> Literal["left", "right"]: ... @overload @@ -2861,7 +2873,7 @@ class Text(Widget, XView, YView): # **kw of peer_create is same as the kwargs of Text.__init__ def peer_create(self, newPathName: str | Text, cnf: dict[str, Any] = ..., **kw: Any) -> None: ... def peer_names(self) -> Tuple[_tkinter.Tcl_Obj, ...]: ... - def replace(self, index1: _TextIndex, index2: _TextIndex, chars: str, *args: str | _TkinterSequence[str]) -> None: ... + def replace(self, index1: _TextIndex, index2: _TextIndex, chars: str, *args: str | list[str] | Tuple[str, ...]) -> None: ... def scan_mark(self, x: int, y: int) -> None: ... def scan_dragto(self, x: int, y: int) -> None: ... def search( @@ -2882,10 +2894,14 @@ class Text(Widget, XView, YView): # tag_bind stuff is very similar to Canvas @overload def tag_bind( - self, tagName: str, sequence: str | None, func: Callable[[Event[Text]], Any] | None, add: bool | None = ... + self, + tagName: str, + sequence: str | None, + func: Callable[[Event[Text]], Any] | None, + add: Literal["", "+"] | bool | None = ..., ) -> str: ... @overload - def tag_bind(self, tagName: str, sequence: str | None, func: str, add: bool | None = ...) -> None: ... + def tag_bind(self, tagName: str, sequence: str | None, func: str, add: Literal["", "+"] | bool | None = ...) -> None: ... def tag_unbind(self, tagName: str, sequence: str, funcid: str | None = ...) -> None: ... # allowing any string for cget instead of just Literals because there's no other way to look up tag options def tag_cget(self, tagName: str, option: str) -> Any: ... @@ -2923,15 +2939,15 @@ class Text(Widget, XView, YView): underline: bool = ..., underlinefg: _Color = ..., wrap: Literal["none", "char", "word"] = ..., # be careful with "none" vs None - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def tag_configure(self, tagName: str, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def tag_configure(self, tagName: str, cnf: str) -> tuple[str, str, str, Any, Any]: ... tag_config = tag_configure def tag_delete(self, __first_tag_name: str, *tagNames: str) -> None: ... # error if no tag names given def tag_lower(self, tagName: str, belowThis: str | None = ...) -> None: ... def tag_names(self, index: _TextIndex | None = ...) -> Tuple[str, ...]: ... - def tag_nextrange(self, tagName: str, index1: _TextIndex, index2: _TextIndex | None = ...) -> Tuple[str, str] | Tuple[()]: ... - def tag_prevrange(self, tagName: str, index1: _TextIndex, index2: _TextIndex | None = ...) -> Tuple[str, str] | Tuple[()]: ... + def tag_nextrange(self, tagName: str, index1: _TextIndex, index2: _TextIndex | None = ...) -> tuple[str, str] | tuple[()]: ... + def tag_prevrange(self, tagName: str, index1: _TextIndex, index2: _TextIndex | None = ...) -> tuple[str, str] | tuple[()]: ... def tag_raise(self, tagName: str, aboveThis: str | None = ...) -> None: ... def tag_ranges(self, tagName: str) -> Tuple[_tkinter.Tcl_Obj, ...]: ... # tag_remove and tag_delete are different @@ -2963,7 +2979,7 @@ class OptionMenu(Menubutton): command: Callable[[StringVar], Any] | None = ..., ) -> None: ... # configure, config, cget are inherited from Menubutton - # destroy and __getitem__ are overrided, signature does not change + # destroy and __getitem__ are overridden, signature does not change class _Image(Protocol): tk: _tkinter.TkappType @@ -3016,9 +3032,21 @@ class PhotoImage(Image): def copy(self) -> PhotoImage: ... def zoom(self, x: int, y: int | Literal[""] = ...) -> PhotoImage: ... def subsample(self, x: int, y: int | Literal[""] = ...) -> PhotoImage: ... - def get(self, x: int, y: int) -> Tuple[int, int, int]: ... - def put(self, data: str | _TkinterSequence[str] | _TkinterSequence2D[_Color], to: Tuple[int, int] | None = ...) -> None: ... - def write(self, filename: StrOrBytesPath, format: str | None = ..., from_coords: Tuple[int, int] | None = ...) -> None: ... + def get(self, x: int, y: int) -> tuple[int, int, int]: ... + def put( + self, + data: ( + str + | list[str] + | list[list[_Color]] + | list[Tuple[_Color, ...]] + | Tuple[str, ...] + | Tuple[list[_Color], ...] + | Tuple[Tuple[_Color, ...], ...] + ), + to: tuple[int, int] | None = ..., + ) -> None: ... + def write(self, filename: StrOrBytesPath, format: str | None = ..., from_coords: tuple[int, int] | None = ...) -> None: ... if sys.version_info >= (3, 8): def transparency_get(self, x: int, y: int) -> bool: ... def transparency_set(self, x: int, y: int, boolean: bool) -> None: ... @@ -3057,8 +3085,8 @@ class Spinbox(Widget, XView): buttoncursor: _Cursor = ..., buttondownrelief: _Relief = ..., buttonuprelief: _Relief = ..., - # percent substitutions don't seem to be supported, it's similar to Entry's validion stuff - command: Callable[[], Any] | str | _TkinterSequence[str] = ..., + # percent substitutions don't seem to be supported, it's similar to Entry's validation stuff + command: Callable[[], Any] | str | list[str] | Tuple[str, ...] = ..., cursor: _Cursor = ..., disabledbackground: _Color = ..., disabledforeground: _Color = ..., @@ -3095,7 +3123,7 @@ class Spinbox(Widget, XView): validate: Literal["none", "focus", "focusin", "focusout", "key", "all"] = ..., validatecommand: _EntryValidateCommand = ..., vcmd: _EntryValidateCommand = ..., - values: _TkinterSequence[str] = ..., + values: list[str] | Tuple[str, ...] = ..., width: int = ..., wrap: bool = ..., xscrollcommand: _XYScrollCommand = ..., @@ -3115,7 +3143,7 @@ class Spinbox(Widget, XView): buttoncursor: _Cursor = ..., buttondownrelief: _Relief = ..., buttonuprelief: _Relief = ..., - command: Callable[[], Any] | str | _TkinterSequence[str] = ..., + command: Callable[[], Any] | str | list[str] | Tuple[str, ...] = ..., cursor: _Cursor = ..., disabledbackground: _Color = ..., disabledforeground: _Color = ..., @@ -3151,13 +3179,13 @@ class Spinbox(Widget, XView): validate: Literal["none", "focus", "focusin", "focusout", "key", "all"] = ..., validatecommand: _EntryValidateCommand = ..., vcmd: _EntryValidateCommand = ..., - values: _TkinterSequence[str] = ..., + values: list[str] | Tuple[str, ...] = ..., width: int = ..., wrap: bool = ..., xscrollcommand: _XYScrollCommand = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def bbox(self, index): ... def delete(self, first, last: Any | None = ...): ... @@ -3212,7 +3240,7 @@ class LabelFrame(Widget): relief: _Relief = ..., takefocus: _TakeFocusValue = ..., text: float | str = ..., - visual: str | Tuple[str, int] = ..., + visual: str | tuple[str, int] = ..., width: _ScreenUnits = ..., ) -> None: ... @overload @@ -3241,9 +3269,9 @@ class LabelFrame(Widget): takefocus: _TakeFocusValue = ..., text: float | str = ..., width: _ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure class PanedWindow(Widget): @@ -3301,9 +3329,9 @@ class PanedWindow(Widget): sashwidth: _ScreenUnits = ..., showhandle: bool = ..., width: _ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def add(self, child: Widget, **kw): ... def remove(self, child): ... diff --git a/mypy/typeshed/stdlib/tkinter/colorchooser.pyi b/mypy/typeshed/stdlib/tkinter/colorchooser.pyi index 184f9a2c9914..b5fdc7c54914 100644 --- a/mypy/typeshed/stdlib/tkinter/colorchooser.pyi +++ b/mypy/typeshed/stdlib/tkinter/colorchooser.pyi @@ -1,7 +1,7 @@ from tkinter.commondialog import Dialog -from typing import Any, ClassVar, Tuple +from typing import Any, ClassVar class Chooser(Dialog): command: ClassVar[str] -def askcolor(color: str | bytes | None = ..., **options: Any) -> Tuple[None, None] | Tuple[Tuple[float, float, float], str]: ... +def askcolor(color: str | bytes | None = ..., **options: Any) -> tuple[None, None] | tuple[tuple[float, float, float], str]: ... diff --git a/mypy/typeshed/stdlib/tkinter/filedialog.pyi b/mypy/typeshed/stdlib/tkinter/filedialog.pyi index ca5ecfff262d..0fc7d6e8a3bc 100644 --- a/mypy/typeshed/stdlib/tkinter/filedialog.pyi +++ b/mypy/typeshed/stdlib/tkinter/filedialog.pyi @@ -1,9 +1,9 @@ from _typeshed import StrOrBytesPath -from tkinter import Button, Entry, Frame, Listbox, Misc, Scrollbar, StringVar, Toplevel, _TkinterSequence, commondialog +from tkinter import Button, Entry, Frame, Listbox, Misc, Scrollbar, StringVar, Toplevel, commondialog from typing import IO, Any, ClassVar, Iterable, Tuple from typing_extensions import Literal -dialogstates: dict[Any, Tuple[Any, Any]] +dialogstates: dict[Any, tuple[Any, Any]] class FileDialog: title: str @@ -64,7 +64,7 @@ def asksaveasfilename( *, confirmoverwrite: bool | None = ..., defaultextension: str | None = ..., - filetypes: Iterable[Tuple[str, str] | Tuple[str, _TkinterSequence[str]]] | None = ..., + filetypes: Iterable[tuple[str, str | list[str] | Tuple[str, ...]]] | None = ..., initialdir: StrOrBytesPath | None = ..., initialfile: StrOrBytesPath | None = ..., parent: Misc | None = ..., @@ -74,7 +74,7 @@ def asksaveasfilename( def askopenfilename( *, defaultextension: str | None = ..., - filetypes: Iterable[Tuple[str, str] | Tuple[str, _TkinterSequence[str]]] | None = ..., + filetypes: Iterable[tuple[str, str | list[str] | Tuple[str, ...]]] | None = ..., initialdir: StrOrBytesPath | None = ..., initialfile: StrOrBytesPath | None = ..., parent: Misc | None = ..., @@ -84,7 +84,7 @@ def askopenfilename( def askopenfilenames( *, defaultextension: str | None = ..., - filetypes: Iterable[Tuple[str, str] | Tuple[str, _TkinterSequence[str]]] | None = ..., + filetypes: Iterable[tuple[str, str | list[str] | Tuple[str, ...]]] | None = ..., initialdir: StrOrBytesPath | None = ..., initialfile: StrOrBytesPath | None = ..., parent: Misc | None = ..., @@ -101,7 +101,7 @@ def asksaveasfile( *, confirmoverwrite: bool | None = ..., defaultextension: str | None = ..., - filetypes: Iterable[Tuple[str, str] | Tuple[str, _TkinterSequence[str]]] | None = ..., + filetypes: Iterable[tuple[str, str | list[str] | Tuple[str, ...]]] | None = ..., initialdir: StrOrBytesPath | None = ..., initialfile: StrOrBytesPath | None = ..., parent: Misc | None = ..., @@ -112,7 +112,7 @@ def askopenfile( mode: str = ..., *, defaultextension: str | None = ..., - filetypes: Iterable[Tuple[str, str] | Tuple[str, _TkinterSequence[str]]] | None = ..., + filetypes: Iterable[tuple[str, str | list[str] | Tuple[str, ...]]] | None = ..., initialdir: StrOrBytesPath | None = ..., initialfile: StrOrBytesPath | None = ..., parent: Misc | None = ..., @@ -123,7 +123,7 @@ def askopenfiles( mode: str = ..., *, defaultextension: str | None = ..., - filetypes: Iterable[Tuple[str, str] | Tuple[str, _TkinterSequence[str]]] | None = ..., + filetypes: Iterable[tuple[str, str | list[str] | Tuple[str, ...]]] | None = ..., initialdir: StrOrBytesPath | None = ..., initialfile: StrOrBytesPath | None = ..., parent: Misc | None = ..., diff --git a/mypy/typeshed/stdlib/tkinter/font.pyi b/mypy/typeshed/stdlib/tkinter/font.pyi index df828c448ae3..fccc0fbf1f0a 100644 --- a/mypy/typeshed/stdlib/tkinter/font.pyi +++ b/mypy/typeshed/stdlib/tkinter/font.pyi @@ -1,7 +1,7 @@ import _tkinter import sys import tkinter -from typing import Any, Tuple, Union, overload +from typing import Any, List, Tuple, Union, overload from typing_extensions import Literal, TypedDict NORMAL: Literal["normal"] @@ -15,7 +15,8 @@ _FontDescription = Union[ # A font object constructed in Python Font, # ("Helvetica", 12, BOLD) - tkinter._TkinterSequence[Any], + List[Any], + Tuple[Any, ...], # A font object constructed in Tcl _tkinter.Tcl_Obj, ] diff --git a/mypy/typeshed/stdlib/tkinter/tix.pyi b/mypy/typeshed/stdlib/tkinter/tix.pyi index 3518802aaa71..3037212c0ad1 100644 --- a/mypy/typeshed/stdlib/tkinter/tix.pyi +++ b/mypy/typeshed/stdlib/tkinter/tix.pyi @@ -193,7 +193,7 @@ class HList(TixWidget, tkinter.XView, tkinter.YView): def indicator_delete(self, entry: str) -> None: ... def indicator_size(self, entry: str) -> int: ... def info_anchor(self) -> str: ... - def info_bbox(self, entry: str) -> Tuple[int, int, int, int]: ... + def info_bbox(self, entry: str) -> tuple[int, int, int, int]: ... def info_children(self, entry: str | None = ...) -> Tuple[str, ...]: ... def info_data(self, entry: str) -> Any: ... def info_dragsite(self) -> str: ... @@ -296,6 +296,6 @@ class Form: def form(self, cnf: dict[str, Any] = ..., **kw: Any) -> None: ... def check(self) -> bool: ... def forget(self) -> None: ... - def grid(self, xsize: int = ..., ysize: int = ...) -> Tuple[int, int] | None: ... + def grid(self, xsize: int = ..., ysize: int = ...) -> tuple[int, int] | None: ... def info(self, option: str | None = ...) -> Any: ... def slaves(self) -> list[tkinter.Widget]: ... diff --git a/mypy/typeshed/stdlib/tkinter/ttk.pyi b/mypy/typeshed/stdlib/tkinter/ttk.pyi index 9569239a7861..be0713ec2e4b 100644 --- a/mypy/typeshed/stdlib/tkinter/ttk.pyi +++ b/mypy/typeshed/stdlib/tkinter/ttk.pyi @@ -75,9 +75,9 @@ class Button(Widget): textvariable: tkinter.Variable = ..., underline: int = ..., width: int | Literal[""] = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def invoke(self) -> Any: ... @@ -127,9 +127,9 @@ class Checkbutton(Widget): underline: int = ..., variable: tkinter.Variable = ..., width: int | Literal[""] = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def invoke(self) -> Any: ... @@ -179,9 +179,9 @@ class Entry(Widget, tkinter.Entry): validatecommand: tkinter._EntryValidateCommand = ..., width: int = ..., xscrollcommand: tkinter._XYScrollCommand = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... # config must be copy/pasted, otherwise ttk.Entry().config is mypy error (don't know why) @overload # type: ignore def config( @@ -204,9 +204,9 @@ class Entry(Widget, tkinter.Entry): validatecommand: tkinter._EntryValidateCommand = ..., width: int = ..., xscrollcommand: tkinter._XYScrollCommand = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def config(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def config(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... def bbox(self, index): ... def identify(self, x, y): ... def validate(self): ... @@ -234,7 +234,7 @@ class Combobox(Entry): textvariable: tkinter.Variable = ..., validate: Literal["none", "focus", "focusin", "focusout", "key", "all"] = ..., # undocumented validatecommand: tkinter._EntryValidateCommand = ..., # undocumented - values: tkinter._TkinterSequence[str] = ..., + values: list[str] | Tuple[str, ...] = ..., width: int = ..., xscrollcommand: tkinter._XYScrollCommand = ..., # undocumented ) -> None: ... @@ -259,12 +259,12 @@ class Combobox(Entry): textvariable: tkinter.Variable = ..., validate: Literal["none", "focus", "focusin", "focusout", "key", "all"] = ..., validatecommand: tkinter._EntryValidateCommand = ..., - values: tkinter._TkinterSequence[str] = ..., + values: list[str] | Tuple[str, ...] = ..., width: int = ..., xscrollcommand: tkinter._XYScrollCommand = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... # config must be copy/pasted, otherwise ttk.Combobox().config is mypy error (don't know why) @overload # type: ignore def config( @@ -287,12 +287,12 @@ class Combobox(Entry): textvariable: tkinter.Variable = ..., validate: Literal["none", "focus", "focusin", "focusout", "key", "all"] = ..., validatecommand: tkinter._EntryValidateCommand = ..., - values: tkinter._TkinterSequence[str] = ..., + values: list[str] | Tuple[str, ...] = ..., width: int = ..., xscrollcommand: tkinter._XYScrollCommand = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def config(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def config(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... def current(self, newindex: Any | None = ...): ... def set(self, value): ... @@ -327,9 +327,9 @@ class Frame(Widget): style: str = ..., takefocus: tkinter._TakeFocusValue = ..., width: tkinter._ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure class Label(Widget): @@ -385,9 +385,9 @@ class Label(Widget): underline: int = ..., width: int | Literal[""] = ..., wraplength: tkinter._ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure class Labelframe(Widget): @@ -429,9 +429,9 @@ class Labelframe(Widget): text: float | str = ..., underline: int = ..., width: tkinter._ScreenUnits = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure LabelFrame = Labelframe @@ -475,9 +475,9 @@ class Menubutton(Widget): textvariable: tkinter.Variable = ..., underline: int = ..., width: int | Literal[""] = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure class Notebook(Widget): @@ -505,9 +505,9 @@ class Notebook(Widget): style: str = ..., takefocus: tkinter._TakeFocusValue = ..., width: int = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def add( self, @@ -557,9 +557,9 @@ class Panedwindow(Widget, tkinter.PanedWindow): style: str = ..., takefocus: tkinter._TakeFocusValue = ..., width: int = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... # config must be copy/pasted, otherwise ttk.Panedwindow().config is mypy error (don't know why) @overload # type: ignore def config( @@ -571,9 +571,9 @@ class Panedwindow(Widget, tkinter.PanedWindow): style: str = ..., takefocus: tkinter._TakeFocusValue = ..., width: int = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def config(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def config(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... forget: Any def insert(self, pos, child, **kw): ... def pane(self, pane, option: Any | None = ..., **kw): ... @@ -614,9 +614,9 @@ class Progressbar(Widget): takefocus: tkinter._TakeFocusValue = ..., value: float = ..., variable: tkinter.IntVar | tkinter.DoubleVar = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def start(self, interval: Any | None = ...): ... def step(self, amount: Any | None = ...): ... @@ -663,9 +663,9 @@ class Radiobutton(Widget): value: Any = ..., variable: tkinter.Variable | Literal[""] = ..., width: int | Literal[""] = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure def invoke(self) -> Any: ... @@ -704,9 +704,9 @@ class Scale(Widget, tkinter.Scale): to: float = ..., value: float = ..., variable: tkinter.IntVar | tkinter.DoubleVar = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... # config must be copy/pasted, otherwise ttk.Scale().config is mypy error (don't know why) @overload # type: ignore def config( @@ -724,9 +724,9 @@ class Scale(Widget, tkinter.Scale): to: float = ..., value: float = ..., variable: tkinter.IntVar | tkinter.DoubleVar = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def config(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def config(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... def get(self, x: Any | None = ..., y: Any | None = ...): ... class Scrollbar(Widget, tkinter.Scrollbar): @@ -735,7 +735,7 @@ class Scrollbar(Widget, tkinter.Scrollbar): master: tkinter.Misc | None = ..., *, class_: str = ..., - command: Callable[..., Tuple[float, float] | None] | str = ..., + command: Callable[..., tuple[float, float] | None] | str = ..., cursor: tkinter._Cursor = ..., name: str = ..., orient: Literal["horizontal", "vertical"] = ..., @@ -747,28 +747,28 @@ class Scrollbar(Widget, tkinter.Scrollbar): self, cnf: dict[str, Any] | None = ..., *, - command: Callable[..., Tuple[float, float] | None] | str = ..., + command: Callable[..., tuple[float, float] | None] | str = ..., cursor: tkinter._Cursor = ..., orient: Literal["horizontal", "vertical"] = ..., style: str = ..., takefocus: tkinter._TakeFocusValue = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... # config must be copy/pasted, otherwise ttk.Scrollbar().config is mypy error (don't know why) @overload # type: ignore def config( self, cnf: dict[str, Any] | None = ..., *, - command: Callable[..., Tuple[float, float] | None] | str = ..., + command: Callable[..., tuple[float, float] | None] | str = ..., cursor: tkinter._Cursor = ..., orient: Literal["horizontal", "vertical"] = ..., style: str = ..., takefocus: tkinter._TakeFocusValue = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def config(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def config(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... class Separator(Widget): def __init__( @@ -791,9 +791,9 @@ class Separator(Widget): orient: Literal["horizontal", "vertical"] = ..., style: str = ..., takefocus: tkinter._TakeFocusValue = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure class Sizegrip(Widget): @@ -815,9 +815,9 @@ class Sizegrip(Widget): cursor: tkinter._Cursor = ..., style: str = ..., takefocus: tkinter._TakeFocusValue = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure if sys.version_info >= (3, 7): @@ -828,7 +828,7 @@ if sys.version_info >= (3, 7): *, background: tkinter._Color = ..., # undocumented class_: str = ..., - command: Callable[[], Any] | str | tkinter._TkinterSequence[str] = ..., + command: Callable[[], Any] | str | list[str] | Tuple[str, ...] = ..., cursor: tkinter._Cursor = ..., exportselection: bool = ..., # undocumented font: _FontDescription = ..., # undocumented @@ -847,7 +847,7 @@ if sys.version_info >= (3, 7): to: float = ..., validate: Literal["none", "focus", "focusin", "focusout", "key", "all"] = ..., validatecommand: tkinter._EntryValidateCommand = ..., - values: tkinter._TkinterSequence[str] = ..., + values: list[str] | Tuple[str, ...] = ..., width: int = ..., # undocumented wrap: bool = ..., xscrollcommand: tkinter._XYScrollCommand = ..., @@ -858,7 +858,7 @@ if sys.version_info >= (3, 7): cnf: dict[str, Any] | None = ..., *, background: tkinter._Color = ..., - command: Callable[[], Any] | str | tkinter._TkinterSequence[str] = ..., + command: Callable[[], Any] | str | list[str] | Tuple[str, ...] = ..., cursor: tkinter._Cursor = ..., exportselection: bool = ..., font: _FontDescription = ..., @@ -876,22 +876,22 @@ if sys.version_info >= (3, 7): to: float = ..., validate: Literal["none", "focus", "focusin", "focusout", "key", "all"] = ..., validatecommand: tkinter._EntryValidateCommand = ..., - values: tkinter._TkinterSequence[str] = ..., + values: list[str] | Tuple[str, ...] = ..., width: int = ..., wrap: bool = ..., xscrollcommand: tkinter._XYScrollCommand = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure # type: ignore def set(self, value: Any) -> None: ... class _TreeviewItemDict(TypedDict): text: str - image: Literal[""] | list[str] # no idea why it's wrapped in list - values: list[Any] + image: list[str] | Literal[""] # no idea why it's wrapped in list + values: list[Any] | Literal[""] open: bool # actually 0 or 1 - tags: list[str] + tags: list[str] | Literal[""] class _TreeviewTagDict(TypedDict): # There is also 'text' and 'anchor', but they don't seem to do anything, using them is likely a bug @@ -922,18 +922,18 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): master: tkinter.Misc | None = ..., *, class_: str = ..., - columns: str | tkinter._TkinterSequence[str] = ..., + columns: str | list[str] | Tuple[str, ...] = ..., cursor: tkinter._Cursor = ..., - displaycolumns: str | tkinter._TkinterSequence[str] | tkinter._TkinterSequence[int] | Literal["#all"] = ..., + displaycolumns: str | list[str] | Tuple[str, ...] | list[int] | Tuple[int, ...] | Literal["#all"] = ..., height: int = ..., name: str = ..., padding: tkinter._Padding = ..., selectmode: Literal["extended", "browse", "none"] = ..., - # _TkinterSequences of Literal don't actually work, using str instead. + # list/tuple of Literal don't actually work in mypy # # 'tree headings' is same as ['tree', 'headings'], and I wouldn't be - # surprised if someone was using it. - show: Literal["tree", "headings", "tree headings"] | tkinter._TkinterSequence[str] = ..., + # surprised if someone is using it. + show: Literal["tree", "headings", "tree headings", ""] | list[str] | Tuple[str, ...] = ..., style: str = ..., takefocus: tkinter._TakeFocusValue = ..., xscrollcommand: tkinter._XYScrollCommand = ..., @@ -944,22 +944,22 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): self, cnf: dict[str, Any] | None = ..., *, - columns: str | tkinter._TkinterSequence[str] = ..., + columns: str | list[str] | Tuple[str, ...] = ..., cursor: tkinter._Cursor = ..., - displaycolumns: str | tkinter._TkinterSequence[str] | tkinter._TkinterSequence[int] | Literal["#all"] = ..., + displaycolumns: str | list[str] | Tuple[str, ...] | list[int] | Tuple[int, ...] | Literal["#all"] = ..., height: int = ..., padding: tkinter._Padding = ..., selectmode: Literal["extended", "browse", "none"] = ..., - show: Literal["tree", "headings", "tree headings"] | tkinter._TkinterSequence[str] = ..., + show: Literal["tree", "headings", "tree headings", ""] | list[str] | Tuple[str, ...] = ..., style: str = ..., takefocus: tkinter._TakeFocusValue = ..., xscrollcommand: tkinter._XYScrollCommand = ..., yscrollcommand: tkinter._XYScrollCommand = ..., - ) -> dict[str, Tuple[str, str, str, Any, Any]] | None: ... + ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload - def configure(self, cnf: str) -> Tuple[str, str, str, Any, Any]: ... + def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure - def bbox(self, item, column: _TreeviewColumnId | None = ...) -> Tuple[int, int, int, int] | Literal[""]: ... # type: ignore + def bbox(self, item, column: _TreeviewColumnId | None = ...) -> tuple[int, int, int, int] | Literal[""]: ... # type: ignore def get_children(self, item: str | None = ...) -> Tuple[str, ...]: ... def set_children(self, item: str, *newchildren: str) -> None: ... @overload @@ -994,7 +994,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): @overload def heading(self, column: _TreeviewColumnId, option: Literal["text"]) -> str: ... @overload - def heading(self, column: _TreeviewColumnId, option: Literal["image"]) -> Tuple[str]: ... + def heading(self, column: _TreeviewColumnId, option: Literal["image"]) -> tuple[str]: ... @overload def heading(self, column: _TreeviewColumnId, option: Literal["anchor"]) -> _tkinter.Tcl_Obj: ... @overload @@ -1027,20 +1027,20 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): id: str = ..., # same as iid text: str = ..., image: tkinter._ImageSpec = ..., - values: tkinter._TkinterSequence[Any] = ..., + values: list[Any] | Tuple[Any, ...] = ..., open: bool = ..., - tags: str | tkinter._TkinterSequence[str] = ..., + tags: str | list[str] | Tuple[str, ...] = ..., ) -> str: ... @overload def item(self, item: str, option: Literal["text"]) -> str: ... @overload - def item(self, item: str, option: Literal["image"]) -> Literal[""] | Tuple[str]: ... + def item(self, item: str, option: Literal["image"]) -> tuple[str] | Literal[""]: ... @overload - def item(self, item: str, option: Literal["values"]) -> Literal[""] | Tuple[Any, ...]: ... + def item(self, item: str, option: Literal["values"]) -> Tuple[Any, ...] | Literal[""]: ... @overload def item(self, item: str, option: Literal["open"]) -> bool: ... # actually 0 or 1 @overload - def item(self, item: str, option: Literal["tags"]) -> Literal[""] | Tuple[str, ...]: ... + def item(self, item: str, option: Literal["tags"]) -> Tuple[str, ...] | Literal[""]: ... @overload def item(self, item: str, option: str) -> Any: ... @overload @@ -1051,9 +1051,9 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): *, text: str = ..., image: tkinter._ImageSpec = ..., - values: tkinter._TkinterSequence[Any] = ..., + values: list[Any] | Tuple[Any, ...] | Literal[""] = ..., open: bool = ..., - tags: str | tkinter._TkinterSequence[str] = ..., + tags: str | list[str] | Tuple[str, ...] = ..., ) -> _TreeviewItemDict | None: ... def move(self, item: str, parent: str, index: int) -> None: ... reattach = move @@ -1065,10 +1065,10 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): def selection(self) -> Tuple[str, ...]: ... else: def selection(self, selop: Any | None = ..., items: Any | None = ...) -> Tuple[str, ...]: ... - def selection_set(self, items: str | tkinter._TkinterSequence[str]) -> None: ... - def selection_add(self, items: str | tkinter._TkinterSequence[str]) -> None: ... - def selection_remove(self, items: str | tkinter._TkinterSequence[str]) -> None: ... - def selection_toggle(self, items: str | tkinter._TkinterSequence[str]) -> None: ... + def selection_set(self, items: str | list[str] | Tuple[str, ...]) -> None: ... + def selection_add(self, items: str | list[str] | Tuple[str, ...]) -> None: ... + def selection_remove(self, items: str | list[str] | Tuple[str, ...]) -> None: ... + def selection_toggle(self, items: str | list[str] | Tuple[str, ...]) -> None: ... @overload def set(self, item: str, column: None = ..., value: None = ...) -> dict[str, Any]: ... @overload @@ -1122,7 +1122,7 @@ class LabeledScale(Frame): compound: Literal["top"] | Literal["bottom"] = ..., **kw: Any, ) -> None: ... - # destroy is overrided, signature does not change + # destroy is overridden, signature does not change value: Any class OptionMenu(Menubutton): @@ -1138,5 +1138,5 @@ class OptionMenu(Menubutton): command: Callable[[tkinter.StringVar], Any] | None = ..., ) -> None: ... # configure, config, cget, destroy are inherited from Menubutton - # destroy and __setitem__ are overrided, signature does not change + # destroy and __setitem__ are overridden, signature does not change def set_menu(self, default: Any | None = ..., *values): ... diff --git a/mypy/typeshed/stdlib/tokenize.pyi b/mypy/typeshed/stdlib/tokenize.pyi index 136dcfcf0a14..a8294adb653f 100644 --- a/mypy/typeshed/stdlib/tokenize.pyi +++ b/mypy/typeshed/stdlib/tokenize.pyi @@ -2,7 +2,7 @@ import sys from _typeshed import StrOrBytesPath from builtins import open as _builtin_open from token import * # noqa: F403 -from typing import Any, Callable, Generator, Iterable, NamedTuple, Pattern, Sequence, Set, TextIO, Tuple, Union +from typing import Any, Callable, Generator, Iterable, NamedTuple, Pattern, Sequence, TextIO, Tuple, Union if sys.version_info < (3, 7): COMMENT: int @@ -44,7 +44,7 @@ class Untokenizer: # the docstring says "returns bytes" but is incorrect -- # if the ENCODING token is missing, it skips the encode def untokenize(iterable: Iterable[_Token]) -> Any: ... -def detect_encoding(readline: Callable[[], bytes]) -> Tuple[str, Sequence[bytes]]: ... +def detect_encoding(readline: Callable[[], bytes]) -> tuple[str, Sequence[bytes]]: ... def tokenize(readline: Callable[[], bytes]) -> Generator[TokenInfo, None, None]: ... def generate_tokens(readline: Callable[[], str]) -> Generator[TokenInfo, None, None]: ... # undocumented def open(filename: StrOrBytesPath | int) -> TextIO: ... @@ -69,7 +69,7 @@ Floatnumber: str # undocumented Imagnumber: str # undocumented Number: str # undocumented -def _all_string_prefixes() -> Set[str]: ... # undocumented +def _all_string_prefixes() -> set[str]: ... # undocumented StringPrefix: str # undocumented @@ -95,7 +95,7 @@ PseudoExtras: str # undocumented PseudoToken: str # undocumented endpats: dict[str, str] # undocumented -single_quoted: Set[str] # undocumented -triple_quoted: Set[str] # undocumented +single_quoted: set[str] # undocumented +triple_quoted: set[str] # undocumented tabsize: int # undocumented diff --git a/mypy/typeshed/stdlib/trace.pyi b/mypy/typeshed/stdlib/trace.pyi index c6d993bf6143..bab75c9ada8d 100644 --- a/mypy/typeshed/stdlib/trace.pyi +++ b/mypy/typeshed/stdlib/trace.pyi @@ -12,17 +12,17 @@ _fileModuleFunction = Tuple[str, Optional[str], str] class CoverageResults: def __init__( self, - counts: dict[Tuple[str, int], int] | None = ..., + counts: dict[tuple[str, int], int] | None = ..., calledfuncs: dict[_fileModuleFunction, int] | None = ..., infile: StrPath | None = ..., - callers: dict[Tuple[_fileModuleFunction, _fileModuleFunction], int] | None = ..., + callers: dict[tuple[_fileModuleFunction, _fileModuleFunction], int] | None = ..., outfile: StrPath | None = ..., ) -> None: ... # undocumented def update(self, other: CoverageResults) -> None: ... def write_results(self, show_missing: bool = ..., summary: bool = ..., coverdir: StrPath | None = ...) -> None: ... def write_results_file( self, path: StrPath, lines: Sequence[str], lnotab: Any, lines_hit: Mapping[int, int], encoding: str | None = ... - ) -> Tuple[int, int]: ... + ) -> tuple[int, int]: ... def is_ignored_filename(self, filename: str) -> bool: ... # undocumented class Trace: diff --git a/mypy/typeshed/stdlib/traceback.pyi b/mypy/typeshed/stdlib/traceback.pyi index e071a3158816..e685b09a6ae4 100644 --- a/mypy/typeshed/stdlib/traceback.pyi +++ b/mypy/typeshed/stdlib/traceback.pyi @@ -1,7 +1,7 @@ import sys from _typeshed import SupportsWrite from types import FrameType, TracebackType -from typing import IO, Any, Generator, Iterable, Iterator, List, Mapping, Optional, Set, Tuple, Type +from typing import IO, Any, Generator, Iterable, Iterator, List, Mapping, Optional, Tuple, Type _PT = Tuple[str, int, str, Optional[str]] @@ -65,8 +65,8 @@ def format_exc(limit: int | None = ..., chain: bool = ...) -> str: ... def format_tb(tb: TracebackType | None, limit: int | None = ...) -> list[str]: ... def format_stack(f: FrameType | None = ..., limit: int | None = ...) -> list[str]: ... def clear_frames(tb: TracebackType) -> None: ... -def walk_stack(f: FrameType | None) -> Iterator[Tuple[FrameType, int]]: ... -def walk_tb(tb: TracebackType | None) -> Iterator[Tuple[FrameType, int]]: ... +def walk_stack(f: FrameType | None) -> Iterator[tuple[FrameType, int]]: ... +def walk_tb(tb: TracebackType | None) -> Iterator[tuple[FrameType, int]]: ... class TracebackException: __cause__: TracebackException @@ -90,7 +90,7 @@ class TracebackException: lookup_lines: bool = ..., capture_locals: bool = ..., compact: bool = ..., - _seen: Set[int] | None = ..., + _seen: set[int] | None = ..., ) -> None: ... @classmethod def from_exception( @@ -112,7 +112,7 @@ class TracebackException: limit: int | None = ..., lookup_lines: bool = ..., capture_locals: bool = ..., - _seen: Set[int] | None = ..., + _seen: set[int] | None = ..., ) -> None: ... @classmethod def from_exception( @@ -146,7 +146,7 @@ class StackSummary(List[FrameSummary]): @classmethod def extract( cls, - frame_gen: Generator[Tuple[FrameType, int], None, None], + frame_gen: Iterable[tuple[FrameType, int]], *, limit: int | None = ..., lookup_lines: bool = ..., diff --git a/mypy/typeshed/stdlib/tracemalloc.pyi b/mypy/typeshed/stdlib/tracemalloc.pyi index e812b8247332..ca4d5901b870 100644 --- a/mypy/typeshed/stdlib/tracemalloc.pyi +++ b/mypy/typeshed/stdlib/tracemalloc.pyi @@ -1,7 +1,6 @@ import sys -from typing import Optional, Sequence, Tuple, Union, overload - from _tracemalloc import * +from typing import Optional, Sequence, Tuple, Union, overload def get_object_traceback(obj: object) -> Traceback | None: ... def take_snapshot() -> Snapshot: ... diff --git a/mypy/typeshed/stdlib/turtle.pyi b/mypy/typeshed/stdlib/turtle.pyi index a289fd03b068..9371f2a7a547 100644 --- a/mypy/typeshed/stdlib/turtle.pyi +++ b/mypy/typeshed/stdlib/turtle.pyi @@ -81,7 +81,7 @@ class TurtleScreen(TurtleScreenBase): @overload def bgpic(self, picname: str) -> None: ... @overload - def screensize(self, canvwidth: None = ..., canvheight: None = ..., bg: None = ...) -> Tuple[int, int]: ... + def screensize(self, canvwidth: None = ..., canvheight: None = ..., bg: None = ...) -> tuple[int, int]: ... # Looks like if self.cv is not a ScrolledCanvas, this could return a tuple as well @overload def screensize(self, canvwidth: int, canvheight: int, bg: _Color | None = ...) -> None: ... @@ -109,18 +109,18 @@ class TNavigator(object): def xcor(self) -> float: ... def ycor(self) -> float: ... @overload - def goto(self, x: Tuple[float, float], y: None = ...) -> None: ... + def goto(self, x: tuple[float, float], y: None = ...) -> None: ... @overload def goto(self, x: float, y: float) -> None: ... def home(self) -> None: ... def setx(self, x: float) -> None: ... def sety(self, y: float) -> None: ... @overload - def distance(self, x: TNavigator | Tuple[float, float], y: None = ...) -> float: ... + def distance(self, x: TNavigator | tuple[float, float], y: None = ...) -> float: ... @overload def distance(self, x: float, y: float) -> float: ... @overload - def towards(self, x: TNavigator | Tuple[float, float], y: None = ...) -> float: ... + def towards(self, x: TNavigator | tuple[float, float], y: None = ...) -> float: ... @overload def towards(self, x: float, y: float) -> float: ... def heading(self) -> float: ... @@ -166,7 +166,7 @@ class TPen(object): @overload def fillcolor(self, r: float, g: float, b: float) -> None: ... @overload - def color(self) -> Tuple[_AnyColor, _AnyColor]: ... + def color(self) -> tuple[_AnyColor, _AnyColor]: ... @overload def color(self, color: _Color) -> None: ... @overload @@ -191,7 +191,7 @@ class TPen(object): pensize: int = ..., speed: int = ..., resizemode: str = ..., - stretchfactor: Tuple[float, float] = ..., + stretchfactor: tuple[float, float] = ..., outline: int = ..., tilt: float = ..., ) -> None: ... @@ -220,7 +220,7 @@ class RawTurtle(TPen, TNavigator): def shape(self, name: str) -> None: ... # Unsafely overlaps when no arguments are provided @overload - def shapesize(self) -> Tuple[float, float, float]: ... # type: ignore + def shapesize(self) -> tuple[float, float, float]: ... # type: ignore @overload def shapesize( self, stretch_wid: float | None = ..., stretch_len: float | None = ..., outline: float | None = ... @@ -231,7 +231,7 @@ class RawTurtle(TPen, TNavigator): def shearfactor(self, shear: float) -> None: ... # Unsafely overlaps when no arguments are provided @overload - def shapetransform(self) -> Tuple[float, float, float, float]: ... # type: ignore + def shapetransform(self) -> tuple[float, float, float, float]: ... # type: ignore @overload def shapetransform( self, t11: float | None = ..., t12: float | None = ..., t21: float | None = ..., t22: float | None = ... @@ -253,7 +253,7 @@ class RawTurtle(TPen, TNavigator): def begin_fill(self) -> None: ... def end_fill(self) -> None: ... def dot(self, size: int | None = ..., *color: _Color) -> None: ... - def write(self, arg: object, move: bool = ..., align: str = ..., font: Tuple[str, int, str] = ...) -> None: ... + def write(self, arg: object, move: bool = ..., align: str = ..., font: tuple[str, int, str] = ...) -> None: ... def begin_poly(self) -> None: ... def end_poly(self) -> None: ... def get_poly(self) -> _PolygonCoords | None: ... @@ -346,7 +346,7 @@ def bgpic(picname: None = ...) -> str: ... @overload def bgpic(picname: str) -> None: ... @overload -def screensize(canvwidth: None = ..., canvheight: None = ..., bg: None = ...) -> Tuple[int, int]: ... +def screensize(canvwidth: None = ..., canvheight: None = ..., bg: None = ...) -> tuple[int, int]: ... @overload def screensize(canvwidth: int, canvheight: int, bg: _Color | None = ...) -> None: ... @@ -379,18 +379,18 @@ def pos() -> Vec2D: ... def xcor() -> float: ... def ycor() -> float: ... @overload -def goto(x: Tuple[float, float], y: None = ...) -> None: ... +def goto(x: tuple[float, float], y: None = ...) -> None: ... @overload def goto(x: float, y: float) -> None: ... def home() -> None: ... def setx(x: float) -> None: ... def sety(y: float) -> None: ... @overload -def distance(x: TNavigator | Tuple[float, float], y: None = ...) -> float: ... +def distance(x: TNavigator | tuple[float, float], y: None = ...) -> float: ... @overload def distance(x: float, y: float) -> float: ... @overload -def towards(x: TNavigator | Tuple[float, float], y: None = ...) -> float: ... +def towards(x: TNavigator | tuple[float, float], y: None = ...) -> float: ... @overload def towards(x: float, y: float) -> float: ... def heading() -> float: ... @@ -436,7 +436,7 @@ def fillcolor(color: _Color) -> None: ... @overload def fillcolor(r: float, g: float, b: float) -> None: ... @overload -def color() -> Tuple[_AnyColor, _AnyColor]: ... +def color() -> tuple[_AnyColor, _AnyColor]: ... @overload def color(color: _Color) -> None: ... @overload @@ -461,7 +461,7 @@ def pen( pensize: int = ..., speed: int = ..., resizemode: str = ..., - stretchfactor: Tuple[float, float] = ..., + stretchfactor: tuple[float, float] = ..., outline: int = ..., tilt: float = ..., ) -> None: ... @@ -485,7 +485,7 @@ def shape(name: str) -> None: ... # Unsafely overlaps when no arguments are provided @overload -def shapesize() -> Tuple[float, float, float]: ... # type: ignore +def shapesize() -> tuple[float, float, float]: ... # type: ignore @overload def shapesize(stretch_wid: float | None = ..., stretch_len: float | None = ..., outline: float | None = ...) -> None: ... @overload @@ -495,7 +495,7 @@ def shearfactor(shear: float) -> None: ... # Unsafely overlaps when no arguments are provided @overload -def shapetransform() -> Tuple[float, float, float, float]: ... # type: ignore +def shapetransform() -> tuple[float, float, float, float]: ... # type: ignore @overload def shapetransform( t11: float | None = ..., t12: float | None = ..., t21: float | None = ..., t22: float | None = ... @@ -518,7 +518,7 @@ def filling() -> bool: ... def begin_fill() -> None: ... def end_fill() -> None: ... def dot(size: int | None = ..., *color: _Color) -> None: ... -def write(arg: object, move: bool = ..., align: str = ..., font: Tuple[str, int, str] = ...) -> None: ... +def write(arg: object, move: bool = ..., align: str = ..., font: tuple[str, int, str] = ...) -> None: ... def begin_poly() -> None: ... def end_poly() -> None: ... def get_poly() -> _PolygonCoords | None: ... diff --git a/mypy/typeshed/stdlib/types.pyi b/mypy/typeshed/stdlib/types.pyi index 7cd99a429461..899024f2dd4d 100644 --- a/mypy/typeshed/stdlib/types.pyi +++ b/mypy/typeshed/stdlib/types.pyi @@ -6,6 +6,7 @@ from typing import ( AsyncGenerator, Awaitable, Callable, + Coroutine, Generator, Generic, ItemsView, @@ -13,13 +14,14 @@ from typing import ( Iterator, KeysView, Mapping, + MutableSequence, Tuple, Type, TypeVar, ValuesView, overload, ) -from typing_extensions import Literal, final +from typing_extensions import Literal, ParamSpec, final # Note, all classes "defined" here require special handling. @@ -142,6 +144,8 @@ class CodeType: co_name: str = ..., co_lnotab: bytes = ..., ) -> CodeType: ... + if sys.version_info >= (3, 11): + def co_positions(self) -> Iterable[tuple[int | None, int | None, int | None, int | None]]: ... @final class MappingProxyType(Mapping[_KT, _VT_co], Generic[_KT, _VT_co]): @@ -169,12 +173,17 @@ class SimpleNamespace: class ModuleType: __name__: str - __file__: str + __file__: str | None __dict__: dict[str, Any] __loader__: _LoaderProtocol | None __package__: str | None + __path__: MutableSequence[str] __spec__: ModuleSpec | 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 + # using `builtins.__import__` or `importlib.import_module` less painful + def __getattr__(self, name: str) -> Any: ... @final class GeneratorType(Generator[_T_co, _T_contra, _V_co]): @@ -211,17 +220,22 @@ class AsyncGeneratorType(AsyncGenerator[_T_co, _T_contra]): def aclose(self) -> Awaitable[None]: ... @final -class CoroutineType: +class CoroutineType(Coroutine[_T_co, _T_contra, _V_co]): + __name__: str + __qualname__: str cr_await: Any | None cr_code: CodeType cr_frame: FrameType cr_running: bool def close(self) -> None: ... - def send(self, __arg: Any) -> Any: ... + def __await__(self) -> Generator[Any, None, _V_co]: ... + def send(self, __arg: _T_contra) -> _T_co: ... @overload - def throw(self, __typ: Type[BaseException], __val: BaseException | object = ..., __tb: TracebackType | None = ...) -> Any: ... + def throw( + self, __typ: Type[BaseException], __val: BaseException | object = ..., __tb: TracebackType | None = ... + ) -> _T_co: ... @overload - def throw(self, __typ: BaseException, __val: None = ..., __tb: TracebackType | None = ...) -> Any: ... + def throw(self, __typ: BaseException, __val: None = ..., __tb: TracebackType | None = ...) -> _T_co: ... class _StaticFunctionType: """Fictional type to correct the type of MethodType.__func__. @@ -357,12 +371,20 @@ else: def prepare_class( name: str, bases: Tuple[type, ...] = ..., kwds: dict[str, Any] | None = ... -) -> Tuple[type, dict[str, Any], dict[str, Any]]: ... +) -> tuple[type, dict[str, Any], dict[str, Any]]: ... # Actually a different type, but `property` is special and we want that too. DynamicClassAttribute = property -def coroutine(func: Callable[..., Any]) -> CoroutineType: ... +_Fn = TypeVar("_Fn", bound=Callable[..., object]) +_R = TypeVar("_R") +_P = ParamSpec("_P") + +# it's not really an Awaitable, but can be used in an await expression. Real type: Generator & Awaitable +@overload +def coroutine(func: Callable[_P, Generator[_R, Any, Any]]) -> Callable[_P, Awaitable[_R]]: ... # type: ignore +@overload +def coroutine(func: _Fn) -> _Fn: ... # type: ignore if sys.version_info >= (3, 8): CellType = _Cell diff --git a/mypy/typeshed/stdlib/typing.pyi b/mypy/typeshed/stdlib/typing.pyi index b87788667c37..4656add7ec21 100644 --- a/mypy/typeshed/stdlib/typing.pyi +++ b/mypy/typeshed/stdlib/typing.pyi @@ -2,7 +2,7 @@ import collections # Needed by aliases like DefaultDict, see mypy issue 2986 import sys from abc import ABCMeta, abstractmethod from types import BuiltinFunctionType, CodeType, FrameType, FunctionType, MethodType, ModuleType, TracebackType -from typing_extensions import Literal as _Literal, ParamSpec as _ParamSpec +from typing_extensions import Literal as _Literal, ParamSpec as _ParamSpec, final as _final if sys.version_info >= (3, 7): from types import MethodDescriptorType, MethodWrapperType, WrapperDescriptorType @@ -50,6 +50,7 @@ Protocol: _SpecialForm = ... Callable: _SpecialForm = ... Type: _SpecialForm = ... ClassVar: _SpecialForm = ... +NoReturn: _SpecialForm = ... if sys.version_info >= (3, 8): Final: _SpecialForm = ... def final(f: _T) -> _T: ... @@ -83,11 +84,6 @@ if sys.version_info >= (3, 10): TypeAlias: _SpecialForm = ... TypeGuard: _SpecialForm = ... -# Return type that indicates a function does not return. -# This type is equivalent to the None type, but the no-op Union is necessary to -# distinguish the None type from the None value. -NoReturn = Union[None] - # These type variables are used by the container types. _S = TypeVar("_S") _KT = TypeVar("_KT") # Key type. @@ -167,7 +163,7 @@ class SupportsRound(Protocol[_T_co]): def __round__(self) -> int: ... @overload @abstractmethod - def __round__(self, ndigits: int) -> _T_co: ... + def __round__(self, __ndigits: int) -> _T_co: ... @runtime_checkable class Sized(Protocol, metaclass=ABCMeta): @@ -304,9 +300,7 @@ class Collection(Iterable[_T_co], Container[_T_co], Protocol[_T_co]): @abstractmethod def __len__(self) -> int: ... -_Collection = Collection[_T_co] - -class Sequence(_Collection[_T_co], Reversible[_T_co], Generic[_T_co]): +class Sequence(Collection[_T_co], Reversible[_T_co], Generic[_T_co]): @overload @abstractmethod def __getitem__(self, i: int) -> _T_co: ... @@ -350,7 +344,7 @@ class MutableSequence(Sequence[_T], Generic[_T]): def remove(self, value: _T) -> None: ... def __iadd__(self, x: Iterable[_T]) -> MutableSequence[_T]: ... -class AbstractSet(_Collection[_T_co], Generic[_T_co]): +class AbstractSet(Collection[_T_co], Generic[_T_co]): @abstractmethod def __contains__(self, x: object) -> bool: ... # Mixin methods @@ -384,33 +378,33 @@ class MappingView(Sized): class ItemsView(MappingView, AbstractSet[Tuple[_KT_co, _VT_co]], Generic[_KT_co, _VT_co]): def __init__(self, mapping: Mapping[_KT_co, _VT_co]) -> None: ... # undocumented - def __and__(self, o: Iterable[Any]) -> Set[Tuple[_KT_co, _VT_co]]: ... - def __rand__(self, o: Iterable[_T]) -> Set[_T]: ... + def __and__(self, o: Iterable[Any]) -> set[tuple[_KT_co, _VT_co]]: ... + def __rand__(self, o: Iterable[_T]) -> set[_T]: ... def __contains__(self, o: object) -> bool: ... - def __iter__(self) -> Iterator[Tuple[_KT_co, _VT_co]]: ... + def __iter__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ... if sys.version_info >= (3, 8): - def __reversed__(self) -> Iterator[Tuple[_KT_co, _VT_co]]: ... - def __or__(self, o: Iterable[_T]) -> Set[Tuple[_KT_co, _VT_co] | _T]: ... - def __ror__(self, o: Iterable[_T]) -> Set[Tuple[_KT_co, _VT_co] | _T]: ... - def __sub__(self, o: Iterable[Any]) -> Set[Tuple[_KT_co, _VT_co]]: ... - def __rsub__(self, o: Iterable[_T]) -> Set[_T]: ... - def __xor__(self, o: Iterable[_T]) -> Set[Tuple[_KT_co, _VT_co] | _T]: ... - def __rxor__(self, o: Iterable[_T]) -> Set[Tuple[_KT_co, _VT_co] | _T]: ... + def __reversed__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ... + def __or__(self, o: Iterable[_T]) -> set[tuple[_KT_co, _VT_co] | _T]: ... + def __ror__(self, o: Iterable[_T]) -> set[tuple[_KT_co, _VT_co] | _T]: ... + def __sub__(self, o: Iterable[Any]) -> set[tuple[_KT_co, _VT_co]]: ... + def __rsub__(self, o: Iterable[_T]) -> set[_T]: ... + def __xor__(self, o: Iterable[_T]) -> set[tuple[_KT_co, _VT_co] | _T]: ... + def __rxor__(self, o: Iterable[_T]) -> set[tuple[_KT_co, _VT_co] | _T]: ... class KeysView(MappingView, AbstractSet[_KT_co], Generic[_KT_co]): def __init__(self, mapping: Mapping[_KT_co, Any]) -> None: ... # undocumented - def __and__(self, o: Iterable[Any]) -> Set[_KT_co]: ... - def __rand__(self, o: Iterable[_T]) -> Set[_T]: ... + def __and__(self, o: Iterable[Any]) -> set[_KT_co]: ... + def __rand__(self, o: Iterable[_T]) -> set[_T]: ... def __contains__(self, o: object) -> bool: ... def __iter__(self) -> Iterator[_KT_co]: ... if sys.version_info >= (3, 8): def __reversed__(self) -> Iterator[_KT_co]: ... - def __or__(self, o: Iterable[_T]) -> Set[_KT_co | _T]: ... - def __ror__(self, o: Iterable[_T]) -> Set[_KT_co | _T]: ... - def __sub__(self, o: Iterable[Any]) -> Set[_KT_co]: ... - def __rsub__(self, o: Iterable[_T]) -> Set[_T]: ... - def __xor__(self, o: Iterable[_T]) -> Set[_KT_co | _T]: ... - def __rxor__(self, o: Iterable[_T]) -> Set[_KT_co | _T]: ... + def __or__(self, o: Iterable[_T]) -> set[_KT_co | _T]: ... + def __ror__(self, o: Iterable[_T]) -> set[_KT_co | _T]: ... + def __sub__(self, o: Iterable[Any]) -> set[_KT_co]: ... + def __rsub__(self, o: Iterable[_T]) -> set[_T]: ... + def __xor__(self, o: Iterable[_T]) -> set[_KT_co | _T]: ... + def __rxor__(self, o: Iterable[_T]) -> set[_KT_co | _T]: ... class ValuesView(MappingView, Iterable[_VT_co], Generic[_VT_co]): def __init__(self, mapping: Mapping[Any, _VT_co]) -> None: ... # undocumented @@ -430,36 +424,36 @@ class ContextManager(Protocol[_T_co]): class AsyncContextManager(Protocol[_T_co]): def __aenter__(self) -> Awaitable[_T_co]: ... def __aexit__( - self, exc_type: Type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None + self, __exc_type: Type[BaseException] | None, __exc_value: BaseException | None, __traceback: TracebackType | None ) -> Awaitable[bool | None]: ... -class Mapping(_Collection[_KT], Generic[_KT, _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, # see discussion in https://github.com/python/typing/pull/273. @abstractmethod - def __getitem__(self, k: _KT) -> _VT_co: ... + def __getitem__(self, __k: _KT) -> _VT_co: ... # Mixin methods @overload def get(self, key: _KT) -> _VT_co | None: ... @overload - def get(self, key: _KT, default: _VT_co | _T) -> _VT_co | _T: ... + def get(self, __key: _KT, __default: _VT_co | _T) -> _VT_co | _T: ... def items(self) -> ItemsView[_KT, _VT_co]: ... def keys(self) -> KeysView[_KT]: ... def values(self) -> ValuesView[_VT_co]: ... - def __contains__(self, o: object) -> bool: ... + def __contains__(self, __o: object) -> bool: ... class MutableMapping(Mapping[_KT, _VT], Generic[_KT, _VT]): @abstractmethod - def __setitem__(self, k: _KT, v: _VT) -> None: ... + def __setitem__(self, __k: _KT, __v: _VT) -> None: ... @abstractmethod - def __delitem__(self, v: _KT) -> None: ... + def __delitem__(self, __v: _KT) -> None: ... def clear(self) -> None: ... @overload - def pop(self, key: _KT) -> _VT: ... + def pop(self, __key: _KT) -> _VT: ... @overload - def pop(self, key: _KT, default: _VT | _T = ...) -> _VT | _T: ... - def popitem(self) -> Tuple[_KT, _VT]: ... - def setdefault(self, key: _KT, default: _VT = ...) -> _VT: ... + def pop(self, __key: _KT, __default: _VT | _T = ...) -> _VT | _T: ... + def popitem(self) -> tuple[_KT, _VT]: ... + def setdefault(self, __key: _KT, __default: _VT = ...) -> _VT: ... # 'update' used to take a Union, but using overloading is better. # The second overloaded type here is a bit too general, because # Mapping[Tuple[_KT, _VT], W] is a subclass of Iterable[Tuple[_KT, _VT]], @@ -473,7 +467,7 @@ class MutableMapping(Mapping[_KT, _VT], Generic[_KT, _VT]): @overload def update(self, __m: Mapping[_KT, _VT], **kwargs: _VT) -> None: ... @overload - def update(self, __m: Iterable[Tuple[_KT, _VT]], **kwargs: _VT) -> None: ... + def update(self, __m: Iterable[tuple[_KT, _VT]], **kwargs: _VT) -> None: ... @overload def update(self, **kwargs: _VT) -> None: ... @@ -551,6 +545,7 @@ class TextIO(IO[str]): class ByteString(Sequence[int], metaclass=ABCMeta): ... +@_final class Match(Generic[AnyStr]): pos: int endpos: int @@ -583,9 +578,9 @@ class Match(Generic[AnyStr]): def groupdict(self, default: _T) -> dict[str, AnyStr | _T]: ... def start(self, __group: int | str = ...) -> int: ... def end(self, __group: int | str = ...) -> int: ... - def span(self, __group: int | str = ...) -> Tuple[int, int]: ... + def span(self, __group: int | str = ...) -> tuple[int, int]: ... @property - def regs(self) -> Tuple[Tuple[int, int], ...]: ... # undocumented + def regs(self) -> Tuple[tuple[int, int], ...]: ... # undocumented # __getitem__() returns "AnyStr" or "AnyStr | None", depending on the pattern. @overload def __getitem__(self, __key: _Literal[0]) -> AnyStr: ... @@ -594,6 +589,7 @@ class Match(Generic[AnyStr]): if sys.version_info >= (3, 9): def __class_getitem__(cls, item: Any) -> GenericAlias: ... +@_final class Pattern(Generic[AnyStr]): flags: int groupindex: Mapping[str, int] @@ -610,9 +606,9 @@ class Pattern(Generic[AnyStr]): @overload def sub(self, repl: Callable[[Match[AnyStr]], AnyStr], string: AnyStr, count: int = ...) -> AnyStr: ... @overload - def subn(self, repl: AnyStr, string: AnyStr, count: int = ...) -> Tuple[AnyStr, int]: ... + def subn(self, repl: AnyStr, string: AnyStr, count: int = ...) -> tuple[AnyStr, int]: ... @overload - def subn(self, repl: Callable[[Match[AnyStr]], AnyStr], string: AnyStr, count: int = ...) -> Tuple[AnyStr, int]: ... + def subn(self, repl: Callable[[Match[AnyStr]], AnyStr], string: AnyStr, count: int = ...) -> tuple[AnyStr, int]: ... if sys.version_info >= (3, 9): def __class_getitem__(cls, item: Any) -> GenericAlias: ... @@ -667,7 +663,10 @@ class NamedTuple(Tuple[Any, ...]): _field_defaults: dict[str, Any] _fields: Tuple[str, ...] _source: str - def __init__(self, typename: str, fields: Iterable[Tuple[str, Any]] = ..., **kwargs: Any) -> None: ... + @overload + def __init__(self, typename: str, fields: Iterable[tuple[str, Any]] = ...) -> None: ... + @overload + def __init__(self, typename: str, fields: None = ..., **kwargs: Any) -> None: ... @classmethod def _make(cls: Type[_T], iterable: Iterable[Any]) -> _T: ... if sys.version_info >= (3, 8): diff --git a/mypy/typeshed/stdlib/typing_extensions.pyi b/mypy/typeshed/stdlib/typing_extensions.pyi index 59fe3df390d2..ce407f996022 100644 --- a/mypy/typeshed/stdlib/typing_extensions.pyi +++ b/mypy/typeshed/stdlib/typing_extensions.pyi @@ -43,6 +43,9 @@ def runtime_checkable(cls: _TC) -> _TC: ... runtime = runtime_checkable Protocol: _SpecialForm = ... Final: _SpecialForm = ... +Self: _SpecialForm = ... +Required: _SpecialForm = ... +NotRequired: _SpecialForm = ... def final(f: _F) -> _F: ... @@ -52,6 +55,9 @@ def IntVar(name: str) -> Any: ... # returns a new TypeVar # Internal mypy fallback type for all typed dicts (does not exist at runtime) class _TypedDict(Mapping[str, object], metaclass=abc.ABCMeta): + __required_keys__: frozenset[str] + __optional_keys__: frozenset[str] + __total__: bool def copy(self: _T) -> _T: ... # Using NoReturn so that only calls using mypy plugin hook that specialize the signature # can go through. @@ -69,14 +75,13 @@ TypedDict: object = ... OrderedDict = _Alias() -def get_type_hints( - obj: Callable[..., Any], - globalns: dict[str, Any] | None = ..., - localns: dict[str, Any] | None = ..., - include_extras: bool = ..., -) -> dict[str, Any]: ... - if sys.version_info >= (3, 7): + def get_type_hints( + obj: Callable[..., Any], + globalns: dict[str, Any] | None = ..., + localns: dict[str, Any] | None = ..., + include_extras: bool = ..., + ) -> dict[str, Any]: ... def get_args(tp: Any) -> Tuple[Any, ...]: ... def get_origin(tp: Any) -> Any | None: ... diff --git a/mypy/typeshed/stdlib/unittest/case.pyi b/mypy/typeshed/stdlib/unittest/case.pyi index ebb1f2457e68..2ae07144373c 100644 --- a/mypy/typeshed/stdlib/unittest/case.pyi +++ b/mypy/typeshed/stdlib/unittest/case.pyi @@ -3,14 +3,14 @@ import logging import sys import unittest.result from _typeshed import Self -from collections.abc import Set +from collections.abc import Set # equivalent to typing.AbstractSet, not builtins.set +from contextlib import AbstractContextManager from types import TracebackType from typing import ( Any, AnyStr, Callable, Container, - ContextManager, Generic, Iterable, Mapping, @@ -61,7 +61,7 @@ class TestCase: def run(self, result: unittest.result.TestResult | None = ...) -> unittest.result.TestResult | None: ... def __call__(self, result: unittest.result.TestResult | None = ...) -> unittest.result.TestResult | None: ... def skipTest(self, reason: Any) -> None: ... - def subTest(self, msg: Any = ..., **params: Any) -> ContextManager[None]: ... + def subTest(self, msg: Any = ..., **params: Any) -> AbstractContextManager[None]: ... def debug(self) -> None: ... def _addSkip(self, result: unittest.result.TestResult, test_case: TestCase, reason: str) -> None: ... def assertEqual(self, first: Any, second: Any, msg: Any = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/unittest/mock.pyi b/mypy/typeshed/stdlib/unittest/mock.pyi index 7ccaf3acaeb5..567ce346f464 100644 --- a/mypy/typeshed/stdlib/unittest/mock.pyi +++ b/mypy/typeshed/stdlib/unittest/mock.pyi @@ -1,7 +1,6 @@ import sys from typing import Any, Callable, Generic, Iterable, List, Mapping, Sequence, Tuple, Type, TypeVar, overload -_F = TypeVar("_F", bound=Callable[..., Any]) _T = TypeVar("_T") _TT = TypeVar("_TT", bound=Type[Any]) _R = TypeVar("_R") @@ -176,10 +175,13 @@ class _patch(Generic[_T]): kwargs: Mapping[str, Any], ) -> None: ... def copy(self) -> _patch[_T]: ... + @overload + def __call__(self, func: _TT) -> _TT: ... + @overload def __call__(self, func: Callable[..., _R]) -> Callable[..., _R]: ... def decorate_class(self, klass: _TT) -> _TT: ... - def decorate_callable(self, func: _F) -> _F: ... - def get_original(self) -> Tuple[Any, bool]: ... + def decorate_callable(self, func: Callable[..., _R]) -> Callable[..., _R]: ... + def get_original(self) -> tuple[Any, bool]: ... target: Any temp_original: Any is_local: bool @@ -318,8 +320,8 @@ class _patcher: spec_set: Any | None = ..., autospec: Any | None = ..., new_callable: Any | None = ..., - **kwargs: _T, - ) -> _patch[_T]: ... + **kwargs: Any, + ) -> _patch[Any]: ... def stopall(self) -> None: ... patch: _patcher diff --git a/mypy/typeshed/stdlib/unittest/result.pyi b/mypy/typeshed/stdlib/unittest/result.pyi index 676c0cd4aeda..20c43cf38aa4 100644 --- a/mypy/typeshed/stdlib/unittest/result.pyi +++ b/mypy/typeshed/stdlib/unittest/result.pyi @@ -10,10 +10,10 @@ _F = TypeVar("_F", bound=Callable[..., Any]) def failfast(method: _F) -> _F: ... class TestResult: - errors: list[Tuple[unittest.case.TestCase, str]] - failures: list[Tuple[unittest.case.TestCase, str]] - skipped: list[Tuple[unittest.case.TestCase, str]] - expectedFailures: list[Tuple[unittest.case.TestCase, str]] + errors: list[tuple[unittest.case.TestCase, str]] + failures: list[tuple[unittest.case.TestCase, str]] + skipped: list[tuple[unittest.case.TestCase, str]] + expectedFailures: list[tuple[unittest.case.TestCase, str]] unexpectedSuccesses: list[unittest.case.TestCase] shouldStop: bool testsRun: int diff --git a/mypy/typeshed/stdlib/unittest/runner.pyi b/mypy/typeshed/stdlib/unittest/runner.pyi index 128909b2090b..bf8f3c05c1cd 100644 --- a/mypy/typeshed/stdlib/unittest/runner.pyi +++ b/mypy/typeshed/stdlib/unittest/runner.pyi @@ -1,7 +1,7 @@ import unittest.case import unittest.result import unittest.suite -from typing import Callable, TextIO, Tuple, Type +from typing import Callable, TextIO, Type _ResultClassType = Callable[[TextIO, bool, int], unittest.result.TestResult] @@ -15,7 +15,7 @@ class TextTestResult(unittest.result.TestResult): def __init__(self, stream: TextIO, descriptions: bool, verbosity: int) -> None: ... def getDescription(self, test: unittest.case.TestCase) -> str: ... def printErrors(self) -> None: ... - def printErrorList(self, flavour: str, errors: Tuple[unittest.case.TestCase, str]) -> None: ... + def printErrorList(self, flavour: str, errors: tuple[unittest.case.TestCase, str]) -> None: ... class TextTestRunner(object): resultclass: _ResultClassType diff --git a/mypy/typeshed/stdlib/unittest/util.pyi b/mypy/typeshed/stdlib/unittest/util.pyi index ffce5d52677c..ab6ed053a6ff 100644 --- a/mypy/typeshed/stdlib/unittest/util.pyi +++ b/mypy/typeshed/stdlib/unittest/util.pyi @@ -11,11 +11,11 @@ _MIN_COMMON_LEN: int _MIN_DIFF_LEN: int def _shorten(s: str, prefixlen: int, suffixlen: int) -> str: ... -def _common_shorten_repr(*args: str) -> Tuple[str]: ... +def _common_shorten_repr(*args: str) -> tuple[str]: ... def safe_repr(obj: object, short: bool = ...) -> str: ... def strclass(cls: type) -> str: ... -def sorted_list_difference(expected: Sequence[_T], actual: Sequence[_T]) -> Tuple[list[_T], list[_T]]: ... -def unorderable_list_difference(expected: Sequence[_T], actual: Sequence[_T]) -> Tuple[list[_T], list[_T]]: ... +def sorted_list_difference(expected: Sequence[_T], actual: Sequence[_T]) -> tuple[list[_T], list[_T]]: ... +def unorderable_list_difference(expected: Sequence[_T], actual: Sequence[_T]) -> tuple[list[_T], list[_T]]: ... def three_way_cmp(x: Any, y: Any) -> int: ... def _count_diff_all_purpose(actual: Sequence[_T], expected: Sequence[_T]) -> list[_Mismatch[_T]]: ... def _count_diff_hashable(actual: Sequence[_T], expected: Sequence[_T]) -> list[_Mismatch[_T]]: ... diff --git a/mypy/typeshed/stdlib/urllib/error.pyi b/mypy/typeshed/stdlib/urllib/error.pyi index 557f84a40159..1d91fedceeca 100644 --- a/mypy/typeshed/stdlib/urllib/error.pyi +++ b/mypy/typeshed/stdlib/urllib/error.pyi @@ -1,5 +1,5 @@ from email.message import Message -from typing import IO, Tuple +from typing import IO from urllib.response import addinfourl # Stubs for urllib.error @@ -13,5 +13,5 @@ class HTTPError(URLError, addinfourl): def __init__(self, url: str, code: int, msg: str, hdrs: Message, fp: IO[bytes] | None) -> None: ... class ContentTooShortError(URLError): - content: Tuple[str, Message] - def __init__(self, message: str, content: Tuple[str, Message]) -> None: ... + content: tuple[str, Message] + def __init__(self, message: str, content: tuple[str, Message]) -> None: ... diff --git a/mypy/typeshed/stdlib/urllib/parse.pyi b/mypy/typeshed/stdlib/urllib/parse.pyi index 49a3dd1cedf4..a2467e96c43c 100644 --- a/mypy/typeshed/stdlib/urllib/parse.pyi +++ b/mypy/typeshed/stdlib/urllib/parse.pyi @@ -96,7 +96,7 @@ def parse_qsl( errors: str = ..., max_num_fields: int | None = ..., separator: str = ..., -) -> list[Tuple[AnyStr, AnyStr]]: ... +) -> list[tuple[AnyStr, AnyStr]]: ... @overload def quote(string: str, safe: _Str = ..., encoding: str | None = ..., errors: str | None = ...) -> str: ... @overload @@ -114,7 +114,7 @@ def urldefrag(url: str) -> DefragResult: ... @overload def urldefrag(url: bytes | None) -> DefragResultBytes: ... def urlencode( - query: Mapping[Any, Any] | Mapping[Any, Sequence[Any]] | Sequence[Tuple[Any, Any]] | Sequence[Tuple[Any, Sequence[Any]]], + query: Mapping[Any, Any] | Mapping[Any, Sequence[Any]] | Sequence[tuple[Any, Any]] | Sequence[tuple[Any, Sequence[Any]]], doseq: bool = ..., safe: AnyStr = ..., encoding: str = ..., @@ -132,11 +132,11 @@ def urlsplit(url: str, scheme: str | None = ..., allow_fragments: bool = ...) -> def urlsplit(url: bytes | None, scheme: bytes | None = ..., allow_fragments: bool = ...) -> SplitResultBytes: ... @overload def urlunparse( - components: Tuple[AnyStr | None, AnyStr | None, AnyStr | None, AnyStr | None, AnyStr | None, AnyStr | None] + components: tuple[AnyStr | None, AnyStr | None, AnyStr | None, AnyStr | None, AnyStr | None, AnyStr | None] ) -> AnyStr: ... @overload def urlunparse(components: Sequence[AnyStr | None]) -> AnyStr: ... @overload -def urlunsplit(components: Tuple[AnyStr | None, AnyStr | None, AnyStr | None, AnyStr | None, AnyStr | None]) -> AnyStr: ... +def urlunsplit(components: tuple[AnyStr | None, AnyStr | None, AnyStr | None, AnyStr | None, AnyStr | None]) -> AnyStr: ... @overload def urlunsplit(components: Sequence[AnyStr | None]) -> AnyStr: ... diff --git a/mypy/typeshed/stdlib/urllib/request.pyi b/mypy/typeshed/stdlib/urllib/request.pyi index 9ac320c680db..3c8a6facde6f 100644 --- a/mypy/typeshed/stdlib/urllib/request.pyi +++ b/mypy/typeshed/stdlib/urllib/request.pyi @@ -77,11 +77,11 @@ class Request: def get_header(self, header_name: str) -> str | None: ... @overload def get_header(self, header_name: str, default: _T) -> str | _T: ... - def header_items(self) -> list[Tuple[str, str]]: ... + def header_items(self) -> list[tuple[str, str]]: ... def has_proxy(self) -> bool: ... class OpenerDirector: - addheaders: list[Tuple[str, str]] + addheaders: list[tuple[str, str]] def add_handler(self, handler: BaseHandler) -> None: ... def open(self, fullurl: str | Request, data: bytes | None = ..., timeout: float | None = ...) -> _UrlopenRet: ... def error(self, proto: str, *args: Any) -> _UrlopenRet: ... @@ -125,13 +125,13 @@ class ProxyHandler(BaseHandler): class HTTPPasswordMgr: def add_password(self, realm: str, uri: str | Sequence[str], user: str, passwd: str) -> None: ... - def find_user_password(self, realm: str, authuri: str) -> Tuple[str | None, str | None]: ... + def find_user_password(self, realm: str, authuri: str) -> tuple[str | None, str | None]: ... def is_suburi(self, base: str, test: str) -> bool: ... # undocumented def reduce_uri(self, uri: str, default_port: bool = ...) -> str: ... # undocumented class HTTPPasswordMgrWithDefaultRealm(HTTPPasswordMgr): def add_password(self, realm: str | None, uri: str | Sequence[str], user: str, passwd: str) -> None: ... - def find_user_password(self, realm: str | None, authuri: str) -> Tuple[str | None, str | None]: ... + def find_user_password(self, realm: str | None, authuri: str) -> tuple[str | None, str | None]: ... class HTTPPasswordMgrWithPriorAuth(HTTPPasswordMgrWithDefaultRealm): def add_password( @@ -167,7 +167,7 @@ class AbstractDigestAuthHandler: def retry_http_digest_auth(self, req: Request, auth: str) -> _UrlopenRet | None: ... def get_cnonce(self, nonce: str) -> str: ... def get_authorization(self, req: Request, chal: Mapping[str, str]) -> str: ... - def get_algorithm_impls(self, algorithm: str) -> Tuple[Callable[[str], str], Callable[[str, str], str]]: ... + def get_algorithm_impls(self, algorithm: str) -> tuple[Callable[[str], str], Callable[[str, str], str]]: ... def get_entity_digest(self, data: bytes | None, chal: Mapping[str, str]) -> str | None: ... class HTTPDigestAuthHandler(BaseHandler, AbstractDigestAuthHandler): @@ -213,7 +213,7 @@ class ftpwrapper: # undocumented def file_close(self) -> None: ... def init(self) -> None: ... def real_close(self) -> None: ... - def retrfile(self, file: str, type: str) -> Tuple[addclosehook, int]: ... + def retrfile(self, file: str, type: str) -> tuple[addclosehook, int]: ... class FTPHandler(BaseHandler): def ftp_open(self, req: Request) -> addinfourl: ... @@ -242,7 +242,7 @@ def urlretrieve( filename: StrOrBytesPath | None = ..., reporthook: Callable[[int, int, int], None] | None = ..., data: bytes | None = ..., -) -> Tuple[str, HTTPMessage]: ... +) -> tuple[str, HTTPMessage]: ... def urlcleanup() -> None: ... class URLopener: @@ -256,8 +256,8 @@ class URLopener: filename: str | None = ..., reporthook: Callable[[int, int, int], None] | None = ..., data: bytes | None = ..., - ) -> Tuple[str, Message | None]: ... - def addheader(self, *args: Tuple[str, str]) -> None: ... # undocumented + ) -> tuple[str, Message | None]: ... + def addheader(self, *args: tuple[str, str]) -> None: ... # undocumented def cleanup(self) -> None: ... # undocumented def close(self) -> None: ... # undocumented def http_error( @@ -275,8 +275,8 @@ class URLopener: def open_unknown_proxy(self, proxy: str, fullurl: str, data: bytes | None = ...) -> None: ... # undocumented class FancyURLopener(URLopener): - def prompt_user_passwd(self, host: str, realm: str) -> Tuple[str, str]: ... - def get_user_passwd(self, host: str, realm: str, clear_cache: int = ...) -> Tuple[str, str]: ... # undocumented + def prompt_user_passwd(self, host: str, realm: str) -> tuple[str, str]: ... + def get_user_passwd(self, host: str, realm: str, clear_cache: int = ...) -> tuple[str, str]: ... # undocumented def http_error_301( self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: HTTPMessage, data: bytes | None = ... ) -> _UrlopenRet | addinfourl | None: ... # undocumented diff --git a/mypy/typeshed/stdlib/urllib/response.pyi b/mypy/typeshed/stdlib/urllib/response.pyi index dd8a80833ba3..647ebf874432 100644 --- a/mypy/typeshed/stdlib/urllib/response.pyi +++ b/mypy/typeshed/stdlib/urllib/response.pyi @@ -1,3 +1,4 @@ +import sys from _typeshed import Self from email.message import Message from types import TracebackType @@ -46,7 +47,10 @@ class addinfo(addbase): class addinfourl(addinfo): url: str - code: int + code: int | None + if sys.version_info >= (3, 9): + @property + def status(self) -> int | None: ... def __init__(self, fp: IO[bytes], headers: Message, url: str, code: int | None = ...) -> None: ... def geturl(self) -> str: ... - def getcode(self) -> int: ... + def getcode(self) -> int | None: ... diff --git a/mypy/typeshed/stdlib/warnings.pyi b/mypy/typeshed/stdlib/warnings.pyi index 62c41c871853..b1c9f4dda8ed 100644 --- a/mypy/typeshed/stdlib/warnings.pyi +++ b/mypy/typeshed/stdlib/warnings.pyi @@ -1,8 +1,9 @@ +from _warnings import warn as warn, warn_explicit as warn_explicit from types import ModuleType, TracebackType from typing import Any, Sequence, TextIO, Type, overload from typing_extensions import Literal -from _warnings import warn as warn, warn_explicit as warn_explicit +_ActionKind = Literal["default", "error", "ignore", "always", "module", "once"] filters: Sequence[tuple[str, str | None, Type[Warning], str | None, int]] # undocumented, do not mutate @@ -11,9 +12,14 @@ def showwarning( ) -> None: ... def formatwarning(message: Warning | str, category: Type[Warning], filename: str, lineno: int, line: str | None = ...) -> str: ... def filterwarnings( - action: str, message: str = ..., category: Type[Warning] = ..., module: str = ..., lineno: int = ..., append: bool = ... + action: _ActionKind, + message: str = ..., + category: Type[Warning] = ..., + module: str = ..., + lineno: int = ..., + append: bool = ..., ) -> None: ... -def simplefilter(action: str, category: Type[Warning] = ..., lineno: int = ..., append: bool = ...) -> None: ... +def simplefilter(action: _ActionKind, category: Type[Warning] = ..., lineno: int = ..., append: bool = ...) -> None: ... def resetwarnings() -> None: ... class _OptionError(Exception): ... diff --git a/mypy/typeshed/stdlib/weakref.pyi b/mypy/typeshed/stdlib/weakref.pyi index 12158ee6c8f4..dbb6b49f2f2e 100644 --- a/mypy/typeshed/stdlib/weakref.pyi +++ b/mypy/typeshed/stdlib/weakref.pyi @@ -1,4 +1,3 @@ -import types from _weakrefset import WeakSet as WeakSet from typing import Any, Callable, Generic, Iterable, Iterator, Mapping, MutableMapping, Tuple, Type, TypeVar, overload @@ -16,18 +15,19 @@ _S = TypeVar("_S") _T = TypeVar("_T") _KT = TypeVar("_KT") _VT = TypeVar("_VT") +_CallableT = TypeVar("_CallableT", bound=Callable[..., Any]) ProxyTypes: Tuple[Type[Any], ...] -class WeakMethod(ref[types.MethodType]): - def __new__(cls, meth: types.MethodType, callback: Callable[[types.MethodType], Any] | None = ...) -> WeakMethod: ... - def __call__(self) -> types.MethodType | None: ... +class WeakMethod(ref[_CallableT], Generic[_CallableT]): + def __new__(cls, meth: _CallableT, callback: Callable[[_CallableT], object] | None = ...) -> WeakMethod[_CallableT]: ... + def __call__(self) -> _CallableT | None: ... class WeakValueDictionary(MutableMapping[_KT, _VT]): @overload def __init__(self) -> None: ... @overload - def __init__(self, __other: Mapping[_KT, _VT] | Iterable[Tuple[_KT, _VT]], **kwargs: _VT) -> None: ... + def __init__(self, __other: Mapping[_KT, _VT] | Iterable[tuple[_KT, _VT]], **kwargs: _VT) -> None: ... def __len__(self) -> int: ... def __getitem__(self, k: _KT) -> _VT: ... def __setitem__(self, k: _KT, v: _VT) -> None: ... @@ -39,9 +39,14 @@ class WeakValueDictionary(MutableMapping[_KT, _VT]): # These are incompatible with Mapping def keys(self) -> Iterator[_KT]: ... # type: ignore def values(self) -> Iterator[_VT]: ... # type: ignore - def items(self) -> Iterator[Tuple[_KT, _VT]]: ... # type: ignore + def items(self) -> Iterator[tuple[_KT, _VT]]: ... # type: ignore def itervaluerefs(self) -> Iterator[KeyedRef[_KT, _VT]]: ... def valuerefs(self) -> list[KeyedRef[_KT, _VT]]: ... + def setdefault(self, key: _KT, default: _VT = ...) -> _VT: ... + @overload + def pop(self, key: _KT) -> _VT: ... + @overload + def pop(self, key: _KT, default: _VT | _T = ...) -> _VT | _T: ... class KeyedRef(ref[_T], Generic[_KT, _T]): key: _KT @@ -53,7 +58,7 @@ class WeakKeyDictionary(MutableMapping[_KT, _VT]): @overload def __init__(self, dict: None = ...) -> None: ... @overload - def __init__(self, dict: Mapping[_KT, _VT] | Iterable[Tuple[_KT, _VT]]) -> None: ... + def __init__(self, dict: Mapping[_KT, _VT] | Iterable[tuple[_KT, _VT]]) -> None: ... def __len__(self) -> int: ... def __getitem__(self, k: _KT) -> _VT: ... def __setitem__(self, k: _KT, v: _VT) -> None: ... @@ -65,13 +70,18 @@ class WeakKeyDictionary(MutableMapping[_KT, _VT]): # These are incompatible with Mapping def keys(self) -> Iterator[_KT]: ... # type: ignore def values(self) -> Iterator[_VT]: ... # type: ignore - def items(self) -> Iterator[Tuple[_KT, _VT]]: ... # type: ignore + def items(self) -> Iterator[tuple[_KT, _VT]]: ... # type: ignore def keyrefs(self) -> list[ref[_KT]]: ... + def setdefault(self, key: _KT, default: _VT = ...) -> _VT: ... + @overload + def pop(self, key: _KT) -> _VT: ... + @overload + def pop(self, key: _KT, default: _VT | _T = ...) -> _VT | _T: ... class finalize: def __init__(self, __obj: object, __func: Callable[..., Any], *args: Any, **kwargs: Any) -> None: ... def __call__(self, _: Any = ...) -> Any | None: ... - def detach(self) -> Tuple[Any, Any, Tuple[Any, ...], dict[str, Any]] | None: ... - def peek(self) -> Tuple[Any, Any, Tuple[Any, ...], dict[str, Any]] | None: ... + def detach(self) -> tuple[Any, Any, Tuple[Any, ...], dict[str, Any]] | None: ... + def peek(self) -> tuple[Any, Any, Tuple[Any, ...], dict[str, Any]] | None: ... alive: bool atexit: bool diff --git a/mypy/typeshed/stdlib/winreg.pyi b/mypy/typeshed/stdlib/winreg.pyi index 3c7ab0113e04..5fff1104e246 100644 --- a/mypy/typeshed/stdlib/winreg.pyi +++ b/mypy/typeshed/stdlib/winreg.pyi @@ -1,6 +1,7 @@ from _typeshed import Self from types import TracebackType -from typing import Any, Tuple, Type, Union +from typing import Any, Type, Union +from typing_extensions import final _KeyType = Union[HKEYType, int] @@ -12,15 +13,15 @@ def DeleteKey(__key: _KeyType, __sub_key: str) -> None: ... def DeleteKeyEx(key: _KeyType, sub_key: str, access: int = ..., reserved: int = ...) -> None: ... def DeleteValue(__key: _KeyType, __value: str) -> None: ... def EnumKey(__key: _KeyType, __index: int) -> str: ... -def EnumValue(__key: _KeyType, __index: int) -> Tuple[str, Any, int]: ... +def EnumValue(__key: _KeyType, __index: int) -> tuple[str, Any, int]: ... def ExpandEnvironmentStrings(__str: str) -> str: ... def FlushKey(__key: _KeyType) -> None: ... def LoadKey(__key: _KeyType, __sub_key: str, __file_name: str) -> None: ... def OpenKey(key: _KeyType, sub_key: str, reserved: int = ..., access: int = ...) -> HKEYType: ... def OpenKeyEx(key: _KeyType, sub_key: str, reserved: int = ..., access: int = ...) -> HKEYType: ... -def QueryInfoKey(__key: _KeyType) -> Tuple[int, int, int]: ... +def QueryInfoKey(__key: _KeyType) -> tuple[int, int, int]: ... def QueryValue(__key: _KeyType, __sub_key: str | None) -> str: ... -def QueryValueEx(__key: _KeyType, __name: str) -> Tuple[Any, int]: ... +def QueryValueEx(__key: _KeyType, __name: str) -> tuple[Any, int]: ... def SaveKey(__key: _KeyType, __file_name: str) -> None: ... def SetValue(__key: _KeyType, __sub_key: str, __type: int, __value: str) -> None: ... def SetValueEx( @@ -88,6 +89,7 @@ REG_WHOLE_HIVE_VOLATILE: int # undocumented error = OSError # Though this class has a __name__ of PyHKEY, it's exposed as HKEYType for some reason +@final class HKEYType: def __bool__(self) -> bool: ... def __int__(self) -> int: ... diff --git a/mypy/typeshed/stdlib/wsgiref/handlers.pyi b/mypy/typeshed/stdlib/wsgiref/handlers.pyi index b9899389cd3b..ac1e56b7664e 100644 --- a/mypy/typeshed/stdlib/wsgiref/handlers.pyi +++ b/mypy/typeshed/stdlib/wsgiref/handlers.pyi @@ -12,7 +12,7 @@ def format_date_time(timestamp: float | None) -> str: ... # undocumented def read_environ() -> dict[str, str]: ... class BaseHandler: - wsgi_version: Tuple[int, int] # undocumented + wsgi_version: tuple[int, int] # undocumented wsgi_multithread: bool wsgi_multiprocess: bool wsgi_run_once: bool @@ -28,7 +28,7 @@ class BaseHandler: traceback_limit: int | None error_status: str - error_headers: list[Tuple[str, str]] + error_headers: list[tuple[str, str]] error_body: bytes def run(self, application: WSGIApplication) -> None: ... def setup_environ(self) -> None: ... @@ -37,7 +37,7 @@ class BaseHandler: def set_content_length(self) -> None: ... def cleanup_headers(self) -> None: ... def start_response( - self, status: str, headers: list[Tuple[str, str]], exc_info: _exc_info | None = ... + self, status: str, headers: list[tuple[str, str]], exc_info: _exc_info | None = ... ) -> Callable[[bytes], None]: ... def send_preamble(self) -> None: ... def write(self, data: bytes) -> None: ... diff --git a/mypy/typeshed/stdlib/xml/dom/domreg.pyi b/mypy/typeshed/stdlib/xml/dom/domreg.pyi index 64c18ae80f0c..b9e2dd9eb263 100644 --- a/mypy/typeshed/stdlib/xml/dom/domreg.pyi +++ b/mypy/typeshed/stdlib/xml/dom/domreg.pyi @@ -1,8 +1,8 @@ from _typeshed.xml import DOMImplementation -from typing import Callable, Iterable, Tuple +from typing import Callable, Iterable well_known_implementations: dict[str, str] registered: dict[str, Callable[[], DOMImplementation]] def registerDOMImplementation(name: str, factory: Callable[[], DOMImplementation]) -> None: ... -def getDOMImplementation(name: str | None = ..., features: str | Iterable[Tuple[str, str | None]] = ...) -> DOMImplementation: ... +def getDOMImplementation(name: str | None = ..., features: str | Iterable[tuple[str, str | None]] = ...) -> DOMImplementation: ... diff --git a/mypy/typeshed/stdlib/xml/dom/minicompat.pyi b/mypy/typeshed/stdlib/xml/dom/minicompat.pyi index e9b0395ab50d..4bc60f7ab965 100644 --- a/mypy/typeshed/stdlib/xml/dom/minicompat.pyi +++ b/mypy/typeshed/stdlib/xml/dom/minicompat.pyi @@ -2,7 +2,7 @@ from typing import Any, Iterable, List, Tuple, Type, TypeVar _T = TypeVar("_T") -StringTypes: Tuple[Type[str]] +StringTypes: tuple[Type[str]] class NodeList(List[_T]): length: int diff --git a/mypy/typeshed/stdlib/xml/etree/ElementTree.pyi b/mypy/typeshed/stdlib/xml/etree/ElementTree.pyi index b9ecf52edf58..03a20dcad4cb 100644 --- a/mypy/typeshed/stdlib/xml/etree/ElementTree.pyi +++ b/mypy/typeshed/stdlib/xml/etree/ElementTree.pyi @@ -12,7 +12,6 @@ from typing import ( KeysView, MutableSequence, Sequence, - Tuple, TypeVar, Union, overload, @@ -26,7 +25,7 @@ VERSION: str class ParseError(SyntaxError): code: int - position: Tuple[int, int] + position: tuple[int, int] def iselement(element: object) -> bool: ... @@ -232,16 +231,16 @@ if sys.version_info >= (3, 9): def indent(tree: Element | ElementTree, space: str = ..., level: int = ...) -> None: ... def parse(source: _File, parser: XMLParser | None = ...) -> ElementTree: ... -def iterparse(source: _File, events: Sequence[str] | None = ..., parser: XMLParser | None = ...) -> Iterator[Tuple[str, Any]]: ... +def iterparse(source: _File, events: Sequence[str] | None = ..., parser: XMLParser | None = ...) -> Iterator[tuple[str, Any]]: ... class XMLPullParser: def __init__(self, events: Sequence[str] | None = ..., *, _parser: XMLParser | None = ...) -> None: ... def feed(self, data: bytes) -> None: ... def close(self) -> None: ... - def read_events(self) -> Iterator[Tuple[str, Element]]: ... + def read_events(self) -> Iterator[tuple[str, Element]]: ... def XML(text: str | bytes, parser: XMLParser | None = ...) -> Element: ... -def XMLID(text: str | bytes, parser: XMLParser | None = ...) -> Tuple[Element, dict[str, Element]]: ... +def XMLID(text: str | bytes, parser: XMLParser | None = ...) -> tuple[Element, dict[str, Element]]: ... # This is aliased to XML in the source. fromstring = XML diff --git a/mypy/typeshed/stdlib/xml/sax/xmlreader.pyi b/mypy/typeshed/stdlib/xml/sax/xmlreader.pyi index 8afc566b16a1..684e9cef1f42 100644 --- a/mypy/typeshed/stdlib/xml/sax/xmlreader.pyi +++ b/mypy/typeshed/stdlib/xml/sax/xmlreader.pyi @@ -1,4 +1,4 @@ -from typing import Mapping, Tuple +from typing import Mapping class XMLReader: def __init__(self) -> None: ... @@ -64,7 +64,7 @@ class AttributesImpl: def values(self): ... class AttributesNSImpl(AttributesImpl): - def __init__(self, attrs: Mapping[Tuple[str, str], str], qnames: Mapping[Tuple[str, str], str]) -> None: ... + def __init__(self, attrs: Mapping[tuple[str, str], str], qnames: Mapping[tuple[str, str], str]) -> None: ... def getValueByQName(self, name): ... def getNameByQName(self, name): ... def getQNameByName(self, name): ... diff --git a/mypy/typeshed/stdlib/xmlrpc/client.pyi b/mypy/typeshed/stdlib/xmlrpc/client.pyi index d0144e732bb7..061df849eff2 100644 --- a/mypy/typeshed/stdlib/xmlrpc/client.pyi +++ b/mypy/typeshed/stdlib/xmlrpc/client.pyi @@ -69,7 +69,7 @@ class DateTime: def __gt__(self, other: _DateTimeComparable) -> bool: ... def __ge__(self, other: _DateTimeComparable) -> bool: ... def __eq__(self, other: _DateTimeComparable) -> bool: ... # type: ignore - def make_comparable(self, other: _DateTimeComparable) -> Tuple[str, str]: ... # undocumented + def make_comparable(self, other: _DateTimeComparable) -> tuple[str, str]: ... # undocumented def timetuple(self) -> time.struct_time: ... # undocumented def decode(self, data: Any) -> None: ... def encode(self, out: SupportsWrite[str]) -> None: ... @@ -86,7 +86,7 @@ class Binary: def _binary(data: bytes) -> Binary: ... # undocumented -WRAPPERS: Tuple[Type[DateTime], Type[Binary]] # undocumented +WRAPPERS: tuple[Type[DateTime], Type[Binary]] # undocumented class ExpatParser: # undocumented def __init__(self, target: Unmarshaller) -> None: ... @@ -159,9 +159,9 @@ class Unmarshaller: class _MultiCallMethod: # undocumented - __call_list: list[Tuple[str, Tuple[_Marshallable, ...]]] + __call_list: list[tuple[str, Tuple[_Marshallable, ...]]] __name: str - def __init__(self, call_list: list[Tuple[str, _Marshallable]], name: str) -> None: ... + def __init__(self, call_list: list[tuple[str, _Marshallable]], name: str) -> None: ... def __getattr__(self, name: str) -> _MultiCallMethod: ... def __call__(self, *args: _Marshallable) -> None: ... @@ -174,7 +174,7 @@ class MultiCallIterator: # undocumented class MultiCall: __server: ServerProxy - __call_list: list[Tuple[str, Tuple[_Marshallable, ...]]] + __call_list: list[tuple[str, Tuple[_Marshallable, ...]]] def __init__(self, server: ServerProxy) -> None: ... def __getattr__(self, item: str) -> _MultiCallMethod: ... def __call__(self) -> MultiCallIterator: ... @@ -184,7 +184,7 @@ FastMarshaller: Marshaller | None FastParser: ExpatParser | None FastUnmarshaller: Unmarshaller | None -def getparser(use_datetime: bool = ..., use_builtin_types: bool = ...) -> Tuple[ExpatParser, Unmarshaller]: ... +def getparser(use_datetime: bool = ..., use_builtin_types: bool = ...) -> tuple[ExpatParser, Unmarshaller]: ... def dumps( params: Fault | Tuple[_Marshallable, ...], methodname: str | None = ..., @@ -192,7 +192,7 @@ def dumps( encoding: str | None = ..., allow_none: bool = ..., ) -> str: ... -def loads(data: str, use_datetime: bool = ..., use_builtin_types: bool = ...) -> Tuple[Tuple[_Marshallable, ...], str | None]: ... +def loads(data: str, use_datetime: bool = ..., use_builtin_types: bool = ...) -> tuple[Tuple[_Marshallable, ...], str | None]: ... def gzip_encode(data: bytes) -> bytes: ... # undocumented def gzip_decode(data: bytes, max_decode: int = ...) -> bytes: ... # undocumented @@ -218,13 +218,13 @@ class Transport: _use_datetime: bool _use_builtin_types: bool - _connection: Tuple[_HostType | None, http.client.HTTPConnection | None] - _headers: list[Tuple[str, str]] - _extra_headers: list[Tuple[str, str]] + _connection: tuple[_HostType | None, http.client.HTTPConnection | None] + _headers: list[tuple[str, str]] + _extra_headers: list[tuple[str, str]] if sys.version_info >= (3, 8): def __init__( - self, use_datetime: bool = ..., use_builtin_types: bool = ..., *, headers: Iterable[Tuple[str, str]] = ... + self, use_datetime: bool = ..., use_builtin_types: bool = ..., *, headers: Iterable[tuple[str, str]] = ... ) -> None: ... else: def __init__(self, use_datetime: bool = ..., use_builtin_types: bool = ...) -> None: ... @@ -232,12 +232,12 @@ class Transport: def single_request( self, host: _HostType, handler: str, request_body: bytes, verbose: bool = ... ) -> Tuple[_Marshallable, ...]: ... - def getparser(self) -> Tuple[ExpatParser, Unmarshaller]: ... - def get_host_info(self, host: _HostType) -> Tuple[str, list[Tuple[str, str]], dict[str, str]]: ... + def getparser(self) -> tuple[ExpatParser, Unmarshaller]: ... + def get_host_info(self, host: _HostType) -> tuple[str, list[tuple[str, str]], dict[str, str]]: ... def make_connection(self, host: _HostType) -> http.client.HTTPConnection: ... def close(self) -> None: ... def send_request(self, host: _HostType, handler: str, request_body: bytes, debug: bool) -> http.client.HTTPConnection: ... - def send_headers(self, connection: http.client.HTTPConnection, headers: list[Tuple[str, str]]) -> None: ... + def send_headers(self, connection: http.client.HTTPConnection, headers: list[tuple[str, str]]) -> None: ... def send_content(self, connection: http.client.HTTPConnection, request_body: bytes) -> None: ... def parse_response(self, response: http.client.HTTPResponse) -> Tuple[_Marshallable, ...]: ... @@ -249,7 +249,7 @@ class SafeTransport(Transport): use_datetime: bool = ..., use_builtin_types: bool = ..., *, - headers: Iterable[Tuple[str, str]] = ..., + headers: Iterable[tuple[str, str]] = ..., context: Any | None = ..., ) -> None: ... else: @@ -276,7 +276,7 @@ class ServerProxy: use_datetime: bool = ..., use_builtin_types: bool = ..., *, - headers: Iterable[Tuple[str, str]] = ..., + headers: Iterable[tuple[str, str]] = ..., context: Any | None = ..., ) -> None: ... else: diff --git a/mypy/typeshed/stdlib/xmlrpc/server.pyi b/mypy/typeshed/stdlib/xmlrpc/server.pyi index 3240181a0467..bf5611fbaa96 100644 --- a/mypy/typeshed/stdlib/xmlrpc/server.pyi +++ b/mypy/typeshed/stdlib/xmlrpc/server.pyi @@ -64,7 +64,7 @@ class SimpleXMLRPCDispatcher: # undocumented class SimpleXMLRPCRequestHandler(http.server.BaseHTTPRequestHandler): - rpc_paths: Tuple[str, str] + rpc_paths: tuple[str, str] encode_threshold: int # undocumented aepattern: Pattern[str] # undocumented def accept_encodings(self) -> dict[str, float]: ... @@ -80,7 +80,7 @@ class SimpleXMLRPCServer(socketserver.TCPServer, SimpleXMLRPCDispatcher): _send_traceback_handler: bool def __init__( self, - addr: Tuple[str, int], + addr: tuple[str, int], requestHandler: Type[SimpleXMLRPCRequestHandler] = ..., logRequests: bool = ..., allow_none: bool = ..., @@ -96,7 +96,7 @@ class MultiPathXMLRPCServer(SimpleXMLRPCServer): # undocumented encoding: str def __init__( self, - addr: Tuple[str, int], + addr: tuple[str, int], requestHandler: Type[SimpleXMLRPCRequestHandler] = ..., logRequests: bool = ..., allow_none: bool = ..., @@ -140,7 +140,7 @@ class DocXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): class DocXMLRPCServer(SimpleXMLRPCServer, XMLRPCDocGenerator): def __init__( self, - addr: Tuple[str, int], + addr: tuple[str, int], requestHandler: Type[SimpleXMLRPCRequestHandler] = ..., logRequests: bool = ..., allow_none: bool = ..., diff --git a/mypy/typeshed/stdlib/zipimport.pyi b/mypy/typeshed/stdlib/zipimport.pyi index 8ca97bf69845..155b9742aa57 100644 --- a/mypy/typeshed/stdlib/zipimport.pyi +++ b/mypy/typeshed/stdlib/zipimport.pyi @@ -1,7 +1,7 @@ import os import sys from types import CodeType, ModuleType -from typing import Any, Tuple +from typing import Any if sys.version_info >= (3, 7): from importlib.abc import ResourceReader @@ -12,7 +12,7 @@ class zipimporter(object): archive: str prefix: str def __init__(self, path: str | bytes | os.PathLike[Any]) -> None: ... - def find_loader(self, fullname: str, path: str | None = ...) -> Tuple[zipimporter | None, list[str]]: ... # undocumented + def find_loader(self, fullname: str, path: str | None = ...) -> tuple[zipimporter | None, list[str]]: ... # undocumented def find_module(self, fullname: str, path: str | None = ...) -> zipimporter | None: ... def get_code(self, fullname: str) -> CodeType: ... def get_data(self, pathname: str) -> str: ... diff --git a/mypy/typeshed/stdlib/zoneinfo/__init__.pyi b/mypy/typeshed/stdlib/zoneinfo/__init__.pyi index 2a188c7d0477..4f924e0cc4bf 100644 --- a/mypy/typeshed/stdlib/zoneinfo/__init__.pyi +++ b/mypy/typeshed/stdlib/zoneinfo/__init__.pyi @@ -1,7 +1,7 @@ import typing from _typeshed import StrPath from datetime import tzinfo -from typing import Any, Iterable, Protocol, Sequence, Set, Type +from typing import Any, Iterable, Protocol, Sequence, Type _T = typing.TypeVar("_T", bound="ZoneInfo") @@ -24,7 +24,7 @@ class ZoneInfo(tzinfo): # 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: ... -def available_timezones() -> Set[str]: ... +def available_timezones() -> set[str]: ... TZPATH: Sequence[str] diff --git a/mypy/typeshed/stubs/mypy-extensions/METADATA.toml b/mypy/typeshed/stubs/mypy-extensions/METADATA.toml index 8732c02c405f..79b51931ee0b 100644 --- a/mypy/typeshed/stubs/mypy-extensions/METADATA.toml +++ b/mypy/typeshed/stubs/mypy-extensions/METADATA.toml @@ -1,2 +1,2 @@ -version = "0.4" +version = "0.4.*" python2 = true diff --git a/mypy/typestate.py b/mypy/typestate.py index 73376ee7157a..4cf2e19a1d26 100644 --- a/mypy/typestate.py +++ b/mypy/typestate.py @@ -4,7 +4,7 @@ """ from typing import Dict, Set, Tuple, Optional, List -from typing_extensions import ClassVar, Final +from typing_extensions import ClassVar, Final, TypeAlias as _TypeAlias from mypy.nodes import TypeInfo from mypy.types import Instance, TypeAliasType, get_proper_type, Type @@ -12,15 +12,15 @@ from mypy import state # Represents that the 'left' instance is a subtype of the 'right' instance -SubtypeRelationship = Tuple[Instance, Instance] +SubtypeRelationship: _TypeAlias = Tuple[Instance, Instance] # A tuple encoding the specific conditions under which we performed the subtype check. # (e.g. did we want a proper subtype? A regular subtype while ignoring variance?) -SubtypeKind = Tuple[bool, ...] +SubtypeKind: _TypeAlias = Tuple[bool, ...] # A cache that keeps track of whether the given TypeInfo is a part of a particular # subtype relationship -SubtypeCache = Dict[TypeInfo, Dict[SubtypeKind, Set[SubtypeRelationship]]] +SubtypeCache: _TypeAlias = Dict[TypeInfo, Dict[SubtypeKind, Set[SubtypeRelationship]]] class TypeState: diff --git a/mypy/typetraverser.py b/mypy/typetraverser.py index 3bebd3831971..a03784b0406e 100644 --- a/mypy/typetraverser.py +++ b/mypy/typetraverser.py @@ -6,7 +6,7 @@ Type, SyntheticTypeVisitor, AnyType, UninhabitedType, NoneType, ErasedType, DeletedType, TypeVarType, LiteralType, Instance, CallableType, TupleType, TypedDictType, UnionType, Overloaded, TypeType, CallableArgument, UnboundType, TypeList, StarType, EllipsisType, - PlaceholderType, PartialType, RawExpressionType, TypeAliasType + PlaceholderType, PartialType, RawExpressionType, TypeAliasType, ParamSpecType ) @@ -37,6 +37,9 @@ def visit_type_var(self, t: TypeVarType) -> None: # definition. We want to traverse everything just once. pass + def visit_param_spec(self, t: ParamSpecType) -> None: + pass + def visit_literal_type(self, t: LiteralType) -> None: t.fallback.accept(self) diff --git a/mypy/typevars.py b/mypy/typevars.py index f595551bd3bc..b49194f342e0 100644 --- a/mypy/typevars.py +++ b/mypy/typevars.py @@ -3,7 +3,7 @@ from mypy.nodes import TypeInfo from mypy.erasetype import erase_typevars -from mypy.types import Instance, TypeVarType, TupleType, Type, TypeOfAny, AnyType +from mypy.types import Instance, TypeVarType, TupleType, Type, TypeOfAny, AnyType, ParamSpecType def fill_typevars(typ: TypeInfo) -> Union[Instance, TupleType]: @@ -16,10 +16,15 @@ def fill_typevars(typ: TypeInfo) -> Union[Instance, TupleType]: for i in range(len(typ.defn.type_vars)): tv = typ.defn.type_vars[i] # Change the line number - tv = TypeVarType( - tv.name, tv.fullname, tv.id, tv.values, - tv.upper_bound, tv.variance, line=-1, column=-1, - ) + if isinstance(tv, TypeVarType): + tv = TypeVarType( + tv.name, tv.fullname, tv.id, tv.values, + tv.upper_bound, tv.variance, line=-1, column=-1, + ) + else: + assert isinstance(tv, ParamSpecType) + tv = ParamSpecType(tv.name, tv.fullname, tv.id, tv.flavor, tv.upper_bound, + line=-1, column=-1) tvs.append(tv) inst = Instance(typ, tvs) if typ.tuple_type is None: diff --git a/mypy/util.py b/mypy/util.py index db77ac42fbd4..533e9c6bee6e 100644 --- a/mypy/util.py +++ b/mypy/util.py @@ -30,14 +30,14 @@ # At least this number of columns will be shown on each side of # error location when printing source code snippet. -MINIMUM_WIDTH = 20 +MINIMUM_WIDTH: Final = 20 # VT100 color code processing was added in Windows 10, but only the second major update, # Threshold 2. Fortunately, everyone (even on LTSB, Long Term Support Branch) should # have a version of Windows 10 newer than this. Note that Windows 8 and below are not # supported, but are either going out of support, or make up only a few % of the market. -MINIMUM_WINDOWS_MAJOR_VT100 = 10 -MINIMUM_WINDOWS_BUILD_VT100 = 10586 +MINIMUM_WINDOWS_MAJOR_VT100: Final = 10 +MINIMUM_WINDOWS_BUILD_VT100: Final = 10586 default_python2_interpreter: Final = [ "python2", @@ -566,11 +566,12 @@ def initialize_unix_colors(self) -> bool: under = curses.tigetstr('smul') set_color = curses.tigetstr('setaf') set_eseq = curses.tigetstr('cup') + normal = curses.tigetstr('sgr0') - if not (bold and under and set_color and set_eseq): + if not (bold and under and set_color and set_eseq and normal): return False - self.NORMAL = curses.tigetstr('sgr0').decode() + self.NORMAL = normal.decode() self.BOLD = bold.decode() self.UNDER = under.decode() self.DIM = parse_gray_color(set_eseq) diff --git a/mypy/version.py b/mypy/version.py index b45a02330d6e..e6188ccf96c1 100644 --- a/mypy/version.py +++ b/mypy/version.py @@ -5,7 +5,7 @@ # - Release versions have the form "0.NNN". # - Dev versions have the form "0.NNN+dev" (PLUS sign to conform to PEP 440). # - For 1.0 we'll switch back to 1.2.3 form. -__version__ = '0.920+dev' +__version__ = '0.930' base_version = __version__ mypy_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) diff --git a/mypy_self_check.ini b/mypy_self_check.ini index 0139deff863b..8fbdf9b96500 100644 --- a/mypy_self_check.ini +++ b/mypy_self_check.ini @@ -19,4 +19,4 @@ pretty = True always_false = MYPYC plugins = misc/proper_plugin.py python_version = 3.6 -exclude = mypy/typeshed/ +exclude = mypy/typeshed/|mypyc/test-data/|mypyc/lib-rt/ diff --git a/scripts/mypyc b/mypyc/__main__.py old mode 100755 new mode 100644 similarity index 84% rename from scripts/mypyc rename to mypyc/__main__.py index 1dc42966eb35..aaaf9a83c8c5 --- a/scripts/mypyc +++ b/mypyc/__main__.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 """Mypyc command-line tool. Usage: @@ -19,14 +18,15 @@ base_path = os.path.join(os.path.dirname(__file__), '..') setup_format = """\ -from distutils.core import setup +from setuptools import setup from mypyc.build import mypycify setup(name='mypyc_output', - ext_modules=mypycify({}, opt_level="{}"), + ext_modules=mypycify({}, opt_level="{}", debug_level="{}"), ) """ + def main() -> None: build_dir = 'build' # can this be overridden?? try: @@ -35,10 +35,11 @@ def main() -> None: pass opt_level = os.getenv("MYPYC_OPT_LEVEL", '3') + debug_level = os.getenv("MYPYC_DEBUG_LEVEL", '1') 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)) + f.write(setup_format.format(sys.argv[1:], opt_level, debug_level)) # 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 @@ -49,5 +50,6 @@ def main() -> None: cmd = subprocess.run([sys.executable, setup_file, 'build_ext', '--inplace'], env=env) sys.exit(cmd.returncode) + if __name__ == '__main__': main() diff --git a/mypyc/analysis/blockfreq.py b/mypyc/analysis/blockfreq.py new file mode 100644 index 000000000000..547fb9ce10d3 --- /dev/null +++ b/mypyc/analysis/blockfreq.py @@ -0,0 +1,32 @@ +"""Find basic blocks that are likely to be executed frequently. + +For example, this would not include blocks that have exception handlers. + +We can use different optimization heuristics for common and rare code. For +example, we can make IR fast to compile instead of fast to execute for rare +code. +""" + +from typing import Set + +from mypyc.ir.ops import BasicBlock, Goto, Branch + + +def frequently_executed_blocks(entry_point: BasicBlock) -> Set[BasicBlock]: + result: Set[BasicBlock] = set() + worklist = [entry_point] + while worklist: + block = worklist.pop() + if block in result: + continue + result.add(block) + t = block.terminator + if isinstance(t, Goto): + worklist.append(t.label) + elif isinstance(t, Branch): + if t.rare or t.traceback_entry is not None: + worklist.append(t.false) + else: + worklist.append(t.true) + worklist.append(t.false) + return result diff --git a/mypyc/analysis/ircheck.py b/mypyc/analysis/ircheck.py new file mode 100644 index 000000000000..f15beceff8ce --- /dev/null +++ b/mypyc/analysis/ircheck.py @@ -0,0 +1,165 @@ +"""Utilities for checking that internal ir is valid and consistent.""" +from typing import List, Union +from mypyc.ir.pprint import format_func +from mypyc.ir.ops import ( + OpVisitor, BasicBlock, Op, ControlOp, Goto, Branch, Return, Unreachable, + Assign, AssignMulti, LoadErrorValue, LoadLiteral, GetAttr, SetAttr, LoadStatic, + InitStatic, TupleGet, TupleSet, IncRef, DecRef, Call, MethodCall, Cast, + Box, Unbox, RaiseStandardError, CallC, Truncate, LoadGlobal, IntOp, ComparisonOp, + LoadMem, SetMem, GetElementPtr, LoadAddress, KeepAlive +) +from mypyc.ir.func_ir import FuncIR + + +class FnError(object): + def __init__(self, source: Union[Op, BasicBlock], desc: str) -> None: + self.source = source + self.desc = desc + + def __eq__(self, other: object) -> bool: + return isinstance(other, FnError) and self.source == other.source and \ + self.desc == other.desc + + def __repr__(self) -> str: + return f"FnError(source={self.source}, desc={self.desc})" + + +def check_func_ir(fn: FuncIR) -> List[FnError]: + """Applies validations to a given function ir and returns a list of errors found.""" + errors = [] + + for block in fn.blocks: + if not block.terminated: + errors.append(FnError( + source=block.ops[-1] if block.ops else block, + desc="Block not terminated", + )) + + op_checker = OpChecker(fn) + for block in fn.blocks: + for op in block.ops: + op.accept(op_checker) + + return errors + op_checker.errors + + +class IrCheckException(Exception): + pass + + +def assert_func_ir_valid(fn: FuncIR) -> None: + errors = check_func_ir(fn) + if errors: + raise IrCheckException("Internal error: Generated invalid IR: \n" + "\n".join( + format_func(fn, [(e.source, e.desc) for e in errors])), + ) + + +class OpChecker(OpVisitor[None]): + def __init__(self, parent_fn: FuncIR) -> None: + self.parent_fn = parent_fn + self.errors: List[FnError] = [] + + def fail(self, source: Op, desc: str) -> None: + self.errors.append(FnError(source=source, desc=desc)) + + def check_control_op_targets(self, op: ControlOp) -> None: + for target in op.targets(): + if target not in self.parent_fn.blocks: + self.fail(source=op, desc=f"Invalid control operation target: {target.label}") + + def visit_goto(self, op: Goto) -> None: + self.check_control_op_targets(op) + + def visit_branch(self, op: Branch) -> None: + self.check_control_op_targets(op) + + def visit_return(self, op: Return) -> None: + pass + + def visit_unreachable(self, op: Unreachable) -> None: + pass + + def visit_assign(self, op: Assign) -> None: + pass + + def visit_assign_multi(self, op: AssignMulti) -> None: + pass + + def visit_load_error_value(self, op: LoadErrorValue) -> None: + pass + + def visit_load_literal(self, op: LoadLiteral) -> None: + pass + + def visit_get_attr(self, op: GetAttr) -> None: + pass + + def visit_set_attr(self, op: SetAttr) -> None: + pass + + def visit_load_static(self, op: LoadStatic) -> None: + pass + + def visit_init_static(self, op: InitStatic) -> None: + pass + + def visit_tuple_get(self, op: TupleGet) -> None: + pass + + def visit_tuple_set(self, op: TupleSet) -> None: + pass + + def visit_inc_ref(self, op: IncRef) -> None: + pass + + def visit_dec_ref(self, op: DecRef) -> None: + pass + + def visit_call(self, op: Call) -> None: + pass + + def visit_method_call(self, op: MethodCall) -> None: + pass + + def visit_cast(self, op: Cast) -> None: + pass + + def visit_box(self, op: Box) -> None: + pass + + def visit_unbox(self, op: Unbox) -> None: + pass + + def visit_raise_standard_error(self, op: RaiseStandardError) -> None: + pass + + def visit_call_c(self, op: CallC) -> None: + pass + + def visit_truncate(self, op: Truncate) -> None: + pass + + def visit_load_global(self, op: LoadGlobal) -> None: + pass + + def visit_int_op(self, op: IntOp) -> None: + pass + + def visit_comparison_op(self, op: ComparisonOp) -> None: + pass + + def visit_load_mem(self, op: LoadMem) -> None: + pass + + def visit_set_mem(self, op: SetMem) -> None: + pass + + def visit_get_element_ptr(self, op: GetElementPtr) -> None: + pass + + def visit_load_address(self, op: LoadAddress) -> None: + pass + + def visit_keep_alive(self, op: KeepAlive) -> None: + pass diff --git a/mypyc/build.py b/mypyc/build.py index 1834b9db2338..571fb0dd2f5a 100644 --- a/mypyc/build.py +++ b/mypyc/build.py @@ -4,7 +4,7 @@ modules to be passed to setup. A trivial setup.py for a mypyc built project, then, looks like: - from distutils.core import setup + from setuptools import setup from mypyc.build import mypycify setup(name='test_module', @@ -45,6 +45,13 @@ if TYPE_CHECKING: from distutils.core import Extension # noqa +try: + # Import setuptools so that it monkey-patch overrides distutils + import setuptools # type: ignore # noqa +except ImportError: + if sys.version_info >= (3, 12): + # Raise on Python 3.12, since distutils will go away forever + raise from distutils import sysconfig, ccompiler @@ -424,7 +431,8 @@ def mypycify( *, only_compile_paths: Optional[Iterable[str]] = None, verbose: bool = False, - opt_level: str = '3', + opt_level: str = "3", + debug_level: str = "1", strip_asserts: bool = False, multi_file: bool = False, separate: Union[bool, List[Tuple[List[str], Optional[str]]]] = False, @@ -447,6 +455,7 @@ def mypycify( verbose: Should mypyc be more verbose. Defaults to false. opt_level: The optimization level, as a string. Defaults to '3' (meaning '-O3'). + debug_level: The debug level, as a string. Defaults to '1' (meaning '-g1'). strip_asserts: Should asserts be stripped from the generated code. multi_file: Should each Python module be compiled into its own C source file. @@ -504,7 +513,9 @@ def mypycify( cflags: List[str] = [] if compiler.compiler_type == 'unix': cflags += [ - '-O{}'.format(opt_level), '-Werror', '-Wno-unused-function', '-Wno-unused-label', + '-O{}'.format(opt_level), + '-g{}'.format(debug_level), + '-Werror', '-Wno-unused-function', '-Wno-unused-label', '-Wno-unreachable-code', '-Wno-unused-variable', '-Wno-unused-command-line-argument', '-Wno-unknown-warning-option', ] diff --git a/mypyc/codegen/emit.py b/mypyc/codegen/emit.py index 323d34f83a04..531121134b03 100644 --- a/mypyc/codegen/emit.py +++ b/mypyc/codegen/emit.py @@ -348,35 +348,56 @@ def declare_tuple_struct(self, tuple_type: RTuple) -> None: is_type=True, ) - def emit_inc_ref(self, dest: str, rtype: RType) -> None: + def emit_inc_ref(self, dest: str, rtype: RType, *, rare: bool = False) -> None: """Increment reference count of C expression `dest`. For composite unboxed structures (e.g. tuples) recursively increment reference counts for each component. + + If rare is True, optimize for code size and compilation speed. """ if is_int_rprimitive(rtype): - self.emit_line('CPyTagged_IncRef(%s);' % dest) + if rare: + self.emit_line('CPyTagged_IncRef(%s);' % dest) + else: + self.emit_line('CPyTagged_INCREF(%s);' % dest) elif isinstance(rtype, RTuple): for i, item_type in enumerate(rtype.types): self.emit_inc_ref('{}.f{}'.format(dest, i), item_type) elif not rtype.is_unboxed: + # Always inline, since this is a simple op self.emit_line('CPy_INCREF(%s);' % dest) # Otherwise assume it's an unboxed, pointerless value and do nothing. - def emit_dec_ref(self, dest: str, rtype: RType, is_xdec: bool = False) -> None: + def emit_dec_ref(self, + dest: str, + rtype: RType, + *, + is_xdec: bool = False, + rare: bool = False) -> None: """Decrement reference count of C expression `dest`. For composite unboxed structures (e.g. tuples) recursively decrement reference counts for each component. + + If rare is True, optimize for code size and compilation speed. """ x = 'X' if is_xdec else '' if is_int_rprimitive(rtype): - self.emit_line('CPyTagged_%sDecRef(%s);' % (x, dest)) + if rare: + self.emit_line('CPyTagged_%sDecRef(%s);' % (x, dest)) + else: + # Inlined + self.emit_line('CPyTagged_%sDECREF(%s);' % (x, dest)) elif isinstance(rtype, RTuple): for i, item_type in enumerate(rtype.types): - self.emit_dec_ref('{}.f{}'.format(dest, i), item_type, is_xdec) + self.emit_dec_ref('{}.f{}'.format(dest, i), item_type, is_xdec=is_xdec, rare=rare) elif not rtype.is_unboxed: - self.emit_line('CPy_%sDecRef(%s);' % (x, dest)) + if rare: + self.emit_line('CPy_%sDecRef(%s);' % (x, dest)) + else: + # Inlined + self.emit_line('CPy_%sDECREF(%s);' % (x, dest)) # Otherwise assume it's an unboxed, pointerless value and do nothing. def pretty_name(self, typ: RType) -> str: diff --git a/mypyc/codegen/emitfunc.py b/mypyc/codegen/emitfunc.py index 15f17a3b0754..3b94c5648769 100644 --- a/mypyc/codegen/emitfunc.py +++ b/mypyc/codegen/emitfunc.py @@ -21,6 +21,7 @@ from mypyc.ir.func_ir import FuncIR, FuncDecl, FUNC_STATICMETHOD, FUNC_CLASSMETHOD, all_values from mypyc.ir.class_ir import ClassIR from mypyc.ir.pprint import generate_names_for_ir +from mypyc.analysis.blockfreq import frequently_executed_blocks # Whether to insert debug asserts for all error handling, to quickly # catch errors propagating without exceptions set. @@ -77,8 +78,11 @@ def generate_native_function(fn: FuncIR, for i, block in enumerate(blocks): block.label = i + common = frequently_executed_blocks(fn.blocks[0]) + for i in range(len(blocks)): block = blocks[i] + visitor.rare = block not in common next_block = None if i + 1 < len(blocks): next_block = blocks[i + 1] @@ -105,6 +109,7 @@ def __init__(self, self.source_path = source_path self.module_name = module_name self.literals = emitter.context.literals + self.rare = False self.next_block: Optional[BasicBlock] = None def temp_name(self) -> str: @@ -416,7 +421,7 @@ def visit_inc_ref(self, op: IncRef) -> None: def visit_dec_ref(self, op: DecRef) -> None: src = self.reg(op.src) - self.emit_dec_ref(src, op.src.type, op.is_xdec) + self.emit_dec_ref(src, op.src.type, is_xdec=op.is_xdec) def visit_box(self, op: Box) -> None: self.emitter.emit_box(self.reg(op.src), self.reg(op), op.src.type, can_borrow=True) @@ -483,14 +488,20 @@ def visit_comparison_op(self, op: ComparisonOp) -> None: rhs = self.reg(op.rhs) lhs_cast = "" rhs_cast = "" - signed_op = {ComparisonOp.SLT, ComparisonOp.SGT, ComparisonOp.SLE, ComparisonOp.SGE} - unsigned_op = {ComparisonOp.ULT, ComparisonOp.UGT, ComparisonOp.ULE, ComparisonOp.UGE} - if op.op in signed_op: + if op.op in (ComparisonOp.SLT, ComparisonOp.SGT, ComparisonOp.SLE, ComparisonOp.SGE): + # Always signed comparison op lhs_cast = self.emit_signed_int_cast(op.lhs.type) rhs_cast = self.emit_signed_int_cast(op.rhs.type) - elif op.op in unsigned_op: + elif op.op in (ComparisonOp.ULT, ComparisonOp.UGT, ComparisonOp.ULE, ComparisonOp.UGE): + # Always unsigned comparison op lhs_cast = self.emit_unsigned_int_cast(op.lhs.type) rhs_cast = self.emit_unsigned_int_cast(op.rhs.type) + elif isinstance(op.lhs, Integer) and op.lhs.value < 0: + # Force signed ==/!= with negative operand + rhs_cast = self.emit_signed_int_cast(op.rhs.type) + elif isinstance(op.rhs, Integer) and op.rhs.value < 0: + # Force signed ==/!= with negative operand + lhs_cast = self.emit_signed_int_cast(op.lhs.type) self.emit_line('%s = %s%s %s %s%s;' % (dest, lhs_cast, lhs, op.op_str[op.op], rhs_cast, rhs)) @@ -542,7 +553,12 @@ def reg(self, reg: Value) -> str: s = str(val) if val >= (1 << 31): # Avoid overflowing signed 32-bit int - s += 'U' + s += 'ULL' + elif val == -(1 << 63): + # Avoid overflowing C integer literal + s = '(-9223372036854775807LL - 1)' + elif val <= -(1 << 31): + s += 'LL' return s else: return self.emitter.reg(reg) @@ -563,10 +579,10 @@ def emit_lines(self, *lines: str) -> None: self.emitter.emit_lines(*lines) def emit_inc_ref(self, dest: str, rtype: RType) -> None: - self.emitter.emit_inc_ref(dest, rtype) + self.emitter.emit_inc_ref(dest, rtype, rare=self.rare) def emit_dec_ref(self, dest: str, rtype: RType, is_xdec: bool) -> None: - self.emitter.emit_dec_ref(dest, rtype, is_xdec) + self.emitter.emit_dec_ref(dest, rtype, is_xdec=is_xdec, rare=self.rare) def emit_declaration(self, line: str) -> None: self.declarations.emit_line(line) diff --git a/mypyc/common.py b/mypyc/common.py index 80db85135201..6080649f7eb6 100644 --- a/mypyc/common.py +++ b/mypyc/common.py @@ -1,5 +1,4 @@ from mypy.util import unnamed_function -import sys from typing import Dict, Any, Optional, Tuple import sys @@ -48,6 +47,7 @@ # Note: Assume that the compiled code uses the same bit width as mypyc, except for # Python 3.5 on macOS. MAX_LITERAL_SHORT_INT: Final = sys.maxsize >> 1 if not IS_MIXED_32_64_BIT_BUILD else 2 ** 30 - 1 +MIN_LITERAL_SHORT_INT: Final = -MAX_LITERAL_SHORT_INT - 1 # Runtime C library files RUNTIME_C_FILES: Final = [ diff --git a/mypyc/doc/dev-intro.md b/mypyc/doc/dev-intro.md index 11de9cdc0c8b..bf0c1a836874 100644 --- a/mypyc/doc/dev-intro.md +++ b/mypyc/doc/dev-intro.md @@ -73,11 +73,11 @@ compiled code. For example, you may want to do interactive testing or to run benchmarks. This is also handy if you want to inspect the generated C code (see Inspecting Generated C). -Run `scripts/mypyc` to compile a module to a C extension using your +Run `mypyc` to compile a module to a C extension using your development version of mypyc: ``` -$ scripts/mypyc program.py +$ mypyc program.py ``` This will generate a C extension for `program` in the current working diff --git a/mypyc/ir/class_ir.py b/mypyc/ir/class_ir.py index 746fa45db327..ade04f39edcb 100644 --- a/mypyc/ir/class_ir.py +++ b/mypyc/ir/class_ir.py @@ -121,7 +121,7 @@ def __init__(self, name: str, module_name: str, is_trait: bool = False, # Map of methods that are actually present in an extension class self.methods: OrderedDict[str, FuncIR] = OrderedDict() # Glue methods for boxing/unboxing when a class changes the type - # while overriding a method. Maps from (parent class overrided, method) + # while overriding a method. Maps from (parent class overridden, method) # to IR of glue method. self.glue_methods: Dict[Tuple[ClassIR, str], FuncIR] = OrderedDict() @@ -152,6 +152,14 @@ def __init__(self, name: str, module_name: str, is_trait: bool = False, # None if separate compilation prevents this from working self.children: Optional[List[ClassIR]] = [] + def __repr__(self) -> str: + return ( + "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}" + ")".format(self=self)) + @property def fullname(self) -> str: return "{}.{}".format(self.module_name, self.name) diff --git a/mypyc/ir/ops.py b/mypyc/ir/ops.py index 0915be50e9a9..22dead2f7976 100644 --- a/mypyc/ir/ops.py +++ b/mypyc/ir/ops.py @@ -340,7 +340,8 @@ def __init__(self, self.negated = False # If not None, the true label should generate a traceback entry (func name, line number) self.traceback_entry: Optional[Tuple[str, int]] = None - # If True, the condition is expected to be usually False (for optimization purposes) + # If True, we expect to usually take the false branch (for optimization purposes); + # this is implicitly treated as true if there is a traceback entry self.rare = rare def targets(self) -> Sequence[BasicBlock]: diff --git a/mypyc/ir/pprint.py b/mypyc/ir/pprint.py index af21328a33e0..daa0fd0f86df 100644 --- a/mypyc/ir/pprint.py +++ b/mypyc/ir/pprint.py @@ -1,6 +1,7 @@ """Utilities for pretty-printing IR in a human-readable form.""" -from typing import Any, Dict, List +from collections import defaultdict +from typing import Any, Dict, List, Union, Sequence, Tuple from typing_extensions import Final @@ -10,12 +11,14 @@ LoadStatic, InitStatic, TupleGet, TupleSet, IncRef, DecRef, Call, MethodCall, Cast, Box, Unbox, RaiseStandardError, CallC, Truncate, LoadGlobal, IntOp, ComparisonOp, LoadMem, SetMem, GetElementPtr, LoadAddress, Register, Value, OpVisitor, BasicBlock, ControlOp, LoadLiteral, - AssignMulti, KeepAlive + AssignMulti, KeepAlive, Op ) from mypyc.ir.func_ir import FuncIR, all_values_full from mypyc.ir.module_ir import ModuleIRs from mypyc.ir.rtypes import is_bool_rprimitive, is_int_rprimitive, RType +ErrorSource = Union[BasicBlock, Op] + class IRPrettyPrintVisitor(OpVisitor[str]): """Internal visitor that pretty-prints ops.""" @@ -269,7 +272,8 @@ def format_registers(func_ir: FuncIR, def format_blocks(blocks: List[BasicBlock], - names: Dict[Value, str]) -> List[str]: + names: Dict[Value, str], + source_to_error: Dict[ErrorSource, List[str]]) -> List[str]: """Format a list of IR basic blocks into a human-readable form.""" # First label all of the blocks for i, block in enumerate(blocks): @@ -290,14 +294,22 @@ def format_blocks(blocks: List[BasicBlock], handler_msg = ' (handler for {})'.format(', '.join(labels)) lines.append('L%d:%s' % (block.label, handler_msg)) + if block in source_to_error: + for error in source_to_error[block]: + lines.append(f" ERR: {error}") ops = block.ops if (isinstance(ops[-1], Goto) and i + 1 < len(blocks) - and ops[-1].label == blocks[i + 1]): - # Hide the last goto if it just goes to the next basic block. + and ops[-1].label == blocks[i + 1] + and not source_to_error.get(ops[-1], [])): + # Hide the last goto if it just goes to the next basic block, + # and there are no assocatiated errors with the op. ops = ops[:-1] for op in ops: line = ' ' + op.accept(visitor) lines.append(line) + if op in source_to_error: + for error in source_to_error[op]: + lines.append(f" ERR: {error}") if not isinstance(block.ops[-1], (Goto, Branch, Return, Unreachable)): # Each basic block needs to exit somewhere. @@ -305,7 +317,7 @@ def format_blocks(blocks: List[BasicBlock], return lines -def format_func(fn: FuncIR) -> List[str]: +def format_func(fn: FuncIR, errors: Sequence[Tuple[ErrorSource, str]] = ()) -> List[str]: lines = [] cls_prefix = fn.class_name + '.' if fn.class_name else '' lines.append('def {}{}({}):'.format(cls_prefix, fn.name, @@ -313,7 +325,12 @@ def format_func(fn: FuncIR) -> List[str]: names = generate_names_for_ir(fn.arg_regs, fn.blocks) for line in format_registers(fn, names): lines.append(' ' + line) - code = format_blocks(fn.blocks, names) + + source_to_error = defaultdict(list) + for source, error in errors: + source_to_error[source].append(error) + + code = format_blocks(fn.blocks, names, source_to_error) lines.extend(code) return lines diff --git a/mypyc/ir/rtypes.py b/mypyc/ir/rtypes.py index 9c27e425a78a..4bf71883b15d 100644 --- a/mypyc/ir/rtypes.py +++ b/mypyc/ir/rtypes.py @@ -522,11 +522,11 @@ def deserialize(cls, data: JsonDict, ctx: 'DeserMaps') -> 'RTuple': # Dictionary iterator tuple: (should continue, internal offset, key, value) # See mypyc.irbuild.for_helpers.ForDictionaryCommon for more details. dict_next_rtuple_pair = RTuple( - [bool_rprimitive, int_rprimitive, object_rprimitive, object_rprimitive] + [bool_rprimitive, short_int_rprimitive, object_rprimitive, object_rprimitive] ) # Same as above but just for key or value. dict_next_rtuple_single = RTuple( - [bool_rprimitive, int_rprimitive, object_rprimitive] + [bool_rprimitive, short_int_rprimitive, object_rprimitive] ) diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index d000dbac373e..57baa8dbf574 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -10,9 +10,10 @@ example, expressions are transformed in mypyc.irbuild.expression and functions are transformed in mypyc.irbuild.function. """ +from contextlib import contextmanager from mypyc.irbuild.prepare import RegisterImplInfo -from typing import Callable, Dict, List, Tuple, Optional, Union, Sequence, Set, Any +from typing import Callable, Dict, List, Tuple, Optional, Union, Sequence, Set, Any, Iterator from typing_extensions import overload from mypy.backports import OrderedDict @@ -541,7 +542,7 @@ def assign(self, rvalue_reg: Value, line: int) -> None: if isinstance(target, Register): - self.add(Assign(target, rvalue_reg)) + self.add(Assign(target, self.coerce(rvalue_reg, target.type, line))) elif isinstance(target, AssignmentTargetRegister): rvalue_reg = self.coerce(rvalue_reg, target.type, line) self.add(Assign(target.register, rvalue_reg)) @@ -1004,22 +1005,18 @@ def leave(self) -> Tuple[List[Register], List[RuntimeArg], List[BasicBlock], RTy self.fn_info = self.fn_infos[-1] return builder.args, runtime_args, builder.blocks, ret_type, fn_info + @contextmanager def enter_method(self, class_ir: ClassIR, name: str, ret_type: RType, fn_info: Union[FuncInfo, str] = '', - self_type: Optional[RType] = None) -> None: - """Begin generating IR for a method. + self_type: Optional[RType] = None) -> Iterator[None]: + """Generate IR for a method. If the method takes arguments, you should immediately afterwards call add_argument() for each non-self argument (self is created implicitly). - Call leave_method() to finish the generation of the method. - - You can enter multiple methods at a time. They are maintained in a - stack, and leave_method() leaves the topmost one. - Args: class_ir: Add method to this class name: Short name of the method @@ -1035,6 +1032,18 @@ def enter_method(self, if self_type is None: self_type = RInstance(class_ir) self.add_argument(SELF_NAME, self_type) + try: + yield + finally: + arg_regs, args, blocks, ret_type, fn_info = self.leave() + sig = FuncSignature(args, ret_type) + name = self.function_name_stack.pop() + class_ir = self.class_ir_stack.pop() + decl = FuncDecl(name, class_ir.name, self.module_name, sig) + ir = FuncIR(decl, arg_regs, blocks) + class_ir.methods[name] = ir + class_ir.method_decls[name] = ir.decl + self.functions.append(ir) def add_argument(self, var: Union[str, Var], typ: RType, kind: ArgKind = ARG_POS) -> Register: """Declare an argument in the current function. @@ -1047,18 +1056,6 @@ def add_argument(self, var: Union[str, Var], typ: RType, kind: ArgKind = ARG_POS self.runtime_args[-1].append(RuntimeArg(var.name, typ, kind)) return reg - def leave_method(self) -> None: - """Finish the generation of IR for a method.""" - arg_regs, args, blocks, ret_type, fn_info = self.leave() - sig = FuncSignature(args, ret_type) - name = self.function_name_stack.pop() - class_ir = self.class_ir_stack.pop() - decl = FuncDecl(name, class_ir.name, self.module_name, sig) - ir = FuncIR(decl, arg_regs, blocks) - class_ir.methods[name] = ir - class_ir.method_decls[name] = ir.decl - self.functions.append(ir) - def lookup(self, symbol: SymbolNode) -> SymbolTarget: return self.symtables[-1][symbol] @@ -1069,7 +1066,12 @@ def add_local(self, symbol: SymbolNode, typ: RType, is_arg: bool = False) -> 'Re is_arg: is this a function argument """ assert isinstance(symbol, SymbolNode) - reg = Register(typ, symbol.name, is_arg=is_arg, line=symbol.line) + reg = Register( + typ, + remangle_redefinition_name(symbol.name), + is_arg=is_arg, + line=symbol.line, + ) self.symtables[-1][symbol] = AssignmentTargetRegister(reg) if is_arg: self.builder.args.append(reg) @@ -1206,3 +1208,14 @@ def get_default() -> Value: GetAttr(builder.fn_info.callable_class.self_reg, name, arg.line)) assert isinstance(target, AssignmentTargetRegister) builder.assign_if_null(target.register, get_default, arg.initializer.line) + + +def remangle_redefinition_name(name: str) -> str: + """Remangle names produced by mypy when allow-redefinition is used and a name + is used with multiple types within a single block. + + We only need to do this for locals, because the name is used as the name of the register; + for globals, the name itself is stored in a register for the purpose of doing dict + lookups. + """ + return name.replace("'", "__redef__") diff --git a/mypyc/irbuild/callable_class.py b/mypyc/irbuild/callable_class.py index 1cb79b88c354..0261332800ae 100644 --- a/mypyc/irbuild/callable_class.py +++ b/mypyc/irbuild/callable_class.py @@ -104,31 +104,27 @@ def add_call_to_callable_class(builder: IRBuilder, def add_get_to_callable_class(builder: IRBuilder, fn_info: FuncInfo) -> None: """Generate the '__get__' method for a callable class.""" line = fn_info.fitem.line + with builder.enter_method( + fn_info.callable_class.ir, '__get__', object_rprimitive, fn_info, + self_type=object_rprimitive): + instance = builder.add_argument('instance', object_rprimitive) + builder.add_argument('owner', object_rprimitive) + + # If accessed through the class, just return the callable + # object. If accessed through an object, create a new bound + # instance method object. + instance_block, class_block = BasicBlock(), BasicBlock() + comparison = builder.translate_is_op( + builder.read(instance), builder.none_object(), 'is', line + ) + builder.add_bool_branch(comparison, class_block, instance_block) + + builder.activate_block(class_block) + builder.add(Return(builder.self())) - builder.enter_method( - fn_info.callable_class.ir, '__get__', object_rprimitive, fn_info, - self_type=object_rprimitive - ) - instance = builder.add_argument('instance', object_rprimitive) - builder.add_argument('owner', object_rprimitive) - - # If accessed through the class, just return the callable - # object. If accessed through an object, create a new bound - # instance method object. - instance_block, class_block = BasicBlock(), BasicBlock() - comparison = builder.translate_is_op( - builder.read(instance), builder.none_object(), 'is', line - ) - builder.add_bool_branch(comparison, class_block, instance_block) - - builder.activate_block(class_block) - builder.add(Return(builder.self())) - - builder.activate_block(instance_block) - builder.add(Return(builder.call_c(method_new_op, - [builder.self(), builder.read(instance)], line))) - - builder.leave_method() + builder.activate_block(instance_block) + builder.add(Return(builder.call_c(method_new_op, + [builder.self(), builder.read(instance)], line))) def instantiate_callable_class(builder: IRBuilder, fn_info: FuncInfo) -> Value: diff --git a/mypyc/irbuild/classdef.py b/mypyc/irbuild/classdef.py index d03b9028fd4d..6c2958c5b8de 100644 --- a/mypyc/irbuild/classdef.py +++ b/mypyc/irbuild/classdef.py @@ -1,12 +1,14 @@ """Transform class definitions from the mypy AST form to IR.""" -from typing import List, Optional, Tuple +from abc import abstractmethod +from typing import Callable, List, Optional, Tuple from typing_extensions import Final from mypy.nodes import ( - ClassDef, FuncDef, OverloadedFuncDef, PassStmt, AssignmentStmt, NameExpr, StrExpr, - ExpressionStmt, TempNode, Decorator, Lvalue, RefExpr, is_class_var + ClassDef, FuncDef, OverloadedFuncDef, PassStmt, AssignmentStmt, CallExpr, NameExpr, StrExpr, + ExpressionStmt, TempNode, Decorator, Lvalue, MemberExpr, RefExpr, TypeInfo, is_class_var ) +from mypy.types import Instance, get_proper_type from mypyc.ir.ops import ( Value, Register, Call, LoadErrorValue, LoadStatic, InitStatic, TupleSet, SetAttr, Return, BasicBlock, Branch, MethodCall, NAMESPACE_TYPE, LoadAddress @@ -24,10 +26,10 @@ ) from mypyc.primitives.dict_ops import dict_set_item_op, dict_new_op from mypyc.irbuild.util import ( - is_dataclass_decorator, get_func_def, is_dataclass, is_constant + is_dataclass_decorator, get_func_def, is_constant, dataclass_type ) from mypyc.irbuild.builder import IRBuilder -from mypyc.irbuild.function import transform_method +from mypyc.irbuild.function import handle_ext_method, handle_non_ext_method, load_type def transform_class_def(builder: IRBuilder, cdef: ClassDef) -> None: @@ -61,32 +63,28 @@ def transform_class_def(builder: IRBuilder, cdef: ClassDef) -> None: # decorated or inherit from Enum. Classes decorated with @trait do not # apply here, and are handled in a different way. if ir.is_ext_class: - # If the class is not decorated, generate an extension class for it. - type_obj: Optional[Value] = allocate_class(builder, cdef) - non_ext: Optional[NonExtClassInfo] = None - dataclass_non_ext = dataclass_non_ext_info(builder, cdef) + cls_type = dataclass_type(cdef) + if cls_type is None: + cls_builder: ClassBuilder = ExtClassBuilder(builder, cdef) + elif cls_type in ['dataclasses', 'attr-auto']: + cls_builder = DataClassBuilder(builder, cdef) + elif cls_type == 'attr': + cls_builder = AttrsClassBuilder(builder, cdef) + else: + raise ValueError(cls_type) else: - non_ext_bases = populate_non_ext_bases(builder, cdef) - non_ext_metaclass = find_non_ext_metaclass(builder, cdef, non_ext_bases) - non_ext_dict = setup_non_ext_dict(builder, cdef, non_ext_metaclass, non_ext_bases) - # We populate __annotations__ for non-extension classes - # because dataclasses uses it to determine which attributes to compute on. - # TODO: Maybe generate more precise types for annotations - non_ext_anns = builder.call_c(dict_new_op, [], cdef.line) - non_ext = NonExtClassInfo(non_ext_dict, non_ext_bases, non_ext_anns, non_ext_metaclass) - dataclass_non_ext = None - attrs_to_cache: List[Tuple[Lvalue, RType]] = [] + cls_builder = NonExtClassBuilder(builder, cdef) for stmt in cdef.defs.body: if isinstance(stmt, OverloadedFuncDef) and stmt.is_property: - if not ir.is_ext_class: + if isinstance(cls_builder, NonExtClassBuilder): # properties with both getters and setters in non_extension # classes not supported builder.error("Property setters not supported in non-extension classes", stmt.line) for item in stmt.items: with builder.catch_errors(stmt.line): - transform_method(builder, cdef, non_ext, get_func_def(item)) + cls_builder.add_method(get_func_def(item)) elif isinstance(stmt, (FuncDef, Decorator, OverloadedFuncDef)): # Ignore plugin generated methods (since they have no # bodies to compile and will need to have the bodies @@ -94,7 +92,7 @@ def transform_class_def(builder: IRBuilder, cdef: ClassDef) -> None: if cdef.info.names[stmt.name].plugin_generated: continue with builder.catch_errors(stmt.line): - transform_method(builder, cdef, non_ext, get_func_def(stmt)) + cls_builder.add_method(get_func_def(stmt)) elif isinstance(stmt, PassStmt): continue elif isinstance(stmt, AssignmentStmt): @@ -108,53 +106,217 @@ def transform_class_def(builder: IRBuilder, cdef: ClassDef) -> None: continue # We want to collect class variables in a dictionary for both real # non-extension classes and fake dataclass ones. - var_non_ext = non_ext or dataclass_non_ext - if var_non_ext: - add_non_ext_class_attr(builder, var_non_ext, lvalue, stmt, cdef, attrs_to_cache) - if non_ext: - continue - # Variable declaration with no body - if isinstance(stmt.rvalue, TempNode): - continue - # Only treat marked class variables as class variables. - if not (is_class_var(lvalue) or stmt.is_final_def): - continue - typ = builder.load_native_type_object(cdef.fullname) - value = builder.accept(stmt.rvalue) - builder.call_c( - py_setattr_op, [typ, builder.load_str(lvalue.name), value], stmt.line) - if builder.non_function_scope() and stmt.is_final_def: - builder.init_final_static(lvalue, value, cdef.name) + cls_builder.add_attr(lvalue, stmt) + elif isinstance(stmt, ExpressionStmt) and isinstance(stmt.expr, StrExpr): # Docstring. Ignore pass else: builder.error("Unsupported statement in class body", stmt.line) - if not non_ext: # That is, an extension class - generate_attr_defaults(builder, cdef) - create_ne_from_eq(builder, cdef) - if dataclass_non_ext: - assert type_obj - dataclass_finalize(builder, cdef, dataclass_non_ext, type_obj) - else: + cls_builder.finalize(ir) + + +class ClassBuilder: + """Create IR for a class definition. + + This is an abstract base class. + """ + + def __init__(self, builder: IRBuilder, cdef: ClassDef) -> None: + self.builder = builder + self.cdef = cdef + self.attrs_to_cache: List[Tuple[Lvalue, RType]] = [] + + @abstractmethod + def add_method(self, fdef: FuncDef) -> None: + """Add a method to the class IR""" + + @abstractmethod + def add_attr(self, lvalue: NameExpr, stmt: AssignmentStmt) -> None: + """Add an attribute to the class IR""" + + @abstractmethod + def finalize(self, ir: ClassIR) -> None: + """Perform any final operations to complete the class IR""" + + +class NonExtClassBuilder(ClassBuilder): + def __init__(self, builder: IRBuilder, cdef: ClassDef) -> None: + super().__init__(builder, cdef) + self.non_ext = self.create_non_ext_info() + + def create_non_ext_info(self) -> NonExtClassInfo: + non_ext_bases = populate_non_ext_bases(self.builder, self.cdef) + non_ext_metaclass = find_non_ext_metaclass(self.builder, self.cdef, non_ext_bases) + non_ext_dict = setup_non_ext_dict(self.builder, self.cdef, non_ext_metaclass, + non_ext_bases) + # We populate __annotations__ for non-extension classes + # because dataclasses uses it to determine which attributes to compute on. + # TODO: Maybe generate more precise types for annotations + non_ext_anns = self.builder.call_c(dict_new_op, [], self.cdef.line) + return NonExtClassInfo(non_ext_dict, non_ext_bases, non_ext_anns, non_ext_metaclass) + + def add_method(self, fdef: FuncDef) -> None: + handle_non_ext_method(self.builder, self.non_ext, self.cdef, fdef) + + def add_attr(self, lvalue: NameExpr, stmt: AssignmentStmt) -> None: + add_non_ext_class_attr_ann(self.builder, self.non_ext, lvalue, stmt) + add_non_ext_class_attr(self.builder, self.non_ext, lvalue, stmt, self.cdef, + self.attrs_to_cache) + + def finalize(self, ir: ClassIR) -> None: # Dynamically create the class via the type constructor - non_ext_class = load_non_ext_class(builder, ir, non_ext, cdef.line) - non_ext_class = load_decorated_class(builder, cdef, non_ext_class) + non_ext_class = load_non_ext_class(self.builder, ir, self.non_ext, self.cdef.line) + non_ext_class = load_decorated_class(self.builder, self.cdef, non_ext_class) # Save the decorated class - builder.add(InitStatic(non_ext_class, cdef.name, builder.module_name, NAMESPACE_TYPE)) + self.builder.add(InitStatic(non_ext_class, self.cdef.name, self.builder.module_name, + NAMESPACE_TYPE)) # Add the non-extension class to the dict - builder.call_c(dict_set_item_op, - [ - builder.load_globals_dict(), - builder.load_str(cdef.name), - non_ext_class - ], cdef.line) + self.builder.call_c(dict_set_item_op, + [ + self.builder.load_globals_dict(), + self.builder.load_str(self.cdef.name), + non_ext_class + ], self.cdef.line) # Cache any cacheable class attributes - cache_class_attrs(builder, attrs_to_cache, cdef) + cache_class_attrs(self.builder, self.attrs_to_cache, self.cdef) + + +class ExtClassBuilder(ClassBuilder): + def __init__(self, builder: IRBuilder, cdef: ClassDef) -> None: + super().__init__(builder, cdef) + # If the class is not decorated, generate an extension class for it. + self.type_obj: Optional[Value] = allocate_class(builder, cdef) + + def skip_attr_default(self, name: str, stmt: AssignmentStmt) -> bool: + """Controls whether to skip generating a default for an attribute.""" + return False + + def add_method(self, fdef: FuncDef) -> None: + handle_ext_method(self.builder, self.cdef, fdef) + + def add_attr(self, lvalue: NameExpr, stmt: AssignmentStmt) -> None: + # Variable declaration with no body + if isinstance(stmt.rvalue, TempNode): + return + # Only treat marked class variables as class variables. + if not (is_class_var(lvalue) or stmt.is_final_def): + return + typ = self.builder.load_native_type_object(self.cdef.fullname) + value = self.builder.accept(stmt.rvalue) + self.builder.call_c( + py_setattr_op, [typ, self.builder.load_str(lvalue.name), value], stmt.line) + if self.builder.non_function_scope() and stmt.is_final_def: + self.builder.init_final_static(lvalue, value, self.cdef.name) + + def finalize(self, ir: ClassIR) -> None: + generate_attr_defaults(self.builder, self.cdef, self.skip_attr_default) + create_ne_from_eq(self.builder, self.cdef) + + +class DataClassBuilder(ExtClassBuilder): + # controls whether an __annotations__ attribute should be added to the class + # __dict__. This is not desirable for attrs classes where auto_attribs is + # disabled, as attrs will reject it. + add_annotations_to_dict = True + + def __init__(self, builder: IRBuilder, cdef: ClassDef) -> None: + super().__init__(builder, cdef) + self.non_ext = self.create_non_ext_info() + + def create_non_ext_info(self) -> NonExtClassInfo: + """Set up a NonExtClassInfo to track dataclass attributes. + + In addition to setting up a normal extension class for dataclasses, + we also collect its class attributes like a non-extension class so + that we can hand them to the dataclass decorator. + """ + return NonExtClassInfo( + self.builder.call_c(dict_new_op, [], self.cdef.line), + self.builder.add(TupleSet([], self.cdef.line)), + self.builder.call_c(dict_new_op, [], self.cdef.line), + self.builder.add(LoadAddress(type_object_op.type, type_object_op.src, self.cdef.line)) + ) + + def skip_attr_default(self, name: str, stmt: AssignmentStmt) -> bool: + return stmt.type is not None + + def get_type_annotation(self, stmt: AssignmentStmt) -> Optional[TypeInfo]: + # We populate __annotations__ because dataclasses uses it to determine + # which attributes to compute on. + ann_type = get_proper_type(stmt.type) + if isinstance(ann_type, Instance): + return ann_type.type + return None + + def add_attr(self, lvalue: NameExpr, stmt: AssignmentStmt) -> None: + add_non_ext_class_attr_ann(self.builder, self.non_ext, lvalue, stmt, + self.get_type_annotation) + add_non_ext_class_attr(self.builder, self.non_ext, lvalue, stmt, self.cdef, + self.attrs_to_cache) + super().add_attr(lvalue, stmt) + + def finalize(self, ir: ClassIR) -> None: + """Generate code to finish instantiating a dataclass. + + This works by replacing all of the attributes on the class + (which will be descriptors) with whatever they would be in a + non-extension class, calling dataclass, then switching them back. + + The resulting class is an extension class and instances of it do not + have a __dict__ (unless something else requires it). + All methods written explicitly in the source are compiled and + may be called through the vtable while the methods generated + by dataclasses are interpreted and may not be. + + (If we just called dataclass without doing this, it would think that all + of the descriptors for our attributes are default values and generate an + incorrect constructor. We need to do the switch so that dataclass gets the + appropriate defaults.) + """ + super().finalize(ir) + assert self.type_obj + add_dunders_to_non_ext_dict(self.builder, self.non_ext, self.cdef.line, + self.add_annotations_to_dict) + dec = self.builder.accept( + next(d for d in self.cdef.decorators if is_dataclass_decorator(d))) + self.builder.call_c( + dataclass_sleight_of_hand, [dec, self.type_obj, self.non_ext.dict, self.non_ext.anns], + self.cdef.line) + + +class AttrsClassBuilder(DataClassBuilder): + """Create IR for an attrs class where auto_attribs=False (the default). + + When auto_attribs is enabled, attrs classes behave similarly to dataclasses + (i.e. types are stored as annotations on the class) and are thus handled + by DataClassBuilder, but when auto_attribs is disabled the types are + provided via attr.ib(type=...) + """ + + add_annotations_to_dict = False + + def skip_attr_default(self, name: str, stmt: AssignmentStmt) -> bool: + return True + + def get_type_annotation(self, stmt: AssignmentStmt) -> Optional[TypeInfo]: + if isinstance(stmt.rvalue, CallExpr): + # find the type arg in `attr.ib(type=str)` + callee = stmt.rvalue.callee + if (isinstance(callee, MemberExpr) and + callee.fullname in ['attr.ib', 'attr.attr'] and + 'type' in stmt.rvalue.arg_names): + index = stmt.rvalue.arg_names.index('type') + type_name = stmt.rvalue.args[index] + if isinstance(type_name, NameExpr) and isinstance(type_name.node, TypeInfo): + lvalue = stmt.lvalues[0] + assert isinstance(lvalue, NameExpr) + return type_name.node + return None def allocate_class(builder: IRBuilder, cdef: ClassDef) -> Value: @@ -312,23 +474,39 @@ def setup_non_ext_dict(builder: IRBuilder, return non_ext_dict +def add_non_ext_class_attr_ann(builder: IRBuilder, + non_ext: NonExtClassInfo, + lvalue: NameExpr, + stmt: AssignmentStmt, + get_type_info: Optional[Callable[[AssignmentStmt], + Optional[TypeInfo]]] = None + ) -> None: + """Add a class attribute to __annotations__ of a non-extension class.""" + typ: Optional[Value] = None + if get_type_info is not None: + type_info = get_type_info(stmt) + if type_info: + typ = load_type(builder, type_info, stmt.line) + + if typ is None: + # FIXME: if get_type_info is not provided, don't fall back to stmt.type? + ann_type = get_proper_type(stmt.type) + if isinstance(ann_type, Instance): + typ = load_type(builder, ann_type.type, stmt.line) + else: + 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) + + def add_non_ext_class_attr(builder: IRBuilder, non_ext: NonExtClassInfo, lvalue: NameExpr, stmt: AssignmentStmt, cdef: ClassDef, attr_to_cache: List[Tuple[Lvalue, RType]]) -> None: - """Add a class attribute to __annotations__ of a non-extension class. - - If the attribute is initialized with a value, also add it to __dict__. - """ - # We populate __annotations__ because dataclasses uses it to determine - # which attributes to compute on. - # TODO: Maybe generate more precise types for annotations - key = builder.load_str(lvalue.name) - typ = builder.add(LoadAddress(type_object_op.type, type_object_op.src, stmt.line)) - builder.call_c(dict_set_item_op, [non_ext.anns, key, typ], stmt.line) - + """Add a class attribute to __dict__ of a non-extension class.""" # Only add the attribute to the __dict__ if the assignment is of the form: # x: type = value (don't add attributes of the form 'x: type' to the __dict__). if not isinstance(stmt.rvalue, TempNode): @@ -346,8 +524,14 @@ def add_non_ext_class_attr(builder: IRBuilder, attr_to_cache.append((lvalue, object_rprimitive)) -def generate_attr_defaults(builder: IRBuilder, cdef: ClassDef) -> None: - """Generate an initialization method for default attr values (from class vars).""" +def generate_attr_defaults(builder: IRBuilder, cdef: ClassDef, + skip: Optional[Callable[[str, AssignmentStmt], bool]] = None) -> None: + """Generate an initialization method for default attr values (from class vars). + + If provided, the skip arg should be a callable which will return whether + to skip generating a default for an attribute. It will be passed the name of + the attribute and the corresponding AssignmentStmt. + """ cls = builder.mapper.type_to_ir[cdef.info] if cls.builtin_base: return @@ -371,8 +555,7 @@ def generate_attr_defaults(builder: IRBuilder, cdef: ClassDef) -> None: check_deletable_declaration(builder, cls, stmt.line) continue - # Skip type annotated assignments in dataclasses - if is_dataclass(cdef) and stmt.type: + if skip is not None and skip(name, stmt): continue default_assignments.append(stmt) @@ -380,28 +563,25 @@ def generate_attr_defaults(builder: IRBuilder, cdef: ClassDef) -> None: if not default_assignments: return - builder.enter_method(cls, '__mypyc_defaults_setup', bool_rprimitive) - - self_var = builder.self() - for stmt in default_assignments: - lvalue = stmt.lvalues[0] - assert isinstance(lvalue, NameExpr) - if not stmt.is_final_def and not is_constant(stmt.rvalue): - builder.warning('Unsupported default attribute value', stmt.rvalue.line) - - # If the attribute is initialized to None and type isn't optional, - # don't initialize it to anything. - attr_type = cls.attr_type(lvalue.name) - if isinstance(stmt.rvalue, RefExpr) and stmt.rvalue.fullname == 'builtins.None': - if (not is_optional_type(attr_type) and not is_object_rprimitive(attr_type) - and not is_none_rprimitive(attr_type)): - continue - val = builder.coerce(builder.accept(stmt.rvalue), attr_type, stmt.line) - builder.add(SetAttr(self_var, lvalue.name, val, -1)) - - builder.add(Return(builder.true())) + with builder.enter_method(cls, '__mypyc_defaults_setup', bool_rprimitive): + self_var = builder.self() + for stmt in default_assignments: + lvalue = stmt.lvalues[0] + assert isinstance(lvalue, NameExpr) + if not stmt.is_final_def and not is_constant(stmt.rvalue): + builder.warning('Unsupported default attribute value', stmt.rvalue.line) + + # If the attribute is initialized to None and type isn't optional, + # don't initialize it to anything. + attr_type = cls.attr_type(lvalue.name) + if isinstance(stmt.rvalue, RefExpr) and stmt.rvalue.fullname == 'builtins.None': + if (not is_optional_type(attr_type) and not is_object_rprimitive(attr_type) + and not is_none_rprimitive(attr_type)): + continue + val = builder.coerce(builder.accept(stmt.rvalue), attr_type, stmt.line) + builder.add(SetAttr(self_var, lvalue.name, val, -1)) - builder.leave_method() + builder.add(Return(builder.true())) def check_deletable_declaration(builder: IRBuilder, cl: ClassIR, line: int) -> None: @@ -429,30 +609,28 @@ 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. """ - 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() - 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)) - - builder.activate_block(not_implemented_block) - builder.add(Return(not_implemented)) + 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() + 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)) - builder.leave_method() + builder.activate_block(not_implemented_block) + builder.add(Return(not_implemented)) def load_non_ext_class(builder: IRBuilder, @@ -461,7 +639,7 @@ def load_non_ext_class(builder: IRBuilder, line: int) -> Value: cls_name = builder.load_str(ir.name) - finish_non_ext_dict(builder, non_ext, line) + add_dunders_to_non_ext_dict(builder, non_ext, line) class_type_obj = builder.py_call( non_ext.metaclass, @@ -508,11 +686,11 @@ def create_mypyc_attrs_tuple(builder: IRBuilder, ir: ClassIR, line: int) -> Valu return builder.new_tuple(items, line) -def finish_non_ext_dict(builder: IRBuilder, non_ext: NonExtClassInfo, line: int) -> None: - # Add __annotations__ to the class dict. - builder.call_c(dict_set_item_op, - [non_ext.dict, builder.load_str('__annotations__'), - non_ext.anns], -1) +def add_dunders_to_non_ext_dict(builder: IRBuilder, non_ext: NonExtClassInfo, + line: int, add_annotations: bool = True) -> None: + if add_annotations: + # Add __annotations__ to the class dict. + builder.add_to_non_ext_dict(non_ext, '__annotations__', non_ext.anns, line) # We add a __doc__ attribute so if the non-extension class is decorated with the # dataclass decorator, dataclass will not try to look for __text_signature__. @@ -522,46 +700,3 @@ def finish_non_ext_dict(builder: IRBuilder, non_ext: NonExtClassInfo, line: int) non_ext, '__doc__', builder.load_str(filler_doc_str), line) builder.add_to_non_ext_dict( non_ext, '__module__', builder.load_str(builder.module_name), line) - - -def dataclass_finalize( - builder: IRBuilder, cdef: ClassDef, non_ext: NonExtClassInfo, type_obj: Value) -> None: - """Generate code to finish instantiating a dataclass. - - This works by replacing all of the attributes on the class - (which will be descriptors) with whatever they would be in a - non-extension class, calling dataclass, then switching them back. - - The resulting class is an extension class and instances of it do not - have a __dict__ (unless something else requires it). - All methods written explicitly in the source are compiled and - may be called through the vtable while the methods generated - by dataclasses are interpreted and may not be. - - (If we just called dataclass without doing this, it would think that all - of the descriptors for our attributes are default values and generate an - incorrect constructor. We need to do the switch so that dataclass gets the - appropriate defaults.) - """ - finish_non_ext_dict(builder, non_ext, cdef.line) - dec = builder.accept(next(d for d in cdef.decorators if is_dataclass_decorator(d))) - builder.call_c( - dataclass_sleight_of_hand, [dec, type_obj, non_ext.dict, non_ext.anns], cdef.line) - - -def dataclass_non_ext_info(builder: IRBuilder, cdef: ClassDef) -> Optional[NonExtClassInfo]: - """Set up a NonExtClassInfo to track dataclass attributes. - - In addition to setting up a normal extension class for dataclasses, - we also collect its class attributes like a non-extension class so - that we can hand them to the dataclass decorator. - """ - if is_dataclass(cdef): - return NonExtClassInfo( - builder.call_c(dict_new_op, [], cdef.line), - builder.add(TupleSet([], cdef.line)), - builder.call_c(dict_new_op, [], cdef.line), - builder.add(LoadAddress(type_object_op.type, type_object_op.src, cdef.line)) - ) - else: - return None diff --git a/mypyc/irbuild/constant_fold.py b/mypyc/irbuild/constant_fold.py new file mode 100644 index 000000000000..21e9ea939a3e --- /dev/null +++ b/mypyc/irbuild/constant_fold.py @@ -0,0 +1,99 @@ +"""Constant folding of IR values. + +For example, 3 + 5 can be constant folded into 8. +""" + +from typing import Optional, Union +from typing_extensions import Final + +from mypy.nodes import Expression, IntExpr, StrExpr, OpExpr, UnaryExpr, NameExpr, MemberExpr, Var +from mypyc.irbuild.builder import IRBuilder + + +# All possible result types of constant folding +ConstantValue = Union[int, str] +CONST_TYPES: Final = (int, str) + + +def constant_fold_expr(builder: IRBuilder, expr: Expression) -> Optional[ConstantValue]: + """Return the constant value of an expression for supported operations. + + Return None otherwise. + """ + if isinstance(expr, IntExpr): + return expr.value + if isinstance(expr, StrExpr): + return expr.value + elif isinstance(expr, NameExpr): + node = expr.node + if isinstance(node, Var) and node.is_final: + value = node.final_value + if isinstance(value, (CONST_TYPES)): + return value + elif isinstance(expr, MemberExpr): + final = builder.get_final_ref(expr) + if final is not None: + fn, final_var, native = final + if final_var.is_final: + value = final_var.final_value + if isinstance(value, (CONST_TYPES)): + return value + elif isinstance(expr, OpExpr): + left = constant_fold_expr(builder, expr.left) + right = constant_fold_expr(builder, expr.right) + if isinstance(left, int) and isinstance(right, int): + return constant_fold_binary_int_op(expr.op, left, right) + elif isinstance(left, str) and isinstance(right, str): + return constant_fold_binary_str_op(expr.op, left, right) + elif isinstance(expr, UnaryExpr): + value = constant_fold_expr(builder, expr.expr) + if isinstance(value, int): + return constant_fold_unary_int_op(expr.op, value) + return None + + +def constant_fold_binary_int_op(op: str, left: int, right: int) -> Optional[int]: + if op == '+': + return left + right + if op == '-': + return left - right + elif op == '*': + return left * right + elif op == '//': + if right != 0: + return left // right + elif op == '%': + if right != 0: + return left % right + elif op == '&': + return left & right + elif op == '|': + return left | right + elif op == '^': + return left ^ right + elif op == '<<': + if right >= 0: + return left << right + elif op == '>>': + if right >= 0: + return left >> right + elif op == '**': + if right >= 0: + return left ** right + return None + + +def constant_fold_unary_int_op(op: str, value: int) -> Optional[int]: + if op == '-': + return -value + elif op == '~': + return ~value + elif op == '+': + return value + return None + + +def constant_fold_binary_str_op(op: str, left: str, right: str) -> Optional[str]: + if op == '+': + return left + right + return None diff --git a/mypyc/irbuild/expression.py b/mypyc/irbuild/expression.py index 225c12eeea9b..6a42820b9b21 100644 --- a/mypyc/irbuild/expression.py +++ b/mypyc/irbuild/expression.py @@ -38,12 +38,13 @@ from mypyc.primitives.set_ops import set_add_op, set_update_op from mypyc.primitives.str_ops import str_slice_op from mypyc.primitives.int_ops import int_comparison_op_mapping -from mypyc.irbuild.specialize import specializers +from mypyc.irbuild.specialize import apply_function_specialization, apply_method_specialization from mypyc.irbuild.builder import IRBuilder from mypyc.irbuild.for_helpers import ( translate_list_comprehension, translate_set_comprehension, comprehension_helper ) +from mypyc.irbuild.constant_fold import constant_fold_expr # Name and attribute references @@ -208,7 +209,8 @@ def transform_call_expr(builder: IRBuilder, expr: CallExpr) -> Value: callee = callee.analyzed.expr # Unwrap type application if isinstance(callee, MemberExpr): - return translate_method_call(builder, expr, callee) + return apply_method_specialization(builder, expr, callee) or \ + translate_method_call(builder, expr, callee) elif isinstance(callee, SuperExpr): return translate_super_method_call(builder, expr, callee) else: @@ -218,7 +220,8 @@ def transform_call_expr(builder: IRBuilder, expr: CallExpr) -> Value: def translate_call(builder: IRBuilder, expr: CallExpr, callee: Expression) -> Value: # The common case of calls is refexprs if isinstance(callee, RefExpr): - return translate_refexpr_call(builder, expr, callee) + return apply_function_specialization(builder, expr, callee) or \ + translate_refexpr_call(builder, expr, callee) function = builder.accept(callee) args = [builder.accept(arg) for arg in expr.args] @@ -228,18 +231,6 @@ def translate_call(builder: IRBuilder, expr: CallExpr, callee: Expression) -> Va def translate_refexpr_call(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Value: """Translate a non-method call.""" - - # TODO: Allow special cases to have default args or named args. Currently they don't since - # they check that everything in arg_kinds is ARG_POS. - - # If there is a specializer for this function, try calling it. - # We would return the first successful one. - if callee.fullname and (callee.fullname, None) in specializers: - for specializer in specializers[callee.fullname, None]: - val = specializer(builder, expr, callee) - if val is not None: - return val - # Gen the argument values arg_values = [builder.accept(arg) for arg in expr.args] @@ -296,11 +287,9 @@ def translate_method_call(builder: IRBuilder, expr: CallExpr, callee: MemberExpr # If there is a specializer for this method name/type, try calling it. # We would return the first successful one. - if (callee.name, receiver_typ) in specializers: - for specializer in specializers[callee.name, receiver_typ]: - val = specializer(builder, expr, callee) - if val is not None: - return val + val = apply_method_specialization(builder, expr, callee, receiver_typ) + if val is not None: + return val obj = builder.accept(callee.expr) args = [builder.accept(arg) for arg in expr.args] @@ -378,6 +367,10 @@ def translate_cast_expr(builder: IRBuilder, expr: CastExpr) -> Value: def transform_unary_expr(builder: IRBuilder, expr: UnaryExpr) -> Value: + folded = try_constant_fold(builder, expr) + if folded: + return folded + return builder.unary_op(builder.accept(expr.expr), expr.op, expr.line) @@ -391,6 +384,10 @@ def transform_op_expr(builder: IRBuilder, expr: OpExpr) -> Value: if ret is not None: return ret + folded = try_constant_fold(builder, expr) + if folded: + return folded + return builder.binary_op( builder.accept(expr.left), builder.accept(expr.right), expr.op, expr.line ) @@ -413,6 +410,19 @@ def transform_index_expr(builder: IRBuilder, expr: IndexExpr) -> Value: base, '__getitem__', [index_reg], builder.node_type(expr), expr.line) +def try_constant_fold(builder: IRBuilder, expr: Expression) -> Optional[Value]: + """Return the constant value of an expression if possible. + + Return None otherwise. + """ + value = constant_fold_expr(builder, expr) + if isinstance(value, int): + return builder.load_int(value) + elif isinstance(value, str): + return builder.load_str(value) + return None + + def try_gen_slice_op(builder: IRBuilder, base: Value, index: SliceExpr) -> Optional[Value]: """Generate specialized slice op for some index expressions. diff --git a/mypyc/irbuild/format_str_tokenizer.py b/mypyc/irbuild/format_str_tokenizer.py index ad06e2ac23ce..721f28dbe385 100644 --- a/mypyc/irbuild/format_str_tokenizer.py +++ b/mypyc/irbuild/format_str_tokenizer.py @@ -2,7 +2,7 @@ from typing import List, Tuple, Optional from typing_extensions import Final -from enum import Enum +from enum import Enum, unique from mypy.checkstrformat import ( parse_format_value, ConversionSpecifier, parse_conversion_specifiers @@ -22,6 +22,7 @@ from mypyc.primitives.str_ops import str_build_op, str_op +@unique class FormatOp(Enum): """FormatOp represents conversion operations of string formatting during compile time. diff --git a/mypyc/irbuild/function.py b/mypyc/irbuild/function.py index a28218d37d05..5b567251111a 100644 --- a/mypyc/irbuild/function.py +++ b/mypyc/irbuild/function.py @@ -117,16 +117,6 @@ def transform_decorator(builder: IRBuilder, dec: Decorator) -> None: builder.functions.append(func_ir) -def transform_method(builder: IRBuilder, - cdef: ClassDef, - non_ext: Optional[NonExtClassInfo], - fdef: FuncDef) -> None: - if non_ext: - handle_non_ext_method(builder, non_ext, cdef, fdef) - else: - handle_ext_method(builder, cdef, fdef) - - def transform_lambda_expr(builder: IRBuilder, expr: LambdaExpr) -> Value: typ = get_proper_type(builder.types[expr]) assert isinstance(typ, CallableType) @@ -978,26 +968,24 @@ def generate_singledispatch_callable_class_ctor(builder: IRBuilder) -> None: """Create an __init__ that sets registry and dispatch_cache to empty dicts""" line = -1 class_ir = builder.fn_info.callable_class.ir - builder.enter_method(class_ir, '__init__', bool_rprimitive) - empty_dict = builder.call_c(dict_new_op, [], line) - builder.add(SetAttr(builder.self(), 'registry', empty_dict, line)) - 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) - # 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)) - builder.leave_method() + with builder.enter_method(class_ir, '__init__', bool_rprimitive): + empty_dict = builder.call_c(dict_new_op, [], line) + builder.add(SetAttr(builder.self(), 'registry', empty_dict, line)) + 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) + # 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)) def add_register_method_to_callable_class(builder: IRBuilder, fn_info: FuncInfo) -> None: line = -1 - builder.enter_method(fn_info.callable_class.ir, 'register', object_rprimitive) - cls_arg = builder.add_argument('cls', object_rprimitive) - func_arg = builder.add_argument('func', object_rprimitive, ArgKind.ARG_OPT) - ret_val = builder.call_c(register_function, [builder.self(), cls_arg, func_arg], line) - builder.add(Return(ret_val, line)) - builder.leave_method() + with builder.enter_method(fn_info.callable_class.ir, 'register', object_rprimitive): + cls_arg = builder.add_argument('cls', object_rprimitive) + func_arg = builder.add_argument('func', object_rprimitive, ArgKind.ARG_OPT) + ret_val = builder.call_c(register_function, [builder.self(), cls_arg, func_arg], line) + builder.add(Return(ret_val, line)) def load_singledispatch_registry(builder: IRBuilder, dispatch_func_obj: Value, line: int) -> Value: diff --git a/mypyc/irbuild/generator.py b/mypyc/irbuild/generator.py index b3490551a5b6..39d30cf74eeb 100644 --- a/mypyc/irbuild/generator.py +++ b/mypyc/irbuild/generator.py @@ -157,9 +157,8 @@ def add_helper_to_generator_class(builder: IRBuilder, def add_iter_to_generator_class(builder: IRBuilder, fn_info: FuncInfo) -> None: """Generates the '__iter__' method for a generator class.""" - builder.enter_method(fn_info.generator_class.ir, '__iter__', object_rprimitive, fn_info) - builder.add(Return(builder.self())) - builder.leave_method() + with builder.enter_method(fn_info.generator_class.ir, '__iter__', object_rprimitive, fn_info): + builder.add(Return(builder.self())) def add_next_to_generator_class(builder: IRBuilder, @@ -167,14 +166,14 @@ def add_next_to_generator_class(builder: IRBuilder, fn_decl: FuncDecl, sig: FuncSignature) -> None: """Generates the '__next__' method for a generator class.""" - builder.enter_method(fn_info.generator_class.ir, '__next__', object_rprimitive, fn_info) - none_reg = builder.none_object() - # Call the helper function with error flags set to Py_None, and return that result. - result = builder.add(Call(fn_decl, - [builder.self(), none_reg, none_reg, none_reg, none_reg], - fn_info.fitem.line)) - builder.add(Return(result)) - builder.leave_method() + with builder.enter_method(fn_info.generator_class.ir, '__next__', + object_rprimitive, fn_info): + none_reg = builder.none_object() + # Call the helper function with error flags set to Py_None, and return that result. + result = builder.add(Call(fn_decl, + [builder.self(), none_reg, none_reg, none_reg, none_reg], + fn_info.fitem.line)) + builder.add(Return(result)) def add_send_to_generator_class(builder: IRBuilder, @@ -182,15 +181,15 @@ def add_send_to_generator_class(builder: IRBuilder, fn_decl: FuncDecl, sig: FuncSignature) -> None: """Generates the 'send' method for a generator class.""" - builder.enter_method(fn_info.generator_class.ir, 'send', object_rprimitive, fn_info) - arg = builder.add_argument('arg', object_rprimitive) - none_reg = builder.none_object() - # Call the helper function with error flags set to Py_None, and return that result. - result = builder.add(Call(fn_decl, - [builder.self(), none_reg, none_reg, none_reg, builder.read(arg)], - fn_info.fitem.line)) - builder.add(Return(result)) - builder.leave_method() + with builder.enter_method(fn_info.generator_class.ir, 'send', object_rprimitive, fn_info): + arg = builder.add_argument('arg', object_rprimitive) + none_reg = builder.none_object() + # Call the helper function with error flags set to Py_None, and return that result. + result = builder.add(Call( + fn_decl, + [builder.self(), none_reg, none_reg, none_reg, builder.read(arg)], + fn_info.fitem.line)) + builder.add(Return(result)) def add_throw_to_generator_class(builder: IRBuilder, @@ -198,47 +197,42 @@ def add_throw_to_generator_class(builder: IRBuilder, fn_decl: FuncDecl, sig: FuncSignature) -> None: """Generates the 'throw' method for a generator class.""" - builder.enter_method(fn_info.generator_class.ir, 'throw', object_rprimitive, fn_info) - typ = builder.add_argument('type', object_rprimitive) - val = builder.add_argument('value', object_rprimitive, ARG_OPT) - tb = builder.add_argument('traceback', object_rprimitive, ARG_OPT) - - # Because the value and traceback arguments are optional and hence - # can be NULL if not passed in, we have to assign them Py_None if - # they are not passed in. - none_reg = builder.none_object() - builder.assign_if_null(val, lambda: none_reg, builder.fn_info.fitem.line) - builder.assign_if_null(tb, lambda: none_reg, builder.fn_info.fitem.line) - - # Call the helper function using the arguments passed in, and return that result. - result = builder.add( - Call( + with builder.enter_method(fn_info.generator_class.ir, 'throw', + object_rprimitive, fn_info): + typ = builder.add_argument('type', object_rprimitive) + val = builder.add_argument('value', object_rprimitive, ARG_OPT) + tb = builder.add_argument('traceback', object_rprimitive, ARG_OPT) + + # Because the value and traceback arguments are optional and hence + # can be NULL if not passed in, we have to assign them Py_None if + # they are not passed in. + none_reg = builder.none_object() + builder.assign_if_null(val, lambda: none_reg, builder.fn_info.fitem.line) + builder.assign_if_null(tb, lambda: none_reg, builder.fn_info.fitem.line) + + # Call the helper function using the arguments passed in, and return that result. + result = builder.add(Call( fn_decl, [builder.self(), builder.read(typ), builder.read(val), builder.read(tb), none_reg], - fn_info.fitem.line - ) - ) - builder.add(Return(result)) - builder.leave_method() + fn_info.fitem.line)) + builder.add(Return(result)) def add_close_to_generator_class(builder: IRBuilder, fn_info: FuncInfo) -> None: """Generates the '__close__' method for a generator class.""" # TODO: Currently this method just triggers a runtime error. # We should fill this out (https://github.com/mypyc/mypyc/issues/790). - builder.enter_method(fn_info.generator_class.ir, 'close', object_rprimitive, fn_info) - builder.add(RaiseStandardError(RaiseStandardError.RUNTIME_ERROR, - 'close method on generator classes unimplemented', - fn_info.fitem.line)) - builder.add(Unreachable()) - builder.leave_method() + with builder.enter_method(fn_info.generator_class.ir, 'close', object_rprimitive, fn_info): + builder.add(RaiseStandardError(RaiseStandardError.RUNTIME_ERROR, + 'close method on generator classes unimplemented', + fn_info.fitem.line)) + builder.add(Unreachable()) def add_await_to_generator_class(builder: IRBuilder, fn_info: FuncInfo) -> None: """Generates the '__await__' method for a generator class.""" - builder.enter_method(fn_info.generator_class.ir, '__await__', object_rprimitive, fn_info) - builder.add(Return(builder.self())) - builder.leave_method() + with builder.enter_method(fn_info.generator_class.ir, '__await__', object_rprimitive, fn_info): + builder.add(Return(builder.self())) def setup_env_for_generator_class(builder: IRBuilder) -> None: diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index b6cf990d025d..27419fcc7385 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -39,11 +39,11 @@ from mypyc.ir.func_ir import FuncDecl, FuncSignature from mypyc.ir.class_ir import ClassIR, all_concrete_classes from mypyc.common import ( - FAST_ISINSTANCE_MAX_SUBCLASSES, MAX_LITERAL_SHORT_INT, PLATFORM_SIZE, use_vectorcall, - use_method_vectorcall + FAST_ISINSTANCE_MAX_SUBCLASSES, MAX_LITERAL_SHORT_INT, MIN_LITERAL_SHORT_INT, PLATFORM_SIZE, + use_vectorcall, use_method_vectorcall ) from mypyc.primitives.registry import ( - method_call_ops, CFunctionDescription, function_ops, + method_call_ops, CFunctionDescription, binary_ops, unary_ops, ERR_NEG_INT ) from mypyc.primitives.bytes_ops import bytes_compare @@ -789,7 +789,7 @@ def none_object(self) -> Value: def load_int(self, value: int) -> Value: """Load a tagged (Python) integer literal value.""" - if abs(value) > MAX_LITERAL_SHORT_INT: + if value > MAX_LITERAL_SHORT_INT or value < MIN_LITERAL_SHORT_INT: return self.add(LoadLiteral(value, int_rprimitive)) else: return Integer(value) @@ -1186,15 +1186,6 @@ def new_list_op(self, values: List[Value], line: int) -> Value: def new_set_op(self, values: List[Value], line: int) -> Value: return self.call_c(new_set_op, values, line) - def builtin_call(self, - args: List[Value], - fn_op: str, - line: int) -> Value: - call_c_ops_candidates = function_ops.get(fn_op, []) - target = self.matching_call_c(call_c_ops_candidates, args, line) - assert target, 'Unsupported builtin function: %s' % fn_op - return target - def shortcircuit_helper(self, op: str, expr_type: RType, left: Callable[[], Value], diff --git a/mypyc/irbuild/prepare.py b/mypyc/irbuild/prepare.py index a42db7eecc6c..3f028d900943 100644 --- a/mypyc/irbuild/prepare.py +++ b/mypyc/irbuild/prepare.py @@ -14,9 +14,9 @@ from typing import List, Dict, Iterable, Optional, Union, DefaultDict, NamedTuple, Tuple from mypy.nodes import ( - MypyFile, TypeInfo, FuncDef, ClassDef, Decorator, OverloadedFuncDef, MemberExpr, Var, - Expression, SymbolNode, ARG_STAR, ARG_STAR2, CallExpr, Decorator, Expression, FuncDef, - MemberExpr, MypyFile, NameExpr, RefExpr, TypeInfo, + ClassDef, OverloadedFuncDef, Var, + SymbolNode, ARG_STAR, ARG_STAR2, CallExpr, Decorator, Expression, FuncDef, + MemberExpr, MypyFile, NameExpr, RefExpr, TypeInfo ) from mypy.types import Type, Instance, get_proper_type from mypy.build import Graph diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 41d1293d0666..d35039ecc0bc 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -16,7 +16,7 @@ from mypy.nodes import ( CallExpr, RefExpr, MemberExpr, NameExpr, TupleExpr, GeneratorExpr, - ListExpr, DictExpr, StrExpr, ARG_POS, Expression + ListExpr, DictExpr, StrExpr, IntExpr, ARG_POS, ARG_NAMED, Expression ) from mypy.types import AnyType, TypeOfAny @@ -57,6 +57,34 @@ specializers: Dict[Tuple[str, Optional[RType]], List[Specializer]] = {} +def _apply_specialization(builder: 'IRBuilder', expr: CallExpr, callee: RefExpr, + name: Optional[str], typ: Optional[RType] = None) -> Optional[Value]: + # TODO: Allow special cases to have default args or named args. Currently they don't since + # they check that everything in arg_kinds is ARG_POS. + + # If there is a specializer for this function, try calling it. + # Return the first successful one. + if name and (name, typ) in specializers: + for specializer in specializers[name, typ]: + val = specializer(builder, expr, callee) + if val is not None: + return val + return None + + +def apply_function_specialization(builder: 'IRBuilder', expr: CallExpr, + callee: RefExpr) -> Optional[Value]: + """Invoke the Specializer callback for a function if one has been registered""" + return _apply_specialization(builder, expr, callee, callee.fullname) + + +def apply_method_specialization(builder: 'IRBuilder', expr: CallExpr, callee: MemberExpr, + typ: Optional[RType] = None) -> Optional[Value]: + """Invoke the Specializer callback for a method if one has been registered""" + name = callee.fullname if typ is None else callee.name + return _apply_specialization(builder, expr, callee, name, typ) + + def specialize_function( name: str, typ: Optional[RType] = None) -> Callable[[Specializer], Specializer]: """Decorator to register a function as being a specializer. @@ -185,10 +213,37 @@ def translate_set_from_generator_call( return None +@specialize_function('builtins.min') +@specialize_function('builtins.max') +def faster_min_max(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Optional[Value]: + if expr.arg_kinds == [ARG_POS, ARG_POS]: + x, y = builder.accept(expr.args[0]), builder.accept(expr.args[1]) + result = Register(builder.node_type(expr)) + # CPython evaluates arguments reversely when calling min(...) or max(...) + if callee.fullname == 'builtins.min': + comparison = builder.binary_op(y, x, '<', expr.line) + else: + comparison = builder.binary_op(y, x, '>', expr.line) + + true_block, false_block, next_block = BasicBlock(), BasicBlock(), BasicBlock() + builder.add_bool_branch(comparison, true_block, false_block) + + builder.activate_block(true_block) + builder.assign(result, builder.coerce(y, result.type, expr.line), expr.line) + builder.goto(next_block) + + builder.activate_block(false_block) + builder.assign(result, builder.coerce(x, result.type, expr.line), expr.line) + builder.goto(next_block) + + builder.activate_block(next_block) + return result + return None + + @specialize_function('builtins.tuple') @specialize_function('builtins.frozenset') @specialize_function('builtins.dict') -@specialize_function('builtins.sum') @specialize_function('builtins.min') @specialize_function('builtins.max') @specialize_function('builtins.sorted') @@ -266,11 +321,48 @@ def gen_inner_stmts() -> None: return retval +@specialize_function('builtins.sum') +def translate_sum_call(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Optional[Value]: + # specialized implementation is used if: + # - only one or two arguments given (if not, sum() has been given invalid arguments) + # - first argument is a Generator (there is no benefit to optimizing the performance of eg. + # sum([1, 2, 3]), so non-Generator Iterables are not handled) + if not (len(expr.args) in (1, 2) + and expr.arg_kinds[0] == ARG_POS + and isinstance(expr.args[0], GeneratorExpr)): + return None + + # handle 'start' argument, if given + if len(expr.args) == 2: + # ensure call to sum() was properly constructed + if not expr.arg_kinds[1] in (ARG_POS, ARG_NAMED): + return None + start_expr = expr.args[1] + else: + start_expr = IntExpr(0) + + gen_expr = expr.args[0] + target_type = builder.node_type(expr) + retval = Register(target_type) + builder.assign(retval, builder.coerce(builder.accept(start_expr), target_type, -1), -1) + + def gen_inner_stmts() -> None: + call_expr = builder.accept(gen_expr.left_expr) + builder.assign(retval, builder.binary_op(retval, call_expr, '+', -1), -1) + + loop_params = list(zip(gen_expr.indices, gen_expr.sequences, gen_expr.condlists)) + comprehension_helper(builder, loop_params, gen_inner_stmts, gen_expr.line) + + return retval + + @specialize_function('dataclasses.field') +@specialize_function('attr.ib') +@specialize_function('attr.attrib') @specialize_function('attr.Factory') def translate_dataclasses_field_call( builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Optional[Value]: - """Special case for 'dataclasses.field' and 'attr.Factory' + """Special case for 'dataclasses.field', 'attr.attrib', and 'attr.Factory' function calls because the results of such calls are type-checked by mypy using the types of the arguments to their respective functions, resulting in attempted coercions by mypyc that throw a @@ -295,12 +387,8 @@ def translate_next_call(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> return None gen = expr.args[0] - retval = Register(builder.node_type(expr)) - default_val = None - if len(expr.args) > 1: - default_val = builder.accept(expr.args[1]) - + default_val = builder.accept(expr.args[1]) if len(expr.args) > 1 else None exit_block = BasicBlock() def gen_inner_stmts() -> None: diff --git a/mypyc/irbuild/util.py b/mypyc/irbuild/util.py index cceef36a9feb..7a7b95245d4c 100644 --- a/mypyc/irbuild/util.py +++ b/mypyc/irbuild/util.py @@ -4,11 +4,18 @@ from mypy.nodes import ( ClassDef, FuncDef, Decorator, OverloadedFuncDef, StrExpr, CallExpr, RefExpr, Expression, - IntExpr, FloatExpr, Var, TupleExpr, UnaryExpr, BytesExpr, + IntExpr, FloatExpr, Var, NameExpr, TupleExpr, UnaryExpr, BytesExpr, ArgKind, ARG_NAMED, ARG_NAMED_OPT, ARG_POS, ARG_OPT, GDEF, ) +DATACLASS_DECORATORS = { + 'dataclasses.dataclass', + 'attr.s', + 'attr.attrs', +} + + def is_trait_decorator(d: Expression) -> bool: return isinstance(d, RefExpr) and d.fullname == 'mypy_extensions.trait' @@ -17,21 +24,40 @@ def is_trait(cdef: ClassDef) -> bool: return any(is_trait_decorator(d) for d in cdef.decorators) or cdef.info.is_protocol -def is_dataclass_decorator(d: Expression) -> bool: - return ( - (isinstance(d, RefExpr) and d.fullname == 'dataclasses.dataclass') - or ( - isinstance(d, CallExpr) +def dataclass_decorator_type(d: Expression) -> Optional[str]: + if isinstance(d, RefExpr) and d.fullname in DATACLASS_DECORATORS: + return d.fullname.split('.')[0] + elif (isinstance(d, CallExpr) and isinstance(d.callee, RefExpr) - and d.callee.fullname == 'dataclasses.dataclass' - ) - ) + and d.callee.fullname in DATACLASS_DECORATORS): + name = d.callee.fullname.split('.')[0] + if name == 'attr' and 'auto_attribs' in d.arg_names: + # Note: the mypy attrs plugin checks that the value of auto_attribs is + # not computed at runtime, so we don't need to perform that check here + auto = d.args[d.arg_names.index('auto_attribs')] + if isinstance(auto, NameExpr) and auto.name == 'True': + return 'attr-auto' + return name + else: + return None + + +def is_dataclass_decorator(d: Expression) -> bool: + return dataclass_decorator_type(d) is not None def is_dataclass(cdef: ClassDef) -> bool: return any(is_dataclass_decorator(d) for d in cdef.decorators) +def dataclass_type(cdef: ClassDef) -> Optional[str]: + for d in cdef.decorators: + typ = dataclass_decorator_type(d) + if typ is not None: + return typ + return None + + def get_mypyc_attr_literal(e: Expression) -> Any: """Convert an expression from a mypyc_attr decorator to a value. diff --git a/mypyc/lib-rt/CPy.h b/mypyc/lib-rt/CPy.h index 8aa7247bd66f..987819154abf 100644 --- a/mypyc/lib-rt/CPy.h +++ b/mypyc/lib-rt/CPy.h @@ -158,6 +158,24 @@ static inline int CPyTagged_CheckShort(CPyTagged x) { return !CPyTagged_CheckLong(x); } +static inline void CPyTagged_INCREF(CPyTagged x) { + if (unlikely(CPyTagged_CheckLong(x))) { + CPyTagged_IncRef(x); + } +} + +static inline void CPyTagged_DECREF(CPyTagged x) { + if (unlikely(CPyTagged_CheckLong(x))) { + CPyTagged_DecRef(x); + } +} + +static inline void CPyTagged_XDECREF(CPyTagged x) { + if (unlikely(CPyTagged_CheckLong(x))) { + CPyTagged_XDecRef(x); + } +} + static inline Py_ssize_t CPyTagged_ShortAsSsize_t(CPyTagged x) { // NOTE: Assume that we sign extend. return (Py_ssize_t)x >> 1; @@ -253,11 +271,10 @@ static inline bool CPyTagged_IsLe(CPyTagged left, CPyTagged right) { // Generic operations (that work with arbitrary types) -/* We use intentionally non-inlined decrefs since it pretty - * substantially speeds up compile time while only causing a ~1% - * performance degradation. We have our own copies both to avoid the - * null check in Py_DecRef and to avoid making an indirect PIC - * call. */ +/* We use intentionally non-inlined decrefs in rarely executed code + * paths since it pretty substantially speeds up compile time. We have + * our own copies both to avoid the null check in Py_DecRef and to avoid + * making an indirect PIC call. */ CPy_NOINLINE static void CPy_DecRef(PyObject *p) { CPy_DECREF(p); diff --git a/mypyc/lib-rt/int_ops.c b/mypyc/lib-rt/int_ops.c index 0ac9b6fe490b..1275f2c10577 100644 --- a/mypyc/lib-rt/int_ops.c +++ b/mypyc/lib-rt/int_ops.c @@ -190,16 +190,17 @@ CPyTagged CPyTagged_Multiply(CPyTagged left, CPyTagged right) { } CPyTagged CPyTagged_FloorDivide(CPyTagged left, CPyTagged right) { - if (CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right) + if (CPyTagged_CheckShort(left) + && CPyTagged_CheckShort(right) && !CPyTagged_MaybeFloorDivideFault(left, right)) { - Py_ssize_t result = ((Py_ssize_t)left / CPyTagged_ShortAsSsize_t(right)) & ~1; + Py_ssize_t result = CPyTagged_ShortAsSsize_t(left) / CPyTagged_ShortAsSsize_t(right); if (((Py_ssize_t)left < 0) != (((Py_ssize_t)right) < 0)) { - if (result / 2 * right != left) { + if (result * right != left) { // Round down - result -= 2; + result--; } } - return result; + return result << 1; } PyObject *left_obj = CPyTagged_AsObject(left); PyObject *right_obj = CPyTagged_AsObject(right); diff --git a/mypyc/lib-rt/misc_ops.c b/mypyc/lib-rt/misc_ops.c index 0701ca9d71a8..6b5685ab1f1a 100644 --- a/mypyc/lib-rt/misc_ops.c +++ b/mypyc/lib-rt/misc_ops.c @@ -3,6 +3,7 @@ // These are registered in mypyc.primitives.misc_ops. #include +#include "pythoncapi_compat.h" #include "CPy.h" PyObject *CPy_GetCoro(PyObject *obj) @@ -148,7 +149,7 @@ PyObject *CPyType_FromTemplate(PyObject *template, // to being type. (This allows us to avoid needing to initialize // it explicitly on windows.) if (!Py_TYPE(template_)) { - Py_TYPE(template_) = &PyType_Type; + Py_SET_TYPE(template_, &PyType_Type); } PyTypeObject *metaclass = Py_TYPE(template_); @@ -249,7 +250,7 @@ PyObject *CPyType_FromTemplate(PyObject *template, // the mro. It was needed for mypy.stats. I need to investigate // what is actually going on here. Py_INCREF(metaclass); - Py_TYPE(t) = metaclass; + Py_SET_TYPE(t, metaclass); if (dummy_class) { if (PyDict_Merge(t->ht_type.tp_dict, dummy_class->tp_dict, 0) != 0) @@ -512,7 +513,7 @@ int CPySequence_CheckUnpackCount(PyObject *sequence, Py_ssize_t expected) { // Parse an integer (size_t) encoded as a variable-length binary sequence. static const char *parse_int(const char *s, size_t *len) { - ssize_t n = 0; + Py_ssize_t n = 0; while ((unsigned char)*s >= 0x80) { n = (n << 7) + (*s & 0x7f); s++; diff --git a/mypyc/lib-rt/pythoncapi_compat.h b/mypyc/lib-rt/pythoncapi_compat.h new file mode 100644 index 000000000000..b4011d20a19a --- /dev/null +++ b/mypyc/lib-rt/pythoncapi_compat.h @@ -0,0 +1,393 @@ +// Header file providing new functions of the Python C API to old Python +// versions. +// +// File distributed under the MIT license. +// Copyright Contributors to the pythoncapi_compat project. +// +// Homepage: +// https://github.com/pythoncapi/pythoncapi_compat +// +// Latest version: +// https://raw.githubusercontent.com/pythoncapi/pythoncapi_compat/master/pythoncapi_compat.h +// +// SPDX-License-Identifier: MIT + +#ifndef PYTHONCAPI_COMPAT +#define PYTHONCAPI_COMPAT + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "frameobject.h" // PyFrameObject, PyFrame_GetBack() + + +// Compatibility with Visual Studio 2013 and older which don't support +// the inline keyword in C (only in C++): use __inline instead. +#if (defined(_MSC_VER) && _MSC_VER < 1900 \ + && !defined(__cplusplus) && !defined(inline)) +# define inline __inline +# define PYTHONCAPI_COMPAT_MSC_INLINE + // These two macros are undefined at the end of this file +#endif + + +// Cast argument to PyObject* type. +#ifndef _PyObject_CAST +# define _PyObject_CAST(op) ((PyObject*)(op)) +#endif +#ifndef _PyObject_CAST_CONST +# define _PyObject_CAST_CONST(op) ((const PyObject*)(op)) +#endif + + +// bpo-42262 added Py_NewRef() to Python 3.10.0a3 +#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_NewRef) +static inline PyObject* _Py_NewRef(PyObject *obj) +{ + Py_INCREF(obj); + return obj; +} +#define Py_NewRef(obj) _Py_NewRef(_PyObject_CAST(obj)) +#endif + + +// bpo-42262 added Py_XNewRef() to Python 3.10.0a3 +#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_XNewRef) +static inline PyObject* _Py_XNewRef(PyObject *obj) +{ + Py_XINCREF(obj); + return obj; +} +#define Py_XNewRef(obj) _Py_XNewRef(_PyObject_CAST(obj)) +#endif + + +// See https://bugs.python.org/issue42522 +#if !defined(_Py_StealRef) +static inline PyObject* __Py_StealRef(PyObject *obj) +{ + Py_DECREF(obj); + return obj; +} +#define _Py_StealRef(obj) __Py_StealRef(_PyObject_CAST(obj)) +#endif + + +// See https://bugs.python.org/issue42522 +#if !defined(_Py_XStealRef) +static inline PyObject* __Py_XStealRef(PyObject *obj) +{ + Py_XDECREF(obj); + return obj; +} +#define _Py_XStealRef(obj) __Py_XStealRef(_PyObject_CAST(obj)) +#endif + + +// bpo-39573 added Py_SET_REFCNT() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_REFCNT) +static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) +{ + ob->ob_refcnt = refcnt; +} +#define Py_SET_REFCNT(ob, refcnt) _Py_SET_REFCNT(_PyObject_CAST(ob), refcnt) +#endif + + +// Py_SETREF() and Py_XSETREF() were added to Python 3.5.2. +// It is excluded from the limited C API. +#if (PY_VERSION_HEX < 0x03050200 && !defined(Py_SETREF)) && !defined(Py_LIMITED_API) +#define Py_SETREF(op, op2) \ + do { \ + PyObject *_py_tmp = _PyObject_CAST(op); \ + (op) = (op2); \ + Py_DECREF(_py_tmp); \ + } while (0) + +#define Py_XSETREF(op, op2) \ + do { \ + PyObject *_py_tmp = _PyObject_CAST(op); \ + (op) = (op2); \ + Py_XDECREF(_py_tmp); \ + } while (0) +#endif + + +// bpo-43753 added Py_Is(), Py_IsNone(), Py_IsTrue() and Py_IsFalse() +// to Python 3.10.0b1. +#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_Is) +# define Py_Is(x, y) ((x) == (y)) +#endif +#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_IsNone) +# define Py_IsNone(x) Py_Is(x, Py_None) +#endif +#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_IsTrue) +# define Py_IsTrue(x) Py_Is(x, Py_True) +#endif +#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_IsFalse) +# define Py_IsFalse(x) Py_Is(x, Py_False) +#endif + + +// bpo-39573 added Py_SET_TYPE() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE) +static inline void +_Py_SET_TYPE(PyObject *ob, PyTypeObject *type) +{ + ob->ob_type = type; +} +#define Py_SET_TYPE(ob, type) _Py_SET_TYPE(_PyObject_CAST(ob), type) +#endif + + +// bpo-39573 added Py_SET_SIZE() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE) +static inline void +_Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) +{ + ob->ob_size = size; +} +#define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size) +#endif + + +// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1 +#if PY_VERSION_HEX < 0x030900B1 +static inline PyCodeObject* +PyFrame_GetCode(PyFrameObject *frame) +{ + assert(frame != NULL); + assert(frame->f_code != NULL); + return (PyCodeObject*)Py_NewRef(frame->f_code); +} +#endif + +static inline PyCodeObject* +_PyFrame_GetCodeBorrow(PyFrameObject *frame) +{ + return (PyCodeObject *)_Py_StealRef(PyFrame_GetCode(frame)); +} + + +// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1 +#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION) +static inline PyFrameObject* +PyFrame_GetBack(PyFrameObject *frame) +{ + assert(frame != NULL); + return (PyFrameObject*)Py_XNewRef(frame->f_back); +} +#endif + +#if !defined(PYPY_VERSION) +static inline PyFrameObject* +_PyFrame_GetBackBorrow(PyFrameObject *frame) +{ + return (PyFrameObject *)_Py_XStealRef(PyFrame_GetBack(frame)); +} +#endif + + +// bpo-39947 added PyThreadState_GetInterpreter() to Python 3.9.0a5 +#if PY_VERSION_HEX < 0x030900A5 +static inline PyInterpreterState * +PyThreadState_GetInterpreter(PyThreadState *tstate) +{ + assert(tstate != NULL); + return tstate->interp; +} +#endif + + +// bpo-40429 added PyThreadState_GetFrame() to Python 3.9.0b1 +#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION) +static inline PyFrameObject* +PyThreadState_GetFrame(PyThreadState *tstate) +{ + assert(tstate != NULL); + return (PyFrameObject *)Py_XNewRef(tstate->frame); +} +#endif + +#if !defined(PYPY_VERSION) +static inline PyFrameObject* +_PyThreadState_GetFrameBorrow(PyThreadState *tstate) +{ + return (PyFrameObject *)_Py_XStealRef(PyThreadState_GetFrame(tstate)); +} +#endif + + +// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a5 +#if PY_VERSION_HEX < 0x030900A5 +static inline PyInterpreterState * +PyInterpreterState_Get(void) +{ + PyThreadState *tstate; + PyInterpreterState *interp; + + tstate = PyThreadState_GET(); + if (tstate == NULL) { + Py_FatalError("GIL released (tstate is NULL)"); + } + interp = tstate->interp; + if (interp == NULL) { + Py_FatalError("no current interpreter"); + } + return interp; +} +#endif + + +// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a6 +#if 0x030700A1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION) +static inline uint64_t +PyThreadState_GetID(PyThreadState *tstate) +{ + assert(tstate != NULL); + return tstate->id; +} +#endif + +// bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2 +#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) +static inline void PyThreadState_EnterTracing(PyThreadState *tstate) +{ + tstate->tracing++; +#if PY_VERSION_HEX >= 0x030A00A1 + tstate->cframe->use_tracing = 0; +#else + tstate->use_tracing = 0; +#endif +} +#endif + +// bpo-43760 added PyThreadState_LeaveTracing() to Python 3.11.0a2 +#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) +static inline void PyThreadState_LeaveTracing(PyThreadState *tstate) +{ + tstate->tracing--; + int use_tracing = (tstate->c_tracefunc != NULL + || tstate->c_profilefunc != NULL); +#if PY_VERSION_HEX >= 0x030A00A1 + tstate->cframe->use_tracing = use_tracing; +#else + tstate->use_tracing = use_tracing; +#endif +} +#endif + + +// bpo-37194 added PyObject_CallNoArgs() to Python 3.9.0a1 +#if PY_VERSION_HEX < 0x030900A1 +static inline PyObject* +PyObject_CallNoArgs(PyObject *func) +{ + return PyObject_CallFunctionObjArgs(func, NULL); +} +#endif + + +// bpo-39245 made PyObject_CallOneArg() public (previously called +// _PyObject_CallOneArg) in Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 +static inline PyObject* +PyObject_CallOneArg(PyObject *func, PyObject *arg) +{ + return PyObject_CallFunctionObjArgs(func, arg, NULL); +} +#endif + + +// bpo-1635741 added PyModule_AddObjectRef() to Python 3.10.0a3 +#if PY_VERSION_HEX < 0x030A00A3 +static inline int +PyModule_AddObjectRef(PyObject *module, const char *name, PyObject *value) +{ + int res; + Py_XINCREF(value); + res = PyModule_AddObject(module, name, value); + if (res < 0) { + Py_XDECREF(value); + } + return res; +} +#endif + + +// bpo-40024 added PyModule_AddType() to Python 3.9.0a5 +#if PY_VERSION_HEX < 0x030900A5 +static inline int +PyModule_AddType(PyObject *module, PyTypeObject *type) +{ + const char *name, *dot; + + if (PyType_Ready(type) < 0) { + return -1; + } + + // inline _PyType_Name() + name = type->tp_name; + assert(name != NULL); + dot = strrchr(name, '.'); + if (dot != NULL) { + name = dot + 1; + } + + return PyModule_AddObjectRef(module, name, (PyObject *)type); +} +#endif + + +// bpo-40241 added PyObject_GC_IsTracked() to Python 3.9.0a6. +// bpo-4688 added _PyObject_GC_IS_TRACKED() to Python 2.7.0a2. +#if PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION) +static inline int +PyObject_GC_IsTracked(PyObject* obj) +{ + return (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)); +} +#endif + +// bpo-40241 added PyObject_GC_IsFinalized() to Python 3.9.0a6. +// bpo-18112 added _PyGCHead_FINALIZED() to Python 3.4.0 final. +#if PY_VERSION_HEX < 0x030900A6 && PY_VERSION_HEX >= 0x030400F0 && !defined(PYPY_VERSION) +static inline int +PyObject_GC_IsFinalized(PyObject *obj) +{ + return (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED((PyGC_Head *)(obj)-1)); +} +#endif + + +// bpo-39573 added Py_IS_TYPE() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_IS_TYPE) +static inline int +_Py_IS_TYPE(const PyObject *ob, const PyTypeObject *type) { + return ob->ob_type == type; +} +#define Py_IS_TYPE(ob, type) _Py_IS_TYPE(_PyObject_CAST_CONST(ob), type) +#endif + + +// Py_UNUSED() was added to Python 3.4.0b2. +#if PY_VERSION_HEX < 0x030400B2 && !defined(Py_UNUSED) +# if defined(__GNUC__) || defined(__clang__) +# define Py_UNUSED(name) _unused_ ## name __attribute__((unused)) +# else +# define Py_UNUSED(name) _unused_ ## name +# endif +#endif + + +#ifdef PYTHONCAPI_COMPAT_MSC_INLINE +# undef inline +# undef PYTHONCAPI_COMPAT_MSC_INLINE +#endif + +#ifdef __cplusplus +} +#endif +#endif // PYTHONCAPI_COMPAT diff --git a/mypyc/lib-rt/pythonsupport.h b/mypyc/lib-rt/pythonsupport.h index 45f3e1fd14f6..c4091dada7fd 100644 --- a/mypyc/lib-rt/pythonsupport.h +++ b/mypyc/lib-rt/pythonsupport.h @@ -8,6 +8,7 @@ #include #include +#include "pythoncapi_compat.h" #include #include #include "mypyc_util.h" @@ -220,7 +221,7 @@ list_resize(PyListObject *self, Py_ssize_t newsize) */ if (allocated >= newsize && newsize >= (allocated >> 1)) { assert(self->ob_item != NULL || newsize == 0); - Py_SIZE(self) = newsize; + Py_SET_SIZE(self, newsize); return 0; } @@ -248,7 +249,7 @@ list_resize(PyListObject *self, Py_ssize_t newsize) return -1; } self->ob_item = items; - Py_SIZE(self) = newsize; + Py_SET_SIZE(self, newsize); self->allocated = new_allocated; return 0; } diff --git a/mypyc/test-data/analysis.test b/mypyc/test-data/analysis.test index 48105d5607bd..efd219cc222a 100644 --- a/mypyc/test-data/analysis.test +++ b/mypyc/test-data/analysis.test @@ -536,10 +536,8 @@ def lol(x): r2 :: object r3 :: str r4 :: object - r5 :: bit - r6 :: int - r7 :: bit - r8, r9 :: int + r5, r6 :: bit + r7, r8 :: int L0: L1: r0 = CPyTagged_Id(x) @@ -555,9 +553,8 @@ L3: r5 = CPy_ExceptionMatches(r4) if r5 goto L4 else goto L5 :: bool L4: - r6 = CPyTagged_Negate(2) CPy_RestoreExcInfo(r1) - return r6 + return -2 L5: CPy_Reraise() if not 0 goto L8 else goto L6 :: bool @@ -568,16 +565,16 @@ L7: goto L10 L8: CPy_RestoreExcInfo(r1) - r7 = CPy_KeepPropagating() - if not r7 goto L11 else goto L9 :: bool + r6 = CPy_KeepPropagating() + if not r6 goto L11 else goto L9 :: bool L9: unreachable L10: - r8 = CPyTagged_Add(st, 2) - return r8 + r7 = CPyTagged_Add(st, 2) + return r7 L11: - r9 = :: int - return r9 + r8 = :: int + return r8 (0, 0) {x} {x} (1, 0) {x} {r0} (1, 1) {r0} {st} @@ -589,20 +586,18 @@ L11: (2, 4) {r1, r4} {r1, r4} (3, 0) {r1, r4} {r1, r5} (3, 1) {r1, r5} {r1} -(4, 0) {r1} {r1, r6} -(4, 1) {r1, r6} {r6} -(4, 2) {r6} {} +(4, 0) {r1} {} +(4, 1) {} {} (5, 0) {r1} {r1} (5, 1) {r1} {r1} (6, 0) {} {} (7, 0) {r1, st} {st} (7, 1) {st} {st} (8, 0) {r1} {} -(8, 1) {} {r7} -(8, 2) {r7} {} +(8, 1) {} {r6} +(8, 2) {r6} {} (9, 0) {} {} -(10, 0) {st} {r8} -(10, 1) {r8} {} -(11, 0) {} {r9} -(11, 1) {r9} {} - +(10, 0) {st} {r7} +(10, 1) {r7} {} +(11, 0) {} {r8} +(11, 1) {r8} {} diff --git a/mypyc/test-data/exceptions-freq.test b/mypyc/test-data/exceptions-freq.test new file mode 100644 index 000000000000..26b690a99503 --- /dev/null +++ b/mypyc/test-data/exceptions-freq.test @@ -0,0 +1,124 @@ +-- Test cases for basic block execution frequency analysis. +-- +-- These test cases are using exception transform test machinery for convenience. +-- +-- NOTE: These must all have the _freq suffix + +[case testSimpleError_freq] +from typing import List +def f(x: List[int]) -> int: + return x[0] +[out] +def f(x): + x :: list + r0 :: object + r1, r2 :: int +L0: + r0 = CPyList_GetItemShort(x, 0) + if is_error(r0) goto L3 (error at f:3) else goto L1 +L1: + r1 = unbox(int, r0) + dec_ref r0 + if is_error(r1) goto L3 (error at f:3) else goto L2 +L2: + return r1 +L3: + r2 = :: int + return r2 +hot blocks: [0, 1, 2] + +[case testHotBranch_freq] +from typing import List +def f(x: bool) -> None: + if x: + y = 1 + else: + y = 2 +[out] +def f(x): + x :: bool + y :: int +L0: + if x goto L1 else goto L2 :: bool +L1: + y = 2 + dec_ref y :: int + goto L3 +L2: + y = 4 + dec_ref y :: int +L3: + return 1 +hot blocks: [0, 1, 2, 3] + +[case testGoto_freq] +from typing import List +def f(x: bool) -> int: + if x: + y = 1 + else: + return 2 + return y +[out] +def f(x): + x :: bool + y :: int +L0: + if x goto L1 else goto L2 :: bool +L1: + y = 2 + goto L3 +L2: + return 4 +L3: + return y +hot blocks: [0, 1, 2, 3] + +[case testFalseOnError_freq] +from typing import List +def f(x: List[int]) -> None: + x[0] = 1 +[out] +def f(x): + x :: list + r0 :: object + r1 :: bit + r2 :: None +L0: + r0 = box(short_int, 2) + r1 = CPyList_SetItem(x, 0, r0) + if not r1 goto L2 (error at f:3) else goto L1 :: bool +L1: + return 1 +L2: + r2 = :: None + return r2 +hot blocks: [0, 1] + +[case testRareBranch_freq] +from typing_extensions import Final + +x: Final = str() + +def f() -> str: + return x +[out] +def f(): + r0 :: str + r1 :: bool + r2 :: str +L0: + r0 = __main__.x :: static + if is_error(r0) goto L1 else goto L3 +L1: + r1 = raise NameError('value for final name "x" was not set') + if not r1 goto L4 (error at f:6) else goto L2 :: bool +L2: + unreachable +L3: + inc_ref r0 + return r0 +L4: + r2 = :: str + return r2 +hot blocks: [0, 3] diff --git a/mypyc/test-data/fixtures/ir.py b/mypyc/test-data/fixtures/ir.py index 362495fdaa68..786f77143e9e 100644 --- a/mypyc/test-data/fixtures/ir.py +++ b/mypyc/test-data/fixtures/ir.py @@ -36,6 +36,7 @@ def __sub__(self, n: int) -> int: pass def __mul__(self, n: int) -> int: pass def __pow__(self, n: int, modulo: Optional[int] = None) -> int: pass def __floordiv__(self, x: int) -> int: pass + def __truediv__(self, x: float) -> float: pass def __mod__(self, x: int) -> int: pass def __neg__(self) -> int: pass def __pos__(self) -> int: pass @@ -271,8 +272,13 @@ class NotImplementedError(RuntimeError): pass class StopIteration(Exception): value: Any +class ArithmeticError(Exception): pass + +class ZeroDivisionError(Exception): pass + def any(i: Iterable[T]) -> bool: pass def all(i: Iterable[T]) -> bool: pass +def sum(i: Iterable[T]) -> int: pass def reversed(object: Sequence[T]) -> Iterator[T]: ... def id(o: object) -> int: pass # This type is obviously wrong but the test stubs don't have Sized anymore @@ -286,7 +292,8 @@ def next(i: Iterator[T]) -> T: pass def next(i: Iterator[T], default: T) -> T: pass def hash(o: object) -> int: ... def globals() -> Dict[str, Any]: ... -def setattr(object: Any, name: str, value: Any) -> None: ... +def getattr(obj: object, name: str) -> Any: ... +def setattr(obj: object, name: str, value: Any) -> None: ... def enumerate(x: Iterable[T]) -> Iterator[Tuple[int, T]]: ... @overload def zip(x: Iterable[T], y: Iterable[S]) -> Iterator[Tuple[T, S]]: ... @@ -295,6 +302,8 @@ def zip(x: Iterable[T], y: Iterable[S], z: Iterable[V]) -> Iterator[Tuple[T, S, def eval(e: str) -> Any: ... def abs(x: float) -> float: ... def exit() -> None: ... +def min(x: T, y: T) -> T: ... +def max(x: T, y: T) -> T: ... def repr(o: object) -> str: ... def ascii(o: object) -> str: ... def ord(o: object) -> int: ... diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 14e4d723532b..2032ea034e71 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -581,12 +581,12 @@ L8: [case testUnaryMinus] def f(n: int) -> int: - return -1 + return -n [out] def f(n): n, r0 :: int L0: - r0 = CPyTagged_Negate(2) + r0 = CPyTagged_Negate(n) return r0 [case testConditionalExpr] @@ -3287,6 +3287,46 @@ L10: L11: return r0 +[case testSum] +from typing import Callable, Iterable + +def call_sum(l: Iterable[int], comparison: Callable[[int], bool]) -> int: + return sum(comparison(x) for x in l) + +[out] +def call_sum(l, comparison): + l, comparison :: object + r0 :: int + r1, r2 :: object + r3, x :: int + r4, r5 :: object + r6 :: bool + r7 :: object + r8, r9 :: int + r10 :: bit +L0: + r0 = 0 + r1 = PyObject_GetIter(l) +L1: + r2 = PyIter_Next(r1) + if is_error(r2) goto L4 else goto L2 +L2: + r3 = unbox(int, r2) + x = r3 + r4 = box(int, x) + r5 = PyObject_CallFunctionObjArgs(comparison, r4, 0) + r6 = unbox(bool, r5) + r7 = box(bool, r6) + r8 = unbox(int, r7) + r9 = CPyTagged_Add(r0, r8) + r0 = r9 +L3: + goto L1 +L4: + r10 = CPy_NoErrOccured() +L5: + return r0 + [case testSetAttr1] from typing import Any, Dict, List def lol(x: Any): @@ -3745,3 +3785,27 @@ L3: goto L1 L4: return 1 +[case testLocalRedefinition] +# mypy: allow-redefinition +def f() -> None: + i = 0 + i += 1 + i = "foo" + i += i + i = 0.0 +[out] +def f(): + i, r0 :: int + r1, i__redef__, r2 :: str + r3, i__redef____redef__ :: float +L0: + i = 0 + r0 = CPyTagged_Add(i, 2) + i = r0 + r1 = 'foo' + i__redef__ = r1 + r2 = CPyStr_Append(i__redef__, i__redef__) + i__redef__ = r2 + r3 = 0.0 + i__redef____redef__ = r3 + return 1 diff --git a/mypyc/test-data/irbuild-constant-fold.test b/mypyc/test-data/irbuild-constant-fold.test new file mode 100644 index 000000000000..7c09021c27ec --- /dev/null +++ b/mypyc/test-data/irbuild-constant-fold.test @@ -0,0 +1,263 @@ +[case testIntConstantFolding] +def bin_ops() -> None: + add = 15 + 47 + add_mul = (2 + 3) * 5 + sub = 7 - 11 + bit_and = 6 & 10 + bit_or = 6 | 10 + bit_xor = 6 ^ 10 + lshift = 5 << 2 + rshift = 13 >> 2 + lshift0 = 5 << 0 + rshift0 = 13 >> 0 +def unary_ops() -> None: + neg1 = -5 + neg2 = --1 + neg3 = -0 + pos = +5 + inverted1 = ~0 + inverted2 = ~5 + inverted3 = ~3 +def pow() -> None: + p0 = 3**0 + p1 = 3**5 + p2 = (-5)**3 + p3 = 0**0 +[out] +def bin_ops(): + add, add_mul, sub, bit_and, bit_or, bit_xor, lshift, rshift, lshift0, rshift0 :: int +L0: + add = 124 + add_mul = 50 + sub = -8 + bit_and = 4 + bit_or = 28 + bit_xor = 24 + lshift = 40 + rshift = 6 + lshift0 = 10 + rshift0 = 26 + return 1 +def unary_ops(): + neg1, neg2, neg3, pos, inverted1, inverted2, inverted3 :: int +L0: + neg1 = -10 + neg2 = 2 + neg3 = 0 + pos = 10 + inverted1 = -2 + inverted2 = -12 + inverted3 = -8 + return 1 +def pow(): + p0, p1, p2, p3 :: int +L0: + p0 = 2 + p1 = 486 + p2 = -250 + p3 = 2 + return 1 + +[case testIntConstantFoldingDivMod] +def div() -> None: + div1 = 25 // 5 + div2 = 24 // 5 + div3 = 29 // 5 + div4 = 30 // 5 + div_zero = 0 // 5 + neg1 = -1 // 3 + neg2 = -2 // 3 + neg3 = -3 // 3 + neg4 = -4 // 3 + neg_neg = -765467 // -234 + pos_neg = 983745 // -7864 +def mod() -> None: + mod1 = 25 % 5 + mod2 = 24 % 5 + mod3 = 29 % 5 + mod4 = 30 % 5 + mod_zero = 0 % 5 + neg1 = -4 % 3 + neg2 = -5 % 3 + neg3 = -6 % 3 + neg4 = -7 % 3 + neg_neg = -765467 % -234 + pos_neg = 983745 % -7864 +[out] +def div(): + div1, div2, div3, div4, div_zero, neg1, neg2, neg3, neg4, neg_neg, pos_neg :: int +L0: + div1 = 10 + div2 = 8 + div3 = 10 + div4 = 12 + div_zero = 0 + neg1 = -2 + neg2 = -2 + neg3 = -2 + neg4 = -4 + neg_neg = 6542 + pos_neg = -252 + return 1 +def mod(): + mod1, mod2, mod3, mod4, mod_zero, neg1, neg2, neg3, neg4, neg_neg, pos_neg :: int +L0: + mod1 = 0 + mod2 = 8 + mod3 = 8 + mod4 = 0 + mod_zero = 0 + neg1 = 4 + neg2 = 2 + neg3 = 0 + neg4 = 4 + neg_neg = -106 + pos_neg = -14238 + return 1 + +[case testIntConstantFoldingUnsupportedCases] +def error_cases() -> None: + div_by_zero = 5 // 0 + mod_by_zero = 5 % 0 + lshift_neg = 6 << -1 + rshift_neg = 7 >> -1 +def unsupported_div() -> None: + x = 4 / 6 + y = 10 / 5 +def unsupported_pow() -> None: + p = 3 ** (-1) +[out] +def error_cases(): + r0, div_by_zero, r1, mod_by_zero, r2, lshift_neg, r3, rshift_neg :: int +L0: + r0 = CPyTagged_FloorDivide(10, 0) + div_by_zero = r0 + r1 = CPyTagged_Remainder(10, 0) + mod_by_zero = r1 + r2 = CPyTagged_Lshift(12, -2) + lshift_neg = r2 + r3 = CPyTagged_Rshift(14, -2) + rshift_neg = r3 + return 1 +def unsupported_div(): + r0, r1, r2 :: object + r3, x :: float + r4, r5, r6 :: object + r7, y :: float +L0: + r0 = box(short_int, 8) + r1 = box(short_int, 12) + r2 = PyNumber_TrueDivide(r0, r1) + r3 = cast(float, r2) + x = r3 + r4 = box(short_int, 20) + r5 = box(short_int, 10) + r6 = PyNumber_TrueDivide(r4, r5) + r7 = cast(float, r6) + y = r7 + return 1 +def unsupported_pow(): + r0, r1, r2 :: object + r3, p :: float +L0: + r0 = box(short_int, 6) + r1 = box(short_int, -2) + r2 = CPyNumber_Power(r0, r1) + r3 = cast(float, r2) + p = r3 + return 1 + +[case testIntConstantFoldingBigIntResult_64bit] +def long_and_short() -> None: + # The smallest and largest representable short integers + short1 = 0x3ffffffffffffff0 + 0xf # (1 << 62) - 1 + short2 = -0x3fffffffffffffff - 1 # -(1 << 62) + short3 = -0x4000000000000000 + # Smallest big integers by absolute value + big1 = 1 << 62 + big2 = 0x4000000000000000 # 1 << 62 + big3 = -(1 << 62) - 1 + big4 = -0x4000000000000001 # -(1 << 62) - 1 + big5 = 123**41 +[out] +def long_and_short(): + short1, short2, short3, r0, big1, r1, big2, r2, big3, r3, big4, r4, big5 :: int +L0: + short1 = 9223372036854775806 + short2 = -9223372036854775808 + short3 = -9223372036854775808 + r0 = object 4611686018427387904 + big1 = r0 + r1 = object 4611686018427387904 + big2 = r1 + r2 = object -4611686018427387905 + big3 = r2 + r3 = object -4611686018427387905 + big4 = r3 + r4 = object 48541095000524544750127162673405880068636916264012200797813591925035550682238127143323 + big5 = r4 + return 1 + +[case testIntConstantFoldingFinal] +from typing_extensions import Final +X: Final = 5 +Y: Final = 2 + 4 + +def f() -> None: + a = X + 1 + # TODO: Constant fold this as well + a = Y + 1 +[out] +def f(): + a, r0 :: int + r1 :: bool + r2 :: int +L0: + a = 12 + r0 = __main__.Y :: static + if is_error(r0) goto L1 else goto L2 +L1: + r1 = raise NameError('value for final name "Y" was not set') + unreachable +L2: + r2 = CPyTagged_Add(r0, 2) + a = r2 + return 1 + +[case testIntConstantFoldingClassFinal] +from typing_extensions import Final +class C: + X: Final = 5 + +def f() -> None: + a = C.X + 1 +[out] +def C.__mypyc_defaults_setup(__mypyc_self__): + __mypyc_self__ :: __main__.C + r0 :: bool +L0: + __mypyc_self__.X = 10; r0 = is_error + return 1 +def f(): + a :: int +L0: + a = 12 + return 1 + +[case testStrConstantFolding] +from typing_extensions import Final + +S: Final = 'z' + +def f() -> None: + x = 'foo' + 'bar' + y = 'x' + 'y' + S +[out] +def f(): + r0, x, r1, y :: str +L0: + r0 = 'foobar' + x = r0 + r1 = 'xyz' + y = r1 + return 1 diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index 2cf99ec5b2ac..69dd42f01dd3 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -154,8 +154,8 @@ def increment(d): r1 :: native_int r2 :: short_int r3 :: object - r4 :: tuple[bool, int, object] - r5 :: int + r4 :: tuple[bool, short_int, object] + r5 :: short_int r6 :: bool r7 :: object r8, k :: str @@ -232,8 +232,8 @@ def print_dict_methods(d1, d2): r1 :: native_int r2 :: short_int r3 :: object - r4 :: tuple[bool, int, object] - r5 :: int + r4 :: tuple[bool, short_int, object] + r5 :: short_int r6 :: bool r7 :: object r8, v :: int @@ -246,8 +246,8 @@ def print_dict_methods(d1, d2): r16 :: native_int r17 :: short_int r18 :: object - r19 :: tuple[bool, int, object, object] - r20 :: int + r19 :: tuple[bool, short_int, object, object] + r20 :: short_int r21 :: bool r22, r23 :: object r24, r25, k :: int diff --git a/mypyc/test-data/irbuild-generics.test b/mypyc/test-data/irbuild-generics.test index 6abd1105bbad..6ec8eb58fe7d 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -122,3 +122,29 @@ L0: r6 = C(r5) x = r6 return 1 + +[case testMax] +from typing import TypeVar +T = TypeVar('T') +def f(x: T, y: T) -> T: + return max(x, y) +[out] +def f(x, y): + x, y, r0 :: object + r1 :: int32 + r2 :: bit + r3 :: bool + r4 :: object +L0: + r0 = PyObject_RichCompare(y, x, 4) + r1 = PyObject_IsTrue(r0) + r2 = r1 >= 0 :: signed + r3 = truncate r1: int32 to builtins.bool + if r3 goto L1 else goto L2 :: bool +L1: + r4 = y + goto L3 +L2: + r4 = x +L3: + return r4 diff --git a/mypyc/test-data/irbuild-int.test b/mypyc/test-data/irbuild-int.test index b1b8d191bd05..ea943eef2c69 100644 --- a/mypyc/test-data/irbuild-int.test +++ b/mypyc/test-data/irbuild-int.test @@ -80,3 +80,40 @@ L14: L15: L16: return 12 + +[case testIntMin] +def f(x: int, y: int) -> int: + return min(x, y) +[out] +def f(x, y): + x, y :: int + r0 :: native_int + r1 :: bit + r2 :: native_int + r3, r4, r5 :: bit + r6 :: bool + r7 :: bit + r8 :: int +L0: + r0 = y & 1 + r1 = r0 == 0 + r2 = x & 1 + r3 = r2 == 0 + r4 = r1 & r3 + if r4 goto L1 else goto L2 :: bool +L1: + r5 = y < x :: signed + r6 = r5 + goto L3 +L2: + r7 = CPyTagged_IsLt_(y, x) + r6 = r7 +L3: + if r6 goto L4 else goto L5 :: bool +L4: + r8 = y + goto L6 +L5: + r8 = x +L6: + return r8 diff --git a/mypyc/test-data/irbuild-lists.test b/mypyc/test-data/irbuild-lists.test index 2d9f24fe8e48..0d29f256cc59 100644 --- a/mypyc/test-data/irbuild-lists.test +++ b/mypyc/test-data/irbuild-lists.test @@ -381,3 +381,49 @@ L7: L8: b = r16 return 1 +[case testGeneratorNext] +from typing import List, Optional + +def test(x: List[int]) -> None: + res = next((i for i in x), None) +[out] +def test(x): + x :: list + r0 :: short_int + r1 :: ptr + r2 :: native_int + r3 :: short_int + r4 :: bit + r5 :: object + r6, i :: int + r7 :: object + r8 :: union[int, None] + r9 :: short_int + r10 :: object + res :: union[int, None] +L0: + r0 = 0 +L1: + r1 = get_element_ptr x ob_size :: PyVarObject + r2 = load_mem r1 :: native_int* + keep_alive x + r3 = r2 << 1 + r4 = r0 < r3 :: signed + if r4 goto L2 else goto L4 :: bool +L2: + r5 = CPyList_GetItemUnsafe(x, r0) + r6 = unbox(int, r5) + i = r6 + r7 = box(int, i) + r8 = r7 + goto L5 +L3: + r9 = r0 + 2 + r0 = r9 + goto L1 +L4: + r10 = box(None, 1) + r8 = r10 +L5: + res = r8 + return 1 diff --git a/mypyc/test-data/irbuild-set.test b/mypyc/test-data/irbuild-set.test index aab70ecd0e76..f620039b7655 100644 --- a/mypyc/test-data/irbuild-set.test +++ b/mypyc/test-data/irbuild-set.test @@ -173,8 +173,8 @@ def test3(): r9 :: native_int r10 :: short_int r11 :: object - r12 :: tuple[bool, int, object] - r13 :: int + r12 :: tuple[bool, short_int, object] + r13 :: short_int r14 :: bool r15 :: object r16, x, r17 :: int diff --git a/mypyc/test-data/irbuild-statements.test b/mypyc/test-data/irbuild-statements.test index 0975ac301db9..8b85e494b07d 100644 --- a/mypyc/test-data/irbuild-statements.test +++ b/mypyc/test-data/irbuild-statements.test @@ -342,8 +342,8 @@ def f(d): r1 :: native_int r2 :: short_int r3 :: object - r4 :: tuple[bool, int, object] - r5 :: int + r4 :: tuple[bool, short_int, object] + r5 :: short_int r6 :: bool r7 :: object r8, key :: int @@ -394,8 +394,8 @@ def sum_over_even_values(d): r1 :: native_int r2 :: short_int r3 :: object - r4 :: tuple[bool, int, object] - r5 :: int + r4 :: tuple[bool, short_int, object] + r5 :: short_int r6 :: bool r7 :: object r8, key :: int diff --git a/mypyc/test-data/irbuild-strip-asserts.test b/mypyc/test-data/irbuild-strip-asserts.test index 1ab6b4107b4d..5772fc8911fe 100644 --- a/mypyc/test-data/irbuild-strip-asserts.test +++ b/mypyc/test-data/irbuild-strip-asserts.test @@ -5,11 +5,8 @@ def g(): return x [out] def g(): - r0 :: int - r1, x :: object + r0, x :: object L0: - r0 = CPyTagged_Add(2, 4) - r1 = box(int, r0) - x = r1 + r0 = box(short_int, 6) + x = r0 return x - diff --git a/mypyc/test-data/refcount.test b/mypyc/test-data/refcount.test index 64b38f33a26b..c48ae1acce09 100644 --- a/mypyc/test-data/refcount.test +++ b/mypyc/test-data/refcount.test @@ -724,8 +724,8 @@ def f(d): r1 :: native_int r2 :: short_int r3 :: object - r4 :: tuple[bool, int, object] - r5 :: int + r4 :: tuple[bool, short_int, object] + r5 :: short_int r6 :: bool r7 :: object r8, key :: int diff --git a/mypyc/test-data/run-attrs.test b/mypyc/test-data/run-attrs.test new file mode 100644 index 000000000000..9c402a3eea7c --- /dev/null +++ b/mypyc/test-data/run-attrs.test @@ -0,0 +1,318 @@ +-- Test cases for dataclasses based on the attrs library, where auto_attribs=True + +[case testRunAttrsclass] +import attr +from typing import Set, List, Callable, Any + +@attr.s(auto_attribs=True) +class Person1: + age : int + name : str + + def __bool__(self) -> bool: + return self.name == 'robot' + +def testBool(p: Person1) -> bool: + if p: + return True + else: + return False + +@attr.s(auto_attribs=True) +class Person1b(Person1): + id: str = '000' + +@attr.s(auto_attribs=True) +class Person2: + age : int + name : str = attr.ib(default='robot') + +@attr.s(auto_attribs=True, order=True) +class Person3: + age : int = attr.ib(default = 6) + friendIDs : List[int] = attr.ib(factory = list) + + def get_age(self) -> int: + return (self.age) + + def set_age(self, new_age : int) -> None: + self.age = new_age + + def add_friendID(self, fid : int) -> None: + self.friendIDs.append(fid) + + def get_friendIDs(self) -> List[int]: + return self.friendIDs + +def get_next_age(g: Callable[[Any], int]) -> Callable[[Any], int]: + def f(a: Any) -> int: + return g(a) + 1 + return f + +@attr.s(auto_attribs=True) +class Person4: + age : int + _name : str = 'Bot' + + @get_next_age + def get_age(self) -> int: + return self.age + + @property + def name(self) -> str: + return self._name + +@attr.s(auto_attribs=True) +class Point: + x : int = attr.ib(converter=int) + y : int = attr.ib(init=False) + + def __attrs_post_init__(self): + self.y = self.x + 1 + + +[file other.py] +from native import Person1, Person1b, Person2, Person3, Person4, testBool, Point +i1 = Person1(age = 5, name = 'robot') +assert i1.age == 5 +assert i1.name == 'robot' +assert testBool(i1) == True +assert testBool(Person1(age = 5, name = 'robo')) == False +i1b = Person1b(age = 5, name = 'robot') +assert i1b.age == 5 +assert i1b.name == 'robot' +assert i1b.id == '000' +assert testBool(i1b) == True +assert testBool(Person1b(age = 5, name = 'robo')) == False +i1c = Person1b(age = 20, name = 'robot', id = 'test') +assert i1c.age == 20 +assert i1c.id == 'test' + +i2 = Person2(age = 5) +assert i2.age == 5 +assert i2.name == 'robot' +i3 = Person2(age = 5, name = 'new_robot') +assert i3.age == 5 +assert i3.name == 'new_robot' +i4 = Person3() +assert i4.age == 6 +assert i4.friendIDs == [] +i5 = Person3(age = 5) +assert i5.age == 5 +assert i5.friendIDs == [] +i6 = Person3(age = 5, friendIDs = [1,2,3]) +assert i6.age == 5 +assert i6.friendIDs == [1,2,3] +assert i6.get_age() == 5 +i6.set_age(10) +assert i6.get_age() == 10 +i6.add_friendID(4) +assert i6.get_friendIDs() == [1,2,3,4] +i7 = Person4(age = 5) +assert i7.get_age() == 6 +i7.age += 3 +assert i7.age == 8 +assert i7.name == 'Bot' +i8 = Person3(age = 1, friendIDs = [1,2]) +i9 = Person3(age = 1, friendIDs = [1,2]) +assert i8 == i9 +i8.age = 2 +assert i8 > i9 + +assert Person1.__annotations__ == {'age': int, 'name': str} +assert Person2.__annotations__ == {'age': int, 'name': str} + +p1 = Point(2) +assert p1.x == 2 +assert p1.y == 3 +p2 = Point('2') +assert p2.x == 2 +assert p2.y == 3 + +assert Point.__annotations__ == {'x': int, 'y': int} + +[file driver.py] +import sys + +# PEP 526 introduced in 3.6 +version = sys.version_info[:2] +if version[0] < 3 or version[1] < 6: + exit() + +# Run the tests in both interpreted and compiled mode +import other +import other_interpreted + +# Test for an exceptional cases +from testutil import assertRaises +from native import Person1, Person1b, Person3 +from types import BuiltinMethodType + +with assertRaises(TypeError, "missing 1 required positional argument"): + Person1(0) + +with assertRaises(TypeError, "missing 2 required positional arguments"): + Person1b() + +with assertRaises(TypeError, "int object expected; got str"): + Person1('nope', 'test') + +p = Person1(0, 'test') +with assertRaises(TypeError, "int object expected; got str"): + p.age = 'nope' + +assert isinstance(Person3().get_age, BuiltinMethodType) + + +[case testRunAttrsclassNonAuto] +import attr +from typing import Set, List, Callable, Any + +@attr.s +class Person1: + age = attr.ib(type=int) + name = attr.ib(type=str) + + def __bool__(self) -> bool: + return self.name == 'robot' + +def testBool(p: Person1) -> bool: + if p: + return True + else: + return False + +@attr.s +class Person1b(Person1): + id = attr.ib(type=str, default='000') + +@attr.s +class Person2: + age = attr.ib(type=int) + name = attr.ib(type=str, default='robot') + +@attr.s(order=True) +class Person3: + age = attr.ib(type=int, default=6) + friendIDs = attr.ib(factory=list, type=List[int]) + + def get_age(self) -> int: + return (self.age) + + def set_age(self, new_age : int) -> None: + self.age = new_age + + def add_friendID(self, fid : int) -> None: + self.friendIDs.append(fid) + + def get_friendIDs(self) -> List[int]: + return self.friendIDs + +def get_next_age(g: Callable[[Any], int]) -> Callable[[Any], int]: + def f(a: Any) -> int: + return g(a) + 1 + return f + +@attr.s +class Person4: + age = attr.ib(type=int) + _name = attr.ib(type=str, default='Bot') + + @get_next_age + def get_age(self) -> int: + return self.age + + @property + def name(self) -> str: + return self._name + +@attr.s +class Point: + x = attr.ib(type=int, converter=int) + y = attr.ib(type=int, init=False) + + def __attrs_post_init__(self): + self.y = self.x + 1 + + +[file other.py] +from native import Person1, Person1b, Person2, Person3, Person4, testBool, Point +i1 = Person1(age = 5, name = 'robot') +assert i1.age == 5 +assert i1.name == 'robot' +assert testBool(i1) == True +assert testBool(Person1(age = 5, name = 'robo')) == False +i1b = Person1b(age = 5, name = 'robot') +assert i1b.age == 5 +assert i1b.name == 'robot' +assert i1b.id == '000' +assert testBool(i1b) == True +assert testBool(Person1b(age = 5, name = 'robo')) == False +i1c = Person1b(age = 20, name = 'robot', id = 'test') +assert i1c.age == 20 +assert i1c.id == 'test' + +i2 = Person2(age = 5) +assert i2.age == 5 +assert i2.name == 'robot' +i3 = Person2(age = 5, name = 'new_robot') +assert i3.age == 5 +assert i3.name == 'new_robot' +i4 = Person3() +assert i4.age == 6 +assert i4.friendIDs == [] +i5 = Person3(age = 5) +assert i5.age == 5 +assert i5.friendIDs == [] +i6 = Person3(age = 5, friendIDs = [1,2,3]) +assert i6.age == 5 +assert i6.friendIDs == [1,2,3] +assert i6.get_age() == 5 +i6.set_age(10) +assert i6.get_age() == 10 +i6.add_friendID(4) +assert i6.get_friendIDs() == [1,2,3,4] +i7 = Person4(age = 5) +assert i7.get_age() == 6 +i7.age += 3 +assert i7.age == 8 +assert i7.name == 'Bot' +i8 = Person3(age = 1, friendIDs = [1,2]) +i9 = Person3(age = 1, friendIDs = [1,2]) +assert i8 == i9 +i8.age = 2 +assert i8 > i9 + +p1 = Point(2) +assert p1.x == 2 +assert p1.y == 3 +p2 = Point('2') +assert p2.x == 2 +assert p2.y == 3 + +[file driver.py] +import sys + +# Run the tests in both interpreted and compiled mode +import other +import other_interpreted + +# Test for an exceptional cases +from testutil import assertRaises +from native import Person1, Person1b, Person3 +from types import BuiltinMethodType + +with assertRaises(TypeError, "missing 1 required positional argument"): + Person1(0) + +with assertRaises(TypeError, "missing 2 required positional arguments"): + Person1b() + +with assertRaises(TypeError, "int object expected; got str"): + Person1('nope', 'test') + +p = Person1(0, 'test') +with assertRaises(TypeError, "int object expected; got str"): + p.age = 'nope' + +assert isinstance(Person3().get_age, BuiltinMethodType) diff --git a/mypyc/test-data/run-classes.test b/mypyc/test-data/run-classes.test index 98b1cc86e5ac..e2beca1bafc6 100644 --- a/mypyc/test-data/run-classes.test +++ b/mypyc/test-data/run-classes.test @@ -1591,13 +1591,13 @@ from mypy_extensions import trait class Temperature: @property def celsius(self) -> float: - return 5.0 * (self.farenheit - 32.0) / 9.0 + return 5.0 * (self.fahrenheit - 32.0) / 9.0 - def __init__(self, farenheit: float) -> None: - self.farenheit = farenheit + def __init__(self, fahrenheit: float) -> None: + self.fahrenheit = fahrenheit def print_temp(self) -> None: - print("F:", self.farenheit, "C:", self.celsius) + print("F:", self.fahrenheit, "C:", self.celsius) @property def rankine(self) -> float: diff --git a/mypyc/test-data/run-dunders.test b/mypyc/test-data/run-dunders.test index 665c9d871497..aee2a956c47f 100644 --- a/mypyc/test-data/run-dunders.test +++ b/mypyc/test-data/run-dunders.test @@ -757,3 +757,42 @@ def test_in_place_operator_returns_none() -> None: o = BadInplaceAdd() with assertRaises(TypeError, "native.BadInplaceAdd object expected; got None"): o += 5 + +[case testDunderMinMax] +class SomeItem: + def __init__(self, val: int) -> None: + self.val = val + + def __lt__(self, x: 'SomeItem') -> bool: + return self.val < x.val + + def __gt__(self, x: 'SomeItem') -> bool: + return self.val > x.val + +class AnotherItem: + def __init__(self, val: str) -> None: + self.val = val + + def __lt__(self, x: 'AnotherItem') -> bool: + return True + + def __gt__(self, x: 'AnotherItem') -> bool: + return True + +def test_dunder_min() -> None: + x = SomeItem(5) + y = SomeItem(10) + z = SomeItem(15) + assert min(x, y).val == 5 + assert min(y, z).val == 10 + assert max(x, y).val == 10 + assert max(y, z).val == 15 + x2 = AnotherItem('xxx') + y2 = AnotherItem('yyy') + z2 = AnotherItem('zzz') + assert min(x2, y2).val == 'yyy' + assert min(y2, x2).val == 'xxx' + assert max(x2, y2).val == 'yyy' + assert max(y2, x2).val == 'xxx' + assert min(y2, z2).val == 'zzz' + assert max(x2, z2).val == 'zzz' diff --git a/mypyc/test-data/run-floats.test b/mypyc/test-data/run-floats.test index 1b40a598bf39..1b67a1190cd8 100644 --- a/mypyc/test-data/run-floats.test +++ b/mypyc/test-data/run-floats.test @@ -13,10 +13,18 @@ assert str_to_float("44324") == 44324.0 assert str_to_float("23.4") == 23.4 assert str_to_float("-43.44e-4") == -43.44e-4 -[case testFloatAbs] +[case testFloatArithmetic] def test_abs() -> None: assert abs(0.0) == 0.0 assert abs(-1.234567) == 1.234567 assert abs(44324.732) == 44324.732 assert abs(-23.4) == 23.4 assert abs(-43.44e-4) == 43.44e-4 + +def test_float_min_max() -> None: + x: float = 20.0 + y: float = 30.0 + assert min(x, y) == 20.0 + assert min(y, x) == 20.0 + assert max(x, y) == 30.0 + assert max(y, x) == 30.0 diff --git a/mypyc/test-data/run-integers.test b/mypyc/test-data/run-integers.test index 59e61931439b..b9668d6dec9f 100644 --- a/mypyc/test-data/run-integers.test +++ b/mypyc/test-data/run-integers.test @@ -87,15 +87,36 @@ def big_int() -> None: max_63_bit = 9223372036854775807 d_64_bit = 9223372036854775808 max_32_bit = 2147483647 + max_32_bit_plus1 = 2147483648 max_31_bit = 1073741823 + max_31_bit_plus1 = 1073741824 + neg = -1234567 + min_signed_63_bit = -4611686018427387904 + underflow = -4611686018427387905 + min_signed_64_bit = -9223372036854775808 + min_signed_31_bit = -1073741824 + min_signed_31_bit_plus1 = -1073741823 + min_signed_31_bit_minus1 = -1073741825 + min_signed_32_bit = -2147483648 print(a_62_bit) print(max_62_bit) print(b_63_bit) print(c_63_bit) print(max_63_bit) print(d_64_bit) + print('==') print(max_32_bit) + print(max_32_bit_plus1) print(max_31_bit) + print(max_31_bit_plus1) + print(neg) + print(min_signed_63_bit) + print(underflow) + print(min_signed_64_bit) + print(min_signed_31_bit) + print(min_signed_31_bit_plus1) + print(min_signed_31_bit_minus1) + print(min_signed_32_bit) [file driver.py] from native import big_int big_int() @@ -106,8 +127,19 @@ big_int() 9223372036854775806 9223372036854775807 9223372036854775808 +== 2147483647 +2147483648 1073741823 +1073741824 +-1234567 +-4611686018427387904 +-4611686018427387905 +-9223372036854775808 +-1073741824 +-1073741823 +-1073741825 +-2147483648 [case testNeg] def neg(x: int) -> int: @@ -131,6 +163,14 @@ assert neg(-9223372036854775807) == 9223372036854775807 assert neg(9223372036854775808) == -9223372036854775808 assert neg(-9223372036854775808) == 9223372036854775808 +[case testIsinstanceIntAndNotBool] +def test_isinstance_int_and_not_bool(value: object) -> bool: + return isinstance(value, int) and not isinstance(value, bool) +[file driver.py] +from native import test_isinstance_int_and_not_bool +assert test_isinstance_int_and_not_bool(True) == False +assert test_isinstance_int_and_not_bool(1) == True + [case testIntOps] def check_and(x: int, y: int) -> None: # eval() can be trusted to calculate expected result @@ -157,15 +197,6 @@ def check_bitwise(x: int, y: int) -> None: check_or(ll, rr) check_xor(ll, rr) -[case testIsinstanceIntAndNotBool] -def test_isinstance_int_and_not_bool(value: object) -> bool: - return isinstance(value, int) and not isinstance(value, bool) -[file driver.py] -from native import test_isinstance_int_and_not_bool -assert test_isinstance_int_and_not_bool(True) == False -assert test_isinstance_int_and_not_bool(1) == True - - SHIFT = 30 DIGIT0a = 615729753 DIGIT0b = 832796681 @@ -198,6 +229,10 @@ def test_and_or_xor() -> None: check_bitwise(BIG_SHORT, DIGIT0a + DIGIT1a + DIGIT2a) check_bitwise(BIG_SHORT, DIGIT0a + DIGIT1a + DIGIT2a + DIGIT50) + for x in range(-25, 25): + for y in range(-25, 25): + check_bitwise(x, y) + def test_bitwise_inplace() -> None: # Basic sanity checks; these should use the same code as the non-in-place variants for x, y in (DIGIT0a, DIGIT1a), (DIGIT2a, DIGIT0a + DIGIT2b): @@ -328,3 +363,116 @@ def test_int_as_bool() -> None: for x in 1, 55, -1, -7, 1 << 50, 1 << 101, -(1 << 50), -(1 << 101): assert is_true(x) assert not is_false(x) + +def test_divide() -> None: + for x in range(-100, 100): + for y in range(-100, 100): + if y != 0: + assert x // y == getattr(x, "__floordiv__")(y) + +def test_mod() -> None: + for x in range(-100, 100): + for y in range(-100, 100): + if y != 0: + assert x % y == getattr(x, "__mod__")(y) + +def test_constant_fold() -> None: + assert str(-5 + 3) == "-2" + assert str(15 - 3) == "12" + assert str(1000 * 1000) == "1000000" + assert str(12325 // 12 ) == "1027" + assert str(87645 % 321) == "12" + assert str(674253 | 76544) == "748493" + assert str(765 ^ 82) == "687" + assert str(6546 << 3) == "52368" + assert str(6546 >> 7) == "51" + assert str(3**5) == "243" + assert str(~76) == "-77" + try: + 2 / 0 + except ZeroDivisionError: + pass + else: + assert False, "no exception raised" + + x = int() + y = int() - 1 + assert x == -1 or y != -3 + assert -1 <= x + assert -1 == y + + # Use int() to avoid constant propagation + i30 = (1 << 30) + int() + assert i30 == 1 << 30 + i31 = (1 << 31) + int() + assert i31 == 1 << 31 + i32 = (1 << 32) + int() + assert i32 == 1 << 32 + i62 = (1 << 62) + int() + assert i62 == 1 << 62 + i63 = (1 << 63) + int() + assert i63 == 1 << 63 + i64 = (1 << 64) + int() + assert i64 == 1 << 64 + + n30 = -(1 << 30) + int() + assert n30 == -(1 << 30) + n31 = -(1 << 31) + int() + assert n31 == -(1 << 31) + n32 = -(1 << 32) + int() + assert n32 == -(1 << 32) + n62 = -(1 << 62) + int() + assert n62 == -(1 << 62) + n63 = -(1 << 63) + int() + assert n63 == -(1 << 63) + n64 = -(1 << 64) + int() + assert n64 == -(1 << 64) + +[case testIntMinMax] +def test_int_min_max() -> None: + x: int = 200 + y: int = 30 + assert min(x, y) == 30 + assert max(x, y) == 200 + assert min(y, x) == 30 + assert max(y, x) == 200 + +def test_int_hybrid_min_max() -> None: + from typing import Any + + x: object = 30 + y: Any = 20.0 + assert min(x, y) == 20.0 + assert max(x, y) == 30 + + u: object = 20 + v: float = 30.0 + assert min(u, v) == 20 + assert max(u, v) == 30.0 + +def test_int_incompatible_min_max() -> None: + x: int = 2 + y: str = 'aaa' + try: + print(min(x, y)) + except TypeError as e: + assert str(e) == "'<' not supported between instances of 'str' and 'int'" + try: + print(max(x, y)) + except TypeError as e: + assert str(e) == "'>' not supported between instances of 'str' and 'int'" + +def test_int_bool_min_max() -> None: + x: int = 2 + y: bool = False + z: bool = True + assert min(x, y) == False + assert min(x, z) == True + assert max(x, y) == 2 + assert max(x, z) == 2 + + u: int = -10 + assert min(u, y) == -10 + assert min(u, z) == -10 + assert max(u, y) == False + assert max(u, z) == True diff --git a/mypyc/test-data/run-lists.test b/mypyc/test-data/run-lists.test index 1366b1fd857e..c98ab9171123 100644 --- a/mypyc/test-data/run-lists.test +++ b/mypyc/test-data/run-lists.test @@ -379,4 +379,8 @@ def test() -> None: source_str = "abcd" f = list("str:" + x for x in source_str) assert f == ["str:a", "str:b", "str:c", "str:d"] +[case testNextBug] +from typing import List, Optional +def test(x: List[int]) -> None: + res = next((i for i in x), None) diff --git a/mypyc/test-data/run-misc.test b/mypyc/test-data/run-misc.test index 431efc2289aa..736169f95b82 100644 --- a/mypyc/test-data/run-misc.test +++ b/mypyc/test-data/run-misc.test @@ -2,6 +2,7 @@ [case testAsync] import asyncio +import sys async def h() -> int: return 1 @@ -13,8 +14,13 @@ async def g() -> int: async def f() -> int: return await g() -loop = asyncio.get_event_loop() -result = loop.run_until_complete(f()) +# sys.version_info >= (3, 7) fails with +# error: Unsupported left operand type for >= ("Tuple[int, int, int, str, int]") +if sys.version_info[0] >= 3 and sys.version_info[1] >= 7: + result = asyncio.run(f()) +else: + loop = asyncio.get_event_loop() + result = loop.run_until_complete(f()) assert result == 1 [typing fixtures/typing-full.pyi] @@ -22,8 +28,13 @@ assert result == 1 [file driver.py] from native import f import asyncio -loop = asyncio.get_event_loop() -result = loop.run_until_complete(f()) +import sys + +if sys.version_info >= (3, 7): + result = asyncio.run(f()) +else: + loop = asyncio.get_event_loop() + result = loop.run_until_complete(f()) assert result == 1 [case testMaybeUninitVar] @@ -820,6 +831,51 @@ assert call_all(mixed_110) == 1 assert call_any_nested([[1, 1, 1], [1, 1], []]) == 1 assert call_any_nested([[1, 1, 1], [0, 1], []]) == 0 +[case testSum] +[typing fixtures/typing-full.pyi] +from typing import Any, List + +def test_sum_of_numbers() -> None: + assert sum(x for x in [1, 2, 3]) == 6 + assert sum(x for x in [0.0, 1.2, 2]) == 6.2 + assert sum(x for x in [1, 1j]) == 1 + 1j + +def test_sum_callables() -> None: + assert sum((lambda x: x == 0)(x) for x in []) == 0 + assert sum((lambda x: x == 0)(x) for x in [0]) == 1 + assert sum((lambda x: x == 0)(x) for x in [0, 0, 0]) == 3 + assert sum((lambda x: x == 0)(x) for x in [0, 1, 0]) == 2 + assert sum((lambda x: x % 2 == 0)(x) for x in range(2**10)) == 2**9 + +def test_sum_comparisons() -> None: + assert sum(x == 0 for x in []) == 0 + assert sum(x == 0 for x in [0]) == 1 + assert sum(x == 0 for x in [0, 0, 0]) == 3 + assert sum(x == 0 for x in [0, 1, 0]) == 2 + assert sum(x % 2 == 0 for x in range(2**10)) == 2**9 + +def test_sum_multi() -> None: + assert sum(i + j == 0 for i, j in zip([0, 0, 0], [0, 1, 0])) == 2 + +def test_sum_misc() -> None: + # misc cases we do optimize (note, according to sum's helptext, we don't need to support + # non-numeric cases, but CPython and mypyc both do anyway) + assert sum(c == 'd' for c in 'abcdd') == 2 + # misc cases we do not optimize + assert sum([0, 1]) == 1 + assert sum([0, 1], 1) == 2 + +def test_sum_start_given() -> None: + a = 1 + assert sum((x == 0 for x in [0, 1]), a) == 2 + assert sum(((lambda x: x == 0)(x) for x in []), 1) == 1 + assert sum(((lambda x: x == 0)(x) for x in [0]), 1) == 2 + assert sum(((lambda x: x == 0)(x) for x in [0, 0, 0]), 1) == 4 + assert sum(((lambda x: x == 0)(x) for x in [0, 1, 0]), 1) == 3 + assert sum(((lambda x: x % 2 == 0)(x) for x in range(2**10)), 1) == 2**9 + 1 + assert sum((x for x in [1, 1j]), 2j) == 1 + 3j + assert sum((c == 'd' for c in 'abcdd'), 1) == 3 + [case testNoneStuff] from typing import Optional class A: @@ -834,7 +890,6 @@ def none() -> None: def arg(x: Optional[A]) -> bool: return x is None - [file driver.py] import native native.lol(native.A()) @@ -1089,3 +1144,14 @@ class A: class B(A): def _(arg): pass def _(arg): pass + +[case testGlobalRedefinition_toplevel] +# mypy: allow-redefinition +i = 0 +i += 1 +i = "foo" +i += i +i = b"foo" + +def test_redefinition() -> None: + assert i == b"foo" diff --git a/mypyc/test-data/run-python37.test b/mypyc/test-data/run-python37.test index 3660ba13a6c8..734e116c1335 100644 --- a/mypyc/test-data/run-python37.test +++ b/mypyc/test-data/run-python37.test @@ -1,6 +1,7 @@ -- Test cases for Python 3.7 features [case testRunDataclass] +import dataclasses from dataclasses import dataclass, field from typing import Set, List, Callable, Any @@ -27,6 +28,11 @@ class Person2: age : int name : str = field(default='robot') +@dataclasses.dataclass +class Person2b: + age : int + name : str = dataclasses.field(default='robot') + @dataclass(order = True) class Person3: age : int = field(default = 6) @@ -109,6 +115,8 @@ assert i8 == i9 i8.age = 2 assert i8 > i9 +assert Person1.__annotations__ == {'age': int, 'name': str} +assert Person2.__annotations__ == {'age': int, 'name': str} [file driver.py] import sys diff --git a/mypyc/test-data/run-strings.test b/mypyc/test-data/run-strings.test index 03a934b1bff8..c2b010bdb2bd 100644 --- a/mypyc/test-data/run-strings.test +++ b/mypyc/test-data/run-strings.test @@ -149,6 +149,15 @@ def test_str_to_bool() -> None: assert is_true(x) assert not is_false(x) +def test_str_min_max() -> None: + x: str = 'aaa' + y: str = 'bbb' + z: str = 'aa' + assert min(x, y) == 'aaa' + assert min(x, z) == 'aa' + assert max(x, y) == 'bbb' + assert max(x, z) == 'aaa' + [case testStringFormattingCStyle] [typing fixtures/typing-full.pyi] from typing import Tuple @@ -218,8 +227,8 @@ def test_fstring_basics() -> None: x = bytes([1, 2, 3, 4]) # assert f'bytes: {x}' == "bytes: b'\\x01\\x02\\x03\\x04'" - # error: On Python 3 '{}'.format(b'abc') produces "b'abc'", not 'abc'; - # use '{!r}'.format(b'abc') if this is desired behavior + # error: On Python 3 formatting "b'abc'" with "{}" produces "b'abc'", not "abc"; + # use "{!r}" if this is desired behavior behavior float_num = 123.4 assert f'{float_num}' == '123.4' @@ -354,7 +363,7 @@ def test_format_method_basics() -> None: def test_format_method_empty_braces() -> None: name = 'Eric' age = 14 - + assert 'Hello, {}!'.format(name) == 'Hello, Eric!' assert '{}'.format(name) == 'Eric' assert '{}! Hi!'.format(name) == 'Eric! Hi!' diff --git a/mypyc/test/test_commandline.py b/mypyc/test/test_commandline.py index 5dae26d294ab..5c80d0fddb1d 100644 --- a/mypyc/test/test_commandline.py +++ b/mypyc/test/test_commandline.py @@ -47,8 +47,7 @@ def run_case(self, testcase: DataDrivenTestCase) -> None: out = b'' try: # Compile program - cmd = subprocess.run([sys.executable, - os.path.join(base_path, 'scripts', 'mypyc')] + args, + cmd = subprocess.run([sys.executable, '-m', 'mypyc', *args], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd='tmp') if 'ErrorOutput' in testcase.name or cmd.returncode != 0: out += cmd.stdout diff --git a/mypyc/test/test_emitfunc.py b/mypyc/test/test_emitfunc.py index 139923aa57c6..a3f55a7facf2 100644 --- a/mypyc/test/test_emitfunc.py +++ b/mypyc/test/test_emitfunc.py @@ -9,7 +9,7 @@ from mypyc.ir.ops import ( BasicBlock, Goto, Return, Integer, Assign, AssignMulti, IncRef, DecRef, Branch, Call, Unbox, Box, TupleGet, GetAttr, SetAttr, Op, Value, CallC, IntOp, LoadMem, - GetElementPtr, LoadAddress, ComparisonOp, SetMem, Register + GetElementPtr, LoadAddress, ComparisonOp, SetMem, Register, Unreachable ) from mypyc.ir.rtypes import ( RTuple, RInstance, RType, RArray, int_rprimitive, bool_rprimitive, list_rprimitive, @@ -202,18 +202,26 @@ def test_call_two_args(self) -> None: "cpy_r_r0 = CPyDef_myfn(cpy_r_m, cpy_r_k);") def test_inc_ref(self) -> None: - self.assert_emit(IncRef(self.m), - "CPyTagged_IncRef(cpy_r_m);") + self.assert_emit(IncRef(self.o), "CPy_INCREF(cpy_r_o);") + self.assert_emit(IncRef(self.o), "CPy_INCREF(cpy_r_o);", rare=True) def test_dec_ref(self) -> None: - self.assert_emit(DecRef(self.m), - "CPyTagged_DecRef(cpy_r_m);") + self.assert_emit(DecRef(self.o), "CPy_DECREF(cpy_r_o);") + self.assert_emit(DecRef(self.o), "CPy_DecRef(cpy_r_o);", rare=True) + + def test_inc_ref_int(self) -> None: + self.assert_emit(IncRef(self.m), "CPyTagged_INCREF(cpy_r_m);") + self.assert_emit(IncRef(self.m), "CPyTagged_IncRef(cpy_r_m);", rare=True) + + def test_dec_ref_int(self) -> None: + self.assert_emit(DecRef(self.m), "CPyTagged_DECREF(cpy_r_m);") + self.assert_emit(DecRef(self.m), "CPyTagged_DecRef(cpy_r_m);", rare=True) def test_dec_ref_tuple(self) -> None: - self.assert_emit(DecRef(self.t), 'CPyTagged_DecRef(cpy_r_t.f0);') + self.assert_emit(DecRef(self.t), 'CPyTagged_DECREF(cpy_r_t.f0);') def test_dec_ref_tuple_nested(self) -> None: - self.assert_emit(DecRef(self.tt), 'CPyTagged_DecRef(cpy_r_tt.f0.f0);') + self.assert_emit(DecRef(self.tt), 'CPyTagged_DECREF(cpy_r_tt.f0.f0);') def test_list_get_item(self) -> None: self.assert_emit(CallC(list_get_item_op.c_function_name, [self.m, self.k], @@ -253,7 +261,7 @@ def test_get_attr(self) -> None: if (unlikely(((mod___AObject *)cpy_r_r)->_y == CPY_INT_TAG)) { PyErr_SetString(PyExc_AttributeError, "attribute 'y' of 'A' undefined"); } else { - CPyTagged_IncRef(((mod___AObject *)cpy_r_r)->_y); + CPyTagged_INCREF(((mod___AObject *)cpy_r_r)->_y); } """) @@ -261,7 +269,7 @@ def test_set_attr(self) -> None: self.assert_emit( SetAttr(self.r, 'y', self.m, 1), """if (((mod___AObject *)cpy_r_r)->_y != CPY_INT_TAG) { - CPyTagged_DecRef(((mod___AObject *)cpy_r_r)->_y); + CPyTagged_DECREF(((mod___AObject *)cpy_r_r)->_y); } ((mod___AObject *)cpy_r_r)->_y = cpy_r_m; cpy_r_r0 = 1; @@ -372,11 +380,23 @@ def test_assign_multi(self) -> None: def test_long_unsigned(self) -> None: a = Register(int64_rprimitive, 'a') self.assert_emit(Assign(a, Integer(1 << 31, int64_rprimitive)), - """cpy_r_a = 2147483648U;""") + """cpy_r_a = 2147483648ULL;""") self.assert_emit(Assign(a, Integer((1 << 31) - 1, int64_rprimitive)), """cpy_r_a = 2147483647;""") - def assert_emit(self, op: Op, expected: str, next_block: Optional[BasicBlock] = None) -> None: + def test_long_signed(self) -> None: + a = Register(int64_rprimitive, 'a') + self.assert_emit(Assign(a, Integer(-(1 << 31) + 1, int64_rprimitive)), + """cpy_r_a = -2147483647;""") + self.assert_emit(Assign(a, Integer(-(1 << 31), int64_rprimitive)), + """cpy_r_a = -2147483648LL;""") + + def assert_emit(self, + op: Op, + expected: str, + next_block: Optional[BasicBlock] = None, + *, + rare: bool = False) -> None: block = BasicBlock(0) block.ops.append(op) value_names = generate_names_for_ir(self.registers, [block]) @@ -387,6 +407,7 @@ def assert_emit(self, op: Op, expected: str, next_block: Optional[BasicBlock] = visitor = FunctionEmitterVisitor(emitter, declarations, 'prog.py', 'prog') visitor.next_block = next_block + visitor.rare = rare op.accept(visitor) frags = declarations.fragments + emitter.fragments @@ -451,6 +472,7 @@ def test_register(self) -> None: reg = Register(int_rprimitive) op = Assign(reg, Integer(5)) self.block.ops.append(op) + self.block.ops.append(Unreachable()) fn = FuncIR(FuncDecl('myfunc', None, 'mod', FuncSignature([self.arg], list_rprimitive)), [self.reg], [self.block]) @@ -464,6 +486,7 @@ def test_register(self) -> None: ' CPyTagged cpy_r_r0;\n', 'CPyL0: ;\n', ' cpy_r_r0 = 10;\n', + ' CPy_Unreachable();\n', '}\n', ], result, msg='Generated code invalid') diff --git a/mypyc/test/test_exceptions.py b/mypyc/test/test_exceptions.py index 67df5ce5c38a..802024f2c86b 100644 --- a/mypyc/test/test_exceptions.py +++ b/mypyc/test/test_exceptions.py @@ -18,9 +18,11 @@ ICODE_GEN_BUILTINS, use_custom_builtins, MypycDataSuite, build_ir_for_single_file, assert_test_output, remove_comment_lines ) +from mypyc.analysis.blockfreq import frequently_executed_blocks files = [ - 'exceptions.test' + 'exceptions.test', + 'exceptions-freq.test', ] @@ -46,6 +48,9 @@ def run_case(self, testcase: DataDrivenTestCase) -> None: insert_exception_handling(fn) insert_ref_count_opcodes(fn) actual.extend(format_func(fn)) + if testcase.name.endswith('_freq'): + common = frequently_executed_blocks(fn.blocks[0]) + actual.append('hot blocks: %s' % sorted(b.label for b in common)) assert_test_output(testcase, actual, 'Invalid source code output', expected_output) diff --git a/mypyc/test/test_irbuild.py b/mypyc/test/test_irbuild.py index 80d9f8df72d3..12da67b8dc1a 100644 --- a/mypyc/test/test_irbuild.py +++ b/mypyc/test/test_irbuild.py @@ -36,6 +36,7 @@ 'irbuild-isinstance.test', 'irbuild-dunders.test', 'irbuild-singledispatch.test', + 'irbuild-constant-fold.test', ] diff --git a/mypyc/test/test_ircheck.py b/mypyc/test/test_ircheck.py new file mode 100644 index 000000000000..28d3c8e8c25d --- /dev/null +++ b/mypyc/test/test_ircheck.py @@ -0,0 +1,95 @@ +import unittest +from typing import List + +from mypyc.analysis.ircheck import check_func_ir, FnError +from mypyc.ir.rtypes import none_rprimitive +from mypyc.ir.ops import BasicBlock, Op, Return, Integer, Goto +from mypyc.ir.func_ir import FuncIR, FuncDecl, FuncSignature +from mypyc.ir.pprint import format_func + + +def assert_has_error(fn: FuncIR, error: FnError) -> None: + errors = check_func_ir(fn) + assert errors == [error] + + +def assert_no_errors(fn: FuncIR) -> None: + assert not check_func_ir(fn) + + +NONE_VALUE = Integer(0, rtype=none_rprimitive) + + +class TestIrcheck(unittest.TestCase): + def setUp(self) -> None: + self.label = 0 + + def basic_block(self, ops: List[Op]) -> BasicBlock: + self.label += 1 + block = BasicBlock(self.label) + block.ops = ops + return block + + def func_decl(self, name: str) -> FuncDecl: + return FuncDecl(name=name, class_name=None, module_name="module", sig=FuncSignature( + args=[], ret_type=none_rprimitive, + )) + + def test_valid_fn(self) -> None: + assert_no_errors(FuncIR( + decl=self.func_decl(name="func_1"), + arg_regs=[], + blocks=[self.basic_block(ops=[ + Return(value=NONE_VALUE), + ])], + )) + + def test_block_not_terminated_empty_block(self) -> None: + block = self.basic_block([]) + fn = FuncIR( + decl=self.func_decl(name="func_1"), + arg_regs=[], + blocks=[block], + ) + assert_has_error(fn, FnError(source=block, desc="Block not terminated")) + + def test_valid_goto(self) -> None: + block_1 = self.basic_block([Return(value=NONE_VALUE)]) + block_2 = self.basic_block([Goto(label=block_1)]) + fn = FuncIR( + decl=self.func_decl(name="func_1"), + arg_regs=[], + blocks=[block_1, block_2], + ) + assert_no_errors(fn) + + def test_invalid_goto(self) -> None: + block_1 = self.basic_block([Return(value=NONE_VALUE)]) + goto = Goto(label=block_1) + block_2 = self.basic_block([goto]) + fn = FuncIR( + decl=self.func_decl(name="func_1"), + arg_regs=[], + # block_1 omitted + blocks=[block_2], + ) + assert_has_error(fn, FnError(source=goto, desc="Invalid control operation target: 1")) + + def test_pprint(self) -> None: + block_1 = self.basic_block([Return(value=NONE_VALUE)]) + goto = Goto(label=block_1) + block_2 = self.basic_block([goto]) + fn = FuncIR( + decl=self.func_decl(name="func_1"), + arg_regs=[], + # block_1 omitted + blocks=[block_2], + ) + errors = [(goto, "Invalid control operation target: 1")] + formatted = format_func(fn, errors) + assert formatted == [ + "def func_1():", + "L0:", + " goto L1", + " ERR: Invalid control operation target: 1", + ] diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index 731f53c6a3f5..306c151ef319 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -52,8 +52,10 @@ 'run-bench.test', 'run-mypy-sim.test', 'run-dunders.test', - 'run-singledispatch.test' + 'run-singledispatch.test', + 'run-attrs.test', ] + if sys.version_info >= (3, 7): files.append('run-python37.test') if sys.version_info >= (3, 8): @@ -242,6 +244,7 @@ def run_case_step(self, testcase: DataDrivenTestCase, incremental_step: int) -> check_serialization_roundtrip(ir) opt_level = int(os.environ.get('MYPYC_OPT_LEVEL', 0)) + debug_level = int(os.environ.get('MYPYC_DEBUG_LEVEL', 0)) setup_file = os.path.abspath(os.path.join(WORKDIR, 'setup.py')) # We pass the C file information to the build script via setup.py unfortunately @@ -250,7 +253,8 @@ def run_case_step(self, testcase: DataDrivenTestCase, incremental_step: int) -> separate, cfiles, self.multi_file, - opt_level)) + opt_level, + debug_level)) if not run_setup(setup_file, ['build_ext', '--inplace']): if testcase.config.getoption('--mypyc-showc'): diff --git a/mypyc/test/testutil.py b/mypyc/test/testutil.py index a98fd6917b18..985356bc469b 100644 --- a/mypyc/test/testutil.py +++ b/mypyc/test/testutil.py @@ -15,6 +15,7 @@ from mypy.test.helpers import assert_string_arrays_equal from mypyc.options import CompilerOptions +from mypyc.analysis.ircheck import assert_func_ir_valid from mypyc.ir.func_ir import FuncIR from mypyc.errors import Errors from mypyc.irbuild.main import build_ir @@ -118,6 +119,8 @@ def build_ir_for_single_file(input_lines: List[str], raise CompileError(errors.new_messages()) module = list(modules.values())[0] + for fn in module.functions: + assert_func_ir_valid(fn) return module.functions diff --git a/pytest.ini b/pytest.ini index b01fcdad0e45..b164c14b6414 100644 --- a/pytest.ini +++ b/pytest.ini @@ -19,7 +19,9 @@ python_classes = python_functions = # always run in parallel (requires pytest-xdist, see test-requirements.txt) -addopts = -nauto +# and enable strict mode: require all markers +# to be defined and raise on invalid config values +addopts = -nauto --strict-markers --strict-config # treat xpasses as test failures so they get converted to regular tests as soon as possible xfail_strict = true diff --git a/setup.cfg b/setup.cfg index 8dd54a52825d..c7adc285db7b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -43,9 +43,8 @@ exclude = # B007: Loop control variable not used within the loop body. # B011: Don't use assert False # F821: Name not defined (generates false positives with error codes) -# F811: Redefinition of unused function (causes annoying errors with overloads) # E741: Ambiguous variable name -extend-ignore = E128,W601,E701,E704,E402,B3,B006,B007,B011,F821,F811,E741 +extend-ignore = E128,W601,E701,E704,E402,B3,B006,B007,B011,F821,E741 [coverage:run] branch = true diff --git a/setup.py b/setup.py index 04cd455070d7..10042279a446 100644 --- a/setup.py +++ b/setup.py @@ -144,10 +144,12 @@ def run(self): from mypyc.build import mypycify opt_level = os.getenv('MYPYC_OPT_LEVEL', '3') + debug_level = os.getenv('MYPYC_DEBUG_LEVEL', '1') force_multifile = os.getenv('MYPYC_MULTI_FILE', '') == '1' ext_modules = mypycify( mypyc_targets + ['--config-file=mypy_bootstrap.ini'], opt_level=opt_level, + debug_level=debug_level, # Use multi-file compilation mode on windows because without it # our Appveyor builds run out of memory sometimes. multi_file=sys.platform == 'win32' or force_multifile, @@ -166,6 +168,7 @@ def run(self): 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', 'Topic :: Software Development', ] @@ -181,22 +184,22 @@ def run(self): ext_modules=ext_modules, packages=find_packages(), package_data={'mypy': package_data}, - scripts=['scripts/mypyc'], 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. - install_requires=["typed_ast >= 1.4.0, < 1.5.0; python_version<'3.8'", - 'typing_extensions>=3.7.4', - 'mypy_extensions >= 0.4.3, < 0.5.0', - 'tomli>=1.1.0,<1.2.0', + install_requires=["typed_ast >= 1.4.0, < 2; python_version<'3.8'", + 'typing_extensions>=3.10', + 'mypy_extensions >= 0.4.3', + 'tomli>=1.1.0', ], # Same here. - extras_require={'dmypy': 'psutil >= 4.0', 'python2': 'typed_ast >= 1.4.0, < 1.5.0'}, + extras_require={'dmypy': 'psutil >= 4.0', 'python2': 'typed_ast >= 1.4.0, < 2'}, python_requires=">=3.6", include_package_data=True, project_urls={ diff --git a/mypy/test/collect.py b/test-data/packages/modulefinder-site-packages/ns_pkg_w_stubs-stubs/typed/__init__.pyi similarity index 100% rename from mypy/test/collect.py rename to test-data/packages/modulefinder-site-packages/ns_pkg_w_stubs-stubs/typed/__init__.pyi diff --git a/test-data/packages/typedpkg_ns/typedpkg_ns/ns/__init__.py b/test-data/packages/modulefinder-site-packages/ns_pkg_w_stubs/typed/__init__.py similarity index 100% rename from test-data/packages/typedpkg_ns/typedpkg_ns/ns/__init__.py rename to test-data/packages/modulefinder-site-packages/ns_pkg_w_stubs/typed/__init__.py diff --git a/test-data/packages/typedpkg_ns/typedpkg_ns/ns/py.typed b/test-data/packages/modulefinder-site-packages/ns_pkg_w_stubs/typed_inline/__init__.py similarity index 100% rename from test-data/packages/typedpkg_ns/typedpkg_ns/ns/py.typed rename to test-data/packages/modulefinder-site-packages/ns_pkg_w_stubs/typed_inline/__init__.py diff --git a/test-data/packages/modulefinder-site-packages/ns_pkg_w_stubs/typed_inline/py.typed b/test-data/packages/modulefinder-site-packages/ns_pkg_w_stubs/typed_inline/py.typed new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/modulefinder-site-packages/ns_pkg_w_stubs/untyped/__init__.py b/test-data/packages/modulefinder-site-packages/ns_pkg_w_stubs/untyped/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/typedpkg-stubs/setup.py b/test-data/packages/typedpkg-stubs/setup.py index 58d8fa968cc3..4948dc6a01df 100644 --- a/test-data/packages/typedpkg-stubs/setup.py +++ b/test-data/packages/typedpkg-stubs/setup.py @@ -2,7 +2,7 @@ This setup file installs packages to test mypy's PEP 561 implementation """ -from distutils.core import setup +from setuptools import setup setup( name='typedpkg-stubs', diff --git a/test-data/packages/typedpkg_ns/setup.py b/test-data/packages/typedpkg_ns_a/setup.py similarity index 50% rename from test-data/packages/typedpkg_ns/setup.py rename to test-data/packages/typedpkg_ns_a/setup.py index 9285e89104bb..3dab731cada9 100644 --- a/test-data/packages/typedpkg_ns/setup.py +++ b/test-data/packages/typedpkg_ns_a/setup.py @@ -1,10 +1,10 @@ -from setuptools import setup, find_packages +from setuptools import setup setup( name='typedpkg_namespace.alpha', version='1.0.0', - packages=find_packages(), namespace_packages=['typedpkg_ns'], zip_safe=False, - package_data={'typedpkg_ns.ns': ['py.typed']} + package_data={'typedpkg_ns.a': ['py.typed']}, + packages=['typedpkg_ns.a'], ) diff --git a/test-data/packages/typedpkg_ns/typedpkg_ns/__init__.py b/test-data/packages/typedpkg_ns_a/typedpkg_ns/__init__.py similarity index 100% rename from test-data/packages/typedpkg_ns/typedpkg_ns/__init__.py rename to test-data/packages/typedpkg_ns_a/typedpkg_ns/__init__.py diff --git a/test-data/packages/typedpkg_ns_a/typedpkg_ns/a/__init__.py b/test-data/packages/typedpkg_ns_a/typedpkg_ns/a/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/typedpkg_ns/typedpkg_ns/ns/bbb.py b/test-data/packages/typedpkg_ns_a/typedpkg_ns/a/bbb.py similarity index 100% rename from test-data/packages/typedpkg_ns/typedpkg_ns/ns/bbb.py rename to test-data/packages/typedpkg_ns_a/typedpkg_ns/a/bbb.py diff --git a/test-data/packages/typedpkg_ns_a/typedpkg_ns/a/py.typed b/test-data/packages/typedpkg_ns_a/typedpkg_ns/a/py.typed new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/typedpkg_ns_b-stubs/setup.py b/test-data/packages/typedpkg_ns_b-stubs/setup.py new file mode 100644 index 000000000000..a5d7df83eeea --- /dev/null +++ b/test-data/packages/typedpkg_ns_b-stubs/setup.py @@ -0,0 +1,14 @@ +""" +This setup file installs packages to test mypy's PEP 561 implementation +""" + +from distutils.core import setup + +setup( + name='typedpkg_ns_b-stubs', + author="The mypy team", + version='0.1', + namespace_packages=['typedpkg_ns-stubs'], + package_data={'typedpkg_ns-stubs.b': ['__init__.pyi', 'bbb.pyi']}, + packages=['typedpkg_ns-stubs.b'], +) diff --git a/test-data/packages/typedpkg_ns_b-stubs/typedpkg_ns-stubs/b/__init__.pyi b/test-data/packages/typedpkg_ns_b-stubs/typedpkg_ns-stubs/b/__init__.pyi new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/typedpkg_ns_b-stubs/typedpkg_ns-stubs/b/bbb.pyi b/test-data/packages/typedpkg_ns_b-stubs/typedpkg_ns-stubs/b/bbb.pyi new file mode 100644 index 000000000000..e00e9e52c05f --- /dev/null +++ b/test-data/packages/typedpkg_ns_b-stubs/typedpkg_ns-stubs/b/bbb.pyi @@ -0,0 +1 @@ +def bf(a: bool) -> bool: ... diff --git a/test-data/packages/typedpkg_ns_b/setup.py b/test-data/packages/typedpkg_ns_b/setup.py new file mode 100644 index 000000000000..4f0d0d954a73 --- /dev/null +++ b/test-data/packages/typedpkg_ns_b/setup.py @@ -0,0 +1,10 @@ +from setuptools import setup + +setup( + name='typedpkg_namespace.beta', + version='1.0.0', + namespace_packages=['typedpkg_ns'], + zip_safe=False, + package_data={'typedpkg_ns.b': []}, + packages=['typedpkg_ns.b'], +) diff --git a/test-data/packages/typedpkg_ns_b/typedpkg_ns/__init__.py b/test-data/packages/typedpkg_ns_b/typedpkg_ns/__init__.py new file mode 100644 index 000000000000..3ac255b8a577 --- /dev/null +++ b/test-data/packages/typedpkg_ns_b/typedpkg_ns/__init__.py @@ -0,0 +1,2 @@ +# namespace pkg +__import__("pkg_resources").declare_namespace(__name__) diff --git a/test-data/packages/typedpkg_ns_b/typedpkg_ns/b/__init__.py b/test-data/packages/typedpkg_ns_b/typedpkg_ns/b/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-data/packages/typedpkg_ns_b/typedpkg_ns/b/bbb.py b/test-data/packages/typedpkg_ns_b/typedpkg_ns/b/bbb.py new file mode 100644 index 000000000000..f10802daace9 --- /dev/null +++ b/test-data/packages/typedpkg_ns_b/typedpkg_ns/b/bbb.py @@ -0,0 +1,2 @@ +def bf(a): + return not a diff --git a/test-data/stdlib-samples/3.2/random.py b/test-data/stdlib-samples/3.2/random.py index 7eecdfe04db4..82bda03f7e53 100644 --- a/test-data/stdlib-samples/3.2/random.py +++ b/test-data/stdlib-samples/3.2/random.py @@ -41,7 +41,7 @@ from math import log as _log, exp as _exp, pi as _pi, e as _e, ceil as _ceil from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin from os import urandom as _urandom -from collections import Set as _Set, Sequence as _Sequence +from collections.abc import Set as _Set, Sequence as _Sequence from hashlib import sha512 as _sha512 from typing import ( diff --git a/test-data/stdlib-samples/3.2/shutil.py b/test-data/stdlib-samples/3.2/shutil.py index e7b5e5aacd04..bcefb7787952 100644 --- a/test-data/stdlib-samples/3.2/shutil.py +++ b/test-data/stdlib-samples/3.2/shutil.py @@ -58,7 +58,7 @@ class ReadError(EnvironmentError): """Raised when an archive cannot be read""" class RegistryError(Exception): - """Raised when a registery operation with the archiving + """Raised when a registry operation with the archiving and unpacking registeries fails""" @@ -676,7 +676,7 @@ def register_unpack_format(name: str, extensions: List[str], function: Any, _UNPACK_FORMATS[name] = extensions, function, extra_args, description def unregister_unpack_format(name: str) -> None: - """Removes the pack format from the registery.""" + """Removes the pack format from the registry.""" del _UNPACK_FORMATS[name] def _ensure_directory(path: str) -> None: diff --git a/test-data/unit/README.md b/test-data/unit/README.md index a84afa8e20af..06a5b77ef769 100644 --- a/test-data/unit/README.md +++ b/test-data/unit/README.md @@ -82,17 +82,17 @@ Running tests and linting First install any additional dependencies needed for testing: - $ python3 -m pip install -U -r test-requirements.txt + python3 -m pip install -U -r test-requirements.txt You must also have a Python 2.7 binary installed that can import the `typing` module: - $ python2 -m pip install -U typing + python2 -m pip install -U typing The unit test suites are driven by the `pytest` framework. To run all mypy tests, run `pytest` in the mypy repository: - $ pytest -q mypy + pytest -q mypy This will run all tests, including integration and regression tests, and will verify that all stubs are valid. This may take several @@ -106,59 +106,59 @@ Note that some tests will be disabled for older python versions. If you work on mypyc, you will want to also run mypyc tests: - $ pytest -q mypyc + pytest -q mypyc You can run tests from a specific module directly, a specific suite within a module, or a test in a suite (even if it's data-driven): - $ pytest -q mypy/test/testdiff.py + pytest -q mypy/test/testdiff.py - $ pytest -q mypy/test/testsemanal.py::SemAnalTypeInfoSuite + pytest -q mypy/test/testsemanal.py::SemAnalTypeInfoSuite - $ pytest -n0 mypy/test/testargs.py::ArgSuite::test_coherence + pytest -n0 mypy/test/testargs.py::ArgSuite::test_coherence - $ pytest -n0 mypy/test/testcheck.py::TypeCheckSuite::testCallingVariableWithFunctionType + pytest -n0 mypy/test/testcheck.py::TypeCheckSuite::testCallingVariableWithFunctionType To control which tests are run and how, you can use the `-k` switch: - $ pytest -q -k "MethodCall" + pytest -q -k "MethodCall" You can also run the type checker for manual testing without installing it by setting up the Python module search path suitably: - $ export PYTHONPATH=$PWD - $ python3 -m mypy PROGRAM.py + export PYTHONPATH=$PWD + python3 -m mypy PROGRAM.py You will have to manually install the `typing` module if you're running Python 3.4 or earlier. You can also execute mypy as a module - $ python3 -m mypy PROGRAM.py + python3 -m mypy PROGRAM.py You can check a module or string instead of a file: - $ python3 -m mypy PROGRAM.py - $ python3 -m mypy -m MODULE - $ python3 -m mypy -c 'import MODULE' + python3 -m mypy PROGRAM.py + python3 -m mypy -m MODULE + python3 -m mypy -c 'import MODULE' To run mypy on itself: - $ python3 -m mypy --config-file mypy_self_check.ini -p mypy + python3 -m mypy --config-file mypy_self_check.ini -p mypy To run the linter: - $ flake8 + flake8 You can also run all of the above tests using `runtests.py` (this includes type checking mypy and linting): - $ python3 runtests.py + python3 runtests.py By default, this runs everything except some mypyc tests. You can give it arguments to control what gets run, such as `self` to run mypy on itself: - $ python3 runtests.py self + python3 runtests.py self Run `python3 runtests.py mypyc-extra` to run mypyc tests that are not enabled by default. This is typically only needed if you work on mypyc. @@ -187,7 +187,7 @@ Debugging You can use interactive debuggers like `pdb` to debug failing tests. You need to pass the `-n0` option to disable parallelization: - $ pytest -n0 --pdb -k MethodCall + pytest -n0 --pdb -k MethodCall You can also write `import pdb; pdb.set_trace()` in code to enter the debugger. @@ -195,7 +195,7 @@ debugger. The `--mypy-verbose` flag can be used to enable additional debug output from most tests (as if `--verbose` had been passed to mypy): - $ pytest -n0 --mypy-verbose -k MethodCall + pytest -n0 --mypy-verbose -k MethodCall Coverage reports ---------------- diff --git a/test-data/unit/check-abstract.test b/test-data/unit/check-abstract.test index 6653768aae46..6f3318a87683 100644 --- a/test-data/unit/check-abstract.test +++ b/test-data/unit/check-abstract.test @@ -446,7 +446,7 @@ class A(I): [out] main:10: error: Signature of "g" incompatible with supertype "I" main:10: note: Superclass: -main:10: note: def g(x: Any) -> Any +main:10: note: def g(self, x: Any) -> Any main:10: note: Subclass: main:10: note: def g(self, x: Any, y: Any) -> None @@ -600,7 +600,7 @@ a.f(B()) # E: No overload variant of "f" of "A" matches argument type "B" \ # N: def f(self, x: int) -> int \ # N: def f(self, x: str) -> str -[case testOverloadedAbstractMethodVariantMissingDecorator1] +[case testOverloadedAbstractMethodVariantMissingDecorator0] from foo import * [file foo.pyi] from abc import abstractmethod, ABCMeta diff --git a/test-data/unit/check-annotated.test b/test-data/unit/check-annotated.test index e1eac154c72e..68862087d13d 100644 --- a/test-data/unit/check-annotated.test +++ b/test-data/unit/check-annotated.test @@ -126,3 +126,34 @@ class Meta: x = Annotated[int, Meta()] reveal_type(x) # N: Revealed type is "def () -> builtins.int" [builtins fixtures/tuple.pyi] + +[case testAnnotatedStringLiteralInFunc] +from typing import TypeVar +from typing_extensions import Annotated +def f1(a: Annotated[str, "metadata"]): + pass +reveal_type(f1) # N: Revealed type is "def (a: builtins.str) -> Any" +def f2(a: Annotated["str", "metadata"]): + pass +reveal_type(f2) # N: Revealed type is "def (a: builtins.str) -> Any" +def f3(a: Annotated["notdefined", "metadata"]): # E: Name "notdefined" is not defined + pass +T = TypeVar('T') +def f4(a: Annotated[T, "metatdata"]): + pass +reveal_type(f4) # N: Revealed type is "def [T] (a: T`-1) -> Any" +[builtins fixtures/tuple.pyi] + +[case testSliceAnnotated39] +# flags: --python-version 3.9 +from typing_extensions import Annotated +a: Annotated[int, 1:2] +reveal_type(a) # N: Revealed type is "builtins.int" +[builtins fixtures/tuple.pyi] + +[case testSliceAnnotated38] +# flags: --python-version 3.8 +from typing_extensions import Annotated +a: Annotated[int, 1:2] +reveal_type(a) # N: Revealed type is "builtins.int" +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/check-attr.test b/test-data/unit/check-attr.test index f8dcfd811e01..e7cea6c27b99 100644 --- a/test-data/unit/check-attr.test +++ b/test-data/unit/check-attr.test @@ -502,7 +502,7 @@ reveal_type(sub_str.attr) # N: Revealed type is "builtins.str*" [builtins fixtures/bool.pyi] -[case testAttrsGenericInheritance] +[case testAttrsGenericInheritance2] from typing import Generic, TypeVar import attr @@ -1402,3 +1402,33 @@ class A: reveal_type(A.__attrs_attrs__) # N: Revealed type is "Tuple[attr.Attribute[builtins.int], attr.Attribute[builtins.str]]" [builtins fixtures/attr.pyi] + +[case testAttrsClassWithSlots] +import attr + +@attr.s(slots=True) +class A: + b: int = attr.ib() + + def __attrs_post_init__(self) -> None: + self.b = 1 + self.c = 2 # E: Trying to assign name "c" that is not in "__slots__" of type "__main__.A" + +@attr.dataclass(slots=True) +class B: + __slots__ = () # would be replaced + b: int + + def __attrs_post_init__(self) -> None: + self.b = 1 + self.c = 2 # E: Trying to assign name "c" that is not in "__slots__" of type "__main__.B" + +@attr.dataclass(slots=False) +class C: + __slots__ = () # would not be replaced + b: int + + def __attrs_post_init__(self) -> None: + self.b = 1 # E: Trying to assign name "b" that is not in "__slots__" of type "__main__.C" + self.c = 2 # E: Trying to assign name "c" that is not in "__slots__" of type "__main__.C" +[builtins fixtures/attr.pyi] diff --git a/test-data/unit/check-basic.test b/test-data/unit/check-basic.test index 184c9e58ca58..03dee485c848 100644 --- a/test-data/unit/check-basic.test +++ b/test-data/unit/check-basic.test @@ -401,9 +401,18 @@ def foo( [case testNoneHasBool] none = None b = none.__bool__() -reveal_type(b) # N: Revealed type is "builtins.bool" +reveal_type(b) # N: Revealed type is "Literal[False]" [builtins fixtures/bool.pyi] +[case testNoneHasBoolShowNoneErrorsFalse] +none = None +b = none.__bool__() +reveal_type(b) # N: Revealed type is "Literal[False]" +[builtins fixtures/bool.pyi] +[file mypy.ini] +\[mypy] +show_none_errors = False + [case testAssignmentInvariantNoteForList] from typing import List x: List[int] diff --git a/test-data/unit/check-bound.test b/test-data/unit/check-bound.test index a137132ebc67..bf13ef874579 100644 --- a/test-data/unit/check-bound.test +++ b/test-data/unit/check-bound.test @@ -39,7 +39,7 @@ class G(Generic[T]): v = None # type: G[A] w = None # type: G[B] -x = None # type: G[str] # E: Type argument "builtins.str" of "G" must be a subtype of "__main__.A" +x = None # type: G[str] # E: Type argument "str" of "G" must be a subtype of "A" y = G('a') # E: Value of type variable "T" of "G" cannot be "str" z = G(A()) z = G(B()) @@ -93,9 +93,9 @@ TA = TypeVar('TA', bound=A) class C(Generic[TA]): pass class D0(C[TA], Generic[TA]): pass -class D1(C[T], Generic[T]): pass # E: Type argument "T`1" of "C" must be a subtype of "__main__.A" +class D1(C[T], Generic[T]): pass # E: Type argument "T" of "C" must be a subtype of "A" class D2(C[A]): pass -class D3(C[str]): pass # E: Type argument "builtins.str" of "C" must be a subtype of "__main__.A" +class D3(C[str]): pass # E: Type argument "str" of "C" must be a subtype of "A" -- Using information from upper bounds diff --git a/test-data/unit/check-callable.test b/test-data/unit/check-callable.test index ee1c84edf185..697a323f2365 100644 --- a/test-data/unit/check-callable.test +++ b/test-data/unit/check-callable.test @@ -223,6 +223,56 @@ else: [builtins fixtures/callable.pyi] +[case testDecoratedCallMethods] +from typing import Any, Callable, Union, TypeVar + +F = TypeVar('F', bound=Callable) + +def decorator(f: F) -> F: + pass +def change(f: Callable) -> Callable[[Any], str]: + pass +def untyped(f): + pass + +class Some1: + @decorator + def __call__(self) -> int: + pass +class Some2: + @change + def __call__(self) -> int: + pass +class Some3: + @untyped + def __call__(self) -> int: + pass +class Some4: + __call__: Any + +s1: Some1 +s2: Some2 +s3: Some3 +s4: Some4 + +if callable(s1): + 1 + 'a' # E: Unsupported operand types for + ("int" and "str") +else: + 2 + 'b' +if callable(s2): + 1 + 'a' # E: Unsupported operand types for + ("int" and "str") +else: + 2 + 'b' +if callable(s3): + 1 + 'a' # E: Unsupported operand types for + ("int" and "str") +else: + 2 + 'b' # E: Unsupported operand types for + ("int" and "str") +if callable(s4): + 1 + 'a' # E: Unsupported operand types for + ("int" and "str") +else: + 2 + 'b' # E: Unsupported operand types for + ("int" and "str") +[builtins fixtures/callable.pyi] + [case testCallableNestedUnions] from typing import Callable, Union @@ -484,3 +534,56 @@ reveal_type(_TYPE) # N: Revealed type is "def (x: Any) -> builtins.type" _TYPE('bar') [builtins fixtures/callable.pyi] + +[case testErrorMessageAboutSelf] +# https://github.com/python/mypy/issues/11309 +class Some: + def method(self, a) -> None: pass + @classmethod + def cls_method(cls, a) -> None: pass + @staticmethod + def st_method(a) -> None: pass + + def bad_method(a) -> None: pass + @classmethod + def bad_cls_method(a) -> None: pass + @staticmethod + def bad_st_method() -> None: pass + +s: Some + +s.method(1) +s.cls_method(1) +Some.cls_method(1) +s.st_method(1) +Some.st_method(1) + +s.method(1, 2) # E: Too many arguments for "method" of "Some" +s.cls_method(1, 2) # E: Too many arguments for "cls_method" of "Some" +Some.cls_method(1, 2) # E: Too many arguments for "cls_method" of "Some" +s.st_method(1, 2) # E: Too many arguments for "st_method" of "Some" +Some.st_method(1, 2) # E: Too many arguments for "st_method" of "Some" + +s.bad_method(1) # E: Too many arguments for "bad_method" of "Some" \ + # N: Looks like the first special argument in a method is not named "self", "cls", or "mcs", maybe it is missing? +s.bad_cls_method(1) # E: Too many arguments for "bad_cls_method" of "Some" \ + # N: Looks like the first special argument in a method is not named "self", "cls", or "mcs", maybe it is missing? +Some.bad_cls_method(1) # E: Too many arguments for "bad_cls_method" of "Some" \ + # N: Looks like the first special argument in a method is not named "self", "cls", or "mcs", maybe it is missing? +s.bad_st_method(1) # E: Too many arguments for "bad_st_method" of "Some" +Some.bad_st_method(1) # E: Too many arguments for "bad_st_method" of "Some" +[builtins fixtures/callable.pyi] + +[case testClassMethodAliasStub] +from a import f +f("no") # E: Argument 1 has incompatible type "str"; expected "int" +[file a.pyi] +from b import C +f = C.f +[file b.pyi] +import a +class C(B): + @classmethod + def f(self, x: int) -> C: ... +class B: ... +[builtins fixtures/classmethod.pyi] diff --git a/test-data/unit/check-class-namedtuple.test b/test-data/unit/check-class-namedtuple.test index a6a30f7731e9..cf3af49ab3a4 100644 --- a/test-data/unit/check-class-namedtuple.test +++ b/test-data/unit/check-class-namedtuple.test @@ -270,7 +270,7 @@ a = A(B()) a = A(1) # E: Argument 1 to "A" has incompatible type "int"; expected "B" [builtins fixtures/tuple.pyi] -[case testNewNamedTupleProperty] +[case testNewNamedTupleProperty36] # flags: --python-version 3.6 from typing import NamedTuple diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index ee58d98d0675..a2bcdade3287 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -114,6 +114,43 @@ class A: A().f = None # E: Cannot assign to a method +[case testOverrideAttributeWithMethod] +# This was crashing: +# https://github.com/python/mypy/issues/10134 +from typing import Protocol + +class Base: + __hash__ = None + +class Derived(Base): + def __hash__(self) -> int: # E: Signature of "__hash__" incompatible with supertype "Base" + pass + +# Correct: + +class CallableProtocol(Protocol): + def __call__(self, arg: int) -> int: + pass + +class CorrectBase: + attr: CallableProtocol + +class CorrectDerived(CorrectBase): + def attr(self, arg: int) -> int: + pass + +[case testOverrideMethodWithAttribute] +# The reverse should not crash as well: +from typing import Callable + +class Base: + def __hash__(self) -> int: + pass + +class Derived(Base): + __hash__ = 1 # E: Incompatible types in assignment (expression has type "int", base class "Base" defined the type as "Callable[[Base], int]") + + -- Attributes -- ---------- @@ -2024,8 +2061,8 @@ class B: class C: def __radd__(self, other, oops) -> int: ... [out] -tmp/foo.pyi:3: error: Invalid signature "def (foo.B) -> foo.A" -tmp/foo.pyi:5: error: Invalid signature "def (foo.C, Any, Any) -> builtins.int" +tmp/foo.pyi:3: error: Invalid signature "Callable[[B], A]" +tmp/foo.pyi:5: error: Invalid signature "Callable[[C, Any, Any], int]" [case testReverseOperatorOrderingCase1] class A: @@ -2617,6 +2654,35 @@ b = a.bar [out] main:9: error: Incompatible types in assignment (expression has type "A", variable has type "B") +[case testDecoratedGetAttribute] +from typing import Callable, TypeVar + +T = TypeVar('T', bound=Callable) + +def decorator(f: T) -> T: + return f + +def bad(f: Callable) -> Callable[..., int]: + return f + +class A: + @decorator + def __getattribute__(self, x: str) -> A: + return A() +class B: + @bad # We test that type will be taken from decorated type, not node itself + def __getattribute__(self, x: str) -> A: + return A() + +a: A +b: B + +a1: A = a.foo +b1: B = a.bar # E: Incompatible types in assignment (expression has type "A", variable has type "B") +a2: A = b.baz # E: Incompatible types in assignment (expression has type "int", variable has type "A") +b2: B = b.roo # E: Incompatible types in assignment (expression has type "int", variable has type "B") +[builtins fixtures/tuple.pyi] + [case testGetattributeSignature] class A: def __getattribute__(self, x: str) -> A: pass @@ -2627,8 +2693,8 @@ class C: class D: def __getattribute__(self, x: str) -> None: pass [out] -main:4: error: Invalid signature "def (__main__.B, __main__.A) -> __main__.B" for "__getattribute__" -main:6: error: Invalid signature "def (__main__.C, builtins.str, builtins.str) -> __main__.C" for "__getattribute__" +main:4: error: Invalid signature "Callable[[B, A], B]" for "__getattribute__" +main:6: error: Invalid signature "Callable[[C, str, str], C]" for "__getattribute__" [case testGetattr] @@ -2644,6 +2710,35 @@ b = a.bar [out] main:9: error: Incompatible types in assignment (expression has type "A", variable has type "B") +[case testDecoratedGetattr] +from typing import Callable, TypeVar + +T = TypeVar('T', bound=Callable) + +def decorator(f: T) -> T: + return f + +def bad(f: Callable) -> Callable[..., int]: + return f + +class A: + @decorator + def __getattr__(self, x: str) -> A: + return A() +class B: + @bad # We test that type will be taken from decorated type, not node itself + def __getattr__(self, x: str) -> A: + return A() + +a: A +b: B + +a1: A = a.foo +b1: B = a.bar # E: Incompatible types in assignment (expression has type "A", variable has type "B") +a2: A = b.baz # E: Incompatible types in assignment (expression has type "int", variable has type "A") +b2: B = b.roo # E: Incompatible types in assignment (expression has type "int", variable has type "B") +[builtins fixtures/tuple.pyi] + [case testGetattrWithGetitem] class A: def __getattr__(self, x: str) -> 'A': @@ -2704,8 +2799,8 @@ class C: class D: def __getattr__(self, x: str) -> None: pass [out] -main:4: error: Invalid signature "def (__main__.B, __main__.A) -> __main__.B" for "__getattr__" -main:6: error: Invalid signature "def (__main__.C, builtins.str, builtins.str) -> __main__.C" for "__getattr__" +main:4: error: Invalid signature "Callable[[B, A], B]" for "__getattr__" +main:6: error: Invalid signature "Callable[[C, str, str], C]" for "__getattr__" [case testSetattr] from typing import Union, Any @@ -2729,7 +2824,7 @@ c = C() c.fail = 4 # E: Incompatible types in assignment (expression has type "int", variable has type "str") class D: - __setattr__ = 'hello' # E: Invalid signature "builtins.str" for "__setattr__" + __setattr__ = 'hello' # E: Invalid signature "str" for "__setattr__" d = D() d.crash = 4 # E: "D" has no attribute "crash" @@ -2750,16 +2845,45 @@ s = Sub() s.success = 4 s.fail = 'fail' # E: Incompatible types in assignment (expression has type "str", variable has type "int") +[case testDecoratedSetattr] +from typing import Any, Callable, TypeVar + +T = TypeVar('T', bound=Callable) + +def decorator(f: T) -> T: + return f + +def bad(f: Callable) -> Callable[[Any, str, int], None]: + return f + +class A: + @decorator + def __setattr__(self, k: str, v: str) -> None: + pass +class B: + @bad # We test that type will be taken from decorated type, not node itself + def __setattr__(self, k: str, v: str) -> None: + pass + +a: A +a.foo = 'a' +a.bar = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "str") + +b: B +b.good = 1 +b.bad = 'a' # E: Incompatible types in assignment (expression has type "str", variable has type "int") +[builtins fixtures/tuple.pyi] + [case testSetattrSignature] from typing import Any class Test: - def __setattr__() -> None: ... # E: Method must have at least one argument # E: Invalid signature "def ()" for "__setattr__" + def __setattr__() -> None: ... # E: Method must have at least one argument # E: Invalid signature "Callable[[], None]" for "__setattr__" t = Test() t.crash = 'test' # E: "Test" has no attribute "crash" class A: - def __setattr__(self): ... # E: Invalid signature "def (__main__.A) -> Any" for "__setattr__" + def __setattr__(self): ... # E: Invalid signature "Callable[[A], Any]" for "__setattr__" a = A() a.test = 4 # E: "A" has no attribute "test" @@ -2769,7 +2893,7 @@ b = B() b.integer = 5 class C: - def __setattr__(self, name: int, value: int) -> None: ... # E: Invalid signature "def (__main__.C, builtins.int, builtins.int)" for "__setattr__" + def __setattr__(self, name: int, value: int) -> None: ... # E: Invalid signature "Callable[[C, int, int], None]" for "__setattr__" c = C() c.check = 13 @@ -2794,6 +2918,15 @@ b.at = '3' # E: Incompatible types in assignment (expression has type "str", va if int(): integer = b.at # E: Incompatible types in assignment (expression has type "str", variable has type "int") +[case testSetattrKeywordArg] +from typing import Any + +class C: + def __setattr__(self, key: str, value: Any, p: bool = False) -> None: ... + +c: C +c.__setattr__("x", 42, p=True) + -- CallableType objects -- ---------------- @@ -2835,7 +2968,7 @@ C(foo='') # E: Argument "foo" to "C" has incompatible type "str"; expected "Opti [case testConstructInstanceWithDynamicallyTyped__new__] class C: - def __new__(cls, foo): + def __new__(cls, foo): # N: "C" defined here obj = object.__new__(cls) return obj @@ -2897,9 +3030,9 @@ c = C(1) c.a # E: "C" has no attribute "a" C('', '') C('') # E: No overload variant of "C" matches argument type "str" \ - # N: Possible overload variant: \ + # N: Possible overload variants: \ # N: def __new__(cls, foo: int) -> C \ - # N: <1 more non-matching overload not shown> + # N: def __new__(cls, x: str, y: str) -> C [builtins fixtures/__new__.pyi] @@ -3325,9 +3458,9 @@ u = new(User) [builtins fixtures/classmethod.pyi] [out] tmp/foo.pyi:17: error: No overload variant of "User" matches argument type "str" -tmp/foo.pyi:17: note: Possible overload variant: +tmp/foo.pyi:17: note: Possible overload variants: +tmp/foo.pyi:17: note: def __init__(self) -> U tmp/foo.pyi:17: note: def __init__(self, arg: int) -> U -tmp/foo.pyi:17: note: <1 more non-matching overload not shown> tmp/foo.pyi:18: error: Too many arguments for "foo" of "User" [case testTypeUsingTypeCInUpperBound] @@ -5500,8 +5633,8 @@ A = G x: A[B[int]] # E B = G [out] -main:8:4: error: Type argument "__main__.G[builtins.int]" of "G" must be a subtype of "builtins.str" -main:8:6: error: Type argument "builtins.int" of "G" must be a subtype of "builtins.str" +main:8:4: error: Type argument "G[int]" of "G" must be a subtype of "str" +main:8:6: error: Type argument "int" of "G" must be a subtype of "str" [case testExtremeForwardReferencing] from typing import TypeVar, Generic @@ -6070,6 +6203,85 @@ class C: reveal_type(self.spec) # N: Revealed type is "__main__.B" [builtins fixtures/bool.pyi] +[case testDecoratedDunderGet] +from typing import Any, Callable, TypeVar, Type + +F = TypeVar('F', bound=Callable) +T = TypeVar('T') + +def decorator(f: F) -> F: + return f + +def change(f: Callable) -> Callable[..., int]: + pass + +def untyped(f): + return f + +class A: ... + +class Descr1: + @decorator + def __get__(self, obj: T, typ: Type[T]) -> A: ... +class Descr2: + @change + def __get__(self, obj: T, typ: Type[T]) -> A: ... +class Descr3: + @untyped + def __get__(self, obj: T, typ: Type[T]) -> A: ... + +class C: + spec1 = Descr1() + spec2 = Descr2() + spec3 = Descr3() + +c: C +reveal_type(c.spec1) # N: Revealed type is "__main__.A" +reveal_type(c.spec2) # N: Revealed type is "builtins.int" +reveal_type(c.spec3) # N: Revealed type is "Any" +[builtins fixtures/bool.pyi] + +[case testDecoratedDunderSet] +from typing import Any, Callable, TypeVar, Type + +F = TypeVar('F', bound=Callable) +T = TypeVar('T') + +def decorator(f: F) -> F: + return f + +def change(f: Callable) -> Callable[[Any, Any, int], None]: + pass + +def untyped(f): + return f + +class A: ... + +class Descr1: + @decorator + def __set__(self, obj: T, value: A) -> None: ... +class Descr2: + @change + def __set__(self, obj: T, value: A) -> None: ... +class Descr3: + @untyped + def __set__(self, obj: T, value: A) -> None: ... + +class C: + spec1 = Descr1() + spec2 = Descr2() + spec3 = Descr3() + +c: C +c.spec1 = A() +c.spec1 = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "A") +c.spec2 = A() # E: Incompatible types in assignment (expression has type "A", variable has type "int") +c.spec2 = 1 +c.spec3 = A() +c.spec3 = 1 +[builtins fixtures/bool.pyi] + [case testClassLevelImport] # flags: --ignore-missing-imports class Test: @@ -6251,7 +6463,7 @@ class C(B): [out] main:4: error: Incompatible types in assignment (expression has type "str", base class "B" defined the type as "int") -[case testIgnorePrivateMethodsTypeCheck] +[case testIgnorePrivateMethodsTypeCheck2] class A: def __foo_(self) -> int: ... class B: @@ -6419,6 +6631,37 @@ class B(A): reveal_type(B()) # N: Revealed type is "__main__.B" +[case testNewReturnType10] +# https://github.com/python/mypy/issues/11398 +from typing import Type + +class MyMetaClass(type): + def __new__(cls, name, bases, attrs) -> Type['MyClass']: + pass + +class MyClass(metaclass=MyMetaClass): + pass + +[case testNewReturnType11] +# https://github.com/python/mypy/issues/11398 +class MyMetaClass(type): + def __new__(cls, name, bases, attrs) -> type: + pass + +class MyClass(metaclass=MyMetaClass): + pass + +[case testNewReturnType12] +# https://github.com/python/mypy/issues/11398 +from typing import Type + +class MyMetaClass(type): + def __new__(cls, name, bases, attrs) -> int: # E: Incompatible return type for "__new__" (returns "int", but must return a subtype of "type") + pass + +class MyClass(metaclass=MyMetaClass): + pass + [case testGenericOverride] from typing import Generic, TypeVar, Any diff --git a/test-data/unit/check-classvar.test b/test-data/unit/check-classvar.test index f572db7225f2..d84bc8d5bf9d 100644 --- a/test-data/unit/check-classvar.test +++ b/test-data/unit/check-classvar.test @@ -285,7 +285,7 @@ main:3: error: Cannot assign to class variable "x" via instance from typing import ClassVar, Generic, TypeVar T = TypeVar('T') class A(Generic[T]): - x: ClassVar[T] + x: ClassVar[T] # E: ClassVar cannot contain type variables @classmethod def foo(cls) -> T: return cls.x # OK @@ -308,7 +308,7 @@ from typing import ClassVar, Generic, Tuple, TypeVar, Union, Type T = TypeVar('T') U = TypeVar('U') class A(Generic[T, U]): - x: ClassVar[Union[T, Tuple[U, Type[U]]]] + x: ClassVar[Union[T, Tuple[U, Type[U]]]] # E: ClassVar cannot contain type variables @classmethod def foo(cls) -> Union[T, Tuple[U, Type[U]]]: return cls.x # OK diff --git a/test-data/unit/check-columns.test b/test-data/unit/check-columns.test index 88f7fb98c994..3220119748e3 100644 --- a/test-data/unit/check-columns.test +++ b/test-data/unit/check-columns.test @@ -135,7 +135,7 @@ def foobar(): pass [builtins fixtures/module.pyi] [case testColumnUnexpectedOrMissingKeywordArg] -def f(): pass +def f(): pass # N:1: "f" defined here # TODO: Point to "x" instead (f(x=1)) # E:2: Unexpected keyword argument "x" for "f" def g(*, x: int) -> None: pass @@ -402,7 +402,7 @@ from typing import TypeVar, List T = TypeVar('T', int, str) -def g(x): pass +def g(x): pass # N:1: "g" defined here def f(x: T) -> T: (x.bad) # E:6: "int" has no attribute "bad" \ diff --git a/test-data/unit/check-custom-plugin.test b/test-data/unit/check-custom-plugin.test index 7c85881363d6..2707d886d64e 100644 --- a/test-data/unit/check-custom-plugin.test +++ b/test-data/unit/check-custom-plugin.test @@ -213,6 +213,74 @@ class DerivedSignal(Signal[T]): ... \[mypy] plugins=/test-data/unit/plugins/attrhook.py +[case testAttributeTypeHookPluginUntypedDecoratedGetattr] +# flags: --config-file tmp/mypy.ini +from m import Magic, DerivedMagic + +magic = Magic() +reveal_type(magic.magic_field) # N: Revealed type is "builtins.str" +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" + +derived = DerivedMagic() +reveal_type(derived.magic_field) # N: Revealed type is "builtins.str" +derived.nonexistent_field # E: Field does not exist +reveal_type(derived.fallback_example) # N: Revealed type is "Any" + +[file m.py] +from typing import Any, Callable + +def decorator(f): + pass + +class Magic: + # Triggers plugin infrastructure: + @decorator + def __getattr__(self, x: Any) -> Any: ... + def non_magic_method(self) -> int: ... + non_magic_field: int + +class DerivedMagic(Magic): ... +[file mypy.ini] +\[mypy] +plugins=/test-data/unit/plugins/attrhook2.py + +[case testAttributeTypeHookPluginDecoratedGetattr] +# flags: --config-file tmp/mypy.ini +from m import Magic, DerivedMagic + +magic = Magic() +reveal_type(magic.magic_field) # N: Revealed type is "builtins.str" +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 "builtins.bool" + +derived = DerivedMagic() +reveal_type(derived.magic_field) # N: Revealed type is "builtins.str" +derived.nonexistent_field # E: Field does not exist +reveal_type(derived.fallback_example) # N: Revealed type is "builtins.bool" + +[file m.py] +from typing import Any, Callable + +def decorator(f: Callable) -> Callable[[Any, str], bool]: + pass + +class Magic: + # Triggers plugin infrastructure: + @decorator + def __getattr__(self, x: Any) -> Any: ... + def non_magic_method(self) -> int: ... + non_magic_field: int + +class DerivedMagic(Magic): ... +[file mypy.ini] +\[mypy] +plugins=/test-data/unit/plugins/attrhook2.py + [case testAttributeHookPluginForDynamicClass] # flags: --config-file tmp/mypy.ini from m import Magic, DerivedMagic @@ -223,7 +291,12 @@ 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(DerivedMagic().magic_field) # N: Revealed type is "builtins.str" + +derived = DerivedMagic() +reveal_type(derived.magic_field) # N: Revealed type is "builtins.str" +derived.nonexistent_field # E: Field does not exist +reveal_type(magic.fallback_example) # N: Revealed type is "Any" + [file m.py] from typing import Any class Magic: @@ -543,26 +616,23 @@ class Instr(Generic[T]): ... \[mypy] plugins=/test-data/unit/plugins/dyn_class.py -[case testDynamicClassPluginNegatives] +[case testDynamicClassPluginChainCall] # flags: --config-file tmp/mypy.ini -from mod import declarative_base, Column, Instr, non_declarative_base +from mod import declarative_base, Column, Instr -Bad1 = non_declarative_base() -Bad2 = Bad3 = declarative_base() +Base = declarative_base().with_optional_xxx() -class C1(Bad1): ... # E: Variable "__main__.Bad1" is not valid as a type \ - # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases \ - # E: Invalid base class "Bad1" -class C2(Bad2): ... # E: Variable "__main__.Bad2" is not valid as a type \ - # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases \ - # E: Invalid base class "Bad2" -class C3(Bad3): ... # E: Variable "__main__.Bad3" is not valid as a type \ - # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases \ - # E: Invalid base class "Bad3" +class Model(Base): + x: Column[int] + +reveal_type(Model().x) # N: Revealed type is "mod.Instr[builtins.int]" [file mod.py] from typing import Generic, TypeVar -def declarative_base(): ... -def non_declarative_base(): ... + +class Base: + def with_optional_xxx(self) -> Base: ... + +def declarative_base() -> Base: ... T = TypeVar('T') @@ -573,6 +643,35 @@ class Instr(Generic[T]): ... \[mypy] plugins=/test-data/unit/plugins/dyn_class.py +[case testDynamicClassPluginChainedAssignment] +# flags: --config-file tmp/mypy.ini +from mod import declarative_base + +Base1 = Base2 = declarative_base() + +class C1(Base1): ... +class C2(Base2): ... +[file mod.py] +def declarative_base(): ... +[file mypy.ini] +\[mypy] +plugins=/test-data/unit/plugins/dyn_class.py + +[case testDynamicClassPluginNegatives] +# flags: --config-file tmp/mypy.ini +from mod import non_declarative_base + +Bad1 = non_declarative_base() + +class C1(Bad1): ... # E: Variable "__main__.Bad1" is not valid as a type \ + # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases \ + # E: Invalid base class "Bad1" +[file mod.py] +def non_declarative_base(): ... +[file mypy.ini] +\[mypy] +plugins=/test-data/unit/plugins/dyn_class.py + [case testDynamicClassHookFromClassMethod] # flags: --config-file tmp/mypy.ini diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 80ad554d846c..73476a646c99 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -224,9 +224,10 @@ from dataclasses import dataclass, field class Person: name: str age: int = field(init=None) # E: No overload variant of "field" matches argument type "None" \ - # N: Possible overload variant: \ - # N: def field(*, init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[str, Any]] = ..., kw_only: bool = ...) -> Any \ - # N: <2 more non-matching overloads not shown> + # N: Possible overload variants: \ + # N: def [_T] field(*, default: _T, init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[str, Any]] = ..., kw_only: bool = ...) -> _T \ + # N: def [_T] field(*, default_factory: Callable[[], _T], init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[str, Any]] = ..., kw_only: bool = ...) -> _T \ + # N: def field(*, init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[str, Any]] = ..., kw_only: bool = ...) -> Any [builtins fixtures/dataclasses.pyi] @@ -1262,45 +1263,81 @@ reveal_type(A.__dataclass_fields__) # N: Revealed type is "builtins.dict[builti [builtins fixtures/dict.pyi] -[case testDataclassCallableFieldAccess] +[case testDataclassCallableProperty] # flags: --python-version 3.7 from dataclasses import dataclass from typing import Callable @dataclass class A: - x: Callable[[int], int] - y: Callable[[int], int] = lambda i: i + foo: Callable[[int], int] -a = A(lambda i:i) -x: int = a.x(0) -y: str = a.y(0) # E: Incompatible types in assignment (expression has type "int", variable has type "str") -reveal_type(a.x) # N: Revealed type is "def (builtins.int) -> builtins.int" -reveal_type(a.y) # N: Revealed type is "def (builtins.int) -> builtins.int" -reveal_type(A.y) # N: Revealed type is "def (builtins.int) -> builtins.int" +def my_foo(x: int) -> int: + return x +a = A(foo=my_foo) +a.foo(1) +reveal_type(a.foo) # N: Revealed type is "def (builtins.int) -> builtins.int" +reveal_type(A.foo) # N: Revealed type is "def (builtins.int) -> builtins.int" +[typing fixtures/typing-medium.pyi] [builtins fixtures/dataclasses.pyi] -[case testDataclassCallableFieldAssignment] +[case testDataclassCallableAssignment] # flags: --python-version 3.7 from dataclasses import dataclass from typing import Callable @dataclass class A: - x: Callable[[int], int] + foo: Callable[[int], int] + +def my_foo(x: int) -> int: + return x -def x(i: int) -> int: - return i -def x2(s: str) -> str: - return s +a = A(foo=my_foo) -a = A(lambda i:i) -a.x = x -a.x = x2 # E: Incompatible types in assignment (expression has type "Callable[[str], str]", variable has type "Callable[[int], int]") +def another_foo(x: int) -> int: + return x +a.foo = another_foo [builtins fixtures/dataclasses.pyi] +[case testDataclassCallablePropertyWrongType] +# flags: --python-version 3.7 +from dataclasses import dataclass +from typing import Callable + +@dataclass +class A: + foo: Callable[[int], int] + +def my_foo(x: int) -> str: + return "foo" + +a = A(foo=my_foo) # E: Argument "foo" to "A" has incompatible type "Callable[[int], str]"; expected "Callable[[int], int]" +[typing fixtures/typing-medium.pyi] +[builtins fixtures/dataclasses.pyi] + +[case testDataclassCallablePropertyWrongTypeAssignment] +# flags: --python-version 3.7 +from dataclasses import dataclass +from typing import Callable + +@dataclass +class A: + foo: Callable[[int], int] + +def my_foo(x: int) -> int: + return x + +a = A(foo=my_foo) + +def another_foo(x: int) -> str: + return "foo" + +a.foo = another_foo # E: Incompatible types in assignment (expression has type "Callable[[int], str]", variable has type "Callable[[int], int]") +[typing fixtures/typing-medium.pyi] +[builtins fixtures/dataclasses.pyi] [case testDataclassFieldDoesNotFailOnKwargsUnpacking] # flags: --python-version 3.7 @@ -1319,6 +1356,19 @@ main:7: note: def [_T] field(*, default_factory: Callable[[], _T], init: boo main:7: note: def field(*, init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[str, Any]] = ..., kw_only: bool = ...) -> Any [builtins fixtures/dataclasses.pyi] +[case testDataclassFieldWithPositionalArguments] +# flags: --python-version 3.7 +from dataclasses import dataclass, field + +@dataclass +class C: + x: int = field(0) # E: "field()" does not accept positional arguments \ + # E: No overload variant of "field" matches argument type "int" \ + # N: Possible overload variants: \ + # N: def [_T] field(*, default: _T, init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[str, Any]] = ..., kw_only: bool = ...) -> _T \ + # N: def [_T] field(*, default_factory: Callable[[], _T], init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[str, Any]] = ..., kw_only: bool = ...) -> _T \ + # N: def field(*, init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., metadata: Optional[Mapping[str, Any]] = ..., kw_only: bool = ...) -> Any +[builtins fixtures/dataclasses.pyi] [case testDataclassFieldWithTypedDictUnpacking] # flags: --python-version 3.7 @@ -1336,3 +1386,73 @@ class Foo: reveal_type(Foo(bar=1.5)) # N: Revealed type is "__main__.Foo" [builtins fixtures/dataclasses.pyi] + +[case testDataclassWithSlotsArg] +# flags: --python-version 3.10 +from dataclasses import dataclass + +@dataclass(slots=True) +class Some: + x: int + + def __init__(self, x: int) -> None: + self.x = x + self.y = 0 # E: Trying to assign name "y" that is not in "__slots__" of type "__main__.Some" + + def __post_init__(self) -> None: + self.y = 1 # E: Trying to assign name "y" that is not in "__slots__" of type "__main__.Some" +[builtins fixtures/dataclasses.pyi] + +[case testDataclassWithSlotsDef] +# flags: --python-version 3.10 +from dataclasses import dataclass + +@dataclass(slots=False) +class Some: + __slots__ = ('x',) + x: int + + def __init__(self, x: int) -> None: + self.x = x + self.y = 0 # E: Trying to assign name "y" that is not in "__slots__" of type "__main__.Some" + + def __post_init__(self) -> None: + self.y = 1 # E: Trying to assign name "y" that is not in "__slots__" of type "__main__.Some" +[builtins fixtures/dataclasses.pyi] + +[case testDataclassWithSlotsConflict] +# flags: --python-version 3.10 +from dataclasses import dataclass + +@dataclass(slots=True) +class Some: # E: "Some" both defines "__slots__" and is used with "slots=True" + __slots__ = ('x',) + x: int + +@dataclass(slots=True) +class EmptyDef: # E: "EmptyDef" both defines "__slots__" and is used with "slots=True" + __slots__ = () + x: int + +slots = ('x',) + +@dataclass(slots=True) +class DynamicDef: # E: "DynamicDef" both defines "__slots__" and is used with "slots=True" + __slots__ = slots + x: int +[builtins fixtures/dataclasses.pyi] + +[case testDataclassWithSlotsArgBefore310] +# flags: --python-version 3.9 +from dataclasses import dataclass + +@dataclass(slots=True) # E: Keyword argument "slots" for "dataclass" is only valid in Python 3.10 and higher +class Some: + x: int + +# Possible conflict: +@dataclass(slots=True) # E: Keyword argument "slots" for "dataclass" is only valid in Python 3.10 and higher +class Other: + __slots__ = ('x',) + x: int +[builtins fixtures/dataclasses.pyi] diff --git a/test-data/unit/check-default-plugin.test b/test-data/unit/check-default-plugin.test index 7493763d3e72..fc9f132abb62 100644 --- a/test-data/unit/check-default-plugin.test +++ b/test-data/unit/check-default-plugin.test @@ -24,6 +24,65 @@ f = g # E: Incompatible types in assignment (expression has type "Callable[[Any, [typing fixtures/typing-medium.pyi] [builtins fixtures/tuple.pyi] +[case testContextManagerWithGenericFunctionAndSendType] +from contextlib import contextmanager +from typing import TypeVar, Generator + +T = TypeVar('T') +S = TypeVar('S') + +@contextmanager +def yield_id(item: T) -> Generator[T, S, None]: + yield item + +reveal_type(yield_id) # N: Revealed type is "def [T] (item: T`-1) -> contextlib.GeneratorContextManager[T`-1]" + +with yield_id(1) as x: + reveal_type(x) # N: Revealed type is "builtins.int*" + +f = yield_id +def g(x, y): pass +f = g # E: Incompatible types in assignment (expression has type "Callable[[Any, Any], Any]", variable has type "Callable[[T], GeneratorContextManager[T]]") +[typing fixtures/typing-medium.pyi] +[builtins fixtures/tuple.pyi] + +[case testAsyncContextManagerWithGenericFunction] +# flags: --python-version 3.7 +from contextlib import asynccontextmanager +from typing import TypeVar, AsyncIterator + +T = TypeVar('T') + +@asynccontextmanager +async def yield_id(item: T) -> AsyncIterator[T]: + yield item + +reveal_type(yield_id) # N: Revealed type is "def [T] (item: T`-1) -> typing.AsyncContextManager[T`-1]" + +async with yield_id(1) as x: + reveal_type(x) # N: Revealed type is "builtins.int*" +[typing fixtures/typing-async.pyi] +[builtins fixtures/tuple.pyi] + +[case testAsyncContextManagerWithGenericFunctionAndSendType] +# flags: --python-version 3.7 +from contextlib import asynccontextmanager +from typing import TypeVar, AsyncGenerator + +T = TypeVar('T') +S = TypeVar('S') + +@asynccontextmanager +async def yield_id(item: T) -> AsyncGenerator[T, S]: + yield item + +reveal_type(yield_id) # N: Revealed type is "def [T] (item: T`-1) -> typing.AsyncContextManager[T`-1]" + +async with yield_id(1) as x: + reveal_type(x) # N: Revealed type is "builtins.int*" +[typing fixtures/typing-async.pyi] +[builtins fixtures/tuple.pyi] + [case testContextManagerWithUnspecifiedArguments] from contextlib import contextmanager from typing import Callable, Iterator diff --git a/test-data/unit/check-dynamic-typing.test b/test-data/unit/check-dynamic-typing.test index 137376535b4e..7b016c342e95 100644 --- a/test-data/unit/check-dynamic-typing.test +++ b/test-data/unit/check-dynamic-typing.test @@ -159,9 +159,9 @@ a or d if int(): c = a in d # E: Incompatible types in assignment (expression has type "bool", variable has type "C") if int(): - c = b and d # E: Incompatible types in assignment (expression has type "Union[bool, Any]", variable has type "C") + c = b and d # E: Incompatible types in assignment (expression has type "Union[Literal[False], Any]", variable has type "C") if int(): - c = b or d # E: Incompatible types in assignment (expression has type "Union[bool, Any]", variable has type "C") + c = b or d # E: Incompatible types in assignment (expression has type "Union[Literal[True], Any]", variable has type "C") if int(): b = a + d if int(): @@ -730,7 +730,7 @@ class A(B): [out] main:5: error: Signature of "f" incompatible with supertype "B" main:5: note: Superclass: -main:5: note: def f(x: Any, y: Any) -> Any +main:5: note: def f(self, x: Any, y: Any) -> Any main:5: note: Subclass: main:5: note: def f(self, x: A) -> None diff --git a/test-data/unit/check-enum.test b/test-data/unit/check-enum.test index 5200c00d3f28..a393df079730 100644 --- a/test-data/unit/check-enum.test +++ b/test-data/unit/check-enum.test @@ -56,7 +56,7 @@ class Truth(Enum): x = '' x = Truth.true.name reveal_type(Truth.true.name) # N: Revealed type is "Literal['true']?" -reveal_type(Truth.false.value) # N: Revealed type is "builtins.bool" +reveal_type(Truth.false.value) # N: Revealed type is "Literal[False]?" [builtins fixtures/bool.pyi] [case testEnumValueExtended] @@ -66,7 +66,7 @@ class Truth(Enum): false = False def infer_truth(truth: Truth) -> None: - reveal_type(truth.value) # N: Revealed type is "builtins.bool" + reveal_type(truth.value) # N: Revealed type is "Union[Literal[True]?, Literal[False]?]" [builtins fixtures/bool.pyi] [case testEnumValueAllAuto] @@ -90,7 +90,7 @@ def infer_truth(truth: Truth) -> None: [builtins fixtures/primitives.pyi] [case testEnumValueExtraMethods] -from enum import Enum, auto +from enum import Enum class Truth(Enum): true = True false = False @@ -99,7 +99,7 @@ class Truth(Enum): return 'bar' def infer_truth(truth: Truth) -> None: - reveal_type(truth.value) # N: Revealed type is "builtins.bool" + reveal_type(truth.value) # N: Revealed type is "Union[Literal[True]?, Literal[False]?]" [builtins fixtures/bool.pyi] [case testEnumValueCustomAuto] @@ -129,6 +129,20 @@ def cannot_infer_truth(truth: Truth) -> None: reveal_type(truth.value) # N: Revealed type is "Any" [builtins fixtures/bool.pyi] +[case testEnumValueSameType] +from enum import Enum + +def newbool() -> bool: + ... + +class Truth(Enum): + true = newbool() + false = newbool() + +def infer_truth(truth: Truth) -> None: + reveal_type(truth.value) # N: Revealed type is "builtins.bool" +[builtins fixtures/bool.pyi] + [case testEnumUnique] import enum @enum.unique @@ -1360,3 +1374,375 @@ class E(IntEnum): A = N(0) reveal_type(E.A.value) # N: Revealed type is "__main__.N" + + +[case testEnumFinalValues] +from enum import Enum +class Medal(Enum): + gold = 1 + silver = 2 + +# Another value: +Medal.gold = 0 # E: Cannot assign to final attribute "gold" +# Same value: +Medal.silver = 2 # E: Cannot assign to final attribute "silver" + + +[case testEnumFinalValuesCannotRedefineValueProp] +from enum import Enum +class Types(Enum): + key = 0 + value = 1 + + +[case testEnumReusedKeys] +# https://github.com/python/mypy/issues/11248 +from enum import Enum +class Correct(Enum): + x = 'y' + y = 'x' +class Foo(Enum): + A = 1 + A = 'a' # E: Attempted to reuse member name "A" in Enum definition "Foo" \ + # E: Incompatible types in assignment (expression has type "str", variable has type "int") +reveal_type(Foo.A.value) # N: Revealed type is "builtins.int" + +class Bar(Enum): + A = 1 + B = A = 2 # E: Attempted to reuse member name "A" in Enum definition "Bar" +class Baz(Enum): + A = 1 + B, A = (1, 2) # E: Attempted to reuse member name "A" in Enum definition "Baz" +[builtins fixtures/tuple.pyi] + +[case testEnumReusedKeysOverlapWithLocalVar] +from enum import Enum +x = 1 +class Foo(Enum): + x = 2 + def method(self) -> None: + x = 3 +x = 4 +[builtins fixtures/bool.pyi] + +[case testEnumImplicitlyFinalForSubclassing] +from enum import Enum, IntEnum, Flag, IntFlag + +class NonEmptyEnum(Enum): + x = 1 +class NonEmptyIntEnum(IntEnum): + x = 1 +class NonEmptyFlag(Flag): + x = 1 +class NonEmptyIntFlag(IntFlag): + x = 1 + +class ErrorEnumWithValue(NonEmptyEnum): # E: Cannot inherit from final class "NonEmptyEnum" + x = 1 # E: Cannot override final attribute "x" (previously declared in base class "NonEmptyEnum") +class ErrorIntEnumWithValue(NonEmptyIntEnum): # E: Cannot inherit from final class "NonEmptyIntEnum" + x = 1 # E: Cannot override final attribute "x" (previously declared in base class "NonEmptyIntEnum") +class ErrorFlagWithValue(NonEmptyFlag): # E: Cannot inherit from final class "NonEmptyFlag" + x = 1 # E: Cannot override final attribute "x" (previously declared in base class "NonEmptyFlag") +class ErrorIntFlagWithValue(NonEmptyIntFlag): # E: Cannot inherit from final class "NonEmptyIntFlag" + x = 1 # E: Cannot override final attribute "x" (previously declared in base class "NonEmptyIntFlag") + +class ErrorEnumWithoutValue(NonEmptyEnum): # E: Cannot inherit from final class "NonEmptyEnum" + pass +class ErrorIntEnumWithoutValue(NonEmptyIntEnum): # E: Cannot inherit from final class "NonEmptyIntEnum" + pass +class ErrorFlagWithoutValue(NonEmptyFlag): # E: Cannot inherit from final class "NonEmptyFlag" + pass +class ErrorIntFlagWithoutValue(NonEmptyIntFlag): # E: Cannot inherit from final class "NonEmptyIntFlag" + pass +[builtins fixtures/bool.pyi] + +[case testSubclassingNonFinalEnums] +from enum import Enum, IntEnum, Flag, IntFlag, EnumMeta + +def decorator(func): + return func + +class EmptyEnum(Enum): + pass +class EmptyIntEnum(IntEnum): + pass +class EmptyFlag(Flag): + pass +class EmptyIntFlag(IntFlag): + pass +class EmptyEnumMeta(EnumMeta): + pass + +class NonEmptyEnumSub(EmptyEnum): + x = 1 +class NonEmptyIntEnumSub(EmptyIntEnum): + x = 1 +class NonEmptyFlagSub(EmptyFlag): + x = 1 +class NonEmptyIntFlagSub(EmptyIntFlag): + x = 1 +class NonEmptyEnumMetaSub(EmptyEnumMeta): + x = 1 + +class EmptyEnumSub(EmptyEnum): + def method(self) -> None: pass + @decorator + def other(self) -> None: pass +class EmptyIntEnumSub(EmptyIntEnum): + def method(self) -> None: pass +class EmptyFlagSub(EmptyFlag): + def method(self) -> None: pass +class EmptyIntFlagSub(EmptyIntFlag): + def method(self) -> None: pass +class EmptyEnumMetaSub(EmptyEnumMeta): + def method(self) -> None: pass + +class NestedEmptyEnumSub(EmptyEnumSub): + x = 1 +class NestedEmptyIntEnumSub(EmptyIntEnumSub): + x = 1 +class NestedEmptyFlagSub(EmptyFlagSub): + x = 1 +class NestedEmptyIntFlagSub(EmptyIntFlagSub): + x = 1 +class NestedEmptyEnumMetaSub(EmptyEnumMetaSub): + x = 1 +[builtins fixtures/bool.pyi] + +[case testEnumExplicitlyAndImplicitlyFinal] +from typing import final +from enum import Enum, IntEnum, Flag, IntFlag, EnumMeta + +@final +class EmptyEnum(Enum): + pass +@final +class EmptyIntEnum(IntEnum): + pass +@final +class EmptyFlag(Flag): + pass +@final +class EmptyIntFlag(IntFlag): + pass +@final +class EmptyEnumMeta(EnumMeta): + pass + +class EmptyEnumSub(EmptyEnum): # E: Cannot inherit from final class "EmptyEnum" + pass +class EmptyIntEnumSub(EmptyIntEnum): # E: Cannot inherit from final class "EmptyIntEnum" + pass +class EmptyFlagSub(EmptyFlag): # E: Cannot inherit from final class "EmptyFlag" + pass +class EmptyIntFlagSub(EmptyIntFlag): # E: Cannot inherit from final class "EmptyIntFlag" + pass +class EmptyEnumMetaSub(EmptyEnumMeta): # E: Cannot inherit from final class "EmptyEnumMeta" + pass + +@final +class NonEmptyEnum(Enum): + x = 1 +@final +class NonEmptyIntEnum(IntEnum): + x = 1 +@final +class NonEmptyFlag(Flag): + x = 1 +@final +class NonEmptyIntFlag(IntFlag): + x = 1 +@final +class NonEmptyEnumMeta(EnumMeta): + x = 1 + +class ErrorEnumWithoutValue(NonEmptyEnum): # E: Cannot inherit from final class "NonEmptyEnum" + pass +class ErrorIntEnumWithoutValue(NonEmptyIntEnum): # E: Cannot inherit from final class "NonEmptyIntEnum" + pass +class ErrorFlagWithoutValue(NonEmptyFlag): # E: Cannot inherit from final class "NonEmptyFlag" + pass +class ErrorIntFlagWithoutValue(NonEmptyIntFlag): # E: Cannot inherit from final class "NonEmptyIntFlag" + pass +class ErrorEnumMetaWithoutValue(NonEmptyEnumMeta): # E: Cannot inherit from final class "NonEmptyEnumMeta" + pass +[builtins fixtures/bool.pyi] + +[case testEnumFinalSubtypingEnumMetaSpecialCase] +from enum import EnumMeta +# `EnumMeta` types are not `Enum`s +class SubMeta(EnumMeta): + x = 1 +class SubSubMeta(SubMeta): + x = 2 +[builtins fixtures/bool.pyi] + +[case testEnumFinalSubtypingOverloadedSpecialCase] +from typing import overload +from enum import Enum, IntEnum, Flag, IntFlag, EnumMeta + +class EmptyEnum(Enum): + @overload + def method(self, arg: int) -> int: + pass + @overload + def method(self, arg: str) -> str: + pass + def method(self, arg): + pass +class EmptyIntEnum(IntEnum): + @overload + def method(self, arg: int) -> int: + pass + @overload + def method(self, arg: str) -> str: + pass + def method(self, arg): + pass +class EmptyFlag(Flag): + @overload + def method(self, arg: int) -> int: + pass + @overload + def method(self, arg: str) -> str: + pass + def method(self, arg): + pass +class EmptyIntFlag(IntFlag): + @overload + def method(self, arg: int) -> int: + pass + @overload + def method(self, arg: str) -> str: + pass + def method(self, arg): + pass +class EmptyEnumMeta(EnumMeta): + @overload + def method(self, arg: int) -> int: + pass + @overload + def method(self, arg: str) -> str: + pass + def method(self, arg): + pass + +class NonEmptyEnumSub(EmptyEnum): + x = 1 +class NonEmptyIntEnumSub(EmptyIntEnum): + x = 1 +class NonEmptyFlagSub(EmptyFlag): + x = 1 +class NonEmptyIntFlagSub(EmptyIntFlag): + x = 1 +class NonEmptyEnumMetaSub(EmptyEnumMeta): + x = 1 +[builtins fixtures/bool.pyi] + +[case testEnumFinalSubtypingMethodAndValueSpecialCase] +from enum import Enum, IntEnum, Flag, IntFlag, EnumMeta + +def decorator(func): + return func + +class NonEmptyEnum(Enum): + x = 1 + def method(self) -> None: pass + @decorator + def other(self) -> None: pass +class NonEmptyIntEnum(IntEnum): + x = 1 + def method(self) -> None: pass +class NonEmptyFlag(Flag): + x = 1 + def method(self) -> None: pass +class NonEmptyIntFlag(IntFlag): + x = 1 + def method(self) -> None: pass + +class ErrorEnumWithoutValue(NonEmptyEnum): # E: Cannot inherit from final class "NonEmptyEnum" + pass +class ErrorIntEnumWithoutValue(NonEmptyIntEnum): # E: Cannot inherit from final class "NonEmptyIntEnum" + pass +class ErrorFlagWithoutValue(NonEmptyFlag): # E: Cannot inherit from final class "NonEmptyFlag" + pass +class ErrorIntFlagWithoutValue(NonEmptyIntFlag): # E: Cannot inherit from final class "NonEmptyIntFlag" + pass +[builtins fixtures/bool.pyi] + +[case testFinalEnumWithClassDef] +from enum import Enum + +class A(Enum): + class Inner: pass +class B(A): pass # E: Cannot inherit from final class "A" +[builtins fixtures/bool.pyi] + +[case testEnumFinalSpecialProps] +# https://github.com/python/mypy/issues/11699 +from enum import Enum, IntEnum + +class E(Enum): + name = 'a' + value = 'b' + _name_ = 'a1' + _value_ = 'b2' + _order_ = 'X Y' + __order__ = 'X Y' + +class EI(IntEnum): + name = 'a' + value = 1 + _name_ = 'a1' + _value_ = 2 + _order_ = 'X Y' + __order__ = 'X Y' + +E._order_ = 'a' # E: Cannot assign to final attribute "_order_" +EI.value = 2 # E: Cannot assign to final attribute "value" +[builtins fixtures/bool.pyi] + +[case testEnumNotFinalWithMethodsAndUninitializedValues] +# https://github.com/python/mypy/issues/11578 +from enum import Enum +from typing import Final + +class A(Enum): + x: int + def method(self) -> int: pass +class B(A): + x = 1 # E: Cannot override writable attribute "x" with a final one + +class A1(Enum): + x: int = 1 +class B1(A1): # E: Cannot inherit from final class "A1" + pass + +class A2(Enum): + x = 2 +class B2(A2): # E: Cannot inherit from final class "A2" + pass + +# We leave this `Final` without a value, +# because we need to test annotation only mode: +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] +import lib + +[file lib.pyi] +from enum import Enum +class A(Enum): + x: int +class B(A): # E: Cannot inherit from final class "A" + x = 1 # E: Cannot override writable attribute "x" with a final one + +class C(Enum): + x = 1 +class D(C): # E: Cannot inherit from final class "C" + x: int # E: Cannot assign to final name "x" +[builtins fixtures/bool.pyi] diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index c7dbf81d909f..2f84ee1f4c6e 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -34,7 +34,7 @@ reveal_type(1) # N: Revealed type is "Literal[1]?" 1 '' [out] main:1: error: invalid syntax [syntax] -[out version>=3.10] +[out version==3.10.0] main:1: error: invalid syntax. Perhaps you forgot a comma? [syntax] [case testErrorCodeSyntaxError2] @@ -111,6 +111,30 @@ a = 'x'.foobar(b) # type: ignore[xyz, w, attr-defined] # E: Name "b" is not de a = 'x'.foobar(b) # type: int # type: ignore[name-defined, attr-defined] b = 'x'.foobar(b) # type: int # type: ignore[name-defined, xyz] # E: "str" has no attribute "foobar" [attr-defined] +[case testErrorCodeWarnUnusedIgnores1] +# flags: --warn-unused-ignores +x # type: ignore[name-defined, attr-defined] # E: Unused "type: ignore[attr-defined]" comment + +[case testErrorCodeWarnUnusedIgnores2] +# flags: --warn-unused-ignores +"x".foobar(y) # type: ignore[name-defined, attr-defined] + +[case testErrorCodeWarnUnusedIgnores3] +# flags: --warn-unused-ignores +"x".foobar(y) # type: ignore[name-defined, attr-defined, xyz] # E: Unused "type: ignore[xyz]" comment + +[case testErrorCodeWarnUnusedIgnores4] +# flags: --warn-unused-ignores +"x".foobar(y) # type: ignore[name-defined, attr-defined, valid-type] # E: Unused "type: ignore[valid-type]" comment + +[case testErrorCodeWarnUnusedIgnores5] +# flags: --warn-unused-ignores +"x".foobar(y) # type: ignore[name-defined, attr-defined, valid-type, xyz] # E: Unused "type: ignore[valid-type, xyz]" comment + +[case testErrorCodeWarnUnusedIgnores6_NoDetailWhenSingleErrorCode] +# flags: --warn-unused-ignores +"x" # type: ignore[name-defined] # E: Unused "type: ignore" comment + [case testErrorCodeIgnoreWithExtraSpace] x # type: ignore [name-defined] x2 # type: ignore [ name-defined ] @@ -416,7 +440,7 @@ class D(Generic[S]): pass class E(Generic[S, T]): pass x: C[object] # E: Value of type variable "T" of "C" cannot be "object" [type-var] -y: D[int] # E: Type argument "builtins.int" of "D" must be a subtype of "builtins.str" [type-var] +y: D[int] # E: Type argument "int" of "D" must be a subtype of "str" [type-var] z: D[int, int] # E: "D" expects 1 type argument, but 2 given [type-arg] def h(a: TT, s: S) -> None: @@ -641,8 +665,8 @@ def g() -> int: '%d' % 'no' # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float, SupportsInt]") [str-format] '%d + %d' % (1, 2, 3) # E: Not all arguments converted during string formatting [str-format] -'{}'.format(b'abc') # E: On Python 3 '{}'.format(b'abc') produces "b'abc'", not 'abc'; use '{!r}'.format(b'abc') if this is desired behavior [str-bytes-safe] -'%s' % b'abc' # E: On Python 3 '%s' % b'abc' produces "b'abc'", not 'abc'; use '%r' % b'abc' if this is desired behavior [str-bytes-safe] +'{}'.format(b'abc') # E: On Python 3 formatting "b'abc'" with "{}" produces "b'abc'", not "abc"; use "{!r}" if this is desired behavior [str-bytes-safe] +'%s' % b'abc' # E: On Python 3 formatting "b'abc'" with "%s" produces "b'abc'", not "abc"; use "%r" if this is desired behavior [str-bytes-safe] [builtins fixtures/primitives.pyi] [typing fixtures/typing-medium.pyi] @@ -830,7 +854,7 @@ class Foo: pass foo = Foo() -if foo: # E: "__main__.foo" has type "__main__.Foo" which does not implement __bool__ or __len__ so it could always be true in boolean context [truthy-bool] +if foo: # E: "__main__.foo" has type "Foo" which does not implement __bool__ or __len__ so it could always be true in boolean context [truthy-bool] pass zero = 0 @@ -856,20 +880,56 @@ if not good_union: pass bad_union: Union[Foo, object] = Foo() -if bad_union: # E: "__main__.bad_union" has type "Union[__main__.Foo, builtins.object]" of which no members implement __bool__ or __len__ so it could always be true in boolean context [truthy-bool] +if bad_union: # E: "__main__.bad_union" has type "Union[Foo, object]" of which no members implement __bool__ or __len__ so it could always be true in boolean context [truthy-bool] pass -if not bad_union: # E: "__main__.bad_union" has type "builtins.object" which does not implement __bool__ or __len__ so it could always be true in boolean context [truthy-bool] +if not bad_union: # E: "__main__.bad_union" has type "object" which does not implement __bool__ or __len__ so it could always be true in boolean context [truthy-bool] pass def f(): pass -if f: # E: Function "def () -> Any" could always be true in boolean context [truthy-bool] +if f: # E: Function "Callable[[], Any]" could always be true in boolean context [truthy-bool] pass -if not f: # E: Function "def () -> Any" could always be true in boolean context [truthy-bool] +if not f: # E: Function "Callable[[], Any]" could always be true in boolean context [truthy-bool] pass -conditional_result = 'foo' if f else 'bar' # E: Function "def () -> Any" could always be true in boolean context [truthy-bool] +conditional_result = 'foo' if f else 'bar' # E: Function "Callable[[], Any]" could always be true in boolean context [truthy-bool] lst: List[int] = [] if lst: pass [builtins fixtures/list.pyi] + +[case testSliceInDict39] +# flags: --python-version 3.9 --show-column-numbers +from typing import Dict +b: Dict[int, x:y] +c: Dict[x:y] + +[builtins fixtures/dict.pyi] +[out] +main:3:14: error: Invalid type comment or annotation [valid-type] +main:3:14: note: did you mean to use ',' instead of ':' ? +main:4:4: error: "dict" expects 2 type arguments, but 1 given [type-arg] +main:4:9: error: Invalid type comment or annotation [valid-type] +main:4:9: note: did you mean to use ',' instead of ':' ? + +[case testSliceInDict38] +# flags: --python-version 3.8 --show-column-numbers +from typing import Dict +b: Dict[int, x:y] +c: Dict[x:y] + +[builtins fixtures/dict.pyi] +[out] +main:3:14: error: Invalid type comment or annotation [valid-type] +main:3:14: note: did you mean to use ',' instead of ':' ? +main:4:4: error: "dict" expects 2 type arguments, but 1 given [type-arg] +main:4:9: error: Invalid type comment or annotation [valid-type] +main:4:9: note: did you mean to use ',' instead of ':' ? + + +[case testSliceInCustomTensorType] +# syntactically mimics torchtyping.TensorType +class TensorType: ... +t: TensorType["batch":..., float] # type: ignore +reveal_type(t) # N: Revealed type is "__main__.TensorType" +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/check-expressions.test b/test-data/unit/check-expressions.test index ff3a5efde6ad..a275de94c9be 100644 --- a/test-data/unit/check-expressions.test +++ b/test-data/unit/check-expressions.test @@ -63,13 +63,7 @@ if str(): a = 1.1 class A: pass -[file builtins.py] -class object: - def __init__(self): pass -class type: pass -class function: pass -class float: pass -class str: pass +[builtins fixtures/dict.pyi] [case testComplexLiteral] a = 0.0j @@ -80,13 +74,7 @@ if str(): a = 1.1j class A: pass -[file builtins.py] -class object: - def __init__(self): pass -class type: pass -class function: pass -class complex: pass -class str: pass +[builtins fixtures/dict.pyi] [case testBytesLiteral] b, a = None, None # type: (bytes, A) @@ -99,14 +87,7 @@ if str(): if str(): a = b'foo' # E: Incompatible types in assignment (expression has type "bytes", variable has type "A") class A: pass -[file builtins.py] -class object: - def __init__(self): pass -class type: pass -class tuple: pass -class function: pass -class bytes: pass -class str: pass +[builtins fixtures/dict.pyi] [case testUnicodeLiteralInPython3] s = None # type: str @@ -316,11 +297,11 @@ if int(): if int(): b = b or b if int(): - b = b and a # E: Incompatible types in assignment (expression has type "Union[bool, A]", variable has type "bool") + b = b and a # E: Incompatible types in assignment (expression has type "Union[Literal[False], A]", variable has type "bool") if int(): b = a and b # E: Incompatible types in assignment (expression has type "Union[A, bool]", variable has type "bool") if int(): - b = b or a # E: Incompatible types in assignment (expression has type "Union[bool, A]", variable has type "bool") + b = b or a # E: Incompatible types in assignment (expression has type "Union[Literal[True], A]", variable has type "bool") if int(): b = a or b # E: Incompatible types in assignment (expression has type "Union[A, bool]", variable has type "bool") class A: pass @@ -1077,6 +1058,7 @@ class A: pass [builtins fixtures/bool.pyi] + -- Slicing -- ------- @@ -1151,624 +1133,6 @@ a[:None] [builtins fixtures/slice.pyi] --- String interpolation --- -------------------- - - -[case testStringInterpolationType] -from typing import Tuple -i, f, s, t = None, None, None, None # type: (int, float, str, Tuple[int]) -'%d' % i -'%f' % f -'%s' % s -'%d' % (f,) -'%d' % (s,) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float, SupportsInt]") -'%d' % t -'%d' % s # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float, SupportsInt]") -'%f' % s # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float, SupportsFloat]") -'%x' % f # E: Incompatible types in string interpolation (expression has type "float", placeholder has type "int") -'%i' % f -'%o' % f # E: Incompatible types in string interpolation (expression has type "float", placeholder has type "int") -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testStringInterpolationSAcceptsAnyType] -from typing import Any -i, o, s = None, None, None # type: (int, object, str) -'%s %s %s' % (i, o, s) -[builtins fixtures/primitives.pyi] - -[case testStringInterpolationSBytesVsStrErrorPy3] -xb: bytes -xs: str - -'%s' % xs # OK -'%s' % xb # E: On Python 3 '%s' % b'abc' produces "b'abc'", not 'abc'; use '%r' % b'abc' if this is desired behavior -'%(name)s' % {'name': b'value'} # E: On Python 3 '%s' % b'abc' produces "b'abc'", not 'abc'; use '%r' % b'abc' if this is desired behavior -[builtins fixtures/primitives.pyi] - -[case testStringInterpolationSBytesVsStrResultsPy2] -# flags: --python-version 2.7 -xs = 'x' -xu = u'x' - -reveal_type('%s' % xu) # N: Revealed type is "builtins.unicode" -reveal_type('%s, %d' % (u'abc', 42)) # N: Revealed type is "builtins.unicode" -reveal_type('%(key)s' % {'key': xu}) # N: Revealed type is "builtins.unicode" -reveal_type('%r' % xu) # N: Revealed type is "builtins.str" -reveal_type('%s' % xs) # N: Revealed type is "builtins.str" -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testStringInterpolationCount] -'%d %d' % 1 # E: Not enough arguments for format string -'%d %d' % (1, 2) -'%d %d' % (1, 2, 3) # E: Not all arguments converted during string formatting -t = 1, 's' -'%d %s' % t -'%s %d' % t # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float, SupportsInt]") -'%d' % t # E: Not all arguments converted during string formatting -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testStringInterpolationWithAnyType] -from typing import Any -a = None # type: Any -'%d %d' % a -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testStringInterpolationInvalidPlaceholder] -'%W' % 1 # E: Unsupported format character "W" -'%b' % 1 # E: Format character "b" is only supported on bytes patterns - -[case testStringInterPolationPython2] -# flags: --python-version 2.7 -b'%b' % 1 # E: Format character "b" is only supported in Python 3.5 and later -b'%s' % 1 -b'%a' % 1 # E: Format character "a" is only supported in Python 3 - -[case testBytesInterpolationBefore35] -# flags: --python-version 3.4 -b'%b' % 1 # E: Unsupported left operand type for % ("bytes") - -[case testBytesInterpolation] -b'%b' % 1 # E: Incompatible types in string interpolation (expression has type "int", placeholder has type "bytes") -b'%b' % b'1' -b'%a' % 3 - -[case testStringInterpolationWidth] -'%2f' % 3.14 -'%*f' % 3.14 # E: Not enough arguments for format string -'%*f' % (4, 3.14) -'%*f' % (1.1, 3.14) # E: * wants int -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testStringInterpolationPrecision] -'%.2f' % 3.14 -'%.*f' % 3.14 # E: Not enough arguments for format string -'%.*f' % (4, 3.14) -'%.*f' % (1.1, 3.14) # E: * wants int -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testStringInterpolationWidthAndPrecision] -'%4.2f' % 3.14 -'%4.*f' % 3.14 # E: Not enough arguments for format string -'%*.2f' % 3.14 # E: Not enough arguments for format string -'%*.*f' % 3.14 # E: Not enough arguments for format string -'%*.*f' % (4, 2, 3.14) -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testStringInterpolationFlagsAndLengthModifiers] -'%04hd' % 1 -'%-.4ld' % 1 -'%+*Ld' % (1, 1) -'% .*ld' % (1, 1) -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testStringInterpolationDoublePercentage] -'%% %d' % 1 -'%3% %d' % 1 -'%*%' % 1 -'%*% %d' % 1 # E: Not enough arguments for format string -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testStringInterPolationCPython2] -# flags: --py2 --no-strict-optional -'%c' % 1 -'%c' % 1.0 # E: "%c" requires int or char (expression has type "float") -'%c' % 's' -'%c' % '' # E: "%c" requires int or char -'%c' % 'ab' # E: "%c" requires int or char -'%c' % b'a' -'%c' % b'' # E: "%c" requires int or char -'%c' % b'ab' # E: "%c" requires int or char -[builtins_py2 fixtures/python2.pyi] - -[case testStringInterpolationC] -# flags: --python-version 3.6 -'%c' % 1 -'%c' % 1.0 # E: "%c" requires int or char (expression has type "float") -'%c' % 's' -'%c' % '' # E: "%c" requires int or char -'%c' % 'ab' # E: "%c" requires int or char -'%c' % b'a' # E: "%c" requires int or char (expression has type "bytes") -'%c' % b'' # E: "%c" requires int or char (expression has type "bytes") -'%c' % b'ab' # E: "%c" requires int or char (expression has type "bytes") -[builtins fixtures/primitives.pyi] - -[case testBytesInterPolationCPython2] -# flags: --py2 --no-strict-optional -b'%c' % 1 -b'%c' % 1.0 # E: "%c" requires int or char (expression has type "float") -b'%c' % 's' -b'%c' % '' # E: "%c" requires int or char -b'%c' % 'ab' # E: "%c" requires int or char -b'%c' % b'a' -b'%c' % b'' # E: "%c" requires int or char -b'%c' % b'aa' # E: "%c" requires int or char -[builtins_py2 fixtures/python2.pyi] - -[case testBytesInterpolationC] -# flags: --python-version 3.6 -b'%c' % 1 -b'%c' % 1.0 # E: "%c" requires an integer in range(256) or a single byte (expression has type "float") -b'%c' % 's' # E: "%c" requires an integer in range(256) or a single byte (expression has type "str") -b'%c' % '' # E: "%c" requires an integer in range(256) or a single byte (expression has type "str") -b'%c' % 'ab' # E: "%c" requires an integer in range(256) or a single byte (expression has type "str") -b'%c' % b'a' -b'%c' % b'' # E: "%c" requires an integer in range(256) or a single byte -b'%c' % b'aa' # E: "%c" requires an integer in range(256) or a single byte -[builtins fixtures/primitives.pyi] - -[case testStringInterpolationMappingTypes] -'%(a)d %(b)s' % {'a': 1, 'b': 's'} -'%(a)d %(b)s' % {'a': 's', 'b': 1} # E: Incompatible types in string interpolation (expression has type "str", placeholder with key 'a' has type "Union[int, float, SupportsInt]") -b'%(x)s' % {b'x': b'data'} -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testStringInterpolationMappingKeys] -'%()d' % {'': 2} -'%(a)d' % {'a': 1, 'b': 2, 'c': 3} -'%(q)d' % {'a': 1, 'b': 2, 'c': 3} # E: Key "q" not found in mapping -'%(a)d %%' % {'a': 1} -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testStringInterpolationMappingDictTypes] -from typing import Any, Dict -a = None # type: Any -ds, do, di = None, None, None # type: Dict[str, int], Dict[object, int], Dict[int, int] -'%(a)' % 1 # E: Format requires a mapping (expression has type "int", expected type for mapping is "Mapping[str, Any]") -'%()d' % a -'%()d' % ds -'%()d' % do # E: Format requires a mapping (expression has type "Dict[object, int]", expected type for mapping is "Mapping[str, Any]") -b'%()d' % ds # E: Format requires a mapping (expression has type "Dict[str, int]", expected type for mapping is "Mapping[bytes, Any]") -[builtins fixtures/primitives.pyi] - -[case testStringInterpolationMappingInvalidDictTypesPy2] -# flags: --py2 --no-strict-optional -from typing import Any, Dict -di = None # type: Dict[int, int] -'%()d' % di # E: Format requires a mapping (expression has type "Dict[int, int]", expected type for mapping is "Union[Mapping[str, Any], Mapping[unicode, Any]]") -[builtins_py2 fixtures/python2.pyi] - -[case testStringInterpolationMappingInvalidSpecifiers] -'%(a)d %d' % 1 # E: String interpolation mixes specifier with and without mapping keys -'%(b)*d' % 1 # E: String interpolation contains both stars and mapping keys -'%(b).*d' % 1 # E: String interpolation contains both stars and mapping keys - -[case testStringInterpolationMappingFlagsAndLengthModifiers] -'%(a)1d' % {'a': 1} -'%(a).1d' % {'a': 1} -'%(a)#1.1ld' % {'a': 1} -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testStringInterpolationFloatPrecision] -'%.f' % 1.2 -'%.3f' % 1.2 -'%.f' % 'x' -'%.3f' % 'x' -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] -[out] -main:3: error: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float, SupportsFloat]") -main:4: error: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float, SupportsFloat]") - -[case testStringInterpolationSpaceKey] -'%( )s' % {' ': 'foo'} - -[case testByteByteInterpolation] -def foo(a: bytes, b: bytes): - b'%s:%s' % (a, b) -foo(b'a', b'b') == b'a:b' -[builtins fixtures/tuple.pyi] - -[case testStringInterpolationStarArgs] -x = (1, 2) -"%d%d" % (*x,) -[typing fixtures/typing-medium.pyi] -[builtins fixtures/tuple.pyi] - -[case testBytePercentInterpolationSupported] -b'%s' % (b'xyz',) -b'%(name)s' % {'name': b'jane'} # E: Dictionary keys in bytes formatting must be bytes, not strings -b'%(name)s' % {b'name': 'jane'} # E: On Python 3 b'%s' requires bytes, not string -b'%c' % (123) -[builtins fixtures/tuple.pyi] - -[case testUnicodeInterpolation_python2] -u'%s' % (u'abc',) - -[case testStringInterpolationVariableLengthTuple] -from typing import Tuple -def f(t: Tuple[int, ...]) -> None: - '%d %d' % t - '%d %d %d' % t -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testStringInterpolationUnionType] -from typing import Tuple, Union -a: Union[Tuple[int, str], Tuple[str, int]] = ('A', 1) -'%s %s' % a -'%s' % a # E: Not all arguments converted during string formatting - -b: Union[Tuple[int, str], Tuple[int, int], Tuple[str, int]] = ('A', 1) -'%s %s' % b -'%s %s %s' % b # E: Not enough arguments for format string - -c: Union[Tuple[str, int], Tuple[str, int, str]] = ('A', 1) -'%s %s' % c # E: Not all arguments converted during string formatting -[builtins fixtures/tuple.pyi] - --- str.format() calls --- ------------------ - -[case testFormatCallParseErrors] -'}'.format() # E: Invalid conversion specifier in format string: unexpected } -'{'.format() # E: Invalid conversion specifier in format string: unmatched { - -'}}'.format() # OK -'{{'.format() # OK - -'{{}}}'.format() # E: Invalid conversion specifier in format string: unexpected } -'{{{}}'.format() # E: Invalid conversion specifier in format string: unexpected } - -'{}}{{}'.format() # E: Invalid conversion specifier in format string: unexpected } -'{{{}:{}}}'.format(0) # E: Cannot find replacement for positional format specifier 1 -[builtins fixtures/primitives.pyi] - -[case testFormatCallValidationErrors] -'{!}}'.format(0) # E: Invalid conversion specifier in format string: unexpected } -'{!x}'.format(0) # E: Invalid conversion type "x", must be one of "r", "s" or "a" -'{!:}'.format(0) # E: Invalid conversion specifier in format string - -'{{}:s}'.format(0) # E: Invalid conversion specifier in format string: unexpected } -'{{}.attr}'.format(0) # E: Invalid conversion specifier in format string: unexpected } -'{{}[key]}'.format(0) # E: Invalid conversion specifier in format string: unexpected } - -'{ {}:s}'.format() # E: Conversion value must not contain { or } -'{ {}.attr}'.format() # E: Conversion value must not contain { or } -'{ {}[key]}'.format() # E: Conversion value must not contain { or } -[builtins fixtures/primitives.pyi] - -[case testFormatCallEscaping] -'{}'.format() # E: Cannot find replacement for positional format specifier 0 -'{}'.format(0) # OK - -'{{}}'.format() # OK -'{{}}'.format(0) # E: Not all arguments converted during string formatting - -'{{{}}}'.format() # E: Cannot find replacement for positional format specifier 0 -'{{{}}}'.format(0) # OK - -'{{}} {} {{}}'.format(0) # OK -'{{}} {:d} {{}} {:d}'.format('a', 'b') # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") - -'foo({}, {}) == {{}} ({{}} expected)'.format(0) # E: Cannot find replacement for positional format specifier 1 -'foo({}, {}) == {{}} ({{}} expected)'.format(0, 1) # OK -'foo({}, {}) == {{}} ({{}} expected)'.format(0, 1, 2) # E: Not all arguments converted during string formatting -[builtins fixtures/primitives.pyi] - -[case testFormatCallNestedFormats] -'{:{}{}}'.format(42, '*') # E: Cannot find replacement for positional format specifier 2 -'{:{}{}}'.format(42, '*', '^') # OK -'{:{}{}}'.format(42, '*', '^', 0) # E: Not all arguments converted during string formatting - -# NOTE: we don't check format specifiers that contain { or } at all -'{:{{}}}'.format() # E: Cannot find replacement for positional format specifier 0 - -'{:{:{}}}'.format() # E: Formatting nesting must be at most two levels deep -'{:{{}:{}}}'.format() # E: Invalid conversion specifier in format string: unexpected } - -'{!s:{fill:d}{align}}'.format(42, fill='*', align='^') # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") -[builtins fixtures/primitives.pyi] - -[case testFormatCallAutoNumbering] -'{}, {{}}, {0}'.format() # E: Cannot combine automatic field numbering and manual field specification -'{0}, {1}, {}'.format() # E: Cannot combine automatic field numbering and manual field specification - -'{0}, {1}, {0}'.format(1, 2, 3) # E: Not all arguments converted during string formatting -'{}, {other:+d}, {}'.format(1, 2, other='no') # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") -'{0}, {other}, {}'.format() # E: Cannot combine automatic field numbering and manual field specification - -'{:{}}, {:{:.5d}{}}'.format(1, 2, 3, 'a', 5) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") -[builtins fixtures/primitives.pyi] - -[case testFormatCallMatchingPositional] -'{}'.format(positional='no') # E: Cannot find replacement for positional format specifier 0 \ - # E: Not all arguments converted during string formatting -'{.x}, {}, {}'.format(1, 'two', 'three') # E: "int" has no attribute "x" -'Reverse {2.x}, {1}, {0}'.format(1, 2, 'three') # E: "str" has no attribute "x" -''.format(1, 2) # E: Not all arguments converted during string formatting -[builtins fixtures/primitives.pyi] - -[case testFormatCallMatchingNamed] -'{named}'.format(0) # E: Cannot find replacement for named format specifier "named" \ - # E: Not all arguments converted during string formatting -'{one.x}, {two}'.format(one=1, two='two') # E: "int" has no attribute "x" -'{one}, {two}, {.x}'.format(1, one='two', two='three') # E: "int" has no attribute "x" -''.format(stuff='yes') # E: Not all arguments converted during string formatting -[builtins fixtures/primitives.pyi] - -[case testFormatCallMatchingVarArg] -from typing import List -args: List[int] = [] -'{}, {}'.format(1, 2, *args) # Don't flag this because args may be empty - -strings: List[str] -'{:d}, {[0].x}'.format(*strings) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") \ - # E: "str" has no attribute "x" -# TODO: this is a runtime error, but error message is confusing -'{[0][:]:d}'.format(*strings) # E: Syntax error in format specifier "0[0][" -[builtins fixtures/primitives.pyi] - -[case testFormatCallMatchingKwArg] -from typing import Dict -kwargs: Dict[str, str] = {} -'{one}, {two}'.format(one=1, two=2, **kwargs) # Don't flag this because args may be empty - -'{stuff:.3d}'.format(**kwargs) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") -'{stuff[0]:f}, {other}'.format(**kwargs) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float]") -'{stuff[0]:c}'.format(**kwargs) -[builtins fixtures/primitives.pyi] - -[case testFormatCallCustomFormatSpec] -from typing import Union -class Bad: - ... -class Good: - def __format__(self, spec: str) -> str: ... - -'{:OMG}'.format(Good()) -'{:OMG}'.format(Bad()) # E: Unrecognized format specification "OMG" -'{!s:OMG}'.format(Good()) # E: Unrecognized format specification "OMG" -'{:{}OMG{}}'.format(Bad(), 'too', 'dynamic') - -x: Union[Good, Bad] -'{:OMG}'.format(x) # E: Unrecognized format specification "OMG" -[builtins fixtures/primitives.pyi] - -[case testFormatCallFormatTypes] -'{:x}'.format(42) -'{:E}'.format(42) -'{:g}'.format(42) -'{:x}'.format('no') # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") -'{:E}'.format('no') # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float]") -'{:g}'.format('no') # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float]") -'{:n}'.format(3.14) -'{:d}'.format(3.14) # E: Incompatible types in string interpolation (expression has type "float", placeholder has type "int") - -'{:s}'.format(42) -'{:s}'.format('yes') - -'{:z}'.format('what') # E: Unsupported format character "z" -'{:Z}'.format('what') # E: Unsupported format character "Z" -[builtins fixtures/primitives.pyi] - -[case testFormatCallFormatTypesChar] -'{:c}'.format(42) -'{:c}'.format('no') # E: ":c" requires int or char -'{:c}'.format('c') - -class C: - ... -'{:c}'.format(C()) # E: Incompatible types in string interpolation (expression has type "C", placeholder has type "Union[int, str]") -x: str -'{:c}'.format(x) -[builtins fixtures/primitives.pyi] - -[case testFormatCallFormatTypesCustomFormat] -from typing import Union -class Bad: - ... -class Good: - def __format__(self, spec: str) -> str: ... - -x: Union[Good, Bad] -y: Union[Good, int] -z: Union[Bad, int] -t: Union[Good, str] -'{:d}'.format(x) # E: Incompatible types in string interpolation (expression has type "Bad", placeholder has type "int") -'{:d}'.format(y) -'{:d}'.format(z) # E: Incompatible types in string interpolation (expression has type "Bad", placeholder has type "int") -'{:d}'.format(t) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") -[builtins fixtures/primitives.pyi] - -[case testFormatCallFormatTypesBytes] -from typing import Union, TypeVar, NewType, Generic - -A = TypeVar('A', str, bytes) -B = TypeVar('B', bound=bytes) - -x: Union[str, bytes] -a: str -b: bytes - -N = NewType('N', bytes) -n: N - -'{}'.format(a) -'{}'.format(b) # E: On Python 3 '{}'.format(b'abc') produces "b'abc'", not 'abc'; use '{!r}'.format(b'abc') if this is desired behavior -'{}'.format(x) # E: On Python 3 '{}'.format(b'abc') produces "b'abc'", not 'abc'; use '{!r}'.format(b'abc') if this is desired behavior -'{}'.format(n) # E: On Python 3 '{}'.format(b'abc') produces "b'abc'", not 'abc'; use '{!r}'.format(b'abc') if this is desired behavior - -class C(Generic[B]): - x: B - def meth(self) -> None: - '{}'.format(self.x) # E: On Python 3 '{}'.format(b'abc') produces "b'abc'", not 'abc'; use '{!r}'.format(b'abc') if this is desired behavior - -def func(x: A) -> A: - '{}'.format(x) # E: On Python 3 '{}'.format(b'abc') produces "b'abc'", not 'abc'; use '{!r}'.format(b'abc') if this is desired behavior - return x - -'{!r}'.format(b) -'{!r}'.format(x) -'{!r}'.format(n) - -class D(bytes): - def __str__(self) -> str: - return "overrides __str__ of bytes" - -'{}'.format(D()) -[builtins fixtures/primitives.pyi] - -[case testFormatCallFormatTypesBytesNotPy2] -# flags: --py2 -from typing import Union, TypeVar, NewType, Generic - -A = TypeVar('A', str, unicode) -B = TypeVar('B', bound=str) - -x = '' # type: Union[str, unicode] -a = '' -b = b'' - -N = NewType('N', str) -n = N(b'') - -'{}'.format(a) -'{}'.format(b) -'{}'.format(x) -'{}'.format(n) - -u'{}'.format(a) -u'{}'.format(b) -u'{}'.format(x) -u'{}'.format(n) - -class C(Generic[B]): - x = None # type: B - def meth(self): - # type: () -> None - '{}'.format(self.x) - -def func(x): - # type: (A) -> A - '{}'.format(x) - return x - -'{!r}'.format(b) -'{!r}'.format(x) -'{!r}'.format(n) -[builtins_py2 fixtures/python2.pyi] - -[case testFormatCallFinal] -from typing_extensions import Final - -FMT: Final = '{.x}, {:{:d}}' - -FMT.format(1, 2, 'no') # E: "int" has no attribute "x" \ - # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") -[builtins fixtures/primitives.pyi] - -[case testFormatCallFinalChar] -from typing_extensions import Final - -GOOD: Final = 'c' -BAD: Final = 'no' -OK: Final[str] = '...' - -'{:c}'.format(GOOD) -'{:c}'.format(BAD) # E: ":c" requires int or char -'{:c}'.format(OK) -[builtins fixtures/primitives.pyi] - -[case testFormatCallForcedConversions] -'{!r}'.format(42) -'{!s}'.format(42) -'{!s:d}'.format(42) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") -'{!s:s}'.format('OK') -'{} and {!x}'.format(0, 1) # E: Invalid conversion type "x", must be one of "r", "s" or "a" -[builtins fixtures/primitives.pyi] - -[case testFormatCallAccessorsBasic] -from typing import Any -x: Any - -'{.x:{[0]}}'.format('yes', 42) # E: "str" has no attribute "x" \ - # E: Value of type "int" is not indexable - -'{.1+}'.format(x) # E: Syntax error in format specifier "0.1+" -'{name.x[x]()[x]:.2f}'.format(name=x) # E: Only index and member expressions are allowed in format field accessors; got "name.x[x]()[x]" -[builtins fixtures/primitives.pyi] - -[case testFormatCallAccessorsIndices] -from typing_extensions import TypedDict - -class User(TypedDict): - id: int - name: str - -u: User -'{user[name]:.3f}'.format(user=u) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float]") - -def f() -> str: ... -'{[f()]}'.format(u) # E: Invalid index expression in format field accessor "[f()]" -[builtins fixtures/primitives.pyi] - -[case testFormatCallFlags] -from typing import Union - -class Good: - def __format__(self, spec: str) -> str: ... - -'{:#}'.format(42) - -'{:#}'.format('no') # E: Numeric flags are only allowed for numeric types -'{!s:#}'.format(42) # E: Numeric flags are only allowed for numeric types - -'{:#s}'.format(42) # E: Numeric flags are only allowed for numeric types -'{:+s}'.format(42) # E: Numeric flags are only allowed for numeric types - -'{:+d}'.format(42) -'{:#d}'.format(42) - -x: Union[float, Good] -'{:+f}'.format(x) -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testFormatCallSpecialCases] -'{:08b}'.format(int('3')) - -class S: - def __int__(self) -> int: ... - -'{:+d}'.format(S()) # E: Incompatible types in string interpolation (expression has type "S", placeholder has type "int") -'%d' % S() # This is OK however -'{:%}'.format(0.001) -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -- Lambdas -- ------- @@ -2126,15 +1490,7 @@ if str(): ....a # E: "ellipsis" has no attribute "a" class A: pass -[file builtins.py] -class object: - def __init__(self): pass -class ellipsis: - def __init__(self): pass - __class__ = object() -class type: pass -class function: pass -class str: pass +[builtins fixtures/dict.pyi] [out] @@ -2366,6 +1722,19 @@ def f() -> None: [out] main:3: note: Revealed type is "builtins.int" +[case testLambdaTypedContext] +def f() -> None: + lambda: 'a'.missing() # E: "str" has no attribute "missing" + +[case testLambdaUnypedContext] +def f(): + lambda: 'a'.missing() + +[case testLambdaCheckUnypedContext] +# flags: --check-untyped-defs +def f(): + lambda: 'a'.missing() # E: "str" has no attribute "missing" + [case testEqNone] None == None [builtins fixtures/ops.pyi] diff --git a/test-data/unit/check-fastparse.test b/test-data/unit/check-fastparse.test index 497ed9b1d2b2..e2dc4f203855 100644 --- a/test-data/unit/check-fastparse.test +++ b/test-data/unit/check-fastparse.test @@ -317,13 +317,6 @@ x = None # type: Any x @ 1 x @= 1 -[case testIncorrectTypeCommentIndex] - -from typing import Dict -x = None # type: Dict[x: y] -[out] -main:3: error: syntax error in type comment - [case testPrintStatementTrailingCommaFastParser_python2] print 0, diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index e0825715db15..02f6b034c512 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -178,6 +178,67 @@ reveal_type(g) # N: Revealed type is "Any" reveal_type(h) # N: Revealed type is "def (*Any, **Any) -> Any" reveal_type(i) # N: Revealed type is "Any" +[case testDisallowUntypedDecoratorsCallableInstanceDecoratedCall] +# flags: --disallow-untyped-decorators +from typing import Callable, TypeVar + +C = TypeVar('C', bound=Callable) + +def typed_decorator(c: C) -> C: + return c + +def untyped_decorator(c): + return c + +class TypedDecorator: + @typed_decorator + def __call__(self, c: Callable) -> Callable: + return function + +class UntypedDecorator1: + @untyped_decorator + def __call__(self, c): + return function + +class UntypedDecorator2: + @untyped_decorator # E: Untyped decorator makes function "__call__" untyped + def __call__(self, c: Callable) -> Callable: + return function + +class UntypedDecorator3: + @typed_decorator + @untyped_decorator # E: Untyped decorator makes function "__call__" untyped + def __call__(self, c: Callable) -> Callable: + return function + +class UntypedDecorator4: + @untyped_decorator # E: Untyped decorator makes function "__call__" untyped + @typed_decorator + def __call__(self, c: Callable) -> Callable: + return function + +@TypedDecorator() +def f() -> None: pass + +@UntypedDecorator1() # E: Untyped decorator makes function "g1" untyped +def g1() -> None: pass + +@UntypedDecorator2() # E: Untyped decorator makes function "g2" untyped +def g2() -> None: pass + +@UntypedDecorator3() # E: Untyped decorator makes function "g3" untyped +def g3() -> None: pass + +@UntypedDecorator4() # E: Untyped decorator makes function "g4" untyped +def g4() -> None: pass + +reveal_type(f) # N: Revealed type is "def (*Any, **Any) -> Any" +reveal_type(g1) # N: Revealed type is "Any" +reveal_type(g2) # N: Revealed type is "Any" +reveal_type(g3) # N: Revealed type is "Any" +reveal_type(g4) # N: Revealed type is "Any" +[builtins fixtures/bool.pyi] + [case testDisallowUntypedDecoratorsNonCallableInstance] # flags: --disallow-untyped-decorators class Decorator: @@ -1525,6 +1586,16 @@ __all__ = ('b',) [out] main:2: error: Module "other_module_2" does not explicitly export attribute "a"; implicit reexport disabled +[case testNoImplicitReexportGetAttr] +# flags: --no-implicit-reexport --python-version 3.7 +from other_module_2 import a # E: Module "other_module_2" does not explicitly export attribute "a"; implicit reexport disabled +[file other_module_1.py] +from typing import Any +def __getattr__(name: str) -> Any: ... +[file other_module_2.py] +from other_module_1 import a +[builtins fixtures/tuple.pyi] + [case textNoImplicitReexportSuggestions] # flags: --no-implicit-reexport from other_module_2 import attr_1 diff --git a/test-data/unit/check-formatting.test b/test-data/unit/check-formatting.test new file mode 100644 index 000000000000..783c31c18770 --- /dev/null +++ b/test-data/unit/check-formatting.test @@ -0,0 +1,651 @@ + +-- String interpolation +-- -------------------- + +[case testStringInterpolationType] +from typing import Tuple +i, f, s, t = None, None, None, None # type: (int, float, str, Tuple[int]) +'%d' % i +'%f' % f +'%s' % s +'%d' % (f,) +'%d' % (s,) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float, SupportsInt]") +'%d' % t +'%d' % s # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float, SupportsInt]") +'%f' % s # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float, SupportsFloat]") +'%x' % f # E: Incompatible types in string interpolation (expression has type "float", placeholder has type "int") +'%i' % f +'%o' % f # E: Incompatible types in string interpolation (expression has type "float", placeholder has type "int") +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testStringInterpolationSAcceptsAnyType] +from typing import Any +i, o, s = None, None, None # type: (int, object, str) +'%s %s %s' % (i, o, s) +[builtins fixtures/primitives.pyi] + +[case testStringInterpolationSBytesVsStrErrorPy3] +xb: bytes +xs: str + +'%s' % xs # OK +'%s' % xb # E: On Python 3 formatting "b'abc'" with "%s" produces "b'abc'", not "abc"; use "%r" if this is desired behavior +'%(name)s' % {'name': b'value'} # E: On Python 3 formatting "b'abc'" with "%s" produces "b'abc'", not "abc"; use "%r" if this is desired behavior +[builtins fixtures/primitives.pyi] + +[case testStringInterpolationSBytesVsStrResultsPy2] +# flags: --python-version 2.7 +xs = 'x' +xu = u'x' + +reveal_type('%s' % xu) # N: Revealed type is "builtins.unicode" +reveal_type('%s, %d' % (u'abc', 42)) # N: Revealed type is "builtins.unicode" +reveal_type('%(key)s' % {'key': xu}) # N: Revealed type is "builtins.unicode" +reveal_type('%r' % xu) # N: Revealed type is "builtins.str" +reveal_type('%s' % xs) # N: Revealed type is "builtins.str" +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testStringInterpolationCount] +'%d %d' % 1 # E: Not enough arguments for format string +'%d %d' % (1, 2) +'%d %d' % (1, 2, 3) # E: Not all arguments converted during string formatting +t = 1, 's' +'%d %s' % t +'%s %d' % t # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float, SupportsInt]") +'%d' % t # E: Not all arguments converted during string formatting +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testStringInterpolationWithAnyType] +from typing import Any +a = None # type: Any +'%d %d' % a +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testStringInterpolationInvalidPlaceholder] +'%W' % 1 # E: Unsupported format character "W" +'%b' % 1 # E: Format character "b" is only supported on bytes patterns + +[case testStringInterPolationPython2] +# flags: --python-version 2.7 +b'%b' % 1 # E: Format character "b" is only supported in Python 3.5 and later +b'%s' % 1 +b'%a' % 1 # E: Format character "a" is only supported in Python 3 + +[case testStringInterpolationWidth] +'%2f' % 3.14 +'%*f' % 3.14 # E: Not enough arguments for format string +'%*f' % (4, 3.14) +'%*f' % (1.1, 3.14) # E: * wants int +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testStringInterpolationPrecision] +'%.2f' % 3.14 +'%.*f' % 3.14 # E: Not enough arguments for format string +'%.*f' % (4, 3.14) +'%.*f' % (1.1, 3.14) # E: * wants int +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testStringInterpolationWidthAndPrecision] +'%4.2f' % 3.14 +'%4.*f' % 3.14 # E: Not enough arguments for format string +'%*.2f' % 3.14 # E: Not enough arguments for format string +'%*.*f' % 3.14 # E: Not enough arguments for format string +'%*.*f' % (4, 2, 3.14) +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testStringInterpolationFlagsAndLengthModifiers] +'%04hd' % 1 +'%-.4ld' % 1 +'%+*Ld' % (1, 1) +'% .*ld' % (1, 1) +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testStringInterpolationDoublePercentage] +'%% %d' % 1 +'%3% %d' % 1 +'%*%' % 1 +'%*% %d' % 1 # E: Not enough arguments for format string +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testStringInterPolationCPython2] +# flags: --py2 --no-strict-optional +'%c' % 1 +'%c' % 1.0 # E: "%c" requires int or char (expression has type "float") +'%c' % 's' +'%c' % '' # E: "%c" requires int or char +'%c' % 'ab' # E: "%c" requires int or char +'%c' % b'a' +'%c' % b'' # E: "%c" requires int or char +'%c' % b'ab' # E: "%c" requires int or char +[builtins_py2 fixtures/python2.pyi] + +[case testStringInterpolationC] +# flags: --python-version 3.6 +'%c' % 1 +'%c' % 1.0 # E: "%c" requires int or char (expression has type "float") +'%c' % 's' +'%c' % '' # E: "%c" requires int or char +'%c' % 'ab' # E: "%c" requires int or char +'%c' % b'a' # E: "%c" requires int or char (expression has type "bytes") +'%c' % b'' # E: "%c" requires int or char (expression has type "bytes") +'%c' % b'ab' # E: "%c" requires int or char (expression has type "bytes") +[builtins fixtures/primitives.pyi] + +[case testStringInterpolationMappingTypes] +'%(a)d %(b)s' % {'a': 1, 'b': 's'} +'%(a)d %(b)s' % {'a': 's', 'b': 1} # E: Incompatible types in string interpolation (expression has type "str", placeholder with key 'a' has type "Union[int, float, SupportsInt]") +b'%(x)s' % {b'x': b'data'} +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testStringInterpolationMappingKeys] +'%()d' % {'': 2} +'%(a)d' % {'a': 1, 'b': 2, 'c': 3} +'%(q)d' % {'a': 1, 'b': 2, 'c': 3} # E: Key "q" not found in mapping +'%(a)d %%' % {'a': 1} +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testStringInterpolationMappingDictTypes] +from typing import Any, Dict +a = None # type: Any +ds, do, di = None, None, None # type: Dict[str, int], Dict[object, int], Dict[int, int] +'%(a)' % 1 # E: Format requires a mapping (expression has type "int", expected type for mapping is "Mapping[str, Any]") +'%()d' % a +'%()d' % ds +'%()d' % do # E: Format requires a mapping (expression has type "Dict[object, int]", expected type for mapping is "Mapping[str, Any]") +b'%()d' % ds # E: Format requires a mapping (expression has type "Dict[str, int]", expected type for mapping is "Mapping[bytes, Any]") +[builtins fixtures/primitives.pyi] + +[case testStringInterpolationMappingInvalidDictTypesPy2] +# flags: --py2 --no-strict-optional +from typing import Any, Dict +di = None # type: Dict[int, int] +'%()d' % di # E: Format requires a mapping (expression has type "Dict[int, int]", expected type for mapping is "Union[Mapping[str, Any], Mapping[unicode, Any]]") +[builtins_py2 fixtures/python2.pyi] + +[case testStringInterpolationMappingInvalidSpecifiers] +'%(a)d %d' % 1 # E: String interpolation mixes specifier with and without mapping keys +'%(b)*d' % 1 # E: String interpolation contains both stars and mapping keys +'%(b).*d' % 1 # E: String interpolation contains both stars and mapping keys + +[case testStringInterpolationMappingFlagsAndLengthModifiers] +'%(a)1d' % {'a': 1} +'%(a).1d' % {'a': 1} +'%(a)#1.1ld' % {'a': 1} +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testStringInterpolationFloatPrecision] +'%.f' % 1.2 +'%.3f' % 1.2 +'%.f' % 'x' +'%.3f' % 'x' +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] +[out] +main:3: error: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float, SupportsFloat]") +main:4: error: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float, SupportsFloat]") + +[case testStringInterpolationSpaceKey] +'%( )s' % {' ': 'foo'} + +[case testStringInterpolationStarArgs] +x = (1, 2) +"%d%d" % (*x,) +[typing fixtures/typing-medium.pyi] +[builtins fixtures/tuple.pyi] + +[case testStringInterpolationVariableLengthTuple] +from typing import Tuple +def f(t: Tuple[int, ...]) -> None: + '%d %d' % t + '%d %d %d' % t +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testStringInterpolationUnionType] +from typing import Tuple, Union +a: Union[Tuple[int, str], Tuple[str, int]] = ('A', 1) +'%s %s' % a +'%s' % a # E: Not all arguments converted during string formatting + +b: Union[Tuple[int, str], Tuple[int, int], Tuple[str, int]] = ('A', 1) +'%s %s' % b +'%s %s %s' % b # E: Not enough arguments for format string + +c: Union[Tuple[str, int], Tuple[str, int, str]] = ('A', 1) +'%s %s' % c # E: Not all arguments converted during string formatting +[builtins fixtures/tuple.pyi] + +[case testStringInterpolationIterableType] +from typing import Sequence, List, Tuple, Iterable + +t1: Sequence[str] = ('A', 'B') +t2: List[str] = ['A', 'B'] +t3: Tuple[str, ...] = ('A', 'B') +t4: Tuple[str, str] = ('A', 'B') +t5: Iterable[str] = ('A', 'B') +'%s %s' % t1 +'%s %s' % t2 +'%s %s' % t3 +'%s %s %s' % t3 +'%s %s' % t4 +'%s %s %s' % t4 # E: Not enough arguments for format string +'%s %s' % t5 +[builtins fixtures/tuple.pyi] + +[case testUnicodeInterpolation_python2] +u'%s' % (u'abc',) + + +-- Bytes interpolation +-- -------------------- + + +[case testBytesInterpolationBefore35] +# flags: --python-version 3.4 +b'%b' % 1 # E: Unsupported left operand type for % ("bytes") + +[case testBytesInterpolation] +b'%b' % 1 # E: Incompatible types in string interpolation (expression has type "int", placeholder has type "bytes") +b'%b' % b'1' +b'%a' % 3 + +[case testBytesInterPolationCPython2] +# flags: --py2 --no-strict-optional +b'%c' % 1 +b'%c' % 1.0 # E: "%c" requires int or char (expression has type "float") +b'%c' % 's' +b'%c' % '' # E: "%c" requires int or char +b'%c' % 'ab' # E: "%c" requires int or char +b'%c' % b'a' +b'%c' % b'' # E: "%c" requires int or char +b'%c' % b'aa' # E: "%c" requires int or char +[builtins_py2 fixtures/python2.pyi] + +[case testBytesInterpolationC] +# flags: --python-version 3.6 +b'%c' % 1 +b'%c' % 1.0 # E: "%c" requires an integer in range(256) or a single byte (expression has type "float") +b'%c' % 's' # E: "%c" requires an integer in range(256) or a single byte (expression has type "str") +b'%c' % '' # E: "%c" requires an integer in range(256) or a single byte (expression has type "str") +b'%c' % 'ab' # E: "%c" requires an integer in range(256) or a single byte (expression has type "str") +b'%c' % b'a' +b'%c' % b'' # E: "%c" requires an integer in range(256) or a single byte +b'%c' % b'aa' # E: "%c" requires an integer in range(256) or a single byte +[builtins fixtures/primitives.pyi] + +[case testByteByteInterpolation] +def foo(a: bytes, b: bytes): + b'%s:%s' % (a, b) +foo(b'a', b'b') == b'a:b' +[builtins fixtures/tuple.pyi] + +[case testBytePercentInterpolationSupported] +b'%s' % (b'xyz',) +b'%(name)s' % {'name': b'jane'} # E: Dictionary keys in bytes formatting must be bytes, not strings +b'%(name)s' % {b'name': 'jane'} # E: On Python 3 b'%s' requires bytes, not string +b'%c' % (123) +[builtins fixtures/tuple.pyi] + + +-- str.format() calls +-- ------------------ + + +[case testFormatCallParseErrors] +'}'.format() # E: Invalid conversion specifier in format string: unexpected } +'{'.format() # E: Invalid conversion specifier in format string: unmatched { + +'}}'.format() # OK +'{{'.format() # OK + +'{{}}}'.format() # E: Invalid conversion specifier in format string: unexpected } +'{{{}}'.format() # E: Invalid conversion specifier in format string: unexpected } + +'{}}{{}'.format() # E: Invalid conversion specifier in format string: unexpected } +'{{{}:{}}}'.format(0) # E: Cannot find replacement for positional format specifier 1 +[builtins fixtures/primitives.pyi] + +[case testFormatCallValidationErrors] +'{!}}'.format(0) # E: Invalid conversion specifier in format string: unexpected } +'{!x}'.format(0) # E: Invalid conversion type "x", must be one of "r", "s" or "a" +'{!:}'.format(0) # E: Invalid conversion specifier in format string + +'{{}:s}'.format(0) # E: Invalid conversion specifier in format string: unexpected } +'{{}.attr}'.format(0) # E: Invalid conversion specifier in format string: unexpected } +'{{}[key]}'.format(0) # E: Invalid conversion specifier in format string: unexpected } + +'{ {}:s}'.format() # E: Conversion value must not contain { or } +'{ {}.attr}'.format() # E: Conversion value must not contain { or } +'{ {}[key]}'.format() # E: Conversion value must not contain { or } +[builtins fixtures/primitives.pyi] + +[case testFormatCallEscaping] +'{}'.format() # E: Cannot find replacement for positional format specifier 0 +'{}'.format(0) # OK + +'{{}}'.format() # OK +'{{}}'.format(0) # E: Not all arguments converted during string formatting + +'{{{}}}'.format() # E: Cannot find replacement for positional format specifier 0 +'{{{}}}'.format(0) # OK + +'{{}} {} {{}}'.format(0) # OK +'{{}} {:d} {{}} {:d}'.format('a', 'b') # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") + +'foo({}, {}) == {{}} ({{}} expected)'.format(0) # E: Cannot find replacement for positional format specifier 1 +'foo({}, {}) == {{}} ({{}} expected)'.format(0, 1) # OK +'foo({}, {}) == {{}} ({{}} expected)'.format(0, 1, 2) # E: Not all arguments converted during string formatting +[builtins fixtures/primitives.pyi] + +[case testFormatCallNestedFormats] +'{:{}{}}'.format(42, '*') # E: Cannot find replacement for positional format specifier 2 +'{:{}{}}'.format(42, '*', '^') # OK +'{:{}{}}'.format(42, '*', '^', 0) # E: Not all arguments converted during string formatting + +# NOTE: we don't check format specifiers that contain { or } at all +'{:{{}}}'.format() # E: Cannot find replacement for positional format specifier 0 + +'{:{:{}}}'.format() # E: Formatting nesting must be at most two levels deep +'{:{{}:{}}}'.format() # E: Invalid conversion specifier in format string: unexpected } + +'{!s:{fill:d}{align}}'.format(42, fill='*', align='^') # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") +[builtins fixtures/primitives.pyi] + +[case testFormatCallAutoNumbering] +'{}, {{}}, {0}'.format() # E: Cannot combine automatic field numbering and manual field specification +'{0}, {1}, {}'.format() # E: Cannot combine automatic field numbering and manual field specification + +'{0}, {1}, {0}'.format(1, 2, 3) # E: Not all arguments converted during string formatting +'{}, {other:+d}, {}'.format(1, 2, other='no') # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") +'{0}, {other}, {}'.format() # E: Cannot combine automatic field numbering and manual field specification + +'{:{}}, {:{:.5d}{}}'.format(1, 2, 3, 'a', 5) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") +[builtins fixtures/primitives.pyi] + +[case testFormatCallMatchingPositional] +'{}'.format(positional='no') # E: Cannot find replacement for positional format specifier 0 \ + # E: Not all arguments converted during string formatting +'{.x}, {}, {}'.format(1, 'two', 'three') # E: "int" has no attribute "x" +'Reverse {2.x}, {1}, {0}'.format(1, 2, 'three') # E: "str" has no attribute "x" +''.format(1, 2) # E: Not all arguments converted during string formatting +[builtins fixtures/primitives.pyi] + +[case testFormatCallMatchingNamed] +'{named}'.format(0) # E: Cannot find replacement for named format specifier "named" \ + # E: Not all arguments converted during string formatting +'{one.x}, {two}'.format(one=1, two='two') # E: "int" has no attribute "x" +'{one}, {two}, {.x}'.format(1, one='two', two='three') # E: "int" has no attribute "x" +''.format(stuff='yes') # E: Not all arguments converted during string formatting +[builtins fixtures/primitives.pyi] + +[case testFormatCallMatchingVarArg] +from typing import List +args: List[int] = [] +'{}, {}'.format(1, 2, *args) # Don't flag this because args may be empty + +strings: List[str] +'{:d}, {[0].x}'.format(*strings) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") \ + # E: "str" has no attribute "x" +# TODO: this is a runtime error, but error message is confusing +'{[0][:]:d}'.format(*strings) # E: Syntax error in format specifier "0[0][" +[builtins fixtures/primitives.pyi] + +[case testFormatCallMatchingKwArg] +from typing import Dict +kwargs: Dict[str, str] = {} +'{one}, {two}'.format(one=1, two=2, **kwargs) # Don't flag this because args may be empty + +'{stuff:.3d}'.format(**kwargs) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") +'{stuff[0]:f}, {other}'.format(**kwargs) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float]") +'{stuff[0]:c}'.format(**kwargs) +[builtins fixtures/primitives.pyi] + +[case testFormatCallCustomFormatSpec] +from typing import Union +class Bad: + ... +class Good: + def __format__(self, spec: str) -> str: ... + +'{:OMG}'.format(Good()) +'{:OMG}'.format(Bad()) # E: Unrecognized format specification "OMG" +'{!s:OMG}'.format(Good()) # E: Unrecognized format specification "OMG" +'{:{}OMG{}}'.format(Bad(), 'too', 'dynamic') + +x: Union[Good, Bad] +'{:OMG}'.format(x) # E: Unrecognized format specification "OMG" +[builtins fixtures/primitives.pyi] + +[case testFormatCallFormatTypes] +'{:x}'.format(42) +'{:E}'.format(42) +'{:g}'.format(42) +'{:x}'.format('no') # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") +'{:E}'.format('no') # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float]") +'{:g}'.format('no') # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float]") +'{:n}'.format(3.14) +'{:d}'.format(3.14) # E: Incompatible types in string interpolation (expression has type "float", placeholder has type "int") + +'{:s}'.format(42) +'{:s}'.format('yes') + +'{:z}'.format('what') # E: Unsupported format character "z" +'{:Z}'.format('what') # E: Unsupported format character "Z" +[builtins fixtures/primitives.pyi] + +[case testFormatCallFormatTypesChar] +'{:c}'.format(42) +'{:c}'.format('no') # E: ":c" requires int or char +'{:c}'.format('c') + +class C: + ... +'{:c}'.format(C()) # E: Incompatible types in string interpolation (expression has type "C", placeholder has type "Union[int, str]") +x: str +'{:c}'.format(x) +[builtins fixtures/primitives.pyi] + +[case testFormatCallFormatTypesCustomFormat] +from typing import Union +class Bad: + ... +class Good: + def __format__(self, spec: str) -> str: ... + +x: Union[Good, Bad] +y: Union[Good, int] +z: Union[Bad, int] +t: Union[Good, str] +'{:d}'.format(x) # E: Incompatible types in string interpolation (expression has type "Bad", placeholder has type "int") +'{:d}'.format(y) +'{:d}'.format(z) # E: Incompatible types in string interpolation (expression has type "Bad", placeholder has type "int") +'{:d}'.format(t) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") +[builtins fixtures/primitives.pyi] + +[case testFormatCallFormatTypesBytes] +from typing import Union, TypeVar, NewType, Generic + +A = TypeVar('A', str, bytes) +B = TypeVar('B', bound=bytes) + +x: Union[str, bytes] +a: str +b: bytes + +N = NewType('N', bytes) +n: N + +'{}'.format(a) +'{}'.format(b) # E: On Python 3 formatting "b'abc'" with "{}" produces "b'abc'", not "abc"; use "{!r}" if this is desired behavior +'{}'.format(x) # E: On Python 3 formatting "b'abc'" with "{}" produces "b'abc'", not "abc"; use "{!r}" if this is desired behavior +'{}'.format(n) # E: On Python 3 formatting "b'abc'" with "{}" produces "b'abc'", not "abc"; use "{!r}" if this is desired behavior + +f'{b}' # E: On Python 3 formatting "b'abc'" with "{}" produces "b'abc'", not "abc"; use "{!r}" if this is desired behavior +f'{x}' # E: On Python 3 formatting "b'abc'" with "{}" produces "b'abc'", not "abc"; use "{!r}" if this is desired behavior +f'{n}' # E: On Python 3 formatting "b'abc'" with "{}" produces "b'abc'", not "abc"; use "{!r}" if this is desired behavior + +class C(Generic[B]): + x: B + def meth(self) -> None: + '{}'.format(self.x) # E: On Python 3 formatting "b'abc'" with "{}" produces "b'abc'", not "abc"; use "{!r}" if this is desired behavior + +def func(x: A) -> A: + '{}'.format(x) # E: On Python 3 formatting "b'abc'" with "{}" produces "b'abc'", not "abc"; use "{!r}" if this is desired behavior + return x + +'{!r}'.format(a) +'{!r}'.format(b) +'{!r}'.format(x) +'{!r}'.format(n) +f'{a}' +f'{a!r}' +f'{b!r}' +f'{x!r}' +f'{n!r}' + +class D(bytes): + def __str__(self) -> str: + return "overrides __str__ of bytes" + +'{}'.format(D()) +[builtins fixtures/primitives.pyi] + +[case testFormatCallFormatTypesBytesNotPy2] +# flags: --py2 +from typing import Union, TypeVar, NewType, Generic + +A = TypeVar('A', str, unicode) +B = TypeVar('B', bound=str) + +x = '' # type: Union[str, unicode] +a = '' +b = b'' + +N = NewType('N', str) +n = N(b'') + +'{}'.format(a) +'{}'.format(b) +'{}'.format(x) +'{}'.format(n) + +u'{}'.format(a) +u'{}'.format(b) +u'{}'.format(x) +u'{}'.format(n) + +class C(Generic[B]): + x = None # type: B + def meth(self): + # type: () -> None + '{}'.format(self.x) + +def func(x): + # type: (A) -> A + '{}'.format(x) + return x + +'{!r}'.format(b) +'{!r}'.format(x) +'{!r}'.format(n) +[builtins_py2 fixtures/python2.pyi] + +[case testFormatCallFinal] +from typing_extensions import Final + +FMT: Final = '{.x}, {:{:d}}' + +FMT.format(1, 2, 'no') # E: "int" has no attribute "x" \ + # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") +[builtins fixtures/primitives.pyi] + +[case testFormatCallFinalChar] +from typing_extensions import Final + +GOOD: Final = 'c' +BAD: Final = 'no' +OK: Final[str] = '...' + +'{:c}'.format(GOOD) +'{:c}'.format(BAD) # E: ":c" requires int or char +'{:c}'.format(OK) +[builtins fixtures/primitives.pyi] + +[case testFormatCallForcedConversions] +'{!r}'.format(42) +'{!s}'.format(42) +'{!s:d}'.format(42) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "int") +'{!s:s}'.format('OK') +'{} and {!x}'.format(0, 1) # E: Invalid conversion type "x", must be one of "r", "s" or "a" +[builtins fixtures/primitives.pyi] + +[case testFormatCallAccessorsBasic] +from typing import Any +x: Any + +'{.x:{[0]}}'.format('yes', 42) # E: "str" has no attribute "x" \ + # E: Value of type "int" is not indexable + +'{.1+}'.format(x) # E: Syntax error in format specifier "0.1+" +'{name.x[x]()[x]:.2f}'.format(name=x) # E: Only index and member expressions are allowed in format field accessors; got "name.x[x]()[x]" +[builtins fixtures/primitives.pyi] + +[case testFormatCallAccessorsIndices] +from typing_extensions import TypedDict + +class User(TypedDict): + id: int + name: str + +u: User +'{user[name]:.3f}'.format(user=u) # E: Incompatible types in string interpolation (expression has type "str", placeholder has type "Union[int, float]") + +def f() -> str: ... +'{[f()]}'.format(u) # E: Invalid index expression in format field accessor "[f()]" +[builtins fixtures/primitives.pyi] + +[case testFormatCallFlags] +from typing import Union + +class Good: + def __format__(self, spec: str) -> str: ... + +'{:#}'.format(42) + +'{:#}'.format('no') # E: Numeric flags are only allowed for numeric types +'{!s:#}'.format(42) # E: Numeric flags are only allowed for numeric types + +'{:#s}'.format(42) # E: Numeric flags are only allowed for numeric types +'{:+s}'.format(42) # E: Numeric flags are only allowed for numeric types + +'{:+d}'.format(42) +'{:#d}'.format(42) + +x: Union[float, Good] +'{:+f}'.format(x) +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testFormatCallSpecialCases] +'{:08b}'.format(int('3')) + +class S: + def __int__(self) -> int: ... + +'{:+d}'.format(S()) # E: Incompatible types in string interpolation (expression has type "S", placeholder has type "int") +'%d' % S() # This is OK however +'{:%}'.format(0.001) +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test index 3f75fc5deb9a..bdf75b2dc58c 100644 --- a/test-data/unit/check-functions.test +++ b/test-data/unit/check-functions.test @@ -599,12 +599,12 @@ A().f('') # E: Argument 1 to "f" of "A" has incompatible type "str"; expected "i [case testMethodAsDataAttribute] -from typing import Any, Callable, ClassVar +from typing import Any, Callable class B: pass x = None # type: Any class A: - f = x # type: ClassVar[Callable[[A], None]] - g = x # type: ClassVar[Callable[[A, B], None]] + f = x # type: Callable[[A], None] + g = x # type: Callable[[A, B], None] a = None # type: A a.f() a.g(B()) @@ -612,38 +612,26 @@ a.f(a) # E: Too many arguments a.g() # E: Too few arguments [case testMethodWithInvalidMethodAsDataAttribute] -from typing import Any, Callable, ClassVar +from typing import Any, Callable class B: pass x = None # type: Any class A: - f = x # type: ClassVar[Callable[[], None]] - g = x # type: ClassVar[Callable[[B], None]] + f = x # type: Callable[[], None] + g = x # type: Callable[[B], None] a = None # type: A a.f() # E: Attribute function "f" with type "Callable[[], None]" does not accept self argument a.g() # E: Invalid self argument "A" to attribute function "g" with type "Callable[[B], None]" [case testMethodWithDynamicallyTypedMethodAsDataAttribute] -from typing import Any, Callable, ClassVar +from typing import Any, Callable class B: pass x = None # type: Any class A: - f = x # type: ClassVar[Callable[[Any], Any]] + f = x # type: Callable[[Any], Any] a = None # type: A a.f() a.f(a) # E: Too many arguments -[case testMethodWithInferredMethodAsDataAttribute] -from typing import Any -def m(self: "A") -> int: ... - -class A: - n = m - -a = A() -reveal_type(a.n()) # N: Revealed type is "builtins.int" -reveal_type(A.n(a)) # N: Revealed type is "builtins.int" -A.n() # E: Too few arguments - [case testOverloadedMethodAsDataAttribute] from foo import * [file foo.pyi] @@ -659,9 +647,9 @@ a = None # type: A a.g() a.g(B()) a.g(a) # E: No overload variant matches argument type "A" \ - # N: Possible overload variant: \ - # N: def f(self, b: B) -> None \ - # N: <1 more non-matching overload not shown> + # N: Possible overload variants: \ + # N: def f(self) -> None \ + # N: def f(self, b: B) -> None [case testMethodAsDataAttributeInferredFromDynamicallyTypedMethod] @@ -685,35 +673,35 @@ a.g(B()) a.g(a) # E: Argument 1 has incompatible type "A[B]"; expected "B" [case testInvalidMethodAsDataAttributeInGenericClass] -from typing import Any, TypeVar, Generic, Callable, ClassVar +from typing import Any, TypeVar, Generic, Callable t = TypeVar('t') class B: pass class C: pass x = None # type: Any class A(Generic[t]): - f = x # type: ClassVar[Callable[[A[B]], None]] + f = x # type: Callable[[A[B]], None] ab = None # type: A[B] ac = None # type: A[C] ab.f() ac.f() # E: Invalid self argument "A[C]" to attribute function "f" with type "Callable[[A[B]], None]" [case testPartiallyTypedSelfInMethodDataAttribute] -from typing import Any, TypeVar, Generic, Callable, ClassVar +from typing import Any, TypeVar, Generic, Callable t = TypeVar('t') class B: pass class C: pass x = None # type: Any class A(Generic[t]): - f = x # type: ClassVar[Callable[[A], None]] + f = x # type: Callable[[A], None] ab = None # type: A[B] ac = None # type: A[C] ab.f() ac.f() [case testCallableDataAttribute] -from typing import Callable, ClassVar +from typing import Callable class A: - g = None # type: ClassVar[Callable[[A], None]] + g = None # type: Callable[[A], None] def __init__(self, f: Callable[[], None]) -> None: self.f = f a = A(None) @@ -1497,7 +1485,7 @@ x = None # type: Any if x: def f(x: int) -> None: pass # E: All conditional function variants must have identical signatures -[case testConditionalRedefinitionOfAnUnconditionalFunctionDefinition1] +[case testConditionalRedefinitionOfAnUnconditionalFunctionDefinition2] from typing import Any def f(x: int) -> None: pass # N: "f" defined here x = None # type: Any @@ -2224,7 +2212,7 @@ from typing import Callable class A: def f(self) -> None: # In particular, test that the error message contains "g" of "A". - self.g() # E: Too few arguments for "g" of "A" + self.g() # E: Too few arguments for "g" of "A" self.g(1) @dec def g(self, x: str) -> None: pass @@ -2242,6 +2230,12 @@ reveal_type(h) # N: Revealed type is "builtins.function" h(7) # E: Cannot call function of unknown type [builtins fixtures/bool.pyi] +[case testFunctionWithNameUnderscore] +def _(x: int) -> None: pass + +_(1) +_('x') # E: Argument 1 to "_" has incompatible type "str"; expected "int" + -- Positional-only arguments -- ------------------------- diff --git a/test-data/unit/check-functools.test b/test-data/unit/check-functools.test index 5332454202cc..33653c8d3fbc 100644 --- a/test-data/unit/check-functools.test +++ b/test-data/unit/check-functools.test @@ -25,12 +25,12 @@ Ord() >= 1 # E: Unsupported operand types for >= ("Ord" and "int") [case testTotalOrderingLambda] from functools import total_ordering -from typing import Any, Callable, ClassVar +from typing import Any, Callable @total_ordering class Ord: - __eq__: ClassVar[Callable[[Any, object], bool]] = lambda self, other: False - __lt__: ClassVar[Callable[[Any, "Ord"], bool]] = lambda self, other: False + __eq__: Callable[[Any, object], bool] = lambda self, other: False + __lt__: Callable[[Any, "Ord"], bool] = lambda self, other: False reveal_type(Ord() < Ord()) # N: Revealed type is "builtins.bool" reveal_type(Ord() <= Ord()) # N: Revealed type is "builtins.bool" diff --git a/test-data/unit/check-generic-subtyping.test b/test-data/unit/check-generic-subtyping.test index d1420a43f9e4..f97e3015fa32 100644 --- a/test-data/unit/check-generic-subtyping.test +++ b/test-data/unit/check-generic-subtyping.test @@ -818,7 +818,7 @@ class Y(Generic[T]): return U() # E: Incompatible return value type (got "U", expected "T") -[case testTypeVarBoundToUnionAttributeAccess] +[case testTypeVarBoundToOldUnionAttributeAccess] from typing import Union, TypeVar class U: @@ -842,3 +842,194 @@ main:14: error: Item "U" of the upper bound "Union[U, V, W]" of type variable "T main:14: error: Item "W" of the upper bound "Union[U, V, W]" of type variable "T" has no attribute "b" main:15: error: Item "U" of the upper bound "Union[U, V, W]" of type variable "T" has no attribute "c" main:15: error: Item "V" of the upper bound "Union[U, V, W]" of type variable "T" has no attribute "c" + + +[case testTypeVarBoundToNewUnionAttributeAccess] +# flags: --python-version 3.10 +from typing import TypeVar + +class U: + a: int +class V: + b: int +class W: + c: int + +T = TypeVar("T", bound=U | V | W) + +def f(x: T) -> None: + x.a # E + x.b = 1 # E + del x.c # E + +[builtins fixtures/tuple.pyi] +[out] +main:14: error: Item "V" of the upper bound "Union[U, V, W]" of type variable "T" has no attribute "a" +main:14: error: Item "W" of the upper bound "Union[U, V, W]" of type variable "T" has no attribute "a" +main:15: error: Item "U" of the upper bound "Union[U, V, W]" of type variable "T" has no attribute "b" +main:15: error: Item "W" of the upper bound "Union[U, V, W]" of type variable "T" has no attribute "b" +main:16: error: Item "U" of the upper bound "Union[U, V, W]" of type variable "T" has no attribute "c" +main:16: error: Item "V" of the upper bound "Union[U, V, W]" of type variable "T" has no attribute "c" + + +[case testSubtypingIterableUnpacking1] +# https://github.com/python/mypy/issues/11138 +from typing import Generic, Iterator, TypeVar +T = TypeVar("T") +U = TypeVar("U") + +class X1(Iterator[U], Generic[T, U]): + pass + +x1: X1[str, int] +reveal_type(list(x1)) # N: Revealed type is "builtins.list[builtins.int*]" +reveal_type([*x1]) # N: Revealed type is "builtins.list[builtins.int*]" + +class X2(Iterator[T], Generic[T, U]): + pass + +x2: X2[str, int] +reveal_type(list(x2)) # N: Revealed type is "builtins.list[builtins.str*]" +reveal_type([*x2]) # N: Revealed type is "builtins.list[builtins.str*]" + +class X3(Generic[T, U], Iterator[U]): + pass + +x3: X3[str, int] +reveal_type(list(x3)) # N: Revealed type is "builtins.list[builtins.int*]" +reveal_type([*x3]) # N: Revealed type is "builtins.list[builtins.int*]" + +class X4(Generic[T, U], Iterator[T]): + pass + +x4: X4[str, int] +reveal_type(list(x4)) # N: Revealed type is "builtins.list[builtins.str*]" +reveal_type([*x4]) # N: Revealed type is "builtins.list[builtins.str*]" + +class X5(Iterator[T]): + pass + +x5: X5[str] +reveal_type(list(x5)) # N: Revealed type is "builtins.list[builtins.str*]" +reveal_type([*x5]) # N: Revealed type is "builtins.list[builtins.str*]" + +class X6(Generic[T, U], Iterator[bool]): + pass + +x6: X6[str, int] +reveal_type(list(x6)) # N: Revealed type is "builtins.list[builtins.bool*]" +reveal_type([*x6]) # N: Revealed type is "builtins.list[builtins.bool*]" +[builtins fixtures/list.pyi] + +[case testSubtypingIterableUnpacking2] +from typing import Generic, Iterator, TypeVar, Mapping +T = TypeVar("T") +U = TypeVar("U") + +class X1(Generic[T, U], Iterator[U], Mapping[U, T]): + pass + +x1: X1[str, int] +reveal_type(list(x1)) # N: Revealed type is "builtins.list[builtins.int*]" +reveal_type([*x1]) # N: Revealed type is "builtins.list[builtins.int*]" + +class X2(Generic[T, U], Iterator[U], Mapping[T, U]): + pass + +x2: X2[str, int] +reveal_type(list(x2)) # N: Revealed type is "builtins.list[builtins.int*]" +reveal_type([*x2]) # N: Revealed type is "builtins.list[builtins.int*]" +[builtins fixtures/list.pyi] + +[case testSubtypingMappingUnpacking1] +# https://github.com/python/mypy/issues/11138 +from typing import Generic, TypeVar, Mapping +T = TypeVar("T") +U = TypeVar("U") + +class X1(Generic[T, U], Mapping[U, T]): + pass + +x1: X1[str, int] +reveal_type(iter(x1)) # N: Revealed type is "typing.Iterator[builtins.int*]" +reveal_type({**x1}) # N: Revealed type is "builtins.dict[builtins.int*, builtins.str*]" + +class X2(Generic[T, U], Mapping[T, U]): + pass + +x2: X2[str, int] +reveal_type(iter(x2)) # N: Revealed type is "typing.Iterator[builtins.str*]" +reveal_type({**x2}) # N: Revealed type is "builtins.dict[builtins.str*, builtins.int*]" + +class X3(Generic[T, U], Mapping[bool, float]): + pass + +x3: X3[str, int] +reveal_type(iter(x3)) # N: Revealed type is "typing.Iterator[builtins.bool*]" +reveal_type({**x3}) # N: Revealed type is "builtins.dict[builtins.bool*, builtins.float*]" +[builtins fixtures/dict.pyi] + +[case testSubtypingMappingUnpacking2] +from typing import Generic, TypeVar, Mapping +T = TypeVar("T") +U = TypeVar("U") + +class X1(Generic[T, U], Mapping[U, T]): + pass + +def func_with_kwargs(**kwargs: int): + pass + +x1: X1[str, int] +reveal_type(iter(x1)) +reveal_type({**x1}) +func_with_kwargs(**x1) +[out] +main:12: note: Revealed type is "typing.Iterator[builtins.int*]" +main:13: note: Revealed type is "builtins.dict[builtins.int*, builtins.str*]" +main:14: error: Keywords must be strings +main:14: error: Argument 1 to "func_with_kwargs" has incompatible type "**X1[str, int]"; expected "int" +[builtins fixtures/dict.pyi] + +[case testSubtypingMappingUnpacking3] +from typing import Generic, TypeVar, Mapping, Iterable +T = TypeVar("T") +U = TypeVar("U") + +class X1(Generic[T, U], Mapping[U, T], Iterable[U]): + pass + +x1: X1[str, int] +reveal_type(iter(x1)) # N: Revealed type is "typing.Iterator[builtins.int*]" +reveal_type({**x1}) # N: Revealed type is "builtins.dict[builtins.int*, builtins.str*]" + +# Some people would expect this to raise an error, but this currently does not: +# `Mapping` has `Iterable[U]` base class, `X2` has direct `Iterable[T]` base class. +# It would be impossible to define correct `__iter__` method for incompatible `T` and `U`. +class X2(Generic[T, U], Mapping[U, T], Iterable[T]): + pass + +x2: X2[str, int] +reveal_type(iter(x2)) # N: Revealed type is "typing.Iterator[builtins.int*]" +reveal_type({**x2}) # N: Revealed type is "builtins.dict[builtins.int*, builtins.str*]" +[builtins fixtures/dict.pyi] + +[case testNotDirectIterableAndMappingSubtyping] +from typing import Generic, TypeVar, Dict, Iterable, Iterator, List +T = TypeVar("T") +U = TypeVar("U") + +class X1(Generic[T, U], Dict[U, T], Iterable[U]): + def __iter__(self) -> Iterator[U]: pass + +x1: X1[str, int] +reveal_type(iter(x1)) # N: Revealed type is "typing.Iterator[builtins.int*]" +reveal_type({**x1}) # N: Revealed type is "builtins.dict[builtins.int*, builtins.str*]" + +class X2(Generic[T, U], List[U]): + def __iter__(self) -> Iterator[U]: pass + +x2: X2[str, int] +reveal_type(iter(x2)) # N: Revealed type is "typing.Iterator[builtins.int*]" +reveal_type([*x2]) # N: Revealed type is "builtins.list[builtins.int*]" +[builtins fixtures/dict.pyi] diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index 161b5d72e772..ed0b680e21aa 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -52,7 +52,7 @@ class C: pass [out] main:8: error: Incompatible types in assignment (expression has type "C", variable has type "B") -[case testGenericMemberVariable] +[case testGenericMemberVariable2] from typing import TypeVar, Generic T = TypeVar('T') a, b, c = None, None, None # type: (A[B], B, C) @@ -2079,9 +2079,9 @@ reveal_type(Base.make_some(1, 1)) # N: Revealed type is "builtins.tuple[__main_ class Sub(Base[str]): ... Sub.make_some(1) # E: No overload variant of "make_some" of "Base" matches argument type "int" \ - # N: Possible overload variant: \ + # N: Possible overload variants: \ # N: def make_some(cls, item: str) -> Sub \ - # N: <1 more non-matching overload not shown> + # N: def make_some(cls, item: str, n: int) -> Tuple[Sub, ...] [builtins fixtures/classmethod.pyi] [case testNoGenericAccessOnImplicitAttributes] @@ -2118,7 +2118,7 @@ class B(A[T], Generic[T, S]): reveal_type(B.foo) # N: Revealed type is "def [T, S] () -> Tuple[T`1, __main__.B[T`1, S`2]]" [builtins fixtures/classmethod.pyi] -[case testGenericClassAlternativeConstructorPrecise] +[case testGenericClassAlternativeConstructorPrecise2] from typing import Generic, TypeVar, Type, Tuple, Any T = TypeVar('T') @@ -2463,7 +2463,8 @@ class B(A): ... a_c: Container[A] b_c: Container[B] -reveal_type([a_c, b_c]) # N: Revealed type is "builtins.list[__main__.Container*[__main__.B]]" +# TODO: this can be more precise than "object", see a comment in mypy/join.py +reveal_type([a_c, b_c]) # N: Revealed type is "builtins.list[builtins.object*]" [builtins fixtures/list.pyi] [case testGenericJoinRecursiveTypes] @@ -2477,3 +2478,29 @@ b: B reveal_type([a, b]) # N: Revealed type is "builtins.list[typing.Sequence*[builtins.object]]" [builtins fixtures/list.pyi] + +[case testGenericJoinRecursiveInvariant] +from typing import Generic, TypeVar + +T = TypeVar("T") +class I(Generic[T]): ... + +class A(I[A]): ... +class B(I[B]): ... + +a: A +b: B +reveal_type([a, b]) # N: Revealed type is "builtins.list[builtins.object*]" +[builtins fixtures/list.pyi] + +[case testGenericJoinNestedInvariantAny] +from typing import Any, Generic, TypeVar + +T = TypeVar("T") +class I(Generic[T]): ... + +a: I[I[int]] +b: I[I[Any]] +reveal_type([a, b]) # N: Revealed type is "builtins.list[__main__.I*[__main__.I[Any]]]" +reveal_type([b, a]) # N: Revealed type is "builtins.list[__main__.I*[__main__.I[Any]]]" +[builtins fixtures/list.pyi] diff --git a/test-data/unit/check-ignore.test b/test-data/unit/check-ignore.test index 686dece1c911..048410ecbab7 100644 --- a/test-data/unit/check-ignore.test +++ b/test-data/unit/check-ignore.test @@ -222,7 +222,7 @@ yield # type: ignore # E: "yield" outside function [case testIgnoreWholeModule1] # flags: --warn-unused-ignores # type: ignore -IGNORE # type: ignore # E: unused "type: ignore" comment +IGNORE # type: ignore # E: Unused "type: ignore" comment [case testIgnoreWholeModule2] # type: ignore diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 0d7d2f125338..ec1dff4977d4 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -2886,7 +2886,7 @@ tmp/m/a.py:1: error: Unsupported operand types for + ("int" and "str") [case testDisallowAnyExprIncremental] # cmd: mypy -m main -# flags: --disallow-any-expr +# flags: --disallow-any-expr [file ns.py] class Namespace: @@ -3671,7 +3671,7 @@ pass [out] [out2] [out3] -tmp/a.py:2: error: unused "type: ignore" comment +tmp/a.py:2: error: Unused "type: ignore" comment -- Test that a non cache_fine_grained run can use a fine-grained cache [case testRegularUsesFgCache] @@ -5585,3 +5585,51 @@ bar.x + 0 x = 0 [rechecked] [stale] + +[case testExplicitReexportImportCycleWildcard] +# flags: --no-implicit-reexport +import pkg.a +[file pkg/__init__.pyi] + +[file pkg/a.pyi] +MYPY = False +if MYPY: + from pkg.b import B + +[file pkg/b.pyi] +import pkg.a +MYPY = False +if MYPY: + from pkg.c import C +class B: + pass + +[file pkg/c.pyi] +from pkg.a import * +class C: + pass +[rechecked] +[stale] + + +[case testEnumAreStillFinalAfterCache] +import a +class Ok(a.RegularEnum): + x = 1 +class NotOk(a.FinalEnum): + x = 1 +[file a.py] +from enum import Enum +class RegularEnum(Enum): + x: int +class FinalEnum(Enum): + x = 1 +[builtins fixtures/isinstance.pyi] +[out] +main:3: error: Cannot override writable attribute "x" with a final one +main:4: error: Cannot inherit from final class "FinalEnum" +main:5: error: Cannot override final attribute "x" (previously declared in base class "FinalEnum") +[out2] +main:3: error: Cannot override writable attribute "x" with a final one +main:4: error: Cannot inherit from final class "FinalEnum" +main:5: error: Cannot override final attribute "x" (previously declared in base class "FinalEnum") diff --git a/test-data/unit/check-inference-context.test b/test-data/unit/check-inference-context.test index 536675ef6bef..e3ec55c516db 100644 --- a/test-data/unit/check-inference-context.test +++ b/test-data/unit/check-inference-context.test @@ -1381,5 +1381,41 @@ from typing import Union, List, Any def f(x: Union[List[str], Any]) -> None: a = x if x else [] - reveal_type(a) # N: Revealed type is "Union[builtins.list[builtins.str], Any]" + reveal_type(a) # N: Revealed type is "Union[builtins.list[Union[builtins.str, Any]], builtins.list[builtins.str], Any]" [builtins fixtures/list.pyi] + +[case testConditionalExpressionWithEmptyIteableAndUnionWithAny] +from typing import Union, Iterable, Any + +def f(x: Union[Iterable[str], Any]) -> None: + a = x if x else [] + reveal_type(a) # N: Revealed type is "Union[builtins.list[Union[builtins.str, Any]], typing.Iterable[builtins.str], Any]" +[builtins fixtures/list.pyi] + +[case testInferMultipleAnyUnionCovariant] +from typing import Any, Mapping, Sequence, Union + +def foo(x: Union[Mapping[Any, Any], Mapping[Any, Sequence[Any]]]) -> None: + ... +foo({1: 2}) +[builtins fixtures/dict.pyi] + +[case testInferMultipleAnyUnionInvariant] +from typing import Any, Dict, Sequence, Union + +def foo(x: Union[Dict[Any, Any], Dict[Any, Sequence[Any]]]) -> None: + ... +foo({1: 2}) +[builtins fixtures/dict.pyi] + +[case testInferMultipleAnyUnionDifferentVariance] +from typing import Any, Dict, Mapping, Sequence, Union + +def foo(x: Union[Dict[Any, Any], Mapping[Any, Sequence[Any]]]) -> None: + ... +foo({1: 2}) + +def bar(x: Union[Mapping[Any, Any], Dict[Any, Sequence[Any]]]) -> None: + ... +bar({1: 2}) +[builtins fixtures/dict.pyi] diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index c945d9c68aee..adf4a7b60420 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -287,8 +287,8 @@ main:6: error: Need more than 3 values to unpack (4 expected) [case testInvalidRvalueTypeInInferredMultipleLvarDefinition] import typing def f() -> None: - a, b = f # E: "def ()" object is not iterable - c, d = A() # E: "__main__.A" object is not iterable + a, b = f # E: "Callable[[], None]" object is not iterable + c, d = A() # E: "A" object is not iterable class A: pass [builtins fixtures/for.pyi] [out] @@ -296,8 +296,8 @@ class A: pass [case testInvalidRvalueTypeInInferredNestedTupleAssignment] import typing def f() -> None: - a1, (a2, b) = A(), f # E: "def ()" object is not iterable - a3, (c, d) = A(), A() # E: "__main__.A" object is not iterable + a1, (a2, b) = A(), f # E: "Callable[[], None]" object is not iterable + a3, (c, d) = A(), A() # E: "A" object is not iterable class A: pass [builtins fixtures/for.pyi] [out] @@ -1004,7 +1004,7 @@ main:4: error: Incompatible types in assignment (expression has type "A", variab main:5: error: Incompatible types in assignment (expression has type "B", variable has type "C") main:6: error: Incompatible types in assignment (expression has type "C", variable has type "A") main:10: error: Need more than 2 values to unpack (3 expected) -main:12: error: "__main__.B" object is not iterable +main:12: error: "B" object is not iterable [case testInferenceOfFor3] @@ -1547,9 +1547,9 @@ def f(blocks: Any): # E: Name "Any" is not defined \ def f(blocks: object): to_process = [] to_process = list(blocks) # E: No overload variant of "list" matches argument type "object" \ - # N: Possible overload variant: \ - # N: def [T] __init__(self, x: Iterable[T]) -> List[T] \ - # N: <1 more non-matching overload not shown> + # N: Possible overload variants: \ + # N: def [T] __init__(self) -> List[T] \ + # N: def [T] __init__(self, x: Iterable[T]) -> List[T] [builtins fixtures/list.pyi] [case testInferListInitializedToEmptyAndAssigned] @@ -1975,7 +1975,7 @@ T = TypeVar('T') class A: def f(self) -> None: - self.g() # E: Too few arguments for "g" of "A" + self.g() # E: Too few arguments for "g" of "A" self.g(1) @dec def g(self, x: str) -> None: pass @@ -2614,7 +2614,7 @@ class C(B): reveal_type(B.x) # N: Revealed type is "None" reveal_type(C.x) # N: Revealed type is "None" -[case testLocalPartialTypesWithInheritance2] +[case testLocalPartialTypesWithInheritance3] # flags: --local-partial-types from typing import Optional @@ -2652,7 +2652,7 @@ class C: def f(self, x) -> None: C.a.y # E: Item "None" of "Optional[Any]" has no attribute "y" -[case testLocalPartialTypesAccessPartialNoneAttribute] +[case testLocalPartialTypesAccessPartialNoneAttribute2] # flags: --local-partial-types class C: a = None # E: Need type annotation for "a" @@ -3170,3 +3170,43 @@ reveal_type(f(lambda: 1)) # N: Revealed type is "builtins.int*" def g() -> None: pass reveal_type(f(g)) # N: Revealed type is "None" + +[case testInferredTypeIsSimpleNestedList] +from typing import Any, Union, List + +y: Union[List[Any], Any] +x: Union[List[Any], Any] +x = [y] +reveal_type(x) # N: Revealed type is "builtins.list[Any]" +[builtins fixtures/list.pyi] + +[case testInferredTypeIsSimpleNestedIterable] +from typing import Any, Union, Iterable + +y: Union[Iterable[Any], Any] +x: Union[Iterable[Any], Any] +x = [y] +reveal_type(x) # N: Revealed type is "builtins.list[Any]" +[builtins fixtures/list.pyi] + +[case testInferredTypeIsSimpleNestedListLoop] +from typing import Any, Union, List + +def test(seq: List[Union[List, Any]]) -> None: + k: Union[List, Any] + for k in seq: + if bool(): + k = [k] + reveal_type(k) # N: Revealed type is "builtins.list[Any]" +[builtins fixtures/list.pyi] + +[case testInferredTypeIsSimpleNestedIterableLoop] +from typing import Any, Union, List, Iterable + +def test(seq: List[Union[Iterable, Any]]) -> None: + k: Union[Iterable, Any] + for k in seq: + if bool(): + k = [k] + reveal_type(k) # N: Revealed type is "builtins.list[Any]" +[builtins fixtures/list.pyi] diff --git a/test-data/unit/check-kwargs.test b/test-data/unit/check-kwargs.test index 4828d1bb37b9..7f0b8af3ba0e 100644 --- a/test-data/unit/check-kwargs.test +++ b/test-data/unit/check-kwargs.test @@ -252,7 +252,7 @@ class B: pass [case testCallingDynamicallyTypedFunctionWithKeywordArgs] import typing -def f(x, y=A()): pass +def f(x, y=A()): pass # N: "f" defined here f(x=A(), y=A()) f(y=A(), x=A()) f(y=A()) # E: Missing positional argument "x" in call to "f" @@ -490,7 +490,7 @@ g(**d) # E: Argument 1 to "g" has incompatible type "**Dict[str, object]"; expe m = {} # type: Mapping[str, object] f(**m) -g(**m) # TODO: Should be an error +g(**m) # E: Argument 1 to "g" has incompatible type "**Mapping[str, object]"; expected "int" [builtins fixtures/dict.pyi] [case testPassingEmptyDictWithStars] @@ -500,3 +500,57 @@ def g(x=1): pass f(**{}) g(**{}) [builtins fixtures/dict.pyi] + +[case testKeywordUnpackWithDifferentTypes] +# https://github.com/python/mypy/issues/11144 +from typing import Dict, Generic, TypeVar, Mapping + +T = TypeVar("T") +T2 = TypeVar("T2") + +class A(Dict[T, T2]): + ... + +class B(Mapping[T, T2]): + ... + +class C(Generic[T, T2]): + ... + +class D: + ... + +def foo(**i: float) -> float: + ... + +a: A[str, str] +b: B[str, str] +c: C[str, float] +d: D +e = {"a": "b"} + +foo(k=1.5) +foo(**a) +foo(**b) +foo(**c) +foo(**d) +foo(**e) + +# Correct: + +class Good(Mapping[str, float]): + ... + +good1: Good +good2: A[str, float] +good3: B[str, float] +foo(**good1) +foo(**good2) +foo(**good3) +[out] +main:29: error: Argument 1 to "foo" has incompatible type "**A[str, str]"; expected "float" +main:30: error: Argument 1 to "foo" has incompatible type "**B[str, str]"; expected "float" +main:31: error: Argument after ** must be a mapping, not "C[str, float]" +main:32: error: Argument after ** must be a mapping, not "D" +main:33: error: Argument 1 to "foo" has incompatible type "**Dict[str, str]"; expected "float" +[builtins fixtures/dict.pyi] diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index e96d72c7358b..37ae12419151 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -2687,11 +2687,8 @@ def force2(x: Tuple[Literal[1], Literal[2]]) -> None: pass reveal_type(a) # N: Revealed type is "Literal[1]?" reveal_type(b) # N: Revealed type is "Tuple[Literal[1]?, Literal[2]?]" -# TODO: This test seems somewhat broken and might need a rewrite (and a fix somewhere in mypy). -# See https://github.com/python/mypy/issues/7399#issuecomment-554188073 for more context. -force1(reveal_type(a)) # N: Revealed type is "Literal[1]" -force2(reveal_type(b)) # E: Argument 1 to "force2" has incompatible type "Tuple[int, int]"; expected "Tuple[Literal[1], Literal[2]]" \ - # N: Revealed type is "Tuple[Literal[1]?, Literal[2]?]" +force1(a) # ok +force2(b) # ok [builtins fixtures/tuple.pyi] [out] @@ -3304,3 +3301,48 @@ else: reveal_type(w) # E: Statement is unreachable [builtins fixtures/bool.pyi] + +[case testLiteralAndInstanceSubtyping] +# https://github.com/python/mypy/issues/7399 +# https://github.com/python/mypy/issues/11232 +from typing import Tuple, Union +from typing_extensions import Literal, Final + +x: bool + +def f() -> Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]: + if x: + return (True, 5) + else: + return (False, 'oops') + +reveal_type(f()) # N: Revealed type is "Union[Tuple[Literal[True], builtins.int], Tuple[Literal[False], builtins.str]]" + +def does_work() -> Tuple[Literal[1]]: + x: Final = (1,) + return x + +def also_works() -> Tuple[Literal[1]]: + x: Tuple[Literal[1]] = (1,) + return x + +def invalid_literal_value() -> Tuple[Literal[1]]: + x: Final = (2,) + return x # E: Incompatible return value type (got "Tuple[int]", expected "Tuple[Literal[1]]") + +def invalid_literal_type() -> Tuple[Literal[1]]: + x: Final = (True,) + return x # E: Incompatible return value type (got "Tuple[bool]", expected "Tuple[Literal[1]]") + +def incorrect_return1() -> Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]: + if x: + return (False, 5) # E: Incompatible return value type (got "Tuple[bool, int]", expected "Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]") + else: + return (True, 'oops') # E: Incompatible return value type (got "Tuple[bool, str]", expected "Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]") + +def incorrect_return2() -> Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]: + if x: + return (bool(), 5) # E: Incompatible return value type (got "Tuple[bool, int]", expected "Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]") + else: + return (bool(), 'oops') # E: Incompatible return value type (got "Tuple[bool, str]", expected "Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]") +[builtins fixtures/bool.pyi] diff --git a/test-data/unit/check-modules-case.test b/test-data/unit/check-modules-case.test index bc2e91aacfdc..b9e48888fea3 100644 --- a/test-data/unit/check-modules-case.test +++ b/test-data/unit/check-modules-case.test @@ -1,6 +1,14 @@ -- Type checker test cases dealing with modules and imports on case-insensitive filesystems. [case testCaseSensitivityDir] +# flags: --no-namespace-packages +from a import B # E: Module "a" has no attribute "B" + +[file a/__init__.py] +[file a/b/__init__.py] + +[case testCaseSensitivityDirNamespacePackages] +# flags: --namespace-packages from a import B # E: Module "a" has no attribute "B" [file a/__init__.py] diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 1a2504f3a611..071fcf54f2b6 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -1,7 +1,7 @@ -- Type checker test cases dealing with modules and imports. -- Towards the end there are tests for PEP 420 (namespace packages, i.e. __init__.py-less packages). -[case testAccessImportedDefinitions] +[case testAccessImportedDefinitions0] import m import typing m.f() # E: Missing positional argument "a" in call to "f" @@ -14,7 +14,7 @@ class A: pass def f(a: A) -> None: pass x = A() -[case testAccessImportedDefinitions] +[case testAccessImportedDefinitions1] import m import typing m.f(object()) # E: Argument 1 to "f" has incompatible type "object"; expected "A" @@ -1676,10 +1676,10 @@ reveal_type(n2.b) # N: Revealed type is "builtins.str" reveal_type(m3.a) # N: Revealed type is "builtins.str" reveal_type(n3.b) # N: Revealed type is "builtins.str" -x, y = m # E: "types.ModuleType" object is not iterable +x, y = m # E: Module object is not iterable x, y, z = m, n # E: Need more than 2 values to unpack (3 expected) x, y = m, m, m # E: Too many values to unpack (2 expected, 3 provided) -x, (y, z) = m, n # E: "types.ModuleType" object is not iterable +x, (y, z) = m, n # E: Module object is not iterable x, (y, z) = m, (n, n, n) # E: Too many values to unpack (2 expected, 3 provided) [file m.py] @@ -2000,7 +2000,7 @@ reveal_type(has_getattr.any_attribute) def __getattr__(x: int, y: str) -> str: ... [out] -tmp/has_getattr.pyi:1: error: Invalid signature "def (builtins.int, builtins.str) -> builtins.str" for "__getattr__" +tmp/has_getattr.pyi:1: error: Invalid signature "Callable[[int, str], str]" for "__getattr__" main:3: note: Revealed type is "builtins.str" [builtins fixtures/module.pyi] @@ -2014,7 +2014,7 @@ reveal_type(has_getattr.any_attribute) __getattr__ = 3 [out] -tmp/has_getattr.pyi:1: error: Invalid signature "builtins.int" for "__getattr__" +tmp/has_getattr.pyi:1: error: Invalid signature "int" for "__getattr__" main:3: note: Revealed type is "Any" [builtins fixtures/module.pyi] @@ -2141,7 +2141,7 @@ def make_getattr_bad() -> Callable[[], int]: ... __getattr__ = make_getattr_bad() [out] -tmp/non_stub.py:4: error: Invalid signature "def () -> builtins.int" for "__getattr__" +tmp/non_stub.py:4: error: Invalid signature "Callable[[], int]" for "__getattr__" main:3: note: Revealed type is "builtins.int" [case testModuleLevelGetattrImportedGood] @@ -2167,7 +2167,7 @@ from has_getattr import __getattr__ def __getattr__() -> int: ... [out] -tmp/has_getattr.py:1: error: Invalid signature "def () -> builtins.int" for "__getattr__" +tmp/has_getattr.py:1: error: Invalid signature "Callable[[], int]" for "__getattr__" main:3: note: Revealed type is "builtins.int" [builtins fixtures/module.pyi] @@ -3131,4 +3131,43 @@ main:2: error: Cannot find implementation or library stub for module named "blea # flags: --ignore-missing-imports import bleach.xyz from bleach.abc import fgh -[file bleach/__init__.pyi] \ No newline at end of file +[file bleach/__init__.pyi] + +[case testCyclicUndefinedImportWithName] +import a +[file a.py] +from b import no_such_export +[file b.py] +from a import no_such_export # E: Module "a" has no attribute "no_such_export" + +[case testCyclicUndefinedImportWithStar1] +import a +[file a.py] +from b import no_such_export +[file b.py] +from a import * +[out] +tmp/b.py:1: error: Cannot resolve name "no_such_export" (possible cyclic definition) +tmp/a.py:1: error: Module "b" has no attribute "no_such_export" + +[case testCyclicUndefinedImportWithStar2] +import a +[file a.py] +from b import no_such_export +[file b.py] +from c import * +[file c.py] +from a import * +[out] +tmp/c.py:1: error: Cannot resolve name "no_such_export" (possible cyclic definition) +tmp/b.py:1: error: Cannot resolve name "no_such_export" (possible cyclic definition) +tmp/a.py:1: error: Module "b" has no attribute "no_such_export" + +[case testCyclicUndefinedImportWithStar3] +import test1 +[file test1.py] +from dir1 import * +[file dir1/__init__.py] +from .test2 import * +[file dir1/test2.py] +from test1 import aaaa # E: Module "test1" has no attribute "aaaa" diff --git a/test-data/unit/check-multiple-inheritance.test b/test-data/unit/check-multiple-inheritance.test index a7701dab0c39..a8d053f9504e 100644 --- a/test-data/unit/check-multiple-inheritance.test +++ b/test-data/unit/check-multiple-inheritance.test @@ -502,7 +502,7 @@ class A(Base1, Base2): [out] main:10: error: Incompatible types in assignment (expression has type "GenericBase[Base2]", base class "Base1" defined the type as "GenericBase[Base1]") -[case testMultipleInheritance_NestedVariableOverriddenWithCompatibleType] +[case testMultipleInheritance_NestedVariableOverriddenWithCompatibleType2] from typing import TypeVar, Generic T = TypeVar('T', covariant=True) class GenericBase(Generic[T]): diff --git a/test-data/unit/check-namedtuple.test b/test-data/unit/check-namedtuple.test index d47b069ea45e..440884333c69 100644 --- a/test-data/unit/check-namedtuple.test +++ b/test-data/unit/check-namedtuple.test @@ -35,7 +35,7 @@ X = namedtuple('X', ('x', 'y')) # type: ignore [case testNamedTupleNoUnderscoreFields] from collections import namedtuple -X = namedtuple('X', 'x, _y, _z') # E: namedtuple() field names cannot start with an underscore: _y, _z +X = namedtuple('X', 'x, _y, _z') # E: "namedtuple()" field names cannot start with an underscore: _y, _z [builtins fixtures/tuple.pyi] [case testNamedTupleAccessingAttributes] @@ -162,7 +162,7 @@ X(0) # ok X(0, 1) # ok X(0, 1, 2) # E: Too many arguments for "X" -Y = namedtuple('Y', ['x', 'y'], defaults=(1, 2, 3)) # E: Too many defaults given in call to namedtuple() +Y = namedtuple('Y', ['x', 'y'], defaults=(1, 2, 3)) # E: Too many defaults given in call to "namedtuple()" Z = namedtuple('Z', ['x', 'y'], defaults='not a tuple') # E: List or tuple literal expected as the defaults argument to namedtuple() # E: Argument "defaults" to "namedtuple" has incompatible type "str"; expected "Optional[Iterable[Any]]" [builtins fixtures/list.pyi] @@ -576,7 +576,7 @@ T = TypeVar('T', bound='M') class G(Generic[T]): x: T -yb: G[int] # E: Type argument "builtins.int" of "G" must be a subtype of "Tuple[builtins.int, fallback=__main__.M]" +yb: G[int] # E: Type argument "int" of "G" must be a subtype of "M" yg: G[M] reveal_type(G[M]().x.x) # N: Revealed type is "builtins.int" reveal_type(G[M]().x[0]) # N: Revealed type is "builtins.int" @@ -973,3 +973,111 @@ B = namedtuple('X', ['a']) # E: First argument to namedtuple() should be C = NamedTuple('X', [('a', 'Y')]) # E: First argument to namedtuple() should be "C", not "X" class Y: ... [builtins fixtures/tuple.pyi] + +[case testNamedTupleTypeIsASuperTypeOfOtherNamedTuples] +from typing import Tuple, NamedTuple + +class Bar(NamedTuple): + name: str = "Bar" + +class Baz(NamedTuple): + a: str + b: str + +class Biz(Baz): ... +class Other: ... +class Both1(Bar, Other): ... +class Both2(Other, Bar): ... +class Both3(Biz, Other): ... + +def print_namedtuple(obj: NamedTuple) -> None: + reveal_type(obj.name) # N: Revealed type is "builtins.str" + +b1: Bar +b2: Baz +b3: Biz +b4: Both1 +b5: Both2 +b6: Both3 +print_namedtuple(b1) # ok +print_namedtuple(b2) # ok +print_namedtuple(b3) # ok +print_namedtuple(b4) # ok +print_namedtuple(b5) # ok +print_namedtuple(b6) # ok + +print_namedtuple(1) # E: Argument 1 to "print_namedtuple" has incompatible type "int"; expected "NamedTuple" +print_namedtuple(('bar',)) # E: Argument 1 to "print_namedtuple" has incompatible type "Tuple[str]"; expected "NamedTuple" +print_namedtuple((1, 2)) # E: Argument 1 to "print_namedtuple" has incompatible type "Tuple[int, int]"; expected "NamedTuple" +print_namedtuple((b1,)) # E: Argument 1 to "print_namedtuple" has incompatible type "Tuple[Bar]"; expected "NamedTuple" +t: Tuple[str, ...] +print_namedtuple(t) # E: Argument 1 to "print_namedtuple" has incompatible type "Tuple[str, ...]"; expected "NamedTuple" + +[builtins fixtures/tuple.pyi] +[typing fixtures/typing-namedtuple.pyi] + +[case testNamedTupleTypeIsASuperTypeOfOtherNamedTuplesReturns] +from typing import Tuple, NamedTuple + +class Bar(NamedTuple): + n: int + +class Baz(NamedTuple): + a: str + b: str + +class Biz(Bar): ... +class Other: ... +class Both1(Bar, Other): ... +class Both2(Other, Bar): ... +class Both3(Biz, Other): ... + +def good1() -> NamedTuple: + b: Bar + return b +def good2() -> NamedTuple: + b: Baz + return b +def good3() -> NamedTuple: + b: Biz + return b +def good4() -> NamedTuple: + b: Both1 + return b +def good5() -> NamedTuple: + b: Both2 + return b +def good6() -> NamedTuple: + b: Both3 + return b + +def bad1() -> NamedTuple: + return 1 # E: Incompatible return value type (got "int", expected "NamedTuple") +def bad2() -> NamedTuple: + return () # E: Incompatible return value type (got "Tuple[]", expected "NamedTuple") +def bad3() -> NamedTuple: + return (1, 2) # E: Incompatible return value type (got "Tuple[int, int]", expected "NamedTuple") + +[builtins fixtures/tuple.pyi] +[typing fixtures/typing-namedtuple.pyi] + +[case testBoolInTuplesRegression] +# https://github.com/python/mypy/issues/11701 +from typing import NamedTuple, Literal, List, Tuple + +C = NamedTuple("C", [("x", Literal[True, False])]) + +T = Tuple[Literal[True, False]] + +# Was error here: +# Incompatible types in assignment (expression has type "List[C]", variable has type "List[C]") +x: List[C] = [C(True)] + +t: T + +# Was error here: +# Incompatible types in assignment (expression has type "List[Tuple[bool]]", +# variable has type "List[Tuple[Union[Literal[True], Literal[False]]]]") +y: List[T] = [t] +[builtins fixtures/tuple.pyi] +[typing fixtures/typing-namedtuple.pyi] diff --git a/test-data/unit/check-narrowing.test b/test-data/unit/check-narrowing.test index 7c8415b75fe1..d6b25ef456d9 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test @@ -655,6 +655,27 @@ else: reveal_type(y["model"]) # N: Revealed type is "Union[TypedDict('__main__.Model1', {'key': Literal['A']}), TypedDict('__main__.Model2', {'key': Literal['B']})]" [builtins fixtures/primitives.pyi] +[case testNarrowingExprPropagation] +from typing import Union +from typing_extensions import Literal + +class A: + tag: Literal['A'] + +class B: + tag: Literal['B'] + +abo: Union[A, B, None] + +if abo is not None and abo.tag == "A": + reveal_type(abo.tag) # N: Revealed type is "Literal['A']" + reveal_type(abo) # N: Revealed type is "__main__.A" + +if not (abo is None or abo.tag != "B"): + reveal_type(abo.tag) # N: Revealed type is "Literal['B']" + reveal_type(abo) # N: Revealed type is "__main__.B" +[builtins fixtures/primitives.pyi] + [case testNarrowingEqualityFlipFlop] # flags: --warn-unreachable --strict-equality from typing_extensions import Literal, Final @@ -1026,8 +1047,81 @@ else: if str_or_bool_literal is not True and str_or_bool_literal is not False: reveal_type(str_or_bool_literal) # N: Revealed type is "builtins.str" else: - reveal_type(str_or_bool_literal) # N: Revealed type is "Union[Literal[False], Literal[True]]" + reveal_type(str_or_bool_literal) # N: Revealed type is "builtins.bool" +[builtins fixtures/primitives.pyi] + +[case testNarrowingBooleanIdentityCheck] +# flags: --strict-optional +from typing import Optional +from typing_extensions import Literal +bool_val: bool + +if bool_val is not False: + reveal_type(bool_val) # N: Revealed type is "Literal[True]" +else: + reveal_type(bool_val) # N: Revealed type is "Literal[False]" + +opt_bool_val: Optional[bool] + +if opt_bool_val is not None: + reveal_type(opt_bool_val) # N: Revealed type is "builtins.bool" + +if opt_bool_val is not False: + reveal_type(opt_bool_val) # N: Revealed type is "Union[Literal[True], None]" +else: + reveal_type(opt_bool_val) # N: Revealed type is "Literal[False]" +[builtins fixtures/primitives.pyi] + +[case testNarrowingBooleanTruthiness] +# flags: --strict-optional +from typing import Optional +from typing_extensions import Literal + +bool_val: bool + +if bool_val: + reveal_type(bool_val) # N: Revealed type is "Literal[True]" +else: + reveal_type(bool_val) # N: Revealed type is "Literal[False]" +reveal_type(bool_val) # N: Revealed type is "builtins.bool" + +opt_bool_val: Optional[bool] + +if opt_bool_val: + reveal_type(opt_bool_val) # N: Revealed type is "Literal[True]" +else: + reveal_type(opt_bool_val) # N: Revealed type is "Union[Literal[False], None]" +reveal_type(opt_bool_val) # N: Revealed type is "Union[builtins.bool, None]" +[builtins fixtures/primitives.pyi] + +[case testNarrowingBooleanBoolOp] +# flags: --strict-optional +from typing import Optional +from typing_extensions import Literal + +bool_a: bool +bool_b: bool + +if bool_a and bool_b: + reveal_type(bool_a) # N: Revealed type is "Literal[True]" + reveal_type(bool_b) # N: Revealed type is "Literal[True]" +else: + reveal_type(bool_a) # N: Revealed type is "builtins.bool" + reveal_type(bool_b) # N: Revealed type is "builtins.bool" + +if not bool_a or bool_b: + reveal_type(bool_a) # N: Revealed type is "builtins.bool" + reveal_type(bool_b) # N: Revealed type is "builtins.bool" +else: + reveal_type(bool_a) # N: Revealed type is "Literal[True]" + reveal_type(bool_b) # N: Revealed type is "Literal[False]" + +if True and bool_b: + reveal_type(bool_b) # N: Revealed type is "Literal[True]" + +x = True and bool_b +reveal_type(x) # N: Revealed type is "builtins.bool" [builtins fixtures/primitives.pyi] [case testNarrowingTypedDictUsingEnumLiteral] @@ -1093,3 +1187,61 @@ def f(t: Type[T], a: A, b: B) -> None: reveal_type(b) # N: Revealed type is "" else: reveal_type(b) # N: Revealed type is "__main__.B" + +[case testNarrowingNestedUnionOfTypedDicts] +from typing import Union +from typing_extensions import Literal, TypedDict + +class A(TypedDict): + tag: Literal["A"] + a: int + +class B(TypedDict): + tag: Literal["B"] + b: int + +class C(TypedDict): + tag: Literal["C"] + c: int + +AB = Union[A, B] +ABC = Union[AB, C] +abc: ABC + +if abc["tag"] == "A": + reveal_type(abc) # N: Revealed type is "TypedDict('__main__.A', {'tag': Literal['A'], 'a': builtins.int})" +elif abc["tag"] == "C": + reveal_type(abc) # N: Revealed type is "TypedDict('__main__.C', {'tag': Literal['C'], 'c': builtins.int})" +else: + reveal_type(abc) # N: Revealed type is "TypedDict('__main__.B', {'tag': Literal['B'], 'b': builtins.int})" + +[builtins fixtures/primitives.pyi] + + +[case testNarrowingRuntimeCover] +from typing import Dict, List, Union + +def unreachable(x: Union[str, List[str]]) -> None: + if isinstance(x, str): + reveal_type(x) # N: Revealed type is "builtins.str" + elif isinstance(x, list): + reveal_type(x) # N: Revealed type is "builtins.list[builtins.str]" + else: + reveal_type(x) # N: Revealed type is "" + +def all_parts_covered(x: Union[str, List[str], List[int], int]) -> None: + if isinstance(x, str): + reveal_type(x) # N: Revealed type is "builtins.str" + elif isinstance(x, list): + reveal_type(x) # N: Revealed type is "Union[builtins.list[builtins.str], builtins.list[builtins.int]]" + else: + reveal_type(x) # N: Revealed type is "builtins.int" + +def two_type_vars(x: Union[str, Dict[str, int], Dict[bool, object], int]) -> None: + if isinstance(x, str): + reveal_type(x) # N: Revealed type is "builtins.str" + elif isinstance(x, dict): + reveal_type(x) # N: Revealed type is "Union[builtins.dict[builtins.str, builtins.int], builtins.dict[builtins.bool, builtins.object]]" + else: + reveal_type(x) # N: Revealed type is "builtins.int" +[builtins fixtures/dict.pyi] diff --git a/test-data/unit/check-newsemanal.test b/test-data/unit/check-newsemanal.test index ed999d1f46b6..8a039ad278f3 100644 --- a/test-data/unit/check-newsemanal.test +++ b/test-data/unit/check-newsemanal.test @@ -304,6 +304,7 @@ from a import x def f(): pass [targets a, b, a, a.y, b.f, __main__] +[builtins fixtures/tuple.pyi] [case testNewAnalyzerRedefinitionAndDeferral1b] import a @@ -762,7 +763,7 @@ class D(C[TY], Generic[TY]): pass class Y(Defer): pass class Defer: ... -x: D[int] # E: Type argument "builtins.int" of "D" must be a subtype of "__main__.Y" +x: D[int] # E: Type argument "int" of "D" must be a subtype of "Y" y: D[Y] [case testNewAnalyzerTypeVarForwardReferenceErrors] @@ -1638,7 +1639,7 @@ class C(Generic[T]): pass class D(B): pass -x: C[D] # E: Type argument "__main__.D" of "C" must be a subtype of "__main__.E" +x: C[D] # E: Type argument "D" of "C" must be a subtype of "E" y: C[F] class B: pass @@ -1677,14 +1678,14 @@ class A(C[str]): # E [out] main:2: note: In module imported here: tmp/a.py: note: In function "f": -tmp/a.py:6: error: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" -tmp/a.py:7: error: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" +tmp/a.py:6: error: Type argument "str" of "C" must be a subtype of "int" +tmp/a.py:7: error: Type argument "str" of "C" must be a subtype of "int" tmp/a.py: note: In class "A": -tmp/a.py:8: error: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" -tmp/a.py:9: error: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" +tmp/a.py:8: error: Type argument "str" of "C" must be a subtype of "int" +tmp/a.py:9: error: Type argument "str" of "C" must be a subtype of "int" tmp/a.py: note: In member "g" of class "A": -tmp/a.py:10: error: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" -tmp/a.py:11: error: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" +tmp/a.py:10: error: Type argument "str" of "C" must be a subtype of "int" +tmp/a.py:11: error: Type argument "str" of "C" must be a subtype of "int" [case testNewAnalyzerTypeArgBoundCheckDifferentNodes] from typing import TypeVar, Generic, NamedTuple, NewType, Union, Any, cast, overload @@ -1694,45 +1695,45 @@ T = TypeVar('T', bound=int) class C(Generic[T]): pass class C2(Generic[T]): pass -A = C[str] # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" \ +A = C[str] # E: Type argument "str" of "C" must be a subtype of "int" \ # E: Value of type variable "T" of "C" cannot be "str" -B = Union[C[str], int] # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" -S = TypeVar('S', bound=C[str]) # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" -U = TypeVar('U', C[str], str) # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" +B = Union[C[str], int] # E: Type argument "str" of "C" must be a subtype of "int" +S = TypeVar('S', bound=C[str]) # E: Type argument "str" of "C" must be a subtype of "int" +U = TypeVar('U', C[str], str) # E: Type argument "str" of "C" must be a subtype of "int" N = NamedTuple('N', [ - ('x', C[str])]) # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" + ('x', C[str])]) # E: Type argument "str" of "C" must be a subtype of "int" class N2(NamedTuple): - x: C[str] # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" + x: C[str] # E: Type argument "str" of "C" must be a subtype of "int" class TD(TypedDict): - x: C[str] # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" + x: C[str] # E: Type argument "str" of "C" must be a subtype of "int" class TD2(TD): - y: C2[str] # E: Type argument "builtins.str" of "C2" must be a subtype of "builtins.int" + y: C2[str] # E: Type argument "str" of "C2" must be a subtype of "int" NT = NewType('NT', - C[str]) # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" + C[str]) # E: Type argument "str" of "C" must be a subtype of "int" class D( - C[str]): # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" + C[str]): # E: Type argument "str" of "C" must be a subtype of "int" pass -TD3 = TypedDict('TD3', {'x': C[str]}) # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" +TD3 = TypedDict('TD3', {'x': C[str]}) # E: Type argument "str" of "C" must be a subtype of "int" a: Any -for i in a: # type: C[str] # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" +for i in a: # type: C[str] # E: Type argument "str" of "C" must be a subtype of "int" pass -with a as w: # type: C[str] # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" +with a as w: # type: C[str] # E: Type argument "str" of "C" must be a subtype of "int" pass -cast(C[str], a) # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" +cast(C[str], a) # E: Type argument "str" of "C" must be a subtype of "int" C[str]() # E: Value of type variable "T" of "C" cannot be "str" def f(s: S, y: U) -> None: pass # No error here @overload -def g(x: C[str]) -> int: ... # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" +def g(x: C[str]) -> int: ... # E: Type argument "str" of "C" must be a subtype of "int" @overload def g(x: int) -> int: ... -def g(x: Union[C[str], int]) -> int: # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" - y: C[object] # E: Type argument "builtins.object" of "C" must be a subtype of "builtins.int" +def g(x: Union[C[str], int]) -> int: # E: Type argument "str" of "C" must be a subtype of "int" + y: C[object] # E: Type argument "object" of "C" must be a subtype of "int" return 0 [builtins fixtures/tuple.pyi] @@ -1744,7 +1745,7 @@ import a from typing import TypeVar, Generic x: C[None] -y: C[str] # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" +y: C[str] # E: Type argument "str" of "C" must be a subtype of "int" z: C[int] T = TypeVar('T', bound=int) @@ -1754,8 +1755,8 @@ class C(Generic[T]): [file a.py] from b import C -x: C[None] # E: Type argument "None" of "C" must be a subtype of "builtins.int" -y: C[str] # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" +x: C[None] # E: Type argument "None" of "C" must be a subtype of "int" +y: C[str] # E: Type argument "str" of "C" must be a subtype of "int" z: C[int] [file mypy.ini] @@ -1773,7 +1774,7 @@ import a from typing import TypeVar, Generic x: C[None] -y: C[str] # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" +y: C[str] # E: Type argument "str" of "C" must be a subtype of "int" z: C[int] T = TypeVar('T', bound=int) @@ -1783,8 +1784,8 @@ class C(Generic[T]): [file a.py] from b import C -x: C[None] # E: Type argument "None" of "C" must be a subtype of "builtins.int" -y: C[str] # E: Type argument "builtins.str" of "C" must be a subtype of "builtins.int" +x: C[None] # E: Type argument "None" of "C" must be a subtype of "int" +y: C[str] # E: Type argument "str" of "C" must be a subtype of "int" z: C[int] [file pyproject.toml] @@ -1992,16 +1993,16 @@ S = TypeVar('S', bound=Tuple[G[A], ...]) class GG(Generic[S]): pass g: GG[Tuple[G[B], G[C]]] \ - # E: Type argument "Tuple[__main__.G[__main__.B], __main__.G[__main__.C]]" of "GG" must be a subtype of "builtins.tuple[__main__.G[__main__.A]]" \ - # E: Type argument "__main__.B" of "G" must be a subtype of "__main__.A" \ - # E: Type argument "__main__.C" of "G" must be a subtype of "__main__.A" + # E: Type argument "Tuple[G[B], G[C]]" of "GG" must be a subtype of "Tuple[G[A], ...]" \ + # E: Type argument "B" of "G" must be a subtype of "A" \ + # E: Type argument "C" of "G" must be a subtype of "A" T = TypeVar('T', bound=A, covariant=True) class G(Generic[T]): pass -t: Tuple[G[B], G[C]] # E: Type argument "__main__.B" of "G" must be a subtype of "__main__.A" \ - # E: Type argument "__main__.C" of "G" must be a subtype of "__main__.A" +t: Tuple[G[B], G[C]] # E: Type argument "B" of "G" must be a subtype of "A" \ + # E: Type argument "C" of "G" must be a subtype of "A" reveal_type(t.__iter__) # N: Revealed type is "def () -> typing.Iterator[builtins.object*]" [builtins fixtures/tuple.pyi] @@ -2200,7 +2201,7 @@ class B(Generic[T]): x: T class C: ... -x: B[int] # E: Type argument "builtins.int" of "B" must be a subtype of "__main__.B[Any]" +x: B[int] # E: Type argument "int" of "B" must be a subtype of "B[Any]" y: B[B[Any]] reveal_type(y.x) # N: Revealed type is "__main__.B*[Any]" @@ -2225,7 +2226,7 @@ x: B[int] y: B[B[Any]] reveal_type(y.x) [out] -tmp/b.py:8: error: Type argument "builtins.int" of "B" must be a subtype of "b.B[Any]" +tmp/b.py:8: error: Type argument "int" of "B" must be a subtype of "B[Any]" tmp/b.py:10: note: Revealed type is "b.B*[Any]" tmp/a.py:5: error: Cannot redefine "T" as a type variable tmp/a.py:5: error: Invalid assignment target @@ -2254,7 +2255,7 @@ x: B[int] y: B[B[Any]] reveal_type(y.x) [out] -tmp/b.py:9: error: Type argument "builtins.int" of "B" must be a subtype of "b.B[Any]" +tmp/b.py:9: error: Type argument "int" of "B" must be a subtype of "B[Any]" tmp/b.py:11: note: Revealed type is "b.B*[Any]" tmp/a.py:5: error: Cannot redefine "T" as a type variable tmp/a.py:5: error: Invalid assignment target @@ -2313,7 +2314,7 @@ reveal_type(x) # N: Revealed type is "builtins.int" C = int -[case testNewAnalyzerCastForward2] +[case testNewAnalyzerCastForward3] from typing import cast, NamedTuple x = cast('C', None) @@ -2390,7 +2391,8 @@ import p import p reveal_type(p.y) [file p.pyi] -from pp import x as y +from pp import x +y = x [file pp.pyi] def __getattr__(attr): ... [out2] diff --git a/test-data/unit/check-overloading.test b/test-data/unit/check-overloading.test index af0e5e97118e..d903c895c45c 100644 --- a/test-data/unit/check-overloading.test +++ b/test-data/unit/check-overloading.test @@ -525,21 +525,21 @@ if int(): if int(): b = f(a) # E: Incompatible types in assignment (expression has type "A", variable has type "B") f(b) # E: No overload variant of "f" matches argument type "B" \ - # N: Possible overload variant: \ + # N: Possible overload variants: \ # N: def f(x: A) -> A \ - # N: <1 more non-matching overload not shown> + # N: def f(x: B, y: A) -> B if int(): b = f(b, a) if int(): a = f(b, a) # E: Incompatible types in assignment (expression has type "B", variable has type "A") f(a, a) # E: No overload variant of "f" matches argument types "A", "A" \ - # N: Possible overload variant: \ - # N: def f(x: B, y: A) -> B \ - # N: <1 more non-matching overload not shown> + # N: Possible overload variants: \ + # N: def f(x: A) -> A \ + # N: def f(x: B, y: A) -> B f(b, b) # E: No overload variant of "f" matches argument types "B", "B" \ - # N: Possible overload variant: \ - # N: def f(x: B, y: A) -> B \ - # N: <1 more non-matching overload not shown> + # N: Possible overload variants: \ + # N: def f(x: A) -> A \ + # N: def f(x: B, y: A) -> B @overload def f(x: 'A') -> 'A': pass @@ -1208,15 +1208,15 @@ def f(x: int, y: str) -> int: pass @overload def f(*x: str) -> str: pass f(*(1,))() # E: No overload variant of "f" matches argument type "Tuple[int]" \ - # N: Possible overload variant: \ - # N: def f(*x: str) -> str \ - # N: <1 more non-matching overload not shown> + # N: Possible overload variants: \ + # N: def f(x: int, y: str) -> int \ + # N: def f(*x: str) -> str f(*('',))() # E: "str" not callable f(*(1, ''))() # E: "int" not callable f(*(1, '', 1))() # E: No overload variant of "f" matches argument type "Tuple[int, str, int]" \ - # N: Possible overload variant: \ - # N: def f(*x: str) -> str \ - # N: <1 more non-matching overload not shown> + # N: Possible overload variants: \ + # N: def f(x: int, y: str) -> int \ + # N: def f(*x: str) -> str [builtins fixtures/tuple.pyi] [case testPreferExactSignatureMatchInOverload] @@ -2502,9 +2502,9 @@ reveal_type(foo(*x)) # N: Revealed type is "__main__.C" y: List[str] foo(*y) # E: No overload variant of "foo" matches argument type "List[str]" \ # N: Possible overload variants: \ - # N: def foo(x: int, y: int, z: int, *args: int) -> C \ # N: def foo(x: int) -> A \ - # N: def foo(x: int, y: int) -> B + # N: def foo(x: int, y: int) -> B \ + # N: def foo(x: int, y: int, z: int, *args: int) -> C [builtins fixtures/list.pyi] [case testOverloadMultipleVarargDefinition] @@ -4314,7 +4314,7 @@ class Wrapper3: def foo(x: Union[int, str]): pass # E: Self argument missing for a non-static method (or an invalid type for self) [builtins fixtures/staticmethod.pyi] -[case testOverloadWithSwappedDecorators] +[case testOverloadWithSwappedDecorators2] from typing import overload class Wrapper1: @@ -4822,7 +4822,9 @@ f(3) # E: No overload variant of "f" matches argument type "int" \ # N: Possible overload variants: \ # N: def f(x: A) -> None \ # N: def f(x: B) -> None \ - # N: <2 more similar overloads not shown, out of 5 total overloads> + # N: def f(x: C) -> None \ + # N: def f(x: D) -> None \ + # N: def f(x: int, y: int) -> None @overload def g(x: A) -> None: ... @@ -4888,9 +4890,9 @@ def f() -> None: pass g(str(), str()) # E: No overload variant of "g" matches argument types "str", "str" \ - # N: Possible overload variant: \ - # N: def [T] g(x: T, y: int) -> T \ - # N: <1 more non-matching overload not shown> + # N: Possible overload variants: \ + # N: def g(x: str) -> str \ + # N: def [T] g(x: T, y: int) -> T reveal_type(g(str(), int())) # N: Revealed type is "builtins.str*" [out] @@ -4941,9 +4943,9 @@ reveal_type(attr("hi")) # N: Revealed type is "builtins.int" x: Any reveal_type(attr(x)) # N: Revealed type is "Any" attr("hi", 1) # E: No overload variant of "attr" matches argument types "str", "int" \ - # N: Possible overload variant: \ + # N: Possible overload variants: \ # N: def [T in (int, float)] attr(default: T = ..., blah: int = ...) -> T \ - # N: <1 more non-matching overload not shown> + # N: def attr(default: Any = ...) -> int [file lib.pyi] from typing import overload, Any, TypeVar @@ -4964,9 +4966,9 @@ reveal_type(attr("hi")) # N: Revealed type is "builtins.int" x: Any reveal_type(attr(x)) # N: Revealed type is "Any" attr("hi", 1) # E: No overload variant of "attr" matches argument types "str", "int" \ - # N: Possible overload variant: \ + # N: Possible overload variants: \ # N: def [T <: int] attr(default: T = ..., blah: int = ...) -> T \ - # N: <1 more non-matching overload not shown> + # N: def attr(default: Any = ...) -> int [file lib.pyi] from typing import overload, TypeVar, Any @@ -5337,3 +5339,85 @@ def register(cls: Any) -> Any: return None x = register(Foo) reveal_type(x) # N: Revealed type is "builtins.int" [builtins fixtures/dict.pyi] + + +[case testOverloadWithObjectDecorator] +from typing import Any, Callable, Union, overload + +class A: + def __call__(self, *arg, **kwargs) -> None: ... + +def dec_a(f: Callable[..., Any]) -> A: + return A() + +@overload +def f_a(arg: int) -> None: ... +@overload +def f_a(arg: str) -> None: ... +@dec_a +def f_a(arg): ... + +class B: + def __call__(self, arg: Union[int, str]) -> None: ... + +def dec_b(f: Callable[..., Any]) -> B: + return B() + +@overload +def f_b(arg: int) -> None: ... +@overload +def f_b(arg: str) -> None: ... +@dec_b +def f_b(arg): ... + +class C: + def __call__(self, arg: int) -> None: ... + +def dec_c(f: Callable[..., Any]) -> C: + return C() + +@overload +def f_c(arg: int) -> None: ... +@overload +def f_c(arg: str) -> None: ... +@dec_c # E: Overloaded function implementation does not accept all possible arguments of signature 2 +def f_c(arg): ... +[builtins fixtures/dict.pyi] + +[case testOverloadWithErrorDecorator] +from typing import Any, Callable, TypeVar, overload + +def dec_d(f: Callable[..., Any]) -> int: ... + +@overload +def f_d(arg: int) -> None: ... +@overload +def f_d(arg: str) -> None: ... +@dec_d # E: "int" not callable +def f_d(arg): ... + +Bad1 = TypeVar('Good') # type: ignore + +def dec_e(f: Bad1) -> Bad1: ... # type: ignore + +@overload +def f_e(arg: int) -> None: ... +@overload +def f_e(arg: str) -> None: ... +@dec_e # E: Bad1? not callable +def f_e(arg): ... + +class Bad2: + def __getattr__(self, attr): + # __getattr__ is not called for implicit `__call__` + if attr == "__call__": + return lambda *a, **kw: print(a, kw) + raise AttributeError + +@overload +def f_f(arg: int) -> None: ... +@overload +def f_f(arg: str) -> None: ... +@Bad2() # E: "Bad2" not callable +def f_f(arg): ... +[builtins fixtures/dict.pyi] diff --git a/test-data/unit/check-parameter-specification.test b/test-data/unit/check-parameter-specification.test index a817ae8064c6..f6123915aada 100644 --- a/test-data/unit/check-parameter-specification.test +++ b/test-data/unit/check-parameter-specification.test @@ -15,7 +15,7 @@ def foo1(x: Callable[P, int]) -> Callable[P, str]: ... def foo2(x: P) -> P: ... # E: Invalid location for ParamSpec "P" \ # N: You can use ParamSpec as the first argument to Callable, e.g., 'Callable[P, int]' -# TODO(shantanu): uncomment once we have support for Concatenate +# TODO(PEP612): uncomment once we have support for Concatenate # def foo3(x: Concatenate[int, P]) -> int: ... $ E: Invalid location for Concatenate def foo4(x: List[P]) -> None: ... # E: Invalid location for ParamSpec "P" \ @@ -28,25 +28,381 @@ def foo6(x: Callable[[P], int]) -> None: ... # E: Invalid location for ParamSpe # N: You can use ParamSpec as the first argument to Callable, e.g., 'Callable[P, int]' [builtins fixtures/tuple.pyi] -[case testParamSpecTemporaryAnyBehaviour] -# This is a test of mypy's temporary behaviour in lieu of full support for ParamSpec +[case testParamSpecContextManagerLike] from typing import Callable, List, Iterator, TypeVar from typing_extensions import ParamSpec P = ParamSpec('P') T = TypeVar('T') -def changes_return_type_to_str(x: Callable[P, int]) -> Callable[P, str]: ... - -def returns_int(a: str, b: bool) -> int: ... - -reveal_type(changes_return_type_to_str(returns_int)) # N: Revealed type is "def (*Any, **Any) -> builtins.str" - def tmpcontextmanagerlike(x: Callable[P, Iterator[T]]) -> Callable[P, List[T]]: ... @tmpcontextmanagerlike def whatever(x: int) -> Iterator[int]: yield x -reveal_type(whatever) # N: Revealed type is "def (*Any, **Any) -> builtins.list[builtins.int*]" +reveal_type(whatever) # N: Revealed type is "def (x: builtins.int) -> builtins.list[builtins.int*]" reveal_type(whatever(217)) # N: Revealed type is "builtins.list[builtins.int*]" [builtins fixtures/tuple.pyi] + +[case testInvalidParamSpecType] +# flags: --python-version 3.10 +from typing import ParamSpec + +P = ParamSpec("P") + +class MyFunction(P): # E: Invalid base class "P" + ... + +[case testParamSpecRevealType] +from typing import Callable +from typing_extensions import ParamSpec + +P = ParamSpec('P') + +def f(x: Callable[P, int]) -> None: ... +reveal_type(f) # N: Revealed type is "def [P] (x: def (*P.args, **P.kwargs) -> builtins.int)" +[builtins fixtures/tuple.pyi] + +[case testParamSpecSimpleFunction] +from typing import Callable, TypeVar +from typing_extensions import ParamSpec + +P = ParamSpec('P') + +def changes_return_type_to_str(x: Callable[P, int]) -> Callable[P, str]: ... + +def returns_int(a: str, b: bool) -> int: ... + +reveal_type(changes_return_type_to_str(returns_int)) # N: Revealed type is "def (a: builtins.str, b: builtins.bool) -> builtins.str" +[builtins fixtures/tuple.pyi] + +[case testParamSpecSimpleClass] +from typing import Callable, TypeVar, Generic +from typing_extensions import ParamSpec + +P = ParamSpec('P') + +class C(Generic[P]): + def __init__(self, x: Callable[P, None]) -> None: ... + + def m(self, *args: P.args, **kwargs: P.kwargs) -> int: + return 1 + +def f(x: int, y: str) -> None: ... + +reveal_type(C(f)) # N: Revealed type is "__main__.C[def (x: builtins.int, y: builtins.str)]" +reveal_type(C(f).m) # N: Revealed type is "def (x: builtins.int, y: builtins.str) -> builtins.int" +[builtins fixtures/dict.pyi] + +[case testParamSpecClassWithPrefixArgument] +from typing import Callable, TypeVar, Generic +from typing_extensions import ParamSpec + +P = ParamSpec('P') + +class C(Generic[P]): + def __init__(self, x: Callable[P, None]) -> None: ... + + def m(self, a: str, *args: P.args, **kwargs: P.kwargs) -> int: + return 1 + +def f(x: int, y: str) -> None: ... + +reveal_type(C(f).m) # N: Revealed type is "def (a: builtins.str, x: builtins.int, y: builtins.str) -> builtins.int" +reveal_type(C(f).m('', 1, '')) # N: Revealed type is "builtins.int" +[builtins fixtures/dict.pyi] + +[case testParamSpecDecorator] +from typing import Callable, TypeVar, Generic +from typing_extensions import ParamSpec + +P = ParamSpec('P') +R = TypeVar('R') + +class W(Generic[P, R]): + f: Callable[P, R] + x: int + def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R: + reveal_type(self.f(*args, **kwargs)) # N: Revealed type is "R`2" + return self.f(*args, **kwargs) + +def dec() -> Callable[[Callable[P, R]], W[P, R]]: + pass + +@dec() +def f(a: int, b: str) -> None: ... + +reveal_type(f) # N: Revealed type is "__main__.W[def (a: builtins.int, b: builtins.str), None]" +reveal_type(f(1, '')) # N: Revealed type is "None" +reveal_type(f.x) # N: Revealed type is "builtins.int" + +## TODO: How should this work? +# +# class C: +# @dec() +# def m(self, x: int) -> str: ... +# +# reveal_type(C().m(x=1)) +[builtins fixtures/dict.pyi] + +[case testParamSpecFunction] +from typing import Callable, TypeVar +from typing_extensions import ParamSpec + +P = ParamSpec('P') +R = TypeVar('R') + +def f(x: Callable[P, R], *args: P.args, **kwargs: P.kwargs) -> R: + return x(*args, **kwargs) + +def g(x: int, y: str) -> None: ... + +reveal_type(f(g, 1, y='x')) # N: Revealed type is "None" +f(g, 'x', y='x') # E: Argument 2 to "f" has incompatible type "str"; expected "int" +f(g, 1, y=1) # E: Argument "y" to "f" has incompatible type "int"; expected "str" +f(g) # E: Missing positional arguments "x", "y" in call to "f" + +[builtins fixtures/dict.pyi] + +[case testParamSpecSpecialCase] +from typing import Callable, TypeVar +from typing_extensions import ParamSpec + +P = ParamSpec('P') +T = TypeVar('T') + +def register(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> Callable[P, T]: ... + +def f(x: int, y: str, z: int, a: str) -> None: ... + +x = register(f, 1, '', 1, '') +[builtins fixtures/dict.pyi] + +[case testParamSpecInferredFromAny] +from typing import Callable, Any +from typing_extensions import ParamSpec + +P = ParamSpec('P') + +def f(x: Callable[P, int]) -> Callable[P, str]: ... + +g: Any +reveal_type(f(g)) # N: Revealed type is "def (*Any, **Any) -> builtins.str" + +f(g)(1, 3, x=1, y=2) +[builtins fixtures/tuple.pyi] + +[case testParamSpecDecoratorImplementation] +from typing import Callable, Any, TypeVar, List +from typing_extensions import ParamSpec + +P = ParamSpec('P') +T = TypeVar('T') + +def dec(f: Callable[P, T]) -> Callable[P, List[T]]: + def wrapper(*args: P.args, **kwargs: P.kwargs) -> List[T]: + return [f(*args, **kwargs)] + return wrapper + +@dec +def g(x: int, y: str = '') -> int: ... + +reveal_type(g) # N: Revealed type is "def (x: builtins.int, y: builtins.str =) -> builtins.list[builtins.int*]" +[builtins fixtures/dict.pyi] + +[case testParamSpecArgsAndKwargsTypes] +from typing import Callable, TypeVar, Generic +from typing_extensions import ParamSpec + +P = ParamSpec('P') + +class C(Generic[P]): + def __init__(self, x: Callable[P, None]) -> None: ... + + def m(self, *args: P.args, **kwargs: P.kwargs) -> None: + reveal_type(args) # N: Revealed type is "P.args`1" + reveal_type(kwargs) # N: Revealed type is "P.kwargs`1" +[builtins fixtures/dict.pyi] + +[case testParamSpecSubtypeChecking1] +from typing import Callable, TypeVar, Generic, Any +from typing_extensions import ParamSpec + +P = ParamSpec('P') + +class C(Generic[P]): + def __init__(self, x: Callable[P, None]) -> None: ... + + def m(self, *args: P.args, **kwargs: P.kwargs) -> None: + args = args + kwargs = kwargs + o: object + o = args + o = kwargs + o2: object + args = o2 # E: Incompatible types in assignment (expression has type "object", variable has type "P.args") + kwargs = o2 # E: Incompatible types in assignment (expression has type "object", variable has type "P.kwargs") + a: Any + a = args + a = kwargs + args = kwargs # E: Incompatible types in assignment (expression has type "P.kwargs", variable has type "P.args") + kwargs = args # E: Incompatible types in assignment (expression has type "P.args", variable has type "P.kwargs") + args = a + kwargs = a +[builtins fixtures/dict.pyi] + +[case testParamSpecSubtypeChecking2] +from typing import Callable, Generic +from typing_extensions import ParamSpec + +P = ParamSpec('P') +P2 = ParamSpec('P2') + +class C(Generic[P]): + pass + +def f(c1: C[P], c2: C[P2]) -> None: + c1 = c1 + c2 = c2 + c1 = c2 # E: Incompatible types in assignment (expression has type "C[P2]", variable has type "C[P]") + c2 = c1 # E: Incompatible types in assignment (expression has type "C[P]", variable has type "C[P2]") + +def g(f: Callable[P, None], g: Callable[P2, None]) -> None: + f = f + g = g + f = g # E: Incompatible types in assignment (expression has type "Callable[P2, None]", variable has type "Callable[P, None]") + g = f # E: Incompatible types in assignment (expression has type "Callable[P, None]", variable has type "Callable[P2, None]") +[builtins fixtures/dict.pyi] + +[case testParamSpecJoin] +from typing import Callable, Generic, TypeVar +from typing_extensions import ParamSpec + +P = ParamSpec('P') +P2 = ParamSpec('P2') +P3 = ParamSpec('P3') +T = TypeVar('T') + +def join(x: T, y: T) -> T: ... + +class C(Generic[P, P2]): + def m(self, f: Callable[P, None], g: Callable[P2, None]) -> None: + reveal_type(join(f, f)) # N: Revealed type is "def (*P.args, **P.kwargs)" + reveal_type(join(f, g)) # N: Revealed type is "builtins.function*" + + def m2(self, *args: P.args, **kwargs: P.kwargs) -> None: + reveal_type(join(args, args)) # N: Revealed type is "P.args`1" + reveal_type(join(kwargs, kwargs)) # N: Revealed type is "P.kwargs`1" + reveal_type(join(args, kwargs)) # N: Revealed type is "builtins.object*" + def f(*args2: P2.args, **kwargs2: P2.kwargs) -> None: + reveal_type(join(args, args2)) # N: Revealed type is "builtins.object*" + reveal_type(join(kwargs, kwargs2)) # N: Revealed type is "builtins.object*" + + def m3(self, c: C[P, P3]) -> None: + reveal_type(join(c, c)) # N: Revealed type is "__main__.C*[P`1, P3`-1]" + reveal_type(join(self, c)) # N: Revealed type is "builtins.object*" +[builtins fixtures/dict.pyi] + +[case testParamSpecClassWithAny] +from typing import Callable, Generic, Any +from typing_extensions import ParamSpec + +P = ParamSpec('P') + +class C(Generic[P]): + def __init__(self, x: Callable[P, None]) -> None: ... + + def m(self, *args: P.args, **kwargs: P.kwargs) -> int: + return 1 + +c: C[Any] +reveal_type(c) # N: Revealed type is "__main__.C[Any]" +reveal_type(c.m) # N: Revealed type is "def (*args: Any, **kwargs: Any) -> builtins.int" +c.m(4, 6, y='x') +c = c + +def f() -> None: pass + +c2 = C(f) +c2 = c +c3 = C(f) +c = c3 +[builtins fixtures/dict.pyi] + +[case testParamSpecInferredFromLambda] +from typing import Callable, TypeVar +from typing_extensions import ParamSpec + +P = ParamSpec('P') +T = TypeVar('T') + +# Similar to atexit.register +def register(f: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> Callable[P, T]: ... # N: "register" defined here + +def f(x: int) -> None: pass + +reveal_type(register(lambda: f(1))) # N: Revealed type is "def ()" +reveal_type(register(lambda x: f(x), x=1)) # N: Revealed type is "def (x: Any)" +register(lambda x: f(x)) # E: Missing positional argument "x" in call to "register" +register(lambda x: f(x), y=1) # E: Unexpected keyword argument "y" for "register" +[builtins fixtures/dict.pyi] + +[case testParamSpecInvalidCalls] +from typing import Callable, Generic +from typing_extensions import ParamSpec + +P = ParamSpec('P') +P2 = ParamSpec('P2') + +class C(Generic[P, P2]): + def m1(self, *args: P.args, **kwargs: P.kwargs) -> None: + self.m1(*args, **kwargs) + self.m2(*args, **kwargs) # E: Argument 1 to "m2" of "C" has incompatible type "*P.args"; expected "P2.args" \ + # E: Argument 2 to "m2" of "C" has incompatible type "**P.kwargs"; expected "P2.kwargs" + self.m1(*kwargs, **args) # E: Argument 1 to "m1" of "C" has incompatible type "*P.kwargs"; expected "P.args" \ + # E: Argument 2 to "m1" of "C" has incompatible type "**P.args"; expected "P.kwargs" + self.m3(*args, **kwargs) # E: Argument 1 to "m3" of "C" has incompatible type "*P.args"; expected "int" \ + # E: Argument 2 to "m3" of "C" has incompatible type "**P.kwargs"; expected "int" + self.m4(*args, **kwargs) # E: Argument 1 to "m4" of "C" has incompatible type "*P.args"; expected "int" \ + # E: Argument 2 to "m4" of "C" has incompatible type "**P.kwargs"; expected "int" + + self.m1(*args, **args) # E: Argument 2 to "m1" of "C" has incompatible type "**P.args"; expected "P.kwargs" + self.m1(*kwargs, **kwargs) # E: Argument 1 to "m1" of "C" has incompatible type "*P.kwargs"; expected "P.args" + + def m2(self, *args: P2.args, **kwargs: P2.kwargs) -> None: + pass + + def m3(self, *args: int, **kwargs: int) -> None: + pass + + def m4(self, x: int) -> None: + pass +[builtins fixtures/dict.pyi] + +[case testParamSpecOverUnannotatedDecorator] +from typing import Callable, Iterator, TypeVar, ContextManager, Any +from typing_extensions import ParamSpec + +from nonexistent import deco2 # type: ignore + +T = TypeVar("T") +P = ParamSpec("P") +T_co = TypeVar("T_co", covariant=True) + +class CM(ContextManager[T_co]): + def __call__(self, func: T) -> T: ... + +def deco1( + func: Callable[P, Iterator[T]]) -> Callable[P, CM[T]]: ... + +@deco1 +@deco2 +def f(): + pass + +reveal_type(f) # N: Revealed type is "def (*Any, **Any) -> __main__.CM[Any]" + +with f() as x: + pass +[builtins fixtures/dict.pyi] +[typing fixtures/typing-full.pyi] diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index 6410427b00af..6768263e9832 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -39,6 +39,57 @@ def fun2() -> P: def fun3() -> P: return B() # E: Incompatible return value type (got "B", expected "P") +[case testProtocolAttrAccessDecoratedGetAttrDunder] +from typing import Any, Protocol, Callable + +def typed_decorator(fun: Callable) -> Callable[[Any, str], str]: + pass + +def untyped_decorator(fun): + pass + +class P(Protocol): + @property + def x(self) -> int: + pass + +class A: + @untyped_decorator + def __getattr__(self, key: str) -> int: + pass + +class B: + @typed_decorator + def __getattr__(self, key: str) -> int: + pass + +class C: + def __getattr__(self, key: str) -> int: + pass + +def fun(x: P) -> None: + pass + +a: A +reveal_type(a.x) +fun(a) + +b: B +reveal_type(b.x) +fun(b) + +c: C +reveal_type(c.x) +fun(c) +[out] +main:32: note: Revealed type is "Any" +main:36: note: Revealed type is "builtins.str" +main:37: error: Argument 1 to "fun" has incompatible type "B"; expected "P" +main:37: note: Following member(s) of "B" have conflicts: +main:37: note: x: expected "int", got "str" +main:40: note: Revealed type is "builtins.int" +[builtins fixtures/bool.pyi] + [case testSimpleProtocolOneAbstractMethod] from typing import Protocol from abc import abstractmethod @@ -486,6 +537,64 @@ class P2(Protocol[T_co]): # E: Covariant type variable "T_co" used in protocol w lst: List[T_co] [builtins fixtures/list.pyi] + +[case testProtocolConstraintsUnsolvableWithSelfAnnotation1] +# https://github.com/python/mypy/issues/11020 +from typing import overload, Protocol, TypeVar + +I = TypeVar('I', covariant=True) +V_contra = TypeVar('V_contra', contravariant=True) + +class C(Protocol[I]): + def __abs__(self: 'C[V_contra]') -> 'C[V_contra]': + ... + + @overload + def f(self: 'C', q: int) -> int: + ... + @overload + def f(self: 'C[float]', q: float) -> 'C[float]': + ... +[builtins fixtures/bool.pyi] + + +[case testProtocolConstraintsUnsolvableWithSelfAnnotation2] +# https://github.com/python/mypy/issues/11020 +from typing import Protocol, TypeVar + +I = TypeVar('I', covariant=True) +V = TypeVar('V') + +class C(Protocol[I]): + def g(self: 'C[V]') -> 'C[V]': + ... + +class D: + pass + +x: C = D() # E: Incompatible types in assignment (expression has type "D", variable has type "C[Any]") +[builtins fixtures/bool.pyi] + + +[case testProtocolConstraintsUnsolvableWithSelfAnnotation3] +# https://github.com/python/mypy/issues/11020 +from typing import Protocol, TypeVar + +I = TypeVar('I', covariant=True) +V = TypeVar('V') + +class C(Protocol[I]): + def g(self: 'C[V]') -> 'C[V]': + ... + +class D: + def g(self) -> D: + ... + +x: C = D() +[builtins fixtures/bool.pyi] + + [case testProtocolVarianceWithUnusedVariable] from typing import Protocol, TypeVar T = TypeVar('T') @@ -2082,7 +2191,10 @@ main:18: note: @overload main:18: note: def f(self, x: int) -> int main:18: note: @overload main:18: note: def f(self, x: str) -> str -main:18: note: <2 more overloads not shown> +main:18: note: @overload +main:18: note: def f(self, x: C1) -> C2 +main:18: note: @overload +main:18: note: def f(self, x: C2) -> C1 main:18: note: Got: main:18: note: def f(self) -> None diff --git a/test-data/unit/check-python2.test b/test-data/unit/check-python2.test index f9837b8cfd03..d658fe013401 100644 --- a/test-data/unit/check-python2.test +++ b/test-data/unit/check-python2.test @@ -27,10 +27,16 @@ class A: # type: (str) -> None pass +class B: + def write(self): + # type: () -> int + pass + print >>A(), '' print >>None, '' print >>1, '' # E: "int" has no attribute "write" print >>(None + ''), None # E: Unsupported left operand type for + ("None") +print >> B(), '' # E: Argument "file" to "print" has incompatible type "def () -> builtins.int"; expected "def (builtins.str) -> Any" [case testDivision] class A: diff --git a/test-data/unit/check-python310.test b/test-data/unit/check-python310.test new file mode 100644 index 000000000000..3bcac61855b4 --- /dev/null +++ b/test-data/unit/check-python310.test @@ -0,0 +1,7 @@ +[case testMatchStatementNotSupported] +# flags: --python-version 3.10 +match str(): # E: Match statement is not supported + case 'x': + 1 + '' + case _: + 1 + b'' diff --git a/test-data/unit/check-python38.test b/test-data/unit/check-python38.test index 7bcef0c498f6..ce1f9841e240 100644 --- a/test-data/unit/check-python38.test +++ b/test-data/unit/check-python38.test @@ -18,7 +18,7 @@ def f(): ... # E: Function is missing a return type annotation \ def d(f): ... # type: ignore @d # type: ignore -def f(): ... # type: ignore # E: unused "type: ignore" comment +def f(): ... # type: ignore # E: Unused "type: ignore" comment [case testIgnoreDecoratedFunction2] # flags: --disallow-untyped-defs @@ -91,28 +91,28 @@ def g(x: int): ... [case testIgnoreScopeUnused1] # flags: --warn-unused-ignores -( # type: ignore # E: unused "type: ignore" comment - "IGNORE" # type: ignore # E: unused "type: ignore" comment - + # type: ignore # E: unused "type: ignore" comment +( # type: ignore # E: Unused "type: ignore" comment + "IGNORE" # type: ignore # E: Unused "type: ignore" comment + + # type: ignore # E: Unused "type: ignore" comment 0 # type: ignore -) # type: ignore # E: unused "type: ignore" comment +) # type: ignore # E: Unused "type: ignore" comment [builtins fixtures/primitives.pyi] [case testIgnoreScopeUnused2] # flags: --warn-unused-ignores -( # type: ignore # E: unused "type: ignore" comment +( # type: ignore # E: Unused "type: ignore" comment "IGNORE" - # type: ignore - 0 # type: ignore # E: unused "type: ignore" comment -) # type: ignore # E: unused "type: ignore" comment + 0 # type: ignore # E: Unused "type: ignore" comment +) # type: ignore # E: Unused "type: ignore" comment [case testIgnoreScopeUnused3] # flags: --warn-unused-ignores -( # type: ignore # E: unused "type: ignore" comment +( # type: ignore # E: Unused "type: ignore" comment "IGNORE" / 0 # type: ignore -) # type: ignore # E: unused "type: ignore" comment +) # type: ignore # E: Unused "type: ignore" comment [case testPEP570ArgTypesMissing] # flags: --disallow-untyped-defs @@ -193,9 +193,9 @@ def f(p1: bytes, p2: float, /) -> None: reveal_type(p2) # N: Revealed type is "builtins.float" [case testPEP570Unannotated] -def f(arg, /): ... +def f(arg, /): ... # N: "f" defined here g = lambda arg, /: arg -def h(arg=0, /): ... +def h(arg=0, /): ... # N: "h" defined here i = lambda arg=0, /: arg f(1) @@ -384,6 +384,57 @@ reveal_type(z2) # E: Name "z2" is not defined # N: Revealed type is "Any" [builtins fixtures/isinstancelist.pyi] +[case testWalrusConditionalTypeBinder] +from typing import Union +from typing_extensions import Literal + +class Good: + @property + def is_good(self) -> Literal[True]: ... + +class Bad: + @property + def is_good(self) -> Literal[False]: ... + +def get_thing() -> Union[Good, Bad]: ... + +if (thing := get_thing()).is_good: + reveal_type(thing) # N: Revealed type is "__main__.Good" +else: + reveal_type(thing) # N: Revealed type is "__main__.Bad" +[builtins fixtures/property.pyi] + +[case testWalrusConditionalTypeCheck] +# flags: --strict-optional +from typing import Optional + +maybe_str: Optional[str] + +if (is_str := maybe_str is not None): + reveal_type(is_str) # N: Revealed type is "Literal[True]" + reveal_type(maybe_str) # N: Revealed type is "builtins.str" +else: + reveal_type(is_str) # N: Revealed type is "Literal[False]" + reveal_type(maybe_str) # N: Revealed type is "None" + +reveal_type(maybe_str) # N: Revealed type is "Union[builtins.str, None]" +[builtins fixtures/bool.pyi] + +[case testWalrusConditionalTypeCheck2] +from typing import Optional + +maybe_str: Optional[str] + +if (x := maybe_str) is not None: + reveal_type(x) # N: Revealed type is "builtins.str" + reveal_type(maybe_str) # N: Revealed type is "Union[builtins.str, None]" +else: + reveal_type(x) # N: Revealed type is "None" + reveal_type(maybe_str) # N: Revealed type is "Union[builtins.str, None]" + +reveal_type(maybe_str) # N: Revealed type is "Union[builtins.str, None]" +[builtins fixtures/bool.pyi] + [case testWalrusPartialTypes] from typing import List @@ -400,6 +451,77 @@ def check_partial_list() -> None: reveal_type(z) # N: Revealed type is "builtins.list[builtins.int]" [builtins fixtures/list.pyi] +[case testWalrusAssignmentAndConditionScopeForLiteral] +# flags: --warn-unreachable + +if (x := 0): + reveal_type(x) # E: Statement is unreachable +else: + reveal_type(x) # N: Revealed type is "builtins.int" + +reveal_type(x) # N: Revealed type is "builtins.int" + +[case testWalrusAssignmentAndConditionScopeForProperty] +# flags: --warn-unreachable + +from typing_extensions import Literal + +class PropertyWrapper: + @property + def f(self) -> str: ... + @property + def always_false(self) -> Literal[False]: ... + +wrapper = PropertyWrapper() + +if x := wrapper.f: + reveal_type(x) # N: Revealed type is "builtins.str" +else: + reveal_type(x) # N: Revealed type is "builtins.str" + +reveal_type(x) # N: Revealed type is "builtins.str" + +if y := wrapper.always_false: + reveal_type(y) # E: Statement is unreachable +else: + reveal_type(y) # N: Revealed type is "Literal[False]" + +reveal_type(y) # N: Revealed type is "Literal[False]" +[builtins fixtures/property.pyi] + +[case testWalrusAssignmentAndConditionScopeForFunction] +# flags: --warn-unreachable + +from typing_extensions import Literal + +def f() -> str: ... + +if x := f(): + reveal_type(x) # N: Revealed type is "builtins.str" +else: + reveal_type(x) # N: Revealed type is "builtins.str" + +reveal_type(x) # N: Revealed type is "builtins.str" + +def always_false() -> Literal[False]: ... + +if y := always_false(): + reveal_type(y) # E: Statement is unreachable +else: + reveal_type(y) # N: Revealed type is "Literal[False]" + +reveal_type(y) # N: Revealed type is "Literal[False]" + +def always_false_with_parameter(x: int) -> Literal[False]: ... + +if z := always_false_with_parameter(5): + reveal_type(z) # E: Statement is unreachable +else: + reveal_type(z) # N: Revealed type is "Literal[False]" + +reveal_type(z) # N: Revealed type is "Literal[False]" +[builtins fixtures/tuple.pyi] + [case testWalrusExpr] def func() -> None: foo = Foo() @@ -418,3 +540,33 @@ def main(a: object) -> None: reveal_type(x) # N: Revealed type is "builtins.float" reveal_type(a) # N: Revealed type is "builtins.object" [builtins fixtures/tuple.pyi] + +[case testWalrusRedefined] +def foo() -> None: + x = 0 + [x := x + y for y in [1, 2, 3]] +[builtins fixtures/dict.pyi] + +[case testOverloadWithPositionalOnlySelf] +from typing import overload, Optional + +class Foo: + @overload + def f(self, a: str, /) -> None: ... + + @overload + def f(self, *, b: bool = False) -> None: ... + + def f(self, a: Optional[str] = None, /, *, b: bool = False) -> None: # E: Overloaded function implementation does not accept all possible arguments of signature 2 + ... + +class Bar: + @overload + def f(self, a: str, /) -> None: ... + + @overload # Notice `/` in sig below: + def f(self, /, *, b: bool = False) -> None: ... + + def f(self, a: Optional[str] = None, /, *, b: bool = False) -> None: + ... +[builtins fixtures/bool.pyi] diff --git a/test-data/unit/check-redefine.test b/test-data/unit/check-redefine.test index d2229dba470f..85208df0932a 100644 --- a/test-data/unit/check-redefine.test +++ b/test-data/unit/check-redefine.test @@ -498,7 +498,8 @@ def _(arg: str): def _(arg: int) -> int: return 'a' # E: Incompatible return value type (got "str", expected "int") -[case testCallingUnderscoreFunctionIsNotAllowed] +[case testCallingUnderscoreFunctionIsNotAllowed-skip] +# Skipped because of https://github.com/python/mypy/issues/11774 def _(arg: str) -> None: pass diff --git a/test-data/unit/check-selftype.test b/test-data/unit/check-selftype.test index 7e37276a3f75..afd75111743d 100644 --- a/test-data/unit/check-selftype.test +++ b/test-data/unit/check-selftype.test @@ -366,7 +366,7 @@ reveal_type(x.f) # N: Revealed type is "builtins.int" [builtins fixtures/property.pyi] [case testSelfTypeProperSupertypeAttribute] -from typing import Callable, TypeVar, ClassVar +from typing import Callable, TypeVar class K: pass T = TypeVar('T', bound=K) class A(K): @@ -374,8 +374,8 @@ class A(K): def g(self: K) -> int: return 0 @property def gt(self: T) -> T: return self - f: ClassVar[Callable[[object], int]] - ft: ClassVar[Callable[[T], T]] + f: Callable[[object], int] + ft: Callable[[T], T] class B(A): pass @@ -392,15 +392,15 @@ reveal_type(B().ft()) # N: Revealed type is "__main__.B*" [builtins fixtures/property.pyi] [case testSelfTypeProperSupertypeAttributeTuple] -from typing import Callable, TypeVar, Tuple, ClassVar +from typing import Callable, TypeVar, Tuple T = TypeVar('T') class A(Tuple[int, int]): @property def g(self: object) -> int: return 0 @property def gt(self: T) -> T: return self - f: ClassVar[Callable[[object], int]] - ft: ClassVar[Callable[[T], T]] + f: Callable[[object], int] + ft: Callable[[T], T] class B(A): pass @@ -450,7 +450,7 @@ reveal_type(X1.ft()) # N: Revealed type is "Type[__main__.X]" [builtins fixtures/property.pyi] [case testSelfTypeProperSupertypeAttributeGeneric] -from typing import Callable, TypeVar, Generic, ClassVar +from typing import Callable, TypeVar, Generic Q = TypeVar('Q', covariant=True) class K(Generic[Q]): q: Q @@ -460,8 +460,8 @@ class A(K[Q]): def g(self: K[object]) -> int: return 0 @property def gt(self: K[T]) -> T: return self.q - f: ClassVar[Callable[[object], int]] - ft: ClassVar[Callable[[T], T]] + f: Callable[[object], int] + ft: Callable[[T], T] class B(A[Q]): pass @@ -802,6 +802,37 @@ class Bad(metaclass=Meta): Good.do_x() Bad.do_x() # E: Invalid self argument "Type[Bad]" to attribute function "do_x" with type "Callable[[Type[T]], T]" +[case testSelfTypeProtocolClassmethodMatch] +from typing import Type, TypeVar, Protocol + +T = TypeVar('T') + +class HasDoX(Protocol): + @classmethod + def do_x(cls: Type[T]) -> T: + ... + +class Good: + @classmethod + def do_x(cls) -> 'Good': + ... + +class Bad: + @classmethod + def do_x(cls) -> Good: + ... + +good: HasDoX = Good() +bad: HasDoX = Bad() +[builtins fixtures/classmethod.pyi] +[out] +main:21: error: Incompatible types in assignment (expression has type "Bad", variable has type "HasDoX") +main:21: note: Following member(s) of "Bad" have conflicts: +main:21: note: Expected: +main:21: note: def do_x(cls) -> Bad +main:21: note: Got: +main:21: note: def do_x(cls) -> Good + [case testSelfTypeNotSelfType] # Friendlier error messages for common mistakes. See #2950 class A: diff --git a/test-data/unit/check-slots.test b/test-data/unit/check-slots.test index 96e4eba3c966..254aa983f82f 100644 --- a/test-data/unit/check-slots.test +++ b/test-data/unit/check-slots.test @@ -361,7 +361,8 @@ a.a = 1 a.b = custom_obj a.c = custom_obj a.d = custom_obj -a.e = custom_obj +# TODO: Should this be allowed? +a.e = custom_obj # E: Cannot assign to a method [out] [builtins fixtures/tuple.pyi] [builtins fixtures/dict.pyi] diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index d5b35784f5e5..6c4c63dc5c2d 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -405,7 +405,7 @@ a, b = None, None # type: (A, B) a1, b1 = a, a # type: (A, B) # E: Incompatible types in assignment (expression has type "A", variable has type "B") a2, b2 = b, b # type: (A, B) # E: Incompatible types in assignment (expression has type "B", variable has type "A") -a3, b3 = a # type: (A, B) # E: "__main__.A" object is not iterable +a3, b3 = a # type: (A, B) # E: "A" object is not iterable a4, b4 = None # type: (A, B) # E: "None" object is not iterable a5, b5 = a, b, a # type: (A, B) # E: Too many values to unpack (2 expected, 3 provided) @@ -421,8 +421,8 @@ a, b = None, None # type: (A, B) def f(): pass a, b = None # E: "None" object is not iterable -a, b = a # E: "__main__.A" object is not iterable -a, b = f # E: "def () -> Any" object is not iterable +a, b = a # E: "A" object is not iterable +a, b = f # E: "Callable[[], Any]" object is not iterable class A: pass class B: pass @@ -1468,7 +1468,7 @@ x9, y9, x10, y10, z5 = *points2, 1, *points2 # E: Contiguous iterable with same () = [] # E: can't assign to () [case testAssignEmptyBogus] -() = 1 # E: "Literal[1]?" object is not iterable +() = 1 # E: "int" object is not iterable [builtins fixtures/tuple.pyi] [case testMultiplyTupleByIntegerLiteral] diff --git a/test-data/unit/check-type-aliases.test b/test-data/unit/check-type-aliases.test index 2701858895d1..a697c32d7c49 100644 --- a/test-data/unit/check-type-aliases.test +++ b/test-data/unit/check-type-aliases.test @@ -659,3 +659,64 @@ reveal_type(w) # N: Revealed type is "__main__.Out.In" reveal_type(x) # N: Revealed type is "__main__.Out.In.Inner" reveal_type(y) # N: Revealed type is "__main__.Out.In.Inner" reveal_type(z) # N: Revealed type is "__main__.Out.In" + + +[case testSimplePep613] +from typing_extensions import TypeAlias +x: TypeAlias = str +a: x +reveal_type(a) # N: Revealed type is "builtins.str" + +y: TypeAlias = "str" +b: y +reveal_type(b) # N: Revealed type is "builtins.str" + +z: TypeAlias = "int | str" +c: z +reveal_type(c) # N: Revealed type is "Union[builtins.int, builtins.str]" +[builtins fixtures/tuple.pyi] + +[case testForwardRefPep613] +from typing_extensions import TypeAlias + +x: TypeAlias = "MyClass" +a: x +reveal_type(a) # N: Revealed type is "__main__.MyClass" + +class MyClass: ... +[builtins fixtures/tuple.pyi] + +[case testInvalidPep613] +from typing_extensions import TypeAlias + +x: TypeAlias = list(int) # E: Invalid type alias: expression is not a valid type \ + # E: Too many arguments for "list" +a: x +[builtins fixtures/tuple.pyi] + +[case testFunctionScopePep613] +from typing_extensions import TypeAlias + +def f() -> None: + x: TypeAlias = str + a: x + reveal_type(a) # N: Revealed type is "builtins.str" + + y: TypeAlias = "str" + b: y + reveal_type(b) # N: Revealed type is "builtins.str" +[builtins fixtures/tuple.pyi] + +[case testImportCyclePep613] +# cmd: mypy -m t t2 +[file t.py] +MYPY = False +if MYPY: + from t2 import A +x: A +reveal_type(x) # N: Revealed type is "builtins.str" +[file t2.py] +from typing_extensions import TypeAlias +A: TypeAlias = str +[builtins fixtures/bool.pyi] +[out] diff --git a/test-data/unit/check-typeddict.test b/test-data/unit/check-typeddict.test index 04bbc9b2b4d4..921d2ab5c46e 100644 --- a/test-data/unit/check-typeddict.test +++ b/test-data/unit/check-typeddict.test @@ -75,6 +75,14 @@ Point = TypedDict('Point', {'x': int, 'y': int}) p = Point(x='meaning_of_life', y=1337) # E: Incompatible types (expression has type "str", TypedDict item "x" has type "int") [builtins fixtures/dict.pyi] +[case testCannotCreateTypedDictInstanceWithInlineTypedDict] +from mypy_extensions import TypedDict +D = TypedDict('D', { + 'x': TypedDict('E', { # E: Inline TypedDict types not supported; use assignment to define TypedDict + 'y': int + }) +}) +[builtins fixtures/dict.pyi] -- Define TypedDict (Class syntax) @@ -171,6 +179,21 @@ p: Point2D reveal_type(p) # N: Revealed type is "TypedDict('__main__.Point2D', {'x': builtins.int, 'y': builtins.int})" [builtins fixtures/dict.pyi] +[case testCannotCreateTypedDictWithDuplicateBases] +# https://github.com/python/mypy/issues/3673 +from typing import TypedDict + +class A(TypedDict): + x: str + y: int + +class B(A, A): # E: Duplicate base class "A" + z: str + +class C(TypedDict, TypedDict): # E: Duplicate base class "TypedDict" + c1: int +[typing fixtures/typing-typeddict.pyi] + [case testCannotCreateTypedDictWithClassWithOtherStuff] # flags: --python-version 3.6 from mypy_extensions import TypedDict @@ -1241,7 +1264,7 @@ from mypy_extensions import TypedDict Point = TypedDict('Point', {'x': 1, 'y': 1}) # E: Invalid type: try using Literal[1] instead? [builtins fixtures/dict.pyi] -[case testCannotCreateTypedDictTypeWithInvalidName] +[case testCannotCreateTypedDictTypeWithInvalidName2] from mypy_extensions import TypedDict X = TypedDict('Y', {'x': int}) # E: First argument "Y" to TypedDict() does not match variable name "X" [builtins fixtures/dict.pyi] @@ -1453,7 +1476,7 @@ T = TypeVar('T', bound='M') class G(Generic[T]): x: T -yb: G[int] # E: Type argument "builtins.int" of "G" must be a subtype of "TypedDict('__main__.M', {'x': builtins.int})" +yb: G[int] # E: Type argument "int" of "G" must be a subtype of "M" yg: G[M] z: int = G[M]().x['x'] @@ -1681,8 +1704,8 @@ s = '' del a[s] # E: Expected TypedDict key to be string literal del b[s] # E: Expected TypedDict key to be string literal alias = b.__delitem__ -alias('x') # E: Argument 1 has incompatible type "str"; expected "NoReturn" -alias(s) # E: Argument 1 has incompatible type "str"; expected "NoReturn" +alias('x') +alias(s) [builtins fixtures/dict.pyi] [case testPluginUnionsOfTypedDicts] @@ -2109,7 +2132,7 @@ class TD(TypedDict): d: TD = {b'foo': 2} # E: Expected TypedDict key to be string literal d[b'foo'] = 3 # E: TypedDict key must be a string literal; expected one of ("foo") \ - # E: Argument 1 has incompatible type "bytes"; expected "str" + # E: Argument 1 to "__setitem__" has incompatible type "bytes"; expected "str" d[b'foo'] # E: TypedDict key must be a string literal; expected one of ("foo") d[3] # E: TypedDict key must be a string literal; expected one of ("foo") d[True] # E: TypedDict key must be a string literal; expected one of ("foo") @@ -2122,3 +2145,246 @@ from mypy_extensions import TypedDict Foo = TypedDict('Foo', {'camelCaseKey': str}) value: Foo = {} # E: Missing key "camelCaseKey" for TypedDict "Foo" [builtins fixtures/dict.pyi] + +-- Required[] + +[case testDoesRecognizeRequiredInTypedDictWithClass] +from typing import TypedDict +from typing import Required +class Movie(TypedDict, total=False): + title: Required[str] + year: int +m = Movie(title='The Matrix') +m = Movie() # E: Missing key "title" for TypedDict "Movie" +[typing fixtures/typing-typeddict.pyi] + +[case testDoesRecognizeRequiredInTypedDictWithAssignment] +from typing import TypedDict +from typing import Required +Movie = TypedDict('Movie', { + 'title': Required[str], + 'year': int, +}, total=False) +m = Movie(title='The Matrix') +m = Movie() # E: Missing key "title" for TypedDict "Movie" +[typing fixtures/typing-typeddict.pyi] + +[case testDoesDisallowRequiredOutsideOfTypedDict] +from typing import Required +x: Required[int] = 42 # E: Required[] can be only used in a TypedDict definition +[typing fixtures/typing-typeddict.pyi] + +[case testDoesOnlyAllowRequiredInsideTypedDictAtTopLevel] +from typing import TypedDict +from typing import Union +from typing import Required +Movie = TypedDict('Movie', { + 'title': Union[ + Required[str], # E: Required[] can be only used in a TypedDict definition + bytes + ], + 'year': int, +}, total=False) +[typing fixtures/typing-typeddict.pyi] + +[case testDoesDisallowRequiredInsideRequired] +from typing import TypedDict +from typing import Union +from typing import Required +Movie = TypedDict('Movie', { + 'title': Required[Union[ + Required[str], # E: Required[] can be only used in a TypedDict definition + bytes + ]], + 'year': int, +}, total=False) +[typing fixtures/typing-typeddict.pyi] + +[case testRequiredOnlyAllowsOneItem] +from typing import TypedDict +from typing import Required +class Movie(TypedDict, total=False): + title: Required[str, bytes] # E: Required[] must have exactly one type argument + year: int +[typing fixtures/typing-typeddict.pyi] + + +-- NotRequired[] + +[case testDoesRecognizeNotRequiredInTypedDictWithClass] +from typing import TypedDict +from typing import NotRequired +class Movie(TypedDict): + title: str + year: NotRequired[int] +m = Movie(title='The Matrix') +m = Movie() # E: Missing key "title" for TypedDict "Movie" +[typing fixtures/typing-typeddict.pyi] + +[case testDoesRecognizeNotRequiredInTypedDictWithAssignment] +from typing import TypedDict +from typing import NotRequired +Movie = TypedDict('Movie', { + 'title': str, + 'year': NotRequired[int], +}) +m = Movie(title='The Matrix') +m = Movie() # E: Missing key "title" for TypedDict "Movie" +[typing fixtures/typing-typeddict.pyi] + +[case testDoesDisallowNotRequiredOutsideOfTypedDict] +from typing import NotRequired +x: NotRequired[int] = 42 # E: NotRequired[] can be only used in a TypedDict definition +[typing fixtures/typing-typeddict.pyi] + +[case testDoesOnlyAllowNotRequiredInsideTypedDictAtTopLevel] +from typing import TypedDict +from typing import Union +from typing import NotRequired +Movie = TypedDict('Movie', { + 'title': Union[ + NotRequired[str], # E: NotRequired[] can be only used in a TypedDict definition + bytes + ], + 'year': int, +}) +[typing fixtures/typing-typeddict.pyi] + +[case testDoesDisallowNotRequiredInsideNotRequired] +from typing import TypedDict +from typing import Union +from typing import NotRequired +Movie = TypedDict('Movie', { + 'title': NotRequired[Union[ + NotRequired[str], # E: NotRequired[] can be only used in a TypedDict definition + bytes + ]], + 'year': int, +}) +[typing fixtures/typing-typeddict.pyi] + +[case testNotRequiredOnlyAllowsOneItem] +from typing import TypedDict +from typing import NotRequired +class Movie(TypedDict): + title: NotRequired[str, bytes] # E: NotRequired[] must have exactly one type argument + year: int +[typing fixtures/typing-typeddict.pyi] + +-- Union dunders + +[case testTypedDictUnionGetItem] +from typing import TypedDict, Union + +class Foo1(TypedDict): + z: str + a: int +class Foo2(TypedDict): + z: str + b: int + +def func(foo: Union[Foo1, Foo2]) -> str: + reveal_type(foo["z"]) # N: Revealed type is "builtins.str" + # ok, but type is incorrect: + reveal_type(foo.__getitem__("z")) # N: Revealed type is "builtins.object*" + + reveal_type(foo["a"]) # N: Revealed type is "Union[builtins.int, Any]" \ + # E: TypedDict "Foo2" has no key "a" + reveal_type(foo["b"]) # N: Revealed type is "Union[Any, builtins.int]" \ + # E: TypedDict "Foo1" has no key "b" + reveal_type(foo["missing"]) # N: Revealed type is "Any" \ + # E: TypedDict "Foo1" has no key "missing" \ + # E: TypedDict "Foo2" has no key "missing" + reveal_type(foo[1]) # N: Revealed type is "Any" \ + # E: TypedDict key must be a string literal; expected one of ("z", "a") \ + # E: TypedDict key must be a string literal; expected one of ("z", "b") + + return foo["z"] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-typeddict.pyi] + + +[case testTypedDictUnionSetItem] +from typing import TypedDict, Union + +class Foo1(TypedDict): + z: str + a: int +class Foo2(TypedDict): + z: str + b: int + +def func(foo: Union[Foo1, Foo2]): + foo["z"] = "a" # ok + foo.__setitem__("z", "a") # ok + + foo["z"] = 1 # E: Value of "z" has incompatible type "int"; expected "str" + + foo["a"] = 1 # E: TypedDict "Foo2" has no key "a" + foo["b"] = 2 # E: TypedDict "Foo1" has no key "b" + + foo["missing"] = 1 # E: TypedDict "Foo1" has no key "missing" \ + # E: TypedDict "Foo2" has no key "missing" + foo[1] = "m" # E: TypedDict key must be a string literal; expected one of ("z", "a") \ + # E: TypedDict key must be a string literal; expected one of ("z", "b") \ + # E: Argument 1 to "__setitem__" has incompatible type "int"; expected "str" +[builtins fixtures/dict.pyi] +[typing fixtures/typing-typeddict.pyi] + + +[case testTypedDictUnionDelItem] +from typing import TypedDict, Union + +class Foo1(TypedDict): + z: str + a: int +class Foo2(TypedDict): + z: str + b: int + +def func(foo: Union[Foo1, Foo2]): + del foo["z"] # E: Key "z" of TypedDict "Foo1" cannot be deleted \ + # E: Key "z" of TypedDict "Foo2" cannot be deleted + foo.__delitem__("z") # E: Key "z" of TypedDict "Foo1" cannot be deleted \ + # E: Key "z" of TypedDict "Foo2" cannot be deleted + + del foo["a"] # E: Key "a" of TypedDict "Foo1" cannot be deleted \ + # E: TypedDict "Foo2" has no key "a" + del foo["b"] # E: TypedDict "Foo1" has no key "b" \ + # E: Key "b" of TypedDict "Foo2" cannot be deleted + + del foo["missing"] # E: TypedDict "Foo1" has no key "missing" \ + # E: TypedDict "Foo2" has no key "missing" + del foo[1] # E: Expected TypedDict key to be string literal \ + # E: Argument 1 to "__delitem__" has incompatible type "int"; expected "str" +[builtins fixtures/dict.pyi] +[typing fixtures/typing-typeddict.pyi] + + +[case testTypedDictTypeVarUnionSetItem] +from typing import TypedDict, Union, TypeVar + +F1 = TypeVar('F1', bound='Foo1') +F2 = TypeVar('F2', bound='Foo2') + +class Foo1(TypedDict): + z: str + a: int +class Foo2(TypedDict): + z: str + b: int + +def func(foo: Union[F1, F2]): + foo["z"] = "a" # ok + foo["z"] = 1 # E: Value of "z" has incompatible type "int"; expected "str" + + foo["a"] = 1 # E: TypedDict "Foo2" has no key "a" + foo["b"] = 2 # E: TypedDict "Foo1" has no key "b" + + foo["missing"] = 1 # E: TypedDict "Foo1" has no key "missing" \ + # E: TypedDict "Foo2" has no key "missing" + foo[1] = "m" # E: TypedDict key must be a string literal; expected one of ("z", "a") \ + # E: TypedDict key must be a string literal; expected one of ("z", "b") \ + # E: Argument 1 to "__setitem__" has incompatible type "int"; expected "str" +[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 fb26f0d3d537..32fe5e750989 100644 --- a/test-data/unit/check-typeguard.test +++ b/test-data/unit/check-typeguard.test @@ -247,7 +247,7 @@ def main1(a: object) -> None: [builtins fixtures/tuple.pyi] -[case testTypeGuardOverload-skip] +[case testTypeGuardOverload] # flags: --strict-optional from typing import overload, Any, Callable, Iterable, Iterator, List, Optional, TypeVar from typing_extensions import TypeGuard @@ -458,3 +458,92 @@ def foobar_typeguard(x: object): return reveal_type(x) # N: Revealed type is "__main__." [builtins fixtures/tuple.pyi] + +[case testTypeGuardAsFunctionArgAsBoolSubtype] +from typing import Callable +from typing_extensions import TypeGuard + +def accepts_bool(f: Callable[[object], bool]): pass + +def with_bool_typeguard(o: object) -> TypeGuard[bool]: pass +def with_str_typeguard(o: object) -> TypeGuard[str]: pass +def with_bool(o: object) -> bool: pass + +accepts_bool(with_bool_typeguard) +accepts_bool(with_str_typeguard) +accepts_bool(with_bool) +[builtins fixtures/tuple.pyi] + +[case testTypeGuardAsFunctionArg] +from typing import Callable +from typing_extensions import TypeGuard + +def accepts_typeguard(f: Callable[[object], TypeGuard[bool]]): pass +def different_typeguard(f: Callable[[object], TypeGuard[str]]): pass + +def with_typeguard(o: object) -> TypeGuard[bool]: pass +def with_bool(o: object) -> bool: pass + +accepts_typeguard(with_typeguard) +accepts_typeguard(with_bool) # E: Argument 1 to "accepts_typeguard" has incompatible type "Callable[[object], bool]"; expected "Callable[[object], TypeGuard[bool]]" + +different_typeguard(with_typeguard) # E: Argument 1 to "different_typeguard" has incompatible type "Callable[[object], TypeGuard[bool]]"; expected "Callable[[object], TypeGuard[str]]" +different_typeguard(with_bool) # E: Argument 1 to "different_typeguard" has incompatible type "Callable[[object], bool]"; expected "Callable[[object], TypeGuard[str]]" +[builtins fixtures/tuple.pyi] + +[case testTypeGuardAsGenericFunctionArg] +from typing import Callable, TypeVar +from typing_extensions import TypeGuard + +T = TypeVar('T') + +def accepts_typeguard(f: Callable[[object], TypeGuard[T]]): pass + +def with_bool_typeguard(o: object) -> TypeGuard[bool]: pass +def with_str_typeguard(o: object) -> TypeGuard[str]: pass +def with_bool(o: object) -> bool: pass + +accepts_typeguard(with_bool_typeguard) +accepts_typeguard(with_str_typeguard) +accepts_typeguard(with_bool) # E: Argument 1 to "accepts_typeguard" has incompatible type "Callable[[object], bool]"; expected "Callable[[object], TypeGuard[bool]]" +[builtins fixtures/tuple.pyi] + +[case testTypeGuardAsOverloadedFunctionArg] +# https://github.com/python/mypy/issues/11307 +from typing import Callable, TypeVar, Generic, Any, overload +from typing_extensions import TypeGuard + +_T = TypeVar('_T') + +class filter(Generic[_T]): + @overload + def __init__(self, function: Callable[[object], TypeGuard[_T]]) -> None: pass + @overload + def __init__(self, function: Callable[[_T], Any]) -> None: pass + def __init__(self, function): pass + +def is_int_typeguard(a: object) -> TypeGuard[int]: pass +def returns_bool(a: object) -> bool: pass + +reveal_type(filter(is_int_typeguard)) # N: Revealed type is "__main__.filter[builtins.int*]" +reveal_type(filter(returns_bool)) # N: Revealed type is "__main__.filter[builtins.object*]" +[builtins fixtures/tuple.pyi] + +[case testTypeGuardSubtypingVariance] +from typing import Callable +from typing_extensions import TypeGuard + +class A: pass +class B(A): pass +class C(B): pass + +def accepts_typeguard(f: Callable[[object], TypeGuard[B]]): pass + +def with_typeguard_a(o: object) -> TypeGuard[A]: pass +def with_typeguard_b(o: object) -> TypeGuard[B]: pass +def with_typeguard_c(o: object) -> TypeGuard[C]: pass + +accepts_typeguard(with_typeguard_a) # E: Argument 1 to "accepts_typeguard" has incompatible type "Callable[[object], TypeGuard[A]]"; expected "Callable[[object], TypeGuard[B]]" +accepts_typeguard(with_typeguard_b) +accepts_typeguard(with_typeguard_c) +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/check-typevar-values.test b/test-data/unit/check-typevar-values.test index 3f77996ec959..2c25e9adc8bb 100644 --- a/test-data/unit/check-typevar-values.test +++ b/test-data/unit/check-typevar-values.test @@ -631,3 +631,74 @@ def g(s: S) -> Callable[[S], None]: ... def f(x: S) -> None: h = g(x) h(x) + +[case testTypeVarWithTypedDictBoundInIndexExpression] +from typing import TypeVar +from typing_extensions import TypedDict + +class Data(TypedDict): + x: int + + +T = TypeVar("T", bound=Data) + + +def f(data: T) -> None: + reveal_type(data["x"]) # N: Revealed type is "builtins.int" +[builtins fixtures/tuple.pyi] + +[case testTypeVarWithUnionTypedDictBoundInIndexExpression] +from typing import TypeVar, Union, Dict +from typing_extensions import TypedDict + +class Data(TypedDict): + x: int + + +T = TypeVar("T", bound=Union[Data, Dict[str, str]]) + + +def f(data: T) -> None: + reveal_type(data["x"]) # N: Revealed type is "Union[builtins.int, builtins.str*]" + +[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] + +[case testTypeVarWithTypedDictValueInIndexExpression] +from typing import TypeVar, Union, Dict +from typing_extensions import TypedDict + +class Data(TypedDict): + x: int + + +T = TypeVar("T", Data, Dict[str, str]) + + +def f(data: T) -> None: + _: Union[str, int] = data["x"] +[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] + +[case testSelfTypeVarIndexExpr] +from typing import TypeVar, Union, Type +from typing_extensions import TypedDict + +T = TypeVar("T", bound="Indexable") + +class Indexable: + def __init__(self, index: str) -> None: + self.index = index + + def __getitem__(self: T, index: str) -> T: + return self._new_instance(index) + + @classmethod + def _new_instance(cls: Type[T], index: str) -> T: + return cls("foo") + + def m(self: T) -> T: + return self["foo"] + +[builtins fixtures/tuple.pyi] +[builtins fixtures/classmethod.pyi] diff --git a/test-data/unit/check-unions.test b/test-data/unit/check-unions.test index 08c183cb3ed1..cf1ff5650d49 100644 --- a/test-data/unit/check-unions.test +++ b/test-data/unit/check-unions.test @@ -241,7 +241,7 @@ def f(x: M[C]) -> None: y = x.get(None) reveal_type(y) # N: Revealed type is "__main__.C" -[case testUnionSimplificationSpecialCases] +[case testUnionSimplificationSpecialCases2] from typing import Any, TypeVar, Union class C(Any): pass @@ -556,7 +556,7 @@ reveal_type(d1) # N: Revealed type is "Union[Any, builtins.float]" reveal_type(d2) # N: Revealed type is "Union[Any, builtins.float]" e: Union[Any, Tuple[float, float], int] -(e1, e2) = e # E: "builtins.int" object is not iterable +(e1, e2) = e # E: "int" object is not iterable [builtins fixtures/tuple.pyi] [case testUnionMultiassignNotJoin] @@ -694,7 +694,7 @@ reveal_type(d) # N: Revealed type is "builtins.list[builtins.int*]" from typing import Union bad: Union[int, str] -x, y = bad # E: "builtins.int" object is not iterable \ +x, y = bad # E: "int" object is not iterable \ # E: Unpacking a string is disallowed reveal_type(x) # N: Revealed type is "Any" reveal_type(y) # N: Revealed type is "Any" diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test index 010c944e3bfc..de85f5188bb8 100644 --- a/test-data/unit/check-unreachable-code.test +++ b/test-data/unit/check-unreachable-code.test @@ -533,11 +533,11 @@ f = (PY3 or PY2) and 's' g = (PY2 or PY3) or 's' h = (PY3 or PY2) or 's' reveal_type(a) # N: Revealed type is "builtins.bool" -reveal_type(b) # N: Revealed type is "builtins.str" -reveal_type(c) # N: Revealed type is "builtins.str" +reveal_type(b) # N: Revealed type is "Literal['s']" +reveal_type(c) # N: Revealed type is "Literal['s']" reveal_type(d) # N: Revealed type is "builtins.bool" -reveal_type(e) # N: Revealed type is "builtins.str" -reveal_type(f) # N: Revealed type is "builtins.str" +reveal_type(e) # N: Revealed type is "Literal['s']" +reveal_type(f) # N: Revealed type is "Literal['s']" reveal_type(g) # N: Revealed type is "builtins.bool" reveal_type(h) # N: Revealed type is "builtins.bool" [builtins fixtures/ops.pyi] @@ -754,35 +754,46 @@ if sys.version_info[0] >= 2: reveal_type('') # N: Revealed type is "Literal['']?" [builtins fixtures/ops.pyi] -[case testUnreachableFlagWithBadControlFlow] +[case testUnreachableFlagWithBadControlFlow1] # flags: --warn-unreachable a: int if isinstance(a, int): reveal_type(a) # N: Revealed type is "builtins.int" else: reveal_type(a) # E: Statement is unreachable +[builtins fixtures/isinstancelist.pyi] +[case testUnreachableFlagWithBadControlFlow2] +# flags: --warn-unreachable b: int while isinstance(b, int): reveal_type(b) # N: Revealed type is "builtins.int" else: reveal_type(b) # E: Statement is unreachable +[builtins fixtures/isinstancelist.pyi] +[case testUnreachableFlagWithBadControlFlow3] +# flags: --warn-unreachable def foo(c: int) -> None: reveal_type(c) # N: Revealed type is "builtins.int" assert not isinstance(c, int) reveal_type(c) # E: Statement is unreachable +[builtins fixtures/isinstancelist.pyi] +[case testUnreachableFlagWithBadControlFlow4] +# flags: --warn-unreachable d: int if False: reveal_type(d) # E: Statement is unreachable +[builtins fixtures/isinstancelist.pyi] +[case testUnreachableFlagWithBadControlFlow5] +# flags: --warn-unreachable e: int if True: reveal_type(e) # N: Revealed type is "builtins.int" else: reveal_type(e) # E: Statement is unreachable - [builtins fixtures/isinstancelist.pyi] [case testUnreachableFlagStatementAfterReturn] @@ -1378,3 +1389,42 @@ def f(t: T) -> None: except BaseException as e: pass [builtins fixtures/dict.pyi] + + +[case testUnreachableLiteral] +# flags: --warn-unreachable +from typing_extensions import Literal + +def nope() -> Literal[False]: ... + +def f() -> None: + if nope(): + x = 1 # E: Statement is unreachable +[builtins fixtures/dict.pyi] + +[case testUnreachableModuleBody1] +# flags: --warn-unreachable +from typing import NoReturn +def foo() -> NoReturn: + raise Exception("foo") +foo() +x = 1 # E: Statement is unreachable +[builtins fixtures/exception.pyi] + +[case testUnreachableModuleBody2] +# flags: --warn-unreachable +raise Exception +x = 1 # E: Statement is unreachable +[builtins fixtures/exception.pyi] + +[case testUnreachableNoReturnBinaryOps] +# flags: --warn-unreachable +from typing import NoReturn + +a: NoReturn +a and 1 # E: Right operand of "and" is never evaluated +a or 1 # E: Right operand of "or" is never evaluated +a or a # E: Right operand of "or" is never evaluated +1 and a and 1 # E: Right operand of "and" is never evaluated +a and a # E: Right operand of "and" is never evaluated +[builtins fixtures/exception.pyi] diff --git a/test-data/unit/check-varargs.test b/test-data/unit/check-varargs.test index d648381f2fc3..57a578401c51 100644 --- a/test-data/unit/check-varargs.test +++ b/test-data/unit/check-varargs.test @@ -414,23 +414,23 @@ main:4: error: Argument 2 to "f" has incompatible type "*List[A]"; expected "B" main:5: error: Argument 3 to "f" has incompatible type "*List[A]"; expected "B" main:6: error: Argument 1 to "f" has incompatible type "*Tuple[A, A, B]"; expected "Optional[B]" -[case testVarArgsAfterKeywordArgInCall1-skip] +[case testVarArgsAfterKeywordArgInCall1] # see: mypy issue #2729 def f(x: int, y: str) -> None: pass f(x=1, *[2]) [builtins fixtures/list.pyi] [out] -main:2: error: "f" gets multiple values for keyword argument "x" -main:2: error: Argument 2 to "f" has incompatible type *List[int]; expected "str" +main:3: error: "f" gets multiple values for keyword argument "x" +main:3: error: Argument 1 to "f" has incompatible type "*List[int]"; expected "str" -[case testVarArgsAfterKeywordArgInCall2-skip] +[case testVarArgsAfterKeywordArgInCall2] # see: mypy issue #2729 def f(x: int, y: str) -> None: pass f(y='x', *[1]) [builtins fixtures/list.pyi] [out] -main:2: error: "f" gets multiple values for keyword argument "y" -main:2: error: Argument 2 to "f" has incompatible type *List[int]; expected "str" +main:3: error: "f" gets multiple values for keyword argument "y" +main:3: error: Argument 1 to "f" has incompatible type "*List[int]"; expected "str" [case testVarArgsAfterKeywordArgInCall3] def f(x: int, y: str) -> None: pass @@ -734,3 +734,29 @@ b = {'b': 1} f(a) # E: Argument 1 to "f" has incompatible type "List[int]"; expected "Listener" g(b) # E: Argument 1 to "g" has incompatible type "Dict[str, int]"; expected "DictReader" [builtins fixtures/dict.pyi] + +[case testInvariantTypeConfusingNames2] +from typing import Iterable, Generic, TypeVar, List + +T = TypeVar('T') + +class I(Iterable[T]): + ... + +class Bad(Generic[T]): + ... + +def bar(*args: float) -> float: + ... + +good1: Iterable[float] +good2: List[float] +good3: I[float] +bad1: I[str] +bad2: Bad[float] +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 variable arguments +[builtins fixtures/dict.pyi] diff --git a/test-data/unit/check-warnings.test b/test-data/unit/check-warnings.test index 165812531e60..10c7968be475 100644 --- a/test-data/unit/check-warnings.test +++ b/test-data/unit/check-warnings.test @@ -51,7 +51,7 @@ a = 1 if int(): a = 'a' # type: ignore if int(): - a = 2 # type: ignore # E: unused "type: ignore" comment + a = 2 # type: ignore # E: Unused "type: ignore" comment if int(): a = 'b' # E: Incompatible types in assignment (expression has type "str", variable has type "int") @@ -63,8 +63,8 @@ from m import * # type: ignore [file m.py] pass [out] -main:3: error: unused "type: ignore" comment -main:4: error: unused "type: ignore" comment +main:3: error: Unused "type: ignore" comment +main:4: error: Unused "type: ignore" comment -- No return diff --git a/test-data/unit/cmdline.test b/test-data/unit/cmdline.test index 92ef7e0690ed..6fa4d210a826 100644 --- a/test-data/unit/cmdline.test +++ b/test-data/unit/cmdline.test @@ -79,7 +79,7 @@ dir/subdir/b.py:1: error: Name "undef" is not defined [file pkg/__init__.py] [file pkg/a.py] undef -import a +import pkg.a [file pkg/subdir/a.py] undef import pkg.a @@ -306,13 +306,13 @@ mypy.ini: [mypy-*]: Per-module sections should only specify per-module flags (py [file mypy.ini] \[mypy] mypy_path = - foo:bar - , baz -[file foo/foo.pyi] + foo_dir:bar_dir + , baz_dir +[file foo_dir/foo.pyi] def foo(x: int) -> str: ... -[file bar/bar.pyi] +[file bar_dir/bar.pyi] def bar(x: str) -> list: ... -[file baz/baz.pyi] +[file baz_dir/baz.pyi] def baz(x: list) -> dict: ... [file file.py] import no_stubs @@ -642,10 +642,6 @@ reveal_type(a**(-2)) # N: Revealed type is "builtins.float" reveal_type(a**b) # N: Revealed type is "Any" reveal_type(a.__pow__(2)) # N: Revealed type is "builtins.int" reveal_type(a.__pow__(a)) # N: Revealed type is "Any" -a.__pow__() # E: All overload variants of "__pow__" of "int" require at least one argument \ - # N: Possible overload variants: \ - # N: def __pow__(self, Literal[2], Optional[int] = ...) -> int \ - # N: def __pow__(self, int, Optional[int] = ...) -> Any [case testDisallowAnyGenericsBuiltinCollections] # cmd: mypy m.py @@ -791,7 +787,7 @@ c.py:2: error: Argument 1 to "bar" has incompatible type "str"; expected "int" [case testSrcPEP420Packages] # cmd: mypy -p anamespace --namespace-packages [file mypy.ini] -\[mypy]] +\[mypy] mypy_path = src [file src/setup.cfg] [file src/anamespace/foo/__init__.py] @@ -946,7 +942,13 @@ emarg/foo.py:1: error: Name "fail" is not defined emarg/hatch/villip/mankangulisk.py:1: error: Name "fail" is not defined [case testPackageRootEmpty] -# cmd: mypy --package-root= a/b/c.py main.py +# cmd: mypy --no-namespace-packages --package-root= a/b/c.py main.py +[file a/b/c.py] +[file main.py] +import a.b.c + +[case testPackageRootEmptyNamespacePackage] +# cmd: mypy --namespace-packages --package-root= a/b/c.py main.py [file a/b/c.py] [file main.py] import a.b.c @@ -1141,6 +1143,7 @@ import foo.bar 1+'x' [out] src/foo/bar.py: error: Source file found twice under different module names: "src.foo.bar" and "foo.bar" +src/foo/bar.py: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules for more info == Return code: 2 [case testEnableInvalidErrorCode] @@ -1296,9 +1299,69 @@ pkg.py:1: error: "int" not callable 1 + 2 [out] +[case testCmdlineNonInteractiveInstallTypesNoSitePackages] +# cmd: mypy --install-types --non-interactive --no-site-packages -m pkg +[out] +error: --install-types not supported without python executable or site packages +== Return code: 2 + [case testCmdlineInteractiveInstallTypesNothingToDo] # cmd: mypy --install-types -m pkg [file pkg.py] 1() [out] pkg.py:1: error: "int" not callable + +[case testCmdlineExclude] +# cmd: mypy --exclude abc . +[file abc/apkg.py] +1() +[file b/bpkg.py] +1() +[file c/cpkg.py] +1() +[out] +c/cpkg.py:1: error: "int" not callable +b/bpkg.py:1: error: "int" not callable + +[case testCmdlineMultipleExclude] +# cmd: mypy --exclude abc --exclude b/ . +[file abc/apkg.py] +1() +[file b/bpkg.py] +1() +[file c/cpkg.py] +1() +[out] +c/cpkg.py:1: error: "int" not callable + +[case testCmdlineCfgExclude] +# cmd: mypy . +[file mypy.ini] +\[mypy] +exclude = abc +[file abc/apkg.py] +1() +[file b/bpkg.py] +1() +[file c/cpkg.py] +1() +[out] +c/cpkg.py:1: error: "int" not callable +b/bpkg.py:1: error: "int" not callable + +[case testCmdlineCfgMultipleExclude] +# cmd: mypy . +[file mypy.ini] +\[mypy] +exclude = + abc + b +[file abc/apkg.py] +1() +[file b/bpkg.py] +1() +[file c/cpkg.py] +1() +[out] +c/cpkg.py:1: error: "int" not callable diff --git a/test-data/unit/daemon.test b/test-data/unit/daemon.test index 862ae57bc096..c73be05e1be3 100644 --- a/test-data/unit/daemon.test +++ b/test-data/unit/daemon.test @@ -274,7 +274,7 @@ bar.py:3: (str) bar.py:4: (arg=str) $ dmypy suggest foo.foo (str) -> int -$ {python} -c "import shutil; shutil.copy('foo.py.2', 'foo.py')" +$ {python} -c "import shutil; shutil.copy('foo2.py', 'foo.py')" $ dmypy check foo.py bar.py bar.py:3: error: Incompatible types in assignment (expression has type "int", variable has type "str") == Return code: 1 @@ -284,7 +284,7 @@ def foo(arg): class Bar: def bar(self): pass var = 0 -[file foo.py.2] +[file foo2.py] def foo(arg: str) -> int: return 12 class Bar: diff --git a/test-data/unit/deps-expressions.test b/test-data/unit/deps-expressions.test index dccae38de300..20d727433193 100644 --- a/test-data/unit/deps-expressions.test +++ b/test-data/unit/deps-expressions.test @@ -191,7 +191,7 @@ def g(a: A) -> int: -> m.g -> m.g -[case testIndexExpr] +[case testIndexExpr2] class A: def __getitem__(self, x: int) -> int: pass diff --git a/test-data/unit/diff.test b/test-data/unit/diff.test index ee3519478c45..7369ea247e26 100644 --- a/test-data/unit/diff.test +++ b/test-data/unit/diff.test @@ -1470,3 +1470,17 @@ x: Union[Callable[[Arg(int, 'y')], None], [builtins fixtures/tuple.pyi] [out] __main__.x + +[case testChangeParamSpec] +from typing import ParamSpec, TypeVar +A = ParamSpec('A') +B = ParamSpec('B') +C = TypeVar('C') +[file next.py] +from typing import ParamSpec, TypeVar +A = ParamSpec('A') +B = TypeVar('B') +C = ParamSpec('C') +[out] +__main__.B +__main__.C diff --git a/test-data/unit/fine-grained-blockers.test b/test-data/unit/fine-grained-blockers.test index ed7ed5783c79..66a68115afa5 100644 --- a/test-data/unit/fine-grained-blockers.test +++ b/test-data/unit/fine-grained-blockers.test @@ -156,7 +156,7 @@ class C: a.py:1: error: invalid syntax == main:5: error: Missing positional argument "x" in call to "f" of "C" -[out version>=3.10] +[out version==3.10.0] == a.py:1: error: invalid syntax. Perhaps you forgot a comma? == @@ -176,7 +176,7 @@ main:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missin a.py:1: error: invalid syntax == main:2: error: Too many arguments for "f" -[out version>=3.10] +[out version==3.10.0] main:1: error: Cannot find implementation or library stub for module named "a" main:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports == @@ -259,7 +259,7 @@ a.py:1: error: invalid syntax a.py:1: error: invalid syntax == a.py:2: error: Missing positional argument "x" in call to "f" -[out version>=3.10] +[out version==3.10.0] == a.py:1: error: invalid syntax. Perhaps you forgot a comma? == @@ -330,7 +330,7 @@ a.py:1: error: invalid syntax main:1: error: Cannot find implementation or library stub for module named "a" main:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports b.py:1: error: Cannot find implementation or library stub for module named "a" -[out version>=3.10] +[out version==3.10.0] == a.py:1: error: invalid syntax. Perhaps you forgot a comma? == @@ -338,7 +338,7 @@ main:1: error: Cannot find implementation or library stub for module named "a" main:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports b.py:1: error: Cannot find implementation or library stub for module named "a" -[case testDeleteFileWithBlockingError-only_when_cache] +[case testDeleteFileWithBlockingError2-only_when_cache] -- Different cache/no-cache tests because: -- Error message ordering differs import a @@ -358,7 +358,7 @@ a.py:1: error: invalid syntax b.py:1: error: Cannot find implementation or library stub for module named "a" b.py:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports main:1: error: Cannot find implementation or library stub for module named "a" -[out version>=3.10] +[out version==3.10.0] == a.py:1: error: invalid syntax. Perhaps you forgot a comma? == @@ -388,7 +388,7 @@ a.py:1: error: invalid syntax == b.py:2: error: Module has no attribute "f" b.py:3: error: "int" not callable -[out version>=3.10] +[out version==3.10.0] == a.py:1: error: invalid syntax. Perhaps you forgot a comma? == @@ -411,7 +411,7 @@ def f() -> None: pass /test-data/unit/lib-stub/blocker.pyi:2: error: invalid syntax == a.py:1: error: "int" not callable -[out version>=3.10] +[out version==3.10.0] == /test-data/unit/lib-stub/blocker.pyi:2: error: invalid syntax. Perhaps you forgot a comma? == @@ -490,7 +490,7 @@ a.py:1: error: invalid syntax /test-data/unit/lib-stub/blocker.pyi:2: error: invalid syntax == a.py:2: error: "int" not callable -[out version>=3.10] +[out version==3.10.0] == a.py:1: error: invalid syntax. Perhaps you forgot a comma? == @@ -515,13 +515,13 @@ a.py:1: error: invalid syntax == b.py:2: error: Incompatible return value type (got "str", expected "int") == -[out version>=3.10] +[out version==3.10.0] a.py:1: error: invalid syntax. Perhaps you forgot a comma? == b.py:2: error: Incompatible return value type (got "str", expected "int") == -[case testDecodeErrorBlocker-posix] +[case testDecodeErrorBlocker1-posix] import a a.f(1) [file a.py] @@ -537,7 +537,7 @@ mypy: can't decode file 'tmp/a.py': 'ascii' codec can't decode byte 0xc3 in posi == main:2: error: Argument 1 to "f" has incompatible type "int"; expected "str" -[case testDecodeErrorBlocker-windows] +[case testDecodeErrorBlocker2-windows] import a a.f(1) [file a.py] diff --git a/test-data/unit/fine-grained-follow-imports.test b/test-data/unit/fine-grained-follow-imports.test index 1bb62adbe552..b4767ea1a94d 100644 --- a/test-data/unit/fine-grained-follow-imports.test +++ b/test-data/unit/fine-grained-follow-imports.test @@ -418,8 +418,7 @@ def f(x: str) -> None: pass [file p/m.py.3] def f(x: str) -> None: pass -[delete p/m.py.4] -[delete p/__init__.py.4] +[delete p.4] [out] == @@ -429,7 +428,7 @@ main.py:3: error: Missing positional argument "x" in call to "f" main.py:3: error: Missing positional argument "x" in call to "f" == -[case testFollowImportsNormalPackage-only_when_cache] +[case testFollowImportsNormalPackage2-only_when_cache] # flags: --follow-imports=normal # cmd: mypy main.py @@ -445,8 +444,7 @@ def f(x: str) -> None: pass 1() -[delete p/m.py.3] -[delete p/__init__.py.3] +[delete p.3] [out] == @@ -638,6 +636,7 @@ import p2.m2 p1/m1.py:1: error: "int" not callable main.py:2: error: Cannot find implementation or library stub for module named "p2.m2" main.py:2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports +main.py:2: error: Cannot find implementation or library stub for module named "p2" == p2/m2.py:1: error: "str" not callable p1/m1.py:1: error: "int" not callable @@ -682,7 +681,7 @@ import bar src/bar.py:1: error: "int" not callable src/foo.py:2: error: "str" not callable -[case testFollowImportsNormalSearchPathUpdate-only_when_cache] +[case testFollowImportsNormalSearchPathUpdate2-only_when_cache] # flags: --follow-imports=normal # cmd: mypy main.py # cmd2: mypy main.py src/foo.py diff --git a/test-data/unit/fine-grained-modules.test b/test-data/unit/fine-grained-modules.test index 8d5b918dbbab..856eaaad083c 100644 --- a/test-data/unit/fine-grained-modules.test +++ b/test-data/unit/fine-grained-modules.test @@ -410,7 +410,7 @@ main:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missin -- TODO: Fix this bug. It is a real bug that was been papered over -- by the test harness. -[case testDeletionOfSubmoduleTriggersImportFrom1-only_when_cache-skip] +[case testDeletionOfSubmoduleTriggersImportFrom1_2-only_when_cache-skip] -- Different cache/no-cache tests because: -- missing module error message mismatch from p import q @@ -854,8 +854,7 @@ p.f(1) from p.a import f [file p/a.py] def f(x: str) -> None: pass -[delete p/__init__.py.2] -[delete p/a.py.2] +[delete p.2] [out] main:2: error: Argument 1 to "f" has incompatible type "int"; expected "str" == @@ -870,7 +869,7 @@ p.a.f(1) [file p/a.py] def f(x: str) -> None: pass [delete p/a.py.2] -[delete p/__init__.py.3] +[delete p.3] [builtins fixtures/module.pyi] [out] main:3: error: Argument 1 to "f" has incompatible type "int"; expected "str" @@ -884,28 +883,30 @@ main:2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missin main:2: error: Cannot find implementation or library stub for module named "p" [case testDeletePackage4] +# flags: --no-namespace-packages import p.a p.a.f(1) [file p/a.py] def f(x: str) -> None: pass [file p/__init__.py] [delete p/__init__.py.2] -[delete p/a.py.3] +[delete p.3] [out] -main:2: error: Argument 1 to "f" has incompatible type "int"; expected "str" +main:3: error: Argument 1 to "f" has incompatible type "int"; expected "str" == -main:1: error: Cannot find implementation or library stub for module named "p.a" -main:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports -main:1: error: Cannot find implementation or library stub for module named "p" +main:2: error: Cannot find implementation or library stub for module named "p.a" +main:2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports +main:2: error: Cannot find implementation or library stub for module named "p" == -main:1: error: Cannot find implementation or library stub for module named "p.a" -main:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports -main:1: error: Cannot find implementation or library stub for module named "p" +main:2: error: Cannot find implementation or library stub for module named "p.a" +main:2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports +main:2: error: Cannot find implementation or library stub for module named "p" [case testDeletePackage5] -# cmd1: mypy main p/a.py p/__init__.py -# cmd2: mypy main p/a.py -# cmd3: mypy main +# flags: --no-namespace-packages +# cmd1: mypy -m main -m p.a -m p.__init__ +# cmd2: mypy -m main -m p.a +# cmd3: mypy -m main import p.a p.a.f(1) @@ -913,23 +914,24 @@ p.a.f(1) def f(x: str) -> None: pass [file p/__init__.py] [delete p/__init__.py.2] -[delete p/a.py.3] +[delete p.3] [out] -main:6: error: Argument 1 to "f" has incompatible type "int"; expected "str" +main:7: error: Argument 1 to "f" has incompatible type "int"; expected "str" == -main:5: error: Cannot find implementation or library stub for module named "p.a" -main:5: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports -main:5: error: Cannot find implementation or library stub for module named "p" +main:6: error: Cannot find implementation or library stub for module named "p.a" +main:6: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports +main:6: error: Cannot find implementation or library stub for module named "p" == -main:5: error: Cannot find implementation or library stub for module named "p.a" -main:5: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports -main:5: error: Cannot find implementation or library stub for module named "p" +main:6: error: Cannot find implementation or library stub for module named "p.a" +main:6: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports +main:6: error: Cannot find implementation or library stub for module named "p" [case testDeletePackage6] -# cmd1: mypy p/a.py p/b.py p/__init__.py -# cmd2: mypy p/a.py p/b.py -# cmd3: mypy p/a.py p/b.py +# flags: --no-namespace-packages +# cmd1: mypy -m p.a -m p.b -m p.__init__ +# cmd2: mypy -m p.a -m p.b +# cmd3: mypy -m p.a -m p.b [file p/a.py] def f(x: str) -> None: pass [file p/b.py] @@ -1750,7 +1752,7 @@ class Foo: == a.py:3: error: Argument 1 to "foo" of "Foo" has incompatible type "int"; expected "str" -[case testAddAndUseClass4] +[case testAddAndUseClass4_2] [file a.py] [file a.py.2] from p.b import * diff --git a/test-data/unit/fine-grained.test b/test-data/unit/fine-grained.test index 28f0260ccce3..ad67ff19dfd2 100644 --- a/test-data/unit/fine-grained.test +++ b/test-data/unit/fine-grained.test @@ -361,7 +361,7 @@ n.py:2: error: "A" has no attribute "g" == n.py:2: error: "A" has no attribute "g" -[case testContinueToReportErrorAtTopLevel-only_when_cache] +[case testContinueToReportErrorAtTopLevel2-only_when_cache] -- Different cache/no-cache tests because: -- Error message ordering differs import n @@ -4922,7 +4922,7 @@ class D(Generic[T]): pass [out] == -a.py:3: error: Type argument "c.A" of "D" must be a subtype of "c.B" +a.py:3: error: Type argument "A" of "D" must be a subtype of "B" [case testTypeVarValuesRuntime] from mod import I, S, D @@ -7171,7 +7171,7 @@ main:4: note: def f(self, arg: int) -> int main:4: note: @overload main:4: note: def f(self, arg: str) -> str -[case testOverloadedMethodSupertype-only_when_nocache] +[case testOverloadedMethodSupertype2-only_when_nocache] -- Different cache/no-cache tests because -- CallableType.def_extras.first_arg differs ("self"/None) from typing import overload, Any @@ -7241,9 +7241,9 @@ class C: [out] == a.py:2: error: No overload variant of "B" matches argument type "int" -a.py:2: note: Possible overload variant: +a.py:2: note: Possible overload variants: a.py:2: note: def __init__(self, x: str) -> B -a.py:2: note: <1 more non-matching overload not shown> +a.py:2: note: def __init__(self, x: str, y: int) -> B [case testOverloadedToNormalMethodMetaclass] import a @@ -8411,7 +8411,7 @@ a.py:3: note: def meth(self, x: str) -> str a.py:3: note: Subclass: a.py:3: note: def meth(self) -> None -[case testFinalBodyReprocessedAndStillFinalOverloaded-only_when_nocache] +[case testFinalBodyReprocessedAndStillFinalOverloaded2-only_when_nocache] -- Different cache/no-cache tests because -- CallableType.def_extras.first_arg differs ("self"/None) import a @@ -9733,3 +9733,28 @@ class C: [out] == main:5: error: Unsupported left operand type for + ("str") +[case testNoneAttribute] +from typing import Generic, TypeVar + +T = TypeVar('T', int, str) + +class ExampleClass(Generic[T]): + def __init__( + self + ) -> None: + self.example_attribute = None +[out] +== +[case testStrictNoneAttribute] +# flags: --strict-optional +from typing import Generic, TypeVar + +T = TypeVar('T', int, str) + +class ExampleClass(Generic[T]): + def __init__( + self + ) -> None: + self.example_attribute = None +[out] +== diff --git a/test-data/unit/fixtures/__init_subclass__.pyi b/test-data/unit/fixtures/__init_subclass__.pyi index 79fd04fd964e..c5a17f60688e 100644 --- a/test-data/unit/fixtures/__init_subclass__.pyi +++ b/test-data/unit/fixtures/__init_subclass__.pyi @@ -1,5 +1,7 @@ # builtins stub with object.__init_subclass__ +from typing import Mapping, Iterable # needed for ArgumentInferContext + class object: def __init_subclass__(cls) -> None: pass diff --git a/test-data/unit/fixtures/alias.pyi b/test-data/unit/fixtures/alias.pyi index 5909cb616794..08b145f4efd1 100644 --- a/test-data/unit/fixtures/alias.pyi +++ b/test-data/unit/fixtures/alias.pyi @@ -1,5 +1,7 @@ # Builtins test fixture with a type alias 'bytes' +from typing import Mapping, Iterable # needed for `ArgumentInferContext` + class object: def __init__(self) -> None: pass class type: diff --git a/test-data/unit/fixtures/args.pyi b/test-data/unit/fixtures/args.pyi index 2ee8736a154c..ffe54375f68e 100644 --- a/test-data/unit/fixtures/args.pyi +++ b/test-data/unit/fixtures/args.pyi @@ -20,9 +20,9 @@ class type: class tuple(Iterable[Tco], Generic[Tco]): pass -class dict(Iterable[T], Mapping[T, S], Generic[T, S]): pass +class dict(Mapping[T, S], Generic[T, S]): pass -class list(Generic[T], Sequence[T]): pass +class list(Sequence[T], Generic[T]): pass class int: def __eq__(self, o: object) -> bool: pass diff --git a/test-data/unit/fixtures/bool.pyi b/test-data/unit/fixtures/bool.pyi index ca2564dabafd..245526d78907 100644 --- a/test-data/unit/fixtures/bool.pyi +++ b/test-data/unit/fixtures/bool.pyi @@ -17,3 +17,4 @@ class str: pass class unicode: pass class ellipsis: pass class list: pass +class property: pass diff --git a/test-data/unit/fixtures/callable.pyi b/test-data/unit/fixtures/callable.pyi index 7d4757df4bf5..4ad72bee93ec 100644 --- a/test-data/unit/fixtures/callable.pyi +++ b/test-data/unit/fixtures/callable.pyi @@ -10,6 +10,8 @@ class type: class tuple(Generic[T]): pass +class classmethod: pass +class staticmethod: pass class function: pass def isinstance(x: object, t: Union[type, Tuple[type, ...]]) -> bool: pass diff --git a/test-data/unit/fixtures/dict.pyi b/test-data/unit/fixtures/dict.pyi index ab8127badd4c..fd509de8a6c2 100644 --- a/test-data/unit/fixtures/dict.pyi +++ b/test-data/unit/fixtures/dict.pyi @@ -48,8 +48,12 @@ class list(Sequence[T]): # needed by some test cases class tuple(Generic[T]): pass class function: pass class float: pass +class complex: pass class bool(int): pass -class ellipsis: pass +class ellipsis: + __class__: object def isinstance(x: object, t: Union[type, Tuple[type, ...]]) -> bool: pass class BaseException: pass + +def iter(__iterable: Iterable[T]) -> Iterator[T]: pass diff --git a/test-data/unit/fixtures/floatdict.pyi b/test-data/unit/fixtures/floatdict.pyi index 7d2f55a6f6dd..7baa7ca9206f 100644 --- a/test-data/unit/fixtures/floatdict.pyi +++ b/test-data/unit/fixtures/floatdict.pyi @@ -36,7 +36,7 @@ class list(Iterable[T], Generic[T]): def append(self, x: T) -> None: pass def extend(self, x: Iterable[T]) -> None: pass -class dict(Iterable[KT], Mapping[KT, VT], Generic[KT, VT]): +class dict(Mapping[KT, VT], Generic[KT, VT]): @overload def __init__(self, **kwargs: VT) -> None: pass @overload diff --git a/test-data/unit/fixtures/floatdict_python2.pyi b/test-data/unit/fixtures/floatdict_python2.pyi index aa22c5464d6b..f177355d5d4b 100644 --- a/test-data/unit/fixtures/floatdict_python2.pyi +++ b/test-data/unit/fixtures/floatdict_python2.pyi @@ -36,7 +36,7 @@ class list(Iterable[T], Generic[T]): def append(self, x: T) -> None: pass def extend(self, x: Iterable[T]) -> None: pass -class dict(Iterable[KT], Mapping[KT, VT], Generic[KT, VT]): +class dict(Mapping[KT, VT], Generic[KT, VT]): @overload def __init__(self, **kwargs: VT) -> None: pass @overload diff --git a/test-data/unit/fixtures/typing-namedtuple.pyi b/test-data/unit/fixtures/typing-namedtuple.pyi new file mode 100644 index 000000000000..3404dc69de44 --- /dev/null +++ b/test-data/unit/fixtures/typing-namedtuple.pyi @@ -0,0 +1,18 @@ +TypeVar = 0 +Generic = 0 +Any = 0 +overload = 0 +Type = 0 +Literal = 0 + +T_co = TypeVar('T_co', covariant=True) +KT = TypeVar('KT') + +class Iterable(Generic[T_co]): pass +class Iterator(Iterable[T_co]): pass +class Sequence(Iterable[T_co]): pass +class Mapping(Iterable[KT], Generic[KT, T_co]): pass + +class Tuple(Sequence): pass +class NamedTuple(Tuple): + name: str diff --git a/test-data/unit/fixtures/typing-typeddict.pyi b/test-data/unit/fixtures/typing-typeddict.pyi index f460a7bfd167..72f500707094 100644 --- a/test-data/unit/fixtures/typing-typeddict.pyi +++ b/test-data/unit/fixtures/typing-typeddict.pyi @@ -23,6 +23,8 @@ Final = 0 Literal = 0 TypedDict = 0 NoReturn = 0 +Required = 0 +NotRequired = 0 T = TypeVar('T') T_co = TypeVar('T_co', covariant=True) diff --git a/test-data/unit/hacks.txt b/test-data/unit/hacks.txt index 501a722fa359..43114a8af004 100644 --- a/test-data/unit/hacks.txt +++ b/test-data/unit/hacks.txt @@ -39,7 +39,7 @@ y = '' # This could be valid if a new 'y' is defined here ``` Note that some of the checks may turn out to be redundant, as the -exact rules for what constitues a redefinition are still up for +exact rules for what constitutes a redefinition are still up for debate. This is okay since the extra if statements generally don't otherwise affect semantics. diff --git a/test-data/unit/lib-stub/typing.pyi b/test-data/unit/lib-stub/typing.pyi index 2f42633843e0..b9f1752aee1b 100644 --- a/test-data/unit/lib-stub/typing.pyi +++ b/test-data/unit/lib-stub/typing.pyi @@ -43,6 +43,7 @@ class Generator(Iterator[T], Generic[T, U, V]): class Sequence(Iterable[T_co]): def __getitem__(self, n: Any) -> T_co: pass -class Mapping(Generic[T, T_co]): pass +# Mapping type is oversimplified intentionally. +class Mapping(Iterable[T], Generic[T, T_co]): pass def final(meth: T) -> T: pass diff --git a/test-data/unit/lib-stub/typing_extensions.pyi b/test-data/unit/lib-stub/typing_extensions.pyi index 478e5dc1b283..5b32449e71cf 100644 --- a/test-data/unit/lib-stub/typing_extensions.pyi +++ b/test-data/unit/lib-stub/typing_extensions.pyi @@ -24,6 +24,8 @@ Annotated: _SpecialForm = ... ParamSpec: _SpecialForm Concatenate: _SpecialForm +TypeAlias: _SpecialForm + TypeGuard: _SpecialForm # Fallback type for all typed dicts (does not exist at runtime). diff --git a/test-data/unit/parse-errors.test b/test-data/unit/parse-errors.test index a0b7a037a082..9123ce0cf509 100644 --- a/test-data/unit/parse-errors.test +++ b/test-data/unit/parse-errors.test @@ -295,7 +295,7 @@ file:1: error: invalid syntax [out] file:1: error: invalid syntax -[case testInvalidConditionInConditionalExpression2] +[case testInvalidConditionInConditionalExpression3] 1 if x else for y in z [out] file:1: error: invalid syntax diff --git a/test-data/unit/parse.test b/test-data/unit/parse.test index 22b1ab28481d..ff892ce0ce05 100644 --- a/test-data/unit/parse.test +++ b/test-data/unit/parse.test @@ -935,7 +935,7 @@ MypyFile:1( x not y [out] main:1: error: invalid syntax -[out version>=3.10] +[out version==3.10.0] main:1: error: invalid syntax. Perhaps you forgot a comma? [case testNotIs] @@ -946,9 +946,24 @@ x not is y # E: invalid syntax 1 ~ 2 [out] main:1: error: invalid syntax -[out version>=3.10] +[out version==3.10.0] main:1: error: invalid syntax. Perhaps you forgot a comma? +[case testSliceInList39] +# flags: --python-version 3.9 +x = [1, 2][1:2] +[out] +MypyFile:1( + AssignmentStmt:2( + NameExpr(x) + IndexExpr:2( + ListExpr:2( + IntExpr(1) + IntExpr(2)) + SliceExpr:2( + IntExpr(1) + IntExpr(2))))) + [case testDictionaryExpression] {} {1:x} @@ -3108,7 +3123,7 @@ MypyFile:1( NameExpr(x) NameExpr(y))))) -[case testConditionalExpressionInListComprehension] +[case testConditionalExpressionInListComprehension2] a = [ 1 if x else 2 for x in y ] [out] MypyFile:1( @@ -3314,7 +3329,7 @@ MypyFile:1() [out] MypyFile:1() -[case testLatinUnixEncoding] +[case testLatinUnixEncoding2] # coding: iso-latin-1 [out] MypyFile:1() diff --git a/test-data/unit/pep561.test b/test-data/unit/pep561.test index 033d0c52c5ae..839ca110b94c 100644 --- a/test-data/unit/pep561.test +++ b/test-data/unit/pep561.test @@ -119,10 +119,10 @@ reveal_type(a) testTypedPkgSimpleEditableEgg.py:5: note: Revealed type is "builtins.tuple[builtins.str]" [case testTypedPkgNamespaceImportFrom] -# pkgs: typedpkg, typedpkg_ns +# pkgs: typedpkg, typedpkg_ns_a from typedpkg.pkg.aaa import af -from typedpkg_ns.ns.bbb import bf -from typedpkg_ns.ns.dne import dne +from typedpkg_ns.a.bbb import bf +from typedpkg_ns.a.dne import dne af("abc") bf(False) @@ -132,16 +132,16 @@ af(False) bf(2) dne("abc") [out] -testTypedPkgNamespaceImportFrom.py:4: error: Cannot find implementation or library stub for module named "typedpkg_ns.ns.dne" +testTypedPkgNamespaceImportFrom.py:4: error: Cannot find implementation or library stub for module named "typedpkg_ns.a.dne" testTypedPkgNamespaceImportFrom.py:4: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports testTypedPkgNamespaceImportFrom.py:10: error: Argument 1 to "af" has incompatible type "bool"; expected "str" testTypedPkgNamespaceImportFrom.py:11: error: Argument 1 to "bf" has incompatible type "int"; expected "bool" [case testTypedPkgNamespaceImportAs] -# pkgs: typedpkg, typedpkg_ns +# pkgs: typedpkg, typedpkg_ns_a import typedpkg.pkg.aaa as nm; af = nm.af -import typedpkg_ns.ns.bbb as am; bf = am.bf -from typedpkg_ns.ns.dne import dne +import typedpkg_ns.a.bbb as am; bf = am.bf +from typedpkg_ns.a.dne import dne af("abc") bf(False) @@ -151,16 +151,16 @@ af(False) bf(2) dne("abc") [out] -testTypedPkgNamespaceImportAs.py:4: error: Cannot find implementation or library stub for module named "typedpkg_ns.ns.dne" +testTypedPkgNamespaceImportAs.py:4: error: Cannot find implementation or library stub for module named "typedpkg_ns.a.dne" testTypedPkgNamespaceImportAs.py:4: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports testTypedPkgNamespaceImportAs.py:10: error: Argument 1 has incompatible type "bool"; expected "str" testTypedPkgNamespaceImportAs.py:11: error: Argument 1 has incompatible type "int"; expected "bool" [case testTypedPkgNamespaceRegImport] -# pkgs: typedpkg, typedpkg_ns +# pkgs: typedpkg, typedpkg_ns_a import typedpkg.pkg.aaa; af = typedpkg.pkg.aaa.af -import typedpkg_ns.ns.bbb; bf = typedpkg_ns.ns.bbb.bf -from typedpkg_ns.ns.dne import dne +import typedpkg_ns.a.bbb; bf = typedpkg_ns.a.bbb.bf +from typedpkg_ns.a.dne import dne af("abc") bf(False) @@ -171,7 +171,7 @@ bf(2) dne("abc") [out] -testTypedPkgNamespaceRegImport.py:4: error: Cannot find implementation or library stub for module named "typedpkg_ns.ns.dne" +testTypedPkgNamespaceRegImport.py:4: error: Cannot find implementation or library stub for module named "typedpkg_ns.a.dne" testTypedPkgNamespaceRegImport.py:4: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports testTypedPkgNamespaceRegImport.py:10: error: Argument 1 has incompatible type "bool"; expected "str" testTypedPkgNamespaceRegImport.py:11: error: Argument 1 has incompatible type "int"; expected "bool" @@ -188,9 +188,37 @@ import a a.py:1: error: Unsupported operand types for + ("int" and "str") [case testTypedPkgNamespaceRegFromImportTwice] -# pkgs: typedpkg_ns -from typedpkg_ns import ns +# pkgs: typedpkg_ns_a +from typedpkg_ns import a -- dummy should trigger a second iteration [file dummy.py.2] [out] [out2] + +[case testNamespacePkgWStubs] +# pkgs: typedpkg_ns_a, typedpkg_ns_b, typedpkg_ns_b-stubs +# flags: --no-namespace-packages +import typedpkg_ns.a.bbb as a +import typedpkg_ns.b.bbb as b +a.bf(False) +b.bf(False) +a.bf(1) +b.bf(1) +[out] +testNamespacePkgWStubs.py:4: error: Skipping analyzing "typedpkg_ns.b.bbb": module is installed, but missing library stubs or py.typed marker +testNamespacePkgWStubs.py:4: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports +testNamespacePkgWStubs.py:4: error: Skipping analyzing "typedpkg_ns.b": module is installed, but missing library stubs or py.typed marker +testNamespacePkgWStubs.py:7: error: Argument 1 to "bf" has incompatible type "int"; expected "bool" + +[case testNamespacePkgWStubsWithNamespacePackagesFlag] +# pkgs: typedpkg_ns_a, typedpkg_ns_b, typedpkg_ns_b-stubs +# flags: --namespace-packages +import typedpkg_ns.a.bbb as a +import typedpkg_ns.b.bbb as b +a.bf(False) +b.bf(False) +a.bf(1) +b.bf(1) +[out] +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" diff --git a/test-data/unit/plugins/arg_kinds.py b/test-data/unit/plugins/arg_kinds.py index e2fc94a7ba51..5392e64c4f11 100644 --- a/test-data/unit/plugins/arg_kinds.py +++ b/test-data/unit/plugins/arg_kinds.py @@ -1,7 +1,4 @@ -import sys from typing import Optional, Callable - -from mypy.nodes import Context from mypy.plugin import Plugin, MethodContext, FunctionContext from mypy.types import Type diff --git a/test-data/unit/plugins/common_api_incremental.py b/test-data/unit/plugins/common_api_incremental.py index 070bc61ceb3f..2dcd559777ec 100644 --- a/test-data/unit/plugins/common_api_incremental.py +++ b/test-data/unit/plugins/common_api_incremental.py @@ -24,7 +24,7 @@ def add_info_hook(ctx) -> None: info = TypeInfo(SymbolTable(), class_def, ctx.api.cur_mod_id) class_def.info = info - obj = ctx.api.builtin_type('builtins.object') + obj = ctx.api.named_type('builtins.object') info.mro = [info, obj.type] info.bases = [obj] ctx.api.add_symbol_table_node(ctx.name, SymbolTableNode(GDEF, info)) diff --git a/test-data/unit/plugins/decimal_to_int.py b/test-data/unit/plugins/decimal_to_int.py index 98e747ed74c0..21fd3b518b7d 100644 --- a/test-data/unit/plugins/decimal_to_int.py +++ b/test-data/unit/plugins/decimal_to_int.py @@ -1,8 +1,5 @@ -import builtins -from typing import Optional, Callable -from mypy.plugin import Plugin, AnalyzeTypeContext -from mypy.types import CallableType, Type +from mypy.plugin import Plugin class MyPlugin(Plugin): diff --git a/test-data/unit/plugins/depshook.py b/test-data/unit/plugins/depshook.py index 037e2861e4dc..76277f3cb82b 100644 --- a/test-data/unit/plugins/depshook.py +++ b/test-data/unit/plugins/depshook.py @@ -1,4 +1,4 @@ -from typing import Optional, Callable, List, Tuple +from typing import List, Tuple from mypy.plugin import Plugin from mypy.nodes import MypyFile diff --git a/test-data/unit/plugins/dyn_class.py b/test-data/unit/plugins/dyn_class.py index 56ef89e17869..54bf377aa8ef 100644 --- a/test-data/unit/plugins/dyn_class.py +++ b/test-data/unit/plugins/dyn_class.py @@ -23,7 +23,7 @@ def add_info_hook(ctx): info = TypeInfo(SymbolTable(), class_def, ctx.api.cur_mod_id) class_def.info = info - obj = ctx.api.builtin_type('builtins.object') + obj = ctx.api.named_type('builtins.object') info.mro = [info, obj.type] info.bases = [obj] ctx.api.add_symbol_table_node(ctx.name, SymbolTableNode(GDEF, info)) diff --git a/test-data/unit/plugins/dyn_class_from_method.py b/test-data/unit/plugins/dyn_class_from_method.py index 8a18f7f1e8e1..4c3904907750 100644 --- a/test-data/unit/plugins/dyn_class_from_method.py +++ b/test-data/unit/plugins/dyn_class_from_method.py @@ -18,7 +18,7 @@ def add_info_hook(ctx: DynamicClassDefContext): class_def.info = info queryset_type_fullname = ctx.call.args[0].fullname queryset_info = ctx.api.lookup_fully_qualified_or_none(queryset_type_fullname).node # type: TypeInfo - obj = ctx.api.builtin_type('builtins.object') + obj = ctx.api.named_type('builtins.object') info.mro = [info, queryset_info, obj.type] info.bases = [Instance(queryset_info, [])] ctx.api.add_symbol_table_node(ctx.name, SymbolTableNode(GDEF, info)) diff --git a/test-data/unit/plugins/type_anal_hook.py b/test-data/unit/plugins/type_anal_hook.py index 66b24bcf323d..86d18d8c8611 100644 --- a/test-data/unit/plugins/type_anal_hook.py +++ b/test-data/unit/plugins/type_anal_hook.py @@ -1,7 +1,7 @@ from typing import Optional, Callable from mypy.plugin import Plugin, AnalyzeTypeContext -from mypy.types import Type, UnboundType, TypeList, AnyType, CallableType, TypeOfAny +from mypy.types import Type, TypeList, AnyType, CallableType, TypeOfAny # The official name changed to NoneType but we have an alias for plugin compat reasons # so we'll keep testing that here. from mypy.types import NoneTyp diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 8a7b39756867..90588a86d8bf 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -1085,7 +1085,7 @@ _testTypedDictGet.py:9: note: Revealed type is "builtins.object*" _testTypedDictGet.py:10: error: All overload variants of "get" of "Mapping" require at least one argument _testTypedDictGet.py:10: note: Possible overload variants: _testTypedDictGet.py:10: note: def get(self, key: str) -> object -_testTypedDictGet.py:10: note: def [_T] get(self, key: str, default: object) -> object +_testTypedDictGet.py:10: note: def [_T] get(self, str, object) -> object _testTypedDictGet.py:12: note: Revealed type is "builtins.object*" [case testTypedDictMappingMethods] @@ -1390,6 +1390,32 @@ x = X(a=1, b='s') [out] _testNamedTupleNew.py:12: note: Revealed type is "Tuple[builtins.int, fallback=_testNamedTupleNew.Child]" +[case testNamedTupleTypeInheritanceSpecialCase] +from typing import NamedTuple, Tuple +from collections import namedtuple + +A = NamedTuple('A', [('param', int)]) +B = namedtuple('B', ['param']) + +def accepts_named_tuple(arg: NamedTuple): + reveal_type(arg._asdict()) + reveal_type(arg._fields) + reveal_type(arg._field_defaults) + +a = A(1) +b = B(1) + +accepts_named_tuple(a) +accepts_named_tuple(b) +accepts_named_tuple(1) +accepts_named_tuple((1, 2)) +[out] +_testNamedTupleTypeInheritanceSpecialCase.py:8: note: Revealed type is "collections.OrderedDict[builtins.str, Any]" +_testNamedTupleTypeInheritanceSpecialCase.py:9: note: Revealed type is "builtins.tuple[builtins.str]" +_testNamedTupleTypeInheritanceSpecialCase.py:10: note: Revealed type is "builtins.dict[builtins.str, Any]" +_testNamedTupleTypeInheritanceSpecialCase.py:17: error: Argument 1 to "accepts_named_tuple" has incompatible type "int"; expected "NamedTuple" +_testNamedTupleTypeInheritanceSpecialCase.py:18: error: Argument 1 to "accepts_named_tuple" has incompatible type "Tuple[int, int]"; expected "NamedTuple" + [case testNewAnalyzerBasicTypeshed_newsemanal] from typing import Dict, List, Tuple @@ -1414,7 +1440,7 @@ def thing(stuff: StuffDict) -> int: ... [out] _testNewAnalyzerTypedDictInStub_newsemanal.py:2: note: Revealed type is "def (stuff: TypedDict('stub.StuffDict', {'foo': builtins.str, 'bar': builtins.int})) -> builtins.int" -[case testStrictEqualityWhitelist] +[case testStrictEqualityAllowlist] # mypy: strict-equality {1} == frozenset({1}) frozenset({1}) == {1} @@ -1429,10 +1455,10 @@ frozenset({1}) == [1] # Error {1: 2}.values() == {2} # Error {1: 2}.keys() == [1] # Error [out] -_testStrictEqualityWhitelist.py:5: error: Non-overlapping equality check (left operand type: "FrozenSet[int]", right operand type: "List[int]") -_testStrictEqualityWhitelist.py:11: error: Non-overlapping equality check (left operand type: "KeysView[int]", right operand type: "Set[str]") -_testStrictEqualityWhitelist.py:12: error: Non-overlapping equality check (left operand type: "ValuesView[int]", right operand type: "Set[int]") -_testStrictEqualityWhitelist.py:13: error: Non-overlapping equality check (left operand type: "KeysView[int]", right operand type: "List[int]") +_testStrictEqualityAllowlist.py:5: error: Non-overlapping equality check (left operand type: "FrozenSet[int]", right operand type: "List[int]") +_testStrictEqualityAllowlist.py:11: error: Non-overlapping equality check (left operand type: "dict_keys[int, int]", right operand type: "Set[str]") +_testStrictEqualityAllowlist.py:12: error: Non-overlapping equality check (left operand type: "dict_values[int, int]", right operand type: "Set[int]") +_testStrictEqualityAllowlist.py:13: error: Non-overlapping equality check (left operand type: "dict_keys[int, int]", right operand type: "List[int]") [case testUnreachableWithStdlibContextManagers] # mypy: warn-unreachable, strict-optional @@ -1531,3 +1557,19 @@ _testNoPython3StubAvailable.py:1: note: See https://mypy.readthedocs.io/en/stabl _testNoPython3StubAvailable.py:3: error: Library stubs not installed for "maxminddb" (or incompatible with Python 3.6) _testNoPython3StubAvailable.py:3: note: Hint: "python3 -m pip install types-maxminddb" _testNoPython3StubAvailable.py:3: note: (or run "mypy --install-types" to install all missing stub packages) + + +[case testTypingOrderedDictAlias] +# flags: --python-version 3.7 +from typing import OrderedDict +x: OrderedDict[str, int] = OrderedDict({}) +reveal_type(x) +[out] +_testTypingOrderedDictAlias.py:4: note: Revealed type is "collections.OrderedDict[builtins.str, builtins.int]" + +[case testTypingExtensionsOrderedDictAlias] +from typing_extensions import OrderedDict +x: OrderedDict[str, str] = OrderedDict({}) +reveal_type(x) # Revealed type is "collections.OrderedDict[builtins.str, builtins.int]" +[out] +_testTypingExtensionsOrderedDictAlias.py:3: note: Revealed type is "collections.OrderedDict[builtins.str, builtins.str]" diff --git a/test-data/unit/reports.test b/test-data/unit/reports.test index 5e0da3f07a98..a7ab6d754b2c 100644 --- a/test-data/unit/reports.test +++ b/test-data/unit/reports.test @@ -456,3 +456,41 @@ DisplayToSource = Callable[[int], int] + +[case testHtmlReportOnNamespacePackagesWithExplicitBases] +# cmd: mypy --html-report report -p folder +[file folder/subfolder/something.py] +class Something: + pass +[file folder/main.py] +from .subfolder.something import Something +print(Something()) +[file folder/__init__.py] +[file mypy.ini] +\[mypy] +explicit_package_bases = True +namespace_packages = True + +[file report/mypy-html.css] +[file report/index.html] +[outfile report/html/folder/subfolder/something.py.html] + + + + + + +

folder.subfolder.something

+ + + + + + +
folder/subfolder/something.py
1
+2
+
class Something:
+    pass
+
+ + diff --git a/test-data/unit/semanal-basic.test b/test-data/unit/semanal-basic.test index 22231f067de3..bb829dd9a4c1 100644 --- a/test-data/unit/semanal-basic.test +++ b/test-data/unit/semanal-basic.test @@ -286,7 +286,7 @@ MypyFile:1( NameExpr(x* [l]) NameExpr(None [builtins.None]))))) -[case testGlobalDeclScope] +[case testGlobalDeclScope2] x = None def f(): global x diff --git a/test-data/unit/semanal-classvar.test b/test-data/unit/semanal-classvar.test index 8add559bdd27..a7bcec0324dc 100644 --- a/test-data/unit/semanal-classvar.test +++ b/test-data/unit/semanal-classvar.test @@ -207,3 +207,14 @@ class B: pass [out] main:4: error: ClassVar can only be used for assignments in class body + +[case testClassVarWithTypeVariable] +from typing import ClassVar, TypeVar, Generic, List + +T = TypeVar('T') + +class Some(Generic[T]): + error: ClassVar[T] # E: ClassVar cannot contain type variables + nested: ClassVar[List[List[T]]] # E: ClassVar cannot contain type variables + ok: ClassVar[int] +[out] diff --git a/test-data/unit/semanal-errors.test b/test-data/unit/semanal-errors.test index 9dc75a4930e4..e5aea483a210 100644 --- a/test-data/unit/semanal-errors.test +++ b/test-data/unit/semanal-errors.test @@ -1030,11 +1030,13 @@ a = TypeVar() # E: Too few arguments for TypeVar() b = TypeVar(x='b') # E: TypeVar() expects a string literal as first argument c = TypeVar(1) # E: TypeVar() expects a string literal as first argument d = TypeVar('D') # E: String argument 1 "D" to TypeVar(...) does not match variable name "d" -e = TypeVar('e', int, str, x=1) # E: Unexpected argument to TypeVar(): "x" +e = TypeVar('e', int, str, x=1) # E: Unexpected argument to "TypeVar()": "x" f = TypeVar('f', (int, str), int) # E: Type expected g = TypeVar('g', int) # E: TypeVar cannot have only a single constraint -h = TypeVar('h', x=(int, str)) # E: Unexpected argument to TypeVar(): "x" +h = TypeVar('h', x=(int, str)) # E: Unexpected argument to "TypeVar()": "x" i = TypeVar('i', bound=1) # E: TypeVar "bound" must be a type +j = TypeVar('j', covariant=None) # E: TypeVar "covariant" may only be a literal bool +k = TypeVar('k', contravariant=1) # E: TypeVar "contravariant" may only be a literal bool [out] [case testMoreInvalidTypevarArguments] @@ -1046,7 +1048,7 @@ S = TypeVar('S', covariant=True, contravariant=True) \ [case testInvalidTypevarValues] from typing import TypeVar -b = TypeVar('b', *[int]) # E: Unexpected argument to TypeVar() +b = TypeVar('b', *[int]) # E: Unexpected argument to "TypeVar()" c = TypeVar('c', int, 2) # E: Invalid type: try using Literal[2] instead? [out] diff --git a/test-data/unit/semanal-lambda.test b/test-data/unit/semanal-lambda.test new file mode 100644 index 000000000000..1cde1a794dc2 --- /dev/null +++ b/test-data/unit/semanal-lambda.test @@ -0,0 +1,94 @@ +[case testLambdaInheritsCheckedContextFromFunc] +def g(): + return lambda x: UNDEFINED in x +[out] +MypyFile:1( + FuncDef:1( + g + Block:1( + ReturnStmt:2( + LambdaExpr:2( + Args( + Var(x)) + Block:2( + ReturnStmt:2( + ComparisonExpr:2( + in + NameExpr(UNDEFINED) + NameExpr(x [l]))))))))) + +[case testLambdaInheritsCheckedContextFromFuncForced] +# flags: --check-untyped-defs +def g(): + return lambda x: UNDEFINED in x # E: Name "UNDEFINED" is not defined + +[case testLambdaInheritsCheckedContextFromTypedFunc] +def g() -> None: + return lambda x: UNDEFINED in x # E: Name "UNDEFINED" is not defined + +[case testLambdaInheritsCheckedContextFromTypedFuncForced] +# flags: --check-untyped-defs +def g() -> None: + return lambda x: UNDEFINED in x # E: Name "UNDEFINED" is not defined + +[case testLambdaInheritsCheckedContextFromModule] +g = lambda x: UNDEFINED in x # E: Name "UNDEFINED" is not defined + +[case testLambdaInheritsCheckedContextFromModuleForce] +# flags: --check-untyped-defs +g = lambda x: UNDEFINED in x # E: Name "UNDEFINED" is not defined + +[case testLambdaInheritsCheckedContextFromModuleLambdaStack] +g = lambda: lambda: lambda x: UNDEFINED in x # E: Name "UNDEFINED" is not defined + +[case testLambdaInheritsCheckedContextFromModuleLambdaStackForce] +# flags: --check-untyped-defs +g = lambda: lambda: lambda x: UNDEFINED in x # E: Name "UNDEFINED" is not defined + +[case testLambdaInheritsCheckedContextFromFuncLambdaStack] +def g(): + return lambda: lambda: lambda x: UNDEFINED in x +[out] +MypyFile:1( + FuncDef:1( + g + Block:1( + ReturnStmt:2( + LambdaExpr:2( + Block:2( + ReturnStmt:2( + LambdaExpr:2( + Block:2( + ReturnStmt:2( + LambdaExpr:2( + Args( + Var(x)) + Block:2( + ReturnStmt:2( + ComparisonExpr:2( + in + NameExpr(UNDEFINED) + NameExpr(x [l]))))))))))))))) + +[case testLambdaInheritsCheckedContextFromFuncLambdaStackForce] +# flags: --check-untyped-defs +def g(): + return lambda: lambda: lambda x: UNDEFINED in x # E: Name "UNDEFINED" is not defined + +[case testLambdaInheritsCheckedContextFromTypedFuncLambdaStack] +def g() -> None: + return lambda: lambda: lambda x: UNDEFINED in x # E: Name "UNDEFINED" is not defined + +[case testLambdaInheritsCheckedContextFromTypedFuncLambdaStackForce] +# flags: --check-untyped-defs +def g() -> None: + return lambda: lambda: lambda x: UNDEFINED in x # E: Name "UNDEFINED" is not defined + +[case testLambdaInheritsCheckedContextFromClassLambdaStack] +class A: + g = lambda: lambda: lambda x: UNDEFINED in x # E: Name "UNDEFINED" is not defined + +[case testLambdaInheritsCheckedContextFromClassLambdaStackForce] +# flags: --check-untyped-defs +class A: + g = lambda: lambda: lambda x: UNDEFINED in x # E: Name "UNDEFINED" is not defined diff --git a/test-data/unit/semanal-modules.test b/test-data/unit/semanal-modules.test index d81a81c326de..86bb82d7bd69 100644 --- a/test-data/unit/semanal-modules.test +++ b/test-data/unit/semanal-modules.test @@ -206,7 +206,7 @@ MypyFile:1( NameExpr(_n) x [_n.x]))) -[case testAccessingImportedModule] +[case testAccessingImportedModule2] import _m _m._n.x [file _m.py] @@ -385,7 +385,7 @@ MypyFile:1( NameExpr(None [builtins.None]) m._n.c)) -[case testSubmodulesAndTypes] +[case testSubmodulesAndTypes2] from m._n import c x = None # type: c [file m/__init__.py] diff --git a/test-data/unit/semanal-namedtuple.test b/test-data/unit/semanal-namedtuple.test index e018763e7712..df1d5679c892 100644 --- a/test-data/unit/semanal-namedtuple.test +++ b/test-data/unit/semanal-namedtuple.test @@ -145,39 +145,76 @@ MypyFile:1( [case testNamedTupleWithTooFewArguments] from collections import namedtuple -N = namedtuple('N') # E: Too few arguments for namedtuple() +N = namedtuple('N') # E: Too few arguments for "namedtuple()" [builtins fixtures/tuple.pyi] [case testNamedTupleWithInvalidName] from collections import namedtuple -N = namedtuple(1, ['x']) # E: namedtuple() expects a string literal as the first argument +N = namedtuple(1, ['x']) # E: "namedtuple()" expects a string literal as the first argument [builtins fixtures/tuple.pyi] [case testNamedTupleWithInvalidItems] from collections import namedtuple -N = namedtuple('N', 1) # E: List or tuple literal expected as the second argument to namedtuple() +N = namedtuple('N', 1) # E: List or tuple literal expected as the second argument to "namedtuple()" [builtins fixtures/tuple.pyi] [case testNamedTupleWithInvalidItems2] from collections import namedtuple -N = namedtuple('N', ['x', 1]) # E: String literal expected as namedtuple() item +N = namedtuple('N', ['x', 1]) # E: String literal expected as "namedtuple()" item [builtins fixtures/tuple.pyi] [case testNamedTupleWithUnderscoreItemName] from collections import namedtuple -N = namedtuple('N', ['_fallback']) # E: namedtuple() field names cannot start with an underscore: _fallback +N = namedtuple('N', ['_fallback']) # E: "namedtuple()" field names cannot start with an underscore: _fallback [builtins fixtures/tuple.pyi] -- NOTE: The following code works at runtime but is not yet supported by mypy. -- Keyword arguments may potentially be supported in the future. [case testNamedTupleWithNonpositionalArgs] from collections import namedtuple -N = namedtuple(typename='N', field_names=['x']) # E: Unexpected arguments to namedtuple() +N = namedtuple(typename='N', field_names=['x']) # E: Unexpected arguments to "namedtuple()" +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleWithTooFewArguments] +from typing import NamedTuple +N = NamedTuple('N') # E: Too few arguments for "NamedTuple()" +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleWithManyArguments] +from typing import NamedTuple +N = NamedTuple('N', [], []) # E: Too many arguments for "NamedTuple()" +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleWithInvalidName] +from typing import NamedTuple +N = NamedTuple(1, ['x']) # E: "NamedTuple()" expects a string literal as the first argument +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleWithInvalidItems] +from typing import NamedTuple +N = NamedTuple('N', 1) # E: List or tuple literal expected as the second argument to "NamedTuple()" +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleWithUnderscoreItemName] +from typing import NamedTuple +N = NamedTuple('N', [('_fallback', int)]) # E: "NamedTuple()" field names cannot start with an underscore: _fallback +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleWithUnexpectedNames] +from typing import NamedTuple +N = NamedTuple(name='N', fields=[]) # E: Unexpected arguments to "NamedTuple()" +[builtins fixtures/tuple.pyi] + +-- NOTE: The following code works at runtime but is not yet supported by mypy. +-- Keyword arguments may potentially be supported in the future. +[case testNamedTupleWithNonpositionalArgs2] +from collections import namedtuple +N = namedtuple(typename='N', field_names=['x']) # E: Unexpected arguments to "namedtuple()" [builtins fixtures/tuple.pyi] [case testInvalidNamedTupleBaseClass] from typing import NamedTuple -class A(NamedTuple('N', [1])): pass # E: Tuple expected as NamedTuple() field +class A(NamedTuple('N', [1])): pass # E: Tuple expected as "NamedTuple()" field class B(A): pass [builtins fixtures/tuple.pyi] diff --git a/test-data/unit/semanal-types.test b/test-data/unit/semanal-types.test index 67ce14c001a3..772de61b5900 100644 --- a/test-data/unit/semanal-types.test +++ b/test-data/unit/semanal-types.test @@ -1284,6 +1284,35 @@ MypyFile:1( builtins.int builtins.str)))) +[case testTypevarWithFalseVariance] +from typing import TypeVar +T1 = TypeVar('T1', covariant=False) +T2 = TypeVar('T2', covariant=False, contravariant=False) +T3 = TypeVar('T3', contravariant=False) +T4 = TypeVar('T4', covariant=True, contravariant=False) +T5 = TypeVar('T5', covariant=False, contravariant=True) +[builtins fixtures/bool.pyi] +[out] +MypyFile:1( + ImportFrom:1(typing, [TypeVar]) + AssignmentStmt:2( + NameExpr(T1* [__main__.T1]) + TypeVarExpr:2()) + AssignmentStmt:3( + NameExpr(T2* [__main__.T2]) + TypeVarExpr:3()) + AssignmentStmt:4( + NameExpr(T3* [__main__.T3]) + TypeVarExpr:4()) + AssignmentStmt:5( + NameExpr(T4* [__main__.T4]) + TypeVarExpr:5( + Variance(COVARIANT))) + AssignmentStmt:6( + NameExpr(T5* [__main__.T5]) + TypeVarExpr:6( + Variance(CONTRAVARIANT)))) + [case testTypevarWithBound] from typing import TypeVar T = TypeVar('T', bound=int) diff --git a/test-data/unit/stubgen.test b/test-data/unit/stubgen.test index 7d95072800dc..e20073027db2 100644 --- a/test-data/unit/stubgen.test +++ b/test-data/unit/stubgen.test @@ -64,6 +64,25 @@ def g(x: Foo = Foo()) -> Bar: ... def f(x: Foo) -> Bar: ... def g(x: Foo = ...) -> Bar: ... +[case testPreserveFunctionAnnotationWithArgs] +def f(x: foo['x']) -> bar: ... +def g(x: foo[x]) -> bar: ... +def h(x: foo['x', 'y']) -> bar: ... +def i(x: foo[x, y]) -> bar: ... +def j(x: foo['x', y]) -> bar: ... +def k(x: foo[x, 'y']) -> bar: ... +def lit_str(x: Literal['str']) -> Literal['str']: ... +def lit_int(x: Literal[1]) -> Literal[1]: ... +[out] +def f(x: foo['x']) -> bar: ... +def g(x: foo[x]) -> bar: ... +def h(x: foo['x', 'y']) -> bar: ... +def i(x: foo[x, y]) -> bar: ... +def j(x: foo['x', y]) -> bar: ... +def k(x: foo[x, 'y']) -> bar: ... +def lit_str(x: Literal['str']) -> Literal['str']: ... +def lit_int(x: Literal[1]) -> Literal[1]: ... + [case testPreserveVarAnnotation] x: Foo [out] @@ -464,7 +483,7 @@ import re as re x: int -[case testExportModule_import] +[case testExportModule2_import] import re __all__ = ['re', 'x'] x = 1 @@ -682,7 +701,7 @@ import x class D(x.C): ... -[case testArbitraryBaseClass] +[case testArbitraryBaseClass2] import x.y class D(x.y.C): ... [out] @@ -818,7 +837,7 @@ import collections x: collections.defaultdict -[case testAnnotationImports] +[case testAnnotationImports2] from typing import List import collections x: List[collections.defaultdict] diff --git a/test-data/unit/typexport-basic.test b/test-data/unit/typexport-basic.test index deb43f6d316f..7a0115f17e9c 100644 --- a/test-data/unit/typexport-basic.test +++ b/test-data/unit/typexport-basic.test @@ -247,7 +247,7 @@ elif not a: [out] NameExpr(3) : builtins.bool IntExpr(4) : Literal[1]? -NameExpr(5) : builtins.bool +NameExpr(5) : Literal[False] UnaryExpr(5) : builtins.bool IntExpr(6) : Literal[1]? @@ -259,7 +259,7 @@ while a: [builtins fixtures/bool.pyi] [out] NameExpr(3) : builtins.bool -NameExpr(4) : builtins.bool +NameExpr(4) : Literal[True] -- Simple type inference @@ -727,7 +727,7 @@ f = lambda: [1] LambdaExpr(3) : def () -> builtins.list[builtins.int] NameExpr(3) : def () -> builtins.list[builtins.int] -[case testLambdaWithInferredType2] +[case testLambdaWithInferredType3] from typing import List, Callable f = lambda x: [] # type: Callable[[B], List[A]] class A: pass diff --git a/test-requirements.txt b/test-requirements.txt index 93300baaaa8e..c5db79ada816 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,7 +1,7 @@ -r mypy-requirements.txt -r build-requirements.txt attrs>=18.0 -flake8>=3.8.1 +flake8==3.9.2 flake8-bugbear flake8-pyi>=20.5 lxml>=4.4.0 @@ -11,6 +11,7 @@ pytest-xdist>=1.34.0,<2.0.0 pytest-forked>=1.3.0,<2.0.0 pytest-cov>=2.10.0,<3.0.0 py>=1.5.2 +typed_ast>=1.4.0,<2; python_version>='3.8' virtualenv>=20.6.0 setuptools!=50 importlib-metadata>=4.6.1,<5.0.0 diff --git a/tox.ini b/tox.ini index ac7cdc72fdb7..44334688b0ad 100644 --- a/tox.ini +++ b/tox.ini @@ -51,7 +51,7 @@ description = type check ourselves basepython = python3.7 commands = python -m mypy --config-file mypy_self_check.ini -p mypy -p mypyc - python -m mypy --config-file mypy_self_check.ini misc/proper_plugin.py scripts/mypyc + python -m mypy --config-file mypy_self_check.ini misc/proper_plugin.py [testenv:docs] description = invoke sphinx-build to build the HTML docs