diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000000..07f00de06ee4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*.{py,c,cpp,h,rst,md,yml,json,test}] +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space + +[*.{py,c,h,json,test}] +indent_size = 4 + +[*.yml] +indent_size = 2 diff --git a/.gitattributes b/.gitattributes index 13eb5742dbf0..840ba454b8e3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ # We vendor typeshed from https://github.com/python/typeshed -mypy/typeshed/ linguist-vendored +mypy/typeshed/** linguist-vendored diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000000..64a2e6494c1b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,7 @@ +contact_links: + - about: "Please check the linked documentation page before filing new issues." + name: "Common issues and solutions" + url: "https://mypy.readthedocs.io/en/stable/common_issues.html" + - about: "Please ask and answer any questions on the mypy Gitter." + name: "Questions or Chat" + url: "https://gitter.im/python/typing" diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index eccce57a270d..000000000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: Questions and Help -about: If you have questions, please check the below links -labels: "question" ---- - -**Questions and Help** - -_Please note that this issue tracker is not a help form and this issue will be closed._ - -Please check here instead: - -- [Website](http://www.mypy-lang.org/) -- [Documentation](https://mypy.readthedocs.io/) -- [Gitter](https://gitter.im/python/typing) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index d44f9143bdc7..228bdb3bd4ad 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -23,7 +23,7 @@ jobs: with: python-version: '3.7' - 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.24.5 - name: Setup tox environment run: tox -e ${{ env.TOXENV }} --notest - name: Test diff --git a/.github/workflows/mypy_primer.yml b/.github/workflows/mypy_primer.yml index fcd8b938f295..e65d918228b4 100644 --- a/.github/workflows/mypy_primer.yml +++ b/.github/workflows/mypy_primer.yml @@ -8,6 +8,10 @@ on: - '**/*.rst' - '**/*.md' - 'mypyc/**' + - 'mypy/stubtest.py' + - 'mypy/stubgen.py' + - 'mypy/stubgenc.py' + - 'mypy/test/**' jobs: mypy_primer: @@ -26,7 +30,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: "3.10" - name: Install dependencies run: | python -m pip install -U pip diff --git a/.github/workflows/mypy_primer_comment.yml b/.github/workflows/mypy_primer_comment.yml index edc91b190e29..9aa5b7a7131e 100644 --- a/.github/workflows/mypy_primer_comment.yml +++ b/.github/workflows/mypy_primer_comment.yml @@ -38,62 +38,41 @@ jobs: fs.writeFileSync("diff.zip", Buffer.from(download.data)); - run: unzip diff.zip - - # Based on https://github.com/kanga333/comment-hider - - name: Hide old comments - uses: actions/github-script@v3 - with: - github-token: ${{secrets.GITHUB_TOKEN}} - script: | - const fs = require('fs') - - const response = await github.issues.listComments({ - issue_number: fs.readFileSync("pr_number.txt", { encoding: "utf8" }), - owner: context.repo.owner, - repo: context.repo.repo, - }) - const botCommentIds = response.data - .filter(comment => comment.user.login === 'github-actions[bot]') - .map(comment => comment.node_id) - - for (const id of botCommentIds) { - const resp = await github.graphql(` - mutation { - minimizeComment(input: {classifier: OUTDATED, subjectId: "${id}"}) { - minimizedComment { - isMinimized - } - } - } - `) - if (resp.errors) { - throw new Error(resp.errors) - } - } + # 30000 bytes is about 300 lines, posting comment fails if too long + - run: | + cat diff_*.txt | head -c 30000 | tee fulldiff.txt - name: Post comment + id: post-comment uses: actions/github-script@v3 with: - github-token: ${{secrets.GITHUB_TOKEN}} + github-token: ${{ secrets.GITHUB_TOKEN }} script: | const fs = require('fs') - // Keep in sync with shards produced by mypy_primer workflow - const data = ( - ['diff_0.txt', 'diff_1.txt', 'diff_2.txt'] - .map(fileName => fs.readFileSync(fileName, { encoding: 'utf8' })) - .join('') - .substr(0, 30000) // About 300 lines - ) + const data = fs.readFileSync('fulldiff.txt', { encoding: 'utf8' }) console.log("Diff from mypy_primer:") console.log(data) + let body if (data.trim()) { - const body = 'Diff from [mypy_primer](https://github.com/hauntsaninja/mypy_primer), showing the effect of this PR on open source code:\n```diff\n' + data + '```' - await github.issues.createComment({ - issue_number: fs.readFileSync("pr_number.txt", { encoding: "utf8" }), - owner: context.repo.owner, - repo: context.repo.repo, - body - }) + body = 'Diff from [mypy_primer](https://github.com/hauntsaninja/mypy_primer), showing the effect of this PR on open source code:\n```diff\n' + data + '```' + } else { + body = 'According to [mypy_primer](https://github.com/hauntsaninja/mypy_primer), this change has no effect on the checked open source code. πŸ€–πŸŽ‰' } + const prNumber = parseInt(fs.readFileSync("pr_number.txt", { encoding: "utf8" })) + await github.issues.createComment({ + issue_number: prNumber, + owner: context.repo.owner, + repo: context.repo.repo, + body + }) + return prNumber + + - name: Hide old comments + # v0.3.0 + uses: kanga333/comment-hider@bbdf5b562fbec24e6f60572d8f712017428b92e0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + leave_visible: 1 + issue_number: ${{ steps.post-comment.outputs.result }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3081c15594cb..7402a97d7321 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -75,11 +75,16 @@ jobs: toxenv: py36 tox_extra_args: "-n 2 mypyc/test/test_run.py mypyc/test/test_external.py" debug_build: true - - name: Type check our own code + - name: Type check our own code (py37-ubuntu) python: '3.7' arch: x64 os: ubuntu-latest toxenv: type + - name: Type check our own code (py37-windows-64) + python: '3.7' + arch: x64 + os: windows-latest + toxenv: type - name: Code style with flake8 python: '3.7' arch: x64 @@ -102,7 +107,7 @@ jobs: ./misc/build-debug-python.sh $PYTHONVERSION $PYTHONDIR $VENV source $VENV/bin/activate - name: Install tox - run: pip install --upgrade 'setuptools!=50' 'virtualenv>=20.6.0' tox==3.20.1 + run: pip install --upgrade 'setuptools!=50' 'virtualenv>=20.6.0' tox==3.24.5 - name: Compiled with mypyc if: ${{ matrix.test_mypyc }} run: | @@ -113,24 +118,23 @@ jobs: - name: Test run: tox -e ${{ matrix.toxenv }} --skip-pkg-install -- ${{ matrix.tox_extra_args }} -# 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 - +# TODO: re-enable when `typed-ast` will be fixed for `python==3.11` +# 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/CONTRIBUTING.md b/CONTRIBUTING.md index 9e5bdeb90a69..eafefe346d01 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -54,6 +54,12 @@ You can also use `tox` to run tests, for instance: tox -e py ``` +The easiest way to run a single test is: +``` +pytest -n0 -k 'test_name' +``` +There's more useful information on writing and running tests [here](test-data/unit/README.md) + ## First time contributors If you're looking for things to help with, browse our [issue tracker](https://github.com/python/mypy/issues)! @@ -63,21 +69,24 @@ In particular, look for: - [good second issues](https://github.com/python/mypy/labels/good-second-issue) - [documentation issues](https://github.com/python/mypy/labels/documentation) -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. - -If you need help getting started, don't hesitate to ask on -[gitter](https://gitter.im/python/typing). +You do not need to ask for permission to work on any of these issues. +Just fix the issue yourself, [try to add a unit test](#running-tests) and +[open a pull request](#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. +itself. You're much more likely to get help if you provide details about what +you've tried and where you've looked (maintainers tend to help those who help +themselves). [gitter](https://gitter.im/python/typing) can also be a good place +to ask for 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/). +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. + ## Submitting changes Even more excellent than a good bug report is a fix for a bug, or the diff --git a/CREDITS b/CREDITS index d0e53de5ee01..fb2fe155a9b8 100644 --- a/CREDITS +++ b/CREDITS @@ -11,15 +11,18 @@ Dropbox core team: Jukka Lehtosalo Ivan Levkivskyi + Jared Hance Non-Dropbox core team members: Ethan Smith Guido van Rossum - Jelle Zijlstra + Jelle Zijlstra Michael J. Sullivan Shantanu Jain - Xuanda Yang + Xuanda Yang + Jingchen Ye <97littleleaf11@gmail.com> + Nikita Sobolev Past Dropbox core team members: diff --git a/LICENSE b/LICENSE index 2e64b704307b..991496cb4878 100644 --- a/LICENSE +++ b/LICENSE @@ -4,7 +4,8 @@ Mypy (and mypyc) are licensed under the terms of the MIT license, reproduced bel The MIT License -Copyright (c) 2015-2021 Jukka Lehtosalo and contributors +Copyright (c) 2012-2022 Jukka Lehtosalo and contributors +Copyright (c) 2015-2022 Dropbox, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,8 +27,8 @@ DEALINGS IN THE SOFTWARE. = = = = = -Portions of mypy and mypyc are licensed under different licenses. The -files under stdlib-samples as well as the files +Portions of mypy and mypyc are licensed under different licenses. +The files mypyc/lib-rt/pythonsupport.h, mypyc/lib-rt/getargs.c and mypyc/lib-rt/getargsfast.c are licensed under the PSF 2 License, reproduced below. diff --git a/MANIFEST.in b/MANIFEST.in index fc657091a3dc..fe10e22265a6 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 action.yml +exclude .gitmodules CONTRIBUTING.md CREDITS ROADMAP.md tox.ini action.yml .editorconfig global-exclude *.py[cod] global-exclude .DS_Store diff --git a/docs/source/class_basics.rst b/docs/source/class_basics.rst index 83177e26aa67..3c12b4b06d9b 100644 --- a/docs/source/class_basics.rst +++ b/docs/source/class_basics.rst @@ -320,8 +320,8 @@ Slots ***** When a class has explicitly defined -`__slots__ `_ -mypy will check that all attributes assigned to are members of `__slots__`. +`__slots__ `_, +mypy will check that all attributes assigned to are members of ``__slots__``: .. code-block:: python @@ -331,13 +331,19 @@ mypy will check that all attributes assigned to are members of `__slots__`. def __init__(self, name: str, year: int) -> None: self.name = name self.year = year - self.released = True # E: Trying to assign name "released" that is not in "__slots__" of type "Album" + # 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: +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 (mirrors CPython's behaviour) -2. ``__slots__`` does not include ``__dict__``, since if ``__slots__`` includes ``__dict__`` - it allows setting any attribute, similar to when ``__slots__`` is not defined (mirrors CPython's behaviour) -3. All values in ``__slots__`` must be statically known. For example, no variables: only string literals. +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 7405ab563e0d..36c13910c21a 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -274,7 +274,7 @@ For more information on how to use these flags, see :ref:`version_and_platform_c Disallow dynamic typing *********************** -The ``Any`` type is used represent a value that has a :ref:`dynamic type `. +The ``Any`` type is used to represent a value that has a :ref:`dynamic type `. The ``--disallow-any`` family of flags will disallow various uses of the ``Any`` type in a module -- this lets us strategically disallow the use of dynamic typing in a controlled way. @@ -312,8 +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. For example you can't use a bare ``x: list``, you must say - ``x: list[int]``. + 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 @@ -524,7 +524,16 @@ of the above sections. # 'items' has type list[str] items = [item.split() for item in items] # 'items' now has type list[list[str]] - ... + + The variable must be used before it can be redefined: + + .. code-block:: python + + def process(items: list[str]) -> None: + items = "mypy" # invalid redefinition to str because the variable hasn't been used yet + print(items) + items = "100" # valid, items now has type str + items = int(items) # valid, items now has type int .. option:: --local-partial-types @@ -853,13 +862,17 @@ format into the specified directory. Causes mypy to generate a Cobertura XML type checking coverage report. - You must install the `lxml`_ library to generate this report. + To generate this report, you must either manually install the `lxml`_ + library or specify mypy installation with the setuptools extra + ``mypy[reports]``. .. option:: --html-report / --xslt-html-report DIR Causes mypy to generate an HTML type checking coverage report. - You must install the `lxml`_ library to generate this report. + To generate this report, you must either manually install the `lxml`_ + library or specify mypy installation with the setuptools extra + ``mypy[reports]``. .. option:: --linecount-report DIR @@ -881,13 +894,17 @@ format into the specified directory. Causes mypy to generate a text file type checking coverage report. - You must install the `lxml`_ library to generate this report. + To generate this report, you must either manually install the `lxml`_ + library or specify mypy installation with the setuptools extra + ``mypy[reports]``. .. option:: --xml-report DIR Causes mypy to generate an XML type checking coverage report. - You must install the `lxml`_ library to generate this report. + To generate this report, you must either manually install the `lxml`_ + library or specify mypy installation with the setuptools extra + ``mypy[reports]``. Miscellaneous ************* 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 c34f23d9e169..6373a5094b3d 100644 --- a/docs/source/config_file.rst +++ b/docs/source/config_file.rst @@ -197,23 +197,64 @@ section of the command line docs. .. confval:: exclude - :type: newline separated list of regular expressions + :type: regular expression - A newline list of regular expression that matches file names, directory names and paths + A 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. + Use forward slashes (``/``) as directory separators on all platforms. .. code-block:: ini [mypy] - exclude = - ^file1\.py$ - ^file2\.py$ + exclude = (?x)( + ^one\.py$ # files named "one.py" + | two\.pyi$ # or files ending with "two.pyi" + | ^three\. # or files starting with "three." + ) + + Crafting a single regular expression that excludes multiple files while remaining + human-readable can be a challenge. The above example demonstrates one approach. + ``(?x)`` enables the ``VERBOSE`` flag for the subsequent regular expression, which + `ignores most whitespace and supports comments`__. The above is equivalent to: + ``(^one\.py$|two\.pyi$|^three\.)``. + + .. __: https://docs.python.org/3/library/re.html#re.X For more details, see :option:`--exclude `. This option may only be set in the global section (``[mypy]``). + .. note:: + + Note that the TOML equivalent differs slightly. It can be either a single string + (including a multi-line string) -- which is treated as a single regular + expression -- or an array of such strings. The following TOML examples are + equivalent to the above INI example. + + Array of strings: + + .. code-block:: toml + + [tool.mypy] + exclude = [ + "^one\\.py$", # TOML's double-quoted strings require escaping backslashes + 'two\.pyi$', # but TOML's single-quoted strings do not + '^three\.', + ] + + A single, multi-line string: + + .. code-block:: toml + + [tool.mypy] + exclude = '''(?x)( + ^one\.py$ # files named "one.py" + | two\.pyi$ # or files ending with "two.pyi" + | ^three\. # or files starting with "three." + )''' # TOML's single-quoted strings do not require escaping backslashes + + See :ref:`using-a-pyproject-toml`. + .. confval:: namespace_packages :type: boolean @@ -574,6 +615,24 @@ section of the command line docs. Allows variables to be redefined with an arbitrary type, as long as the redefinition is in the same block and nesting level as the original definition. + Example where this can be useful: + + .. code-block:: python + + 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]] + + The variable must be used before it can be redefined: + + .. code-block:: python + + def process(items: list[str]) -> None: + items = "mypy" # invalid redefinition to str because the variable hasn't been used yet + print(items) + items = "100" # valid, items now has type str + items = int(items) # valid, items now has type int .. confval:: local_partial_types @@ -820,7 +879,9 @@ format into the specified directory. Causes mypy to generate a Cobertura XML type checking coverage report. - You must install the `lxml`_ library to generate this report. + To generate this report, you must either manually install the `lxml`_ + library or specify mypy installation with the setuptools extra + ``mypy[reports]``. .. confval:: html_report / xslt_html_report @@ -828,7 +889,9 @@ format into the specified directory. Causes mypy to generate an HTML type checking coverage report. - You must install the `lxml`_ library to generate this report. + To generate this report, you must either manually install the `lxml`_ + library or specify mypy installation with the setuptools extra + ``mypy[reports]``. .. confval:: linecount_report @@ -858,7 +921,9 @@ format into the specified directory. Causes mypy to generate a text file type checking coverage report. - You must install the `lxml`_ library to generate this report. + To generate this report, you must either manually install the `lxml`_ + library or specify mypy installation with the setuptools extra + ``mypy[reports]``. .. confval:: xml_report @@ -866,7 +931,9 @@ format into the specified directory. Causes mypy to generate an XML type checking coverage report. - You must install the `lxml`_ library to generate this report. + To generate this report, you must either manually install the `lxml`_ + library or specify mypy installation with the setuptools extra + ``mypy[reports]``. Miscellaneous @@ -907,6 +974,8 @@ These options may only be set in the global section (``[mypy]``). Controls how much debug output will be generated. Higher numbers are more verbose. +.. _using-a-pyproject-toml: + Using a pyproject.toml file *************************** @@ -965,6 +1034,10 @@ of your repo (or append it to the end of an existing ``pyproject.toml`` file) an python_version = "2.7" warn_return_any = true warn_unused_configs = true + exclude = [ + '^file1\.py$', # TOML literal string (single-quotes, no escaping necessary) + "^file2\\.py$", # TOML basic string (double-quotes, backslash and other characters need escaping) + ] # mypy per-module options: diff --git a/docs/source/error_code_list.rst b/docs/source/error_code_list.rst index 852913ce79bb..e655cae3c45d 100644 --- a/docs/source/error_code_list.rst +++ b/docs/source/error_code_list.rst @@ -657,6 +657,28 @@ consistently when using the call-based syntax. Example: # Error: First argument to namedtuple() should be "Point2D", not "Point" Point2D = NamedTuple("Point", [("x", int), ("y", int)]) +Check that overloaded functions have an implementation [no-overload-impl] +------------------------------------------------------------------------- + +Overloaded functions outside of stub files must be followed by a non overloaded +implementation. + +.. code-block:: python + + from typing import overload + + @overload + def func(value: int) -> int: + ... + + @overload + def func(value: str) -> str: + ... + + # presence of required function below is checked + def func(value): + pass # actual implementation + Report syntax errors [syntax] ----------------------------- diff --git a/docs/source/error_code_list2.rst b/docs/source/error_code_list2.rst index 1e035fcf7f69..c55643ad6181 100644 --- a/docs/source/error_code_list2.rst +++ b/docs/source/error_code_list2.rst @@ -255,3 +255,36 @@ no error in practice. In such case, it might be prudent to annotate ``items: Seq This is similar in concept to ensuring that an expression's type implements an expected interface (e.g. ``Sized``), except that attempting to invoke an undefined method (e.g. ``__len__``) results in an error, while attempting to evaluate an object in boolean context without a concrete implementation results in a truthy value. + + +.. _ignore-without-code: + +Check that ``# type: ignore`` include an error code [ignore-without-code] +------------------------------------------------------------------------- + +Warn when a ``# type: ignore`` comment does not specify any error codes. +This clarifies the intent of the ignore and ensures that only the +expected errors are silenced. + +Example: + +.. code-block:: python + + # mypy: enable-error-code ignore-without-code + + class Foo: + def __init__(self, name: str) -> None: + self.name = name + + f = Foo('foo') + + # This line has a typo that mypy can't help with as both: + # - the expected error 'assignment', and + # - the unexpected error 'attr-defined' + # are silenced. + # Error: "type: ignore" comment without error code (consider "type: ignore[attr-defined]" instead) + f.nme = 42 # type: ignore + + # This line warns correctly about the typo in the attribute name + # Error: "Foo" has no attribute "nme"; maybe "name"? + f.nme = 42 # type: ignore[assignment] diff --git a/docs/source/error_codes.rst b/docs/source/error_codes.rst index 5255a6984b7b..08d56c59fba2 100644 --- a/docs/source/error_codes.rst +++ b/docs/source/error_codes.rst @@ -31,6 +31,10 @@ 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] +It's also possible to require error codes for ``type: ignore`` comments. +See :ref:`ignore-without-code` for more information. + + .. _silence-error-codes: Silencing errors based on error codes diff --git a/docs/source/generics.rst b/docs/source/generics.rst index 84582be13f88..7730bd0e5c10 100644 --- a/docs/source/generics.rst +++ b/docs/source/generics.rst @@ -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,11 +90,20 @@ instantiation: >>> print(Stack[int]().__class__) __main__.Stack -For Python 3.8 and lower, 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 @@ -103,15 +112,24 @@ you a class that directly inherits from the target class in Python: >>> 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: @@ -655,6 +673,10 @@ protocols mostly follow the normal rules for generic classes. Example: y: Box[int] = ... x = y # Error -- Box is invariant +Per :pep:`PEP 544: Generic protocols <544#generic-protocols>`, ``class +ClassName(Protocol[T])`` is allowed as a shorthand for ``class +ClassName(Protocol, Generic[T])``. + The main difference between generic protocols and ordinary generic classes is that mypy checks that the declared variances of generic type variables in a protocol match how they are used in the protocol 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 7cdedf671867..866535949d74 100644 --- a/docs/source/kinds_of_types.rst +++ b/docs/source/kinds_of_types.rst @@ -362,7 +362,6 @@ is needed: .. code-block:: python - class Container: items: list[str] # No initializer @@ -522,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 @@ -564,8 +582,8 @@ Python 3.6 introduced an alternative, class-based syntax for named tuples with t .. note:: - You can use raw ``NamedTuple`` pseudo-class to annotate type - where any ``NamedTuple`` is expected. + 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: @@ -580,10 +598,12 @@ Python 3.6 introduced an alternative, class-based syntax for named tuples with t deserialize_named_tuple(Point(x=1, y=2)) # ok deserialize_named_tuple(Person(name='Nikita', age=18)) # ok - deserialize_named_tuple((1, 2)) # Argument 1 to "deserialize_named_tuple" has incompatible type "Tuple[int, int]"; expected "NamedTuple" + # Error: Argument 1 to "deserialize_named_tuple" has incompatible type + # "Tuple[int, int]"; expected "NamedTuple" + deserialize_named_tuple((1, 2)) - Note, that behavior is highly experimental, non-standard, - and can be not supported by other type checkers. + Note that this behavior is highly experimental, non-standard, + and may not be supported by other type checkers and IDEs. .. _type-of-class: @@ -729,15 +749,15 @@ type of either :py:class:`Iterator[YieldType] ` or :py:class:`I def squares(n: int) -> Iterator[int]: 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 +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 +: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 +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 diff --git a/docs/source/literal_types.rst b/docs/source/literal_types.rst index 94eec06236ca..2bca6db71ac7 100644 --- a/docs/source/literal_types.rst +++ b/docs/source/literal_types.rst @@ -1,7 +1,10 @@ +Literal types and Enums +======================= + .. _literal_types: Literal types -============= +------------- Literal types let you indicate that an expression is equal to some specific primitive value. For example, if we annotate a variable with type ``Literal["foo"]``, @@ -142,7 +145,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 @@ -186,13 +189,13 @@ corresponding to some particular index, we can use Literal types like so: # But what if we want the index to be a variable? Normally mypy won't # know exactly what the index is and so will return a less precise type: - int_index = 1 + int_index = 0 reveal_type(tup[int_index]) # Revealed type is "Union[str, float]" # But if we use either Literal types or a Final int, we can gain back # the precision we originally had: - lit_index: Literal[1] = 1 - fin_index: Final = 1 + lit_index: Literal[0] = 0 + fin_index: Final = 0 reveal_type(tup[lit_index]) # Revealed type is "str" reveal_type(tup[fin_index]) # Revealed type is "str" @@ -208,7 +211,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 +251,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 +292,11 @@ using ``isinstance()``: This feature is sometimes called "sum types" or "discriminated union types" in other programming languages. -Exhaustive checks -***************** +Exhaustiveness checking +*********************** -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 +309,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 +333,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 +343,50 @@ 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: + def validate(x: PossibleValues) -> bool: + if x == 'one': + return True + elif x == 'two': + return False + # Error: Argument 1 to "assert_never" has incompatible type "Literal['three']"; + # expected "NoReturn" + assert_never(x) + +If runtime checking against unexpected values is not needed, you can +leave out the ``assert_never`` call in the above example, and mypy +will still generate an error about function ``validate`` returning +without a value: .. code-block:: python + PossibleValues = Literal['one', 'two', 'three'] + + # Error: Missing return statement 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" + +Exhaustiveness checking is also supported for match statements (Python 3.10 and later): + +.. code-block:: python + + def validate(x: PossibleValues) -> bool: + match x: + case 'one': + return True + case 'two': + return False + assert_never(x) + Limitations *********** @@ -369,3 +401,131 @@ whatever type the parameter has. For example, ``Literal[3]`` is treated as a subtype of ``int`` and so will inherit all of ``int``'s methods directly. This means that ``Literal[3].__add__`` accepts the same arguments and has the same return type as ``int.__add__``. + + +Enums +----- + +Mypy has special support for :py:class:`enum.Enum` and its subclasses: +:py:class:`enum.IntEnum`, :py:class:`enum.Flag`, :py:class:`enum.IntFlag`, +and :py:class:`enum.StrEnum`. + +.. code-block:: python + + from enum import Enum + + class Direction(Enum): + up = 'up' + down = 'down' + + reveal_type(Direction.up) # Revealed type is "Literal[Direction.up]?" + reveal_type(Direction.down) # Revealed type is "Literal[Direction.down]?" + +You can use enums to annotate types as you would expect: + +.. code-block:: python + + class Movement: + def __init__(self, direction: Direction, speed: float) -> None: + self.direction = direction + self.speed = speed + + Movement(Direction.up, 5.0) # ok + Movement('up', 5.0) # E: Argument 1 to "Movemement" has incompatible type "str"; expected "Direction" + +Exhaustiveness checking +*********************** + +Similar to ``Literal`` types, ``Enum`` supports exhaustiveness checking. +Let's start with a definition: + +.. code-block:: python + + from enum import Enum + from typing import NoReturn + + 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) + + class Direction(Enum): + up = 'up' + down = 'down' + +Now, let's use an exhaustiveness check: + +.. code-block:: python + + def choose_direction(direction: Direction) -> None: + if direction is Direction.up: + reveal_type(direction) # N: Revealed type is "Literal[Direction.up]" + print('Going up!') + return + elif direction is Direction.down: + print('Down') + return + # This line is never reached + assert_never(direction) + +If we forget to handle one of the cases, mypy will generate an error: + +.. code-block:: python + + def choose_direction(direction: Direction) -> None: + if direction == Direction.up: + print('Going up!') + return + assert_never(direction) # E: Argument 1 to "assert_never" has incompatible type "Direction"; expected "NoReturn" + +Exhaustiveness checking is also supported for match statements (Python 3.10 and later). + +Extra Enum checks +***************** + +Mypy also tries to support special features of ``Enum`` +the same way Python's runtime does: + +- Any ``Enum`` class with values is implicitly :ref:`final `. + This is what happens in CPython: + + .. code-block:: python + + >>> class AllDirection(Direction): + ... left = 'left' + ... right = 'right' + Traceback (most recent call last): + ... + TypeError: Other: cannot extend enumeration 'Some' + + Mypy also catches this error: + + .. code-block:: python + + class AllDirection(Direction): # E: Cannot inherit from final class "Some" + left = 'left' + right = 'right' + +- All ``Enum`` fields are implictly ``final`` as well. + + .. code-block:: python + + Direction.up = '^' # E: Cannot assign to final attribute "up" + +- All field names are checked to be unique. + + .. code-block:: python + + class Some(Enum): + x = 1 + x = 2 # E: Attempted to reuse member name "x" in Enum definition "Some" + +- Base classes have no conflicts and mixin types are correct. + + .. code-block:: python + + class WrongEnum(str, int, enum.Enum): + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "int" + ... + + class MixinAfterEnum(enum.Enum, Mixin): # E: No base classes are allowed after "enum.Enum" + ... diff --git a/docs/source/more_types.rst b/docs/source/more_types.rst index 11dbef32cbfa..dd688cab7e17 100644 --- a/docs/source/more_types.rst +++ b/docs/source/more_types.rst @@ -294,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 @@ -581,6 +581,115 @@ with ``Union[int, slice]`` and ``Union[T, Sequence]``. to returning ``Any`` only if the input arguments also contain ``Any``. +Conditional overloads +--------------------- + +Sometimes it is useful to define overloads conditionally. +Common use cases include types that are unavailable at runtime or that +only exist in a certain Python version. All existing overload rules still apply. +For example, there must be at least two overloads. + +.. note:: + + Mypy can only infer a limited number of conditions. + Supported ones currently include :py:data:`~typing.TYPE_CHECKING`, ``MYPY``, + :ref:`version_and_platform_checks`, :option:`--always-true `, + and :option:`--always-false ` values. + +.. code-block:: python + + from typing import TYPE_CHECKING, Any, overload + + if TYPE_CHECKING: + class A: ... + class B: ... + + + if TYPE_CHECKING: + @overload + def func(var: A) -> A: ... + + @overload + def func(var: B) -> B: ... + + def func(var: Any) -> Any: + return var + + + reveal_type(func(A())) # Revealed type is "A" + +.. code-block:: python + + # flags: --python-version 3.10 + import sys + from typing import Any, overload + + class A: ... + class B: ... + class C: ... + class D: ... + + + if sys.version_info < (3, 7): + @overload + def func(var: A) -> A: ... + + elif sys.version_info >= (3, 10): + @overload + def func(var: B) -> B: ... + + else: + @overload + def func(var: C) -> C: ... + + @overload + def func(var: D) -> D: ... + + def func(var: Any) -> Any: + return var + + + reveal_type(func(B())) # Revealed type is "B" + reveal_type(func(C())) # No overload variant of "func" matches argument type "C" + # Possible overload variants: + # def func(var: B) -> B + # def func(var: D) -> D + # Revealed type is "Any" + + +.. note:: + + In the last example, mypy is executed with + :option:`--python-version 3.10 `. + Therefore, the condition ``sys.version_info >= (3, 10)`` will match and + the overload for ``B`` will be added. + The overloads for ``A`` and ``C`` are ignored! + The overload for ``D`` is not defined conditionally and thus is also added. + +When mypy cannot infer a condition to be always ``True`` or always ``False``, +an error is emitted. + +.. code-block:: python + + from typing import Any, overload + + class A: ... + class B: ... + + + def g(bool_var: bool) -> None: + if bool_var: # Condition can't be inferred, unable to merge overloads + @overload + def func(var: A) -> A: ... + + @overload + def func(var: B) -> B: ... + + def func(var: Any) -> Any: ... + + reveal_type(func(A())) # Revealed type is "Any" + + .. _advanced_self: Advanced uses of self-types @@ -765,68 +874,6 @@ value of type :py:class:`Coroutine[Any, Any, T] `, which is a :ref:`reveal_type() ` displays the inferred static type of an expression. -If you want to use coroutines in Python 3.4, which does not support -the ``async def`` syntax, you can instead use the :py:func:`@asyncio.coroutine ` -decorator to convert a generator into a coroutine. - -Note that we set the ``YieldType`` of the generator to be ``Any`` in the -following example. This is because the exact yield type is an implementation -detail of the coroutine runner (e.g. the :py:mod:`asyncio` event loop) and your -coroutine shouldn't have to know or care about what precisely that type is. - -.. code-block:: python - - from typing import Any, Generator - import asyncio - - @asyncio.coroutine - def countdown_2(tag: str, count: int) -> Generator[Any, None, str]: - while count > 0: - print('T-minus {} ({})'.format(count, tag)) - yield from asyncio.sleep(0.1) - count -= 1 - return "Blastoff!" - - loop = asyncio.get_event_loop() - loop.run_until_complete(countdown_2("USS Enterprise", 5)) - loop.close() - -As before, the result of calling a generator decorated with :py:func:`@asyncio.coroutine ` -will be a value of type :py:class:`Awaitable[T] `. - -.. note:: - - At runtime, you are allowed to add the :py:func:`@asyncio.coroutine ` decorator to - both functions and generators. This is useful when you want to mark a - work-in-progress function as a coroutine, but have not yet added ``yield`` or - ``yield from`` statements: - - .. code-block:: python - - import asyncio - - @asyncio.coroutine - def serialize(obj: object) -> str: - # todo: add yield/yield from to turn this into a generator - return "placeholder" - - However, mypy currently does not support converting functions into - coroutines. Support for this feature will be added in a future version, but - for now, you can manually force the function to be a generator by doing - something like this: - - .. code-block:: python - - from typing import Generator - import asyncio - - @asyncio.coroutine - def serialize(obj: object) -> Generator[None, None, str]: - # todo: add yield/yield from to turn this into a generator - if False: - yield - return "placeholder" - You may also choose to create a subclass of :py:class:`~typing.Awaitable` instead: .. code-block:: python @@ -886,11 +933,29 @@ To create an iterable coroutine, subclass :py:class:`~typing.AsyncIterator`: loop.run_until_complete(countdown_4("Serenity", 5)) loop.close() -For a more concrete example, the mypy repo has a toy webcrawler that -demonstrates how to work with coroutines. One version -`uses async/await `_ -and one -`uses yield from `_. +If you use coroutines in legacy code that was originally written for +Python 3.4, which did not support the ``async def`` syntax, you would +instead use the :py:func:`@asyncio.coroutine ` +decorator to convert a generator into a coroutine, and use a +generator type as the return type: + +.. code-block:: python + + from typing import Any, Generator + import asyncio + + @asyncio.coroutine + def countdown_2(tag: str, count: int) -> Generator[Any, None, str]: + while count > 0: + print('T-minus {} ({})'.format(count, tag)) + yield from asyncio.sleep(0.1) + count -= 1 + return "Blastoff!" + + loop = asyncio.get_event_loop() + loop.run_until_complete(countdown_2("USS Enterprise", 5)) + loop.close() + .. _typeddict: diff --git a/docs/source/running_mypy.rst b/docs/source/running_mypy.rst index d1c701e27e5a..070e4556c04e 100644 --- a/docs/source/running_mypy.rst +++ b/docs/source/running_mypy.rst @@ -491,7 +491,7 @@ This is computed from the following items: .. note:: - You cannot point to a :pep:`561` package via the ``MYPYPATH``, it must be + You cannot point to a stub-only package (:pep:`561`) via the ``MYPYPATH``, it must be installed (see :ref:`PEP 561 support `) Second, mypy searches for stub files in addition to regular Python files diff --git a/docs/source/stubtest.rst b/docs/source/stubtest.rst index 5903de2cf7ca..828931fbdf2b 100644 --- a/docs/source/stubtest.rst +++ b/docs/source/stubtest.rst @@ -17,24 +17,24 @@ 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 +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 +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 more things stubtest does not do: +For clarity, here are some additional things stubtest can't do: -* Type check your code, use ``mypy`` -* Generate stubs, use ``stubgen`` or ``pyright --createstub`` -* Generate stubs based on running your application or test suite, use ``monkeytype`` -* Apply stubs to code to produce inline types, use ``retype`` or ``libcst`` +* 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 @@ -81,11 +81,11 @@ Usage Running stubtest can be as simple as ``stubtest module_to_check``. Run :option:`stubtest --help` for a quick summary of options. -stubtest must be able to import the code to be checked, so make sure that mypy +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 +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 diff --git a/docs/source/type_inference_and_annotations.rst b/docs/source/type_inference_and_annotations.rst index 80b9356cd681..8150f88e579e 100644 --- a/docs/source/type_inference_and_annotations.rst +++ b/docs/source/type_inference_and_annotations.rst @@ -95,10 +95,11 @@ Similarly, you can also give an explicit type when creating an empty set: .. note:: - Using type annotations (e.g. `list[int]`) on builtin collections like + 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`, :py:class:`~typing.Dict`, etc. + :py:class:`~typing.List` (e.g. ``List[int]``), :py:class:`~typing.Dict`, and + so on. Compatibility of container types @@ -267,19 +268,20 @@ short explanation of the bug. To do that, use this format: app.run(8000) # type: ignore # `run()` now accepts an `int`, as a port -If your error displays an error code, like so: +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, like -``# type: ignore[attr-defined]``, to clarify what's being silenced. You can -find more information about error codes here: :ref:`silence-error-codes`. +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`` on the top of the file: +``# type: ignore`` at the top of the file: .. code-block:: python diff --git a/misc/build_wheel.py b/misc/build_wheel.py index 44b40c2e8fed..9d34242ead41 100644 --- a/misc/build_wheel.py +++ b/misc/build_wheel.py @@ -44,8 +44,8 @@ def create_environ(python_version: str) -> Dict[str, str]: # 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" - env['CIBW_TEST_SKIP'] = "*-macosx_arm64" + env['CIBW_ARCHS_MACOS'] = "x86_64 arm64 universal2" + env['CIBW_TEST_SKIP'] = "*-macosx_arm64 *_universal2:arm64" env['CIBW_BUILD_VERBOSITY'] = '1' @@ -73,21 +73,35 @@ def create_environ(python_version: str) -> Dict[str, str]: 'MYPY_USE_MYPYC=1 MYPYC_OPT_LEVEL=2 PIP_NO_BUILD_ISOLATION=no' ) - # lxml is slow to build wheels for new releases, so allow installing reqs to fail - # if we failed to install lxml, we'll skip tests, but allow the build to succeed - env['CIBW_BEFORE_TEST'] = ( - 'pip install -r {project}/mypy/test-requirements.txt || true' - ) + # lxml doesn't have a wheel for Python 3.10 on the manylinux image we use. + # lxml has historically been slow to support new Pythons as well. + env['CIBW_BEFORE_TEST'] = """ + ( + grep -v lxml {project}/mypy/test-requirements.txt > /tmp/test-requirements.txt + && cp {project}/mypy/mypy-requirements.txt /tmp/mypy-requirements.txt + && cp {project}/mypy/build-requirements.txt /tmp/build-requirements.txt + && pip install -r /tmp/test-requirements.txt + ) + """.replace('\n', ' ') + # lxml currently has wheels on Windows and doesn't have grep, so special case + env['CIBW_BEFORE_TEST_WINDOWS'] = "pip install -r {project}/mypy/test-requirements.txt" # pytest looks for configuration files in the parent directories of where the tests live. # since we are trying to run the tests from their installed location, we copy those into # the venv. Ew ew ew. + # We don't run tests that need lxml since we don't install lxml + # We don't run external mypyc tests since there's some issue with compilation on the + # manylinux image we use. env['CIBW_TEST_COMMAND'] = """ - ( ! pip list | grep lxml ) || ( + ( DIR=$(python -c 'import mypy, os; dn = os.path.dirname; print(dn(dn(mypy.__path__[0])))') - && TEST_DIR=$(python -c 'import mypy.test; print(mypy.test.__path__[0])') && cp '{project}/mypy/pytest.ini' '{project}/mypy/conftest.py' $DIR - && MYPY_TEST_PREFIX='{project}/mypy' pytest $TEST_DIR + + && MYPY_TEST_DIR=$(python -c 'import mypy.test; print(mypy.test.__path__[0])') + && MYPY_TEST_PREFIX='{project}/mypy' pytest $MYPY_TEST_DIR -k 'not (reports.test or testreports)' + + && MYPYC_TEST_DIR=$(python -c 'import mypyc.test; print(mypyc.test.__path__[0])') + && MYPY_TEST_PREFIX='{project}/mypy' pytest $MYPYC_TEST_DIR -k 'not test_external' ) """.replace('\n', ' ') @@ -95,7 +109,7 @@ def create_environ(python_version: str) -> Dict[str, str]: # previously didn't run any tests on windows wheels, so this is a net win. env['CIBW_TEST_COMMAND_WINDOWS'] = """ bash -c " - ( ! pip list | grep lxml ) || ( + ( DIR=$(python -c 'import mypy, os; dn = os.path.dirname; print(dn(dn(mypy.__path__[0])))') && TEST_DIR=$(python -c 'import mypy.test; print(mypy.test.__path__[0])') && cp '{project}/mypy/pytest.ini' '{project}/mypy/conftest.py' $DIR diff --git a/mypy/build.py b/mypy/build.py index 5eebc0a22a85..4b5f7e1cf5dc 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -56,7 +56,7 @@ from mypy.fscache import FileSystemCache from mypy.metastore import MetadataStore, FilesystemMetadataStore, SqliteMetadataStore from mypy.typestate import TypeState, reset_global_state -from mypy.renaming import VariableRenameVisitor +from mypy.renaming import VariableRenameVisitor, LimitedVariableRenameVisitor from mypy.config_parser import parse_mypy_comments from mypy.freetree import free_tree from mypy.stubinfo import legacy_bundled_packages, is_legacy_bundled_package @@ -511,7 +511,7 @@ def find_config_file_line_number(path: str, section: str, setting_name: str) -> in_desired_section = False try: results = [] - with open(path) as f: + with open(path, encoding="UTF-8") as f: for i, line in enumerate(f): line = line.strip() if line.startswith('[') and line.endswith(']'): @@ -539,8 +539,6 @@ class BuildManager: modules: Mapping of module ID to MypyFile (shared by the passes) semantic_analyzer: Semantic analyzer, pass 2 - semantic_analyzer_pass3: - Semantic analyzer, pass 3 all_types: Map {Expression: Type} from all modules (enabled by export_types) options: Build options missing_modules: Set of modules that could not be imported encountered so far @@ -2121,9 +2119,12 @@ def semantic_analysis_pass1(self) -> None: analyzer.visit_file(self.tree, self.xpath, self.id, options) # TODO: Do this while constructing the AST? self.tree.names = SymbolTable() - if options.allow_redefinition: - # Perform renaming across the AST to allow variable redefinitions - self.tree.accept(VariableRenameVisitor()) + if not self.tree.is_stub: + # Always perform some low-key variable renaming + self.tree.accept(LimitedVariableRenameVisitor()) + if options.allow_redefinition: + # Perform more renaming across the AST to allow variable redefinitions + self.tree.accept(VariableRenameVisitor()) def add_dependency(self, dep: str) -> None: if dep not in self.dependencies_set: @@ -2188,8 +2189,10 @@ def type_checker(self) -> TypeChecker: if not self._type_checker: assert self.tree is not None, "Internal error: must be called on parsed file only" manager = self.manager - self._type_checker = TypeChecker(manager.errors, manager.modules, self.options, - self.tree, self.xpath, manager.plugin) + self._type_checker = TypeChecker( + manager.errors, manager.modules, self.options, + self.tree, self.xpath, manager.plugin, + ) return self._type_checker def type_map(self) -> Dict[Expression, Type]: @@ -2371,6 +2374,13 @@ def generate_unused_ignore_notes(self) -> None: self.verify_dependencies(suppressed_only=True) self.manager.errors.generate_unused_ignore_errors(self.xpath) + def generate_ignore_without_code_notes(self) -> None: + if self.manager.errors.is_error_code_enabled(codes.IGNORE_WITHOUT_CODE): + self.manager.errors.generate_ignore_without_code_errors( + self.xpath, + self.options.warn_unused_ignores, + ) + # Module import and diagnostic glue @@ -2832,8 +2842,15 @@ def load_graph(sources: List[BuildSource], manager: BuildManager, ) manager.errors.report( -1, -1, - "Are you missing an __init__.py? Alternatively, consider using --exclude to " - "avoid checking one of them.", + "See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules " # noqa: E501 + "for more info", + severity='note', + ) + manager.errors.report( + -1, -1, + "Common resolutions include: a) using `--exclude` to avoid checking one of them, " + "b) adding `__init__.py` somewhere, c) using `--explicit-package-bases` or " + "adjusting MYPYPATH", severity='note' ) @@ -2907,6 +2924,12 @@ def load_graph(sources: List[BuildSource], manager: BuildManager, "for more info", severity='note', ) + manager.errors.report( + -1, 0, + "Common resolutions include: a) adding `__init__.py` somewhere, " + "b) using `--explicit-package-bases` or adjusting MYPYPATH", + severity='note', + ) manager.errors.raise_error() seen_files[newst_path] = newst @@ -2936,12 +2959,16 @@ def process_graph(graph: Graph, manager: BuildManager) -> None: # Order the SCC's nodes using a heuristic. # Note that ascc is a set, and scc is a list. scc = order_ascc(graph, ascc) - # If builtins is in the list, move it last. (This is a bit of - # a hack, but it's necessary because the builtins module is - # part of a small cycle involving at least {builtins, abc, - # typing}. Of these, builtins must be processed last or else - # some builtin objects will be incompletely processed.) + # Make the order of the SCC that includes 'builtins' and 'typing', + # among other things, predictable. Various things may break if + # the order changes. if 'builtins' in ascc: + scc = sorted(scc, reverse=True) + # If builtins is in the list, move it last. (This is a bit of + # a hack, but it's necessary because the builtins module is + # part of a small cycle involving at least {builtins, abc, + # typing}. Of these, builtins must be processed last or else + # some builtin objects will be incompletely processed.) scc.remove('builtins') scc.append('builtins') if manager.options.verbosity >= 2: @@ -3157,6 +3184,7 @@ def process_stale_scc(graph: Graph, scc: List[str], manager: BuildManager) -> No graph[id].finish_passes() for id in stale: graph[id].generate_unused_ignore_notes() + graph[id].generate_ignore_without_code_notes() if any(manager.errors.is_errors_for_file(graph[id].xpath) for id in stale): for id in stale: graph[id].transitive_error = True diff --git a/mypy/checker.py b/mypy/checker.py index b90221a0a5a5..c50d67b275c4 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -2,11 +2,12 @@ import itertools import fnmatch +from collections import defaultdict from contextlib import contextmanager from typing import ( Any, Dict, Set, List, cast, Tuple, TypeVar, Union, Optional, NamedTuple, Iterator, - Iterable, Sequence, Mapping, Generic, AbstractSet, Callable + Iterable, Sequence, Mapping, Generic, AbstractSet, Callable, overload ) from typing_extensions import Final, TypeAlias as _TypeAlias @@ -23,10 +24,9 @@ Context, Decorator, PrintStmt, BreakStmt, PassStmt, ContinueStmt, ComparisonExpr, StarExpr, EllipsisExpr, RefExpr, PromoteExpr, Import, ImportFrom, ImportAll, ImportBase, TypeAlias, - ARG_POS, ARG_STAR, LITERAL_TYPE, LDEF, MDEF, GDEF, + ARG_POS, ARG_STAR, ARG_NAMED, LITERAL_TYPE, LDEF, MDEF, GDEF, CONTRAVARIANT, COVARIANT, INVARIANT, TypeVarExpr, AssignmentExpr, - is_final_node, - ARG_NAMED) + is_final_node, MatchStmt) from mypy import nodes from mypy import operators from mypy.literals import literal, literal_hash, Key @@ -50,6 +50,7 @@ type_object_type, analyze_decorator_or_funcbase_access, ) +from mypy.checkpattern import PatternChecker 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, @@ -63,7 +64,7 @@ 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, + restrict_subtype_away, is_callable_compatible, unify_generic_callable, find_member ) from mypy.constraints import SUPERTYPE_OF @@ -85,7 +86,7 @@ from mypy import state, errorcodes as codes from mypy.traverser import has_return_statement, all_return_statements from mypy.errorcodes import ErrorCode -from mypy.util import is_typeshed_file +from mypy.util import is_typeshed_file, is_dunder, is_sunder T = TypeVar('T') @@ -171,6 +172,8 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface): # Helper for type checking expressions expr_checker: mypy.checkexpr.ExpressionChecker + pattern_checker: PatternChecker + tscope: Scope scope: "CheckerScope" # Stack of function return types @@ -235,6 +238,7 @@ def __init__(self, errors: Errors, modules: Dict[str, MypyFile], options: Option self.msg = MessageBuilder(errors, modules) self.plugin = plugin self.expr_checker = mypy.checkexpr.ExpressionChecker(self, self.msg, self.plugin) + self.pattern_checker = PatternChecker(self, self.msg, self.plugin) self.tscope = Scope() self.scope = CheckerScope(tree) self.binder = ConditionalTypeBinder() @@ -596,7 +600,8 @@ def check_overlapping_overloads(self, defn: OverloadedFuncDef) -> None: self.msg.overloaded_signatures_arg_specific(i + 1, defn.impl) # Is the overload alternative's return type a subtype of the implementation's? - if not is_subtype_no_promote(sig1.ret_type, impl.ret_type): + if not (is_subtype_no_promote(sig1.ret_type, impl.ret_type) or + is_subtype_no_promote(impl.ret_type, sig1.ret_type)): self.msg.overloaded_signatures_ret_specific(i + 1, defn.impl) # Here's the scoop about generators and coroutines. @@ -956,7 +961,7 @@ def check_func_def(self, defn: FuncItem, typ: CallableType, name: Optional[str]) if isclass: ref_type = mypy.types.TypeType.make_normalized(ref_type) erased = get_proper_type(erase_to_bound(arg_type)) - if not is_subtype_ignoring_tvars(ref_type, erased): + if not is_subtype(ref_type, erased, ignore_type_params=True): note = None if (isinstance(erased, Instance) and erased.type.is_protocol or isinstance(erased, TypeType) and @@ -1434,6 +1439,14 @@ def check_setattr_method(self, typ: Type, context: Context) -> None: if not is_subtype(typ, method_type): self.msg.invalid_signature_for_special_method(typ, context, '__setattr__') + def check_match_args(self, var: Var, typ: Type, context: Context) -> None: + """Check that __match_args__ contains literal strings""" + typ = get_proper_type(typ) + if not isinstance(typ, TupleType) or \ + not all([is_string_literal(item) for item in typ.items]): + self.msg.note("__match_args__ must be a tuple containing string literals for checking " + "of match statements to work", context, code=codes.LITERAL_REQ) + def expand_typevars(self, defn: FuncItem, typ: CallableType) -> List[Tuple[FuncItem, CallableType]]: # TODO use generator @@ -1737,7 +1750,7 @@ def erase_override(t: Type) -> Type: if len(order) == len(original.items) and order != sorted(order): self.msg.overload_signature_incompatible_with_supertype( - name, name_in_super, supertype, override, node) + name, name_in_super, supertype, node) emitted_msg = True if not emitted_msg: @@ -1816,6 +1829,8 @@ def visit_class_def(self, defn: ClassDef) -> None: # that completely swap out the type. (e.g. Callable[[Type[A]], Type[B]]) if typ.is_protocol and typ.defn.type_vars: self.check_protocol_variance(defn) + if not defn.has_incompatible_baseclass and defn.info.is_enum: + self.check_enum(defn) def check_final_deletable(self, typ: TypeInfo) -> None: # These checks are only for mypyc. Only perform some checks that are easier @@ -1873,6 +1888,105 @@ def check_init_subclass(self, defn: ClassDef) -> None: # all other bases have already been checked. break + def check_enum(self, defn: ClassDef) -> None: + assert defn.info.is_enum + if defn.info.fullname not in ENUM_BASES: + for sym in defn.info.names.values(): + if (isinstance(sym.node, Var) and sym.node.has_explicit_value and + sym.node.name == '__members__'): + # `__members__` will always be overwritten by `Enum` and is considered + # read-only so we disallow assigning a value to it + self.fail( + message_registry.ENUM_MEMBERS_ATTR_WILL_BE_OVERRIDEN, sym.node + ) + for base in defn.info.mro[1:-1]: # we don't need self and `object` + if base.is_enum and base.fullname not in ENUM_BASES: + self.check_final_enum(defn, base) + + self.check_enum_bases(defn) + self.check_enum_new(defn) + + def check_final_enum(self, defn: ClassDef, base: TypeInfo) -> None: + for sym in base.names.values(): + if self.is_final_enum_value(sym): + self.fail( + 'Cannot extend enum with existing members: "{}"'.format( + base.name, + ), + defn, + ) + break + + def is_final_enum_value(self, sym: SymbolTableNode) -> bool: + if isinstance(sym.node, (FuncBase, Decorator)): + return False # A method is fine + if not isinstance(sym.node, Var): + return True # Can be a class or anything else + + # Now, only `Var` is left, we need to check: + # 1. Private name like in `__prop = 1` + # 2. Dunder name like `__hash__ = some_hasher` + # 3. Sunder name like `_order_ = 'a, b, c'` + # 4. If it is a method / descriptor like in `method = classmethod(func)` + if ( + is_private(sym.node.name) + or is_dunder(sym.node.name) + or is_sunder(sym.node.name) + # TODO: make sure that `x = @class/staticmethod(func)` + # and `x = property(prop)` both work correctly. + # Now they are incorrectly counted as enum members. + or isinstance(get_proper_type(sym.node.type), FunctionLike) + ): + return False + + if self.is_stub or sym.node.has_explicit_value: + return True + return False + + def check_enum_bases(self, defn: ClassDef) -> None: + enum_base: Optional[Instance] = None + for base in defn.info.bases: + if enum_base is None and base.type.is_enum: + enum_base = base + continue + elif enum_base is not None: + self.fail( + 'No base classes are allowed after "{}"'.format(enum_base), + defn, + ) + break + + def check_enum_new(self, defn: ClassDef) -> None: + def has_new_method(info: TypeInfo) -> bool: + new_method = info.get('__new__') + return bool( + new_method + and new_method.node + and new_method.node.fullname != 'builtins.object.__new__' + ) + + has_new = False + for base in defn.info.bases: + candidate = False + + if base.type.is_enum: + # If we have an `Enum`, then we need to check all its bases. + candidate = any( + not b.is_enum and has_new_method(b) + for b in base.type.mro[1:-1] + ) + else: + candidate = has_new_method(base.type) + + if candidate and has_new: + self.fail( + 'Only a single data type mixin is allowed for Enum subtypes, ' + 'found extra "{}"'.format(base), + defn, + ) + elif candidate: + has_new = True + def check_protocol_variance(self, defn: ClassDef) -> None: """Check that protocol definition is compatible with declared variances of type variables. @@ -1999,8 +2113,9 @@ class C(B, A[int]): ... # this is unsafe because... self.msg.cant_override_final(name, base2.name, ctx) if is_final_node(first.node): self.check_if_final_var_override_writable(name, second.node, ctx) - # __slots__ and __deletable__ are special and the type can vary across class hierarchy. - if name in ('__slots__', '__deletable__'): + # Some attributes like __slots__ and __deletable__ are special, and the type can + # vary across class hierarchy. + if isinstance(second.node, Var) and second.node.allow_incompatible_override: ok = True if not ok: self.msg.base_class_definitions_incompatible(name, base1, base2, @@ -2166,13 +2281,22 @@ def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type else: self.check_getattr_method(signature, lvalue, name) + if name == '__match_args__' and inferred is not None: + typ = self.expr_checker.accept(rvalue) + self.check_match_args(inferred, typ, lvalue) + # Defer PartialType's super type checking. if (isinstance(lvalue, RefExpr) and - not (isinstance(lvalue_type, PartialType) and lvalue_type.type is None)): + not (isinstance(lvalue_type, PartialType) and + lvalue_type.type is None) and + not (isinstance(lvalue, NameExpr) and lvalue.name == '__match_args__')): if self.check_compatibility_all_supers(lvalue, lvalue_type, rvalue): # We hit an error on this line; don't check for any others return + if isinstance(lvalue, MemberExpr) and lvalue.name == '__match_args__': + self.fail(message_registry.CANNOT_MODIFY_MATCH_ARGS, lvalue) + if lvalue_type: if isinstance(lvalue_type, PartialType) and lvalue_type.type is None: # Try to infer a proper type for a variable with a partial None type. @@ -2269,7 +2393,8 @@ def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type if inferred: rvalue_type = self.expr_checker.accept(rvalue) - if not inferred.is_final: + if not (inferred.is_final or (isinstance(lvalue, NameExpr) and + lvalue.name == '__match_args__')): rvalue_type = remove_instance_last_known_values(rvalue_type) self.infer_variable_type(inferred, lvalue, rvalue_type, rvalue) self.check_assignment_to_slots(lvalue) @@ -2352,16 +2477,12 @@ def check_compatibility_all_supers(self, lvalue: RefExpr, lvalue_type: Optional[ last_immediate_base = direct_bases[-1] if direct_bases else None for base in lvalue_node.info.mro[1:]: - # Only check __slots__ against the 'object' - # If a base class defines a Tuple of 3 elements, a child of - # this class should not be allowed to define it as a Tuple of - # anything other than 3 elements. The exception to this rule - # is __slots__, where it is allowed for any child class to - # redefine it. - if lvalue_node.name == "__slots__" and base.fullname != "builtins.object": - continue - # We don't care about the type of "__deletable__". - if lvalue_node.name == "__deletable__": + # The type of "__slots__" and some other attributes usually doesn't need to + # be compatible with a base class. We'll still check the type of "__slots__" + # against "object" as an exception. + if (isinstance(lvalue_node, Var) and lvalue_node.allow_incompatible_override and + not (lvalue_node.name == "__slots__" and + base.fullname == "builtins.object")): continue if is_private(lvalue_node.name): @@ -2517,7 +2638,7 @@ 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: + if base.fullname in ENUM_BASES or node.name in ENUM_SPECIAL_PROPS: return True self.check_if_final_var_override_writable(node.name, base_node, node) return True @@ -3486,7 +3607,7 @@ def visit_raise_stmt(self, s: RaiseStmt) -> None: if s.expr: self.type_check_raise(s.expr, s) if s.from_expr: - self.type_check_raise(s.from_expr, s, True) + self.type_check_raise(s.from_expr, s, optional=True) self.binder.unreachable() def type_check_raise(self, e: Expression, s: RaiseStmt, @@ -3495,24 +3616,94 @@ def type_check_raise(self, e: Expression, s: RaiseStmt, if isinstance(typ, DeletedType): self.msg.deleted_as_rvalue(typ, e) return + + if self.options.python_version[0] == 2: + # Since `raise` has very different rule on python2, we use a different helper. + # https://github.com/python/mypy/pull/11289 + self._type_check_raise_python2(e, s, typ) + return + + # Python3 case: exc_type = self.named_type('builtins.BaseException') - expected_type = UnionType([exc_type, TypeType(exc_type)]) + expected_type_items = [exc_type, TypeType(exc_type)] if optional: - expected_type.items.append(NoneType()) - if self.options.python_version[0] == 2: - # allow `raise type, value, traceback` - # https://docs.python.org/2/reference/simple_stmts.html#the-raise-statement - # TODO: Also check tuple item types. - any_type = AnyType(TypeOfAny.implementation_artifact) - tuple_type = self.named_type('builtins.tuple') - expected_type.items.append(TupleType([any_type, any_type], tuple_type)) - expected_type.items.append(TupleType([any_type, any_type, any_type], tuple_type)) - self.check_subtype(typ, expected_type, s, message_registry.INVALID_EXCEPTION) + # This is used for `x` part in a case like `raise e from x`, + # where we allow `raise e from None`. + expected_type_items.append(NoneType()) + + self.check_subtype( + typ, UnionType.make_union(expected_type_items), s, + message_registry.INVALID_EXCEPTION, + ) if isinstance(typ, FunctionLike): # https://github.com/python/mypy/issues/11089 self.expr_checker.check_call(typ, [], [], e) + def _type_check_raise_python2(self, e: Expression, s: RaiseStmt, typ: ProperType) -> None: + # Python2 has two possible major cases: + # 1. `raise expr`, where `expr` is some expression, it can be: + # - Exception typ + # - Exception instance + # - Old style class (not supported) + # - Tuple, where 0th item is exception type or instance + # 2. `raise exc, msg, traceback`, where: + # - `exc` is exception type (not instance!) + # - `traceback` is `types.TracebackType | None` + # Important note: `raise exc, msg` is not the same as `raise (exc, msg)` + # We call `raise exc, msg, traceback` - legacy mode. + exc_type = self.named_type('builtins.BaseException') + exc_inst_or_type = UnionType([exc_type, TypeType(exc_type)]) + + if (not s.legacy_mode and (isinstance(typ, TupleType) and typ.items + or (isinstance(typ, Instance) and typ.args + and typ.type.fullname == 'builtins.tuple'))): + # `raise (exc, ...)` case: + item = typ.items[0] if isinstance(typ, TupleType) else typ.args[0] + self.check_subtype( + item, exc_inst_or_type, s, + 'When raising a tuple, first element must by derived from BaseException', + ) + return + elif s.legacy_mode: + # `raise Exception, msg` case + # `raise Exception, msg, traceback` case + # https://docs.python.org/2/reference/simple_stmts.html#the-raise-statement + assert isinstance(typ, TupleType) # Is set in fastparse2.py + if (len(typ.items) >= 2 + and isinstance(get_proper_type(typ.items[1]), NoneType)): + expected_type: Type = exc_inst_or_type + else: + expected_type = TypeType(exc_type) + self.check_subtype( + typ.items[0], expected_type, s, + 'Argument 1 must be "{}" subtype'.format(expected_type), + ) + + # Typecheck `traceback` part: + if len(typ.items) == 3: + # Now, we typecheck `traceback` argument if it is present. + # We do this after the main check for better error message + # and better ordering: first about `BaseException` subtype, + # then about `traceback` type. + traceback_type = UnionType.make_union([ + self.named_type('types.TracebackType'), + NoneType(), + ]) + self.check_subtype( + typ.items[2], traceback_type, s, + 'Argument 3 must be "{}" subtype'.format(traceback_type), + ) + else: + expected_type_items = [ + # `raise Exception` and `raise Exception()` cases: + exc_type, TypeType(exc_type), + ] + self.check_subtype( + typ, UnionType.make_union(expected_type_items), + s, message_registry.INVALID_EXCEPTION, + ) + def visit_try_stmt(self, s: TryStmt) -> None: """Type check a try statement.""" # Our enclosing frame will get the result if the try/except falls through. @@ -3904,6 +4095,106 @@ def visit_continue_stmt(self, s: ContinueStmt) -> None: self.binder.handle_continue() return None + def visit_match_stmt(self, s: MatchStmt) -> None: + with self.binder.frame_context(can_skip=False, fall_through=0): + subject_type = get_proper_type(self.expr_checker.accept(s.subject)) + + if isinstance(subject_type, DeletedType): + self.msg.deleted_as_rvalue(subject_type, s) + + # We infer types of patterns twice. The first pass is used + # to infer the types of capture variables. The type of a + # capture variable may depend on multiple patterns (it + # will be a union of all capture types). This pass ignores + # guard expressions. + pattern_types = [self.pattern_checker.accept(p, subject_type) for p in s.patterns] + type_maps: List[TypeMap] = [t.captures for t in pattern_types] + inferred_types = self.infer_variable_types_from_type_maps(type_maps) + + # The second pass narrows down the types and type checks bodies. + for p, g, b in zip(s.patterns, s.guards, s.bodies): + current_subject_type = self.expr_checker.narrow_type_from_binder(s.subject, + subject_type) + pattern_type = self.pattern_checker.accept(p, current_subject_type) + with self.binder.frame_context(can_skip=True, fall_through=2): + if b.is_unreachable or isinstance(get_proper_type(pattern_type.type), + UninhabitedType): + self.push_type_map(None) + else_map: TypeMap = {} + else: + pattern_map, else_map = conditional_types_to_typemaps( + s.subject, + pattern_type.type, + pattern_type.rest_type + ) + self.remove_capture_conflicts(pattern_type.captures, + inferred_types) + self.push_type_map(pattern_map) + self.push_type_map(pattern_type.captures) + if g is not None: + with self.binder.frame_context(can_skip=True, fall_through=3): + gt = get_proper_type(self.expr_checker.accept(g)) + + if isinstance(gt, DeletedType): + self.msg.deleted_as_rvalue(gt, s) + + guard_map, guard_else_map = self.find_isinstance_check(g) + else_map = or_conditional_maps(else_map, guard_else_map) + + self.push_type_map(guard_map) + self.accept(b) + else: + self.accept(b) + self.push_type_map(else_map) + + # This is needed due to a quirk in frame_context. Without it types will stay narrowed + # after the match. + with self.binder.frame_context(can_skip=False, fall_through=2): + pass + + def infer_variable_types_from_type_maps(self, type_maps: List[TypeMap]) -> Dict[Var, Type]: + all_captures: Dict[Var, List[Tuple[NameExpr, Type]]] = defaultdict(list) + for tm in type_maps: + if tm is not None: + for expr, typ in tm.items(): + if isinstance(expr, NameExpr): + node = expr.node + assert isinstance(node, Var) + all_captures[node].append((expr, typ)) + + inferred_types: Dict[Var, Type] = {} + for var, captures in all_captures.items(): + already_exists = False + types: List[Type] = [] + for expr, typ in captures: + types.append(typ) + + previous_type, _, _ = self.check_lvalue(expr) + if previous_type is not None: + already_exists = True + if self.check_subtype(typ, previous_type, expr, + msg=message_registry.INCOMPATIBLE_TYPES_IN_CAPTURE, + subtype_label="pattern captures type", + supertype_label="variable has type"): + inferred_types[var] = previous_type + + if not already_exists: + new_type = UnionType.make_union(types) + # Infer the union type at the first occurrence + first_occurrence, _ = captures[0] + inferred_types[var] = new_type + self.infer_variable_type(var, first_occurrence, new_type, first_occurrence) + return inferred_types + + def remove_capture_conflicts(self, type_map: TypeMap, inferred_types: Dict[Var, Type]) -> None: + if type_map: + for expr, typ in list(type_map.items()): + if isinstance(expr, NameExpr): + node = expr.node + assert isinstance(node, Var) + if node not in inferred_types or not is_subtype(typ, inferred_types[node]): + del type_map[expr] + def make_fake_typeinfo(self, curr_module_fullname: str, class_gen_name: str, @@ -4268,11 +4559,14 @@ def is_type_call(expr: CallExpr) -> bool: if_maps: List[TypeMap] = [] else_maps: List[TypeMap] = [] for expr in exprs_in_type_calls: - current_if_map, current_else_map = self.conditional_type_map_with_intersection( - expr, + current_if_type, current_else_type = self.conditional_types_with_intersection( type_map[expr], - type_being_compared + type_being_compared, + expr ) + current_if_map, current_else_map = conditional_types_to_typemaps(expr, + current_if_type, + current_else_type) if_maps.append(current_if_map) else_maps.append(current_else_map) @@ -4328,10 +4622,13 @@ def find_isinstance_check_helper(self, node: Expression) -> Tuple[TypeMap, TypeM if len(node.args) != 2: # the error will be reported elsewhere return {}, {} if literal(expr) == LITERAL_TYPE: - return self.conditional_type_map_with_intersection( + return conditional_types_to_typemaps( expr, - type_map[expr], - get_isinstance_type(node.args[1], type_map), + *self.conditional_types_with_intersection( + type_map[expr], + get_isinstance_type(node.args[1], type_map), + expr + ) ) elif refers_to_fullname(node.callee, 'builtins.issubclass'): if len(node.args) != 2: # the error will be reported elsewhere @@ -4550,17 +4847,16 @@ def has_no_custom_eq_checks(t: Type) -> bool: 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_type = true_only(vartype) + else_type = false_only(vartype) if_map = ( - {ref: if_type} - if not isinstance(get_proper_type(if_type), UninhabitedType) + {node: if_type} + if not isinstance(if_type, UninhabitedType) else None ) else_map = ( - {ref: else_type} - if not isinstance(get_proper_type(else_type), UninhabitedType) + {node: else_type} + if not isinstance(else_type, UninhabitedType) else None ) return if_map, else_map @@ -4850,10 +5146,11 @@ def refine_identity_comparison_expression(self, 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 + # We intentionally use 'conditional_types' directly here instead of + # 'self.conditional_types_with_intersection': we only compute ad-hoc # intersections when working with pure instances. - partial_type_maps.append(conditional_type_map(expr, expr_type, target_type)) + types = conditional_types(expr_type, target_type) + partial_type_maps.append(conditional_types_to_typemaps(expr, *types)) return reduce_conditional_maps(partial_type_maps) @@ -5280,54 +5577,72 @@ def infer_issubclass_maps(self, node: CallExpr, # Any other object whose type we don't know precisely # for example, Any or a custom metaclass. return {}, {} # unknown type - yes_map, no_map = self.conditional_type_map_with_intersection(expr, vartype, type) + yes_type, no_type = self.conditional_types_with_intersection(vartype, type, expr) + yes_map, no_map = conditional_types_to_typemaps(expr, yes_type, no_type) yes_map, no_map = map(convert_to_typetype, (yes_map, no_map)) return yes_map, no_map - def conditional_type_map_with_intersection(self, - expr: Expression, - expr_type: Type, - type_ranges: Optional[List[TypeRange]], - ) -> Tuple[TypeMap, TypeMap]: - # For some reason, doing "yes_map, no_map = conditional_type_maps(...)" + @overload + def conditional_types_with_intersection(self, + expr_type: Type, + type_ranges: Optional[List[TypeRange]], + ctx: Context, + default: None = None + ) -> Tuple[Optional[Type], Optional[Type]]: ... + + @overload + def conditional_types_with_intersection(self, + expr_type: Type, + type_ranges: Optional[List[TypeRange]], + ctx: Context, + default: Type + ) -> Tuple[Type, Type]: ... + + def conditional_types_with_intersection(self, + expr_type: Type, + type_ranges: Optional[List[TypeRange]], + ctx: Context, + default: Optional[Type] = None + ) -> Tuple[Optional[Type], Optional[Type]]: + initial_types = conditional_types(expr_type, type_ranges, default) + # For some reason, doing "yes_map, no_map = conditional_types_to_typemaps(...)" # doesn't work: mypyc will decide that 'yes_map' is of type None if we try. - initial_maps = conditional_type_map(expr, expr_type, type_ranges) - yes_map: TypeMap = initial_maps[0] - no_map: TypeMap = initial_maps[1] + yes_type: Optional[Type] = initial_types[0] + no_type: Optional[Type] = initial_types[1] - if yes_map is not None or type_ranges is None: - return yes_map, no_map + if not isinstance(get_proper_type(yes_type), UninhabitedType) or type_ranges is None: + return yes_type, no_type - # If conditions_type_map was unable to successfully narrow the expr_type + # If conditional_types was unable to successfully narrow the expr_type # using the type_ranges and concluded if-branch is unreachable, we try # computing it again using a different algorithm that tries to generate # an ad-hoc intersection between the expr_type and the type_ranges. - expr_type = get_proper_type(expr_type) - if isinstance(expr_type, UnionType): - possible_expr_types = get_proper_types(expr_type.relevant_items()) + proper_type = get_proper_type(expr_type) + if isinstance(proper_type, UnionType): + possible_expr_types = get_proper_types(proper_type.relevant_items()) else: - possible_expr_types = [expr_type] + possible_expr_types = [proper_type] possible_target_types = [] for tr in type_ranges: item = get_proper_type(tr.item) if not isinstance(item, Instance) or tr.is_upper_bound: - return yes_map, no_map + return yes_type, no_type possible_target_types.append(item) out = [] for v in possible_expr_types: if not isinstance(v, Instance): - return yes_map, no_map + return yes_type, no_type for t in possible_target_types: - intersection = self.intersect_instances((v, t), expr) + intersection = self.intersect_instances((v, t), ctx) if intersection is None: continue out.append(intersection) if len(out) == 0: - return None, {} + return UninhabitedType(), expr_type new_yes_type = make_simplified_union(out) - return {expr: new_yes_type}, {} + return new_yes_type, expr_type def is_writable_attribute(self, node: Node) -> bool: """Check if an attribute is writable""" @@ -5340,48 +5655,83 @@ def is_writable_attribute(self, node: Node) -> bool: return False -def conditional_type_map(expr: Expression, - current_type: Optional[Type], - proposed_type_ranges: Optional[List[TypeRange]], - ) -> Tuple[TypeMap, TypeMap]: - """Takes in an expression, the current type of the expression, and a - proposed type of that expression. +@overload +def conditional_types(current_type: Type, + proposed_type_ranges: Optional[List[TypeRange]], + default: None = None + ) -> Tuple[Optional[Type], Optional[Type]]: ... + + +@overload +def conditional_types(current_type: Type, + proposed_type_ranges: Optional[List[TypeRange]], + default: Type + ) -> Tuple[Type, Type]: ... + - Returns a 2-tuple: The first element is a map from the expression to - the proposed type, if the expression can be the proposed type. The - second element is a map from the expression to the type it would hold - if it was not the proposed type, if any. None means bot, {} means top""" +def conditional_types(current_type: Type, + proposed_type_ranges: Optional[List[TypeRange]], + default: Optional[Type] = None + ) -> Tuple[Optional[Type], Optional[Type]]: + """Takes in the current type and a proposed type of an expression. + + Returns a 2-tuple: The first element is the proposed type, if the expression + can be the proposed type. The second element is the type it would hold + if it was not the proposed type, if any. UninhabitedType means unreachable. + None means no new information can be inferred. If default is set it is returned + instead.""" if proposed_type_ranges: + if len(proposed_type_ranges) == 1: + target = proposed_type_ranges[0].item + target = get_proper_type(target) + if isinstance(target, LiteralType) and (target.is_enum_literal() + or isinstance(target.value, bool)): + enum_name = target.fallback.type.fullname + current_type = try_expanding_sum_type_to_union(current_type, + enum_name) proposed_items = [type_range.item for type_range in proposed_type_ranges] proposed_type = make_simplified_union(proposed_items) - if current_type: - if isinstance(proposed_type, AnyType): - # We don't really know much about the proposed type, so we shouldn't - # attempt to narrow anything. Instead, we broaden the expr to Any to - # avoid false positives - return {expr: proposed_type}, {} - elif (not any(type_range.is_upper_bound for type_range in proposed_type_ranges) - and is_proper_subtype(current_type, proposed_type)): - # Expression is always of one of the types in proposed_type_ranges - return {}, None - elif not is_overlapping_types(current_type, proposed_type, - prohibit_none_typevar_overlap=True): - # Expression is never of any type in proposed_type_ranges - return None, {} - else: - # we can only restrict when the type is precise, not bounded - 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} + if isinstance(proposed_type, AnyType): + # We don't really know much about the proposed type, so we shouldn't + # attempt to narrow anything. Instead, we broaden the expr to Any to + # avoid false positives + return proposed_type, default + elif (not any(type_range.is_upper_bound for type_range in proposed_type_ranges) + and is_proper_subtype(current_type, proposed_type)): + # Expression is always of one of the types in proposed_type_ranges + return default, UninhabitedType() + elif not is_overlapping_types(current_type, proposed_type, + prohibit_none_typevar_overlap=True): + # Expression is never of any type in proposed_type_ranges + return UninhabitedType(), default else: - return {expr: proposed_type}, {} + # we can only restrict when the type is precise, not bounded + 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 proposed_type, remaining_type else: # An isinstance check, but we don't understand the type - return {}, {} + return current_type, default + + +def conditional_types_to_typemaps(expr: Expression, + yes_type: Optional[Type], + no_type: Optional[Type] + ) -> Tuple[TypeMap, TypeMap]: + maps: List[TypeMap] = [] + for typ in (yes_type, no_type): + proper_type = get_proper_type(typ) + if isinstance(proper_type, UninhabitedType): + maps.append(None) + elif proper_type is None: + maps.append({}) + else: + assert typ is not None + maps.append({expr: typ}) + + return cast(Tuple[TypeMap, TypeMap], tuple(maps)) def gen_unique_name(base: str, table: SymbolTable) -> str: @@ -6191,6 +6541,11 @@ def is_private(node_name: str) -> bool: return node_name.startswith('__') and not node_name.endswith('__') +def is_string_literal(typ: Type) -> bool: + strs = try_getting_str_literals_from_type(typ) + return strs is not None and len(strs) == 1 + + def has_bool_item(typ: ProperType) -> bool: """Return True if type is 'bool' or a union with a 'bool' item.""" if is_named_instance(typ, 'builtins.bool'): diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 1647339ef217..4ece9ac4c94b 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -1,11 +1,10 @@ """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 + cast, Dict, Set, List, Tuple, Callable, Union, Optional, Sequence, Iterator ) from typing_extensions import ClassVar, Final, overload, TypeAlias as _TypeAlias @@ -21,7 +20,7 @@ PartialType, DeletedType, UninhabitedType, TypeType, TypeOfAny, LiteralType, LiteralValue, is_named_instance, FunctionLike, ParamSpecType, ParamSpecFlavor, StarType, is_optional, remove_optional, is_generic_instance, get_proper_type, ProperType, - get_proper_types, flatten_nested_unions + get_proper_types, flatten_nested_unions, LITERAL_TYPE_NAMES, ) from mypy.nodes import ( NameExpr, RefExpr, Var, FuncDef, OverloadedFuncDef, TypeInfo, CallExpr, @@ -347,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 @@ -385,6 +378,8 @@ def visit_call_expr_inner(self, e: CallExpr, allow_none_return: bool = False) -> if isinstance(e.callee, MemberExpr) and e.callee.name == 'format': self.check_str_format_call(e) ret_type = get_proper_type(ret_type) + if isinstance(ret_type, UnionType): + ret_type = make_simplified_union(ret_type.items) if isinstance(ret_type, UninhabitedType) and not ret_type.ambiguous: self.chk.binder.unreachable() # Warn on calls to functions that always return None. The check @@ -1612,8 +1607,7 @@ def check_overload_call(self, # Record if we succeeded. Next we need to see if maybe normal procedure # gives a narrower type. if unioned_return: - # TODO: fix signature of zip() in typeshed. - returns, inferred_types = cast(Any, zip)(*unioned_return) + returns, inferred_types = zip(*unioned_return) # Note that we use `combine_function_signatures` instead of just returning # a union of inferred callables because for example a call # Union[int -> int, str -> str](Union[int, str]) is invalid and @@ -2071,11 +2065,19 @@ def check_union_call(self, arg_names: Optional[Sequence[Optional[str]]], context: Context, arg_messages: MessageBuilder) -> Tuple[Type, Type]: - self.msg.disable_type_names += 1 - results = [self.check_call(subtype, args, arg_kinds, context, arg_names, - arg_messages=arg_messages) - for subtype in callee.relevant_items()] - self.msg.disable_type_names -= 1 + with self.msg.disable_type_names(): + results = [ + self.check_call( + subtype, + args, + arg_kinds, + context, + arg_names, + arg_messages=arg_messages, + ) + for subtype in callee.relevant_items() + ] + return (make_simplified_union([res[0] for res in results]), callee) @@ -2204,7 +2206,7 @@ def visit_op_expr(self, e: OpExpr) -> Type: return self.strfrm_checker.check_str_interpolation(e.left, e.right) if isinstance(e.left, StrExpr): return self.strfrm_checker.check_str_interpolation(e.left, e.right) - elif pyversion[0] <= 2: + elif pyversion[0] == 2: if isinstance(e.left, (StrExpr, BytesExpr, UnicodeExpr)): return self.strfrm_checker.check_str_interpolation(e.left, e.right) left_type = self.accept(e.left) @@ -2414,8 +2416,11 @@ def dangerous_comparison(self, left: Type, right: Type, def get_operator_method(self, op: str) -> str: if op == '/' and self.chk.options.python_version[0] == 2: - # TODO also check for "from __future__ import division" - return '__div__' + return ( + '__truediv__' + if self.chk.tree.is_future_flag_set('division') + else '__div__' + ) else: return operators.op_methods[op] @@ -2469,11 +2474,11 @@ def check_union_method_call_by_name(self, for typ in base_type.relevant_items(): # Format error messages consistently with # mypy.checkmember.analyze_union_member_access(). - local_errors.disable_type_names += 1 - item, meth_item = self.check_method_call_by_name(method, typ, args, arg_kinds, - context, local_errors, - original_type) - local_errors.disable_type_names -= 1 + with local_errors.disable_type_names(): + item, meth_item = self.check_method_call_by_name( + method, typ, args, arg_kinds, + context, local_errors, original_type, + ) res.append(item) meth_res.append(meth_item) return make_simplified_union(res), make_simplified_union(meth_res) @@ -3076,7 +3081,11 @@ def nonliteral_tuple_index_helper(self, left_type: TupleType, index: Expression) else: return union - def visit_typeddict_index_expr(self, td_type: TypedDictType, index: Expression) -> Type: + def visit_typeddict_index_expr(self, td_type: TypedDictType, + index: Expression, + local_errors: Optional[MessageBuilder] = None + ) -> Type: + local_errors = local_errors or self.msg if isinstance(index, (StrExpr, UnicodeExpr)): key_names = [index.value] else: @@ -3096,14 +3105,14 @@ def visit_typeddict_index_expr(self, td_type: TypedDictType, index: Expression) and key_type.fallback.type.fullname != 'builtins.bytes'): key_names.append(key_type.value) else: - self.msg.typeddict_key_must_be_string_literal(td_type, index) + local_errors.typeddict_key_must_be_string_literal(td_type, index) return AnyType(TypeOfAny.from_error) value_types = [] for key_name in key_names: value_type = td_type.items.get(key_name) if value_type is None: - self.msg.typeddict_key_not_found(td_type, key_name, index) + local_errors.typeddict_key_not_found(td_type, key_name, index) return AnyType(TypeOfAny.from_error) else: value_types.append(value_type) @@ -4550,10 +4559,9 @@ def try_getting_literal(typ: Type) -> ProperType: def is_expr_literal_type(node: Expression) -> bool: """Returns 'true' if the given node is a Literal""" - valid = ('typing.Literal', 'typing_extensions.Literal') if isinstance(node, IndexExpr): base = node.base - return isinstance(base, RefExpr) and base.fullname in valid + return isinstance(base, RefExpr) and base.fullname in LITERAL_TYPE_NAMES if isinstance(node, NameExpr): underlying = node.node return isinstance(underlying, TypeAlias) and isinstance(get_proper_type(underlying.target), diff --git a/mypy/checkmember.py b/mypy/checkmember.py index c01f52de5a77..e7af3978867f 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -6,7 +6,8 @@ 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, ParamSpecType + DeletedType, NoneType, TypeType, has_type_vars, get_proper_type, ProperType, ParamSpecType, + ENUM_REMOVED_PROPS ) from mypy.nodes import ( TypeInfo, FuncBase, Var, FuncDef, SymbolNode, SymbolTable, Context, @@ -311,13 +312,12 @@ def analyze_type_type_member_access(name: str, def analyze_union_member_access(name: str, typ: UnionType, mx: MemberContext) -> Type: - mx.msg.disable_type_names += 1 - results = [] - for subtype in typ.relevant_items(): - # Self types should be bound to every individual item of a union. - item_mx = mx.copy_modified(self_type=subtype) - results.append(_analyze_member_access(name, subtype, item_mx)) - mx.msg.disable_type_names -= 1 + with mx.msg.disable_type_names(): + results = [] + for subtype in typ.relevant_items(): + # Self types should be bound to every individual item of a union. + item_mx = mx.copy_modified(self_type=subtype) + results.append(_analyze_member_access(name, subtype, item_mx)) return make_simplified_union(results) @@ -832,8 +832,8 @@ def analyze_enum_class_attribute_access(itype: Instance, name: str, mx: MemberContext, ) -> Optional[Type]: - # Skip "_order_" and "__order__", since Enum will remove it - if name in ("_order_", "__order__"): + # Skip these since Enum will remove it + if name in ENUM_REMOVED_PROPS: return mx.msg.has_no_attr( mx.original_type, itype, name, mx.context, mx.module_symbol_table ) diff --git a/mypy/checkpattern.py b/mypy/checkpattern.py new file mode 100644 index 000000000000..a20dfb714025 --- /dev/null +++ b/mypy/checkpattern.py @@ -0,0 +1,706 @@ +"""Pattern checker. This file is conceptually part of TypeChecker.""" + +from collections import defaultdict +from typing import List, Optional, Tuple, Dict, NamedTuple, Set, Union +from typing_extensions import Final + +import mypy.checker +from mypy.checkmember import analyze_member_access +from mypy.expandtype import expand_type_by_instance +from mypy.join import join_types +from mypy.literals import literal_hash +from mypy.maptype import map_instance_to_supertype +from mypy.meet import narrow_declared_type +from mypy import message_registry +from mypy.messages import MessageBuilder +from mypy.nodes import Expression, ARG_POS, TypeAlias, TypeInfo, Var, NameExpr +from mypy.patterns import ( + Pattern, AsPattern, OrPattern, ValuePattern, SequencePattern, StarredPattern, MappingPattern, + ClassPattern, SingletonPattern +) +from mypy.plugin import Plugin +from mypy.subtypes import is_subtype +from mypy.typeops import try_getting_str_literals_from_type, make_simplified_union, \ + coerce_to_literal +from mypy.types import ( + ProperType, AnyType, TypeOfAny, Instance, Type, UninhabitedType, get_proper_type, + TypedDictType, TupleType, NoneType, UnionType +) +from mypy.typevars import fill_typevars +from mypy.visitor import PatternVisitor + +self_match_type_names: Final = [ + "builtins.bool", + "builtins.bytearray", + "builtins.bytes", + "builtins.dict", + "builtins.float", + "builtins.frozenset", + "builtins.int", + "builtins.list", + "builtins.set", + "builtins.str", + "builtins.tuple", +] + +non_sequence_match_type_names: Final = [ + "builtins.str", + "builtins.bytes", + "builtins.bytearray" +] + + +# For every Pattern a PatternType can be calculated. This requires recursively calculating +# the PatternTypes of the sub-patterns first. +# Using the data in the PatternType the match subject and captured names can be narrowed/inferred. +PatternType = NamedTuple( + 'PatternType', + [ + ('type', Type), # The type the match subject can be narrowed to + ('rest_type', Type), # The remaining type if the pattern didn't match + ('captures', Dict[Expression, Type]), # The variables captured by the pattern + ]) + + +class PatternChecker(PatternVisitor[PatternType]): + """Pattern checker. + + This class checks if a pattern can match a type, what the type can be narrowed to, and what + type capture patterns should be inferred as. + """ + + # Some services are provided by a TypeChecker instance. + chk: 'mypy.checker.TypeChecker' + # This is shared with TypeChecker, but stored also here for convenience. + msg: MessageBuilder + # Currently unused + plugin: Plugin + # The expression being matched against the pattern + subject: Expression + + subject_type: Type + # Type of the subject to check the (sub)pattern against + type_context: List[Type] + # Types that match against self instead of their __match_args__ if used as a class pattern + # Filled in from self_match_type_names + self_match_types: List[Type] + # Types that are sequences, but don't match sequence patterns. Filled in from + # non_sequence_match_type_names + non_sequence_match_types: List[Type] + + def __init__(self, + chk: 'mypy.checker.TypeChecker', + msg: MessageBuilder, plugin: Plugin + ) -> None: + self.chk = chk + self.msg = msg + self.plugin = plugin + + self.type_context = [] + self.self_match_types = self.generate_types_from_names(self_match_type_names) + self.non_sequence_match_types = self.generate_types_from_names( + non_sequence_match_type_names + ) + + def accept(self, o: Pattern, type_context: Type) -> PatternType: + self.type_context.append(type_context) + result = o.accept(self) + self.type_context.pop() + + return result + + def visit_as_pattern(self, o: AsPattern) -> PatternType: + current_type = self.type_context[-1] + if o.pattern is not None: + pattern_type = self.accept(o.pattern, current_type) + typ, rest_type, type_map = pattern_type + else: + typ, rest_type, type_map = current_type, UninhabitedType(), {} + + if not is_uninhabited(typ) and o.name is not None: + typ, _ = self.chk.conditional_types_with_intersection(current_type, + [get_type_range(typ)], + o, + default=current_type) + if not is_uninhabited(typ): + type_map[o.name] = typ + + return PatternType(typ, rest_type, type_map) + + def visit_or_pattern(self, o: OrPattern) -> PatternType: + current_type = self.type_context[-1] + + # + # Check all the subpatterns + # + pattern_types = [] + for pattern in o.patterns: + pattern_type = self.accept(pattern, current_type) + pattern_types.append(pattern_type) + current_type = pattern_type.rest_type + + # + # Collect the final type + # + types = [] + for pattern_type in pattern_types: + if not is_uninhabited(pattern_type.type): + types.append(pattern_type.type) + + # + # Check the capture types + # + capture_types: Dict[Var, List[Tuple[Expression, Type]]] = defaultdict(list) + # Collect captures from the first subpattern + for expr, typ in pattern_types[0].captures.items(): + node = get_var(expr) + capture_types[node].append((expr, typ)) + + # Check if other subpatterns capture the same names + for i, pattern_type in enumerate(pattern_types[1:]): + vars = {get_var(expr) for expr, _ in pattern_type.captures.items()} + if capture_types.keys() != vars: + self.msg.fail(message_registry.OR_PATTERN_ALTERNATIVE_NAMES, o.patterns[i]) + for expr, typ in pattern_type.captures.items(): + node = get_var(expr) + capture_types[node].append((expr, typ)) + + captures: Dict[Expression, Type] = {} + for var, capture_list in capture_types.items(): + typ = UninhabitedType() + for _, other in capture_list: + typ = join_types(typ, other) + + captures[capture_list[0][0]] = typ + + union_type = make_simplified_union(types) + return PatternType(union_type, current_type, captures) + + def visit_value_pattern(self, o: ValuePattern) -> PatternType: + current_type = self.type_context[-1] + typ = self.chk.expr_checker.accept(o.expr) + typ = coerce_to_literal(typ) + narrowed_type, rest_type = self.chk.conditional_types_with_intersection( + current_type, + [get_type_range(typ)], + o, + default=current_type + ) + return PatternType(narrowed_type, rest_type, {}) + + def visit_singleton_pattern(self, o: SingletonPattern) -> PatternType: + current_type = self.type_context[-1] + value: Union[bool, None] = o.value + if isinstance(value, bool): + typ = self.chk.expr_checker.infer_literal_expr_type(value, "builtins.bool") + elif value is None: + typ = NoneType() + else: + assert False + + narrowed_type, rest_type = self.chk.conditional_types_with_intersection( + current_type, + [get_type_range(typ)], + o, + default=current_type + ) + return PatternType(narrowed_type, rest_type, {}) + + def visit_sequence_pattern(self, o: SequencePattern) -> PatternType: + # + # check for existence of a starred pattern + # + current_type = get_proper_type(self.type_context[-1]) + if not self.can_match_sequence(current_type): + return self.early_non_match() + star_positions = [i for i, p in enumerate(o.patterns) if isinstance(p, StarredPattern)] + star_position: Optional[int] = None + if len(star_positions) == 1: + star_position = star_positions[0] + elif len(star_positions) >= 2: + assert False, "Parser should prevent multiple starred patterns" + required_patterns = len(o.patterns) + if star_position is not None: + required_patterns -= 1 + + # + # get inner types of original type + # + if isinstance(current_type, TupleType): + inner_types = current_type.items + size_diff = len(inner_types) - required_patterns + if size_diff < 0: + return self.early_non_match() + elif size_diff > 0 and star_position is None: + return self.early_non_match() + else: + inner_type = self.get_sequence_type(current_type) + if inner_type is None: + inner_type = self.chk.named_type("builtins.object") + inner_types = [inner_type] * len(o.patterns) + + # + # match inner patterns + # + contracted_new_inner_types: List[Type] = [] + contracted_rest_inner_types: List[Type] = [] + captures: Dict[Expression, Type] = {} + + contracted_inner_types = self.contract_starred_pattern_types(inner_types, + star_position, + required_patterns) + can_match = True + for p, t in zip(o.patterns, contracted_inner_types): + pattern_type = self.accept(p, t) + typ, rest, type_map = pattern_type + if is_uninhabited(typ): + can_match = False + else: + contracted_new_inner_types.append(typ) + contracted_rest_inner_types.append(rest) + self.update_type_map(captures, type_map) + new_inner_types = self.expand_starred_pattern_types(contracted_new_inner_types, + star_position, + len(inner_types)) + rest_inner_types = self.expand_starred_pattern_types(contracted_rest_inner_types, + star_position, + len(inner_types)) + + # + # Calculate new type + # + new_type: Type + rest_type: Type = current_type + if not can_match: + new_type = UninhabitedType() + elif isinstance(current_type, TupleType): + narrowed_inner_types = [] + inner_rest_types = [] + for inner_type, new_inner_type in zip(inner_types, new_inner_types): + narrowed_inner_type, inner_rest_type = \ + self.chk.conditional_types_with_intersection( + new_inner_type, + [get_type_range(inner_type)], + o, + default=new_inner_type + ) + narrowed_inner_types.append(narrowed_inner_type) + inner_rest_types.append(inner_rest_type) + if all(not is_uninhabited(typ) for typ in narrowed_inner_types): + new_type = TupleType(narrowed_inner_types, current_type.partial_fallback) + else: + new_type = UninhabitedType() + + if all(is_uninhabited(typ) for typ in inner_rest_types): + # All subpatterns always match, so we can apply negative narrowing + rest_type = TupleType(rest_inner_types, current_type.partial_fallback) + else: + new_inner_type = UninhabitedType() + for typ in new_inner_types: + new_inner_type = join_types(new_inner_type, typ) + new_type = self.construct_sequence_child(current_type, new_inner_type) + if is_subtype(new_type, current_type): + new_type, _ = self.chk.conditional_types_with_intersection( + current_type, + [get_type_range(new_type)], + o, + default=current_type + ) + else: + new_type = current_type + return PatternType(new_type, rest_type, captures) + + def get_sequence_type(self, t: Type) -> Optional[Type]: + t = get_proper_type(t) + if isinstance(t, AnyType): + return AnyType(TypeOfAny.from_another_any, t) + if isinstance(t, UnionType): + items = [self.get_sequence_type(item) for item in t.items] + not_none_items = [item for item in items if item is not None] + if len(not_none_items) > 0: + return make_simplified_union(not_none_items) + else: + return None + + if self.chk.type_is_iterable(t) and isinstance(t, Instance): + return self.chk.iterable_item_type(t) + else: + return None + + def contract_starred_pattern_types(self, + types: List[Type], + star_pos: Optional[int], + num_patterns: int + ) -> List[Type]: + """ + Contracts a list of types in a sequence pattern depending on the position of a starred + capture pattern. + + For example if the sequence pattern [a, *b, c] is matched against types [bool, int, str, + bytes] the contracted types are [bool, Union[int, str], bytes]. + + If star_pos in None the types are returned unchanged. + """ + if star_pos is None: + return types + new_types = types[:star_pos] + star_length = len(types) - num_patterns + new_types.append(make_simplified_union(types[star_pos:star_pos+star_length])) + new_types += types[star_pos+star_length:] + + return new_types + + def expand_starred_pattern_types(self, + types: List[Type], + star_pos: Optional[int], + num_types: int + ) -> List[Type]: + """Undoes the contraction done by contract_starred_pattern_types. + + For example if the sequence pattern is [a, *b, c] and types [bool, int, str] are extended + to lenght 4 the result is [bool, int, int, str]. + """ + if star_pos is None: + return types + new_types = types[:star_pos] + star_length = num_types - len(types) + 1 + new_types += [types[star_pos]] * star_length + new_types += types[star_pos+1:] + + return new_types + + def visit_starred_pattern(self, o: StarredPattern) -> PatternType: + captures: Dict[Expression, Type] = {} + if o.capture is not None: + list_type = self.chk.named_generic_type('builtins.list', [self.type_context[-1]]) + captures[o.capture] = list_type + return PatternType(self.type_context[-1], UninhabitedType(), captures) + + def visit_mapping_pattern(self, o: MappingPattern) -> PatternType: + current_type = get_proper_type(self.type_context[-1]) + can_match = True + captures: Dict[Expression, Type] = {} + for key, value in zip(o.keys, o.values): + inner_type = self.get_mapping_item_type(o, current_type, key) + if inner_type is None: + can_match = False + inner_type = self.chk.named_type("builtins.object") + pattern_type = self.accept(value, inner_type) + if is_uninhabited(pattern_type.type): + can_match = False + else: + self.update_type_map(captures, pattern_type.captures) + + if o.rest is not None: + mapping = self.chk.named_type("typing.Mapping") + if is_subtype(current_type, mapping) and isinstance(current_type, Instance): + mapping_inst = map_instance_to_supertype(current_type, mapping.type) + dict_typeinfo = self.chk.lookup_typeinfo("builtins.dict") + dict_type = fill_typevars(dict_typeinfo) + rest_type = expand_type_by_instance(dict_type, mapping_inst) + else: + object_type = self.chk.named_type("builtins.object") + rest_type = self.chk.named_generic_type("builtins.dict", + [object_type, object_type]) + + captures[o.rest] = rest_type + + if can_match: + # We can't narrow the type here, as Mapping key is invariant. + new_type = self.type_context[-1] + else: + new_type = UninhabitedType() + return PatternType(new_type, current_type, captures) + + def get_mapping_item_type(self, + pattern: MappingPattern, + mapping_type: Type, + key: Expression + ) -> Optional[Type]: + local_errors = self.msg.clean_copy() + local_errors.disable_count = 0 + mapping_type = get_proper_type(mapping_type) + if isinstance(mapping_type, TypedDictType): + result: Optional[Type] = self.chk.expr_checker.visit_typeddict_index_expr( + mapping_type, key, local_errors=local_errors) + # If we can't determine the type statically fall back to treating it as a normal + # mapping + if local_errors.is_errors(): + local_errors = self.msg.clean_copy() + local_errors.disable_count = 0 + result = self.get_simple_mapping_item_type(pattern, + mapping_type, + key, + local_errors) + + if local_errors.is_errors(): + result = None + else: + result = self.get_simple_mapping_item_type(pattern, + mapping_type, + key, + local_errors) + return result + + def get_simple_mapping_item_type(self, + pattern: MappingPattern, + mapping_type: Type, + key: Expression, + local_errors: MessageBuilder + ) -> Type: + result, _ = self.chk.expr_checker.check_method_call_by_name('__getitem__', + mapping_type, + [key], + [ARG_POS], + pattern, + local_errors=local_errors) + return result + + def visit_class_pattern(self, o: ClassPattern) -> PatternType: + current_type = get_proper_type(self.type_context[-1]) + + # + # Check class type + # + type_info = o.class_ref.node + if type_info is None: + return PatternType(AnyType(TypeOfAny.from_error), AnyType(TypeOfAny.from_error), {}) + if isinstance(type_info, TypeAlias) and not type_info.no_args: + self.msg.fail(message_registry.CLASS_PATTERN_GENERIC_TYPE_ALIAS, o) + return self.early_non_match() + if isinstance(type_info, TypeInfo): + any_type = AnyType(TypeOfAny.implementation_artifact) + typ: Type = Instance(type_info, [any_type] * len(type_info.defn.type_vars)) + elif isinstance(type_info, TypeAlias): + typ = type_info.target + else: + if isinstance(type_info, Var): + name = str(type_info.type) + else: + name = type_info.name + self.msg.fail(message_registry.CLASS_PATTERN_TYPE_REQUIRED.format(name), o.class_ref) + return self.early_non_match() + + new_type, rest_type = self.chk.conditional_types_with_intersection( + current_type, [get_type_range(typ)], o, default=current_type + ) + if is_uninhabited(new_type): + return self.early_non_match() + # TODO: Do I need this? + narrowed_type = narrow_declared_type(current_type, new_type) + + # + # Convert positional to keyword patterns + # + keyword_pairs: List[Tuple[Optional[str], Pattern]] = [] + match_arg_set: Set[str] = set() + + captures: Dict[Expression, Type] = {} + + if len(o.positionals) != 0: + if self.should_self_match(typ): + if len(o.positionals) > 1: + self.msg.fail(message_registry.CLASS_PATTERN_TOO_MANY_POSITIONAL_ARGS, o) + pattern_type = self.accept(o.positionals[0], narrowed_type) + if not is_uninhabited(pattern_type.type): + return PatternType(pattern_type.type, + join_types(rest_type, pattern_type.rest_type), + pattern_type.captures) + captures = pattern_type.captures + else: + local_errors = self.msg.clean_copy() + match_args_type = analyze_member_access("__match_args__", typ, o, + False, False, False, + local_errors, + original_type=typ, + chk=self.chk) + + if local_errors.is_errors(): + self.msg.fail(message_registry.MISSING_MATCH_ARGS.format(typ), o) + return self.early_non_match() + + proper_match_args_type = get_proper_type(match_args_type) + if isinstance(proper_match_args_type, TupleType): + match_arg_names = get_match_arg_names(proper_match_args_type) + + if len(o.positionals) > len(match_arg_names): + self.msg.fail(message_registry.CLASS_PATTERN_TOO_MANY_POSITIONAL_ARGS, o) + return self.early_non_match() + else: + match_arg_names = [None] * len(o.positionals) + + for arg_name, pos in zip(match_arg_names, o.positionals): + keyword_pairs.append((arg_name, pos)) + if arg_name is not None: + match_arg_set.add(arg_name) + + # + # Check for duplicate patterns + # + keyword_arg_set = set() + has_duplicates = False + for key, value in zip(o.keyword_keys, o.keyword_values): + keyword_pairs.append((key, value)) + if key in match_arg_set: + self.msg.fail( + message_registry.CLASS_PATTERN_KEYWORD_MATCHES_POSITIONAL.format(key), + value + ) + has_duplicates = True + elif key in keyword_arg_set: + self.msg.fail(message_registry.CLASS_PATTERN_DUPLICATE_KEYWORD_PATTERN.format(key), + value) + has_duplicates = True + keyword_arg_set.add(key) + + if has_duplicates: + return self.early_non_match() + + # + # Check keyword patterns + # + can_match = True + for keyword, pattern in keyword_pairs: + key_type: Optional[Type] = None + local_errors = self.msg.clean_copy() + if keyword is not None: + key_type = analyze_member_access(keyword, + narrowed_type, + pattern, + False, + False, + False, + local_errors, + original_type=new_type, + chk=self.chk) + else: + key_type = AnyType(TypeOfAny.from_error) + if local_errors.is_errors() or key_type is None: + key_type = AnyType(TypeOfAny.from_error) + self.msg.fail(message_registry.CLASS_PATTERN_UNKNOWN_KEYWORD.format(typ, keyword), + pattern) + + inner_type, inner_rest_type, inner_captures = self.accept(pattern, key_type) + if is_uninhabited(inner_type): + can_match = False + else: + self.update_type_map(captures, inner_captures) + if not is_uninhabited(inner_rest_type): + rest_type = current_type + + if not can_match: + new_type = UninhabitedType() + return PatternType(new_type, rest_type, captures) + + def should_self_match(self, typ: Type) -> bool: + typ = get_proper_type(typ) + if isinstance(typ, Instance) and typ.type.is_named_tuple: + return False + for other in self.self_match_types: + if is_subtype(typ, other): + return True + return False + + def can_match_sequence(self, typ: ProperType) -> bool: + if isinstance(typ, UnionType): + return any(self.can_match_sequence(get_proper_type(item)) for item in typ.items) + for other in self.non_sequence_match_types: + # We have to ignore promotions, as memoryview should match, but bytes, + # which it can be promoted to, shouldn't + if is_subtype(typ, other, ignore_promotions=True): + return False + sequence = self.chk.named_type("typing.Sequence") + # If the static type is more general than sequence the actual type could still match + return is_subtype(typ, sequence) or is_subtype(sequence, typ) + + def generate_types_from_names(self, type_names: List[str]) -> List[Type]: + types: List[Type] = [] + for name in type_names: + try: + types.append(self.chk.named_type(name)) + except KeyError as e: + # Some built in types are not defined in all test cases + if not name.startswith('builtins.'): + raise e + pass + + return types + + def update_type_map(self, + original_type_map: Dict[Expression, Type], + extra_type_map: Dict[Expression, Type] + ) -> None: + # Calculating this would not be needed if TypeMap directly used literal hashes instead of + # expressions, as suggested in the TODO above it's definition + already_captured = set(literal_hash(expr) for expr in original_type_map) + for expr, typ in extra_type_map.items(): + if literal_hash(expr) in already_captured: + node = get_var(expr) + self.msg.fail(message_registry.MULTIPLE_ASSIGNMENTS_IN_PATTERN.format(node.name), + expr) + else: + original_type_map[expr] = typ + + def construct_sequence_child(self, outer_type: Type, inner_type: Type) -> Type: + """ + If outer_type is a child class of typing.Sequence returns a new instance of + outer_type, that is a Sequence of inner_type. If outer_type is not a child class of + typing.Sequence just returns a Sequence of inner_type + + For example: + construct_sequence_child(List[int], str) = List[str] + """ + proper_type = get_proper_type(outer_type) + if isinstance(proper_type, UnionType): + types = [ + self.construct_sequence_child(item, inner_type) for item in proper_type.items + if self.can_match_sequence(get_proper_type(item)) + ] + return make_simplified_union(types) + sequence = self.chk.named_generic_type("typing.Sequence", [inner_type]) + if is_subtype(outer_type, self.chk.named_type("typing.Sequence")): + proper_type = get_proper_type(outer_type) + assert isinstance(proper_type, Instance) + empty_type = fill_typevars(proper_type.type) + partial_type = expand_type_by_instance(empty_type, sequence) + return expand_type_by_instance(partial_type, proper_type) + else: + return sequence + + def early_non_match(self) -> PatternType: + return PatternType(UninhabitedType(), self.type_context[-1], {}) + + +def get_match_arg_names(typ: TupleType) -> List[Optional[str]]: + args: List[Optional[str]] = [] + for item in typ.items: + values = try_getting_str_literals_from_type(item) + if values is None or len(values) != 1: + args.append(None) + else: + args.append(values[0]) + return args + + +def get_var(expr: Expression) -> Var: + """ + Warning: this in only true for expressions captured by a match statement. + Don't call it from anywhere else + """ + assert isinstance(expr, NameExpr) + node = expr.node + assert isinstance(node, Var) + return node + + +def get_type_range(typ: Type) -> 'mypy.checker.TypeRange': + typ = get_proper_type(typ) + if (isinstance(typ, Instance) + and typ.last_known_value + and isinstance(typ.last_known_value.value, bool)): + typ = typ.last_known_value + return mypy.checker.TypeRange(typ, is_upper_bound=False) + + +def is_uninhabited(typ: Type) -> bool: + return isinstance(get_proper_type(typ), UninhabitedType) diff --git a/mypy/config_parser.py b/mypy/config_parser.py index 24e61df0441c..fa57caee14a4 100644 --- a/mypy/config_parser.py +++ b/mypy/config_parser.py @@ -57,6 +57,12 @@ def expand_path(path: str) -> str: return os.path.expandvars(os.path.expanduser(path)) +def str_or_array_as_list(v: Union[str, Sequence[str]]) -> List[str]: + if isinstance(v, str): + return [v.strip()] if v.strip() else [] + return [p.strip() for p in v if p.strip()] + + def split_and_match_files_list(paths: Sequence[str]) -> List[str]: """Take a list of files/directories (with support for globbing through the glob library). @@ -126,7 +132,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()], + 'exclude': lambda s: [s.strip()], } # Reuse the ini_config_types and overwrite the diff @@ -143,6 +149,7 @@ def check_follow_imports(choice: str) -> str: 'disable_error_code': try_split, 'enable_error_code': try_split, 'package_root': try_split, + 'exclude': str_or_array_as_list, }) diff --git a/mypy/constraints.py b/mypy/constraints.py index 5a78cdb94e93..040bcff8c99d 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -8,7 +8,8 @@ TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, TypeVarId, TypeQuery, is_named_instance, TypeOfAny, LiteralType, ProperType, ParamSpecType, get_proper_type, TypeAliasType, is_union_with_any, - callable_with_ellipsis + callable_with_ellipsis, + TUPLE_LIKE_INSTANCE_NAMES, ) from mypy.maptype import map_instance_to_supertype import mypy.subtypes @@ -501,11 +502,8 @@ def visit_instance(self, template: Instance) -> List[Constraint]: return res if isinstance(actual, AnyType): return self.infer_against_any(template.args, actual) - if (isinstance(actual, TupleType) and - (is_named_instance(template, 'typing.Iterable') or - is_named_instance(template, 'typing.Container') or - is_named_instance(template, 'typing.Sequence') or - is_named_instance(template, 'typing.Reversible')) + if (isinstance(actual, TupleType) + and is_named_instance(template, TUPLE_LIKE_INSTANCE_NAMES) and self.direction == SUPERTYPE_OF): for item in actual.items: cb = infer_constraints(template.args[0], item, SUPERTYPE_OF) @@ -515,6 +513,10 @@ def visit_instance(self, template: Instance) -> List[Constraint]: return infer_constraints(template, mypy.typeops.tuple_fallback(actual), self.direction) + elif isinstance(actual, TypeVarType): + if not actual.values: + return infer_constraints(template, actual.upper_bound, self.direction) + return [] else: return [] @@ -660,8 +662,12 @@ def infer_against_any(self, types: Iterable[Type], any_type: AnyType) -> List[Co return res def visit_overloaded(self, template: Overloaded) -> List[Constraint]: + if isinstance(self.actual, CallableType): + items = find_matching_overload_items(template, self.actual) + else: + items = template.items res: List[Constraint] = [] - for t in template.items: + for t in items: res.extend(infer_constraints(t, self.actual, self.direction)) return res @@ -703,3 +709,22 @@ def find_matching_overload_item(overloaded: Overloaded, template: CallableType) # Fall back to the first item if we can't find a match. This is totally arbitrary -- # maybe we should just bail out at this point. return items[0] + + +def find_matching_overload_items(overloaded: Overloaded, + template: CallableType) -> List[CallableType]: + """Like find_matching_overload_item, but return all matches, not just the first.""" + items = overloaded.items + res = [] + for item in items: + # Return type may be indeterminate in the template, so ignore it when performing a + # subtype check. + if mypy.subtypes.is_callable_compatible(item, template, + is_compat=mypy.subtypes.is_subtype, + ignore_return=True): + res.append(item) + if not res: + # Falling back to all items if we can't find a match is pretty arbitrary, but + # it maintains backward compatibility. + res = items[:] + return res diff --git a/mypy/erasetype.py b/mypy/erasetype.py index 8acebbd783d8..f33b4f3a95cc 100644 --- a/mypy/erasetype.py +++ b/mypy/erasetype.py @@ -1,10 +1,10 @@ -from typing import Optional, Container, Callable +from typing import Optional, Container, Callable, List, Dict, cast from mypy.types import ( 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, ParamSpecType + get_proper_type, get_proper_types, TypeAliasType, ParamSpecType ) from mypy.nodes import ARG_STAR, ARG_STAR2 @@ -41,8 +41,7 @@ def visit_uninhabited_type(self, t: UninhabitedType) -> ProperType: return t def visit_erased_type(self, t: ErasedType) -> ProperType: - # Should not get here. - raise RuntimeError() + return t def visit_partial_type(self, t: PartialType) -> ProperType: # Should not get here. @@ -162,3 +161,34 @@ def visit_type_alias_type(self, t: TypeAliasType) -> Type: # Type aliases can't contain literal values, because they are # always constructed as explicit types. return t + + def visit_union_type(self, t: UnionType) -> Type: + new = cast(UnionType, super().visit_union_type(t)) + # Erasure can result in many duplicate items; merge them. + # Call make_simplified_union only on lists of instance types + # that all have the same fullname, to avoid simplifying too + # much. + instances = [item for item in new.items + if isinstance(get_proper_type(item), Instance)] + # Avoid merge in simple cases such as optional types. + if len(instances) > 1: + instances_by_name: Dict[str, List[Instance]] = {} + new_items = get_proper_types(new.items) + for item in new_items: + if isinstance(item, Instance) and not item.args: + instances_by_name.setdefault(item.type.fullname, []).append(item) + merged: List[Type] = [] + for item in new_items: + if isinstance(item, Instance) and not item.args: + types = instances_by_name.get(item.type.fullname) + if types is not None: + if len(types) == 1: + merged.append(item) + else: + from mypy.typeops import make_simplified_union + merged.append(make_simplified_union(types)) + del instances_by_name[item.type.fullname] + else: + merged.append(item) + return UnionType.make_union(merged) + return new diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index 2a07bbb8597b..4407df47d596 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -94,6 +94,9 @@ def __str__(self) -> str: EXIT_RETURN: Final = ErrorCode( "exit-return", "Warn about too general return type for '__exit__'", "General" ) +LITERAL_REQ: Final = ErrorCode( + "literal-required", "Check that value is a literal", 'General' +) # These error codes aren't enabled by default. NO_UNTYPED_DEF: Final[ErrorCode] = ErrorCode( @@ -133,10 +136,26 @@ def __str__(self) -> str: NAME_MATCH: Final = ErrorCode( "name-match", "Check that type definition has consistent naming", "General" ) +NO_OVERLOAD_IMPL: Final = ErrorCode( + "no-overload-impl", + "Check that overloaded functions outside stub files have an implementation", + "General", +) +IGNORE_WITHOUT_CODE: Final = ErrorCode( + "ignore-without-code", + "Warn about '# type: ignore' comments which do not have error codes", + "General", + default_enabled=False, +) # Syntax errors are often blocking. SYNTAX: Final = ErrorCode("syntax", "Report syntax errors", "General") +# This is an internal marker code for a whole-file ignore. It is not intended to +# be user-visible. +FILE: Final = ErrorCode("file", "Internal marker for a whole file being ignored", "General") +del error_codes[FILE.code] + # This is a catch-all for remaining uncategorized errors. MISC: Final = ErrorCode("misc", "Miscellaneous other checks", "General") diff --git a/mypy/errors.py b/mypy/errors.py index c711456468ed..60abb739ba84 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -16,8 +16,13 @@ from mypy.util import DEFAULT_SOURCE_OFFSET, is_typeshed_file T = TypeVar("T") + allowed_duplicates: Final = ["@overload", "Got:", "Expected:"] +# Keep track of the original error code when the error code of a message is changed. +# This is used to give notes about out-of-date "type: ignore" comments. +original_error_codes: Final = {codes.LITERAL_REQ: codes.MISC} + class ErrorInfo: """Representation of a single error message.""" @@ -388,6 +393,24 @@ def add_error_info(self, info: ErrorInfo) -> None: info.hidden = True self.report_hidden_errors(info) self._add_error_info(file, info) + ignored_codes = self.ignored_lines.get(file, {}).get(info.line, []) + if ignored_codes and info.code: + # Something is ignored on the line, but not this error, so maybe the error + # code is incorrect. + msg = f'Error code "{info.code.code}" not covered by "type: ignore" comment' + if info.code in original_error_codes: + # If there seems to be a "type: ignore" with a stale error + # code, report a more specific note. + old_code = original_error_codes[info.code].code + if old_code in ignored_codes: + msg = (f'Error code changed to {info.code.code}; "type: ignore" comment ' + + 'may be out of date') + note = ErrorInfo( + info.import_ctx, info.file, info.module, info.type, info.function_or_member, + info.line, info.column, 'note', msg, + code=None, blocker=False, only_once=False, allow_dups=False + ) + self._add_error_info(file, note) def has_many_errors(self) -> bool: if self.many_errors_threshold < 0: @@ -485,6 +508,41 @@ def generate_unused_ignore_errors(self, file: str) -> None: None, False, False, False) self._add_error_info(file, info) + def generate_ignore_without_code_errors(self, + file: str, + is_warning_unused_ignores: bool) -> None: + if is_typeshed_file(file) or file in self.ignored_files: + return + + used_ignored_lines = self.used_ignored_lines[file] + + # If the whole file is ignored, ignore it. + if used_ignored_lines: + _, used_codes = min(used_ignored_lines.items()) + if codes.FILE.code in used_codes: + return + + for line, ignored_codes in self.ignored_lines[file].items(): + if ignored_codes: + continue + + # If the ignore is itself unused and that would be warned about, let + # that error stand alone + if is_warning_unused_ignores and not used_ignored_lines[line]: + continue + + codes_hint = '' + ignored_codes = sorted(set(used_ignored_lines[line])) + if ignored_codes: + codes_hint = f' (consider "type: ignore[{", ".join(ignored_codes)}]" instead)' + + message = f'"type: ignore" comment without error code{codes_hint}' + # 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', message, codes.IGNORE_WITHOUT_CODE, + False, False, False) + self._add_error_info(file, info) + def num_messages(self) -> int: """Return the number of generated messages.""" return sum(len(x) for x in self.error_info_map.values()) diff --git a/mypy/exprtotype.py b/mypy/exprtotype.py index 8f6f6c11f346..243bbf024faf 100644 --- a/mypy/exprtotype.py +++ b/mypy/exprtotype.py @@ -10,7 +10,7 @@ from mypy.fastparse import parse_type_string from mypy.types import ( Type, UnboundType, TypeList, EllipsisType, AnyType, CallableArgument, TypeOfAny, - RawExpressionType, ProperType, UnionType + RawExpressionType, ProperType, UnionType, ANNOTATED_TYPE_NAMES, ) from mypy.options import Options @@ -69,9 +69,7 @@ def expr_to_unanalyzed_type(expr: Expression, else: args = [expr.index] - if isinstance(expr.base, RefExpr) and expr.base.fullname in [ - 'typing.Annotated', 'typing_extensions.Annotated' - ]: + if isinstance(expr.base, RefExpr) and expr.base.fullname in ANNOTATED_TYPE_NAMES: # TODO: this is not the optimal solution as we are basically getting rid # of the Annotation definition and only returning the type information, # losing all the annotations. diff --git a/mypy/fastparse.py b/mypy/fastparse.py index 34fe2c0da32d..077d287655fb 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -8,6 +8,7 @@ from typing import ( Tuple, Union, TypeVar, Callable, Sequence, Optional, Any, Dict, cast, List ) + from typing_extensions import Final, Literal, overload from mypy.sharedparse import ( @@ -19,18 +20,22 @@ ClassDef, Decorator, Block, Var, OperatorAssignmentStmt, ExpressionStmt, AssignmentStmt, ReturnStmt, RaiseStmt, AssertStmt, DelStmt, BreakStmt, ContinueStmt, PassStmt, GlobalDecl, - WhileStmt, ForStmt, IfStmt, TryStmt, WithStmt, + WhileStmt, ForStmt, IfStmt, TryStmt, WithStmt, MatchStmt, TupleExpr, GeneratorExpr, ListComprehension, ListExpr, ConditionalExpr, DictExpr, SetExpr, NameExpr, IntExpr, StrExpr, BytesExpr, UnicodeExpr, FloatExpr, CallExpr, SuperExpr, MemberExpr, IndexExpr, SliceExpr, OpExpr, UnaryExpr, LambdaExpr, ComparisonExpr, AssignmentExpr, StarExpr, YieldFromExpr, NonlocalDecl, DictionaryComprehension, SetComprehension, ComplexExpr, EllipsisExpr, YieldExpr, Argument, - AwaitExpr, TempNode, Expression, Statement, + AwaitExpr, TempNode, RefExpr, Expression, Statement, ArgKind, ARG_POS, ARG_OPT, ARG_STAR, ARG_NAMED, ARG_NAMED_OPT, ARG_STAR2, check_arg_names, FakeInfo, ) +from mypy.patterns import ( + AsPattern, OrPattern, ValuePattern, SequencePattern, StarredPattern, MappingPattern, + ClassPattern, SingletonPattern +) from mypy.types import ( Type, CallableType, AnyType, UnboundType, TupleType, TypeList, EllipsisType, CallableArgument, TypeOfAny, Instance, RawExpressionType, ProperType, UnionType, @@ -39,7 +44,8 @@ from mypy import message_registry, errorcodes as codes from mypy.errors import Errors from mypy.options import Options -from mypy.reachability import mark_block_unreachable +from mypy.reachability import infer_reachability_of_if_statement, mark_block_unreachable +from mypy.util import bytes_to_human_readable_repr try: # pull this into a final variable to make mypyc be quiet about the @@ -106,6 +112,29 @@ def ast3_parse(source: Union[str, bytes], filename: str, mode: str, # These don't exist before 3.8 NamedExpr = Any Constant = Any + + if sys.version_info >= (3, 10): + Match = ast3.Match + MatchValue = ast3.MatchValue + MatchSingleton = ast3.MatchSingleton + MatchSequence = ast3.MatchSequence + MatchStar = ast3.MatchStar + MatchMapping = ast3.MatchMapping + MatchClass = ast3.MatchClass + MatchAs = ast3.MatchAs + MatchOr = ast3.MatchOr + AstNode = Union[ast3.expr, ast3.stmt, ast3.pattern, ast3.ExceptHandler] + else: + Match = Any + MatchValue = Any + MatchSingleton = Any + MatchSequence = Any + MatchStar = Any + MatchMapping = Any + MatchClass = Any + MatchAs = Any + MatchOr = Any + AstNode = Union[ast3.expr, ast3.stmt, ast3.ExceptHandler] except ImportError: try: from typed_ast import ast35 # type: ignore[attr-defined] # noqa: F401 @@ -315,9 +344,19 @@ def fail(self, msg: str, line: int, column: int, - blocker: bool = True) -> None: + blocker: bool = True, + code: codes.ErrorCode = codes.SYNTAX) -> None: if blocker or not self.options.ignore_errors: - self.errors.report(line, column, msg, blocker=blocker, code=codes.SYNTAX) + self.errors.report(line, column, msg, blocker=blocker, code=code) + + def fail_merge_overload(self, node: IfStmt) -> None: + self.fail( + "Condition can't be inferred, unable to merge overloads", + line=node.line, + column=node.column, + blocker=False, + code=codes.MISC, + ) def visit(self, node: Optional[AST]) -> Any: if node is None: @@ -330,7 +369,7 @@ def visit(self, node: Optional[AST]) -> Any: self.visitor_cache[typeobj] = visitor return visitor(node) - def set_line(self, node: N, n: Union[ast3.expr, ast3.stmt, ast3.ExceptHandler]) -> N: + def set_line(self, node: N, n: AstNode) -> N: node.line = n.lineno node.column = n.col_offset node.end_line = getattr(n, "end_lineno", None) if isinstance(n, ast3.expr) else None @@ -360,7 +399,7 @@ def translate_stmt_list(self, 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][min(self.type_ignores)].append( - codes.MISC.code) + codes.FILE.code) block = Block(self.fix_function_overloads(self.translate_stmt_list(stmts))) mark_block_unreachable(block) return [block] @@ -447,12 +486,97 @@ def fix_function_overloads(self, stmts: List[Statement]) -> List[Statement]: ret: List[Statement] = [] current_overload: List[OverloadPart] = [] current_overload_name: Optional[str] = None + seen_unconditional_func_def = False + last_if_stmt: Optional[IfStmt] = None + last_if_overload: Optional[Union[Decorator, FuncDef, OverloadedFuncDef]] = None + last_if_stmt_overload_name: Optional[str] = None + last_if_unknown_truth_value: Optional[IfStmt] = None + skipped_if_stmts: List[IfStmt] = [] for stmt in stmts: + if_overload_name: Optional[str] = None + if_block_with_overload: Optional[Block] = None + if_unknown_truth_value: Optional[IfStmt] = None + if ( + isinstance(stmt, IfStmt) + and len(stmt.body[0].body) == 1 + and seen_unconditional_func_def is False + and ( + isinstance(stmt.body[0].body[0], (Decorator, OverloadedFuncDef)) + or current_overload_name is not None + and isinstance(stmt.body[0].body[0], FuncDef) + ) + ): + # Check IfStmt block to determine if function overloads can be merged + if_overload_name = self._check_ifstmt_for_overloads(stmt) + if if_overload_name is not None: + if_block_with_overload, if_unknown_truth_value = \ + self._get_executable_if_block_with_overloads(stmt) + if (current_overload_name is not None and isinstance(stmt, (Decorator, FuncDef)) and stmt.name == current_overload_name): + if last_if_stmt is not None: + skipped_if_stmts.append(last_if_stmt) + if last_if_overload is not None: + # Last stmt was an IfStmt with same overload name + # Add overloads to current_overload + if isinstance(last_if_overload, OverloadedFuncDef): + current_overload.extend(last_if_overload.items) + else: + current_overload.append(last_if_overload) + last_if_stmt, last_if_overload = None, None + if last_if_unknown_truth_value: + self.fail_merge_overload(last_if_unknown_truth_value) + last_if_unknown_truth_value = None current_overload.append(stmt) + if isinstance(stmt, FuncDef): + seen_unconditional_func_def = True + elif ( + current_overload_name is not None + and isinstance(stmt, IfStmt) + and if_overload_name == current_overload_name + ): + # IfStmt only contains stmts relevant to current_overload. + # Check if stmts are reachable and add them to current_overload, + # otherwise skip IfStmt to allow subsequent overload + # or function definitions. + skipped_if_stmts.append(stmt) + if if_block_with_overload is None: + if if_unknown_truth_value is not None: + self.fail_merge_overload(if_unknown_truth_value) + continue + if last_if_overload is not None: + # Last stmt was an IfStmt with same overload name + # Add overloads to current_overload + if isinstance(last_if_overload, OverloadedFuncDef): + current_overload.extend(last_if_overload.items) + else: + current_overload.append(last_if_overload) + last_if_stmt, last_if_overload = None, None + if isinstance(if_block_with_overload.body[0], OverloadedFuncDef): + current_overload.extend(if_block_with_overload.body[0].items) + else: + current_overload.append( + cast(Union[Decorator, FuncDef], if_block_with_overload.body[0]) + ) else: + if last_if_stmt is not None: + ret.append(last_if_stmt) + last_if_stmt_overload_name = current_overload_name + last_if_stmt, last_if_overload = None, None + last_if_unknown_truth_value = None + + if current_overload and current_overload_name == last_if_stmt_overload_name: + # Remove last stmt (IfStmt) from ret if the overload names matched + # Only happens if no executable block had been found in IfStmt + skipped_if_stmts.append(cast(IfStmt, ret.pop())) + if current_overload and skipped_if_stmts: + # Add bare IfStmt (without overloads) to ret + # Required for mypy to be able to still check conditions + for if_stmt in skipped_if_stmts: + self._strip_contents_from_if_stmt(if_stmt) + ret.append(if_stmt) + skipped_if_stmts = [] if len(current_overload) == 1: ret.append(current_overload[0]) elif len(current_overload) > 1: @@ -463,20 +587,123 @@ def fix_function_overloads(self, stmts: List[Statement]) -> List[Statement]: # most of mypy/mypyc assumes that all the functions in an OverloadedFuncDef are # related, but multiple underscore functions next to each other aren't necessarily # related + seen_unconditional_func_def = False if isinstance(stmt, Decorator) and not unnamed_function(stmt.name): current_overload = [stmt] current_overload_name = stmt.name + elif ( + isinstance(stmt, IfStmt) + and if_overload_name is not None + ): + current_overload = [] + current_overload_name = if_overload_name + last_if_stmt = stmt + last_if_stmt_overload_name = None + if if_block_with_overload is not None: + last_if_overload = cast( + Union[Decorator, FuncDef, OverloadedFuncDef], + if_block_with_overload.body[0] + ) + last_if_unknown_truth_value = if_unknown_truth_value else: current_overload = [] current_overload_name = None ret.append(stmt) + if current_overload and skipped_if_stmts: + # Add bare IfStmt (without overloads) to ret + # Required for mypy to be able to still check conditions + for if_stmt in skipped_if_stmts: + self._strip_contents_from_if_stmt(if_stmt) + ret.append(if_stmt) if len(current_overload) == 1: ret.append(current_overload[0]) elif len(current_overload) > 1: ret.append(OverloadedFuncDef(current_overload)) + elif last_if_stmt is not None: + ret.append(last_if_stmt) return ret + def _check_ifstmt_for_overloads(self, stmt: IfStmt) -> Optional[str]: + """Check if IfStmt contains only overloads with the same name. + Return overload_name if found, None otherwise. + """ + # Check that block only contains a single Decorator, FuncDef, or OverloadedFuncDef. + # Multiple overloads have already been merged as OverloadedFuncDef. + if not ( + len(stmt.body[0].body) == 1 + and isinstance(stmt.body[0].body[0], (Decorator, FuncDef, OverloadedFuncDef)) + ): + return None + + overload_name = stmt.body[0].body[0].name + if stmt.else_body is None: + return overload_name + + if isinstance(stmt.else_body, Block) and len(stmt.else_body.body) == 1: + # For elif: else_body contains an IfStmt itself -> do a recursive check. + if ( + isinstance(stmt.else_body.body[0], (Decorator, FuncDef, OverloadedFuncDef)) + and stmt.else_body.body[0].name == overload_name + ): + return overload_name + if ( + isinstance(stmt.else_body.body[0], IfStmt) + and self._check_ifstmt_for_overloads(stmt.else_body.body[0]) == overload_name + ): + return overload_name + + return None + + def _get_executable_if_block_with_overloads( + self, stmt: IfStmt + ) -> Tuple[Optional[Block], Optional[IfStmt]]: + """Return block from IfStmt that will get executed. + + Return + 0 -> A block if sure that alternative blocks are unreachable. + 1 -> An IfStmt if the reachability of it can't be inferred, + i.e. the truth value is unknown. + """ + infer_reachability_of_if_statement(stmt, self.options) + if ( + stmt.else_body is None + and stmt.body[0].is_unreachable is True + ): + # always False condition with no else + return None, None + if ( + stmt.else_body is None + or stmt.body[0].is_unreachable is False + and stmt.else_body.is_unreachable is False + ): + # The truth value is unknown, thus not conclusive + return None, stmt + if stmt.else_body.is_unreachable is True: + # else_body will be set unreachable if condition is always True + return stmt.body[0], None + if stmt.body[0].is_unreachable is True: + # body will be set unreachable if condition is always False + # else_body can contain an IfStmt itself (for elif) -> do a recursive check + if isinstance(stmt.else_body.body[0], IfStmt): + return self._get_executable_if_block_with_overloads(stmt.else_body.body[0]) + return stmt.else_body, None + return None, stmt + + def _strip_contents_from_if_stmt(self, stmt: IfStmt) -> None: + """Remove contents from IfStmt. + + Needed to still be able to check the conditions after the contents + have been merged with the surrounding function overloads. + """ + if len(stmt.body) == 1: + stmt.body[0].body = [] + if stmt.else_body and len(stmt.else_body.body) == 1: + if isinstance(stmt.else_body.body[0], IfStmt): + self._strip_contents_from_if_stmt(stmt.else_body.body[0]) + else: + stmt.else_body.body = [] + def in_method_scope(self) -> bool: return self.class_and_function_stack[-2:] == ['C', 'F'] @@ -1286,11 +1513,74 @@ 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() + # Match(expr subject, match_case* cases) # python 3.10 and later + def visit_Match(self, n: Match) -> MatchStmt: + node = MatchStmt(self.visit(n.subject), + [self.visit(c.pattern) for c in n.cases], + [self.visit(c.guard) for c in n.cases], + [self.as_required_block(c.body, n.lineno) for c in n.cases]) + return self.set_line(node, n) + + def visit_MatchValue(self, n: MatchValue) -> ValuePattern: + node = ValuePattern(self.visit(n.value)) + return self.set_line(node, n) + + def visit_MatchSingleton(self, n: MatchSingleton) -> SingletonPattern: + node = SingletonPattern(n.value) + return self.set_line(node, n) + + def visit_MatchSequence(self, n: MatchSequence) -> SequencePattern: + patterns = [self.visit(p) for p in n.patterns] + stars = [p for p in patterns if isinstance(p, StarredPattern)] + assert len(stars) < 2 + + node = SequencePattern(patterns) + return self.set_line(node, n) + + def visit_MatchStar(self, n: MatchStar) -> StarredPattern: + if n.name is None: + node = StarredPattern(None) + else: + node = StarredPattern(NameExpr(n.name)) + + return self.set_line(node, n) + + def visit_MatchMapping(self, n: MatchMapping) -> MappingPattern: + keys = [self.visit(k) for k in n.keys] + values = [self.visit(v) for v in n.patterns] + + if n.rest is None: + rest = None + else: + rest = NameExpr(n.rest) + + node = MappingPattern(keys, values, rest) + return self.set_line(node, n) + + def visit_MatchClass(self, n: MatchClass) -> ClassPattern: + class_ref = self.visit(n.cls) + assert isinstance(class_ref, RefExpr) + positionals = [self.visit(p) for p in n.patterns] + keyword_keys = n.kwd_attrs + keyword_values = [self.visit(p) for p in n.kwd_patterns] + + node = ClassPattern(class_ref, positionals, keyword_keys, keyword_values) + return self.set_line(node, n) + + # MatchAs(expr pattern, identifier name) + def visit_MatchAs(self, n: MatchAs) -> AsPattern: + if n.name is None: + name = None + else: + name = NameExpr(n.name) + name = self.set_line(name, n) + node = AsPattern(self.visit(n.pattern), name) + return self.set_line(node, n) + + # MatchOr(expr* pattern) + def visit_MatchOr(self, n: MatchOr) -> OrPattern: + node = OrPattern([self.visit(pattern) for pattern in n.patterns]) + return self.set_line(node, n) class TypeConverter: @@ -1638,17 +1928,3 @@ def stringify_name(n: AST) -> Optional[str]: if sv is not None: return "{}.{}".format(sv, n.attr) return None # Can't do it. - - -def bytes_to_human_readable_repr(b: bytes) -> str: - """Converts bytes into some human-readable representation. Unprintable - bytes such as the nul byte are escaped. For example: - - >>> b = bytes([102, 111, 111, 10, 0]) - >>> s = bytes_to_human_readable_repr(b) - >>> print(s) - foo\n\x00 - >>> print(repr(s)) - 'foo\\n\\x00' - """ - return repr(b)[2:-1] diff --git a/mypy/fastparse2.py b/mypy/fastparse2.py index 2d288bf158e5..0e8faa957d67 100644 --- a/mypy/fastparse2.py +++ b/mypy/fastparse2.py @@ -47,10 +47,11 @@ from mypy import message_registry, errorcodes as codes from mypy.errors import Errors from mypy.fastparse import ( - TypeConverter, parse_type_comment, bytes_to_human_readable_repr, parse_type_ignore_tag, + TypeConverter, parse_type_comment, parse_type_ignore_tag, TYPE_IGNORE_PATTERN, INVALID_TYPE_IGNORE ) from mypy.options import Options +from mypy.util import bytes_to_human_readable_repr from mypy.reachability import mark_block_unreachable try: @@ -216,7 +217,7 @@ def translate_stmt_list(self, 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][min(self.type_ignores)].append( - codes.MISC.code) + codes.FILE.code) block = Block(self.fix_function_overloads(self.translate_stmt_list(stmts))) mark_block_unreachable(block) return [block] @@ -664,19 +665,23 @@ def visit_With(self, n: ast27.With) -> WithStmt: typ) return self.set_line(stmt, n) + # 'raise' [test [',' test [',' test]]] def visit_Raise(self, n: ast27.Raise) -> RaiseStmt: + legacy_mode = False if n.type is None: e = None else: if n.inst is None: e = self.visit(n.type) else: + legacy_mode = True if n.tback is None: e = TupleExpr([self.visit(n.type), self.visit(n.inst)]) else: e = TupleExpr([self.visit(n.type), self.visit(n.inst), self.visit(n.tback)]) stmt = RaiseStmt(e, None) + stmt.legacy_mode = legacy_mode return self.set_line(stmt, n) # TryExcept(stmt* body, excepthandler* handlers, stmt* orelse) diff --git a/mypy/fscache.py b/mypy/fscache.py index ea71577b5f86..d0be1abd8cb9 100644 --- a/mypy/fscache.py +++ b/mypy/fscache.py @@ -143,16 +143,13 @@ def _fake_init(self, path: str) -> os.stat_result: assert not os.path.exists(path), path # Not cached! dirname = os.path.normpath(dirname) st = self.stat(dirname) # May raise OSError - # Get stat result as a sequence so we can modify it. - # (Alas, typeshed's os.stat_result is not a sequence yet.) - tpl = tuple(st) # type: ignore[arg-type, var-annotated] - seq: List[float] = list(tpl) + # Get stat result as a list so we can modify it. + seq: List[float] = list(st) seq[stat.ST_MODE] = stat.S_IFREG | 0o444 seq[stat.ST_INO] = 1 seq[stat.ST_NLINK] = 1 seq[stat.ST_SIZE] = 0 - tpl = tuple(seq) - st = os.stat_result(tpl) + st = os.stat_result(seq) self.stat_cache[path] = st # Make listdir() and read() also pretend this file exists. self.fake_package_cache.add(dirname) diff --git a/mypy/git.py b/mypy/git.py index da36ff2cb54a..8e73b1eeb9c5 100644 --- a/mypy/git.py +++ b/mypy/git.py @@ -30,9 +30,3 @@ def is_dirty(dir: str) -> bool: """Check whether a git repository has uncommitted changes.""" output = subprocess.check_output(["git", "status", "-uno", "--porcelain"], cwd=dir) return output.strip() != b"" - - -def has_extra_files(dir: str) -> bool: - """Check whether a git repository has untracked files.""" - output = subprocess.check_output(["git", "clean", "--dry-run", "-d"], cwd=dir) - return output.strip() != b"" diff --git a/mypy/ipc.py b/mypy/ipc.py index 8a6a310d7ff8..f48ac18075d8 100644 --- a/mypy/ipc.py +++ b/mypy/ipc.py @@ -54,9 +54,6 @@ def read(self, size: int = 100000) -> bytes: if sys.platform == 'win32': while True: ov, err = _winapi.ReadFile(self.connection, size, overlapped=True) - # TODO: remove once typeshed supports Literal types - assert isinstance(ov, _winapi.Overlapped) - assert isinstance(err, int) try: if err == _winapi.ERROR_IO_PENDING: timeout = int(self.timeout * 1000) if self.timeout else _winapi.INFINITE diff --git a/mypy/join.py b/mypy/join.py index e0d926f3fcf4..161c65ea800c 100644 --- a/mypy/join.py +++ b/mypy/join.py @@ -11,7 +11,7 @@ ) from mypy.maptype import map_instance_to_supertype from mypy.subtypes import ( - is_subtype, is_equivalent, is_subtype_ignoring_tvars, is_proper_subtype, + is_subtype, is_equivalent, is_proper_subtype, is_protocol_implementation, find_member ) from mypy.nodes import INVARIANT, COVARIANT, CONTRAVARIANT @@ -72,7 +72,7 @@ def join_instances(self, t: Instance, s: Instance) -> ProperType: assert new_type is not None args.append(new_type) result: ProperType = Instance(t.type, args) - elif t.type.bases and is_subtype_ignoring_tvars(t, s): + elif t.type.bases and is_subtype(t, s, ignore_type_params=True): result = self.join_instances_via_supertype(t, s) else: # Now t is not a subtype of s, and t != s. Now s could be a subtype @@ -175,15 +175,15 @@ def join_types(s: Type, t: Type, instance_joiner: Optional[InstanceJoiner] = Non s = mypy.typeops.true_or_false(s) t = mypy.typeops.true_or_false(t) + if isinstance(s, UnionType) and not isinstance(t, UnionType): + s, t = t, s + if isinstance(s, AnyType): return s if isinstance(s, ErasedType): return t - if isinstance(s, UnionType) and not isinstance(t, UnionType): - s, t = t, s - if isinstance(s, NoneType) and not isinstance(t, NoneType): s, t = t, s @@ -402,8 +402,7 @@ def visit_typeddict_type(self, t: TypedDictType) -> ProperType: if (is_equivalent(s_item_type, t_item_type) and (item_name in t.required_keys) == (item_name in self.s.required_keys)) ]) - mapping_value_type = join_type_list(list(items.values())) - fallback = self.s.create_anonymous_fallback(value_type=mapping_value_type) + fallback = self.s.create_anonymous_fallback() # We need to filter by items.keys() since some required keys present in both t and # self.s might be missing from the join if the types are incompatible. required_keys = set(items.keys()) & t.required_keys & self.s.required_keys diff --git a/mypy/meet.py b/mypy/meet.py index 644b57afbcbe..0b336aa6f810 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -508,15 +508,14 @@ def visit_param_spec(self, t: ParamSpecType) -> ProperType: def visit_instance(self, t: Instance) -> ProperType: if isinstance(self.s, Instance): - si = self.s - if t.type == si.type: + if t.type == self.s.type: if is_subtype(t, self.s) or is_subtype(self.s, t): # Combine type arguments. We could have used join below # equivalently. args: List[Type] = [] # N.B: We use zip instead of indexing because the lengths might have # mismatches during daemon reprocessing. - for ta, sia in zip(t.args, si.args): + for ta, sia in zip(t.args, self.s.args): args.append(self.meet(ta, sia)) return Instance(t.type, args) else: @@ -629,8 +628,7 @@ def visit_typeddict_type(self, t: TypedDictType) -> ProperType: assert t_item_type is not None item_list.append((item_name, t_item_type)) items = OrderedDict(item_list) - mapping_value_type = join.join_type_list(list(items.values())) - fallback = self.s.create_anonymous_fallback(value_type=mapping_value_type) + fallback = self.s.create_anonymous_fallback() required_keys = t.required_keys | self.s.required_keys return TypedDictType(items, required_keys, fallback) elif isinstance(self.s, Instance) and is_subtype(t, self.s): diff --git a/mypy/message_registry.py b/mypy/message_registry.py index 77dff1154833..7a75ae8b0043 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -64,6 +64,7 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage": 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" +INCOMPATIBLE_TYPES_IN_CAPTURE: Final = ErrorMessage('Incompatible types in capture pattern') 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") @@ -203,6 +204,11 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage": ) CANNOT_MAKE_DELETABLE_FINAL: Final = ErrorMessage("Deletable attribute cannot be final") +# Enum +ENUM_MEMBERS_ATTR_WILL_BE_OVERRIDEN: Final = ErrorMessage( + 'Assigned "__members__" will be overriden by "Enum" internally' +) + # ClassVar CANNOT_OVERRIDE_INSTANCE_VAR: Final = ErrorMessage( 'Cannot override instance variable (previously declared on base class "{}") with class ' @@ -229,3 +235,19 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage": 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") + +# Match Statement +MISSING_MATCH_ARGS: Final = 'Class "{}" doesn\'t define "__match_args__"' +OR_PATTERN_ALTERNATIVE_NAMES: Final = "Alternative patterns bind different names" +CLASS_PATTERN_GENERIC_TYPE_ALIAS: Final = ( + "Class pattern class must not be a type alias with type parameters" +) +CLASS_PATTERN_TYPE_REQUIRED: Final = 'Expected type in class pattern; found "{}"' +CLASS_PATTERN_TOO_MANY_POSITIONAL_ARGS: Final = "Too many positional patterns for class pattern" +CLASS_PATTERN_KEYWORD_MATCHES_POSITIONAL: Final = ( + 'Keyword "{}" already matches a positional pattern' +) +CLASS_PATTERN_DUPLICATE_KEYWORD_PATTERN: Final = 'Duplicate keyword pattern "{}"' +CLASS_PATTERN_UNKNOWN_KEYWORD: Final = 'Class "{}" has no attribute "{}"' +MULTIPLE_ASSIGNMENTS_IN_PATTERN: Final = 'Multiple assignments to name "{}" in pattern' +CANNOT_MODIFY_MATCH_ARGS: Final = 'Cannot assign to "__match_args__"' diff --git a/mypy/messages.py b/mypy/messages.py index da284cc88ba4..bb6977190105 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -39,6 +39,7 @@ IS_SETTABLE, IS_CLASSVAR, IS_CLASS_OR_STATIC, ) from mypy.sametypes import is_same_type +from mypy.typeops import separate_union_literals from mypy.util import unmangle from mypy.errorcodes import ErrorCode from mypy import message_registry, errorcodes as codes @@ -107,13 +108,13 @@ class MessageBuilder: disable_count = 0 # Hack to deduplicate error messages from union types - disable_type_names = 0 + disable_type_names_count = 0 def __init__(self, errors: Errors, modules: Dict[str, MypyFile]) -> None: self.errors = errors self.modules = modules self.disable_count = 0 - self.disable_type_names = 0 + self.disable_type_names_count = 0 # # Helpers @@ -122,7 +123,7 @@ def __init__(self, errors: Errors, modules: Dict[str, MypyFile]) -> None: def copy(self) -> 'MessageBuilder': new = MessageBuilder(self.errors.copy(), self.modules) new.disable_count = self.disable_count - new.disable_type_names = self.disable_type_names + new.disable_type_names_count = self.disable_type_names_count return new def clean_copy(self) -> 'MessageBuilder': @@ -145,6 +146,14 @@ def disable_errors(self) -> Iterator[None]: finally: self.disable_count -= 1 + @contextmanager + def disable_type_names(self) -> Iterator[None]: + self.disable_type_names_count += 1 + try: + yield + finally: + self.disable_type_names_count -= 1 + def is_errors(self) -> bool: return self.errors.is_errors() @@ -298,7 +307,7 @@ def has_no_attr(self, extra = ' (not iterable)' elif member == '__aiter__': extra = ' (not async iterable)' - if not self.disable_type_names: + if not self.disable_type_names_count: failed = False if isinstance(original_type, Instance) and original_type.type.names: alternatives = set(original_type.type.names.keys()) @@ -380,7 +389,7 @@ def unsupported_operand_types(self, else: right_str = format_type(right_type) - if self.disable_type_names: + if self.disable_type_names_count: msg = 'Unsupported operand types for {} (likely involving Union)'.format(op) else: msg = 'Unsupported operand types for {} ({} and {})'.format( @@ -389,7 +398,7 @@ def unsupported_operand_types(self, def unsupported_left_operand(self, op: str, typ: Type, context: Context) -> None: - if self.disable_type_names: + if self.disable_type_names_count: msg = 'Unsupported left operand type for {} (some union)'.format(op) else: msg = 'Unsupported left operand type for {} ({})'.format( @@ -807,7 +816,7 @@ def incompatible_operator_assignment(self, op: str, def overload_signature_incompatible_with_supertype( self, name: str, name_in_super: str, supertype: str, - overload: Overloaded, context: Context) -> None: + context: Context) -> None: target = self.override_target(name, name_in_super, supertype) self.fail('Signature of "{}" incompatible with {}'.format( name, target), context, code=codes.OVERRIDE) @@ -945,11 +954,8 @@ def invalid_keyword_var_arg(self, typ: Type, is_mapping: bool, context: Context) if isinstance(typ, Instance) and is_mapping: self.fail('Keywords must be strings', context) else: - suffix = '' - if isinstance(typ, Instance): - suffix = ', not {}'.format(format_type(typ)) self.fail( - 'Argument after ** must be a mapping{}'.format(suffix), + 'Argument after ** must be a mapping, not {}'.format(format_type(typ)), context, code=codes.ARG_TYPE) def undefined_in_superclass(self, member: str, context: Context) -> None: @@ -1250,7 +1256,7 @@ def typeddict_key_must_be_string_literal( context: Context) -> None: self.fail( 'TypedDict key must be a string literal; expected one of {}'.format( - format_item_name_list(typ.items.keys())), context) + format_item_name_list(typ.items.keys())), context, code=codes.LITERAL_REQ) def typeddict_key_not_found( self, @@ -1399,9 +1405,6 @@ def redundant_condition_in_comprehension(self, truthiness: bool, context: Contex def redundant_condition_in_if(self, truthiness: bool, context: Context) -> None: self.redundant_expr("If condition", truthiness, context) - def redundant_condition_in_assert(self, truthiness: bool, context: Context) -> None: - self.redundant_expr("Condition in assert", truthiness, context) - def redundant_expr(self, description: str, truthiness: bool, context: Context) -> None: self.fail("{} is always {}".format(description, str(truthiness).lower()), context, code=codes.REDUNDANT_EXPR) @@ -1659,6 +1662,16 @@ def format_type_inner(typ: Type, def format(typ: Type) -> str: return format_type_inner(typ, verbosity, fullnames) + def format_list(types: Sequence[Type]) -> str: + return ', '.join(format(typ) for typ in types) + + def format_literal_value(typ: LiteralType) -> str: + if typ.is_enum_literal(): + underlying_type = format(typ.fallback) + return '{}.{}'.format(underlying_type, typ.value) + else: + return typ.value_repr() + # TODO: show type alias names in errors. typ = get_proper_type(typ) @@ -1681,15 +1694,10 @@ def format(typ: Type) -> str: elif itype.type.fullname in reverse_builtin_aliases: alias = reverse_builtin_aliases[itype.type.fullname] alias = alias.split('.')[-1] - items = [format(arg) for arg in itype.args] - return '{}[{}]'.format(alias, ', '.join(items)) + return '{}[{}]'.format(alias, format_list(itype.args)) else: # There are type arguments. Convert the arguments to strings. - a: List[str] = [] - for arg in itype.args: - a.append(format(arg)) - s = ', '.join(a) - return '{}[{}]'.format(base_str, s) + return '{}[{}]'.format(base_str, format_list(itype.args)) elif isinstance(typ, TypeVarType): # This is similar to non-generic instance types. return typ.name @@ -1699,10 +1707,7 @@ def format(typ: Type) -> str: # Prefer the name of the fallback class (if not tuple), as it's more informative. if typ.partial_fallback.type.fullname != 'builtins.tuple': return format(typ.partial_fallback) - items = [] - for t in typ.items: - items.append(format(t)) - s = 'Tuple[{}]'.format(', '.join(items)) + s = 'Tuple[{}]'.format(format_list(typ.items)) return s elif isinstance(typ, TypedDictType): # If the TypedDictType is named, return the name @@ -1717,24 +1722,34 @@ def format(typ: Type) -> str: s = 'TypedDict({{{}}})'.format(', '.join(items)) return s elif isinstance(typ, LiteralType): - if typ.is_enum_literal(): - underlying_type = format(typ.fallback) - return 'Literal[{}.{}]'.format(underlying_type, typ.value) - else: - return str(typ) + return 'Literal[{}]'.format(format_literal_value(typ)) elif isinstance(typ, UnionType): - # Only print Unions as Optionals if the Optional wouldn't have to contain another Union - print_as_optional = (len(typ.items) - - sum(isinstance(get_proper_type(t), NoneType) - for t in typ.items) == 1) - if print_as_optional: - rest = [t for t in typ.items if not isinstance(get_proper_type(t), NoneType)] - return 'Optional[{}]'.format(format(rest[0])) + literal_items, union_items = separate_union_literals(typ) + + # Coalesce multiple Literal[] members. This also changes output order. + # If there's just one Literal item, retain the original ordering. + if len(literal_items) > 1: + literal_str = 'Literal[{}]'.format( + ', '.join(format_literal_value(t) for t in literal_items) + ) + + if len(union_items) == 1 and isinstance(get_proper_type(union_items[0]), NoneType): + return 'Optional[{}]'.format(literal_str) + elif union_items: + return 'Union[{}, {}]'.format(format_list(union_items), literal_str) + else: + return literal_str else: - items = [] - for t in typ.items: - items.append(format(t)) - s = 'Union[{}]'.format(', '.join(items)) + # Only print Union as Optional if the Optional wouldn't have to contain another Union + print_as_optional = (len(typ.items) - + sum(isinstance(get_proper_type(t), NoneType) + for t in typ.items) == 1) + if print_as_optional: + rest = [t for t in typ.items if not isinstance(get_proper_type(t), NoneType)] + return 'Optional[{}]'.format(format(rest[0])) + else: + s = 'Union[{}]'.format(format_list(typ.items)) + return s elif isinstance(typ, NoneType): return 'None' @@ -1855,8 +1870,7 @@ def format_type(typ: Type, verbosity: int = 0) -> str: def format_type_bare(typ: Type, - verbosity: int = 0, - fullnames: Optional[Set[str]] = None) -> str: + verbosity: int = 0) -> str: """ Convert a type to a relatively short string suitable for error messages. diff --git a/mypy/nodes.py b/mypy/nodes.py index 156d756030ae..fbd36b67cbc0 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -17,6 +17,9 @@ from mypy.bogus_type import Bogus +if TYPE_CHECKING: + from mypy.patterns import Pattern + class Context: """Base type for objects that are valid as error message locations.""" @@ -255,7 +258,8 @@ class MypyFile(SymbolNode): __slots__ = ('_fullname', 'path', 'defs', 'alias_deps', 'is_bom', 'names', 'imports', 'ignored_lines', 'is_stub', - 'is_cache_skeleton', 'is_partial_stub_package', 'plugin_deps') + 'is_cache_skeleton', 'is_partial_stub_package', 'plugin_deps', + 'future_import_flags') # Fully qualified module name _fullname: Bogus[str] @@ -284,6 +288,8 @@ class MypyFile(SymbolNode): is_partial_stub_package: bool # Plugin-created dependencies plugin_deps: Dict[str, Set[str]] + # Future imports defined in this file. Populated during semantic analysis. + future_import_flags: Set[str] def __init__(self, defs: List[Statement], @@ -306,6 +312,7 @@ def __init__(self, self.is_stub = False self.is_cache_skeleton = False self.is_partial_stub_package = False + self.future_import_flags = set() def local_definitions(self) -> Iterator[Definition]: """Return all definitions within the module (including nested). @@ -328,6 +335,9 @@ def accept(self, visitor: NodeVisitor[T]) -> T: def is_package_init_file(self) -> bool: return len(self.path) != 0 and os.path.basename(self.path).startswith('__init__.') + def is_future_flag_set(self, flag: str) -> bool: + return flag in self.future_import_flags + def serialize(self) -> JsonDict: return {'.class': 'MypyFile', '_fullname': self._fullname, @@ -335,6 +345,7 @@ def serialize(self) -> JsonDict: 'is_stub': self.is_stub, 'path': self.path, 'is_partial_stub_package': self.is_partial_stub_package, + 'future_import_flags': list(self.future_import_flags), } @classmethod @@ -347,6 +358,7 @@ def deserialize(cls, data: JsonDict) -> 'MypyFile': tree.path = data['path'] tree.is_partial_stub_package = data['is_partial_stub_package'] tree.is_cache_skeleton = True + tree.future_import_flags = set(data['future_import_flags']) return tree @@ -840,6 +852,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', 'allow_incompatible_override', ] @@ -870,6 +883,8 @@ class Var(SymbolNode): 'is_suppressed_import', 'explicit_self_type', 'from_module_getattr', + 'has_explicit_value', + 'allow_incompatible_override', ) def __init__(self, name: str, type: 'Optional[mypy.types.Type]' = None) -> None: @@ -914,6 +929,11 @@ 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 + # If True, subclasses can override this with an incompatible type. + self.allow_incompatible_override = False @property def name(self) -> str: @@ -1294,16 +1314,19 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class RaiseStmt(Statement): - __slots__ = ('expr', 'from_expr') + __slots__ = ('expr', 'from_expr', 'legacy_mode') # Plain 'raise' is a valid statement. expr: Optional[Expression] from_expr: Optional[Expression] + # Is set when python2 has `raise exc, msg, traceback`. + legacy_mode: bool def __init__(self, expr: Optional[Expression], from_expr: Optional[Expression]) -> None: super().__init__() self.expr = expr self.from_expr = from_expr + self.legacy_mode = False def accept(self, visitor: StatementVisitor[T]) -> T: return visitor.visit_raise_stmt(self) @@ -1363,6 +1386,25 @@ def accept(self, visitor: StatementVisitor[T]) -> T: return visitor.visit_with_stmt(self) +class MatchStmt(Statement): + subject: Expression + patterns: List['Pattern'] + guards: List[Optional[Expression]] + bodies: List[Block] + + def __init__(self, subject: Expression, patterns: List['Pattern'], + guards: List[Optional[Expression]], bodies: List[Block]) -> None: + super().__init__() + assert len(patterns) == len(guards) == len(bodies) + self.subject = subject + self.patterns = patterns + self.guards = guards + self.bodies = bodies + + def accept(self, visitor: StatementVisitor[T]) -> T: + return visitor.visit_match_stmt(self) + + class PrintStmt(Statement): """Python 2 print statement""" diff --git a/mypy/patterns.py b/mypy/patterns.py new file mode 100644 index 000000000000..f7f5f56d0ed5 --- /dev/null +++ b/mypy/patterns.py @@ -0,0 +1,137 @@ +"""Classes for representing match statement patterns.""" +from typing import TypeVar, List, Optional, Union + +from mypy_extensions import trait + +from mypy.nodes import Node, RefExpr, NameExpr, Expression +from mypy.visitor import PatternVisitor + + +T = TypeVar('T') + + +@trait +class Pattern(Node): + """A pattern node.""" + + __slots__ = () + + def accept(self, visitor: PatternVisitor[T]) -> T: + raise RuntimeError('Not implemented') + + +class AsPattern(Pattern): + """The pattern as """ + # The python ast, and therefore also our ast merges capture, wildcard and as patterns into one + # for easier handling. + # If pattern is None this is a capture pattern. If name and pattern are both none this is a + # wildcard pattern. + # Only name being None should not happen but also won't break anything. + pattern: Optional[Pattern] + name: Optional[NameExpr] + + def __init__(self, pattern: Optional[Pattern], name: Optional[NameExpr]) -> None: + super().__init__() + self.pattern = pattern + self.name = name + + def accept(self, visitor: PatternVisitor[T]) -> T: + return visitor.visit_as_pattern(self) + + +class OrPattern(Pattern): + """The pattern | | ...""" + patterns: List[Pattern] + + def __init__(self, patterns: List[Pattern]) -> None: + super().__init__() + self.patterns = patterns + + def accept(self, visitor: PatternVisitor[T]) -> T: + return visitor.visit_or_pattern(self) + + +class ValuePattern(Pattern): + """The pattern x.y (or x.y.z, ...)""" + expr: Expression + + def __init__(self, expr: Expression): + super().__init__() + self.expr = expr + + def accept(self, visitor: PatternVisitor[T]) -> T: + return visitor.visit_value_pattern(self) + + +class SingletonPattern(Pattern): + # This can be exactly True, False or None + value: Union[bool, None] + + def __init__(self, value: Union[bool, None]): + super().__init__() + self.value = value + + def accept(self, visitor: PatternVisitor[T]) -> T: + return visitor.visit_singleton_pattern(self) + + +class SequencePattern(Pattern): + """The pattern [, ...]""" + patterns: List[Pattern] + + def __init__(self, patterns: List[Pattern]): + super().__init__() + self.patterns = patterns + + def accept(self, visitor: PatternVisitor[T]) -> T: + return visitor.visit_sequence_pattern(self) + + +class StarredPattern(Pattern): + # None corresponds to *_ in a list pattern. It will match multiple items but won't bind them to + # a name. + capture: Optional[NameExpr] + + def __init__(self, capture: Optional[NameExpr]): + super().__init__() + self.capture = capture + + def accept(self, visitor: PatternVisitor[T]) -> T: + return visitor.visit_starred_pattern(self) + + +class MappingPattern(Pattern): + keys: List[Expression] + values: List[Pattern] + rest: Optional[NameExpr] + + def __init__(self, keys: List[Expression], values: List[Pattern], + rest: Optional[NameExpr]): + super().__init__() + assert len(keys) == len(values) + self.keys = keys + self.values = values + self.rest = rest + + def accept(self, visitor: PatternVisitor[T]) -> T: + return visitor.visit_mapping_pattern(self) + + +class ClassPattern(Pattern): + """The pattern Cls(...)""" + class_ref: RefExpr + positionals: List[Pattern] + keyword_keys: List[str] + keyword_values: List[Pattern] + + def __init__(self, class_ref: RefExpr, positionals: List[Pattern], keyword_keys: List[str], + keyword_values: List[Pattern]): + super().__init__() + assert len(keyword_keys) == len(keyword_values) + self.class_ref = class_ref + self.positionals = positionals + self.keyword_keys = keyword_keys + self.keyword_values = keyword_values + + def accept(self, visitor: PatternVisitor[T]) -> T: + return visitor.visit_class_pattern(self) diff --git a/mypy/plugin.py b/mypy/plugin.py index 3772d7039b05..dfa446521548 100644 --- a/mypy/plugin.py +++ b/mypy/plugin.py @@ -124,7 +124,7 @@ class C: pass from mypy_extensions import trait, mypyc_attr from mypy.nodes import ( - Expression, Context, ClassDef, SymbolTableNode, MypyFile, CallExpr, ArgKind + Expression, Context, ClassDef, SymbolTableNode, MypyFile, CallExpr, ArgKind, TypeInfo ) from mypy.tvar_scope import TypeVarLikeScope from mypy.types import ( @@ -257,6 +257,12 @@ def named_type(self, fullname: str, """Construct an instance of a builtin type with given type arguments.""" raise NotImplementedError + @abstractmethod + def builtin_type(self, fully_qualified_name: str) -> Instance: + """Legacy function -- use named_type() instead.""" + # NOTE: Do not delete this since many plugins may still use it. + raise NotImplementedError + @abstractmethod def named_type_or_none(self, fullname: str, args: Optional[List[Type]] = None) -> Optional[Instance]: @@ -268,6 +274,10 @@ def named_type_or_none(self, fullname: str, """ raise NotImplementedError + @abstractmethod + def basic_new_typeinfo(self, name: str, basetype_or_fallback: Instance, line: int) -> TypeInfo: + raise NotImplementedError + @abstractmethod def parse_bool(self, expr: Expression) -> Optional[bool]: """Parse True/False literals.""" diff --git a/mypy/plugins/attrs.py b/mypy/plugins/attrs.py index 051dae18b96c..9e4b80c905cf 100644 --- a/mypy/plugins/attrs.py +++ b/mypy/plugins/attrs.py @@ -18,18 +18,19 @@ from mypy.plugin import SemanticAnalyzerPluginInterface from mypy.plugins.common import ( _get_argument, _get_bool_argument, _get_decorator_bool_argument, add_method, - deserialize_and_fixup_type + deserialize_and_fixup_type, add_attribute_to_class, ) from mypy.types import ( TupleType, Type, AnyType, TypeOfAny, CallableType, NoneType, TypeVarType, - Overloaded, UnionType, FunctionLike, get_proper_type, + Overloaded, UnionType, FunctionLike, Instance, get_proper_type, + LiteralType, ) from mypy.typeops import make_simplified_union, map_type_from_supertype from mypy.typevars import fill_typevars from mypy.util import unmangle from mypy.server.trigger import make_wildcard_trigger -KW_ONLY_PYTHON_2_UNSUPPORTED = "kw_only is not supported in Python 2" +KW_ONLY_PYTHON_2_UNSUPPORTED: Final = "kw_only is not supported in Python 2" # The names of the different functions that create classes or arguments. attr_class_makers: Final = { @@ -50,6 +51,8 @@ } SELF_TVAR_NAME: Final = "_AT" +MAGIC_ATTR_NAME: Final = "__attrs_attrs__" +MAGIC_ATTR_CLS_NAME: Final = "_AttrsAttributes" # The namedtuple subclass name. class Converter: @@ -276,6 +279,7 @@ def attr_class_maker_callback(ctx: 'mypy.plugin.ClassDefContext', auto_attribs = _get_decorator_optional_bool_argument(ctx, 'auto_attribs', auto_attribs_default) kw_only = _get_decorator_bool_argument(ctx, 'kw_only', False) + match_args = _get_decorator_bool_argument(ctx, 'match_args', True) if ctx.api.options.python_version[0] < 3: if auto_attribs: @@ -302,9 +306,13 @@ def attr_class_maker_callback(ctx: 'mypy.plugin.ClassDefContext', ctx.api.defer() return - _add_attrs_magic_attribute(ctx, raw_attr_types=[info[attr.name].type for attr in attributes]) + _add_attrs_magic_attribute(ctx, [(attr.name, info[attr.name].type) for attr in attributes]) if slots: _add_slots(ctx, attributes) + if match_args and ctx.api.options.python_version[:2] >= (3, 10): + # `.__match_args__` is only added for python3.10+, but the argument + # exists for earlier versions as well. + _add_match_args(ctx, attributes) # Save the attributes so that subclasses can reuse them. ctx.cls.info.metadata['attrs'] = { @@ -710,23 +718,38 @@ def _add_init(ctx: 'mypy.plugin.ClassDefContext', attributes: List[Attribute], def _add_attrs_magic_attribute(ctx: 'mypy.plugin.ClassDefContext', - raw_attr_types: 'List[Optional[Type]]') -> None: - attr_name = '__attrs_attrs__' + attrs: 'List[Tuple[str, Optional[Type]]]') -> None: any_type = AnyType(TypeOfAny.explicit) attributes_types: 'List[Type]' = [ ctx.api.named_type_or_none('attr.Attribute', [attr_type or any_type]) or any_type - for attr_type in raw_attr_types + for _, attr_type in attrs ] 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)) + + ti = ctx.api.basic_new_typeinfo(MAGIC_ATTR_CLS_NAME, fallback_type, 0) + ti.is_named_tuple = True + for (name, _), attr_type in zip(attrs, attributes_types): + var = Var(name, attr_type) + var.is_property = True + proper_type = get_proper_type(attr_type) + if isinstance(proper_type, Instance): + var.info = proper_type.type + ti.names[name] = SymbolTableNode(MDEF, var, plugin_generated=True) + attributes_type = Instance(ti, []) + + # TODO: refactor using `add_attribute_to_class` + var = Var(name=MAGIC_ATTR_NAME, type=TupleType(attributes_types, fallback=attributes_type)) var.info = ctx.cls.info - var._fullname = ctx.cls.info.fullname + '.' + attr_name - ctx.cls.info.names[attr_name] = SymbolTableNode( + var.is_classvar = True + var._fullname = f"{ctx.cls.fullname}.{MAGIC_ATTR_CLS_NAME}" + var.allow_incompatible_override = True + ctx.cls.info.names[MAGIC_ATTR_NAME] = SymbolTableNode( kind=MDEF, node=var, plugin_generated=True, + no_serialize=True, ) @@ -736,6 +759,29 @@ def _add_slots(ctx: 'mypy.plugin.ClassDefContext', ctx.cls.info.slots = {attr.name for attr in attributes} +def _add_match_args(ctx: 'mypy.plugin.ClassDefContext', + attributes: List[Attribute]) -> None: + if ('__match_args__' not in ctx.cls.info.names + or ctx.cls.info.names['__match_args__'].plugin_generated): + str_type = ctx.api.named_type('builtins.str') + match_args = TupleType( + [ + str_type.copy_modified( + last_known_value=LiteralType(attr.name, fallback=str_type), + ) + for attr in attributes + if not attr.kw_only and attr.init + ], + fallback=ctx.api.named_type('builtins.tuple'), + ) + add_attribute_to_class( + api=ctx.api, + cls=ctx.cls, + name='__match_args__', + typ=match_args, + ) + + class MethodAdder: """Helper to add methods to a TypeInfo. diff --git a/mypy/plugins/common.py b/mypy/plugins/common.py index 1beb53849327..90db614404bd 100644 --- a/mypy/plugins/common.py +++ b/mypy/plugins/common.py @@ -5,7 +5,7 @@ FuncDef, PassStmt, RefExpr, SymbolTableNode, Var, JsonDict, ) from mypy.plugin import CheckerPluginInterface, ClassDefContext, SemanticAnalyzerPluginInterface -from mypy.semanal import set_callable_name +from mypy.semanal import set_callable_name, ALLOW_INCOMPATIBLE_OVERRIDE from mypy.types import ( CallableType, Overloaded, Type, TypeVarType, deserialize_type, get_proper_type, ) @@ -156,6 +156,44 @@ def add_method_to_class( info.defn.defs.body.append(func) +def add_attribute_to_class( + api: SemanticAnalyzerPluginInterface, + cls: ClassDef, + name: str, + typ: Type, + final: bool = False, + no_serialize: bool = False, + override_allow_incompatible: bool = False, +) -> None: + """ + Adds a new attribute to a class definition. + This currently only generates the symbol table entry and no corresponding AssignmentStatement + """ + info = cls.info + + # NOTE: we would like the plugin generated node to dominate, but we still + # need to keep any existing definitions so they get semantically analyzed. + if name in info.names: + # Get a nice unique name instead. + r_name = get_unique_redefinition_name(name, info.names) + info.names[r_name] = info.names[name] + + node = Var(name, typ) + node.info = info + node.is_final = final + if name in ALLOW_INCOMPATIBLE_OVERRIDE: + node.allow_incompatible_override = True + else: + node.allow_incompatible_override = override_allow_incompatible + node._fullname = info.fullname + '.' + name + info.names[name] = SymbolTableNode( + MDEF, + node, + plugin_generated=True, + no_serialize=no_serialize, + ) + + def deserialize_and_fixup_type( data: Union[str, JsonDict], api: SemanticAnalyzerPluginInterface ) -> Type: diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index 6d78bc17e615..211f0a8dda83 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -4,18 +4,19 @@ from typing_extensions import Final from mypy.nodes import ( - ARG_OPT, ARG_NAMED, ARG_NAMED_OPT, ARG_POS, MDEF, Argument, AssignmentStmt, CallExpr, - Context, Expression, JsonDict, NameExpr, RefExpr, - SymbolTableNode, TempNode, TypeInfo, Var, TypeVarExpr, PlaceholderNode + ARG_OPT, ARG_NAMED, ARG_NAMED_OPT, ARG_POS, ARG_STAR, ARG_STAR2, MDEF, + Argument, AssignmentStmt, CallExpr, Context, Expression, JsonDict, + NameExpr, RefExpr, SymbolTableNode, TempNode, TypeInfo, Var, TypeVarExpr, + PlaceholderNode ) from mypy.plugin import ClassDefContext, SemanticAnalyzerPluginInterface from mypy.plugins.common import ( - add_method, _get_decorator_bool_argument, deserialize_and_fixup_type, + add_method, _get_decorator_bool_argument, deserialize_and_fixup_type, add_attribute_to_class, ) from mypy.typeops import map_type_from_supertype from mypy.types import ( - Type, Instance, NoneType, TypeVarType, CallableType, get_proper_type, - AnyType, TypeOfAny, + Type, Instance, NoneType, TypeVarType, CallableType, TupleType, LiteralType, + get_proper_type, AnyType, TypeOfAny, ) from mypy.server.trigger import make_wildcard_trigger @@ -131,6 +132,7 @@ def transform(self) -> None: '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), + 'match_args': _get_decorator_bool_argument(self._ctx, 'match_args', True), } py_version = self._ctx.api.options.python_version @@ -141,11 +143,28 @@ def transform(self) -> None: if (decorator_arguments['init'] and ('__init__' not in info.names or info.names['__init__'].plugin_generated) and attributes): + + args = [attr.to_argument() for attr in attributes if attr.is_in_init + and not self._is_kw_only_type(attr.type)] + + if info.fallback_to_any: + # Make positional args optional since we don't know their order. + # This will at least allow us to typecheck them if they are called + # as kwargs + for arg in args: + if arg.kind == ARG_POS: + arg.kind = ARG_OPT + + nameless_var = Var('') + args = [Argument(nameless_var, AnyType(TypeOfAny.explicit), None, ARG_STAR), + *args, + Argument(nameless_var, AnyType(TypeOfAny.explicit), None, ARG_STAR2), + ] + add_method( ctx, '__init__', - args=[attr.to_argument() for attr in attributes if attr.is_in_init - and not self._is_kw_only_type(attr.type)], + args=args, return_type=NoneType(), ) @@ -200,6 +219,16 @@ def transform(self) -> None: self.reset_init_only_vars(info, attributes) + if (decorator_arguments['match_args'] and + ('__match_args__' not in info.names or + info.names['__match_args__'].plugin_generated) and + attributes): + str_type = ctx.api.named_type("builtins.str") + literals: List[Type] = [LiteralType(attr.name, str_type) + for attr in attributes if attr.is_in_init] + match_args_type = TupleType(literals, ctx.api.named_type("builtins.tuple")) + add_attribute_to_class(ctx.api, ctx.cls, "__match_args__", match_args_type) + self._add_dataclass_fields_magic_attribute() info.metadata['dataclass'] = { @@ -221,9 +250,12 @@ def add_slots(self, self._ctx.reason, ) return - if info.slots is not None or info.names.get('__slots__'): + + generated_slots = {attr.name for attr in attributes} + if ((info.slots is not None and info.slots != generated_slots) + or info.names.get('__slots__')): # This means we have a slots conflict. - # Class explicitly specifies `__slots__` field. + # Class explicitly specifies a different `__slots__` field. # And `@dataclass(slots=True)` is used. # In runtime this raises a type error. self._ctx.api.fail( @@ -234,7 +266,7 @@ def add_slots(self, ) return - info.slots = {attr.name for attr in attributes} + info.slots = generated_slots def reset_init_only_vars(self, info: TypeInfo, attributes: List[DataclassAttribute]) -> None: """Remove init-only vars from the class and reset init var declarations.""" diff --git a/mypy/plugins/default.py b/mypy/plugins/default.py index 67587090e0ba..acbb0460ae07 100644 --- a/mypy/plugins/default.py +++ b/mypy/plugins/default.py @@ -2,10 +2,9 @@ from typing import Callable, Optional, List from mypy import message_registry -from mypy.nodes import Expression, StrExpr, IntExpr, DictExpr, UnaryExpr +from mypy.nodes import StrExpr, IntExpr, DictExpr, UnaryExpr from mypy.plugin import ( - Plugin, FunctionContext, MethodContext, MethodSigContext, AttributeContext, ClassDefContext, - CheckerPluginInterface, + Plugin, FunctionContext, MethodContext, MethodSigContext, AttributeContext, ClassDefContext ) from mypy.plugins.common import try_getting_str_literals from mypy.types import ( @@ -15,7 +14,6 @@ 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): @@ -27,8 +25,6 @@ def get_function_hook(self, fullname: str if fullname in ('contextlib.contextmanager', 'contextlib.asynccontextmanager'): return contextmanager_callback - elif fullname == 'builtins.open' and self.python_version[0] == 3: - return open_callback elif fullname == 'ctypes.Array': return ctypes.array_constructor_callback elif fullname == 'functools.singledispatch': @@ -75,8 +71,6 @@ def get_method_hook(self, fullname: str return ctypes.array_getitem_callback elif fullname == 'ctypes.Array.__iter__': return ctypes.array_iter_callback - elif fullname == 'pathlib.Path.open': - return path_open_callback elif fullname == singledispatch.SINGLEDISPATCH_REGISTER_METHOD: return singledispatch.singledispatch_register_callback elif fullname == singledispatch.REGISTER_CALLABLE_CALL_METHOD: @@ -130,58 +124,6 @@ def get_class_decorator_hook(self, fullname: str return None -def open_callback(ctx: FunctionContext) -> Type: - """Infer a better return type for 'open'.""" - return _analyze_open_signature( - arg_types=ctx.arg_types, - args=ctx.args, - mode_arg_index=1, - default_return_type=ctx.default_return_type, - api=ctx.api, - ) - - -def path_open_callback(ctx: MethodContext) -> Type: - """Infer a better return type for 'pathlib.Path.open'.""" - return _analyze_open_signature( - arg_types=ctx.arg_types, - args=ctx.args, - mode_arg_index=0, - default_return_type=ctx.default_return_type, - api=ctx.api, - ) - - -def _analyze_open_signature(arg_types: List[List[Type]], - args: List[List[Expression]], - mode_arg_index: int, - default_return_type: Type, - api: CheckerPluginInterface, - ) -> Type: - """A helper for analyzing any function that has approximately - the same signature as the builtin 'open(...)' function. - - Currently, the only thing the caller can customize is the index - of the 'mode' argument. If the mode argument is omitted or is a - string literal, we refine the return type to either 'TextIO' or - 'BinaryIO' as appropriate. - """ - mode = None - if not arg_types or len(arg_types[mode_arg_index]) != 1: - mode = 'r' - else: - mode_expr = args[mode_arg_index][0] - if isinstance(mode_expr, StrExpr): - mode = mode_expr.value - if mode is not None: - assert isinstance(default_return_type, Instance) # type: ignore - if 'b' in mode: - return api.named_generic_type('typing.BinaryIO', []) - else: - return api.named_generic_type('typing.TextIO', []) - return default_return_type - - def contextmanager_callback(ctx: FunctionContext) -> Type: """Infer a better return type for 'contextlib.contextmanager'.""" # Be defensive, just in case. @@ -192,12 +134,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 detach_callable(default_return.copy_modified( + return 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 diff --git a/mypy/plugins/singledispatch.py b/mypy/plugins/singledispatch.py index 104faa38d1ce..f4b3d7c19425 100644 --- a/mypy/plugins/singledispatch.py +++ b/mypy/plugins/singledispatch.py @@ -201,15 +201,6 @@ def call_singledispatch_function_after_register_argument(ctx: MethodContext) -> return ctx.default_return_type -def rename_func(func: CallableType, new_name: CallableType) -> CallableType: - """Return a new CallableType that is `function` with the name of `new_name`""" - if new_name.name is not None: - signature_used = func.with_name(new_name.name) - else: - signature_used = func - return signature_used - - def call_singledispatch_function_callback(ctx: MethodSigContext) -> FunctionLike: """Called for functools._SingleDispatchCallable.__call__""" if not isinstance(ctx.type, Instance): diff --git a/mypy/pyinfo.py b/mypy/pyinfo.py index 3834c04e218e..ab2d3286bd5c 100644 --- a/mypy/pyinfo.py +++ b/mypy/pyinfo.py @@ -19,7 +19,7 @@ def getprefixes(): # type: () -> Tuple[str, str] - return sys.base_prefix, sys.prefix + return getattr(sys, "base_prefix", sys.prefix), sys.prefix def getsitepackages(): diff --git a/mypy/reachability.py b/mypy/reachability.py index 44a21b993cfc..eec472376317 100644 --- a/mypy/reachability.py +++ b/mypy/reachability.py @@ -4,11 +4,12 @@ from typing_extensions import Final from mypy.nodes import ( - Expression, IfStmt, Block, AssertStmt, NameExpr, UnaryExpr, MemberExpr, OpExpr, ComparisonExpr, - StrExpr, UnicodeExpr, CallExpr, IntExpr, TupleExpr, IndexExpr, SliceExpr, Import, ImportFrom, - ImportAll, LITERAL_YES + Expression, IfStmt, Block, AssertStmt, MatchStmt, NameExpr, UnaryExpr, MemberExpr, OpExpr, + ComparisonExpr, StrExpr, UnicodeExpr, CallExpr, IntExpr, TupleExpr, IndexExpr, SliceExpr, + Import, ImportFrom, ImportAll, LITERAL_YES ) from mypy.options import Options +from mypy.patterns import Pattern, AsPattern, OrPattern from mypy.traverser import TraverserVisitor from mypy.literals import literal @@ -63,6 +64,30 @@ def infer_reachability_of_if_statement(s: IfStmt, options: Options) -> None: break +def infer_reachability_of_match_statement(s: MatchStmt, options: Options) -> None: + for i, guard in enumerate(s.guards): + pattern_value = infer_pattern_value(s.patterns[i]) + + if guard is not None: + guard_value = infer_condition_value(guard, options) + else: + guard_value = ALWAYS_TRUE + + if pattern_value in (ALWAYS_FALSE, MYPY_FALSE) \ + or guard_value in (ALWAYS_FALSE, MYPY_FALSE): + # The case is considered always false, so we skip the case body. + mark_block_unreachable(s.bodies[i]) + elif pattern_value in (ALWAYS_FALSE, MYPY_TRUE) \ + and guard_value in (ALWAYS_TRUE, MYPY_TRUE): + for body in s.bodies[i + 1:]: + mark_block_unreachable(body) + + if guard_value == MYPY_TRUE: + # This condition is false at runtime; this will affect + # import priorities. + mark_block_mypy_only(s.bodies[i]) + + def assert_will_always_fail(s: AssertStmt, options: Options) -> bool: return infer_condition_value(s.expr, options) in (ALWAYS_FALSE, MYPY_FALSE) @@ -118,6 +143,16 @@ def infer_condition_value(expr: Expression, options: Options) -> int: return result +def infer_pattern_value(pattern: Pattern) -> int: + if isinstance(pattern, AsPattern) and pattern.pattern is None: + return ALWAYS_TRUE + elif isinstance(pattern, OrPattern) and \ + any(infer_pattern_value(p) == ALWAYS_TRUE for p in pattern.patterns): + return ALWAYS_TRUE + else: + return TRUTH_VALUE_UNKNOWN + + def consider_sys_version_info(expr: Expression, pyversion: Tuple[int, ...]) -> int: """Consider whether expr is a comparison involving sys.version_info. diff --git a/mypy/renaming.py b/mypy/renaming.py index a43abb13c688..ae21631f0f0a 100644 --- a/mypy/renaming.py +++ b/mypy/renaming.py @@ -1,12 +1,13 @@ from contextlib import contextmanager -from typing import Dict, Iterator, List +from typing import Dict, Iterator, List, Set from typing_extensions import Final from mypy.nodes import ( Block, AssignmentStmt, NameExpr, MypyFile, FuncDef, Lvalue, ListExpr, TupleExpr, - WhileStmt, ForStmt, BreakStmt, ContinueStmt, TryStmt, WithStmt, StarExpr, ImportFrom, - MemberExpr, IndexExpr, Import, ClassDef + WhileStmt, ForStmt, BreakStmt, ContinueStmt, TryStmt, WithStmt, MatchStmt, StarExpr, + ImportFrom, MemberExpr, IndexExpr, Import, ImportAll, ClassDef ) +from mypy.patterns import AsPattern from mypy.traverser import TraverserVisitor # Scope kinds @@ -159,6 +160,21 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> None: for lvalue in s.lvalues: self.analyze_lvalue(lvalue) + def visit_match_stmt(self, s: MatchStmt) -> None: + for i in range(len(s.patterns)): + with self.enter_block(): + s.patterns[i].accept(self) + guard = s.guards[i] + if guard is not None: + guard.accept(self) + # We already entered a block, so visit this block's statements directly + for stmt in s.bodies[i].body: + stmt.accept(self) + + def visit_capture_pattern(self, p: AsPattern) -> None: + if p.name is not None: + self.analyze_lvalue(p.name) + def analyze_lvalue(self, lvalue: Lvalue, is_nested: bool = False) -> None: """Process assignment; in particular, keep track of (re)defined names. @@ -246,15 +262,9 @@ def flush_refs(self) -> None: # as it will be publicly visible outside the module. to_rename = refs[:-1] for i, item in enumerate(to_rename): - self.rename_refs(item, i) + rename_refs(item, i) self.refs.pop() - def rename_refs(self, names: List[NameExpr], index: int) -> None: - name = names[0].name - new_name = name + "'" * (index + 1) - for expr in names: - expr.name = new_name - # Helpers for determining which assignments define new variables def clear(self) -> None: @@ -376,3 +386,162 @@ def record_assignment(self, name: str, can_be_redefined: bool) -> bool: else: # Assigns to an existing variable. return False + + +class LimitedVariableRenameVisitor(TraverserVisitor): + """Perform some limited variable renaming in with statements. + + This allows reusing a variable in multiple with statements with + different types. For example, the two instances of 'x' can have + incompatible types: + + with C() as x: + f(x) + with D() as x: + g(x) + + The above code gets renamed conceptually into this (not valid Python!): + + with C() as x': + f(x') + with D() as x: + g(x) + + If there's a reference to a variable defined in 'with' outside the + statement, or if there's any trickiness around variable visibility + (e.g. function definitions), we give up and won't perform renaming. + + The main use case is to allow binding both readable and writable + binary files into the same variable. These have different types: + + with open(fnam, 'rb') as f: ... + with open(fnam, 'wb') as f: ... + """ + + def __init__(self) -> None: + # Short names of variables bound in with statements using "as" + # in a surrounding scope + self.bound_vars: List[str] = [] + # Stack of names that can't be safely renamed, per scope ('*' means that + # no names can be renamed) + self.skipped: List[Set[str]] = [] + # References to variables that we may need to rename. Stack of + # scopes; each scope is a mapping from name to list of collections + # of names that refer to the same logical variable. + self.refs: List[Dict[str, List[List[NameExpr]]]] = [] + + def visit_mypy_file(self, file_node: MypyFile) -> None: + """Rename variables within a file. + + This is the main entry point to this class. + """ + with self.enter_scope(): + for d in file_node.defs: + d.accept(self) + + def visit_func_def(self, fdef: FuncDef) -> None: + self.reject_redefinition_of_vars_in_scope() + with self.enter_scope(): + for arg in fdef.arguments: + self.record_skipped(arg.variable.name) + super().visit_func_def(fdef) + + def visit_class_def(self, cdef: ClassDef) -> None: + self.reject_redefinition_of_vars_in_scope() + with self.enter_scope(): + super().visit_class_def(cdef) + + def visit_with_stmt(self, stmt: WithStmt) -> None: + for expr in stmt.expr: + expr.accept(self) + old_len = len(self.bound_vars) + for target in stmt.target: + if target is not None: + self.analyze_lvalue(target) + for target in stmt.target: + if target: + target.accept(self) + stmt.body.accept(self) + + while len(self.bound_vars) > old_len: + self.bound_vars.pop() + + def analyze_lvalue(self, lvalue: Lvalue) -> None: + if isinstance(lvalue, NameExpr): + name = lvalue.name + if name in self.bound_vars: + # Name bound in a surrounding with statement, so it can be renamed + self.visit_name_expr(lvalue) + else: + var_info = self.refs[-1] + if name not in var_info: + var_info[name] = [] + var_info[name].append([]) + self.bound_vars.append(name) + elif isinstance(lvalue, (ListExpr, TupleExpr)): + for item in lvalue.items: + self.analyze_lvalue(item) + elif isinstance(lvalue, MemberExpr): + lvalue.expr.accept(self) + elif isinstance(lvalue, IndexExpr): + lvalue.base.accept(self) + lvalue.index.accept(self) + elif isinstance(lvalue, StarExpr): + self.analyze_lvalue(lvalue.expr) + + def visit_import(self, imp: Import) -> None: + # We don't support renaming imports + for id, as_id in imp.ids: + self.record_skipped(as_id or id) + + def visit_import_from(self, imp: ImportFrom) -> None: + # We don't support renaming imports + for id, as_id in imp.names: + self.record_skipped(as_id or id) + + def visit_import_all(self, imp: ImportAll) -> None: + # Give up, since we don't know all imported names yet + self.reject_redefinition_of_vars_in_scope() + + def visit_name_expr(self, expr: NameExpr) -> None: + name = expr.name + if name in self.bound_vars: + # Record reference so that it can be renamed later + for scope in reversed(self.refs): + if name in scope: + scope[name][-1].append(expr) + else: + self.record_skipped(name) + + @contextmanager + def enter_scope(self) -> Iterator[None]: + self.skipped.append(set()) + self.refs.append({}) + yield None + self.flush_refs() + + def reject_redefinition_of_vars_in_scope(self) -> None: + self.record_skipped('*') + + def record_skipped(self, name: str) -> None: + self.skipped[-1].add(name) + + def flush_refs(self) -> None: + ref_dict = self.refs.pop() + skipped = self.skipped.pop() + if '*' not in skipped: + for name, refs in ref_dict.items(): + if len(refs) <= 1 or name in skipped: + continue + # At module top level we must not rename the final definition, + # as it may be publicly visible + to_rename = refs[:-1] + for i, item in enumerate(to_rename): + rename_refs(item, i) + + +def rename_refs(names: List[NameExpr], index: int) -> None: + name = names[0].name + new_name = name + "'" * (index + 1) + for expr in names: + expr.name = new_name diff --git a/mypy/report.py b/mypy/report.py index 380a8c6b6441..23b5c78ef929 100644 --- a/mypy/report.py +++ b/mypy/report.py @@ -245,10 +245,10 @@ def _write_out_report(self, f.write(separator + '\n') for row_values in rows: r = ("{:>{}}" * len(widths)).format(*itertools.chain(*zip(row_values, widths))) - f.writelines(r + '\n') + f.write(r + '\n') f.write(separator + '\n') footer_str = ("{:>{}}" * len(widths)).format(*itertools.chain(*zip(footer, widths))) - f.writelines(footer_str + '\n') + f.write(footer_str + '\n') def _report_any_exprs(self) -> None: total_any = sum(num_any for num_any, _ in self.counts.values()) diff --git a/mypy/semanal.py b/mypy/semanal.py index 9a5076beb6f4..30134d5b1003 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -51,7 +51,7 @@ from contextlib import contextmanager from typing import ( - List, Dict, Set, Tuple, cast, TypeVar, Union, Optional, Callable, Iterator, Iterable + Any, List, Dict, Set, Tuple, cast, TypeVar, Union, Optional, Callable, Iterator, Iterable ) from typing_extensions import Final, TypeAlias as _TypeAlias @@ -77,7 +77,12 @@ REVEAL_LOCALS, is_final_node, TypedDictExpr, type_aliases_source_versions, typing_extensions_aliases, EnumCallExpr, RUNTIME_PROTOCOL_DECOS, FakeExpression, Statement, AssignmentExpr, - ParamSpecExpr, EllipsisExpr, TypeVarLikeExpr, FuncBase, implicit_module_attrs, + ParamSpecExpr, EllipsisExpr, TypeVarLikeExpr, implicit_module_attrs, + MatchStmt, FuncBase +) +from mypy.patterns import ( + AsPattern, OrPattern, ValuePattern, SequencePattern, + StarredPattern, MappingPattern, ClassPattern, ) from mypy.tvar_scope import TypeVarLikeScope from mypy.typevars import fill_typevars @@ -89,10 +94,12 @@ from mypy.errorcodes import ErrorCode from mypy import message_registry, errorcodes as codes from mypy.types import ( - FunctionLike, UnboundType, TypeVarType, TupleType, UnionType, StarType, + NEVER_NAMES, 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, TypeVarLikeType + get_proper_type, get_proper_types, TypeAliasType, TypeVarLikeType, + PROTOCOL_NAMES, TYPE_ALIAS_NAMES, FINAL_TYPE_NAMES, FINAL_DECORATOR_NAMES, REVEAL_TYPE_NAMES, + is_named_instance, ) from mypy.typeops import function_type, get_type_vars from mypy.type_visitor import TypeQuery @@ -109,6 +116,7 @@ ) from mypy.util import ( correct_relative_import, unmangle, module_prefix, is_typeshed_file, unnamed_function, + is_dunder, ) from mypy.scope import Scope from mypy.semanal_shared import ( @@ -116,11 +124,11 @@ ) from mypy.semanal_namedtuple import NamedTupleAnalyzer from mypy.semanal_typeddict import TypedDictAnalyzer -from mypy.semanal_enum import EnumCallAnalyzer, ENUM_BASES +from mypy.semanal_enum import EnumCallAnalyzer from mypy.semanal_newtype import NewTypeAnalyzer from mypy.reachability import ( - infer_reachability_of_if_statement, infer_condition_value, ALWAYS_FALSE, ALWAYS_TRUE, - MYPY_TRUE, MYPY_FALSE + infer_reachability_of_if_statement, infer_reachability_of_match_statement, + infer_condition_value, ALWAYS_FALSE, ALWAYS_TRUE, MYPY_TRUE, MYPY_FALSE ) from mypy.mro import calculate_mro, MroError @@ -145,6 +153,10 @@ # available very early on. CORE_BUILTIN_CLASSES: Final = ["object", "bool", "function"] +# Subclasses can override these Var attributes with incompatible types. This can also be +# set for individual attributes using 'allow_incompatible_override' of Var. +ALLOW_INCOMPATIBLE_OVERRIDE: Final = ('__slots__', '__deletable__', '__match_args__') + # Used for tracking incomplete references Tag: _TypeAlias = int @@ -219,7 +231,6 @@ class SemanticAnalyzer(NodeVisitor[None], errors: Errors # Keeps track of generated errors plugin: Plugin # Mypy plugin for special casing of library features statement: Optional[Statement] = None # Statement/definition being analyzed - future_import_flags: Set[str] # Mapping from 'async def' function definitions to their return type wrapped as a # 'Coroutine[Any, Any, T]'. Used to keep track of whether a function definition's @@ -284,8 +295,6 @@ def __init__(self, # current SCC or top-level function. self.deferral_debug_context: List[Tuple[str, int]] = [] - self.future_import_flags: Set[str] = set() - # mypyc doesn't properly handle implementing an abstractproperty # with a regular attribute so we make them properties @property @@ -878,7 +887,7 @@ def handle_missing_overload_implementation(self, defn: OverloadedFuncDef) -> Non else: self.fail( "An overloaded function outside a stub file must have an implementation", - defn) + defn, code=codes.NO_OVERLOAD_IMPL) def process_final_in_overload(self, defn: OverloadedFuncDef) -> None: """Detect the @final status of an overloaded function (and perform checks).""" @@ -1037,8 +1046,7 @@ def visit_decorator(self, dec: Decorator) -> None: removed.append(i) dec.func.is_abstract = True self.check_decorated_function_is_method('abstractmethod', dec) - elif (refers_to_fullname(d, 'asyncio.coroutines.coroutine') or - refers_to_fullname(d, 'types.coroutine')): + elif refers_to_fullname(d, ('asyncio.coroutines.coroutine', 'types.coroutine')): removed.append(i) dec.func.is_awaitable_coroutine = True elif refers_to_fullname(d, 'builtins.staticmethod'): @@ -1051,9 +1059,10 @@ def visit_decorator(self, dec: Decorator) -> None: dec.func.is_class = True dec.var.is_classmethod = True self.check_decorated_function_is_method('classmethod', dec) - elif (refers_to_fullname(d, 'builtins.property') or - refers_to_fullname(d, 'abc.abstractproperty') or - refers_to_fullname(d, 'functools.cached_property')): + elif refers_to_fullname(d, ( + 'builtins.property', + 'abc.abstractproperty', + 'functools.cached_property')): removed.append(i) dec.func.is_property = True dec.var.is_property = True @@ -1067,8 +1076,7 @@ def visit_decorator(self, dec: Decorator) -> None: elif refers_to_fullname(d, 'typing.no_type_check'): dec.var.type = AnyType(TypeOfAny.special_form) no_type_check = True - elif (refers_to_fullname(d, 'typing.final') or - refers_to_fullname(d, 'typing_extensions.final')): + elif refers_to_fullname(d, FINAL_DECORATOR_NAMES): if self.is_class_scope(): assert self.type is not None, "No type set at class scope" if self.type.is_protocol: @@ -1154,8 +1162,7 @@ def analyze_class(self, defn: ClassDef) -> None: for decorator in defn.decorators: decorator.accept(self) if isinstance(decorator, RefExpr): - if decorator.fullname in ('typing.final', - 'typing_extensions.final'): + if decorator.fullname in FINAL_DECORATOR_NAMES: self.fail("@final cannot be used with TypedDict", decorator) if info is None: self.mark_incomplete(defn.name, defn) @@ -1282,8 +1289,7 @@ def analyze_class_decorator(self, defn: ClassDef, decorator: Expression) -> None else: self.fail('@runtime_checkable can only be used with protocol classes', defn) - elif decorator.fullname in ('typing.final', - 'typing_extensions.final'): + elif decorator.fullname in FINAL_DECORATOR_NAMES: defn.info.is_final = True def clean_up_bases_and_infer_type_variables( @@ -1328,8 +1334,7 @@ class Foo(Bar, Generic[T]): ... if isinstance(base, UnboundType): sym = self.lookup_qualified(base.name, base) if sym is not None and sym.node is not None: - if (sym.node.fullname in ('typing.Protocol', 'typing_extensions.Protocol') and - i not in removed): + if sym.node.fullname in PROTOCOL_NAMES and i not in removed: # also remove bare 'Protocol' bases removed.append(i) is_protocol = True @@ -1377,8 +1382,7 @@ def analyze_class_typevar_declaration( if sym is None or sym.node is None: return None if (sym.node.fullname == 'typing.Generic' or - sym.node.fullname == 'typing.Protocol' and base.args or - sym.node.fullname == 'typing_extensions.Protocol' and base.args): + sym.node.fullname in PROTOCOL_NAMES and base.args): is_proto = sym.node.fullname != 'typing.Generic' tvars: TypeVarLikeList = [] for arg in unbound.args: @@ -1552,18 +1556,6 @@ def configure_base_classes(self, elif isinstance(base, Instance): if base.type.is_newtype: self.fail('Cannot subclass "NewType"', defn) - if ( - base.type.is_enum - and base.type.fullname not in ENUM_BASES - and base.type.names - and any(not isinstance(n.node, (FuncBase, Decorator)) - for n in base.type.names.values()) - ): - # 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. - base.type.is_final = True base_types.append(base) elif isinstance(base, AnyType): if self.options.disallow_subclassing_any: @@ -1892,7 +1884,11 @@ def process_imported_symbol(self, fullname: str, module_public: bool, context: ImportBase) -> None: - module_hidden = not module_public and fullname not in self.modules + module_hidden = not module_public and not ( + # `from package import module` should work regardless of whether package + # re-exports module + isinstance(node.node, MypyFile) and fullname in self.modules + ) if isinstance(node.node, PlaceholderNode): if self.final_iteration: @@ -2023,12 +2019,10 @@ def visit_import_all(self, i: ImportAll) -> None: if self.process_import_over_existing_name( name, existing_symbol, node, i): continue - # In stub files, `from x import *` always reexports the symbols. - # In regular files, only if implicit reexports are enabled. - module_public = self.is_stub_file or self.options.implicit_reexport + # `from x import *` always reexports symbols self.add_imported_symbol(name, node, i, - module_public=module_public, - module_hidden=not module_public) + module_public=True, + module_hidden=False) else: # Don't add any dummy symbols for 'from x import *' if 'x' is unknown. @@ -2040,7 +2034,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 @@ -2091,10 +2085,10 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> None: s.is_final_def = self.unwrap_final(s) self.analyze_lvalues(s) self.check_final_implicit_def(s) + self.store_final_status(s) self.check_classvar(s) self.process_type_annotation(s) self.apply_dynamic_class_hook(s) - self.store_final_status(s) if not s.type: self.process_module_assignment(s.lvalues, s.rvalue, s) self.process__all__(s) @@ -2185,11 +2179,14 @@ def can_be_type_alias(self, rv: Expression, allow_none: bool = False) -> bool: return True if allow_none and isinstance(rv, NameExpr) and rv.fullname == 'builtins.None': return True - if (isinstance(rv, OpExpr) - and rv.op == '|' - and self.can_be_type_alias(rv.left, allow_none=True) - and self.can_be_type_alias(rv.right, allow_none=True)): - return True + if isinstance(rv, OpExpr) and rv.op == '|': + if self.is_stub_file: + return True + if ( + self.can_be_type_alias(rv.left, allow_none=True) + and self.can_be_type_alias(rv.right, allow_none=True) + ): + return True return False def is_type_ref(self, rv: Expression, bare: bool = False) -> bool: @@ -2231,6 +2228,8 @@ def is_type_ref(self, rv: Expression, bare: bool = False) -> bool: return True # Assignment color = Color['RED'] defines a variable, not an alias. return not rv.node.is_enum + if isinstance(rv.node, Var): + return rv.node.fullname in NEVER_NAMES if isinstance(rv, NameExpr): n = self.lookup(rv.name, rv) @@ -2333,10 +2332,20 @@ 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 not isinstance(s.rvalue, CallExpr): @@ -2469,8 +2478,9 @@ def store_final_status(self, s: AssignmentStmt) -> None: 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 + # Double underscored members are writable on an `Enum`. + # (Except read-only `__members__` but that is handled in type checker) + cur_node.node.is_final = s.is_final_def = not is_dunder(cur_node.node.name) # Special case: deferred initialization of a final attribute in __init__. # In this case we just pretend this is a valid final definition to suppress @@ -2605,7 +2615,6 @@ def analyze_alias(self, rvalue: Expression, self.plugin, self.options, self.is_typeshed_stub_file, - allow_new_syntax=self.is_stub_file, allow_placeholder=allow_placeholder, in_dynamic_func=dynamic, global_scope=global_scope) @@ -2637,10 +2646,10 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool: 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"): + lookup = self.lookup_qualified(s.unanalyzed_type.name, s, suppress_errors=True) + if lookup and lookup.fullname in TYPE_ALIAS_NAMES: pep_613 = True - if s.unanalyzed_type is not None and not pep_613: + if not pep_613 and s.unanalyzed_type is not None: # Second rule: Explicit type (cls: Type[A] = A) always creates variable, not alias. # unless using PEP 613 `cls: TypeAlias = A` return False @@ -2667,7 +2676,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 and not pep_613: + if not pep_613 and isinstance(s.rvalue, RefExpr) and non_global_scope: # Fourth rule (special case): Non-subscripted right hand side creates a variable # at class and function scopes. For example: # @@ -2680,7 +2689,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) and not pep_613: + if not pep_613 and not self.can_be_type_alias(rvalue): return False if existing and not isinstance(existing.node, (PlaceholderNode, TypeAlias)): @@ -2776,7 +2785,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: @@ -2790,7 +2800,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): @@ -2814,7 +2828,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". @@ -2837,14 +2852,14 @@ def analyze_name_lvalue(self, 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: + if existing is not None and not isinstance(existing.node, PlaceholderNode): 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: @@ -2895,21 +2910,26 @@ 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) + name = lvalue.name + v = Var(name) v.set_line(lvalue) v.is_inferred = inferred if kind == MDEF: assert self.type is not None v.info = self.type v.is_initialized_in_class = True + v.allow_incompatible_override = name in ALLOW_INCOMPATIBLE_OVERRIDE if kind != LDEF: - v._fullname = self.qualified_name(lvalue.name) + v._fullname = self.qualified_name(name) else: # fullanme should never stay None - v._fullname = lvalue.name + v._fullname = 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( @@ -2953,7 +2973,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. @@ -3269,6 +3296,15 @@ def process_paramspec_declaration(self, s: AssignmentStmt) -> bool: if not self.check_typevarlike_name(call, name, s): return False + # ParamSpec is different from a regular TypeVar: + # arguments are not semantically valid. But, allowed in runtime. + # So, we need to warn users about possible invalid usage. + if len(call.args) > 1: + self.fail( + "Only the first argument to ParamSpec has defined semantics", + s, + ) + # PEP 612 reserves the right to define bound, covariant and contravariant arguments to # ParamSpec in a later PEP. If and when that happens, we should do something # on the lines of process_typevar_parameters @@ -3363,7 +3399,7 @@ def is_final_type(self, typ: Optional[Type]) -> bool: sym = self.lookup_qualified(typ.name, typ) if not sym or not sym.node: return False - return sym.node.fullname in ('typing.Final', 'typing_extensions.Final') + return sym.node.fullname in FINAL_TYPE_NAMES def fail_invalid_classvar(self, context: Context) -> None: self.fail(message_registry.CLASS_VAR_OUTSIDE_OF_CLASS, context) @@ -3735,6 +3771,17 @@ def visit_exec_stmt(self, s: ExecStmt) -> None: if s.locals: s.locals.accept(self) + def visit_match_stmt(self, s: MatchStmt) -> None: + self.statement = s + infer_reachability_of_match_statement(s, self.options) + s.subject.accept(self) + for i in range(len(s.patterns)): + s.patterns[i].accept(self) + guard = s.guards[i] + if guard is not None: + guard.accept(self) + self.visit_block(s.bodies[i]) + # # Expressions # @@ -3796,13 +3843,15 @@ def visit_star_expr(self, expr: StarExpr) -> None: expr.expr.accept(self) def visit_yield_from_expr(self, e: YieldFromExpr) -> None: - if not self.is_func_scope(): # not sure + if not self.is_func_scope(): self.fail('"yield from" outside function', e, serious=True, blocker=True) + elif self.is_comprehension_stack[-1]: + self.fail('"yield from" inside comprehension or generator expression', + e, serious=True, blocker=True) + elif self.function_stack[-1].is_coroutine: + self.fail('"yield from" in async function', e, serious=True, blocker=True) else: - if self.function_stack[-1].is_coroutine: - self.fail('"yield from" in async function', e, serious=True, blocker=True) - else: - self.function_stack[-1].is_generator = True + self.function_stack[-1].is_generator = True if e.expr: e.expr.accept(self) @@ -3829,7 +3878,7 @@ def visit_call_expr(self, expr: CallExpr) -> None: expr.analyzed.line = expr.line expr.analyzed.column = expr.column expr.analyzed.accept(self) - elif refers_to_fullname(expr.callee, 'builtins.reveal_type'): + elif refers_to_fullname(expr.callee, REVEAL_TYPE_NAMES): if not self.check_fixed_args(expr, 1, 'reveal_type'): return expr.analyzed = RevealExpr(kind=REVEAL_TYPE, expr=expr.args[0]) @@ -4044,6 +4093,7 @@ def analyze_type_application(self, expr: IndexExpr) -> None: name = target.type.fullname if (alias.no_args and # this avoids bogus errors for already reported aliases name in get_nongen_builtins(self.options.python_version) and + not self.is_stub_file and not alias.normalized): self.fail(no_subscript_builtin_alias(name, propose_alt=False), expr) # ...or directly. @@ -4179,20 +4229,22 @@ def visit__promote_expr(self, expr: PromoteExpr) -> None: if analyzed is not None: expr.type = analyzed - def visit_yield_expr(self, expr: YieldExpr) -> None: + def visit_yield_expr(self, e: YieldExpr) -> None: if not self.is_func_scope(): - self.fail('"yield" outside function', expr, serious=True, blocker=True) - else: - if self.function_stack[-1].is_coroutine: - if self.options.python_version < (3, 6): - self.fail('"yield" in async function', expr, serious=True, blocker=True) - else: - self.function_stack[-1].is_generator = True - self.function_stack[-1].is_async_generator = True + self.fail('"yield" outside function', e, serious=True, blocker=True) + elif self.is_comprehension_stack[-1]: + self.fail('"yield" inside comprehension or generator expression', + e, serious=True, blocker=True) + elif self.function_stack[-1].is_coroutine: + if self.options.python_version < (3, 6): + self.fail('"yield" in async function', e, serious=True, blocker=True) else: self.function_stack[-1].is_generator = True - if expr.expr: - expr.expr.accept(self) + self.function_stack[-1].is_async_generator = True + else: + self.function_stack[-1].is_generator = True + if e.expr: + e.expr.accept(self) def visit_await_expr(self, expr: AwaitExpr) -> None: if not self.is_func_scope(): @@ -4201,6 +4253,46 @@ def visit_await_expr(self, expr: AwaitExpr) -> None: self.fail('"await" outside coroutine ("async def")', expr) expr.expr.accept(self) + # + # Patterns + # + + def visit_as_pattern(self, p: AsPattern) -> None: + if p.pattern is not None: + p.pattern.accept(self) + if p.name is not None: + self.analyze_lvalue(p.name) + + def visit_or_pattern(self, p: OrPattern) -> None: + for pattern in p.patterns: + pattern.accept(self) + + def visit_value_pattern(self, p: ValuePattern) -> None: + p.expr.accept(self) + + def visit_sequence_pattern(self, p: SequencePattern) -> None: + for pattern in p.patterns: + pattern.accept(self) + + def visit_starred_pattern(self, p: StarredPattern) -> None: + if p.capture is not None: + self.analyze_lvalue(p.capture) + + def visit_mapping_pattern(self, p: MappingPattern) -> None: + for key in p.keys: + key.accept(self) + for value in p.values: + value.accept(self) + if p.rest is not None: + self.analyze_lvalue(p.rest) + + def visit_class_pattern(self, p: ClassPattern) -> None: + p.class_ref.accept(self) + for pos in p.positionals: + pos.accept(self) + for v in p.keyword_values: + v.accept(self) + # # Lookup functions # @@ -4256,7 +4348,7 @@ def lookup(self, name: str, ctx: Context, assert isinstance(b.node, MypyFile) table = b.node.names if name in table: - if name[0] == "_" and name[1] != "_": + if len(name) > 1 and name[0] == "_" and name[1] != "_": if not suppress_errors: self.name_not_defined(name, ctx) return None @@ -4519,6 +4611,10 @@ def named_type_or_none(self, fullname: str, return Instance(node, args) return Instance(node, [AnyType(TypeOfAny.unannotated)] * len(node.defn.type_vars)) + def builtin_type(self, fully_qualified_name: str) -> Instance: + """Legacy function -- use named_type() instead.""" + return self.named_type(fully_qualified_name) + def lookup_current_scope(self, name: str) -> Optional[SymbolTableNode]: if self.locals[-1] is not None: return self.locals[-1].get(name) @@ -4699,6 +4795,48 @@ def add_module_symbol(self, module_hidden=module_hidden ) + def _get_node_for_class_scoped_import( + self, name: str, symbol_node: Optional[SymbolNode], context: Context + ) -> Optional[SymbolNode]: + if symbol_node is None: + return None + # I promise this type checks; I'm just making mypyc issues go away. + # mypyc is absolutely convinced that `symbol_node` narrows to a Var in the following, + # when it can also be a FuncBase. Once fixed, `f` in the following can be removed. + # See also https://github.com/mypyc/mypyc/issues/892 + f = cast(Any, lambda x: x) + if isinstance(f(symbol_node), (FuncBase, Var)): + # For imports in class scope, we construct a new node to represent the symbol and + # set its `info` attribute to `self.type`. + existing = self.current_symbol_table().get(name) + if ( + # The redefinition checks in `add_symbol_table_node` don't work for our + # constructed Var / FuncBase, so check for possible redefinitions here. + existing is not None + and isinstance(f(existing.node), (FuncBase, Var)) + and ( + isinstance(f(existing.type), f(AnyType)) + or f(existing.type) == f(symbol_node).type + ) + ): + return existing.node + + # Construct the new node + if isinstance(f(symbol_node), FuncBase): + # In theory we could construct a new node here as well, but in practice + # it doesn't work well, see #12197 + typ: Optional[Type] = AnyType(TypeOfAny.from_error) + self.fail('Unsupported class scoped import', context) + else: + typ = f(symbol_node).type + symbol_node = Var(name, typ) + symbol_node._fullname = self.qualified_name(name) + assert self.type is not None # guaranteed by is_class_scope + symbol_node.info = self.type + symbol_node.line = context.line + symbol_node.column = context.column + return symbol_node + def add_imported_symbol(self, name: str, node: SymbolTableNode, @@ -4707,7 +4845,13 @@ def add_imported_symbol(self, module_hidden: bool) -> None: """Add an alias to an existing symbol through import.""" assert not module_hidden or not module_public - symbol = SymbolTableNode(node.kind, node.node, + + symbol_node: Optional[SymbolNode] = node.node + + if self.is_class_scope(): + symbol_node = self._get_node_for_class_scoped_import(name, symbol_node, context) + + symbol = SymbolTableNode(node.kind, symbol_node, module_public=module_public, module_hidden=module_hidden) self.add_symbol_table_node(name, symbol, context) @@ -4937,19 +5081,6 @@ def add_exports(self, exp_or_exps: Union[Iterable[Expression], Expression]) -> N if isinstance(exp, StrExpr): self.all_exports.append(exp.value) - def check_no_global(self, - name: str, - ctx: Context, - is_overloaded_func: bool = False) -> None: - if name in self.globals: - prev_is_overloaded = isinstance(self.globals[name], OverloadedFuncDef) - if is_overloaded_func and prev_is_overloaded: - self.fail("Nonconsecutive overload {} found".format(name), ctx) - elif prev_is_overloaded: - self.fail("Definition of '{}' missing 'overload'".format(name), ctx) - else: - self.name_already_defined(name, ctx, self.globals[name]) - def name_not_defined(self, name: str, ctx: Context, namespace: Optional[str] = None) -> None: incomplete = self.is_incomplete_namespace(namespace or self.cur_mod_id) if (namespace is None @@ -5079,9 +5210,6 @@ def fail(self, assert ctx is not None, msg self.errors.report(ctx.get_line(), ctx.get_column(), msg, blocker=blocker, code=code) - 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.in_checked_function(): return @@ -5143,8 +5271,7 @@ def type_analyzer(self, *, allow_tuple_literal=allow_tuple_literal, report_invalid_types=report_invalid_types, allow_placeholder=allow_placeholder, - allow_required=allow_required, - allow_new_syntax=self.is_stub_file) + allow_required=allow_required) 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 @@ -5252,10 +5379,12 @@ def parse_bool(self, expr: Expression) -> Optional[bool]: def set_future_import_flags(self, module_name: str) -> None: if module_name in FUTURE_IMPORTS: - self.future_import_flags.add(FUTURE_IMPORTS[module_name]) + self.modules[self.cur_mod_id].future_import_flags.add( + FUTURE_IMPORTS[module_name], + ) def is_future_flag_set(self, flag: str) -> bool: - return flag in self.future_import_flags + return self.modules[self.cur_mod_id].is_future_flag_set(flag) class HasPlaceholders(TypeQuery[bool]): @@ -5283,16 +5412,17 @@ def replace_implicit_first_type(sig: FunctionLike, new: Type) -> FunctionLike: assert False -def refers_to_fullname(node: Expression, fullname: str) -> bool: +def refers_to_fullname(node: Expression, fullnames: Union[str, Tuple[str, ...]]) -> bool: """Is node a name or member expression with the given full name?""" + if not isinstance(fullnames, tuple): + fullnames = (fullnames,) + if not isinstance(node, RefExpr): return False - if node.fullname == fullname: + if node.fullname in fullnames: return True if isinstance(node.node, TypeAlias): - target = get_proper_type(node.node.target) - if isinstance(target, Instance) and target.type.fullname == fullname: - return True + return is_named_instance(node.node.target, fullnames) return False diff --git a/mypy/semanal_enum.py b/mypy/semanal_enum.py index 5682f66298f6..8b5ecf1b1df4 100644 --- a/mypy/semanal_enum.py +++ b/mypy/semanal_enum.py @@ -13,14 +13,17 @@ ) from mypy.semanal_shared import SemanticAnalyzerInterface from mypy.options import Options +from mypy.types import get_proper_type, LiteralType, ENUM_REMOVED_PROPS # 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.Enum', 'enum.IntEnum', 'enum.Flag', 'enum.IntFlag', 'enum.StrEnum', )) ENUM_SPECIAL_PROPS: Final = frozenset(( - 'name', 'value', '_name_', '_value_', '_order_', '__order__', + 'name', 'value', '_name_', '_value_', *ENUM_REMOVED_PROPS, + # Also attributes from `object`: + '__module__', '__annotations__', '__doc__', '__slots__', '__dict__', )) @@ -171,6 +174,23 @@ def parse_enum_call_args(self, call: CallExpr, "%s() with dict literal requires string literals" % class_name, call) items.append(key.value) values.append(value) + elif isinstance(args[1], RefExpr) and isinstance(args[1].node, Var): + proper_type = get_proper_type(args[1].node.type) + if (proper_type is not None + and isinstance(proper_type, LiteralType) + and isinstance(proper_type.value, str)): + fields = proper_type.value + for field in fields.replace(',', ' ').split(): + items.append(field) + elif args[1].node.is_final and isinstance(args[1].node.final_value, str): + fields = args[1].node.final_value + for field in fields.replace(',', ' ').split(): + items.append(field) + else: + return self.fail_enum_call_arg( + "%s() expects a string, tuple, list or dict literal as the second argument" % + class_name, + call) else: # TODO: Allow dict(x=1, y=2) as a substitute for {'x': 1, 'y': 2}? return self.fail_enum_call_arg( diff --git a/mypy/semanal_main.py b/mypy/semanal_main.py index 7e187945da48..d935252ba9cf 100644 --- a/mypy/semanal_main.py +++ b/mypy/semanal_main.py @@ -307,7 +307,7 @@ def semantic_analyze_target(target: str, Return tuple with these items: - list of deferred targets - was some definition incomplete (need to run another pass) - - were any new names were defined (or placeholders replaced) + - were any new names defined (or placeholders replaced) """ state.manager.processed_targets.append(target) tree = state.tree diff --git a/mypy/semanal_namedtuple.py b/mypy/semanal_namedtuple.py index 8930c63d2bef..2357225caebb 100644 --- a/mypy/semanal_namedtuple.py +++ b/mypy/semanal_namedtuple.py @@ -9,7 +9,7 @@ from mypy.types import ( Type, TupleType, AnyType, TypeOfAny, CallableType, TypeType, TypeVarType, - UnboundType, + UnboundType, LiteralType, ) from mypy.semanal_shared import ( SemanticAnalyzerInterface, set_callable_name, calculate_tuple_fallback, PRIORITY_FALLBACKS @@ -398,6 +398,9 @@ def build_namedtuple_typeinfo(self, iterable_type = self.api.named_type_or_none('typing.Iterable', [implicit_any]) function_type = self.api.named_type('builtins.function') + literals: List[Type] = [LiteralType(item, strtype) for item in items] + match_args_type = TupleType(literals, basetuple_type) + info = self.api.basic_new_typeinfo(name, fallback, line) info.is_named_tuple = True tuple_base = TupleType(types, fallback) @@ -436,6 +439,7 @@ def add_field(var: Var, is_initialized_in_class: bool = False, add_field(Var('_source', strtype), is_initialized_in_class=True) add_field(Var('__annotations__', ordereddictype), is_initialized_in_class=True) add_field(Var('__doc__', strtype), is_initialized_in_class=True) + add_field(Var('__match_args__', match_args_type), is_initialized_in_class=True) tvd = TypeVarType(SELF_TVAR_NAME, info.fullname + '.' + SELF_TVAR_NAME, -1, [], info.tuple_type) diff --git a/mypy/semanal_pass1.py b/mypy/semanal_pass1.py index 0296788e3990..2b096f08082a 100644 --- a/mypy/semanal_pass1.py +++ b/mypy/semanal_pass1.py @@ -2,11 +2,14 @@ from mypy.nodes import ( MypyFile, AssertStmt, IfStmt, Block, AssignmentStmt, ExpressionStmt, ReturnStmt, ForStmt, - Import, ImportAll, ImportFrom, ClassDef, FuncDef + MatchStmt, Import, ImportAll, ImportFrom, ClassDef, FuncDef ) from mypy.traverser import TraverserVisitor from mypy.options import Options -from mypy.reachability import infer_reachability_of_if_statement, assert_will_always_fail +from mypy.reachability import ( + infer_reachability_of_if_statement, assert_will_always_fail, + infer_reachability_of_match_statement +) class SemanticAnalyzerPreAnalysis(TraverserVisitor): @@ -102,6 +105,14 @@ def visit_block(self, b: Block) -> None: return super().visit_block(b) + def visit_match_stmt(self, s: MatchStmt) -> None: + infer_reachability_of_match_statement(s, self.options) + for guard in s.guards: + if guard is not None: + guard.accept(self) + for body in s.bodies: + body.accept(self) + # The remaining methods are an optimization: don't visit nested expressions # of common statements, since they can have no effect. diff --git a/mypy/semanal_shared.py b/mypy/semanal_shared.py index 3638d0878d8f..85a6779ac9f3 100644 --- a/mypy/semanal_shared.py +++ b/mypy/semanal_shared.py @@ -7,10 +7,9 @@ from mypy_extensions import trait from mypy.nodes import ( - Context, SymbolTableNode, MypyFile, ImportedName, FuncDef, Node, TypeInfo, Expression, GDEF, + Context, SymbolTableNode, FuncDef, Node, TypeInfo, Expression, SymbolNode, SymbolTable ) -from mypy.util import correct_relative_import from mypy.types import ( Type, FunctionLike, Instance, TupleType, TPDICT_FB_NAMES, ProperType, get_proper_type ) @@ -179,27 +178,6 @@ def is_func_scope(self) -> bool: raise NotImplementedError -def create_indirect_imported_name(file_node: MypyFile, - module: str, - relative: int, - imported_name: str) -> Optional[SymbolTableNode]: - """Create symbol table entry for a name imported from another module. - - These entries act as indirect references. - """ - target_module, ok = correct_relative_import( - file_node.fullname, - relative, - module, - file_node.is_package_init_file()) - if not ok: - return None - target_name = '%s.%s' % (target_module, imported_name) - link = ImportedName(target_name) - # Use GDEF since this refers to a module-level definition. - return SymbolTableNode(GDEF, link) - - def set_callable_name(sig: Type, fdef: FuncDef) -> ProperType: sig = get_proper_type(sig) if isinstance(sig, FunctionLike): diff --git a/mypy/server/update.py b/mypy/server/update.py index e82064c63a11..2f57001766d5 100644 --- a/mypy/server/update.py +++ b/mypy/server/update.py @@ -485,13 +485,6 @@ def ensure_trees_loaded(manager: BuildManager, graph: Dict[str, State], process_fresh_modules(graph, to_process, manager) -def fix_fg_dependencies(manager: BuildManager, deps: Dict[str, Set[str]]) -> None: - """Populate the dependencies with stuff that build may have missed""" - # This means the root module and typestate - merge_dependencies(manager.load_fine_grained_deps(FAKE_ROOT_MODULE), deps) - # TypeState.add_all_protocol_deps(deps) - - # The result of update_module_isolated when no blockers, with these items: # # - Id of the changed module (can be different from the module argument) diff --git a/mypy/strconv.py b/mypy/strconv.py index c63063af0776..22534a44971d 100644 --- a/mypy/strconv.py +++ b/mypy/strconv.py @@ -4,11 +4,15 @@ import os from typing import Any, List, Tuple, Optional, Union, Sequence +from typing_extensions import TYPE_CHECKING from mypy.util import short_type, IdMapper import mypy.nodes from mypy.visitor import NodeVisitor +if TYPE_CHECKING: + import mypy.patterns + class StrConv(NodeVisitor[str]): """Visitor for converting a node to a human-readable string. @@ -311,6 +315,15 @@ def visit_print_stmt(self, o: 'mypy.nodes.PrintStmt') -> str: def visit_exec_stmt(self, o: 'mypy.nodes.ExecStmt') -> str: return self.dump([o.expr, o.globals, o.locals], o) + def visit_match_stmt(self, o: 'mypy.nodes.MatchStmt') -> str: + a: List[Any] = [o.subject] + for i in range(len(o.patterns)): + a.append(('Pattern', [o.patterns[i]])) + if o.guards[i] is not None: + a.append(('Guard', [o.guards[i]])) + a.append(('Body', o.bodies[i].body)) + return self.dump(a, o) + # Expressions # Simple expressions @@ -537,6 +550,42 @@ def visit_backquote_expr(self, o: 'mypy.nodes.BackquoteExpr') -> str: def visit_temp_node(self, o: 'mypy.nodes.TempNode') -> str: return self.dump([o.type], o) + def visit_as_pattern(self, o: 'mypy.patterns.AsPattern') -> str: + return self.dump([o.pattern, o.name], o) + + def visit_or_pattern(self, o: 'mypy.patterns.OrPattern') -> str: + return self.dump(o.patterns, o) + + def visit_value_pattern(self, o: 'mypy.patterns.ValuePattern') -> str: + return self.dump([o.expr], o) + + def visit_singleton_pattern(self, o: 'mypy.patterns.SingletonPattern') -> str: + return self.dump([o.value], o) + + def visit_sequence_pattern(self, o: 'mypy.patterns.SequencePattern') -> str: + return self.dump(o.patterns, o) + + def visit_starred_pattern(self, o: 'mypy.patterns.StarredPattern') -> str: + return self.dump([o.capture], o) + + def visit_mapping_pattern(self, o: 'mypy.patterns.MappingPattern') -> str: + a: List[Any] = [] + for i in range(len(o.keys)): + a.append(('Key', [o.keys[i]])) + a.append(('Value', [o.values[i]])) + if o.rest is not None: + a.append(('Rest', [o.rest])) + return self.dump(a, o) + + def visit_class_pattern(self, o: 'mypy.patterns.ClassPattern') -> str: + a: List[Any] = [o.class_ref] + if len(o.positionals) > 0: + a.append(('Positionals', o.positionals)) + for i in range(len(o.keyword_keys)): + a.append(('Keyword', [o.keyword_keys[i], o.keyword_values[i]])) + + return self.dump(a, o) + def dump_tagged(nodes: Sequence[object], tag: Optional[str], str_conv: 'StrConv') -> str: """Convert an array into a pretty-printed multiline string representation. diff --git a/mypy/stubgen.py b/mypy/stubgen.py index b0a2c4e64587..dafb446a835a 100755 --- a/mypy/stubgen.py +++ b/mypy/stubgen.py @@ -649,9 +649,11 @@ def visit_func_def(self, o: FuncDef, is_abstract: bool = False, # type "UnboundType" and will not match. if not isinstance(get_proper_type(annotated_type), AnyType): annotation = ": {}".format(self.print_annotation(annotated_type)) + + if kind.is_named() and not any(arg.startswith('*') for arg in args): + args.append('*') + if arg_.initializer: - if kind.is_named() and not any(arg.startswith('*') for arg in args): - args.append('*') if not annotation: typename = self.get_str_type_of_node(arg_.initializer, True, False) if typename == '': diff --git a/mypy/stubinfo.py b/mypy/stubinfo.py index 9945a12c121f..d1bcb4a6c157 100644 --- a/mypy/stubinfo.py +++ b/mypy/stubinfo.py @@ -59,7 +59,6 @@ def is_legacy_bundled_package(prefix: str, py_version: int) -> bool: 'maxminddb': StubInfo('types-maxminddb'), 'mock': StubInfo('types-mock'), 'OpenSSL': StubInfo('types-pyOpenSSL'), - 'orjson': StubInfo('types-orjson', py_version=3), 'paramiko': StubInfo('types-paramiko'), 'pathlib2': StubInfo('types-pathlib2', py_version=2), 'pkg_resources': StubInfo('types-setuptools', py_version=3), diff --git a/mypy/stubtest.py b/mypy/stubtest.py index 7228afaed446..b568017cfa5f 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -25,7 +25,7 @@ from mypy import nodes from mypy.config_parser import parse_config_file from mypy.options import Options -from mypy.util import FancyFormatter +from mypy.util import FancyFormatter, bytes_to_human_readable_repr, is_dunder class Missing: @@ -144,6 +144,11 @@ def get_description(self, concise: bool = False) -> str: return "".join(output) +# ==================== +# Core logic +# ==================== + + def test_module(module_name: str) -> Iterator[Error]: """Tests a given module's stub against introspecting it at runtime. @@ -204,12 +209,15 @@ def verify_mypyfile( to_check = set( m for m, o in stub.names.items() - if not o.module_hidden and (not m.startswith("_") or hasattr(runtime, m)) + if not o.module_hidden and (not is_probably_private(m) or hasattr(runtime, m)) ) def _belongs_to_runtime(r: types.ModuleType, attr: str) -> bool: obj = getattr(r, attr) - obj_mod = getattr(obj, "__module__", None) + try: + obj_mod = getattr(obj, "__module__", None) + except Exception: + return False if obj_mod is not None: return obj_mod == r.__name__ return not isinstance(obj, types.ModuleType) @@ -220,7 +228,7 @@ def _belongs_to_runtime(r: types.ModuleType, attr: str) -> bool: else [ m for m in dir(runtime) - if not m.startswith("_") + if not is_probably_private(m) # 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) @@ -228,7 +236,7 @@ def _belongs_to_runtime(r: types.ModuleType, attr: str) -> bool: ) # 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__"}) + to_check.difference_update(IGNORED_MODULE_DUNDERS) for entry in sorted(to_check): stub_entry = stub.names[entry].node if entry in stub.names else MISSING @@ -236,11 +244,19 @@ def _belongs_to_runtime(r: types.ModuleType, attr: str) -> bool: # Don't recursively check exported modules, since that leads to infinite recursion continue assert stub_entry is not None - yield from verify( - stub_entry, - getattr(runtime, entry, MISSING), - object_path + [entry], - ) + try: + runtime_entry = getattr(runtime, entry, MISSING) + except Exception: + # Catch all exceptions in case the runtime raises an unexpected exception + # from __getattr__ or similar. + continue + yield from verify(stub_entry, runtime_entry, object_path + [entry]) + + +if sys.version_info >= (3, 7): + _WrapperDescriptorType = types.WrapperDescriptorType +else: + _WrapperDescriptorType = type(object.__init__) @verify.register(nodes.TypeInfo) @@ -254,13 +270,32 @@ def verify_typeinfo( yield Error(object_path, "is not a type", stub, runtime, stub_desc=repr(stub)) return - # Check everything already defined in the stub + try: + class SubClass(runtime): # type: ignore + pass + except TypeError: + # Enum classes are implicitly @final + if not stub.is_final and not issubclass(runtime, enum.Enum): + yield Error( + object_path, + "cannot be subclassed at runtime, but isn't marked with @final in the stub", + stub, + runtime, + stub_desc=repr(stub), + ) + except Exception: + # The class probably wants its subclasses to do something special. + # Examples: ctypes.Array, ctypes._SimpleCData + pass + + # Check everything already defined on the stub class itself (i.e. not inherited) to_check = set(stub.names) - # There's a reasonable case to be made that we should always check all dunders, but it's - # currently quite noisy. We could turn this into a denylist instead of an allowlist. + # Check all public things on the runtime class to_check.update( # cast to workaround mypyc complaints - m for m in cast(Any, vars)(runtime) if not m.startswith("_") or m in SPECIAL_DUNDERS + m + for m in cast(Any, vars)(runtime) + if not is_probably_private(m) and m not in IGNORABLE_CLASS_DUNDERS ) for entry in sorted(to_check): @@ -269,11 +304,22 @@ def verify_typeinfo( mangled_entry = "_{}{}".format(stub.name, entry) stub_to_verify = next((t.names[entry].node for t in stub.mro if entry in t.names), MISSING) assert stub_to_verify is not None - yield from verify( - stub_to_verify, - getattr(runtime, mangled_entry, MISSING), - object_path + [entry], - ) + try: + runtime_attr = getattr(runtime, mangled_entry, MISSING) + except Exception: + # Catch all exceptions in case the runtime raises an unexpected exception + # from __getattr__ or similar. + continue + # Do not error for an object missing from the stub + # If the runtime object is a types.WrapperDescriptorType object + # and has a non-special dunder name. + # The vast majority of these are false positives. + if not ( + isinstance(stub_to_verify, Missing) + and isinstance(runtime_attr, _WrapperDescriptorType) + and is_dunder(mangled_entry, exclude_special=True) + ): + yield from verify(stub_to_verify, runtime_attr, object_path + [entry]) def _verify_static_class_methods( @@ -584,6 +630,7 @@ def _verify_signature( if ( runtime_arg.kind != inspect.Parameter.POSITIONAL_ONLY and stub_arg.variable.name.startswith("__") + and not is_dunder(function_name, exclude_special=True) # noisy for dunder methods ): yield ( 'stub argument "{}" should be positional or keyword ' @@ -673,19 +720,39 @@ def verify_funcitem( yield Error(object_path, "is inconsistent, " + message, stub, runtime) signature = safe_inspect_signature(runtime) + runtime_is_coroutine = inspect.iscoroutinefunction(runtime) + + if signature: + stub_sig = Signature.from_funcitem(stub) + runtime_sig = Signature.from_inspect_signature(signature) + runtime_sig_desc = f'{"async " if runtime_is_coroutine else ""}def {signature}' + stub_desc = f'def {stub_sig!r}' + else: + runtime_sig_desc, stub_desc = None, None + + # Don't raise an error if the stub is a coroutine, but the runtime isn't. + # That results in false positives. + # See https://github.com/python/typeshed/issues/7344 + if runtime_is_coroutine and not stub.is_coroutine: + yield Error( + object_path, + 'is an "async def" function at runtime, but not in the stub', + stub, + runtime, + stub_desc=stub_desc, + runtime_desc=runtime_sig_desc + ) + if not signature: return - stub_sig = Signature.from_funcitem(stub) - runtime_sig = Signature.from_inspect_signature(signature) - for message in _verify_signature(stub_sig, runtime_sig, function_name=stub.name): yield Error( object_path, "is inconsistent, " + message, stub, runtime, - runtime_desc="def " + str(signature), + runtime_desc=runtime_sig_desc, ) @@ -896,18 +963,76 @@ def verify_typealias( ) -SPECIAL_DUNDERS = ("__init__", "__new__", "__call__", "__init_subclass__", "__class_getitem__") - - -def is_dunder(name: str, exclude_special: bool = False) -> bool: - """Returns whether name is a dunder name. +# ==================== +# Helpers +# ==================== + + +IGNORED_MODULE_DUNDERS = frozenset( + { + "__file__", + "__doc__", + "__name__", + "__builtins__", + "__package__", + "__cached__", + "__loader__", + "__spec__", + "__path__", # mypy adds __path__ to packages, but C packages don't have it + "__getattr__", # resulting behaviour might be typed explicitly + # TODO: remove the following from this list + "__author__", + "__version__", + "__copyright__", + } +) + +IGNORABLE_CLASS_DUNDERS = frozenset( + { + # Special attributes + "__dict__", + "__text_signature__", + "__weakref__", + "__del__", # Only ever called when an object is being deleted, who cares? + "__hash__", + "__getattr__", # resulting behaviour might be typed explicitly + "__setattr__", # defining this on a class can cause worse type checking + # isinstance/issubclass hooks that type-checkers don't usually care about + "__instancecheck__", + "__subclasshook__", + "__subclasscheck__", + # Pickle methods + "__setstate__", + "__getstate__", + "__getnewargs__", + "__getinitargs__", + "__reduce_ex__", + "__reduce__", + # ctypes weirdness + "__ctype_be__", + "__ctype_le__", + "__ctypes_from_outparam__", + # mypy limitations + "__abstractmethods__", # Classes with metaclass=ABCMeta inherit this attribute + "__new_member__", # If an enum defines __new__, the method is renamed as __new_member__ + "__dataclass_fields__", # Generated by dataclasses + "__dataclass_params__", # Generated by dataclasses + "__doc__", # mypy's semanal for namedtuples assumes this is str, not Optional[str] + # typing implementation details, consider removing some of these: + "__parameters__", + "__origin__", + "__args__", + "__orig_bases__", + "__final__", + # Consider removing these: + "__match_args__", + "__slots__", + } +) - :param exclude_special: Whether to return False for a couple special dunder methods. - """ - if exclude_special and name in SPECIAL_DUNDERS: - return False - return name.startswith("__") and name.endswith("__") +def is_probably_private(name: str) -> bool: + return name.startswith("_") and not is_dunder(name) def is_probably_a_function(runtime: Any) -> bool: @@ -942,6 +1067,15 @@ def is_subtype_helper(left: mypy.types.Type, right: mypy.types.Type) -> bool: ): # Pretend Literal[0, 1] is a subtype of bool to avoid unhelpful errors. return True + + if ( + isinstance(right, mypy.types.TypedDictType) + and isinstance(left, mypy.types.Instance) + and left.type.fullname == "builtins.dict" + ): + # Special case checks against TypedDicts + return True + with mypy.state.strict_optional_set(True): return mypy.subtypes.is_subtype(left, right) @@ -1029,17 +1163,24 @@ def anytype() -> mypy.types.AnyType: return mypy.types.TupleType(items, fallback) fallback = mypy.types.Instance(type_info, [anytype() for _ in type_info.type_vars]) - try: - # Literals are supposed to be only bool, int, str, bytes or enums, but this seems to work - # well (when not using mypyc, for which bytes and enums are also problematic). - return mypy.types.LiteralType( - value=runtime, - fallback=fallback, - ) - except TypeError: - # Ask for forgiveness if we're using mypyc. + + value: Union[bool, int, str] + if isinstance(runtime, bytes): + value = bytes_to_human_readable_repr(runtime) + elif isinstance(runtime, enum.Enum): + value = runtime.name + elif isinstance(runtime, (bool, int, str)): + value = runtime + else: return fallback + return mypy.types.LiteralType(value=value, fallback=fallback) + + +# ==================== +# Build and entrypoint +# ==================== + _all_stubs: Dict[str, nodes.MypyFile] = {} @@ -1107,19 +1248,27 @@ def get_stub(module: str) -> Optional[nodes.MypyFile]: return _all_stubs.get(module) -def get_typeshed_stdlib_modules(custom_typeshed_dir: Optional[str]) -> List[str]: +def get_typeshed_stdlib_modules( + custom_typeshed_dir: Optional[str], + version_info: Optional[Tuple[int, int]] = None +) -> List[str]: """Returns a list of stdlib modules in typeshed (for current Python version).""" stdlib_py_versions = mypy.modulefinder.load_stdlib_py_versions(custom_typeshed_dir) - packages = set() + if version_info is None: + version_info = sys.version_info[0:2] # Typeshed's minimum supported Python 3 is Python 3.6 if sys.version_info < (3, 6): version_info = (3, 6) - else: - version_info = sys.version_info[0:2] - for module, versions in stdlib_py_versions.items(): - minver, maxver = versions - if version_info >= minver and (maxver is None or version_info <= maxver): - packages.add(module) + + def exists_in_version(module: str) -> bool: + assert version_info is not None + parts = module.split(".") + for i in range(len(parts), 0, -1): + current_module = ".".join(parts[:i]) + if current_module in stdlib_py_versions: + minver, maxver = stdlib_py_versions[current_module] + return version_info >= minver and (maxver is None or version_info <= maxver) + return False if custom_typeshed_dir: typeshed_dir = Path(custom_typeshed_dir) @@ -1132,7 +1281,7 @@ def get_typeshed_stdlib_modules(custom_typeshed_dir: Optional[str]) -> List[str] if path.stem == "__init__": path = path.parent module = ".".join(path.relative_to(stdlib_dir).parts[:-1] + (path.stem,)) - if module.split(".")[0] in packages: + if exists_in_version(module): modules.append(module) return sorted(modules) @@ -1169,7 +1318,8 @@ def test_stubs(args: argparse.Namespace, use_builtins_fixtures: bool = False) -> if args.check_typeshed: assert not args.modules, "Cannot pass both --check-typeshed and a list of modules" modules = get_typeshed_stdlib_modules(args.custom_typeshed_dir) - annoying_modules = {"antigravity", "this"} + # typeshed added a stub for __main__, but that causes stubtest to check itself + annoying_modules = {"antigravity", "this", "__main__"} modules = [m for m in modules if m not in annoying_modules] assert modules, "No modules to check" diff --git a/mypy/subtypes.py b/mypy/subtypes.py index f90009445b09..a261e3712328 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -7,7 +7,8 @@ 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, ParamSpecType + FunctionLike, TypeOfAny, LiteralType, get_proper_type, TypeAliasType, ParamSpecType, + TUPLE_LIKE_INSTANCE_NAMES, ) import mypy.applytype import mypy.constraints @@ -154,10 +155,6 @@ def _is_subtype(left: Type, right: Type, ignore_promotions=ignore_promotions)) -def is_subtype_ignoring_tvars(left: Type, right: Type) -> bool: - return is_subtype(left, right, ignore_type_params=True) - - def is_equivalent(a: Type, b: Type, *, ignore_type_params: bool = False, @@ -366,11 +363,7 @@ def visit_tuple_type(self, left: TupleType) -> bool: if isinstance(right, Instance): if is_named_instance(right, 'typing.Sized'): return True - elif (is_named_instance(right, 'builtins.tuple') or - is_named_instance(right, 'typing.Iterable') or - is_named_instance(right, 'typing.Container') or - is_named_instance(right, 'typing.Sequence') or - is_named_instance(right, 'typing.Reversible')): + elif is_named_instance(right, TUPLE_LIKE_INSTANCE_NAMES): if right.args: iter_type = right.args[0] else: @@ -770,7 +763,7 @@ def non_method_protocol_members(tp: TypeInfo) -> List[str]: for member in tp.protocol_members: typ = get_proper_type(find_member(member, instance, instance)) - if not isinstance(typ, CallableType): + if not isinstance(typ, (Overloaded, CallableType)): result.append(member) return result @@ -1171,6 +1164,7 @@ def restrict_subtype_away(t: Type, s: Type, *, ignore_promotions: bool = False) def covers_at_runtime(item: Type, supertype: Type, ignore_promotions: bool) -> bool: """Will isinstance(item, supertype) always return True at runtime?""" item = get_proper_type(item) + supertype = get_proper_type(supertype) # Since runtime type checks will ignore type arguments, erase the types. supertype = erase_type(supertype) @@ -1380,11 +1374,7 @@ def visit_callable_type(self, left: CallableType) -> bool: def visit_tuple_type(self, left: TupleType) -> bool: right = self.right if isinstance(right, Instance): - if (is_named_instance(right, 'builtins.tuple') or - is_named_instance(right, 'typing.Iterable') or - is_named_instance(right, 'typing.Container') or - is_named_instance(right, 'typing.Sequence') or - is_named_instance(right, 'typing.Reversible')): + if is_named_instance(right, TUPLE_LIKE_INSTANCE_NAMES): if not right.args: return False iter_type = get_proper_type(right.args[0]) @@ -1446,7 +1436,7 @@ def visit_type_type(self, left: TypeType) -> bool: if right.type.fullname == 'builtins.type': # TODO: Strictly speaking, the type builtins.type is considered equivalent to # Type[Any]. However, this would break the is_proper_subtype check in - # conditional_type_map for cases like isinstance(x, type) when the type + # conditional_types for cases like isinstance(x, type) when the type # of x is Type[int]. It's unclear what's the right way to address this. return True if right.type.fullname == 'builtins.object': diff --git a/mypy/suggestions.py b/mypy/suggestions.py index 87b54814c637..af42cca8a216 100644 --- a/mypy/suggestions.py +++ b/mypy/suggestions.py @@ -344,9 +344,11 @@ def get_args(self, is_method: bool, types.append(arg_types) return types - def get_default_arg_types(self, state: State, fdef: FuncDef) -> List[Optional[Type]]: - return [self.manager.all_types[arg.initializer] if arg.initializer else None - for arg in fdef.arguments] + def get_default_arg_types(self, fdef: FuncDef) -> List[Optional[Type]]: + return [ + self.manager.all_types[arg.initializer] if arg.initializer else None + for arg in fdef.arguments + ] def add_adjustments(self, typs: List[Type]) -> List[Type]: if not self.try_text or self.manager.options.python_version[0] != 2: @@ -441,7 +443,7 @@ def get_suggestion(self, mod: str, node: FuncDef) -> PyAnnotateSignature: guesses = self.get_guesses( is_method, self.get_starting_type(node), - self.get_default_arg_types(graph[mod], node), + self.get_default_arg_types(node), callsites, uses, ) @@ -632,11 +634,8 @@ def try_type(self, func: FuncDef, typ: ProperType) -> List[str]: finally: func.unanalyzed_type = old - def reload(self, state: State, check_errors: bool = False) -> List[str]: - """Recheck the module given by state. - - If check_errors is true, raise an exception if there are errors. - """ + def reload(self, state: State) -> List[str]: + """Recheck the module given by state.""" assert state.path is not None self.fgmanager.flush_cache() return self.fgmanager.update([(state.id, state.path)], []) diff --git a/mypy/test/data.py b/mypy/test/data.py index 17cda87c1bd3..e886b11ffa8e 100644 --- a/mypy/test/data.py +++ b/mypy/test/data.py @@ -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: diff --git a/mypy/test/helpers.py b/mypy/test/helpers.py index fbd44bca868b..f9f117634c21 100644 --- a/mypy/test/helpers.py +++ b/mypy/test/helpers.py @@ -287,6 +287,8 @@ def num_skipped_suffix_lines(a1: List[str], a2: List[str]) -> int: def testfile_pyversion(path: str) -> Tuple[int, int]: if path.endswith('python2.test'): return defaults.PYTHON2_VERSION + elif path.endswith('python310.test'): + return 3, 10 else: return defaults.PYTHON3_VERSION diff --git a/mypy/test/testfinegrained.py b/mypy/test/testfinegrained.py index ed99b4aeae13..79507948af14 100644 --- a/mypy/test/testfinegrained.py +++ b/mypy/test/testfinegrained.py @@ -49,6 +49,7 @@ class FineGrainedSuite(DataSuite): 'fine-grained-modules.test', 'fine-grained-follow-imports.test', 'fine-grained-suggest.test', + 'fine-grained-attr.test', ] # Whether to use the fine-grained cache in the testing. This is overridden diff --git a/mypy/test/testparse.py b/mypy/test/testparse.py index e9ff6839bc2c..1587147c0777 100644 --- a/mypy/test/testparse.py +++ b/mypy/test/testparse.py @@ -18,6 +18,9 @@ class ParserSuite(DataSuite): files = ['parse.test', 'parse-python2.test'] + if sys.version_info >= (3, 10): + files.append('parse-python310.test') + def run_case(self, testcase: DataDrivenTestCase) -> None: test_parser(testcase) @@ -31,6 +34,8 @@ def test_parser(testcase: DataDrivenTestCase) -> None: if testcase.file.endswith('python2.test'): options.python_version = defaults.PYTHON2_VERSION + elif testcase.file.endswith('python310.test'): + options.python_version = (3, 10) else: options.python_version = defaults.PYTHON3_VERSION diff --git a/mypy/test/testreports.py b/mypy/test/testreports.py index 84ac3e005bec..75f24d514431 100644 --- a/mypy/test/testreports.py +++ b/mypy/test/testreports.py @@ -4,8 +4,6 @@ from mypy.test.helpers import Suite, assert_equal from mypy.report import CoberturaPackage, get_line_rate -import lxml.etree as etree # type: ignore - class CoberturaReportSuite(Suite): def test_get_line_rate(self) -> None: @@ -13,6 +11,8 @@ def test_get_line_rate(self) -> None: assert_equal('0.3333', get_line_rate(1, 3)) def test_as_xml(self) -> None: + import lxml.etree as etree # type: ignore + cobertura_package = CoberturaPackage('foobar') cobertura_package.covered_lines = 21 cobertura_package.total_lines = 42 diff --git a/mypy/test/testsamples.py b/mypy/test/testsamples.py deleted file mode 100644 index 27b26af16f36..000000000000 --- a/mypy/test/testsamples.py +++ /dev/null @@ -1,35 +0,0 @@ -import os.path -from typing import List, Set - -from mypy.test.helpers import Suite, run_mypy - - -class SamplesSuite(Suite): - """Test that we can type check some sample code.""" - - def test_samples(self) -> None: - for f in find_files(os.path.join('test-data', 'samples'), suffix='.py'): - mypy_args = ['--no-strict-optional'] - if f == os.path.join('test-data', 'samples', 'crawl2.py'): - # This test requires 3.5 for async functions - mypy_args.append('--python-version=3.5') - run_mypy(mypy_args + [f]) - - def test_stdlibsamples(self) -> None: - seen: Set[str] = set() - stdlibsamples_dir = os.path.join('test-data', 'stdlib-samples', '3.2', 'test') - modules: List[str] = [] - for f in find_files(stdlibsamples_dir, prefix='test_', suffix='.py'): - if f not in seen: - seen.add(f) - modules.append(f) - if modules: - # TODO: Remove need for --no-strict-optional - run_mypy(['--no-strict-optional', '--platform=linux'] + modules) - - -def find_files(base: str, prefix: str = '', suffix: str = '') -> List[str]: - return [os.path.join(root, f) - for root, dirs, files in os.walk(base) - for f in files - if f.startswith(prefix) and f.endswith(suffix)] diff --git a/mypy/test/testsemanal.py b/mypy/test/testsemanal.py index a71bac53619d..441f9ab32dbb 100644 --- a/mypy/test/testsemanal.py +++ b/mypy/test/testsemanal.py @@ -1,6 +1,7 @@ """Semantic analyzer test cases""" import os.path +import sys from typing import Dict, List @@ -38,6 +39,10 @@ ] +if sys.version_info >= (3, 10): + semanal_files.append('semanal-python310.test') + + def get_semanal_options(program_text: str, testcase: DataDrivenTestCase) -> Options: options = parse_options(program_text, testcase, 1) options.use_builtins_fixtures = True @@ -104,6 +109,8 @@ def test_semanal(testcase: DataDrivenTestCase) -> None: class SemAnalErrorSuite(DataSuite): files = ['semanal-errors.test'] + if sys.version_info >= (3, 10): + semanal_files.append('semanal-errors-python310.test') def run_case(self, testcase: DataDrivenTestCase) -> None: test_semanal_error(testcase) diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index e6eb8465c665..759942c57ce7 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -7,7 +7,6 @@ import tempfile import textwrap import unittest -from pathlib import Path from typing import Any, Callable, Iterator, List, Optional import mypy.stubtest @@ -16,18 +15,53 @@ @contextlib.contextmanager -def use_tmp_dir() -> Iterator[None]: +def use_tmp_dir(mod_name: str) -> Iterator[str]: current = os.getcwd() + current_syspath = sys.path[:] with tempfile.TemporaryDirectory() as tmp: try: os.chdir(tmp) - yield + if sys.path[0] != tmp: + sys.path.insert(0, tmp) + yield tmp finally: + sys.path = current_syspath[:] + if mod_name in sys.modules: + del sys.modules[mod_name] + os.chdir(current) TEST_MODULE_NAME = "test_module" + +stubtest_typing_stub = """ +Any = object() + +class _SpecialForm: + def __getitem__(self, typeargs: Any) -> object: ... + +Callable: _SpecialForm = ... +Generic: _SpecialForm = ... + +class TypeVar: + def __init__(self, name, covariant: bool = ..., contravariant: bool = ...) -> None: ... + +_T = TypeVar("_T") +_T_co = TypeVar("_T_co", covariant=True) +_K = TypeVar("_K") +_V = TypeVar("_V") +_S = TypeVar("_S", contravariant=True) +_R = TypeVar("_R", covariant=True) + +class Coroutine(Generic[_T_co, _S, _R]): ... +class Iterable(Generic[_T_co]): ... +class Mapping(Generic[_K, _V]): ... +class Sequence(Iterable[_T_co]): ... +class Tuple(Sequence[_T_co]): ... +def overload(func: _T) -> _T: ... +""" + stubtest_builtins_stub = """ from typing import Generic, Mapping, Sequence, TypeVar, overload @@ -37,6 +71,7 @@ def use_tmp_dir() -> Iterator[None]: VT = TypeVar('VT') class object: + __module__: str def __init__(self) -> None: pass class type: ... @@ -63,9 +98,11 @@ def staticmethod(f: T) -> T: ... def run_stubtest( stub: str, runtime: str, options: List[str], config_file: Optional[str] = None, ) -> str: - with use_tmp_dir(): + with use_tmp_dir(TEST_MODULE_NAME) as tmp_dir: with open("builtins.pyi", "w") as f: f.write(stubtest_builtins_stub) + with open("typing.pyi", "w") as f: + f.write(stubtest_typing_stub) with open("{}.pyi".format(TEST_MODULE_NAME), "w") as f: f.write(stub) with open("{}.py".format(TEST_MODULE_NAME), "w") as f: @@ -74,21 +111,14 @@ def run_stubtest( with open("{}_config.ini".format(TEST_MODULE_NAME), "w") as f: f.write(config_file) options = options + ["--mypy-config-file", "{}_config.ini".format(TEST_MODULE_NAME)] - if sys.path[0] != ".": - sys.path.insert(0, ".") - if TEST_MODULE_NAME in sys.modules: - del sys.modules[TEST_MODULE_NAME] - output = io.StringIO() with contextlib.redirect_stdout(output): test_stubs( parse_options([TEST_MODULE_NAME] + options), use_builtins_fixtures=True ) - - module_path = Path(os.getcwd()) / TEST_MODULE_NAME # remove cwd as it's not available from outside - return output.getvalue().replace(str(module_path), TEST_MODULE_NAME) + return output.getvalue().replace(tmp_dir + os.sep, "") class Case: @@ -112,7 +142,11 @@ def test(*args: Any, **kwargs: Any) -> None: for c in cases: if c.error is None: continue - expected_error = "{}.{}".format(TEST_MODULE_NAME, c.error) + expected_error = c.error + if expected_error == "": + expected_error = TEST_MODULE_NAME + elif not expected_error.startswith(f"{TEST_MODULE_NAME}."): + expected_error = f"{TEST_MODULE_NAME}.{expected_error}" assert expected_error not in expected_errors, ( "collect_cases merges cases into a single stubtest invocation; we already " "expect an error for {}".format(expected_error) @@ -172,6 +206,30 @@ class X: error="X.mistyped_var", ) + @collect_cases + def test_coroutines(self) -> Iterator[Case]: + yield Case( + stub="def bar() -> int: ...", + runtime="async def bar(): return 5", + error="bar", + ) + # Don't error for this one -- we get false positives otherwise + yield Case( + stub="async def foo() -> int: ...", + runtime="def foo(): return 5", + error=None, + ) + yield Case( + stub="def baz() -> int: ...", + runtime="def baz(): return 5", + error=None, + ) + yield Case( + stub="async def bingo() -> int: ...", + runtime="async def bingo(): return 5", + error=None, + ) + @collect_cases def test_arg_name(self) -> Iterator[Case]: yield Case( @@ -657,6 +715,16 @@ def h(x: str): ... yield Case( stub="from mystery import A, B as B, C as D # type: ignore", runtime="", error="B" ) + yield Case( + stub="class Y: ...", + runtime="__all__ += ['Y']\nclass Y:\n def __or__(self, other): return self|other", + error="Y.__or__" + ) + yield Case( + stub="class Z: ...", + runtime="__all__ += ['Z']\nclass Z:\n def __reduce__(self): return (Z,)", + error=None + ) @collect_cases def test_missing_no_runtime_all(self) -> Iterator[Case]: @@ -666,7 +734,9 @@ def test_missing_no_runtime_all(self) -> Iterator[Case]: @collect_cases def test_non_public_1(self) -> Iterator[Case]: - yield Case(stub="__all__: list[str]", runtime="", error=None) # dummy case + yield Case( + stub="__all__: list[str]", runtime="", error="test_module.__all__" + ) # dummy case yield Case(stub="_f: int", runtime="def _f(): ...", error="_f") @collect_cases @@ -678,7 +748,7 @@ def test_non_public_2(self) -> Iterator[Case]: yield Case(stub="g: int", runtime="def g(): ...", error="g") @collect_cases - def test_special_dunders(self) -> Iterator[Case]: + def test_dunders(self) -> Iterator[Case]: yield Case( stub="class A:\n def __init__(self, a: int, b: int) -> None: ...", runtime="class A:\n def __init__(self, a, bx): pass", @@ -691,8 +761,13 @@ def test_special_dunders(self) -> Iterator[Case]: ) if sys.version_info >= (3, 6): yield Case( - stub="class C:\n def __init_subclass__(cls, e: int, **kwargs: int) -> None: ...", - runtime="class C:\n def __init_subclass__(cls, e, **kwargs): pass", + stub=( + "class C:\n" + " def __init_subclass__(\n" + " cls, e: int = ..., **kwargs: int\n" + " ) -> None: ...\n" + ), + runtime="class C:\n def __init_subclass__(cls, e=1, **kwargs): pass", error=None, ) if sys.version_info >= (3, 9): @@ -702,6 +777,19 @@ def test_special_dunders(self) -> Iterator[Case]: error=None, ) + @collect_cases + def test_not_subclassable(self) -> Iterator[Case]: + yield Case( + stub="class CanBeSubclassed: ...", + runtime="class CanBeSubclassed: ...", + error=None, + ) + yield Case( + stub="class CannotBeSubclassed:\n def __init_subclass__(cls) -> None: ...", + runtime="class CannotBeSubclassed:\n def __init_subclass__(cls): raise TypeError", + error="CannotBeSubclassed", + ) + @collect_cases def test_name_mangling(self) -> Iterator[Case]: yield Case( @@ -750,6 +838,119 @@ def __init__(self, x): pass error="X.__init__" ) + @collect_cases + def test_good_literal(self) -> Iterator[Case]: + yield Case( + stub=r""" + from typing_extensions import Literal + + import enum + class Color(enum.Enum): + RED: int + + NUM: Literal[1] + CHAR: Literal['a'] + FLAG: Literal[True] + NON: Literal[None] + BYT1: Literal[b'abc'] + BYT2: Literal[b'\x90'] + ENUM: Literal[Color.RED] + """, + runtime=r""" + import enum + class Color(enum.Enum): + RED = 3 + + NUM = 1 + CHAR = 'a' + NON = None + FLAG = True + BYT1 = b"abc" + BYT2 = b'\x90' + ENUM = Color.RED + """, + error=None, + ) + + @collect_cases + def test_bad_literal(self) -> Iterator[Case]: + yield Case("from typing_extensions import Literal", "", None) # dummy case + yield Case( + stub="INT_FLOAT_MISMATCH: Literal[1]", + runtime="INT_FLOAT_MISMATCH = 1.0", + error="INT_FLOAT_MISMATCH", + ) + yield Case( + stub="WRONG_INT: Literal[1]", + runtime="WRONG_INT = 2", + error="WRONG_INT", + ) + yield Case( + stub="WRONG_STR: Literal['a']", + runtime="WRONG_STR = 'b'", + error="WRONG_STR", + ) + yield Case( + stub="BYTES_STR_MISMATCH: Literal[b'value']", + runtime="BYTES_STR_MISMATCH = 'value'", + error="BYTES_STR_MISMATCH", + ) + yield Case( + stub="STR_BYTES_MISMATCH: Literal['value']", + runtime="STR_BYTES_MISMATCH = b'value'", + error="STR_BYTES_MISMATCH", + ) + yield Case( + stub="WRONG_BYTES: Literal[b'abc']", + runtime="WRONG_BYTES = b'xyz'", + error="WRONG_BYTES", + ) + yield Case( + stub="WRONG_BOOL_1: Literal[True]", + runtime="WRONG_BOOL_1 = False", + error='WRONG_BOOL_1', + ) + yield Case( + stub="WRONG_BOOL_2: Literal[False]", + runtime="WRONG_BOOL_2 = True", + error='WRONG_BOOL_2', + ) + + @collect_cases + def test_special_subtype(self) -> Iterator[Case]: + yield Case( + stub=""" + b1: bool + b2: bool + b3: bool + """, + runtime=""" + b1 = 0 + b2 = 1 + b3 = 2 + """, + error="b3", + ) + yield Case( + stub=""" + from typing_extensions import TypedDict + + class _Options(TypedDict): + a: str + b: int + + opt1: _Options + opt2: _Options + opt3: _Options + """, + runtime=""" + opt1 = {"a": "3.", "b": 14} + opt2 = {"some": "stuff"} # false negative + opt3 = 0 + """, + error="opt3", + ) + def remove_color_code(s: str) -> str: return re.sub("\\x1b.*?m", "", s) # this works! @@ -870,12 +1071,19 @@ def test_missing_stubs(self) -> None: assert "error: not_a_module failed to find stubs" in remove_color_code(output.getvalue()) def test_get_typeshed_stdlib_modules(self) -> None: - stdlib = mypy.stubtest.get_typeshed_stdlib_modules(None) + stdlib = mypy.stubtest.get_typeshed_stdlib_modules(None, (3, 6)) assert "builtins" in stdlib assert "os" in stdlib assert "os.path" in stdlib assert "asyncio" in stdlib - assert ("dataclasses" in stdlib) == (sys.version_info >= (3, 7)) + assert "graphlib" not in stdlib + assert "formatter" in stdlib + assert "importlib.metadata" not in stdlib + + stdlib = mypy.stubtest.get_typeshed_stdlib_modules(None, (3, 10)) + assert "graphlib" in stdlib + assert "formatter" not in stdlib + assert "importlib.metadata" in stdlib def test_signature(self) -> None: def f(a: int, b: int, *, c: int, d: int = 0, **kwargs: Any) -> None: @@ -894,7 +1102,7 @@ def test_config_file(self) -> None: "plugins={}/test-data/unit/plugins/decimal_to_int.py\n".format(root_dir) ) output = run_stubtest(stub=stub, runtime=runtime, options=[]) - assert output == ( + assert remove_color_code(output) == ( "error: test_module.temp variable differs from runtime type Literal[5]\n" "Stub: at line 2\ndecimal.Decimal\nRuntime:\n5\n\n" ) diff --git a/mypy/test/testtypes.py b/mypy/test/testtypes.py index 0d37fe795bbc..6af1c18145cf 100644 --- a/mypy/test/testtypes.py +++ b/mypy/test/testtypes.py @@ -3,7 +3,7 @@ from typing import List, Tuple from mypy.test.helpers import Suite, assert_equal, assert_type, skip -from mypy.erasetype import erase_type +from mypy.erasetype import erase_type, remove_instance_last_known_values from mypy.expandtype import expand_type from mypy.join import join_types, join_simple from mypy.meet import meet_types, narrow_declared_type @@ -11,7 +11,8 @@ from mypy.indirection import TypeIndirectionVisitor from mypy.types import ( UnboundType, AnyType, CallableType, TupleType, TypeVarType, Type, Instance, NoneType, - Overloaded, TypeType, UnionType, UninhabitedType, TypeVarId, TypeOfAny, get_proper_type + Overloaded, TypeType, UnionType, UninhabitedType, TypeVarId, TypeOfAny, ProperType, + get_proper_type ) from mypy.nodes import ARG_POS, ARG_OPT, ARG_STAR, ARG_STAR2, CONTRAVARIANT, INVARIANT, COVARIANT from mypy.subtypes import is_subtype, is_more_precise, is_proper_subtype @@ -1092,3 +1093,46 @@ def assert_simple_is_same(self, s: Type, t: Type, expected: bool, strict: bool) '({} == {}) is {{}} ({{}} expected)'.format(s, t)) assert_equal(hash(s) == hash(t), expected, '(hash({}) == hash({}) is {{}} ({{}} expected)'.format(s, t)) + + +class RemoveLastKnownValueSuite(Suite): + def setUp(self) -> None: + self.fx = TypeFixture() + + def test_optional(self) -> None: + t = UnionType.make_union([self.fx.a, self.fx.nonet]) + self.assert_union_result(t, [self.fx.a, self.fx.nonet]) + + def test_two_instances(self) -> None: + t = UnionType.make_union([self.fx.a, self.fx.b]) + self.assert_union_result(t, [self.fx.a, self.fx.b]) + + def test_multiple_same_instances(self) -> None: + t = UnionType.make_union([self.fx.a, self.fx.a]) + assert remove_instance_last_known_values(t) == self.fx.a + t = UnionType.make_union([self.fx.a, self.fx.a, self.fx.b]) + self.assert_union_result(t, [self.fx.a, self.fx.b]) + t = UnionType.make_union([self.fx.a, self.fx.nonet, self.fx.a, self.fx.b]) + self.assert_union_result(t, [self.fx.a, self.fx.nonet, self.fx.b]) + + def test_single_last_known_value(self) -> None: + t = UnionType.make_union([self.fx.lit1_inst, self.fx.nonet]) + self.assert_union_result(t, [self.fx.a, self.fx.nonet]) + + def test_last_known_values_with_merge(self) -> None: + t = UnionType.make_union([self.fx.lit1_inst, self.fx.lit2_inst, self.fx.lit4_inst]) + assert remove_instance_last_known_values(t) == self.fx.a + t = UnionType.make_union([self.fx.lit1_inst, + self.fx.b, + self.fx.lit2_inst, + self.fx.lit4_inst]) + self.assert_union_result(t, [self.fx.a, self.fx.b]) + + def test_generics(self) -> None: + t = UnionType.make_union([self.fx.ga, self.fx.gb]) + self.assert_union_result(t, [self.fx.ga, self.fx.gb]) + + def assert_union_result(self, t: ProperType, expected: List[Type]) -> None: + t2 = remove_instance_last_known_values(t) + assert type(t2) is UnionType + assert t2.items == expected diff --git a/mypy/test/typefixture.py b/mypy/test/typefixture.py index 1a5dd8164136..7d4faeccf432 100644 --- a/mypy/test/typefixture.py +++ b/mypy/test/typefixture.py @@ -157,9 +157,11 @@ def make_type_var(name: str, id: int, values: List[Type], upper_bound: Type, self.lit1 = LiteralType(1, self.a) self.lit2 = LiteralType(2, self.a) self.lit3 = LiteralType("foo", self.d) + self.lit4 = LiteralType(4, self.a) self.lit1_inst = Instance(self.ai, [], last_known_value=self.lit1) self.lit2_inst = Instance(self.ai, [], last_known_value=self.lit2) self.lit3_inst = Instance(self.di, [], last_known_value=self.lit3) + self.lit4_inst = Instance(self.ai, [], last_known_value=self.lit4) self.type_a = TypeType.make_normalized(self.a) self.type_b = TypeType.make_normalized(self.b) diff --git a/mypy/traverser.py b/mypy/traverser.py index a5f993bd2fa5..6ab97116a12e 100644 --- a/mypy/traverser.py +++ b/mypy/traverser.py @@ -3,13 +3,17 @@ from typing import List, Tuple from mypy_extensions import mypyc_attr +from mypy.patterns import ( + AsPattern, OrPattern, ValuePattern, SequencePattern, StarredPattern, MappingPattern, + ClassPattern +) from mypy.visitor import NodeVisitor from mypy.nodes import ( Block, MypyFile, FuncBase, FuncItem, CallExpr, ClassDef, Decorator, FuncDef, ExpressionStmt, AssignmentStmt, OperatorAssignmentStmt, WhileStmt, ForStmt, ReturnStmt, AssertStmt, DelStmt, IfStmt, RaiseStmt, - TryStmt, WithStmt, NameExpr, MemberExpr, OpExpr, SliceExpr, CastExpr, RevealExpr, - UnaryExpr, ListExpr, TupleExpr, DictExpr, SetExpr, IndexExpr, AssignmentExpr, + TryStmt, WithStmt, MatchStmt, NameExpr, MemberExpr, OpExpr, SliceExpr, CastExpr, + RevealExpr, UnaryExpr, ListExpr, TupleExpr, DictExpr, SetExpr, IndexExpr, AssignmentExpr, GeneratorExpr, ListComprehension, SetComprehension, DictionaryComprehension, ConditionalExpr, TypeApplication, ExecStmt, Import, ImportFrom, LambdaExpr, ComparisonExpr, OverloadedFuncDef, YieldFromExpr, @@ -156,6 +160,15 @@ def visit_with_stmt(self, o: WithStmt) -> None: targ.accept(self) o.body.accept(self) + def visit_match_stmt(self, o: MatchStmt) -> None: + o.subject.accept(self) + for i in range(len(o.patterns)): + o.patterns[i].accept(self) + guard = o.guards[i] + if guard is not None: + guard.accept(self) + o.bodies[i].accept(self) + def visit_member_expr(self, o: MemberExpr) -> None: o.expr.accept(self) @@ -279,6 +292,42 @@ def visit_await_expr(self, o: AwaitExpr) -> None: def visit_super_expr(self, o: SuperExpr) -> None: o.call.accept(self) + def visit_as_pattern(self, o: AsPattern) -> None: + if o.pattern is not None: + o.pattern.accept(self) + if o.name is not None: + o.name.accept(self) + + def visit_or_pattern(self, o: OrPattern) -> None: + for p in o.patterns: + p.accept(self) + + def visit_value_pattern(self, o: ValuePattern) -> None: + o.expr.accept(self) + + def visit_sequence_pattern(self, o: SequencePattern) -> None: + for p in o.patterns: + p.accept(self) + + def visit_starred_patten(self, o: StarredPattern) -> None: + if o.capture is not None: + o.capture.accept(self) + + def visit_mapping_pattern(self, o: MappingPattern) -> None: + for key in o.keys: + key.accept(self) + for value in o.values: + value.accept(self) + if o.rest is not None: + o.rest.accept(self) + + def visit_class_pattern(self, o: ClassPattern) -> None: + o.class_ref.accept(self) + for p in o.positionals: + p.accept(self) + for v in o.keyword_values: + v.accept(self) + def visit_import(self, o: Import) -> None: for a in o.assignments: a.accept(self) diff --git a/mypy/typeanal.py b/mypy/typeanal.py index f7b584eadae8..766e41354553 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -12,12 +12,13 @@ from mypy.messages import MessageBuilder, quote_type_string, format_type_bare from mypy.options import Options from mypy.types import ( - Type, UnboundType, TupleType, TypedDictType, UnionType, Instance, AnyType, + NEVER_NAMES, Type, UnboundType, TupleType, TypedDictType, UnionType, Instance, AnyType, CallableType, NoneType, ErasedType, DeletedType, TypeList, TypeVarType, SyntheticTypeVisitor, 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 + TypeVarLikeType, ParamSpecType, ParamSpecFlavor, callable_with_ellipsis, + TYPE_ALIAS_NAMES, FINAL_TYPE_NAMES, LITERAL_TYPE_NAMES, ANNOTATED_TYPE_NAMES, ) from mypy.nodes import ( @@ -42,10 +43,8 @@ 'typing.Tuple', 'typing.Type', 'typing.Union', - 'typing.Literal', - 'typing_extensions.Literal', - 'typing.Annotated', - 'typing_extensions.Annotated', + *LITERAL_TYPE_NAMES, + *ANNOTATED_TYPE_NAMES, } ARG_KINDS_BY_CONSTRUCTOR: Final = { @@ -70,7 +69,6 @@ def analyze_type_alias(node: Expression, plugin: Plugin, options: Options, is_typeshed_stub: bool, - allow_new_syntax: bool = False, allow_placeholder: bool = False, in_dynamic_func: bool = False, global_scope: bool = True) -> Optional[Tuple[Type, Set[str]]]: @@ -81,12 +79,12 @@ def analyze_type_alias(node: Expression, Return None otherwise. 'node' must have been semantically analyzed. """ try: - type = expr_to_unanalyzed_type(node, options, allow_new_syntax) + type = expr_to_unanalyzed_type(node, options, api.is_stub_file) except TypeTranslationError: api.fail('Invalid type alias: expression is not a valid type', node) return None analyzer = TypeAnalyser(api, tvar_scope, plugin, options, is_typeshed_stub, - allow_new_syntax=allow_new_syntax, defining_alias=True, + defining_alias=True, allow_placeholder=allow_placeholder) analyzer.in_dynamic_func = in_dynamic_func analyzer.global_scope = global_scope @@ -127,7 +125,6 @@ def __init__(self, is_typeshed_stub: bool, *, defining_alias: bool = False, allow_tuple_literal: bool = False, - allow_new_syntax: bool = False, allow_unbound_tvars: bool = False, allow_placeholder: bool = False, allow_required: bool = False, @@ -144,8 +141,11 @@ def __init__(self, # Positive if we are analyzing arguments of another (outer) type self.nesting_level = 0 # Should we allow new type syntax when targeting older Python versions - # like 'list[int]' or 'X | Y' (allowed in stubs)? - self.allow_new_syntax = allow_new_syntax + # like 'list[int]' or 'X | Y' (allowed in stubs and with `__future__` import)? + self.always_allow_new_syntax = ( + self.api.is_stub_file + or self.api.is_future_flag_set('annotations') + ) # Should we accept unbound type variables (always OK in aliases)? self.allow_unbound_tvars = allow_unbound_tvars or defining_alias # If false, record incomplete ref if we generate PlaceholderType. @@ -202,9 +202,8 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool) if hook is not None: return hook(AnalyzeTypeContext(t, t, self)) if (fullname in get_nongen_builtins(self.options.python_version) - and t.args and - not self.allow_new_syntax and - not self.api.is_future_flag_set("annotations")): + and t.args + and not self.always_allow_new_syntax): self.fail(no_subscript_builtin_alias(fullname, propose_alt=not self.defining_alias), t) tvar_def = self.tvar_scope.get_binding(sym) @@ -262,7 +261,7 @@ 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"): + elif node.fullname in TYPE_ALIAS_NAMES: return AnyType(TypeOfAny.special_form) else: return self.analyze_unbound_type_without_type_info(t, sym, defining_literal) @@ -286,14 +285,13 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Opt return NoneType() elif fullname == 'typing.Any' or fullname == 'builtins.Any': return AnyType(TypeOfAny.explicit) - elif fullname in ('typing.Final', 'typing_extensions.Final'): + elif fullname in FINAL_TYPE_NAMES: self.fail("Final can be only used as an outermost qualifier" " in a variable annotation", t) return AnyType(TypeOfAny.from_error) elif (fullname == 'typing.Tuple' or - (fullname == 'builtins.tuple' and (self.options.python_version >= (3, 9) or - self.api.is_future_flag_set('annotations') or - self.allow_new_syntax))): + (fullname == 'builtins.tuple' + and (self.always_allow_new_syntax or self.options.python_version >= (3, 9)))): # Tuple is special because it is involved in builtin import cycle # and may be not ready when used. sym = self.api.lookup_fully_qualified_or_none('builtins.tuple') @@ -326,8 +324,8 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Opt elif fullname == 'typing.Callable': return self.analyze_callable_type(t) elif (fullname == 'typing.Type' or - (fullname == 'builtins.type' and (self.options.python_version >= (3, 9) or - self.api.is_future_flag_set('annotations')))): + (fullname == 'builtins.type' + and (self.always_allow_new_syntax or self.options.python_version >= (3, 9)))): if len(t.args) == 0: if fullname == 'typing.Type': any_type = self.get_omitted_any(t) @@ -350,11 +348,11 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Opt self.fail('ClassVar[...] must have at most one type argument', t) return AnyType(TypeOfAny.from_error) return self.anal_type(t.args[0]) - elif fullname in ('mypy_extensions.NoReturn', 'typing.NoReturn'): + elif fullname in NEVER_NAMES: return UninhabitedType(is_noreturn=True) - elif fullname in ('typing_extensions.Literal', 'typing.Literal'): + elif fullname in LITERAL_TYPE_NAMES: return self.analyze_literal_type(t) - elif fullname in ('typing_extensions.Annotated', 'typing.Annotated'): + elif fullname in ANNOTATED_TYPE_NAMES: if len(t.args) < 2: self.fail("Annotated[...] must have exactly one type argument" " and at least one annotation", t) @@ -494,7 +492,12 @@ def analyze_unbound_type_without_type_info(self, t: UnboundType, sym: SymbolTabl message = 'Variable "{}" is not valid as a type' elif isinstance(sym.node, (SYMBOL_FUNCBASE_TYPES, Decorator)): message = 'Function "{}" is not valid as a type' - notes.append('Perhaps you need "Callable[...]" or a callback protocol?') + if name == 'builtins.any': + notes.append('Perhaps you meant "typing.Any" instead of "any"?') + elif name == 'builtins.callable': + notes.append('Perhaps you meant "typing.Callable" instead of "callable"?') + else: + notes.append('Perhaps you need "Callable[...]" or a callback protocol?') elif isinstance(sym.node, MypyFile): # TODO: suggest a protocol when supported. message = 'Module "{}" is not valid as a type' @@ -704,9 +707,8 @@ def visit_star_type(self, t: StarType) -> Type: def visit_union_type(self, t: UnionType) -> Type: if (t.uses_pep604_syntax is True and t.is_evaluated is True - and self.api.is_stub_file is False - and self.options.python_version < (3, 10) - and self.api.is_future_flag_set('annotations') is False): + and not self.always_allow_new_syntax + and not self.options.python_version >= (3, 10)): self.fail("X | Y syntax for unions requires Python 3.10", t) return UnionType(self.anal_array(t.items), t.line) @@ -1289,9 +1291,9 @@ def visit_unbound_type(self, t: UnboundType) -> TypeVarLikeList: return [(name, node.node)] elif not self.include_callables and self._seems_like_callable(t): return [] - elif node and node.fullname in ('typing_extensions.Literal', 'typing.Literal'): + elif node and node.fullname in LITERAL_TYPE_NAMES: return [] - elif node and node.fullname in ('typing_extensions.Annotated', 'typing.Annotated'): + elif node and node.fullname in ANNOTATED_TYPE_NAMES and t.args: # Don't query the second argument to Annotated for TypeVars return self.query_types([t.args[0]]) else: @@ -1356,26 +1358,6 @@ def visit_typeddict_type(self, t: TypedDictType) -> bool: return False -def collect_any_types(t: Type) -> List[AnyType]: - """Return all inner `AnyType`s of type t""" - return t.accept(CollectAnyTypesQuery()) - - -class CollectAnyTypesQuery(TypeQuery[List[AnyType]]): - def __init__(self) -> None: - super().__init__(self.combine_lists_strategy) - - def visit_any(self, t: AnyType) -> List[AnyType]: - return [t] - - @classmethod - def combine_lists_strategy(cls, it: Iterable[List[AnyType]]) -> List[AnyType]: - result: List[AnyType] = [] - for l in it: - result.extend(l) - return result - - def collect_all_inner_types(t: Type) -> List[Type]: """ Return all types that `t` contains diff --git a/mypy/typeops.py b/mypy/typeops.py index 9ba170b4b822..57fdfeadad9a 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -12,9 +12,10 @@ from mypy.types import ( TupleType, Instance, FunctionLike, Type, CallableType, TypeVarLikeType, Overloaded, - TypeVarType, UninhabitedType, FormalArgument, UnionType, NoneType, TypedDictType, + TypeVarType, UninhabitedType, FormalArgument, UnionType, NoneType, AnyType, TypeOfAny, TypeType, ProperType, LiteralType, get_proper_type, get_proper_types, - copy_type, TypeAliasType, TypeQuery, ParamSpecType + copy_type, TypeAliasType, TypeQuery, ParamSpecType, + ENUM_REMOVED_PROPS ) from mypy.nodes import ( FuncBase, FuncItem, FuncDef, OverloadedFuncDef, TypeInfo, ARG_STAR, ARG_STAR2, ARG_POS, @@ -44,25 +45,6 @@ def tuple_fallback(typ: TupleType) -> Instance: return Instance(info, [join_type_list(typ.items)]) -def try_getting_instance_fallback(typ: ProperType) -> Optional[Instance]: - """Returns the Instance fallback for this type if one exists. - - Otherwise, returns None. - """ - if isinstance(typ, Instance): - return typ - elif isinstance(typ, TupleType): - return tuple_fallback(typ) - elif isinstance(typ, TypedDictType): - return typ.fallback - elif isinstance(typ, FunctionLike): - return typ.fallback - elif isinstance(typ, LiteralType): - return typ.fallback - else: - return None - - def type_object_type_from_function(signature: FunctionLike, info: TypeInfo, def_info: TypeInfo, @@ -723,7 +705,10 @@ class Status(Enum): typ = get_proper_type(typ) if isinstance(typ, UnionType): - items = [try_expanding_sum_type_to_union(item, target_fullname) for item in typ.items] + items = [ + try_expanding_sum_type_to_union(item, target_fullname) + for item in typ.relevant_items() + ] return make_simplified_union(items, contract_literals=False) elif isinstance(typ, Instance) and typ.type.fullname == target_fullname: if typ.type.is_enum: @@ -731,8 +716,8 @@ class Status(Enum): 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__"): + # Skip these since Enum will remove it + if name in ENUM_REMOVED_PROPS: continue new_items.append(LiteralType(name, typ)) # SymbolTables are really just dicts, and dicts are guaranteed to preserve @@ -795,7 +780,7 @@ def coerce_to_literal(typ: Type) -> Type: typ = get_proper_type(typ) if isinstance(typ, UnionType): new_items = [coerce_to_literal(item) for item in typ.items] - return make_simplified_union(new_items) + return UnionType.make_union(new_items) elif isinstance(typ, Instance): if typ.last_known_value: return typ.last_known_value @@ -861,3 +846,18 @@ def is_redundant_literal_instance(general: ProperType, specific: ProperType) -> return True return False + + +def separate_union_literals(t: UnionType) -> Tuple[Sequence[LiteralType], Sequence[Type]]: + """Separate literals from other members in a union type.""" + literal_items = [] + union_items = [] + + for item in t.items: + proper = get_proper_type(item) + if isinstance(proper, LiteralType): + literal_items.append(proper) + else: + union_items.append(item) + + return literal_items, union_items diff --git a/mypy/types.py b/mypy/types.py index 14eefea7dd81..dadbb84fe1c8 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -81,6 +81,73 @@ "mypy_extensions._TypedDict", ) +# Supported names of Protocol base class. +PROTOCOL_NAMES: Final = ( + 'typing.Protocol', + 'typing_extensions.Protocol', +) + +# Supported TypeAlias names. +TYPE_ALIAS_NAMES: Final = ( + "typing.TypeAlias", + "typing_extensions.TypeAlias", +) + +# Supported Final type names. +FINAL_TYPE_NAMES: Final = ( + 'typing.Final', + 'typing_extensions.Final', +) + +# Supported @final decorator names. +FINAL_DECORATOR_NAMES: Final = ( + 'typing.final', + 'typing_extensions.final', +) + +# Supported Literal type names. +LITERAL_TYPE_NAMES: Final = ( + 'typing.Literal', + 'typing_extensions.Literal', +) + +# Supported Annotated type names. +ANNOTATED_TYPE_NAMES: Final = ( + 'typing.Annotated', + 'typing_extensions.Annotated', +) + +# We use this constant in various places when checking `tuple` subtyping: +TUPLE_LIKE_INSTANCE_NAMES: Final = ( + 'builtins.tuple', + 'typing.Iterable', + 'typing.Container', + 'typing.Sequence', + 'typing.Reversible', +) + +REVEAL_TYPE_NAMES: Final = ( + 'builtins.reveal_type', + 'typing.reveal_type', + 'typing_extensions.reveal_type', +) + +# Attributes that can optionally be defined in the body of a subclass of +# enum.Enum but are removed from the class __dict__ by EnumMeta. +ENUM_REMOVED_PROPS: Final = ( + '_ignore_', + '_order_', + '__order__', +) + +NEVER_NAMES: Final = ( + 'typing.NoReturn', + 'typing_extensions.NoReturn', + 'mypy_extensions.NoReturn', + 'typing.Never', + 'typing_extensions.Never', +) + # A placeholder used for Bogus[...] parameters _dummy: Final[Any] = object() @@ -315,6 +382,9 @@ def __repr__(self) -> str: else: return "NotRequired[{}]".format(self.item) + def accept(self, visitor: 'TypeVisitor[T]') -> T: + return self.item.accept(visitor) + class ProperType(Type): """Not a type alias. @@ -903,6 +973,31 @@ class Instance(ProperType): """An instance type of form C[T1, ..., Tn]. The list of type variables may be empty. + + Several types has fallbacks to `Instance`. Why? + Because, for example `TupleTuple` is related to `builtins.tuple` instance. + And `FunctionLike` has `builtins.function` fallback. + This allows us to use types defined + in typeshed for our "special" and more precise types. + + We used to have this helper function to get a fallback from different types. + Note, that it might be incomplete, since it is not used and not updated. + It just illustrates the concept: + + def try_getting_instance_fallback(typ: ProperType) -> Optional[Instance]: + '''Returns the Instance fallback for this type if one exists or None.''' + if isinstance(typ, Instance): + return typ + elif isinstance(typ, TupleType): + return tuple_fallback(typ) + elif isinstance(typ, TypedDictType): + return typ.fallback + elif isinstance(typ, FunctionLike): + return typ.fallback + elif isinstance(typ, LiteralType): + return typ.fallback + return None + """ __slots__ = ('type', 'args', 'erased', 'invalid', 'type_ref', 'last_known_value') @@ -1033,10 +1128,11 @@ class FunctionLike(ProperType): __slots__ = ('fallback',) + fallback: Instance + def __init__(self, line: int = -1, column: int = -1) -> None: super().__init__(line, column) self.can_be_false = False - self.fallback: Instance @abstractmethod def is_type_obj(self) -> bool: pass @@ -1247,7 +1343,7 @@ def max_possible_positional_args(self) -> int: return sum([kind.is_positional() for kind in self.arg_kinds]) def formal_arguments(self, include_star_args: bool = False) -> List[FormalArgument]: - """Yields the formal arguments corresponding to this callable, ignoring *arg and **kwargs. + """Return a list of the formal arguments of this callable, ignoring *arg and **kwargs. To handle *args and **kwargs, use the 'callable.var_args' and 'callable.kw_args' fields, if they are not None. @@ -1485,7 +1581,7 @@ class TupleType(ProperType): Instance variables: items: Tuple item types partial_fallback: The (imprecise) underlying instance type that is used - for non-tuple methods. This is generally builtins.tuple[Any] for + for non-tuple methods. This is generally builtins.tuple[Any, ...] for regular tuples, but it's different for named tuples and classes with a tuple base class. Use mypy.typeops.tuple_fallback to calculate the precise fallback type derived from item types. @@ -1500,12 +1596,31 @@ class TupleType(ProperType): def __init__(self, items: List[Type], fallback: Instance, line: int = -1, column: int = -1, implicit: bool = False) -> None: - super().__init__(line, column) - self.items = items self.partial_fallback = fallback + self.items = items self.implicit = implicit - self.can_be_true = len(self.items) > 0 - self.can_be_false = len(self.items) == 0 + super().__init__(line, column) + + def can_be_true_default(self) -> bool: + if self.can_be_any_bool(): + # Corner case: it is a `NamedTuple` with `__bool__` method defined. + # It can be anything: both `True` and `False`. + return True + return self.length() > 0 + + def can_be_false_default(self) -> bool: + if self.can_be_any_bool(): + # Corner case: it is a `NamedTuple` with `__bool__` method defined. + # It can be anything: both `True` and `False`. + return True + return self.length() == 0 + + def can_be_any_bool(self) -> bool: + return bool( + self.partial_fallback.type + and self.partial_fallback.type.fullname != 'builtins.tuple' + and self.partial_fallback.type.names.get('__bool__') + ) def length(self) -> int: return len(self.items) @@ -1639,7 +1754,7 @@ def copy_modified(self, *, fallback: Optional[Instance] = None, required_keys = self.required_keys return TypedDictType(items, required_keys, fallback, self.line, self.column) - def create_anonymous_fallback(self, *, value_type: Type) -> Instance: + def create_anonymous_fallback(self) -> Instance: anonymous = self.as_anonymous() return anonymous.fallback @@ -2203,7 +2318,11 @@ def visit_instance(self, t: Instance) -> str: if t.erased: s += '*' if t.args: - s += '[{}]'.format(self.list_str(t.args)) + if t.type.fullname == 'builtins.tuple': + assert len(t.args) == 1 + s += '[{}, ...]'.format(self.list_str(t.args)) + else: + s += '[{}]'.format(self.list_str(t.args)) if self.id_mapper: s += '<{}>'.format(self.id_mapper.id(t.type)) return s @@ -2397,9 +2516,12 @@ def strip_type(typ: Type) -> ProperType: return typ -def is_named_instance(t: Type, fullname: str) -> bool: +def is_named_instance(t: Type, fullnames: Union[str, Tuple[str, ...]]) -> bool: + if not isinstance(fullnames, tuple): + fullnames = (fullnames,) + t = get_proper_type(t) - return isinstance(t, Instance) and t.type.fullname == fullname + return isinstance(t, Instance) and t.type.fullname in fullnames TP = TypeVar('TP', bound=Type) diff --git a/mypy/typeshed/stdlib/@python2/_typeshed/xml.pyi b/mypy/typeshed/stdlib/@python2/_typeshed/xml.pyi index 6a5d2531ca72..eaff9a641db4 100644 --- a/mypy/typeshed/stdlib/@python2/_typeshed/xml.pyi +++ b/mypy/typeshed/stdlib/@python2/_typeshed/xml.pyi @@ -1,7 +1,6 @@ # Stub-only types. This module does not exist at runtime. -from typing import Any -from typing_extensions import Protocol +from typing import Any, Protocol # As defined https://docs.python.org/3/library/xml.dom.html#domimplementation-objects class DOMImplementation(Protocol): diff --git a/mypy/typeshed/stdlib/@python2/_winreg.pyi b/mypy/typeshed/stdlib/@python2/_winreg.pyi index 7297626ac8b3..5b8ec1130ca1 100644 --- a/mypy/typeshed/stdlib/@python2/_winreg.pyi +++ b/mypy/typeshed/stdlib/@python2/_winreg.pyi @@ -1,96 +1,96 @@ +import sys from types import TracebackType from typing import Any, Tuple, Type, Union -_KeyType = Union[HKEYType, int] +if sys.platform == "win32": + _KeyType = Union[HKEYType, int] + def CloseKey(__hkey: _KeyType) -> None: ... + def ConnectRegistry(__computer_name: str | None, __key: _KeyType) -> HKEYType: ... + def CreateKey(__key: _KeyType, __sub_key: str | None) -> HKEYType: ... + def CreateKeyEx(key: _KeyType, sub_key: str | None, reserved: int = ..., access: int = ...) -> HKEYType: ... + 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 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 QueryValue(__key: _KeyType, __sub_key: str | None) -> str: ... + 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( + __key: _KeyType, __value_name: str | None, __reserved: Any, __type: int, __value: str | int + ) -> None: ... # reserved is ignored + def DisableReflectionKey(__key: _KeyType) -> None: ... + def EnableReflectionKey(__key: _KeyType) -> None: ... + def QueryReflectionKey(__key: _KeyType) -> bool: ... + HKEY_CLASSES_ROOT: int + HKEY_CURRENT_USER: int + HKEY_LOCAL_MACHINE: int + HKEY_USERS: int + HKEY_PERFORMANCE_DATA: int + HKEY_CURRENT_CONFIG: int + HKEY_DYN_DATA: int -def CloseKey(__hkey: _KeyType) -> None: ... -def ConnectRegistry(__computer_name: str | None, __key: _KeyType) -> HKEYType: ... -def CreateKey(__key: _KeyType, __sub_key: str | None) -> HKEYType: ... -def CreateKeyEx(key: _KeyType, sub_key: str | None, reserved: int = ..., access: int = ...) -> HKEYType: ... -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 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 QueryValue(__key: _KeyType, __sub_key: str | None) -> str: ... -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( - __key: _KeyType, __value_name: str | None, __reserved: Any, __type: int, __value: str | int -) -> None: ... # reserved is ignored -def DisableReflectionKey(__key: _KeyType) -> None: ... -def EnableReflectionKey(__key: _KeyType) -> None: ... -def QueryReflectionKey(__key: _KeyType) -> bool: ... + KEY_ALL_ACCESS: int + KEY_WRITE: int + KEY_READ: int + KEY_EXECUTE: int + KEY_QUERY_VALUE: int + KEY_SET_VALUE: int + KEY_CREATE_SUB_KEY: int + KEY_ENUMERATE_SUB_KEYS: int + KEY_NOTIFY: int + KEY_CREATE_LINK: int -HKEY_CLASSES_ROOT: int -HKEY_CURRENT_USER: int -HKEY_LOCAL_MACHINE: int -HKEY_USERS: int -HKEY_PERFORMANCE_DATA: int -HKEY_CURRENT_CONFIG: int -HKEY_DYN_DATA: int + KEY_WOW64_64KEY: int + KEY_WOW64_32KEY: int -KEY_ALL_ACCESS: int -KEY_WRITE: int -KEY_READ: int -KEY_EXECUTE: int -KEY_QUERY_VALUE: int -KEY_SET_VALUE: int -KEY_CREATE_SUB_KEY: int -KEY_ENUMERATE_SUB_KEYS: int -KEY_NOTIFY: int -KEY_CREATE_LINK: int + REG_BINARY: int + REG_DWORD: int + REG_DWORD_LITTLE_ENDIAN: int + REG_DWORD_BIG_ENDIAN: int + REG_EXPAND_SZ: int + REG_LINK: int + REG_MULTI_SZ: int + REG_NONE: int + REG_RESOURCE_LIST: int + REG_FULL_RESOURCE_DESCRIPTOR: int + REG_RESOURCE_REQUIREMENTS_LIST: int + REG_SZ: int -KEY_WOW64_64KEY: int -KEY_WOW64_32KEY: int + REG_CREATED_NEW_KEY: int # undocumented + REG_LEGAL_CHANGE_FILTER: int # undocumented + REG_LEGAL_OPTION: int # undocumented + REG_NOTIFY_CHANGE_ATTRIBUTES: int # undocumented + REG_NOTIFY_CHANGE_LAST_SET: int # undocumented + REG_NOTIFY_CHANGE_NAME: int # undocumented + REG_NOTIFY_CHANGE_SECURITY: int # undocumented + REG_NO_LAZY_FLUSH: int # undocumented + REG_OPENED_EXISTING_KEY: int # undocumented + REG_OPTION_BACKUP_RESTORE: int # undocumented + REG_OPTION_CREATE_LINK: int # undocumented + REG_OPTION_NON_VOLATILE: int # undocumented + REG_OPTION_OPEN_LINK: int # undocumented + REG_OPTION_RESERVED: int # undocumented + REG_OPTION_VOLATILE: int # undocumented + REG_REFRESH_HIVE: int # undocumented + REG_WHOLE_HIVE_VOLATILE: int # undocumented -REG_BINARY: int -REG_DWORD: int -REG_DWORD_LITTLE_ENDIAN: int -REG_DWORD_BIG_ENDIAN: int -REG_EXPAND_SZ: int -REG_LINK: int -REG_MULTI_SZ: int -REG_NONE: int -REG_RESOURCE_LIST: int -REG_FULL_RESOURCE_DESCRIPTOR: int -REG_RESOURCE_REQUIREMENTS_LIST: int -REG_SZ: int + error = OSError -REG_CREATED_NEW_KEY: int # undocumented -REG_LEGAL_CHANGE_FILTER: int # undocumented -REG_LEGAL_OPTION: int # undocumented -REG_NOTIFY_CHANGE_ATTRIBUTES: int # undocumented -REG_NOTIFY_CHANGE_LAST_SET: int # undocumented -REG_NOTIFY_CHANGE_NAME: int # undocumented -REG_NOTIFY_CHANGE_SECURITY: int # undocumented -REG_NO_LAZY_FLUSH: int # undocumented -REG_OPENED_EXISTING_KEY: int # undocumented -REG_OPTION_BACKUP_RESTORE: int # undocumented -REG_OPTION_CREATE_LINK: int # undocumented -REG_OPTION_NON_VOLATILE: int # undocumented -REG_OPTION_OPEN_LINK: int # undocumented -REG_OPTION_RESERVED: int # undocumented -REG_OPTION_VOLATILE: int # undocumented -REG_REFRESH_HIVE: int # undocumented -REG_WHOLE_HIVE_VOLATILE: int # undocumented - -error = OSError - -# Though this class has a __name__ of PyHKEY, it's exposed as HKEYType for some reason -class HKEYType: - def __bool__(self) -> bool: ... - def __int__(self) -> int: ... - def __enter__(self) -> HKEYType: ... - def __exit__( - self, exc_type: Type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None - ) -> bool | None: ... - def Close(self) -> None: ... - def Detach(self) -> int: ... + # Though this class has a __name__ of PyHKEY, it's exposed as HKEYType for some reason + class HKEYType: + def __bool__(self) -> bool: ... + def __int__(self) -> int: ... + def __enter__(self) -> HKEYType: ... + def __exit__( + self, exc_type: Type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None + ) -> bool | None: ... + def Close(self) -> None: ... + def Detach(self) -> int: ... diff --git a/mypy/typeshed/stdlib/@python2/contextlib.pyi b/mypy/typeshed/stdlib/@python2/contextlib.pyi index 6aabf5a16e47..6782fbf1874c 100644 --- a/mypy/typeshed/stdlib/@python2/contextlib.pyi +++ b/mypy/typeshed/stdlib/@python2/contextlib.pyi @@ -1,6 +1,5 @@ from types import TracebackType -from typing import IO, Any, Callable, ContextManager, Iterable, Iterator, Optional, Type, TypeVar -from typing_extensions import Protocol +from typing import IO, Any, Callable, ContextManager, Iterable, Iterator, Optional, Protocol, Type, TypeVar _T = TypeVar("_T") _T_co = TypeVar("_T_co", covariant=True) diff --git a/mypy/typeshed/stdlib/@python2/crypt.pyi b/mypy/typeshed/stdlib/@python2/crypt.pyi index c4036dbe7a5a..a7c0cb1e8fbc 100644 --- a/mypy/typeshed/stdlib/@python2/crypt.pyi +++ b/mypy/typeshed/stdlib/@python2/crypt.pyi @@ -1 +1,4 @@ -def crypt(word: str, salt: str) -> str: ... +import sys + +if sys.platform != "win32": + def crypt(word: str, salt: str) -> str: ... diff --git a/mypy/typeshed/stdlib/@python2/ctypes/__init__.pyi b/mypy/typeshed/stdlib/@python2/ctypes/__init__.pyi index 33184cc2ff88..8a10ff954e27 100644 --- a/mypy/typeshed/stdlib/@python2/ctypes/__init__.pyi +++ b/mypy/typeshed/stdlib/@python2/ctypes/__init__.pyi @@ -150,7 +150,7 @@ def create_unicode_buffer(init: _UnionT[int, Text], size: int | None = ...) -> A if sys.platform == "win32": def DllCanUnloadNow() -> int: ... def DllGetClassObject(rclsid: Any, riid: Any, ppv: Any) -> int: ... # TODO not documented - def FormatError(code: int) -> str: ... + def FormatError(code: int = ...) -> str: ... def GetLastError() -> int: ... def get_errno() -> int: ... diff --git a/mypy/typeshed/stdlib/@python2/distutils/command/bdist_msi.pyi b/mypy/typeshed/stdlib/@python2/distutils/command/bdist_msi.pyi index a761792018a9..150229fb01c9 100644 --- a/mypy/typeshed/stdlib/@python2/distutils/command/bdist_msi.pyi +++ b/mypy/typeshed/stdlib/@python2/distutils/command/bdist_msi.pyi @@ -1,6 +1,8 @@ -from distutils.cmd import Command +import sys -class bdist_msi(Command): - def initialize_options(self) -> None: ... - def finalize_options(self) -> None: ... - def run(self) -> None: ... +if sys.platform == "win32": + from distutils.cmd import Command + class bdist_msi(Command): + def initialize_options(self) -> None: ... + def finalize_options(self) -> None: ... + def run(self) -> None: ... diff --git a/mypy/typeshed/stdlib/@python2/fcntl.pyi b/mypy/typeshed/stdlib/@python2/fcntl.pyi index b3730270f1cc..0d9d598ab7c5 100644 --- a/mypy/typeshed/stdlib/@python2/fcntl.pyi +++ b/mypy/typeshed/stdlib/@python2/fcntl.pyi @@ -1,82 +1,83 @@ +import sys from _typeshed import FileDescriptorLike from typing import Any -FASYNC: int -FD_CLOEXEC: int +if sys.platform != "win32": + FASYNC: int + FD_CLOEXEC: int -DN_ACCESS: int -DN_ATTRIB: int -DN_CREATE: int -DN_DELETE: int -DN_MODIFY: int -DN_MULTISHOT: int -DN_RENAME: int -F_DUPFD: int -F_EXLCK: int -F_GETFD: int -F_GETFL: int -F_GETLEASE: int -F_GETLK: int -F_GETLK64: int -F_GETOWN: int -F_GETSIG: int -F_NOTIFY: int -F_RDLCK: int -F_SETFD: int -F_SETFL: int -F_SETLEASE: int -F_SETLK: int -F_SETLK64: int -F_SETLKW: int -F_SETLKW64: int -F_SETOWN: int -F_SETSIG: int -F_SHLCK: int -F_UNLCK: int -F_WRLCK: int -I_ATMARK: int -I_CANPUT: int -I_CKBAND: int -I_FDINSERT: int -I_FIND: int -I_FLUSH: int -I_FLUSHBAND: int -I_GETBAND: int -I_GETCLTIME: int -I_GETSIG: int -I_GRDOPT: int -I_GWROPT: int -I_LINK: int -I_LIST: int -I_LOOK: int -I_NREAD: int -I_PEEK: int -I_PLINK: int -I_POP: int -I_PUNLINK: int -I_PUSH: int -I_RECVFD: int -I_SENDFD: int -I_SETCLTIME: int -I_SETSIG: int -I_SRDOPT: int -I_STR: int -I_SWROPT: int -I_UNLINK: int -LOCK_EX: int -LOCK_MAND: int -LOCK_NB: int -LOCK_READ: int -LOCK_RW: int -LOCK_SH: int -LOCK_UN: int -LOCK_WRITE: int + DN_ACCESS: int + DN_ATTRIB: int + DN_CREATE: int + DN_DELETE: int + DN_MODIFY: int + DN_MULTISHOT: int + DN_RENAME: int + F_DUPFD: int + F_EXLCK: int + F_GETFD: int + F_GETFL: int + F_GETLEASE: int + F_GETLK: int + F_GETLK64: int + F_GETOWN: int + F_GETSIG: int + F_NOTIFY: int + F_RDLCK: int + F_SETFD: int + F_SETFL: int + F_SETLEASE: int + F_SETLK: int + F_SETLK64: int + F_SETLKW: int + F_SETLKW64: int + F_SETOWN: int + F_SETSIG: int + F_SHLCK: int + F_UNLCK: int + F_WRLCK: int + I_ATMARK: int + I_CANPUT: int + I_CKBAND: int + I_FDINSERT: int + I_FIND: int + I_FLUSH: int + I_FLUSHBAND: int + I_GETBAND: int + I_GETCLTIME: int + I_GETSIG: int + I_GRDOPT: int + I_GWROPT: int + I_LINK: int + I_LIST: int + I_LOOK: int + I_NREAD: int + I_PEEK: int + I_PLINK: int + I_POP: int + I_PUNLINK: int + I_PUSH: int + I_RECVFD: int + I_SENDFD: int + I_SETCLTIME: int + I_SETSIG: int + I_SRDOPT: int + I_STR: int + I_SWROPT: int + I_UNLINK: int + LOCK_EX: int + LOCK_MAND: int + LOCK_NB: int + LOCK_READ: int + LOCK_RW: int + LOCK_SH: int + LOCK_UN: int + LOCK_WRITE: int -# TODO All these return either int or bytes depending on the value of -# cmd (not on the type of arg). -def fcntl(fd: FileDescriptorLike, op: int, arg: int | bytes = ...) -> Any: ... - -# TODO: arg: int or read-only buffer interface or read-write buffer interface -def ioctl(fd: FileDescriptorLike, op: int, arg: int | bytes = ..., mutate_flag: bool = ...) -> Any: ... -def flock(fd: FileDescriptorLike, op: int) -> None: ... -def lockf(fd: FileDescriptorLike, op: int, length: int = ..., start: int = ..., whence: int = ...) -> Any: ... + # TODO All these return either int or bytes depending on the value of + # cmd (not on the type of arg). + def fcntl(fd: FileDescriptorLike, op: int, arg: int | bytes = ...) -> Any: ... + # TODO: arg: int or read-only buffer interface or read-write buffer interface + def ioctl(fd: FileDescriptorLike, op: int, arg: int | bytes = ..., mutate_flag: bool = ...) -> Any: ... + def flock(fd: FileDescriptorLike, op: int) -> None: ... + def lockf(fd: FileDescriptorLike, op: int, length: int = ..., start: int = ..., whence: int = ...) -> Any: ... diff --git a/mypy/typeshed/stdlib/@python2/grp.pyi b/mypy/typeshed/stdlib/@python2/grp.pyi index 63898b26bf17..6e937ec0f262 100644 --- a/mypy/typeshed/stdlib/@python2/grp.pyi +++ b/mypy/typeshed/stdlib/@python2/grp.pyi @@ -1,11 +1,12 @@ +import sys from typing import List, NamedTuple -class struct_group(NamedTuple): - gr_name: str - gr_passwd: str | None - gr_gid: int - gr_mem: List[str] - -def getgrall() -> List[struct_group]: ... -def getgrgid(id: int) -> struct_group: ... -def getgrnam(name: str) -> struct_group: ... +if sys.platform != "win32": + class struct_group(NamedTuple): + gr_name: str + gr_passwd: str | None + gr_gid: int + gr_mem: List[str] + def getgrall() -> List[struct_group]: ... + def getgrgid(id: int) -> struct_group: ... + def getgrnam(name: str) -> struct_group: ... diff --git a/mypy/typeshed/stdlib/@python2/pty.pyi b/mypy/typeshed/stdlib/@python2/pty.pyi index e8afa2df5166..d9d9fd98e41b 100644 --- a/mypy/typeshed/stdlib/@python2/pty.pyi +++ b/mypy/typeshed/stdlib/@python2/pty.pyi @@ -1,15 +1,16 @@ +import sys from typing import Callable, Iterable, Tuple -_Reader = Callable[[int], bytes] +if sys.platform != "win32": + _Reader = Callable[[int], bytes] -STDIN_FILENO: int -STDOUT_FILENO: int -STDERR_FILENO: int + STDIN_FILENO: int + STDOUT_FILENO: int + STDERR_FILENO: int -CHILD: int - -def openpty() -> Tuple[int, int]: ... -def master_open() -> Tuple[int, str]: ... -def slave_open(tty_name: str) -> int: ... -def fork() -> Tuple[int, int]: ... -def spawn(argv: str | Iterable[str], master_read: _Reader = ..., stdin_read: _Reader = ...) -> None: ... + CHILD: int + def openpty() -> Tuple[int, int]: ... + def master_open() -> Tuple[int, str]: ... + def slave_open(tty_name: str) -> int: ... + def fork() -> Tuple[int, int]: ... + def spawn(argv: str | Iterable[str], master_read: _Reader = ..., stdin_read: _Reader = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/@python2/pwd.pyi b/mypy/typeshed/stdlib/@python2/pwd.pyi index 83020c1576dd..583999fd84b7 100644 --- a/mypy/typeshed/stdlib/@python2/pwd.pyi +++ b/mypy/typeshed/stdlib/@python2/pwd.pyi @@ -1,14 +1,15 @@ +import sys from typing import List, Tuple -class struct_passwd(Tuple[str, str, int, int, str, str, str]): - pw_name: str - pw_passwd: str - pw_uid: int - pw_gid: int - pw_gecos: str - pw_dir: str - pw_shell: str - -def getpwall() -> List[struct_passwd]: ... -def getpwuid(__uid: int) -> struct_passwd: ... -def getpwnam(__name: str) -> struct_passwd: ... +if sys.platform != "win32": + class struct_passwd(Tuple[str, str, int, int, str, str, str]): + pw_name: str + pw_passwd: str + pw_uid: int + pw_gid: int + pw_gecos: str + pw_dir: str + pw_shell: str + def getpwall() -> List[struct_passwd]: ... + def getpwuid(__uid: int) -> struct_passwd: ... + def getpwnam(__name: str) -> struct_passwd: ... diff --git a/mypy/typeshed/stdlib/@python2/readline.pyi b/mypy/typeshed/stdlib/@python2/readline.pyi index fb9b12d9a8e9..9b82d9bae636 100644 --- a/mypy/typeshed/stdlib/@python2/readline.pyi +++ b/mypy/typeshed/stdlib/@python2/readline.pyi @@ -1,30 +1,31 @@ +import sys from typing import Callable, Optional, Sequence, Text -_CompleterT = Optional[Callable[[str, int], Optional[str]]] -_CompDispT = Optional[Callable[[str, Sequence[str], int], None]] - -def parse_and_bind(__string: str) -> None: ... -def read_init_file(__filename: Text | None = ...) -> None: ... -def get_line_buffer() -> str: ... -def insert_text(__string: str) -> None: ... -def redisplay() -> None: ... -def read_history_file(__filename: Text | None = ...) -> None: ... -def write_history_file(__filename: Text | None = ...) -> None: ... -def get_history_length() -> int: ... -def set_history_length(__length: int) -> None: ... -def clear_history() -> None: ... -def get_current_history_length() -> int: ... -def get_history_item(__index: int) -> str: ... -def remove_history_item(__pos: int) -> None: ... -def replace_history_item(__pos: int, __line: str) -> None: ... -def add_history(__string: str) -> None: ... -def set_startup_hook(__function: Callable[[], None] | None = ...) -> None: ... -def set_pre_input_hook(__function: Callable[[], None] | None = ...) -> None: ... -def set_completer(__function: _CompleterT = ...) -> None: ... -def get_completer() -> _CompleterT: ... -def get_completion_type() -> int: ... -def get_begidx() -> int: ... -def get_endidx() -> int: ... -def set_completer_delims(__string: str) -> None: ... -def get_completer_delims() -> str: ... -def set_completion_display_matches_hook(__function: _CompDispT = ...) -> None: ... +if sys.platform != "win32": + _CompleterT = Optional[Callable[[str, int], Optional[str]]] + _CompDispT = Optional[Callable[[str, Sequence[str], int], None]] + def parse_and_bind(__string: str) -> None: ... + def read_init_file(__filename: Text | None = ...) -> None: ... + def get_line_buffer() -> str: ... + def insert_text(__string: str) -> None: ... + def redisplay() -> None: ... + def read_history_file(__filename: Text | None = ...) -> None: ... + def write_history_file(__filename: Text | None = ...) -> None: ... + def get_history_length() -> int: ... + def set_history_length(__length: int) -> None: ... + def clear_history() -> None: ... + def get_current_history_length() -> int: ... + def get_history_item(__index: int) -> str: ... + def remove_history_item(__pos: int) -> None: ... + def replace_history_item(__pos: int, __line: str) -> None: ... + def add_history(__string: str) -> None: ... + def set_startup_hook(__function: Callable[[], None] | None = ...) -> None: ... + def set_pre_input_hook(__function: Callable[[], None] | None = ...) -> None: ... + def set_completer(__function: _CompleterT = ...) -> None: ... + def get_completer() -> _CompleterT: ... + def get_completion_type() -> int: ... + def get_begidx() -> int: ... + def get_endidx() -> int: ... + def set_completer_delims(__string: str) -> None: ... + def get_completer_delims() -> str: ... + def set_completion_display_matches_hook(__function: _CompDispT = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/@python2/resource.pyi b/mypy/typeshed/stdlib/@python2/resource.pyi index ad9502db1940..476438d53674 100644 --- a/mypy/typeshed/stdlib/@python2/resource.pyi +++ b/mypy/typeshed/stdlib/@python2/resource.pyi @@ -1,46 +1,42 @@ +import sys from typing import NamedTuple, Tuple -class error(Exception): ... - -RLIM_INFINITY: int - -def getrlimit(resource: int) -> Tuple[int, int]: ... -def setrlimit(resource: int, limits: Tuple[int, int]) -> None: ... - -RLIMIT_CORE: int -RLIMIT_CPU: int -RLIMIT_FSIZE: int -RLIMIT_DATA: int -RLIMIT_STACK: int -RLIMIT_RSS: int -RLIMIT_NPROC: int -RLIMIT_NOFILE: int -RLIMIT_OFILE: int -RLIMIT_MEMLOCK: int -RLIMIT_VMEM: int -RLIMIT_AS: int - -class _RUsage(NamedTuple): - ru_utime: float - ru_stime: float - ru_maxrss: int - ru_ixrss: int - ru_idrss: int - ru_isrss: int - ru_minflt: int - ru_majflt: int - ru_nswap: int - ru_inblock: int - ru_oublock: int - ru_msgsnd: int - ru_msgrcv: int - ru_nsignals: int - ru_nvcsw: int - ru_nivcsw: int - -def getrusage(who: int) -> _RUsage: ... -def getpagesize() -> int: ... - -RUSAGE_SELF: int -RUSAGE_CHILDREN: int -RUSAGE_BOTH: int +if sys.platform != "win32": + class error(Exception): ... + RLIM_INFINITY: int + def getrlimit(resource: int) -> Tuple[int, int]: ... + def setrlimit(resource: int, limits: Tuple[int, int]) -> None: ... + RLIMIT_CORE: int + RLIMIT_CPU: int + RLIMIT_FSIZE: int + RLIMIT_DATA: int + RLIMIT_STACK: int + RLIMIT_RSS: int + RLIMIT_NPROC: int + RLIMIT_NOFILE: int + RLIMIT_OFILE: int + RLIMIT_MEMLOCK: int + RLIMIT_VMEM: int + RLIMIT_AS: int + class _RUsage(NamedTuple): + ru_utime: float + ru_stime: float + ru_maxrss: int + ru_ixrss: int + ru_idrss: int + ru_isrss: int + ru_minflt: int + ru_majflt: int + ru_nswap: int + ru_inblock: int + ru_oublock: int + ru_msgsnd: int + ru_msgrcv: int + ru_nsignals: int + ru_nvcsw: int + ru_nivcsw: int + def getrusage(who: int) -> _RUsage: ... + def getpagesize() -> int: ... + RUSAGE_SELF: int + RUSAGE_CHILDREN: int + RUSAGE_BOTH: int diff --git a/mypy/typeshed/stdlib/@python2/spwd.pyi b/mypy/typeshed/stdlib/@python2/spwd.pyi index 756c142a61da..95122ce43d1e 100644 --- a/mypy/typeshed/stdlib/@python2/spwd.pyi +++ b/mypy/typeshed/stdlib/@python2/spwd.pyi @@ -1,15 +1,16 @@ +import sys from typing import List, NamedTuple -class struct_spwd(NamedTuple): - sp_nam: str - sp_pwd: str - sp_lstchg: int - sp_min: int - sp_max: int - sp_warn: int - sp_inact: int - sp_expire: int - sp_flag: int - -def getspall() -> List[struct_spwd]: ... -def getspnam(name: str) -> struct_spwd: ... +if sys.platform != "win32": + class struct_spwd(NamedTuple): + sp_nam: str + sp_pwd: str + sp_lstchg: int + sp_min: int + sp_max: int + sp_warn: int + sp_inact: int + sp_expire: int + sp_flag: int + def getspall() -> List[struct_spwd]: ... + def getspnam(name: str) -> struct_spwd: ... diff --git a/mypy/typeshed/stdlib/@python2/syslog.pyi b/mypy/typeshed/stdlib/@python2/syslog.pyi index 49169f40db5c..eaeeb7715e48 100644 --- a/mypy/typeshed/stdlib/@python2/syslog.pyi +++ b/mypy/typeshed/stdlib/@python2/syslog.pyi @@ -1,43 +1,44 @@ +import sys from typing import overload -LOG_ALERT: int -LOG_AUTH: int -LOG_CONS: int -LOG_CRIT: int -LOG_CRON: int -LOG_DAEMON: int -LOG_DEBUG: int -LOG_EMERG: int -LOG_ERR: int -LOG_INFO: int -LOG_KERN: int -LOG_LOCAL0: int -LOG_LOCAL1: int -LOG_LOCAL2: int -LOG_LOCAL3: int -LOG_LOCAL4: int -LOG_LOCAL5: int -LOG_LOCAL6: int -LOG_LOCAL7: int -LOG_LPR: int -LOG_MAIL: int -LOG_NDELAY: int -LOG_NEWS: int -LOG_NOTICE: int -LOG_NOWAIT: int -LOG_PERROR: int -LOG_PID: int -LOG_SYSLOG: int -LOG_USER: int -LOG_UUCP: int -LOG_WARNING: int - -def LOG_MASK(a: int) -> int: ... -def LOG_UPTO(a: int) -> int: ... -def closelog() -> None: ... -def openlog(ident: str = ..., logoption: int = ..., facility: int = ...) -> None: ... -def setlogmask(x: int) -> int: ... -@overload -def syslog(priority: int, message: str) -> None: ... -@overload -def syslog(message: str) -> None: ... +if sys.platform != "win32": + LOG_ALERT: int + LOG_AUTH: int + LOG_CONS: int + LOG_CRIT: int + LOG_CRON: int + LOG_DAEMON: int + LOG_DEBUG: int + LOG_EMERG: int + LOG_ERR: int + LOG_INFO: int + LOG_KERN: int + LOG_LOCAL0: int + LOG_LOCAL1: int + LOG_LOCAL2: int + LOG_LOCAL3: int + LOG_LOCAL4: int + LOG_LOCAL5: int + LOG_LOCAL6: int + LOG_LOCAL7: int + LOG_LPR: int + LOG_MAIL: int + LOG_NDELAY: int + LOG_NEWS: int + LOG_NOTICE: int + LOG_NOWAIT: int + LOG_PERROR: int + LOG_PID: int + LOG_SYSLOG: int + LOG_USER: int + LOG_UUCP: int + LOG_WARNING: int + def LOG_MASK(a: int) -> int: ... + def LOG_UPTO(a: int) -> int: ... + def closelog() -> None: ... + def openlog(ident: str = ..., logoption: int = ..., facility: int = ...) -> None: ... + def setlogmask(x: int) -> int: ... + @overload + def syslog(priority: int, message: str) -> None: ... + @overload + def syslog(message: str) -> None: ... diff --git a/mypy/typeshed/stdlib/@python2/termios.pyi b/mypy/typeshed/stdlib/@python2/termios.pyi index 0c627f4b72bd..cee6b85f9ba5 100644 --- a/mypy/typeshed/stdlib/@python2/termios.pyi +++ b/mypy/typeshed/stdlib/@python2/termios.pyi @@ -1,246 +1,246 @@ +import sys from _typeshed import FileDescriptorLike from typing import Any, List, Union -_Attr = List[Union[int, List[Union[bytes, int]]]] +if sys.platform != "win32": + _Attr = List[Union[int, List[Union[bytes, int]]]] -# TODO constants not really documented -B0: int -B1000000: int -B110: int -B115200: int -B1152000: int -B1200: int -B134: int -B150: int -B1500000: int -B1800: int -B19200: int -B200: int -B2000000: int -B230400: int -B2400: int -B2500000: int -B300: int -B3000000: int -B3500000: int -B38400: int -B4000000: int -B460800: int -B4800: int -B50: int -B500000: int -B57600: int -B576000: int -B600: int -B75: int -B921600: int -B9600: int -BRKINT: int -BS0: int -BS1: int -BSDLY: int -CBAUD: int -CBAUDEX: int -CDSUSP: int -CEOF: int -CEOL: int -CEOT: int -CERASE: int -CFLUSH: int -CIBAUD: int -CINTR: int -CKILL: int -CLNEXT: int -CLOCAL: int -CQUIT: int -CR0: int -CR1: int -CR2: int -CR3: int -CRDLY: int -CREAD: int -CRPRNT: int -CRTSCTS: int -CS5: int -CS6: int -CS7: int -CS8: int -CSIZE: int -CSTART: int -CSTOP: int -CSTOPB: int -CSUSP: int -CWERASE: int -ECHO: int -ECHOCTL: int -ECHOE: int -ECHOK: int -ECHOKE: int -ECHONL: int -ECHOPRT: int -EXTA: int -EXTB: int -FF0: int -FF1: int -FFDLY: int -FIOASYNC: int -FIOCLEX: int -FIONBIO: int -FIONCLEX: int -FIONREAD: int -FLUSHO: int -HUPCL: int -ICANON: int -ICRNL: int -IEXTEN: int -IGNBRK: int -IGNCR: int -IGNPAR: int -IMAXBEL: int -INLCR: int -INPCK: int -IOCSIZE_MASK: int -IOCSIZE_SHIFT: int -ISIG: int -ISTRIP: int -IUCLC: int -IXANY: int -IXOFF: int -IXON: int -NCC: int -NCCS: int -NL0: int -NL1: int -NLDLY: int -NOFLSH: int -N_MOUSE: int -N_PPP: int -N_SLIP: int -N_STRIP: int -N_TTY: int -OCRNL: int -OFDEL: int -OFILL: int -OLCUC: int -ONLCR: int -ONLRET: int -ONOCR: int -OPOST: int -PARENB: int -PARMRK: int -PARODD: int -PENDIN: int -TAB0: int -TAB1: int -TAB2: int -TAB3: int -TABDLY: int -TCFLSH: int -TCGETA: int -TCGETS: int -TCIFLUSH: int -TCIOFF: int -TCIOFLUSH: int -TCION: int -TCOFLUSH: int -TCOOFF: int -TCOON: int -TCSADRAIN: int -TCSAFLUSH: int -TCSANOW: int -TCSBRK: int -TCSBRKP: int -TCSETA: int -TCSETAF: int -TCSETAW: int -TCSETS: int -TCSETSF: int -TCSETSW: int -TCXONC: int -TIOCCONS: int -TIOCEXCL: int -TIOCGETD: int -TIOCGICOUNT: int -TIOCGLCKTRMIOS: int -TIOCGPGRP: int -TIOCGSERIAL: int -TIOCGSOFTCAR: int -TIOCGWINSZ: int -TIOCINQ: int -TIOCLINUX: int -TIOCMBIC: int -TIOCMBIS: int -TIOCMGET: int -TIOCMIWAIT: int -TIOCMSET: int -TIOCM_CAR: int -TIOCM_CD: int -TIOCM_CTS: int -TIOCM_DSR: int -TIOCM_DTR: int -TIOCM_LE: int -TIOCM_RI: int -TIOCM_RNG: int -TIOCM_RTS: int -TIOCM_SR: int -TIOCM_ST: int -TIOCNOTTY: int -TIOCNXCL: int -TIOCOUTQ: int -TIOCPKT: int -TIOCPKT_DATA: int -TIOCPKT_DOSTOP: int -TIOCPKT_FLUSHREAD: int -TIOCPKT_FLUSHWRITE: int -TIOCPKT_NOSTOP: int -TIOCPKT_START: int -TIOCPKT_STOP: int -TIOCSCTTY: int -TIOCSERCONFIG: int -TIOCSERGETLSR: int -TIOCSERGETMULTI: int -TIOCSERGSTRUCT: int -TIOCSERGWILD: int -TIOCSERSETMULTI: int -TIOCSERSWILD: int -TIOCSER_TEMT: int -TIOCSETD: int -TIOCSLCKTRMIOS: int -TIOCSPGRP: int -TIOCSSERIAL: int -TIOCSSOFTCAR: int -TIOCSTI: int -TIOCSWINSZ: int -TOSTOP: int -VDISCARD: int -VEOF: int -VEOL: int -VEOL2: int -VERASE: int -VINTR: int -VKILL: int -VLNEXT: int -VMIN: int -VQUIT: int -VREPRINT: int -VSTART: int -VSTOP: int -VSUSP: int -VSWTC: int -VSWTCH: int -VT0: int -VT1: int -VTDLY: int -VTIME: int -VWERASE: int -XCASE: int -XTABS: int - -def tcgetattr(__fd: FileDescriptorLike) -> List[Any]: ... -def tcsetattr(__fd: FileDescriptorLike, __when: int, __attributes: _Attr) -> None: ... -def tcsendbreak(__fd: FileDescriptorLike, __duration: int) -> None: ... -def tcdrain(__fd: FileDescriptorLike) -> None: ... -def tcflush(__fd: FileDescriptorLike, __queue: int) -> None: ... -def tcflow(__fd: FileDescriptorLike, __action: int) -> None: ... - -class error(Exception): ... + # TODO constants not really documented + B0: int + B1000000: int + B110: int + B115200: int + B1152000: int + B1200: int + B134: int + B150: int + B1500000: int + B1800: int + B19200: int + B200: int + B2000000: int + B230400: int + B2400: int + B2500000: int + B300: int + B3000000: int + B3500000: int + B38400: int + B4000000: int + B460800: int + B4800: int + B50: int + B500000: int + B57600: int + B576000: int + B600: int + B75: int + B921600: int + B9600: int + BRKINT: int + BS0: int + BS1: int + BSDLY: int + CBAUD: int + CBAUDEX: int + CDSUSP: int + CEOF: int + CEOL: int + CEOT: int + CERASE: int + CFLUSH: int + CIBAUD: int + CINTR: int + CKILL: int + CLNEXT: int + CLOCAL: int + CQUIT: int + CR0: int + CR1: int + CR2: int + CR3: int + CRDLY: int + CREAD: int + CRPRNT: int + CRTSCTS: int + CS5: int + CS6: int + CS7: int + CS8: int + CSIZE: int + CSTART: int + CSTOP: int + CSTOPB: int + CSUSP: int + CWERASE: int + ECHO: int + ECHOCTL: int + ECHOE: int + ECHOK: int + ECHOKE: int + ECHONL: int + ECHOPRT: int + EXTA: int + EXTB: int + FF0: int + FF1: int + FFDLY: int + FIOASYNC: int + FIOCLEX: int + FIONBIO: int + FIONCLEX: int + FIONREAD: int + FLUSHO: int + HUPCL: int + ICANON: int + ICRNL: int + IEXTEN: int + IGNBRK: int + IGNCR: int + IGNPAR: int + IMAXBEL: int + INLCR: int + INPCK: int + IOCSIZE_MASK: int + IOCSIZE_SHIFT: int + ISIG: int + ISTRIP: int + IUCLC: int + IXANY: int + IXOFF: int + IXON: int + NCC: int + NCCS: int + NL0: int + NL1: int + NLDLY: int + NOFLSH: int + N_MOUSE: int + N_PPP: int + N_SLIP: int + N_STRIP: int + N_TTY: int + OCRNL: int + OFDEL: int + OFILL: int + OLCUC: int + ONLCR: int + ONLRET: int + ONOCR: int + OPOST: int + PARENB: int + PARMRK: int + PARODD: int + PENDIN: int + TAB0: int + TAB1: int + TAB2: int + TAB3: int + TABDLY: int + TCFLSH: int + TCGETA: int + TCGETS: int + TCIFLUSH: int + TCIOFF: int + TCIOFLUSH: int + TCION: int + TCOFLUSH: int + TCOOFF: int + TCOON: int + TCSADRAIN: int + TCSAFLUSH: int + TCSANOW: int + TCSBRK: int + TCSBRKP: int + TCSETA: int + TCSETAF: int + TCSETAW: int + TCSETS: int + TCSETSF: int + TCSETSW: int + TCXONC: int + TIOCCONS: int + TIOCEXCL: int + TIOCGETD: int + TIOCGICOUNT: int + TIOCGLCKTRMIOS: int + TIOCGPGRP: int + TIOCGSERIAL: int + TIOCGSOFTCAR: int + TIOCGWINSZ: int + TIOCINQ: int + TIOCLINUX: int + TIOCMBIC: int + TIOCMBIS: int + TIOCMGET: int + TIOCMIWAIT: int + TIOCMSET: int + TIOCM_CAR: int + TIOCM_CD: int + TIOCM_CTS: int + TIOCM_DSR: int + TIOCM_DTR: int + TIOCM_LE: int + TIOCM_RI: int + TIOCM_RNG: int + TIOCM_RTS: int + TIOCM_SR: int + TIOCM_ST: int + TIOCNOTTY: int + TIOCNXCL: int + TIOCOUTQ: int + TIOCPKT: int + TIOCPKT_DATA: int + TIOCPKT_DOSTOP: int + TIOCPKT_FLUSHREAD: int + TIOCPKT_FLUSHWRITE: int + TIOCPKT_NOSTOP: int + TIOCPKT_START: int + TIOCPKT_STOP: int + TIOCSCTTY: int + TIOCSERCONFIG: int + TIOCSERGETLSR: int + TIOCSERGETMULTI: int + TIOCSERGSTRUCT: int + TIOCSERGWILD: int + TIOCSERSETMULTI: int + TIOCSERSWILD: int + TIOCSER_TEMT: int + TIOCSETD: int + TIOCSLCKTRMIOS: int + TIOCSPGRP: int + TIOCSSERIAL: int + TIOCSSOFTCAR: int + TIOCSTI: int + TIOCSWINSZ: int + TOSTOP: int + VDISCARD: int + VEOF: int + VEOL: int + VEOL2: int + VERASE: int + VINTR: int + VKILL: int + VLNEXT: int + VMIN: int + VQUIT: int + VREPRINT: int + VSTART: int + VSTOP: int + VSUSP: int + VSWTC: int + VSWTCH: int + VT0: int + VT1: int + VTDLY: int + VTIME: int + VWERASE: int + XCASE: int + XTABS: int + def tcgetattr(__fd: FileDescriptorLike) -> List[Any]: ... + def tcsetattr(__fd: FileDescriptorLike, __when: int, __attributes: _Attr) -> None: ... + def tcsendbreak(__fd: FileDescriptorLike, __duration: int) -> None: ... + def tcdrain(__fd: FileDescriptorLike) -> None: ... + def tcflush(__fd: FileDescriptorLike, __queue: int) -> None: ... + def tcflow(__fd: FileDescriptorLike, __action: int) -> None: ... + class error(Exception): ... diff --git a/mypy/typeshed/stdlib/@python2/tty.pyi b/mypy/typeshed/stdlib/@python2/tty.pyi index c0dc418e9933..56e85108c75e 100644 --- a/mypy/typeshed/stdlib/@python2/tty.pyi +++ b/mypy/typeshed/stdlib/@python2/tty.pyi @@ -1,15 +1,16 @@ +import sys from typing import IO, Union _FD = Union[int, IO[str]] -# XXX: Undocumented integer constants -IFLAG: int -OFLAG: int -CFLAG: int -LFLAG: int -ISPEED: int -OSPEED: int -CC: int - -def setraw(fd: _FD, when: int = ...) -> None: ... -def setcbreak(fd: _FD, when: int = ...) -> None: ... +if sys.platform != "win32": + # XXX: Undocumented integer constants + IFLAG: int + OFLAG: int + CFLAG: int + LFLAG: int + ISPEED: int + OSPEED: int + CC: int + def setraw(fd: _FD, when: int = ...) -> None: ... + def setcbreak(fd: _FD, when: int = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/@python2/types.pyi b/mypy/typeshed/stdlib/@python2/types.pyi index 72b9321a860f..0feee4530586 100644 --- a/mypy/typeshed/stdlib/@python2/types.pyi +++ b/mypy/typeshed/stdlib/@python2/types.pyi @@ -148,7 +148,7 @@ class FrameType: f_exc_traceback: None f_globals: Dict[str, Any] f_lasti: int - f_lineno: int + f_lineno: int | None f_locals: Dict[str, Any] f_restricted: bool f_trace: Callable[[], None] diff --git a/mypy/typeshed/stdlib/VERSIONS b/mypy/typeshed/stdlib/VERSIONS index 9b9271117fa7..e82161d97cb6 100644 --- a/mypy/typeshed/stdlib/VERSIONS +++ b/mypy/typeshed/stdlib/VERSIONS @@ -29,8 +29,8 @@ _compression: 3.6- _csv: 2.7- _curses: 2.7- _decimal: 3.6- -_dummy_thread: 3.6- -_dummy_threading: 2.7- +_dummy_thread: 3.6-3.8 +_dummy_threading: 2.7-3.8 _heapq: 2.7- _imp: 3.6- _json: 2.7- @@ -103,8 +103,9 @@ decimal: 2.7- difflib: 2.7- dis: 2.7- distutils: 2.7- +distutils.command.bdist_msi: 2.7-3.10 doctest: 2.7- -dummy_threading: 2.7- +dummy_threading: 2.7-3.8 email: 2.7- encodings: 2.7- ensurepip: 2.7- @@ -138,6 +139,7 @@ imghdr: 2.7- imp: 2.7- importlib: 2.7- importlib.metadata: 3.8- +importlib.metadata._meta: 3.10- importlib.resources: 3.7- inspect: 2.7- io: 2.7- @@ -259,6 +261,7 @@ typing: 3.5- typing_extensions: 2.7- unicodedata: 2.7- unittest: 2.7- +unittest._log: 3.9- urllib: 2.7- uu: 2.7- uuid: 2.7- diff --git a/mypy/typeshed/stdlib/_bisect.pyi b/mypy/typeshed/stdlib/_bisect.pyi index 6da6e7f58823..1f67dadd89a0 100644 --- a/mypy/typeshed/stdlib/_bisect.pyi +++ b/mypy/typeshed/stdlib/_bisect.pyi @@ -1,21 +1,31 @@ import sys -from _typeshed import SupportsLessThan +from _typeshed import SupportsRichComparison from typing import Callable, MutableSequence, Sequence, TypeVar _T = TypeVar("_T") if sys.version_info >= (3, 10): def bisect_left( - a: Sequence[_T], x: _T, lo: int = ..., hi: int | None = ..., *, key: Callable[[_T], SupportsLessThan] | None = ... + a: Sequence[_T], x: _T, lo: int = ..., hi: int | None = ..., *, key: Callable[[_T], SupportsRichComparison] | None = ... ) -> int: ... def bisect_right( - a: Sequence[_T], x: _T, lo: int = ..., hi: int | None = ..., *, key: Callable[[_T], SupportsLessThan] | None = ... + a: Sequence[_T], x: _T, lo: int = ..., hi: int | None = ..., *, key: Callable[[_T], SupportsRichComparison] | None = ... ) -> int: ... def insort_left( - a: MutableSequence[_T], x: _T, lo: int = ..., hi: int | None = ..., *, key: Callable[[_T], SupportsLessThan] | None = ... + a: MutableSequence[_T], + x: _T, + lo: int = ..., + hi: int | None = ..., + *, + key: Callable[[_T], SupportsRichComparison] | None = ..., ) -> None: ... def insort_right( - a: MutableSequence[_T], x: _T, lo: int = ..., hi: int | None = ..., *, key: Callable[[_T], SupportsLessThan] | None = ... + a: MutableSequence[_T], + x: _T, + lo: int = ..., + hi: int | None = ..., + *, + key: Callable[[_T], SupportsRichComparison] | None = ..., ) -> None: ... else: diff --git a/mypy/typeshed/stdlib/_codecs.pyi b/mypy/typeshed/stdlib/_codecs.pyi index 5e4a9ad6da3d..470722a293a3 100644 --- a/mypy/typeshed/stdlib/_codecs.pyi +++ b/mypy/typeshed/stdlib/_codecs.pyi @@ -1,13 +1,13 @@ import codecs import sys -from typing import Any, Callable, Dict, Tuple, Union +from typing import Any, Callable, Union # This type is not exposed; it is defined in unicodeobject.c class _EncodingMap: def size(self) -> int: ... -_MapT = Union[Dict[int, int], _EncodingMap] -_Handler = Callable[[Exception], Tuple[str, int]] +_MapT = Union[dict[int, int], _EncodingMap] +_Handler = Callable[[Exception], tuple[str, int]] def register(__search_function: Callable[[str], Any]) -> None: ... def register_error(__errors: str, __handler: _Handler) -> None: ... @@ -24,10 +24,22 @@ def escape_decode(__data: str | bytes, __errors: str | None = ...) -> tuple[str, 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]: ... + +if sys.version_info >= (3, 9): + def raw_unicode_escape_decode(__data: str | bytes, __errors: str | None = ..., __final: bool = ...) -> tuple[str, int]: ... + +else: + 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]: ... + +if sys.version_info >= (3, 9): + def unicode_escape_decode(__data: str | bytes, __errors: str | None = ..., __final: bool = ...) -> tuple[str, int]: ... + +else: + 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): diff --git a/mypy/typeshed/stdlib/_compat_pickle.pyi b/mypy/typeshed/stdlib/_compat_pickle.pyi index 76aba3020321..50fb22442cc9 100644 --- a/mypy/typeshed/stdlib/_compat_pickle.pyi +++ b/mypy/typeshed/stdlib/_compat_pickle.pyi @@ -1,10 +1,8 @@ -from typing import Tuple - IMPORT_MAPPING: dict[str, str] NAME_MAPPING: dict[tuple[str, str], tuple[str, str]] -PYTHON2_EXCEPTIONS: Tuple[str, ...] -MULTIPROCESSING_EXCEPTIONS: Tuple[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]] -PYTHON3_OSERROR_EXCEPTIONS: Tuple[str, ...] -PYTHON3_IMPORTERROR_EXCEPTIONS: Tuple[str, ...] +PYTHON3_OSERROR_EXCEPTIONS: tuple[str, ...] +PYTHON3_IMPORTERROR_EXCEPTIONS: tuple[str, ...] diff --git a/mypy/typeshed/stdlib/_compression.pyi b/mypy/typeshed/stdlib/_compression.pyi index 8f81847ff492..31940e3eb15b 100644 --- a/mypy/typeshed/stdlib/_compression.pyi +++ b/mypy/typeshed/stdlib/_compression.pyi @@ -1,6 +1,6 @@ from _typeshed import WriteableBuffer from io import BufferedIOBase, RawIOBase -from typing import Any, Callable, Protocol, Tuple, Type +from typing import Any, Callable, Protocol, Type BUFFER_SIZE: Any @@ -16,7 +16,7 @@ class DecompressReader(RawIOBase): self, fp: _Reader, decomp_factory: Callable[..., object], - trailing_error: Type[Exception] | Tuple[Type[Exception], ...] = ..., + trailing_error: Type[Exception] | tuple[Type[Exception], ...] = ..., **decomp_args: Any, ) -> None: ... def readable(self) -> bool: ... diff --git a/mypy/typeshed/stdlib/_csv.pyi b/mypy/typeshed/stdlib/_csv.pyi index 1dc43780f687..54e9099bbdcd 100644 --- a/mypy/typeshed/stdlib/_csv.pyi +++ b/mypy/typeshed/stdlib/_csv.pyi @@ -1,4 +1,4 @@ -from typing import Any, Iterable, Iterator, List, Protocol, Type, Union +from typing import Any, Iterable, Iterator, Protocol, Type, Union QUOTE_ALL: int QUOTE_MINIMAL: int @@ -20,7 +20,7 @@ class Dialect: _DialectLike = Union[str, Dialect, Type[Dialect]] -class _reader(Iterator[List[str]]): +class _reader(Iterator[list[str]]): dialect: Dialect line_num: int def __next__(self) -> list[str]: ... @@ -31,7 +31,7 @@ class _writer: def writerows(self, rows: Iterable[Iterable[Any]]) -> None: ... class _Writer(Protocol): - def write(self, s: str) -> Any: ... + def write(self, __s: str) -> object: ... def writer(csvfile: _Writer, dialect: _DialectLike = ..., **fmtparams: Any) -> _writer: ... def reader(csvfile: Iterable[str], dialect: _DialectLike = ..., **fmtparams: Any) -> _reader: ... diff --git a/mypy/typeshed/stdlib/_curses.pyi b/mypy/typeshed/stdlib/_curses.pyi index e0f978c5cae1..9f23eeb1c6dc 100644 --- a/mypy/typeshed/stdlib/_curses.pyi +++ b/mypy/typeshed/stdlib/_curses.pyi @@ -1,548 +1,547 @@ import sys -from typing import IO, Any, BinaryIO, NamedTuple, Union, overload +from _typeshed import SupportsRead +from typing import IO, Any, NamedTuple, Union, overload -_chtype = Union[str, bytes, int] +if sys.platform != "win32": + _chtype = Union[str, bytes, int] -# ACS codes are only initialized after initscr is called -ACS_BBSS: int -ACS_BLOCK: int -ACS_BOARD: int -ACS_BSBS: int -ACS_BSSB: int -ACS_BSSS: int -ACS_BTEE: int -ACS_BULLET: int -ACS_CKBOARD: int -ACS_DARROW: int -ACS_DEGREE: int -ACS_DIAMOND: int -ACS_GEQUAL: int -ACS_HLINE: int -ACS_LANTERN: int -ACS_LARROW: int -ACS_LEQUAL: int -ACS_LLCORNER: int -ACS_LRCORNER: int -ACS_LTEE: int -ACS_NEQUAL: int -ACS_PI: int -ACS_PLMINUS: int -ACS_PLUS: int -ACS_RARROW: int -ACS_RTEE: int -ACS_S1: int -ACS_S3: int -ACS_S7: int -ACS_S9: int -ACS_SBBS: int -ACS_SBSB: int -ACS_SBSS: int -ACS_SSBB: int -ACS_SSBS: int -ACS_SSSB: int -ACS_SSSS: int -ACS_STERLING: int -ACS_TTEE: int -ACS_UARROW: int -ACS_ULCORNER: int -ACS_URCORNER: int -ACS_VLINE: int -ALL_MOUSE_EVENTS: int -A_ALTCHARSET: int -A_ATTRIBUTES: int -A_BLINK: int -A_BOLD: int -A_CHARTEXT: int -A_COLOR: int -A_DIM: int -A_HORIZONTAL: int -A_INVIS: int -if sys.version_info >= (3, 7): - A_ITALIC: int -A_LEFT: int -A_LOW: int -A_NORMAL: int -A_PROTECT: int -A_REVERSE: int -A_RIGHT: int -A_STANDOUT: int -A_TOP: int -A_UNDERLINE: int -A_VERTICAL: int -BUTTON1_CLICKED: int -BUTTON1_DOUBLE_CLICKED: int -BUTTON1_PRESSED: int -BUTTON1_RELEASED: int -BUTTON1_TRIPLE_CLICKED: int -BUTTON2_CLICKED: int -BUTTON2_DOUBLE_CLICKED: int -BUTTON2_PRESSED: int -BUTTON2_RELEASED: int -BUTTON2_TRIPLE_CLICKED: int -BUTTON3_CLICKED: int -BUTTON3_DOUBLE_CLICKED: int -BUTTON3_PRESSED: int -BUTTON3_RELEASED: int -BUTTON3_TRIPLE_CLICKED: int -BUTTON4_CLICKED: int -BUTTON4_DOUBLE_CLICKED: int -BUTTON4_PRESSED: int -BUTTON4_RELEASED: int -BUTTON4_TRIPLE_CLICKED: int -# Darwin ncurses doesn't provide BUTTON5_* constants -if sys.version_info >= (3, 10) and sys.platform != "darwin": - BUTTON5_PRESSED: int - BUTTON5_RELEASED: int - BUTTON5_CLICKED: int - BUTTON5_DOUBLE_CLICKED: int - BUTTON5_TRIPLE_CLICKED: int -BUTTON_ALT: int -BUTTON_CTRL: int -BUTTON_SHIFT: int -COLOR_BLACK: int -COLOR_BLUE: int -COLOR_CYAN: int -COLOR_GREEN: int -COLOR_MAGENTA: int -COLOR_RED: int -COLOR_WHITE: int -COLOR_YELLOW: int -ERR: int -KEY_A1: int -KEY_A3: int -KEY_B2: int -KEY_BACKSPACE: int -KEY_BEG: int -KEY_BREAK: int -KEY_BTAB: int -KEY_C1: int -KEY_C3: int -KEY_CANCEL: int -KEY_CATAB: int -KEY_CLEAR: int -KEY_CLOSE: int -KEY_COMMAND: int -KEY_COPY: int -KEY_CREATE: int -KEY_CTAB: int -KEY_DC: int -KEY_DL: int -KEY_DOWN: int -KEY_EIC: int -KEY_END: int -KEY_ENTER: int -KEY_EOL: int -KEY_EOS: int -KEY_EXIT: int -KEY_F0: int -KEY_F1: int -KEY_F10: int -KEY_F11: int -KEY_F12: int -KEY_F13: int -KEY_F14: int -KEY_F15: int -KEY_F16: int -KEY_F17: int -KEY_F18: int -KEY_F19: int -KEY_F2: int -KEY_F20: int -KEY_F21: int -KEY_F22: int -KEY_F23: int -KEY_F24: int -KEY_F25: int -KEY_F26: int -KEY_F27: int -KEY_F28: int -KEY_F29: int -KEY_F3: int -KEY_F30: int -KEY_F31: int -KEY_F32: int -KEY_F33: int -KEY_F34: int -KEY_F35: int -KEY_F36: int -KEY_F37: int -KEY_F38: int -KEY_F39: int -KEY_F4: int -KEY_F40: int -KEY_F41: int -KEY_F42: int -KEY_F43: int -KEY_F44: int -KEY_F45: int -KEY_F46: int -KEY_F47: int -KEY_F48: int -KEY_F49: int -KEY_F5: int -KEY_F50: int -KEY_F51: int -KEY_F52: int -KEY_F53: int -KEY_F54: int -KEY_F55: int -KEY_F56: int -KEY_F57: int -KEY_F58: int -KEY_F59: int -KEY_F6: int -KEY_F60: int -KEY_F61: int -KEY_F62: int -KEY_F63: int -KEY_F7: int -KEY_F8: int -KEY_F9: int -KEY_FIND: int -KEY_HELP: int -KEY_HOME: int -KEY_IC: int -KEY_IL: int -KEY_LEFT: int -KEY_LL: int -KEY_MARK: int -KEY_MAX: int -KEY_MESSAGE: int -KEY_MIN: int -KEY_MOUSE: int -KEY_MOVE: int -KEY_NEXT: int -KEY_NPAGE: int -KEY_OPEN: int -KEY_OPTIONS: int -KEY_PPAGE: int -KEY_PREVIOUS: int -KEY_PRINT: int -KEY_REDO: int -KEY_REFERENCE: int -KEY_REFRESH: int -KEY_REPLACE: int -KEY_RESET: int -KEY_RESIZE: int -KEY_RESTART: int -KEY_RESUME: int -KEY_RIGHT: int -KEY_SAVE: int -KEY_SBEG: int -KEY_SCANCEL: int -KEY_SCOMMAND: int -KEY_SCOPY: int -KEY_SCREATE: int -KEY_SDC: int -KEY_SDL: int -KEY_SELECT: int -KEY_SEND: int -KEY_SEOL: int -KEY_SEXIT: int -KEY_SF: int -KEY_SFIND: int -KEY_SHELP: int -KEY_SHOME: int -KEY_SIC: int -KEY_SLEFT: int -KEY_SMESSAGE: int -KEY_SMOVE: int -KEY_SNEXT: int -KEY_SOPTIONS: int -KEY_SPREVIOUS: int -KEY_SPRINT: int -KEY_SR: int -KEY_SREDO: int -KEY_SREPLACE: int -KEY_SRESET: int -KEY_SRIGHT: int -KEY_SRSUME: int -KEY_SSAVE: int -KEY_SSUSPEND: int -KEY_STAB: int -KEY_SUNDO: int -KEY_SUSPEND: int -KEY_UNDO: int -KEY_UP: int -OK: int -REPORT_MOUSE_POSITION: int -_C_API: Any -version: bytes - -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]: ... - -# Changed in Python 3.8.8 and 3.9.2 -if sys.version_info >= (3, 8): - def color_pair(pair_number: int) -> int: ... - -else: - def color_pair(__color_number: int) -> int: ... - -def curs_set(__visibility: int) -> int: ... -def def_prog_mode() -> None: ... -def def_shell_mode() -> None: ... -def delay_output(__ms: int) -> None: ... -def doupdate() -> None: ... -def echo(__flag: bool = ...) -> None: ... -def endwin() -> None: ... -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: ... -def halfdelay(__tenths: int) -> None: ... -def has_colors() -> bool: ... - -if sys.version_info >= (3, 10): - def has_extended_color_support() -> bool: ... - -def has_ic() -> bool: ... -def has_il() -> bool: ... -def has_key(__key: int) -> bool: ... -def init_color(__color_number: int, __r: int, __g: int, __b: int) -> None: ... -def init_pair(__pair_number: int, __fg: int, __bg: int) -> None: ... -def initscr() -> _CursesWindow: ... -def intrflush(__flag: bool) -> None: ... -def is_term_resized(__nlines: int, __ncols: int) -> bool: ... -def isendwin() -> bool: ... -def keyname(__key: int) -> bytes: ... -def killchar() -> bytes: ... -def longname() -> bytes: ... -def meta(__yes: bool) -> None: ... -def mouseinterval(__interval: int) -> None: ... -def mousemask(__newmask: int) -> tuple[int, int]: ... -def napms(__ms: int) -> int: ... -def newpad(__nlines: int, __ncols: int) -> _CursesWindow: ... -def newwin(__nlines: int, __ncols: int, __begin_y: int = ..., __begin_x: int = ...) -> _CursesWindow: ... -def nl(__flag: bool = ...) -> None: ... -def nocbreak() -> None: ... -def noecho() -> None: ... -def nonl() -> None: ... -def noqiflush() -> None: ... -def noraw() -> None: ... -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: ... -def raw(__flag: bool = ...) -> None: ... -def reset_prog_mode() -> None: ... -def reset_shell_mode() -> None: ... -def resetty() -> None: ... -def resize_term(__nlines: int, __ncols: int) -> None: ... -def resizeterm(__nlines: int, __ncols: int) -> None: ... -def savetty() -> None: ... -def setsyx(__y: int, __x: int) -> None: ... -def setupterm(term: str | None = ..., fd: int = ...) -> None: ... -def start_color() -> None: ... -def termattrs() -> int: ... -def termname() -> bytes: ... -def tigetflag(__capname: str) -> int: ... -def tigetnum(__capname: str) -> int: ... -def tigetstr(__capname: str) -> bytes: ... -def tparm( - __str: bytes, - __i1: int = ..., - __i2: int = ..., - __i3: int = ..., - __i4: int = ..., - __i5: int = ..., - __i6: int = ..., - __i7: int = ..., - __i8: int = ..., - __i9: int = ..., -) -> bytes: ... -def typeahead(__fd: int) -> None: ... -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 use_default_colors() -> None: ... -def use_env(__flag: bool) -> None: ... - -class error(Exception): ... - -class _CursesWindow: - encoding: str - @overload - def addch(self, ch: _chtype, attr: int = ...) -> None: ... - @overload - def addch(self, y: int, x: int, ch: _chtype, attr: int = ...) -> None: ... - @overload - def addnstr(self, str: str, n: int, attr: int = ...) -> None: ... - @overload - def addnstr(self, y: int, x: int, str: str, n: int, attr: int = ...) -> None: ... - @overload - def addstr(self, str: str, attr: int = ...) -> None: ... - @overload - def addstr(self, y: int, x: int, str: str, attr: int = ...) -> None: ... - def attroff(self, __attr: int) -> None: ... - def attron(self, __attr: int) -> None: ... - def attrset(self, __attr: int) -> None: ... - def bkgd(self, __ch: _chtype, __attr: int = ...) -> None: ... - def bkgdset(self, __ch: _chtype, __attr: int = ...) -> None: ... - def border( - self, - ls: _chtype = ..., - rs: _chtype = ..., - ts: _chtype = ..., - bs: _chtype = ..., - tl: _chtype = ..., - tr: _chtype = ..., - bl: _chtype = ..., - br: _chtype = ..., - ) -> None: ... - @overload - def box(self) -> None: ... - @overload - def box(self, vertch: _chtype = ..., horch: _chtype = ...) -> None: ... - @overload - def chgat(self, attr: int) -> None: ... - @overload - def chgat(self, num: int, attr: int) -> None: ... - @overload - def chgat(self, y: int, x: int, attr: int) -> None: ... - @overload - def chgat(self, y: int, x: int, num: int, attr: int) -> None: ... - def clear(self) -> None: ... - def clearok(self, yes: int) -> None: ... - def clrtobot(self) -> None: ... - def clrtoeol(self) -> None: ... - def cursyncup(self) -> None: ... - @overload - def delch(self) -> None: ... - @overload - def delch(self, y: int, x: int) -> None: ... - def deleteln(self) -> None: ... - @overload - def derwin(self, begin_y: int, begin_x: int) -> _CursesWindow: ... - @overload - def derwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _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]: ... - @overload - def getch(self) -> int: ... - @overload - def getch(self, y: int, x: int) -> int: ... - @overload - def get_wch(self) -> int | str: ... - @overload - def get_wch(self, y: int, x: int) -> int | str: ... - @overload - 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]: ... - @overload - def getstr(self) -> _chtype: ... - @overload - def getstr(self, n: int) -> _chtype: ... - @overload - def getstr(self, y: int, x: int) -> _chtype: ... - @overload - def getstr(self, y: int, x: int, n: int) -> _chtype: ... - def getyx(self) -> tuple[int, int]: ... - @overload - def hline(self, ch: _chtype, n: int) -> None: ... - @overload - def hline(self, y: int, x: int, ch: _chtype, n: int) -> None: ... - def idcok(self, flag: bool) -> None: ... - def idlok(self, yes: bool) -> None: ... - def immedok(self, flag: bool) -> None: ... - @overload - def inch(self) -> _chtype: ... - @overload - def inch(self, y: int, x: int) -> _chtype: ... - @overload - def insch(self, ch: _chtype, attr: int = ...) -> None: ... - @overload - def insch(self, y: int, x: int, ch: _chtype, attr: int = ...) -> None: ... - def insdelln(self, nlines: int) -> None: ... - def insertln(self) -> None: ... - @overload - def insnstr(self, str: str, n: int, attr: int = ...) -> None: ... - @overload - def insnstr(self, y: int, x: int, str: str, n: int, attr: int = ...) -> None: ... - @overload - def insstr(self, str: str, attr: int = ...) -> None: ... - @overload - def insstr(self, y: int, x: int, str: str, attr: int = ...) -> None: ... - @overload - def instr(self, n: int = ...) -> _chtype: ... - @overload - def instr(self, y: int, x: int, n: int = ...) -> _chtype: ... - def is_linetouched(self, __line: int) -> bool: ... - def is_wintouched(self) -> bool: ... - def keypad(self, yes: bool) -> None: ... - def leaveok(self, yes: bool) -> None: ... - def move(self, new_y: int, new_x: int) -> None: ... - def mvderwin(self, y: int, x: int) -> None: ... - def mvwin(self, new_y: int, new_x: int) -> None: ... - def nodelay(self, yes: bool) -> None: ... - def notimeout(self, yes: bool) -> None: ... - @overload - def noutrefresh(self) -> None: ... - @overload - def noutrefresh(self, pminrow: int, pmincol: int, sminrow: int, smincol: int, smaxrow: int, smaxcol: int) -> None: ... - @overload - def overlay(self, destwin: _CursesWindow) -> None: ... - @overload - def overlay( - self, destwin: _CursesWindow, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int - ) -> None: ... - @overload - def overwrite(self, destwin: _CursesWindow) -> None: ... - @overload - def overwrite( - self, destwin: _CursesWindow, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int - ) -> None: ... - def putwin(self, __file: IO[Any]) -> None: ... - def redrawln(self, __beg: int, __num: int) -> None: ... - def redrawwin(self) -> None: ... - @overload - def refresh(self) -> None: ... - @overload - def refresh(self, pminrow: int, pmincol: int, sminrow: int, smincol: int, smaxrow: int, smaxcol: int) -> None: ... - def resize(self, nlines: int, ncols: int) -> None: ... - def scroll(self, lines: int = ...) -> None: ... - def scrollok(self, flag: bool) -> None: ... - def setscrreg(self, __top: int, __bottom: int) -> None: ... - def standend(self) -> None: ... - def standout(self) -> None: ... - @overload - def subpad(self, begin_y: int, begin_x: int) -> _CursesWindow: ... - @overload - def subpad(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ... - @overload - def subwin(self, begin_y: int, begin_x: int) -> _CursesWindow: ... - @overload - def subwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ... - def syncdown(self) -> None: ... - def syncok(self, flag: bool) -> None: ... - def syncup(self) -> None: ... - def timeout(self, delay: int) -> None: ... - def touchline(self, start: int, count: int, changed: bool = ...) -> None: ... - def touchwin(self) -> None: ... - def untouchwin(self) -> None: ... - @overload - def vline(self, ch: _chtype, n: int) -> None: ... - @overload - def vline(self, y: int, x: int, ch: _chtype, n: int) -> None: ... - -if sys.version_info >= (3, 8): - class _ncurses_version(NamedTuple): - major: int - minor: int - patch: int - ncurses_version: _ncurses_version - window = _CursesWindow # undocumented + # ACS codes are only initialized after initscr is called + ACS_BBSS: int + ACS_BLOCK: int + ACS_BOARD: int + ACS_BSBS: int + ACS_BSSB: int + ACS_BSSS: int + ACS_BTEE: int + ACS_BULLET: int + ACS_CKBOARD: int + ACS_DARROW: int + ACS_DEGREE: int + ACS_DIAMOND: int + ACS_GEQUAL: int + ACS_HLINE: int + ACS_LANTERN: int + ACS_LARROW: int + ACS_LEQUAL: int + ACS_LLCORNER: int + ACS_LRCORNER: int + ACS_LTEE: int + ACS_NEQUAL: int + ACS_PI: int + ACS_PLMINUS: int + ACS_PLUS: int + ACS_RARROW: int + ACS_RTEE: int + ACS_S1: int + ACS_S3: int + ACS_S7: int + ACS_S9: int + ACS_SBBS: int + ACS_SBSB: int + ACS_SBSS: int + ACS_SSBB: int + ACS_SSBS: int + ACS_SSSB: int + ACS_SSSS: int + ACS_STERLING: int + ACS_TTEE: int + ACS_UARROW: int + ACS_ULCORNER: int + ACS_URCORNER: int + ACS_VLINE: int + ALL_MOUSE_EVENTS: int + A_ALTCHARSET: int + A_ATTRIBUTES: int + A_BLINK: int + A_BOLD: int + A_CHARTEXT: int + A_COLOR: int + A_DIM: int + A_HORIZONTAL: int + A_INVIS: int + if sys.version_info >= (3, 7): + A_ITALIC: int + A_LEFT: int + A_LOW: int + A_NORMAL: int + A_PROTECT: int + A_REVERSE: int + A_RIGHT: int + A_STANDOUT: int + A_TOP: int + A_UNDERLINE: int + A_VERTICAL: int + BUTTON1_CLICKED: int + BUTTON1_DOUBLE_CLICKED: int + BUTTON1_PRESSED: int + BUTTON1_RELEASED: int + BUTTON1_TRIPLE_CLICKED: int + BUTTON2_CLICKED: int + BUTTON2_DOUBLE_CLICKED: int + BUTTON2_PRESSED: int + BUTTON2_RELEASED: int + BUTTON2_TRIPLE_CLICKED: int + BUTTON3_CLICKED: int + BUTTON3_DOUBLE_CLICKED: int + BUTTON3_PRESSED: int + BUTTON3_RELEASED: int + BUTTON3_TRIPLE_CLICKED: int + BUTTON4_CLICKED: int + BUTTON4_DOUBLE_CLICKED: int + BUTTON4_PRESSED: int + BUTTON4_RELEASED: int + BUTTON4_TRIPLE_CLICKED: int + # Darwin ncurses doesn't provide BUTTON5_* constants + if sys.version_info >= (3, 10) and sys.platform != "darwin": + BUTTON5_PRESSED: int + BUTTON5_RELEASED: int + BUTTON5_CLICKED: int + BUTTON5_DOUBLE_CLICKED: int + BUTTON5_TRIPLE_CLICKED: int + BUTTON_ALT: int + BUTTON_CTRL: int + BUTTON_SHIFT: int + COLOR_BLACK: int + COLOR_BLUE: int + COLOR_CYAN: int + COLOR_GREEN: int + COLOR_MAGENTA: int + COLOR_RED: int + COLOR_WHITE: int + COLOR_YELLOW: int + ERR: int + KEY_A1: int + KEY_A3: int + KEY_B2: int + KEY_BACKSPACE: int + KEY_BEG: int + KEY_BREAK: int + KEY_BTAB: int + KEY_C1: int + KEY_C3: int + KEY_CANCEL: int + KEY_CATAB: int + KEY_CLEAR: int + KEY_CLOSE: int + KEY_COMMAND: int + KEY_COPY: int + KEY_CREATE: int + KEY_CTAB: int + KEY_DC: int + KEY_DL: int + KEY_DOWN: int + KEY_EIC: int + KEY_END: int + KEY_ENTER: int + KEY_EOL: int + KEY_EOS: int + KEY_EXIT: int + KEY_F0: int + KEY_F1: int + KEY_F10: int + KEY_F11: int + KEY_F12: int + KEY_F13: int + KEY_F14: int + KEY_F15: int + KEY_F16: int + KEY_F17: int + KEY_F18: int + KEY_F19: int + KEY_F2: int + KEY_F20: int + KEY_F21: int + KEY_F22: int + KEY_F23: int + KEY_F24: int + KEY_F25: int + KEY_F26: int + KEY_F27: int + KEY_F28: int + KEY_F29: int + KEY_F3: int + KEY_F30: int + KEY_F31: int + KEY_F32: int + KEY_F33: int + KEY_F34: int + KEY_F35: int + KEY_F36: int + KEY_F37: int + KEY_F38: int + KEY_F39: int + KEY_F4: int + KEY_F40: int + KEY_F41: int + KEY_F42: int + KEY_F43: int + KEY_F44: int + KEY_F45: int + KEY_F46: int + KEY_F47: int + KEY_F48: int + KEY_F49: int + KEY_F5: int + KEY_F50: int + KEY_F51: int + KEY_F52: int + KEY_F53: int + KEY_F54: int + KEY_F55: int + KEY_F56: int + KEY_F57: int + KEY_F58: int + KEY_F59: int + KEY_F6: int + KEY_F60: int + KEY_F61: int + KEY_F62: int + KEY_F63: int + KEY_F7: int + KEY_F8: int + KEY_F9: int + KEY_FIND: int + KEY_HELP: int + KEY_HOME: int + KEY_IC: int + KEY_IL: int + KEY_LEFT: int + KEY_LL: int + KEY_MARK: int + KEY_MAX: int + KEY_MESSAGE: int + KEY_MIN: int + KEY_MOUSE: int + KEY_MOVE: int + KEY_NEXT: int + KEY_NPAGE: int + KEY_OPEN: int + KEY_OPTIONS: int + KEY_PPAGE: int + KEY_PREVIOUS: int + KEY_PRINT: int + KEY_REDO: int + KEY_REFERENCE: int + KEY_REFRESH: int + KEY_REPLACE: int + KEY_RESET: int + KEY_RESIZE: int + KEY_RESTART: int + KEY_RESUME: int + KEY_RIGHT: int + KEY_SAVE: int + KEY_SBEG: int + KEY_SCANCEL: int + KEY_SCOMMAND: int + KEY_SCOPY: int + KEY_SCREATE: int + KEY_SDC: int + KEY_SDL: int + KEY_SELECT: int + KEY_SEND: int + KEY_SEOL: int + KEY_SEXIT: int + KEY_SF: int + KEY_SFIND: int + KEY_SHELP: int + KEY_SHOME: int + KEY_SIC: int + KEY_SLEFT: int + KEY_SMESSAGE: int + KEY_SMOVE: int + KEY_SNEXT: int + KEY_SOPTIONS: int + KEY_SPREVIOUS: int + KEY_SPRINT: int + KEY_SR: int + KEY_SREDO: int + KEY_SREPLACE: int + KEY_SRESET: int + KEY_SRIGHT: int + KEY_SRSUME: int + KEY_SSAVE: int + KEY_SSUSPEND: int + KEY_STAB: int + KEY_SUNDO: int + KEY_SUSPEND: int + KEY_UNDO: int + KEY_UP: int + OK: int + REPORT_MOUSE_POSITION: int + _C_API: Any + version: bytes + 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]: ... + # Changed in Python 3.8.8 and 3.9.2 + if sys.version_info >= (3, 8): + def color_pair(pair_number: int) -> int: ... + else: + def color_pair(__color_number: int) -> int: ... + def curs_set(__visibility: int) -> int: ... + def def_prog_mode() -> None: ... + def def_shell_mode() -> None: ... + def delay_output(__ms: int) -> None: ... + def doupdate() -> None: ... + def echo(__flag: bool = ...) -> None: ... + def endwin() -> None: ... + def erasechar() -> bytes: ... + def filter() -> None: ... + def flash() -> None: ... + def flushinp() -> None: ... + 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: ... + if sys.version_info >= (3, 10): + def has_extended_color_support() -> bool: ... + def has_ic() -> bool: ... + def has_il() -> bool: ... + def has_key(__key: int) -> bool: ... + def init_color(__color_number: int, __r: int, __g: int, __b: int) -> None: ... + def init_pair(__pair_number: int, __fg: int, __bg: int) -> None: ... + def initscr() -> _CursesWindow: ... + def intrflush(__flag: bool) -> None: ... + def is_term_resized(__nlines: int, __ncols: int) -> bool: ... + def isendwin() -> bool: ... + def keyname(__key: int) -> bytes: ... + def killchar() -> bytes: ... + def longname() -> bytes: ... + def meta(__yes: bool) -> None: ... + def mouseinterval(__interval: int) -> None: ... + def mousemask(__newmask: int) -> tuple[int, int]: ... + def napms(__ms: int) -> int: ... + def newpad(__nlines: int, __ncols: int) -> _CursesWindow: ... + def newwin(__nlines: int, __ncols: int, __begin_y: int = ..., __begin_x: int = ...) -> _CursesWindow: ... + def nl(__flag: bool = ...) -> None: ... + def nocbreak() -> None: ... + def noecho() -> None: ... + def nonl() -> None: ... + def noqiflush() -> None: ... + def noraw() -> None: ... + 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: ... + def raw(__flag: bool = ...) -> None: ... + def reset_prog_mode() -> None: ... + def reset_shell_mode() -> None: ... + 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: ... + def termattrs() -> int: ... + def termname() -> bytes: ... + def tigetflag(__capname: str) -> int: ... + def tigetnum(__capname: str) -> int: ... + def tigetstr(__capname: str) -> bytes | None: ... + def tparm( + __str: bytes, + __i1: int = ..., + __i2: int = ..., + __i3: int = ..., + __i4: int = ..., + __i5: int = ..., + __i6: int = ..., + __i7: int = ..., + __i8: int = ..., + __i9: int = ..., + ) -> bytes: ... + def typeahead(__fd: int) -> None: ... + 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() -> None: ... + def use_default_colors() -> None: ... + def use_env(__flag: bool) -> None: ... + class error(Exception): ... + class _CursesWindow: + encoding: str + @overload + def addch(self, ch: _chtype, attr: int = ...) -> None: ... + @overload + def addch(self, y: int, x: int, ch: _chtype, attr: int = ...) -> None: ... + @overload + def addnstr(self, str: str, n: int, attr: int = ...) -> None: ... + @overload + def addnstr(self, y: int, x: int, str: str, n: int, attr: int = ...) -> None: ... + @overload + def addstr(self, str: str, attr: int = ...) -> None: ... + @overload + def addstr(self, y: int, x: int, str: str, attr: int = ...) -> None: ... + def attroff(self, __attr: int) -> None: ... + def attron(self, __attr: int) -> None: ... + def attrset(self, __attr: int) -> None: ... + def bkgd(self, __ch: _chtype, __attr: int = ...) -> None: ... + def bkgdset(self, __ch: _chtype, __attr: int = ...) -> None: ... + def border( + self, + ls: _chtype = ..., + rs: _chtype = ..., + ts: _chtype = ..., + bs: _chtype = ..., + tl: _chtype = ..., + tr: _chtype = ..., + bl: _chtype = ..., + br: _chtype = ..., + ) -> None: ... + @overload + def box(self) -> None: ... + @overload + def box(self, vertch: _chtype = ..., horch: _chtype = ...) -> None: ... + @overload + def chgat(self, attr: int) -> None: ... + @overload + def chgat(self, num: int, attr: int) -> None: ... + @overload + def chgat(self, y: int, x: int, attr: int) -> None: ... + @overload + def chgat(self, y: int, x: int, num: int, attr: int) -> None: ... + def clear(self) -> None: ... + def clearok(self, yes: int) -> None: ... + def clrtobot(self) -> None: ... + def clrtoeol(self) -> None: ... + def cursyncup(self) -> None: ... + @overload + def delch(self) -> None: ... + @overload + def delch(self, y: int, x: int) -> None: ... + def deleteln(self) -> None: ... + @overload + def derwin(self, begin_y: int, begin_x: int) -> _CursesWindow: ... + @overload + def derwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _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]: ... + @overload + def getch(self) -> int: ... + @overload + def getch(self, y: int, x: int) -> int: ... + @overload + def get_wch(self) -> int | str: ... + @overload + def get_wch(self, y: int, x: int) -> int | str: ... + @overload + 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]: ... + @overload + def getstr(self) -> bytes: ... + @overload + def getstr(self, n: int) -> bytes: ... + @overload + def getstr(self, y: int, x: int) -> bytes: ... + @overload + 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 + def hline(self, y: int, x: int, ch: _chtype, n: int) -> None: ... + def idcok(self, flag: bool) -> None: ... + def idlok(self, yes: bool) -> None: ... + def immedok(self, flag: bool) -> None: ... + @overload + def inch(self) -> int: ... + @overload + def inch(self, y: int, x: int) -> int: ... + @overload + def insch(self, ch: _chtype, attr: int = ...) -> None: ... + @overload + def insch(self, y: int, x: int, ch: _chtype, attr: int = ...) -> None: ... + def insdelln(self, nlines: int) -> None: ... + def insertln(self) -> None: ... + @overload + def insnstr(self, str: str, n: int, attr: int = ...) -> None: ... + @overload + def insnstr(self, y: int, x: int, str: str, n: int, attr: int = ...) -> None: ... + @overload + def insstr(self, str: str, attr: int = ...) -> None: ... + @overload + def insstr(self, y: int, x: int, str: str, attr: int = ...) -> None: ... + @overload + def instr(self, n: int = ...) -> bytes: ... + @overload + 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: ... + def leaveok(self, yes: bool) -> None: ... + def move(self, new_y: int, new_x: int) -> None: ... + def mvderwin(self, y: int, x: int) -> None: ... + def mvwin(self, new_y: int, new_x: int) -> None: ... + def nodelay(self, yes: bool) -> None: ... + def notimeout(self, yes: bool) -> None: ... + @overload + def noutrefresh(self) -> None: ... + @overload + def noutrefresh(self, pminrow: int, pmincol: int, sminrow: int, smincol: int, smaxrow: int, smaxcol: int) -> None: ... + @overload + def overlay(self, destwin: _CursesWindow) -> None: ... + @overload + def overlay( + self, destwin: _CursesWindow, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int + ) -> None: ... + @overload + def overwrite(self, destwin: _CursesWindow) -> None: ... + @overload + def overwrite( + self, destwin: _CursesWindow, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int + ) -> None: ... + def putwin(self, __file: IO[Any]) -> None: ... + def redrawln(self, __beg: int, __num: int) -> None: ... + def redrawwin(self) -> None: ... + @overload + def refresh(self) -> None: ... + @overload + def refresh(self, pminrow: int, pmincol: int, sminrow: int, smincol: int, smaxrow: int, smaxcol: int) -> None: ... + def resize(self, nlines: int, ncols: int) -> None: ... + def scroll(self, lines: int = ...) -> None: ... + def scrollok(self, flag: bool) -> None: ... + def setscrreg(self, __top: int, __bottom: int) -> None: ... + def standend(self) -> None: ... + def standout(self) -> None: ... + @overload + def subpad(self, begin_y: int, begin_x: int) -> _CursesWindow: ... + @overload + def subpad(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ... + @overload + def subwin(self, begin_y: int, begin_x: int) -> _CursesWindow: ... + @overload + def subwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ... + def syncdown(self) -> None: ... + def syncok(self, flag: bool) -> None: ... + def syncup(self) -> None: ... + def timeout(self, delay: int) -> None: ... + def touchline(self, start: int, count: int, changed: bool = ...) -> None: ... + def touchwin(self) -> None: ... + def untouchwin(self) -> None: ... + @overload + def vline(self, ch: _chtype, n: int) -> None: ... + @overload + def vline(self, y: int, x: int, ch: _chtype, n: int) -> None: ... + if sys.version_info >= (3, 8): + class _ncurses_version(NamedTuple): + major: int + minor: int + patch: int + ncurses_version: _ncurses_version + window = _CursesWindow # undocumented diff --git a/mypy/typeshed/stdlib/_dummy_thread.pyi b/mypy/typeshed/stdlib/_dummy_thread.pyi index 886d9d739780..6e936726a48f 100644 --- a/mypy/typeshed/stdlib/_dummy_thread.pyi +++ b/mypy/typeshed/stdlib/_dummy_thread.pyi @@ -1,15 +1,15 @@ -from typing import Any, Callable, NoReturn, Tuple +from typing import Any, Callable, NoReturn TIMEOUT_MAX: int error = RuntimeError -def start_new_thread(function: Callable[..., Any], args: Tuple[Any, ...], kwargs: dict[str, Any] = ...) -> None: ... +def start_new_thread(function: Callable[..., Any], args: tuple[Any, ...], kwargs: dict[str, Any] = ...) -> None: ... def exit() -> NoReturn: ... def get_ident() -> int: ... def allocate_lock() -> LockType: ... def stack_size(size: int | None = ...) -> int: ... -class LockType(object): +class LockType: locked_status: bool def __init__(self) -> None: ... def acquire(self, waitflag: bool | None = ..., timeout: int = ...) -> bool: ... diff --git a/mypy/typeshed/stdlib/_dummy_threading.pyi b/mypy/typeshed/stdlib/_dummy_threading.pyi index 64998d86bf9f..075ea4637f73 100644 --- a/mypy/typeshed/stdlib/_dummy_threading.pyi +++ b/mypy/typeshed/stdlib/_dummy_threading.pyi @@ -28,7 +28,7 @@ TIMEOUT_MAX: float class ThreadError(Exception): ... -class local(object): +class local: def __getattribute__(self, name: str) -> Any: ... def __setattr__(self, name: str, value: Any) -> None: ... def __delattr__(self, name: str) -> None: ... diff --git a/mypy/typeshed/stdlib/_imp.pyi b/mypy/typeshed/stdlib/_imp.pyi index b61c9f29b96d..23272591df4c 100644 --- a/mypy/typeshed/stdlib/_imp.pyi +++ b/mypy/typeshed/stdlib/_imp.pyi @@ -1,7 +1,11 @@ +import sys import types from importlib.machinery import ModuleSpec from typing import Any +if sys.version_info >= (3, 7): + check_hash_based_pycs: str + def create_builtin(__spec: ModuleSpec) -> types.ModuleType: ... def create_dynamic(__spec: ModuleSpec, __file: Any = ...) -> None: ... def acquire_lock() -> None: ... diff --git a/mypy/typeshed/stdlib/_markupbase.pyi b/mypy/typeshed/stdlib/_markupbase.pyi index 368d32bd5b4c..2c497f65bb43 100644 --- a/mypy/typeshed/stdlib/_markupbase.pyi +++ b/mypy/typeshed/stdlib/_markupbase.pyi @@ -1,6 +1,17 @@ +import sys +from typing import Any + class ParserBase: def __init__(self) -> None: ... - def error(self, message: str) -> None: ... def reset(self) -> None: ... def getpos(self) -> tuple[int, int]: ... def unknown_decl(self, data: str) -> None: ... + def parse_comment(self, i: int, report: int = ...) -> int: ... # undocumented + def parse_declaration(self, i: int) -> int: ... # undocumented + def parse_marked_section(self, i: int, report: int = ...) -> int: ... # undocumented + def updatepos(self, i: int, j: int) -> int: ... # undocumented + if sys.version_info < (3, 10): + # Removed from ParserBase: https://bugs.python.org/issue31844 + def error(self, message: str) -> Any: ... # undocumented + lineno: int # undocumented + offset: int # undocumented diff --git a/mypy/typeshed/stdlib/_msi.pyi b/mypy/typeshed/stdlib/_msi.pyi index 754febe68da9..b7e852f38ae9 100644 --- a/mypy/typeshed/stdlib/_msi.pyi +++ b/mypy/typeshed/stdlib/_msi.pyi @@ -10,8 +10,8 @@ if sys.platform == "win32": def Modify(self, mode: int, record: _Record) -> None: ... def Close(self) -> None: ... # Don't exist at runtime - __new__: None # type: ignore - __init__: None # type: ignore + __new__: None # type: ignore[assignment] + __init__: None # type: ignore[assignment] # Actual typename Summary, not exposed by the implementation class _Summary: def GetProperty(self, propid: int) -> str | bytes | None: ... @@ -19,8 +19,8 @@ if sys.platform == "win32": def SetProperty(self, propid: int, value: str | bytes) -> None: ... def Persist(self) -> None: ... # Don't exist at runtime - __new__: None # type: ignore - __init__: None # type: ignore + __new__: None # type: ignore[assignment] + __init__: None # type: ignore[assignment] # Actual typename Database, not exposed by the implementation class _Database: def OpenView(self, sql: str) -> _View: ... @@ -28,8 +28,8 @@ if sys.platform == "win32": def GetSummaryInformation(self, updateCount: int) -> _Summary: ... def Close(self) -> None: ... # Don't exist at runtime - __new__: None # type: ignore - __init__: None # type: ignore + __new__: None # type: ignore[assignment] + __init__: None # type: ignore[assignment] # Actual typename Record, not exposed by the implementation class _Record: def GetFieldCount(self) -> int: ... @@ -40,8 +40,8 @@ if sys.platform == "win32": def SetInteger(self, field: int, int: int) -> None: ... def ClearData(self) -> None: ... # Don't exist at runtime - __new__: None # type: ignore - __init__: None # type: ignore + __new__: None # type: ignore[assignment] + __init__: None # type: ignore[assignment] def UuidCreate() -> str: ... def FCICreate(cabname: str, files: list[str]) -> None: ... def OpenDatabase(name: str, flags: int) -> _Database: ... diff --git a/mypy/typeshed/stdlib/_operator.pyi b/mypy/typeshed/stdlib/_operator.pyi index bea438861886..77a88d4fa141 100644 --- a/mypy/typeshed/stdlib/_operator.pyi +++ b/mypy/typeshed/stdlib/_operator.pyi @@ -1,60 +1,141 @@ -# In reality the import is the other way around, but this way we can keep the operator stub in 2and3 -from operator import ( - abs as abs, - add as add, - and_ as and_, - attrgetter as attrgetter, - concat as concat, - contains as contains, - countOf as countOf, - delitem as delitem, - eq as eq, - floordiv as floordiv, - ge as ge, - getitem as getitem, - gt as gt, - iadd as iadd, - iand as iand, - iconcat as iconcat, - ifloordiv as ifloordiv, - ilshift as ilshift, - imatmul as imatmul, - imod as imod, - imul as imul, - index as index, - indexOf as indexOf, - inv as inv, - invert as invert, - ior as ior, - ipow as ipow, - irshift as irshift, - is_ as is_, - is_not as is_not, - isub as isub, - itemgetter as itemgetter, - itruediv as itruediv, - ixor as ixor, - le as le, - length_hint as length_hint, - lshift as lshift, - lt as lt, - matmul as matmul, - methodcaller as methodcaller, - mod as mod, - mul as mul, - ne as ne, - neg as neg, - not_ as not_, - or_ as or_, - pos as pos, - pow as pow, - rshift as rshift, - setitem as setitem, - sub as sub, - truediv as truediv, - truth as truth, - xor as xor, +import sys +from _typeshed import SupportsAnyComparison +from typing import ( + Any, + AnyStr, + Callable, + Container, + Generic, + Iterable, + Mapping, + MutableMapping, + MutableSequence, + Protocol, + Sequence, + SupportsAbs, + TypeVar, + overload, ) -from typing import AnyStr +from typing_extensions import ParamSpec, SupportsIndex, final + +_R = TypeVar("_R") +_T = TypeVar("_T") +_T_co = TypeVar("_T_co", covariant=True) +_K = TypeVar("_K") +_V = TypeVar("_V") +_P = ParamSpec("_P") + +class _SupportsInversion(Protocol[_T_co]): + def __invert__(self) -> _T_co: ... + +class _SupportsNeg(Protocol[_T_co]): + def __neg__(self) -> _T_co: ... + +class _SupportsPos(Protocol[_T_co]): + def __pos__(self) -> _T_co: ... + +# All four comparison functions must have the same signature, or we get false-positive errors +def lt(__a: SupportsAnyComparison, __b: SupportsAnyComparison) -> Any: ... +def le(__a: SupportsAnyComparison, __b: SupportsAnyComparison) -> Any: ... +def eq(__a: object, __b: object) -> Any: ... +def ne(__a: object, __b: object) -> Any: ... +def ge(__a: SupportsAnyComparison, __b: SupportsAnyComparison) -> Any: ... +def gt(__a: SupportsAnyComparison, __b: SupportsAnyComparison) -> Any: ... +def not_(__a: object) -> bool: ... +def truth(__a: object) -> bool: ... +def is_(__a: object, __b: object) -> bool: ... +def is_not(__a: object, __b: object) -> bool: ... +def abs(__a: SupportsAbs[_T]) -> _T: ... +def add(__a: Any, __b: Any) -> Any: ... +def and_(__a: Any, __b: Any) -> Any: ... +def floordiv(__a: Any, __b: Any) -> Any: ... +def index(__a: SupportsIndex) -> int: ... +def inv(__a: _SupportsInversion[_T_co]) -> _T_co: ... +def invert(__a: _SupportsInversion[_T_co]) -> _T_co: ... +def lshift(__a: Any, __b: Any) -> Any: ... +def mod(__a: Any, __b: Any) -> Any: ... +def mul(__a: Any, __b: Any) -> Any: ... +def matmul(__a: Any, __b: Any) -> Any: ... +def neg(__a: _SupportsNeg[_T_co]) -> _T_co: ... +def or_(__a: Any, __b: Any) -> Any: ... +def pos(__a: _SupportsPos[_T_co]) -> _T_co: ... +def pow(__a: Any, __b: Any) -> Any: ... +def rshift(__a: Any, __b: Any) -> Any: ... +def sub(__a: Any, __b: Any) -> Any: ... +def truediv(__a: Any, __b: Any) -> Any: ... +def xor(__a: Any, __b: Any) -> Any: ... +def concat(__a: Sequence[_T], __b: Sequence[_T]) -> Sequence[_T]: ... +def contains(__a: Container[object], __b: object) -> bool: ... +def countOf(__a: Iterable[object], __b: object) -> int: ... +@overload +def delitem(__a: MutableSequence[Any], __b: SupportsIndex) -> None: ... +@overload +def delitem(__a: MutableSequence[Any], __b: slice) -> None: ... +@overload +def delitem(__a: MutableMapping[_K, Any], __b: _K) -> None: ... +@overload +def getitem(__a: Sequence[_T], __b: SupportsIndex) -> _T: ... +@overload +def getitem(__a: Sequence[_T], __b: slice) -> Sequence[_T]: ... +@overload +def getitem(__a: Mapping[_K, _V], __b: _K) -> _V: ... +def indexOf(__a: Iterable[_T], __b: _T) -> int: ... +@overload +def setitem(__a: MutableSequence[_T], __b: SupportsIndex, __c: _T) -> None: ... +@overload +def setitem(__a: MutableSequence[_T], __b: slice, __c: Sequence[_T]) -> None: ... +@overload +def setitem(__a: MutableMapping[_K, _V], __b: _K, __c: _V) -> None: ... +def length_hint(__obj: object, __default: int = ...) -> int: ... +@final +class attrgetter(Generic[_T_co]): + @overload + def __new__(cls, attr: str) -> attrgetter[Any]: ... + @overload + def __new__(cls, attr: str, __attr2: str) -> attrgetter[tuple[Any, Any]]: ... + @overload + def __new__(cls, attr: str, __attr2: str, __attr3: str) -> attrgetter[tuple[Any, Any, Any]]: ... + @overload + def __new__(cls, attr: str, __attr2: str, __attr3: str, __attr4: str) -> attrgetter[tuple[Any, Any, Any, Any]]: ... + @overload + def __new__(cls, attr: str, *attrs: str) -> attrgetter[tuple[Any, ...]]: ... + def __call__(self, obj: Any) -> _T_co: ... + +@final +class itemgetter(Generic[_T_co]): + @overload + def __new__(cls, item: Any) -> itemgetter[Any]: ... + @overload + 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]]: ... + @overload + 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: ... + +def iadd(__a: Any, __b: Any) -> Any: ... +def iand(__a: Any, __b: Any) -> Any: ... +def iconcat(__a: Any, __b: Any) -> Any: ... +def ifloordiv(__a: Any, __b: Any) -> Any: ... +def ilshift(__a: Any, __b: Any) -> Any: ... +def imod(__a: Any, __b: Any) -> Any: ... +def imul(__a: Any, __b: Any) -> Any: ... +def imatmul(__a: Any, __b: Any) -> Any: ... +def ior(__a: Any, __b: Any) -> Any: ... +def ipow(__a: Any, __b: Any) -> Any: ... +def irshift(__a: Any, __b: Any) -> Any: ... +def isub(__a: Any, __b: Any) -> Any: ... +def itruediv(__a: Any, __b: Any) -> Any: ... +def ixor(__a: Any, __b: Any) -> Any: ... + +if sys.version_info >= (3, 11): + def call(__obj: Callable[_P, _R], *args: _P.args, **kwargs: _P.kwargs) -> _R: ... def _compare_digest(__a: AnyStr, __b: AnyStr) -> bool: ... diff --git a/mypy/typeshed/stdlib/_osx_support.pyi b/mypy/typeshed/stdlib/_osx_support.pyi index ce1fffc00e8c..ffb25d5a2c0e 100644 --- a/mypy/typeshed/stdlib/_osx_support.pyi +++ b/mypy/typeshed/stdlib/_osx_support.pyi @@ -1,4 +1,5 @@ -from typing import Iterable, Sequence, Tuple, TypeVar +import sys +from typing import Iterable, Sequence, TypeVar _T = TypeVar("_T") _K = TypeVar("_K") @@ -6,12 +7,18 @@ _V = TypeVar("_V") __all__: list[str] -_UNIVERSAL_CONFIG_VARS: Tuple[str, ...] # undocumented -_COMPILER_CONFIG_VARS: Tuple[str, ...] # undocumented +_UNIVERSAL_CONFIG_VARS: tuple[str, ...] # undocumented +_COMPILER_CONFIG_VARS: tuple[str, ...] # undocumented _INITPRE: str # undocumented def _find_executable(executable: str, path: str | None = ...) -> str | None: ... # undocumented -def _read_output(commandstring: str) -> str | None: ... # undocumented + +if sys.version_info >= (3, 8): + def _read_output(commandstring: str, capture_stderr: bool = ...) -> str | None: ... # undocumented + +else: + def _read_output(commandstring: str) -> str | None: ... # undocumented + def _find_build_tool(toolname: str) -> str: ... # undocumented _SYSTEM_VERSION: str | None # undocumented diff --git a/mypy/typeshed/stdlib/_posixsubprocess.pyi b/mypy/typeshed/stdlib/_posixsubprocess.pyi index 0eae723e7a67..5481100cacfc 100644 --- a/mypy/typeshed/stdlib/_posixsubprocess.pyi +++ b/mypy/typeshed/stdlib/_posixsubprocess.pyi @@ -1,24 +1,24 @@ -# NOTE: These are incomplete! - +import sys from typing import Callable, Sequence -def cloexec_pipe() -> tuple[int, int]: ... -def fork_exec( - args: Sequence[str], - executable_list: Sequence[bytes], - close_fds: bool, - fds_to_keep: Sequence[int], - cwd: str, - env_list: Sequence[bytes], - p2cread: int, - p2cwrite: int, - c2pred: int, - c2pwrite: int, - errread: int, - errwrite: int, - errpipe_read: int, - errpipe_write: int, - restore_signals: int, - start_new_session: int, - preexec_fn: Callable[[], None], -) -> int: ... +if sys.platform != "win32": + def cloexec_pipe() -> tuple[int, int]: ... + def fork_exec( + args: Sequence[str], + executable_list: Sequence[bytes], + close_fds: bool, + fds_to_keep: Sequence[int], + cwd: str, + env_list: Sequence[bytes], + p2cread: int, + p2cwrite: int, + c2pred: int, + c2pwrite: int, + errread: int, + errwrite: int, + errpipe_read: int, + errpipe_write: int, + restore_signals: int, + start_new_session: int, + preexec_fn: Callable[[], None], + ) -> int: ... diff --git a/mypy/typeshed/stdlib/_py_abc.pyi b/mypy/typeshed/stdlib/_py_abc.pyi index 8d7938918271..697a7f17111a 100644 --- a/mypy/typeshed/stdlib/_py_abc.pyi +++ b/mypy/typeshed/stdlib/_py_abc.pyi @@ -1,4 +1,4 @@ -from typing import Any, Tuple, Type, TypeVar +from typing import Any, Type, TypeVar _T = TypeVar("_T") @@ -6,5 +6,5 @@ _T = TypeVar("_T") def get_cache_token() -> object: ... class ABCMeta(type): - def __new__(__mcls, __name: str, __bases: Tuple[Type[Any], ...], __namespace: dict[str, Any]) -> ABCMeta: ... + def __new__(__mcls, __name: str, __bases: tuple[Type[Any], ...], __namespace: dict[str, Any]) -> ABCMeta: ... def register(cls, subclass: Type[_T]) -> Type[_T]: ... diff --git a/mypy/typeshed/stdlib/_random.pyi b/mypy/typeshed/stdlib/_random.pyi index fa80c6d98144..9aff4b3cb026 100644 --- a/mypy/typeshed/stdlib/_random.pyi +++ b/mypy/typeshed/stdlib/_random.pyi @@ -1,9 +1,7 @@ -from typing import Tuple - # Actually Tuple[(int,) * 625] -_State = Tuple[int, ...] +_State = tuple[int, ...] -class Random(object): +class Random: def __init__(self, seed: object = ...) -> None: ... def seed(self, __n: object = ...) -> None: ... def getstate(self) -> _State: ... diff --git a/mypy/typeshed/stdlib/_socket.pyi b/mypy/typeshed/stdlib/_socket.pyi index 846f64d5a433..d7d7f73ea37d 100644 --- a/mypy/typeshed/stdlib/_socket.pyi +++ b/mypy/typeshed/stdlib/_socket.pyi @@ -1,7 +1,7 @@ import sys from _typeshed import ReadableBuffer, WriteableBuffer from collections.abc import Iterable -from typing import Any, SupportsInt, Tuple, Union, overload +from typing import Any, SupportsInt, Union, overload if sys.version_info >= (3, 8): from typing import SupportsIndex @@ -10,12 +10,12 @@ if sys.version_info >= (3, 8): else: _FD = SupportsInt -_CMSG = Tuple[int, int, bytes] -_CMSGArg = Tuple[int, int, ReadableBuffer] +_CMSG = tuple[int, int, bytes] +_CMSGArg = tuple[int, int, ReadableBuffer] # Addresses can be either tuples of varying lengths (AF_INET, AF_INET6, # AF_NETLINK, AF_TIPC) or strings (AF_UNIX). -_Address = Union[Tuple[Any, ...], str] +_Address = Union[tuple[Any, ...], str] _RetAddress = Any # TODO Most methods allow bytes as address objects @@ -527,6 +527,8 @@ class socket: family: int type: int proto: int + @property + def timeout(self) -> float | None: ... def __init__(self, family: int = ..., type: int = ..., proto: int = ..., fileno: _FD | None = ...) -> None: ... def bind(self, __address: _Address | bytes) -> None: ... def close(self) -> None: ... diff --git a/mypy/typeshed/stdlib/_stat.pyi b/mypy/typeshed/stdlib/_stat.pyi index 634f7da02563..83d832e4dd8e 100644 --- a/mypy/typeshed/stdlib/_stat.pyi +++ b/mypy/typeshed/stdlib/_stat.pyi @@ -1,54 +1,68 @@ -SF_APPEND: int -SF_ARCHIVED: int -SF_IMMUTABLE: int -SF_NOUNLINK: int -SF_SNAPSHOT: int -ST_ATIME: int -ST_CTIME: int -ST_DEV: int -ST_GID: int -ST_INO: int -ST_MODE: int -ST_MTIME: int -ST_NLINK: int -ST_SIZE: int -ST_UID: int -S_ENFMT: int -S_IEXEC: int -S_IFBLK: int -S_IFCHR: int -S_IFDIR: int +import sys +from typing_extensions import Literal + +SF_APPEND: Literal[0x00040000] +SF_ARCHIVED: Literal[0x00010000] +SF_IMMUTABLE: Literal[0x00020000] +SF_NOUNLINK: Literal[0x00100000] +SF_SNAPSHOT: Literal[0x00200000] + +ST_MODE: Literal[0] +ST_INO: Literal[1] +ST_DEV: Literal[2] +ST_NLINK: Literal[3] +ST_UID: Literal[4] +ST_GID: Literal[5] +ST_SIZE: Literal[6] +ST_ATIME: Literal[7] +ST_MTIME: Literal[8] +ST_CTIME: Literal[9] + +S_IFIFO: Literal[0o010000] +S_IFLNK: Literal[0o120000] +S_IFREG: Literal[0o100000] +S_IFSOCK: Literal[0o140000] +S_IFBLK: Literal[0o060000] +S_IFCHR: Literal[0o020000] +S_IFDIR: Literal[0o040000] + +# These are 0 on systems that don't support the specific kind of file. +# Example: Linux doesn't support door files, so S_IFDOOR is 0 on linux. S_IFDOOR: int -S_IFIFO: int -S_IFLNK: int S_IFPORT: int -S_IFREG: int -S_IFSOCK: int S_IFWHT: int -S_IREAD: int -S_IRGRP: int -S_IROTH: int -S_IRUSR: int -S_IRWXG: int -S_IRWXO: int -S_IRWXU: int -S_ISGID: int -S_ISUID: int -S_ISVTX: int -S_IWGRP: int -S_IWOTH: int -S_IWRITE: int -S_IWUSR: int -S_IXGRP: int -S_IXOTH: int -S_IXUSR: int -UF_APPEND: int -UF_COMPRESSED: int -UF_HIDDEN: int -UF_IMMUTABLE: int -UF_NODUMP: int -UF_NOUNLINK: int -UF_OPAQUE: int + +S_ISUID: Literal[0o4000] +S_ISGID: Literal[0o2000] +S_ISVTX: Literal[0o1000] + +S_IRWXU: Literal[0o0700] +S_IRUSR: Literal[0o0400] +S_IWUSR: Literal[0o0200] +S_IXUSR: Literal[0o0100] + +S_IRWXG: Literal[0o0070] +S_IRGRP: Literal[0o0040] +S_IWGRP: Literal[0o0020] +S_IXGRP: Literal[0o0010] + +S_IRWXO: Literal[0o0007] +S_IROTH: Literal[0o0004] +S_IWOTH: Literal[0o0002] +S_IXOTH: Literal[0o0001] + +S_ENFMT: Literal[0o2000] +S_IREAD: Literal[0o0400] +S_IWRITE: Literal[0o0200] +S_IEXEC: Literal[0o0100] + +UF_APPEND: Literal[0x00000004] +UF_COMPRESSED: Literal[0x00000020] # OS X 10.6+ only +UF_HIDDEN: Literal[0x00008000] # OX X 10.5+ only +UF_IMMUTABLE: Literal[0x00000002] +UF_NODUMP: Literal[0x00000001] +UF_NOUNLINK: Literal[0x00000010] +UF_OPAQUE: Literal[0x00000008] def S_IMODE(mode: int) -> int: ... def S_IFMT(mode: int) -> int: ... @@ -63,3 +77,27 @@ def S_ISREG(mode: int) -> bool: ... def S_ISSOCK(mode: int) -> bool: ... def S_ISWHT(mode: int) -> bool: ... def filemode(mode: int) -> str: ... + +if sys.platform == "win32" and sys.version_info >= (3, 8): + IO_REPARSE_TAG_SYMLINK: int + IO_REPARSE_TAG_MOUNT_POINT: int + IO_REPARSE_TAG_APPEXECLINK: int + +if sys.platform == "win32": + FILE_ATTRIBUTE_ARCHIVE: Literal[32] + FILE_ATTRIBUTE_COMPRESSED: Literal[2048] + FILE_ATTRIBUTE_DEVICE: Literal[64] + FILE_ATTRIBUTE_DIRECTORY: Literal[16] + FILE_ATTRIBUTE_ENCRYPTED: Literal[16384] + FILE_ATTRIBUTE_HIDDEN: Literal[2] + FILE_ATTRIBUTE_INTEGRITY_STREAM: Literal[32768] + FILE_ATTRIBUTE_NORMAL: Literal[128] + FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: Literal[8192] + FILE_ATTRIBUTE_NO_SCRUB_DATA: Literal[131072] + FILE_ATTRIBUTE_OFFLINE: Literal[4096] + FILE_ATTRIBUTE_READONLY: Literal[1] + FILE_ATTRIBUTE_REPARSE_POINT: Literal[1024] + FILE_ATTRIBUTE_SPARSE_FILE: Literal[512] + FILE_ATTRIBUTE_SYSTEM: Literal[4] + FILE_ATTRIBUTE_TEMPORARY: Literal[256] + FILE_ATTRIBUTE_VIRTUAL: Literal[65536] diff --git a/mypy/typeshed/stdlib/_thread.pyi b/mypy/typeshed/stdlib/_thread.pyi index 2f4252981b68..03318a0b2d41 100644 --- a/mypy/typeshed/stdlib/_thread.pyi +++ b/mypy/typeshed/stdlib/_thread.pyi @@ -1,7 +1,8 @@ import sys +from _typeshed import structseq from threading import Thread from types import TracebackType -from typing import Any, Callable, NoReturn, Optional, Tuple, Type +from typing import Any, Callable, NoReturn, Optional, Type from typing_extensions import final error = RuntimeError @@ -20,7 +21,7 @@ class LockType: self, type: Type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None ) -> None: ... -def start_new_thread(function: Callable[..., Any], args: Tuple[Any, ...], kwargs: dict[str, Any] = ...) -> int: ... +def start_new_thread(function: Callable[..., Any], args: tuple[Any, ...], kwargs: dict[str, Any] = ...) -> int: ... def interrupt_main() -> None: ... def exit() -> NoReturn: ... def allocate_lock() -> LockType: ... @@ -32,7 +33,9 @@ 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]]): + class _ExceptHookArgs( + structseq[Any], tuple[Type[BaseException], Optional[BaseException], Optional[TracebackType], Optional[Thread]] + ): @property def exc_type(self) -> Type[BaseException]: ... @property diff --git a/mypy/typeshed/stdlib/_threading_local.pyi b/mypy/typeshed/stdlib/_threading_local.pyi index bab69a7c2e7d..9e1e3f48d286 100644 --- a/mypy/typeshed/stdlib/_threading_local.pyi +++ b/mypy/typeshed/stdlib/_threading_local.pyi @@ -1,7 +1,7 @@ -from typing import Any, Dict +from typing import Any from weakref import ReferenceType -localdict = Dict[Any, Any] +localdict = dict[Any, Any] class _localimpl: key: str diff --git a/mypy/typeshed/stdlib/_tkinter.pyi b/mypy/typeshed/stdlib/_tkinter.pyi index e97edf5b4fae..b6c8ccd1c380 100644 --- a/mypy/typeshed/stdlib/_tkinter.pyi +++ b/mypy/typeshed/stdlib/_tkinter.pyi @@ -1,3 +1,4 @@ +import sys from typing import Any from typing_extensions import Literal, final @@ -68,7 +69,8 @@ class TkappType: quit: Any record: Any setvar: Any - split: Any + if sys.version_info < (3, 11): + split: Any splitlist: Any unsetvar: Any wantobjects: Any diff --git a/mypy/typeshed/stdlib/_typeshed/__init__.pyi b/mypy/typeshed/stdlib/_typeshed/__init__.pyi index 0d4c42afc285..a7f8c5147103 100644 --- a/mypy/typeshed/stdlib/_typeshed/__init__.pyi +++ b/mypy/typeshed/stdlib/_typeshed/__init__.pyi @@ -7,7 +7,7 @@ import ctypes import mmap import sys from os import PathLike -from typing import AbstractSet, Any, Awaitable, Container, Iterable, Protocol, TypeVar, Union +from typing import AbstractSet, Any, Awaitable, ClassVar, Container, Generic, Iterable, Protocol, Type, TypeVar, Union from typing_extensions import Literal, final _KT = TypeVar("_KT") @@ -35,16 +35,6 @@ class SupportsNext(Protocol[_T_co]): class SupportsAnext(Protocol[_T_co]): def __anext__(self) -> Awaitable[_T_co]: ... -class SupportsLessThan(Protocol): - def __lt__(self, __other: Any) -> bool: ... - -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): @@ -209,3 +199,20 @@ else: @final class NoneType: def __bool__(self) -> Literal[False]: ... + +# This is an internal CPython type that is like, but subtly different from, a NamedTuple +# Subclasses of this type are found in multiple modules. +# In typeshed, `structseq` is only ever used as a mixin in combination with a fixed-length `Tuple` +# See discussion at #6546 & #6560 +# `structseq` classes are unsubclassable, so are all decorated with `@final`. +class structseq(Generic[_T_co]): + n_fields: ClassVar[int] + n_unnamed_fields: ClassVar[int] + n_sequence_fields: ClassVar[int] + # The first parameter will generally only take an iterable of a specific length. + # E.g. `os.uname_result` takes any iterable of length exactly 5. + # + # The second parameter will accept a dict of any kind without raising an exception, + # but only has any meaning if you supply it a dict where the keys are strings. + # https://github.com/python/typeshed/pull/6560#discussion_r767149830 + def __new__(cls: Type[_T], sequence: Iterable[_T_co], dict: dict[str, Any] = ...) -> _T: ... diff --git a/mypy/typeshed/stdlib/_typeshed/dbapi.pyi b/mypy/typeshed/stdlib/_typeshed/dbapi.pyi new file mode 100644 index 000000000000..eee4fc03874e --- /dev/null +++ b/mypy/typeshed/stdlib/_typeshed/dbapi.pyi @@ -0,0 +1,36 @@ +# PEP 249 Database API 2.0 Types +# https://www.python.org/dev/peps/pep-0249/ + +from collections.abc import Mapping, Sequence +from typing import Any, Protocol + +DBAPITypeCode = Any | None +# Strictly speaking, this should be a Sequence, but the type system does +# not support fixed-length sequences. +DBAPIColumnDescription = tuple[str, DBAPITypeCode, int | None, int | None, int | None, int | None, bool | None] + +class DBAPIConnection(Protocol): + def close(self) -> object: ... + def commit(self) -> object: ... + # optional: + # def rollback(self) -> Any: ... + def cursor(self) -> DBAPICursor: ... + +class DBAPICursor(Protocol): + @property + def description(self) -> Sequence[DBAPIColumnDescription] | None: ... + @property + def rowcount(self) -> int: ... + # optional: + # def callproc(self, __procname: str, __parameters: Sequence[Any] = ...) -> Sequence[Any]: ... + def close(self) -> object: ... + def execute(self, __operation: str, __parameters: Sequence[Any] | Mapping[str, Any] = ...) -> object: ... + def executemany(self, __operation: str, __seq_of_parameters: Sequence[Sequence[Any]]) -> object: ... + def fetchone(self) -> Sequence[Any] | None: ... + def fetchmany(self, __size: int = ...) -> Sequence[Sequence[Any]]: ... + def fetchall(self) -> Sequence[Sequence[Any]]: ... + # optional: + # def nextset(self) -> None | Literal[True]: ... + arraysize: int + def setinputsizes(self, __sizes: Sequence[DBAPITypeCode | int | None]) -> object: ... + def setoutputsize(self, __size: int, __column: int = ...) -> object: ... diff --git a/mypy/typeshed/stdlib/_typeshed/wsgi.pyi b/mypy/typeshed/stdlib/_typeshed/wsgi.pyi index 658b0fed2c6c..031d1472b6c5 100644 --- a/mypy/typeshed/stdlib/_typeshed/wsgi.pyi +++ b/mypy/typeshed/stdlib/_typeshed/wsgi.pyi @@ -3,7 +3,7 @@ # See the README.md file in this directory for more information. from sys import _OptExcInfo -from typing import Any, Callable, Dict, Iterable, Protocol +from typing import Any, Callable, Iterable, Protocol # stable class StartResponse(Protocol): @@ -11,7 +11,7 @@ class StartResponse(Protocol): self, status: str, headers: list[tuple[str, str]], exc_info: _OptExcInfo | None = ... ) -> Callable[[bytes], Any]: ... -WSGIEnvironment = Dict[str, Any] # stable +WSGIEnvironment = dict[str, Any] # stable WSGIApplication = Callable[[WSGIEnvironment, StartResponse], Iterable[bytes]] # stable # WSGI input streams per PEP 3333, stable diff --git a/mypy/typeshed/stdlib/_typeshed/xml.pyi b/mypy/typeshed/stdlib/_typeshed/xml.pyi index d53b743af2d3..231c2b86e912 100644 --- a/mypy/typeshed/stdlib/_typeshed/xml.pyi +++ b/mypy/typeshed/stdlib/_typeshed/xml.pyi @@ -1,7 +1,6 @@ # See the README.md file in this directory for more information. -from typing import Any -from typing_extensions import Protocol +from typing import Any, Protocol # As defined https://docs.python.org/3/library/xml.dom.html#domimplementation-objects class DOMImplementation(Protocol): diff --git a/mypy/typeshed/stdlib/_weakref.pyi b/mypy/typeshed/stdlib/_weakref.pyi index dcaef25b3f0f..00dc2d5114b8 100644 --- a/mypy/typeshed/stdlib/_weakref.pyi +++ b/mypy/typeshed/stdlib/_weakref.pyi @@ -11,6 +11,7 @@ _T = TypeVar("_T") @final class CallableProxyType(Generic[_C]): # "weakcallableproxy" def __getattr__(self, attr: str) -> Any: ... + __call__: _C @final class ProxyType(Generic[_T]): # "weakproxy" diff --git a/mypy/typeshed/stdlib/_winapi.pyi b/mypy/typeshed/stdlib/_winapi.pyi index 83089d485c17..eba236597840 100644 --- a/mypy/typeshed/stdlib/_winapi.pyi +++ b/mypy/typeshed/stdlib/_winapi.pyi @@ -2,133 +2,194 @@ import sys from typing import Any, NoReturn, Sequence, overload from typing_extensions import Literal, final -CREATE_NEW_CONSOLE: int -CREATE_NEW_PROCESS_GROUP: int -DUPLICATE_CLOSE_SOURCE: int -DUPLICATE_SAME_ACCESS: int -ERROR_ALREADY_EXISTS: int -ERROR_BROKEN_PIPE: int -ERROR_IO_PENDING: int -ERROR_MORE_DATA: int -ERROR_NETNAME_DELETED: int -ERROR_NO_DATA: int -ERROR_NO_SYSTEM_RESOURCES: int -ERROR_OPERATION_ABORTED: int -ERROR_PIPE_BUSY: int -ERROR_PIPE_CONNECTED: int -ERROR_SEM_TIMEOUT: int -FILE_FLAG_FIRST_PIPE_INSTANCE: int -FILE_FLAG_OVERLAPPED: int -FILE_GENERIC_READ: int -FILE_GENERIC_WRITE: int -GENERIC_READ: int -GENERIC_WRITE: int -INFINITE: int -NMPWAIT_WAIT_FOREVER: int -NULL: int -OPEN_EXISTING: int -PIPE_ACCESS_DUPLEX: int -PIPE_ACCESS_INBOUND: int -PIPE_READMODE_MESSAGE: int -PIPE_TYPE_MESSAGE: int -PIPE_UNLIMITED_INSTANCES: int -PIPE_WAIT: int -PROCESS_ALL_ACCESS: int -PROCESS_DUP_HANDLE: int -STARTF_USESHOWWINDOW: int -STARTF_USESTDHANDLES: int -STD_ERROR_HANDLE: int -STD_INPUT_HANDLE: int -STD_OUTPUT_HANDLE: int -STILL_ACTIVE: int -SW_HIDE: int -WAIT_ABANDONED_0: int -WAIT_OBJECT_0: int -WAIT_TIMEOUT: int +if sys.platform == "win32": + if sys.version_info >= (3, 7): + ABOVE_NORMAL_PRIORITY_CLASS: Literal[32768] + BELOW_NORMAL_PRIORITY_CLASS: Literal[16384] + CREATE_BREAKAWAY_FROM_JOB: Literal[16777216] + CREATE_DEFAULT_ERROR_MODE: Literal[67108864] + CREATE_NO_WINDOW: Literal[134217728] + CREATE_NEW_CONSOLE: Literal[16] + CREATE_NEW_PROCESS_GROUP: Literal[512] + if sys.version_info >= (3, 7): + DETACHED_PROCESS: Literal[8] + DUPLICATE_CLOSE_SOURCE: Literal[1] + DUPLICATE_SAME_ACCESS: Literal[2] -def CloseHandle(__handle: int) -> None: ... -@overload -def ConnectNamedPipe(handle: int, overlapped: Literal[True]) -> Overlapped: ... -@overload -def ConnectNamedPipe(handle: int, overlapped: Literal[False] = ...) -> None: ... -@overload -def ConnectNamedPipe(handle: int, overlapped: bool) -> Overlapped | None: ... -def CreateFile( - __file_name: str, - __desired_access: int, - __share_mode: int, - __security_attributes: int, - __creation_disposition: int, - __flags_and_attributes: int, - __template_file: int, -) -> int: ... -def CreateJunction(__src_path: str, __dst_path: str) -> None: ... -def CreateNamedPipe( - __name: str, - __open_mode: int, - __pipe_mode: int, - __max_instances: int, - __out_buffer_size: int, - __in_buffer_size: int, - __default_timeout: int, - __security_attributes: int, -) -> int: ... -def CreatePipe(__pipe_attrs: Any, __size: int) -> tuple[int, int]: ... -def CreateProcess( - __application_name: str | None, - __command_line: str | None, - __proc_attrs: Any, - __thread_attrs: Any, - __inherit_handles: bool, - __creation_flags: int, - __env_mapping: dict[str, str], - __current_directory: str | None, - __startup_info: Any, -) -> tuple[int, int, int, int]: ... -def DuplicateHandle( - __source_process_handle: int, - __source_handle: int, - __target_process_handle: int, - __desired_access: int, - __inherit_handle: bool, - __options: int = ..., -) -> int: ... -def ExitProcess(__ExitCode: int) -> NoReturn: ... + ERROR_ALREADY_EXISTS: Literal[183] + ERROR_BROKEN_PIPE: Literal[109] + ERROR_IO_PENDING: Literal[997] + ERROR_MORE_DATA: Literal[234] + ERROR_NETNAME_DELETED: Literal[64] + ERROR_NO_DATA: Literal[232] + ERROR_NO_SYSTEM_RESOURCES: Literal[1450] + ERROR_OPERATION_ABORTED: Literal[995] + ERROR_PIPE_BUSY: Literal[231] + ERROR_PIPE_CONNECTED: Literal[535] + ERROR_SEM_TIMEOUT: Literal[121] -if sys.version_info >= (3, 7): - def GetACP() -> int: ... - def GetFileType(handle: int) -> int: ... + FILE_FLAG_FIRST_PIPE_INSTANCE: Literal[524288] + FILE_FLAG_OVERLAPPED: Literal[1073741824] + FILE_GENERIC_READ: Literal[1179785] + FILE_GENERIC_WRITE: Literal[1179926] + if sys.version_info >= (3, 8): + FILE_MAP_ALL_ACCESS: Literal[983071] + FILE_MAP_COPY: Literal[1] + FILE_MAP_EXECUTE: Literal[32] + FILE_MAP_READ: Literal[4] + FILE_MAP_WRITE: Literal[2] + if sys.version_info >= (3, 7): + FILE_TYPE_CHAR: Literal[2] + FILE_TYPE_DISK: Literal[1] + FILE_TYPE_PIPE: Literal[3] + FILE_TYPE_REMOTE: Literal[32768] + FILE_TYPE_UNKNOWN: Literal[0] -def GetCurrentProcess() -> int: ... -def GetExitCodeProcess(__process: int) -> int: ... -def GetLastError() -> int: ... -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]: ... -@overload -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]: ... -@overload -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: ... -def TerminateProcess(__handle: int, __exit_code: int) -> None: ... -def WaitForMultipleObjects(__handle_seq: Sequence[int], __wait_flag: bool, __milliseconds: int = ...) -> int: ... -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]: ... -@overload -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]: ... -@final -class Overlapped: - event: int - def GetOverlappedResult(self, __wait: bool) -> tuple[int, int]: ... - def cancel(self) -> None: ... - def getbuffer(self) -> bytes | None: ... + GENERIC_READ: Literal[2147483648] + GENERIC_WRITE: Literal[1073741824] + if sys.version_info >= (3, 7): + HIGH_PRIORITY_CLASS: Literal[128] + INFINITE: Literal[4294967295] + if sys.version_info >= (3, 8): + INVALID_HANDLE_VALUE: int # very large number + if sys.version_info >= (3, 7): + IDLE_PRIORITY_CLASS: Literal[64] + NORMAL_PRIORITY_CLASS: Literal[32] + REALTIME_PRIORITY_CLASS: Literal[256] + NMPWAIT_WAIT_FOREVER: Literal[4294967295] + + if sys.version_info >= (3, 8): + MEM_COMMIT: Literal[4096] + MEM_FREE: Literal[65536] + MEM_IMAGE: Literal[16777216] + MEM_MAPPED: Literal[262144] + MEM_PRIVATE: Literal[131072] + MEM_RESERVE: Literal[8192] + + NULL: Literal[0] + OPEN_EXISTING: Literal[3] + + PIPE_ACCESS_DUPLEX: Literal[3] + PIPE_ACCESS_INBOUND: Literal[1] + PIPE_READMODE_MESSAGE: Literal[2] + PIPE_TYPE_MESSAGE: Literal[4] + PIPE_UNLIMITED_INSTANCES: Literal[255] + PIPE_WAIT: Literal[0] + if sys.version_info >= (3, 8): + PAGE_EXECUTE: Literal[16] + PAGE_EXECUTE_READ: Literal[32] + PAGE_EXECUTE_READWRITE: Literal[64] + PAGE_EXECUTE_WRITECOPY: Literal[128] + PAGE_GUARD: Literal[256] + PAGE_NOACCESS: Literal[1] + PAGE_NOCACHE: Literal[512] + PAGE_READONLY: Literal[2] + PAGE_READWRITE: Literal[4] + PAGE_WRITECOMBINE: Literal[1024] + PAGE_WRITECOPY: Literal[8] + + PROCESS_ALL_ACCESS: Literal[2097151] + PROCESS_DUP_HANDLE: Literal[64] + if sys.version_info >= (3, 8): + SEC_COMMIT: Literal[134217728] + SEC_IMAGE: Literal[16777216] + SEC_LARGE_PAGES: Literal[2147483648] + SEC_NOCACHE: Literal[268435456] + SEC_RESERVE: Literal[67108864] + SEC_WRITECOMBINE: Literal[1073741824] + STARTF_USESHOWWINDOW: Literal[1] + STARTF_USESTDHANDLES: Literal[256] + STD_ERROR_HANDLE: Literal[4294967284] + STD_INPUT_HANDLE: Literal[4294967286] + STD_OUTPUT_HANDLE: Literal[4294967285] + STILL_ACTIVE: Literal[259] + SW_HIDE: Literal[0] + if sys.version_info >= (3, 8): + SYNCHRONIZE: Literal[1048576] + WAIT_ABANDONED_0: Literal[128] + WAIT_OBJECT_0: Literal[0] + WAIT_TIMEOUT: Literal[258] + def CloseHandle(__handle: int) -> None: ... + @overload + def ConnectNamedPipe(handle: int, overlapped: Literal[True]) -> Overlapped: ... + @overload + def ConnectNamedPipe(handle: int, overlapped: Literal[False] = ...) -> None: ... + @overload + def ConnectNamedPipe(handle: int, overlapped: bool) -> Overlapped | None: ... + def CreateFile( + __file_name: str, + __desired_access: int, + __share_mode: int, + __security_attributes: int, + __creation_disposition: int, + __flags_and_attributes: int, + __template_file: int, + ) -> int: ... + def CreateJunction(__src_path: str, __dst_path: str) -> None: ... + def CreateNamedPipe( + __name: str, + __open_mode: int, + __pipe_mode: int, + __max_instances: int, + __out_buffer_size: int, + __in_buffer_size: int, + __default_timeout: int, + __security_attributes: int, + ) -> int: ... + def CreatePipe(__pipe_attrs: Any, __size: int) -> tuple[int, int]: ... + def CreateProcess( + __application_name: str | None, + __command_line: str | None, + __proc_attrs: Any, + __thread_attrs: Any, + __inherit_handles: bool, + __creation_flags: int, + __env_mapping: dict[str, str], + __current_directory: str | None, + __startup_info: Any, + ) -> tuple[int, int, int, int]: ... + def DuplicateHandle( + __source_process_handle: int, + __source_handle: int, + __target_process_handle: int, + __desired_access: int, + __inherit_handle: bool, + __options: int = ..., + ) -> int: ... + def ExitProcess(__ExitCode: int) -> NoReturn: ... + if sys.version_info >= (3, 7): + def GetACP() -> int: ... + def GetFileType(handle: int) -> int: ... + def GetCurrentProcess() -> int: ... + def GetExitCodeProcess(__process: int) -> int: ... + def GetLastError() -> int: ... + 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]: ... + @overload + 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]: ... + @overload + 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: ... + def TerminateProcess(__handle: int, __exit_code: int) -> None: ... + def WaitForMultipleObjects(__handle_seq: Sequence[int], __wait_flag: bool, __milliseconds: int = ...) -> int: ... + 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]: ... + @overload + 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]: ... + @final + class Overlapped: + event: int + def GetOverlappedResult(self, __wait: bool) -> tuple[int, int]: ... + def cancel(self) -> None: ... + def getbuffer(self) -> bytes | None: ... diff --git a/mypy/typeshed/stdlib/abc.pyi b/mypy/typeshed/stdlib/abc.pyi index 7896e910c81f..3c53692e1b36 100644 --- a/mypy/typeshed/stdlib/abc.pyi +++ b/mypy/typeshed/stdlib/abc.pyi @@ -1,5 +1,6 @@ +import sys from _typeshed import SupportsWrite -from typing import Any, Callable, Tuple, Type, TypeVar +from typing import Any, Callable, Type, TypeVar _T = TypeVar("_T") _FuncT = TypeVar("_FuncT", bound=Callable[..., Any]) @@ -7,7 +8,7 @@ _FuncT = TypeVar("_FuncT", bound=Callable[..., Any]) # These definitions have special processing in mypy class ABCMeta(type): __abstractmethods__: frozenset[str] - def __init__(self, name: str, bases: Tuple[type, ...], namespace: dict[str, Any]) -> None: ... + def __init__(self, name: str, bases: tuple[type, ...], namespace: dict[str, Any]) -> None: ... def __instancecheck__(cls: ABCMeta, instance: Any) -> Any: ... def __subclasscheck__(cls: ABCMeta, subclass: Any) -> Any: ... def _dump_registry(cls: ABCMeta, file: SupportsWrite[str] | None = ...) -> None: ... @@ -24,3 +25,6 @@ def abstractclassmethod(callable: _FuncT) -> _FuncT: ... class ABC(metaclass=ABCMeta): ... def get_cache_token() -> object: ... + +if sys.version_info >= (3, 10): + def update_abstractmethods(cls: Type[_T]) -> Type[_T]: ... diff --git a/mypy/typeshed/stdlib/aifc.pyi b/mypy/typeshed/stdlib/aifc.pyi index 79f470a366bb..e19bf2478bf3 100644 --- a/mypy/typeshed/stdlib/aifc.pyi +++ b/mypy/typeshed/stdlib/aifc.pyi @@ -1,7 +1,7 @@ import sys from _typeshed import Self from types import TracebackType -from typing import IO, Any, NamedTuple, Tuple, Type, Union, overload +from typing import IO, Any, NamedTuple, Type, Union, overload from typing_extensions import Literal class Error(Exception): ... @@ -15,7 +15,7 @@ class _aifc_params(NamedTuple): compname: bytes _File = Union[str, IO[bytes]] -_Marker = Tuple[int, int, bytes] +_Marker = tuple[int, int, bytes] class Aifc_read: def __init__(self, f: _File) -> None: ... diff --git a/mypy/typeshed/stdlib/argparse.pyi b/mypy/typeshed/stdlib/argparse.pyi index b9a09f56a812..51933dc66668 100644 --- a/mypy/typeshed/stdlib/argparse.pyi +++ b/mypy/typeshed/stdlib/argparse.pyi @@ -1,20 +1,5 @@ import sys -from typing import ( - IO, - Any, - Callable, - Generator, - Generic, - Iterable, - NoReturn, - Pattern, - Protocol, - Sequence, - Tuple, - Type, - TypeVar, - overload, -) +from typing import IO, Any, Callable, Generator, Generic, Iterable, NoReturn, Pattern, Protocol, Sequence, Type, TypeVar, overload _T = TypeVar("_T") _ActionT = TypeVar("_ActionT", bound=Action) @@ -66,11 +51,11 @@ class _ActionsContainer: nargs: int | str = ..., const: Any = ..., default: Any = ..., - type: Callable[[str], _T] | Callable[[str], _T] | FileType = ..., + type: Callable[[str], _T] | FileType = ..., choices: Iterable[_T] | None = ..., required: bool = ..., help: str | None = ..., - metavar: str | Tuple[str, ...] | None = ..., + metavar: str | tuple[str, ...] | None = ..., dest: str | None = ..., version: str = ..., **kwargs: Any, @@ -143,11 +128,11 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): @overload def parse_args(self, args: Sequence[str] | None = ...) -> Namespace: ... @overload - def parse_args(self, args: Sequence[str] | None, namespace: None) -> Namespace: ... # type: ignore + def parse_args(self, args: Sequence[str] | None, namespace: None) -> Namespace: ... # type: ignore[misc] @overload def parse_args(self, args: Sequence[str] | None, namespace: _N) -> _N: ... @overload - def parse_args(self, *, namespace: None) -> Namespace: ... # type: ignore + def parse_args(self, *, namespace: None) -> Namespace: ... # type: ignore[misc] @overload def parse_args(self, *, namespace: _N) -> _N: ... if sys.version_info >= (3, 7): @@ -274,7 +259,7 @@ class HelpFormatter: def _format_text(self, text: str) -> str: ... def _format_action(self, action: Action) -> str: ... def _format_action_invocation(self, action: Action) -> str: ... - def _metavar_formatter(self, action: Action, default_metavar: str) -> Callable[[int], Tuple[str, ...]]: ... + def _metavar_formatter(self, action: Action, default_metavar: str) -> Callable[[int], tuple[str, ...]]: ... def _format_args(self, action: Action, default_metavar: str) -> str: ... def _expand_help(self, action: Action) -> str: ... def _iter_indented_subactions(self, action: Action) -> Generator[Action, None, None]: ... @@ -299,7 +284,7 @@ class Action(_AttributeHolder): choices: Iterable[Any] | None required: bool help: str | None - metavar: str | Tuple[str, ...] | None + metavar: str | tuple[str, ...] | None def __init__( self, option_strings: Sequence[str], @@ -311,7 +296,7 @@ class Action(_AttributeHolder): choices: Iterable[_T] | None = ..., required: bool = ..., help: str | None = ..., - metavar: str | Tuple[str, ...] | None = ..., + metavar: str | tuple[str, ...] | None = ..., ) -> None: ... def __call__( self, parser: ArgumentParser, namespace: Namespace, values: str | Sequence[Any] | None, option_string: str | None = ... @@ -330,7 +315,7 @@ if sys.version_info >= (3, 9): choices: Iterable[_T] | None = ..., required: bool = ..., help: str | None = ..., - metavar: str | Tuple[str, ...] | None = ..., + metavar: str | tuple[str, ...] | None = ..., ) -> None: ... class Namespace(_AttributeHolder): @@ -375,7 +360,7 @@ class _StoreConstAction(Action): default: Any = ..., required: bool = ..., help: str | None = ..., - metavar: str | Tuple[str, ...] | None = ..., + metavar: str | tuple[str, ...] | None = ..., ) -> None: ... # undocumented @@ -403,7 +388,7 @@ class _AppendConstAction(Action): default: Any = ..., required: bool = ..., help: str | None = ..., - metavar: str | Tuple[str, ...] | None = ..., + metavar: str | tuple[str, ...] | None = ..., ) -> None: ... # undocumented @@ -440,7 +425,7 @@ class _SubParsersAction(Action, Generic[_ArgumentParserT]): dest: str = ..., required: bool = ..., help: str | None = ..., - metavar: str | Tuple[str, ...] | None = ..., + metavar: str | tuple[str, ...] | None = ..., ) -> None: ... else: def __init__( @@ -450,7 +435,7 @@ class _SubParsersAction(Action, Generic[_ArgumentParserT]): parser_class: Type[_ArgumentParserT], dest: str = ..., help: str | None = ..., - metavar: str | Tuple[str, ...] | None = ..., + metavar: str | tuple[str, ...] | None = ..., ) -> None: ... # TODO: Type keyword args properly. def add_parser(self, name: str, **kwargs: Any) -> _ArgumentParserT: ... diff --git a/mypy/typeshed/stdlib/array.pyi b/mypy/typeshed/stdlib/array.pyi index 6f4444b10f96..f49eb2c916c2 100644 --- a/mypy/typeshed/stdlib/array.pyi +++ b/mypy/typeshed/stdlib/array.pyi @@ -1,6 +1,6 @@ import sys from typing import Any, BinaryIO, Generic, Iterable, MutableSequence, TypeVar, Union, overload -from typing_extensions import Literal +from typing_extensions import Literal, SupportsIndex _IntTypeCode = Literal["b", "B", "h", "H", "i", "I", "l", "L", "q", "Q"] _FloatTypeCode = Literal["f", "d"] @@ -48,14 +48,14 @@ 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: SupportsIndex) -> _T: ... @overload def __getitem__(self, __s: slice) -> array[_T]: ... @overload # type: ignore # Overrides MutableSequence - def __setitem__(self, __i: int, __o: _T) -> None: ... + def __setitem__(self, __i: SupportsIndex, __o: _T) -> None: ... @overload def __setitem__(self, __s: slice, __o: array[_T]) -> None: ... - def __delitem__(self, __i: int | slice) -> None: ... + def __delitem__(self, __i: SupportsIndex | slice) -> None: ... def __add__(self, __x: array[_T]) -> array[_T]: ... def __ge__(self, __other: array[_T]) -> bool: ... def __gt__(self, __other: array[_T]) -> bool: ... diff --git a/mypy/typeshed/stdlib/ast.pyi b/mypy/typeshed/stdlib/ast.pyi index 00c62c30c037..8494a3a99126 100644 --- a/mypy/typeshed/stdlib/ast.pyi +++ b/mypy/typeshed/stdlib/ast.pyi @@ -8,7 +8,7 @@ # sys. import sys import typing as _typing -from _ast import * # type: ignore +from _ast import * from typing import Any, Iterator, TypeVar, overload from typing_extensions import Literal @@ -165,6 +165,57 @@ if sys.version_info >= (3, 8): feature_version: None | int | _typing.Tuple[int, int] = ..., ) -> Module: ... @overload + def parse( + source: str | bytes, + filename: str | bytes, + mode: Literal["eval"], + *, + type_comments: bool = ..., + feature_version: None | int | _typing.Tuple[int, int] = ..., + ) -> Expression: ... + @overload + def parse( + source: str | bytes, + filename: str | bytes, + mode: Literal["func_type"], + *, + type_comments: bool = ..., + feature_version: None | int | _typing.Tuple[int, int] = ..., + ) -> FunctionType: ... + @overload + def parse( + source: str | bytes, + filename: str | bytes, + mode: Literal["single"], + *, + type_comments: bool = ..., + feature_version: None | int | _typing.Tuple[int, int] = ..., + ) -> Interactive: ... + @overload + def parse( + source: str | bytes, + *, + mode: Literal["eval"], + type_comments: bool = ..., + feature_version: None | int | _typing.Tuple[int, int] = ..., + ) -> Expression: ... + @overload + def parse( + source: str | bytes, + *, + mode: Literal["func_type"], + type_comments: bool = ..., + feature_version: None | int | _typing.Tuple[int, int] = ..., + ) -> FunctionType: ... + @overload + def parse( + source: str | bytes, + *, + mode: Literal["single"], + type_comments: bool = ..., + feature_version: None | int | _typing.Tuple[int, int] = ..., + ) -> Interactive: ... + @overload def parse( source: str | bytes, filename: str | bytes = ..., @@ -178,6 +229,14 @@ else: @overload def parse(source: str | bytes, filename: str | bytes = ..., mode: Literal["exec"] = ...) -> Module: ... @overload + def parse(source: str | bytes, filename: str | bytes, mode: Literal["eval"]) -> Expression: ... + @overload + def parse(source: str | bytes, filename: str | bytes, mode: Literal["single"]) -> Interactive: ... + @overload + def parse(source: str | bytes, *, mode: Literal["eval"]) -> Expression: ... + @overload + def parse(source: str | bytes, *, mode: Literal["single"]) -> Interactive: ... + @overload def parse(source: str | bytes, filename: str | bytes = ..., mode: str = ...) -> AST: ... if sys.version_info >= (3, 9): diff --git a/mypy/typeshed/stdlib/asyncio/__init__.pyi b/mypy/typeshed/stdlib/asyncio/__init__.pyi index 42e7aa9ba6d8..f2f7c6b0d165 100644 --- a/mypy/typeshed/stdlib/asyncio/__init__.pyi +++ b/mypy/typeshed/stdlib/asyncio/__init__.pyi @@ -2,7 +2,7 @@ import sys from typing import Type from .base_events import BaseEventLoop as BaseEventLoop -from .coroutines import coroutine as coroutine, iscoroutine as iscoroutine, iscoroutinefunction as iscoroutinefunction +from .coroutines import iscoroutine as iscoroutine, iscoroutinefunction as iscoroutinefunction from .events import ( AbstractEventLoop as AbstractEventLoop, AbstractEventLoopPolicy as AbstractEventLoopPolicy, @@ -71,39 +71,48 @@ from .transports import ( WriteTransport as WriteTransport, ) -if sys.version_info >= (3, 7): - from .events import get_running_loop as get_running_loop +if sys.version_info < (3, 11): + from .coroutines import coroutine as coroutine + +if sys.version_info >= (3, 9): + from .threads import to_thread as to_thread + if sys.version_info >= (3, 8): from .exceptions import ( CancelledError as CancelledError, IncompleteReadError as IncompleteReadError, InvalidStateError as InvalidStateError, LimitOverrunError as LimitOverrunError, - SendfileNotAvailableError as SendfileNotAvailableError, TimeoutError as TimeoutError, ) else: - if sys.version_info >= (3, 7): - from .events import SendfileNotAvailableError as SendfileNotAvailableError from .futures import CancelledError as CancelledError, InvalidStateError as InvalidStateError, TimeoutError as TimeoutError from .streams import IncompleteReadError as IncompleteReadError, LimitOverrunError as LimitOverrunError -if sys.version_info >= (3, 7): - from .protocols import BufferedProtocol as BufferedProtocol +if sys.version_info >= (3, 8): + from .exceptions import SendfileNotAvailableError as SendfileNotAvailableError +elif sys.version_info >= (3, 7): + from .events import SendfileNotAvailableError as SendfileNotAvailableError if sys.version_info >= (3, 7): + from .events import get_running_loop as get_running_loop + from .protocols import BufferedProtocol as BufferedProtocol from .runners import run as run - -if sys.version_info >= (3, 7): - from .tasks import all_tasks as all_tasks, create_task as create_task, current_task as current_task -if sys.version_info >= (3, 9): - from .threads import to_thread as to_thread + from .tasks import ( + _enter_task as _enter_task, + _leave_task as _leave_task, + _register_task as _register_task, + _unregister_task as _unregister_task, + all_tasks as all_tasks, + create_task as create_task, + current_task as current_task, + ) DefaultEventLoopPolicy: Type[AbstractEventLoopPolicy] + if sys.platform == "win32": from .windows_events import * - -if sys.platform != "win32": +else: from .streams import open_unix_connection as open_unix_connection, start_unix_server as start_unix_server from .unix_events import ( AbstractChildWatcher as AbstractChildWatcher, diff --git a/mypy/typeshed/stdlib/asyncio/base_events.pyi b/mypy/typeshed/stdlib/asyncio/base_events.pyi index 15471f54483f..674baf49ba05 100644 --- a/mypy/typeshed/stdlib/asyncio/base_events.pyi +++ b/mypy/typeshed/stdlib/asyncio/base_events.pyi @@ -9,18 +9,18 @@ from asyncio.tasks import Task from asyncio.transports import BaseTransport from collections.abc import Iterable from socket import AddressFamily, SocketKind, _Address, _RetAddress, socket -from typing import IO, Any, Awaitable, Callable, Dict, Generator, Sequence, Tuple, TypeVar, Union, overload +from typing import IO, Any, Awaitable, Callable, Generator, Sequence, TypeVar, Union, overload from typing_extensions import Literal if sys.version_info >= (3, 7): from contextvars import Context _T = TypeVar("_T") -_Context = Dict[str, Any] +_Context = dict[str, Any] _ExceptionHandler = Callable[[AbstractEventLoop, _Context], Any] _ProtocolFactory = Callable[[], BaseProtocol] _SSLContext = Union[bool, None, ssl.SSLContext] -_TransProtPair = Tuple[BaseTransport, BaseProtocol] +_TransProtPair = tuple[BaseTransport, BaseProtocol] class Server(AbstractServer): if sys.version_info >= (3, 7): @@ -37,7 +37,7 @@ class Server(AbstractServer): def __init__(self, loop: AbstractEventLoop, sockets: list[socket]) -> None: ... if sys.version_info >= (3, 8): @property - def sockets(self) -> Tuple[socket, ...]: ... + def sockets(self) -> tuple[socket, ...]: ... elif sys.version_info >= (3, 7): @property def sockets(self) -> list[socket]: ... @@ -285,20 +285,35 @@ class BaseEventLoop(AbstractEventLoop, metaclass=ABCMeta): async def connect_accepted_socket( self, protocol_factory: _ProtocolFactory, sock: socket, *, ssl: _SSLContext = ... ) -> _TransProtPair: ... - async def create_datagram_endpoint( - self, - protocol_factory: _ProtocolFactory, - local_addr: tuple[str, int] | None = ..., - remote_addr: tuple[str, int] | None = ..., - *, - family: int = ..., - proto: int = ..., - flags: int = ..., - reuse_address: bool | None = ..., - reuse_port: bool | None = ..., - allow_broadcast: bool | None = ..., - sock: socket | None = ..., - ) -> _TransProtPair: ... + if sys.version_info >= (3, 11): + async def create_datagram_endpoint( + self, + protocol_factory: _ProtocolFactory, + local_addr: tuple[str, int] | None = ..., + remote_addr: tuple[str, int] | None = ..., + *, + family: int = ..., + proto: int = ..., + flags: int = ..., + reuse_port: bool | None = ..., + allow_broadcast: bool | None = ..., + sock: socket | None = ..., + ) -> _TransProtPair: ... + else: + async def create_datagram_endpoint( + self, + protocol_factory: _ProtocolFactory, + local_addr: tuple[str, int] | None = ..., + remote_addr: tuple[str, int] | None = ..., + *, + family: int = ..., + proto: int = ..., + flags: int = ..., + reuse_address: bool | None = ..., + reuse_port: bool | None = ..., + allow_broadcast: bool | None = ..., + sock: socket | None = ..., + ) -> _TransProtPair: ... # Pipes and subprocesses. async def connect_read_pipe(self, protocol_factory: _ProtocolFactory, pipe: Any) -> _TransProtPair: ... async def connect_write_pipe(self, protocol_factory: _ProtocolFactory, pipe: Any) -> _TransProtPair: ... diff --git a/mypy/typeshed/stdlib/asyncio/base_subprocess.pyi b/mypy/typeshed/stdlib/asyncio/base_subprocess.pyi index 23034790a4a9..94c7c01dd1bc 100644 --- a/mypy/typeshed/stdlib/asyncio/base_subprocess.pyi +++ b/mypy/typeshed/stdlib/asyncio/base_subprocess.pyi @@ -1,6 +1,6 @@ import subprocess from collections import deque -from typing import IO, Any, Callable, Optional, Sequence, Tuple, Union +from typing import IO, Any, Callable, Optional, Sequence, Union from . import events, futures, protocols, transports @@ -15,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__( @@ -46,11 +46,11 @@ class BaseSubprocessTransport(transports.SubprocessTransport): def get_protocol(self) -> protocols.BaseProtocol: ... def is_closing(self) -> bool: ... def close(self) -> None: ... - def get_pid(self) -> int | None: ... # type: ignore + def get_pid(self) -> int | None: ... # type: ignore[override] def get_returncode(self) -> int | None: ... - def get_pipe_transport(self, fd: int) -> _File: ... # type: ignore + def get_pipe_transport(self, fd: int) -> _File: ... # type: ignore[override] def _check_proc(self) -> None: ... # undocumented - def send_signal(self, signal: int) -> None: ... # type: ignore + def send_signal(self, signal: int) -> None: ... # type: ignore[override] def terminate(self) -> None: ... def kill(self) -> None: ... async def _connect_pipes(self, waiter: futures.Future[Any] | None) -> None: ... # undocumented diff --git a/mypy/typeshed/stdlib/asyncio/constants.pyi b/mypy/typeshed/stdlib/asyncio/constants.pyi index 2010fe9123ae..230cf4faf483 100644 --- a/mypy/typeshed/stdlib/asyncio/constants.pyi +++ b/mypy/typeshed/stdlib/asyncio/constants.pyi @@ -1,12 +1,13 @@ import enum import sys +from typing_extensions import Literal -LOG_THRESHOLD_FOR_CONNLOST_WRITES: int -ACCEPT_RETRY_DELAY: int -DEBUG_STACK_DEPTH: int +LOG_THRESHOLD_FOR_CONNLOST_WRITES: Literal[5] +ACCEPT_RETRY_DELAY: Literal[1] +DEBUG_STACK_DEPTH: Literal[10] if sys.version_info >= (3, 7): SSL_HANDSHAKE_TIMEOUT: float - SENDFILE_FALLBACK_READBUFFER_SIZE: int + SENDFILE_FALLBACK_READBUFFER_SIZE: Literal[262144] class _SendfileMode(enum.Enum): UNSUPPORTED: int diff --git a/mypy/typeshed/stdlib/asyncio/coroutines.pyi b/mypy/typeshed/stdlib/asyncio/coroutines.pyi index df94d5ba156a..6c2d8179d1f1 100644 --- a/mypy/typeshed/stdlib/asyncio/coroutines.pyi +++ b/mypy/typeshed/stdlib/asyncio/coroutines.pyi @@ -1,16 +1,20 @@ import sys import types -from collections.abc import Callable, Coroutine -from typing import Any, TypeVar +from collections.abc import Coroutine +from typing import Any from typing_extensions import TypeGuard -_F = TypeVar("_F", bound=Callable[..., Any]) +if sys.version_info < (3, 11): + from collections.abc import Callable + from typing import TypeVar + + _F = TypeVar("_F", bound=Callable[..., Any]) + def coroutine(func: _F) -> _F: ... -def coroutine(func: _F) -> _F: ... def iscoroutinefunction(func: object) -> bool: ... -if sys.version_info < (3, 8): - def iscoroutine(obj: object) -> TypeGuard[types.GeneratorType[Any, Any, Any] | Coroutine[Any, Any, Any]]: ... +if sys.version_info >= (3, 8): + def iscoroutine(obj: object) -> TypeGuard[Coroutine[Any, Any, Any]]: ... else: - def iscoroutine(obj: object) -> TypeGuard[Coroutine[Any, Any, Any]]: ... + def iscoroutine(obj: object) -> TypeGuard[types.GeneratorType[Any, Any, Any] | Coroutine[Any, Any, Any]]: ... diff --git a/mypy/typeshed/stdlib/asyncio/events.pyi b/mypy/typeshed/stdlib/asyncio/events.pyi index 6ef9117b6491..81b30b7e0065 100644 --- a/mypy/typeshed/stdlib/asyncio/events.pyi +++ b/mypy/typeshed/stdlib/asyncio/events.pyi @@ -3,7 +3,7 @@ import sys from _typeshed import FileDescriptorLike, Self from abc import ABCMeta, abstractmethod from socket import AddressFamily, SocketKind, _Address, _RetAddress, socket -from typing import IO, Any, Awaitable, Callable, Dict, Generator, Sequence, Tuple, TypeVar, Union, overload +from typing import IO, Any, Awaitable, Callable, Generator, Sequence, TypeVar, Union, overload from typing_extensions import Literal from .base_events import Server @@ -17,11 +17,11 @@ if sys.version_info >= (3, 7): from contextvars import Context _T = TypeVar("_T") -_Context = Dict[str, Any] +_Context = dict[str, Any] _ExceptionHandler = Callable[[AbstractEventLoop, _Context], Any] _ProtocolFactory = Callable[[], BaseProtocol] _SSLContext = Union[bool, None, ssl.SSLContext] -_TransProtPair = Tuple[BaseTransport, BaseProtocol] +_TransProtPair = tuple[BaseTransport, BaseProtocol] class Handle: _cancelled = False diff --git a/mypy/typeshed/stdlib/asyncio/proactor_events.pyi b/mypy/typeshed/stdlib/asyncio/proactor_events.pyi index 6c8c558e5dfa..1e9cff1b1dd6 100644 --- a/mypy/typeshed/stdlib/asyncio/proactor_events.pyi +++ b/mypy/typeshed/stdlib/asyncio/proactor_events.pyi @@ -1,7 +1,7 @@ import sys from socket import socket -from typing import Any, Mapping, Type -from typing_extensions import Literal, Protocol +from typing import Any, Mapping, Protocol, Type +from typing_extensions import Literal from . import base_events, constants, events, futures, streams, transports diff --git a/mypy/typeshed/stdlib/asyncio/streams.pyi b/mypy/typeshed/stdlib/asyncio/streams.pyi index 595222280d58..6dae893e3b97 100644 --- a/mypy/typeshed/stdlib/asyncio/streams.pyi +++ b/mypy/typeshed/stdlib/asyncio/streams.pyi @@ -16,43 +16,71 @@ if sys.version_info < (3, 8): consumed: int def __init__(self, message: str, consumed: int) -> None: ... -async def open_connection( - host: str | None = ..., - port: int | str | None = ..., - *, - loop: events.AbstractEventLoop | None = ..., - limit: int = ..., - ssl_handshake_timeout: float | None = ..., - **kwds: Any, -) -> tuple[StreamReader, StreamWriter]: ... -async def start_server( - client_connected_cb: _ClientConnectedCallback, - host: str | None = ..., - port: int | str | None = ..., - *, - loop: events.AbstractEventLoop | None = ..., - limit: int = ..., - ssl_handshake_timeout: float | None = ..., - **kwds: Any, -) -> Server: ... +if sys.version_info >= (3, 10): + async def open_connection( + host: str | None = ..., + port: int | str | None = ..., + *, + limit: int = ..., + ssl_handshake_timeout: float | None = ..., + **kwds: Any, + ) -> tuple[StreamReader, StreamWriter]: ... + async def start_server( + client_connected_cb: _ClientConnectedCallback, + host: str | None = ..., + port: int | str | None = ..., + *, + limit: int = ..., + ssl_handshake_timeout: float | None = ..., + **kwds: Any, + ) -> Server: ... -if sys.platform != "win32": - if sys.version_info >= (3, 7): - _PathType = StrPath - else: - _PathType = str - async def open_unix_connection( - path: _PathType | None = ..., *, loop: events.AbstractEventLoop | None = ..., limit: int = ..., **kwds: Any +else: + async def open_connection( + host: str | None = ..., + port: int | str | None = ..., + *, + loop: events.AbstractEventLoop | None = ..., + limit: int = ..., + ssl_handshake_timeout: float | None = ..., + **kwds: Any, ) -> tuple[StreamReader, StreamWriter]: ... - async def start_unix_server( + async def start_server( client_connected_cb: _ClientConnectedCallback, - path: _PathType | None = ..., + host: str | None = ..., + port: int | str | None = ..., *, loop: events.AbstractEventLoop | None = ..., limit: int = ..., + ssl_handshake_timeout: float | None = ..., **kwds: Any, ) -> Server: ... +if sys.platform != "win32": + if sys.version_info >= (3, 7): + _PathType = StrPath + else: + _PathType = str + if sys.version_info >= (3, 10): + async def open_unix_connection( + path: _PathType | None = ..., *, limit: int = ..., **kwds: Any + ) -> tuple[StreamReader, StreamWriter]: ... + async def start_unix_server( + client_connected_cb: _ClientConnectedCallback, path: _PathType | None = ..., *, limit: int = ..., **kwds: Any + ) -> Server: ... + else: + async def open_unix_connection( + path: _PathType | None = ..., *, loop: events.AbstractEventLoop | None = ..., limit: int = ..., **kwds: Any + ) -> tuple[StreamReader, StreamWriter]: ... + async def start_unix_server( + client_connected_cb: _ClientConnectedCallback, + path: _PathType | None = ..., + *, + loop: events.AbstractEventLoop | None = ..., + limit: int = ..., + **kwds: Any, + ) -> Server: ... + class FlowControlMixin(protocols.Protocol): def __init__(self, loop: events.AbstractEventLoop | None = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/asyncio/tasks.pyi b/mypy/typeshed/stdlib/asyncio/tasks.pyi index 15c12909f3c3..71f9741cb33b 100644 --- a/mypy/typeshed/stdlib/asyncio/tasks.pyi +++ b/mypy/typeshed/stdlib/asyncio/tasks.pyi @@ -21,9 +21,9 @@ _FT = TypeVar("_FT", bound=Future[Any]) _FutureT = Union[Future[_T], Generator[Any, None, _T], Awaitable[_T]] _TaskYieldType = Optional[Future[object]] -FIRST_EXCEPTION: str -FIRST_COMPLETED: str -ALL_COMPLETED: str +FIRST_COMPLETED = concurrent.futures.FIRST_COMPLETED +FIRST_EXCEPTION = concurrent.futures.FIRST_EXCEPTION +ALL_COMPLETED = concurrent.futures.ALL_COMPLETED if sys.version_info >= (3, 10): def as_completed(fs: Iterable[_FutureT[_T]], *, timeout: float | None = ...) -> Iterator[Future[_T]]: ... @@ -34,7 +34,7 @@ else: ) -> Iterator[Future[_T]]: ... @overload -def ensure_future(coro_or_future: _FT, *, loop: AbstractEventLoop | None = ...) -> _FT: ... # type: ignore +def ensure_future(coro_or_future: _FT, *, loop: AbstractEventLoop | None = ...) -> _FT: ... # type: ignore[misc] @overload def ensure_future(coro_or_future: Awaitable[_T], *, loop: AbstractEventLoop | None = ...) -> Task[_T]: ... @@ -230,25 +230,27 @@ def run_coroutine_threadsafe(coro: _FutureT[_T], loop: AbstractEventLoop) -> con if sys.version_info >= (3, 10): def shield(arg: _FutureT[_T]) -> Future[_T]: ... - def sleep(delay: float, result: _T = ...) -> Future[_T]: ... + async def sleep(delay: float, result: _T = ...) -> _T: ... @overload - def wait(fs: Iterable[_FT], *, timeout: float | None = ..., return_when: str = ...) -> Future[tuple[set[_FT], set[_FT]]]: ... # type: ignore + async def wait(fs: Iterable[_FT], *, timeout: float | None = ..., return_when: str = ...) -> tuple[set[_FT], set[_FT]]: ... # type: ignore[misc] @overload - def wait( + async def wait( fs: Iterable[Awaitable[_T]], *, timeout: float | None = ..., return_when: str = ... - ) -> Future[tuple[set[Task[_T]], set[Task[_T]]]]: ... - def wait_for(fut: _FutureT[_T], timeout: float | None) -> Future[_T]: ... + ) -> tuple[set[Task[_T]], set[Task[_T]]]: ... + async def wait_for(fut: _FutureT[_T], timeout: float | None) -> _T: ... else: def shield(arg: _FutureT[_T], *, loop: AbstractEventLoop | None = ...) -> Future[_T]: ... - def sleep(delay: float, result: _T = ..., *, loop: AbstractEventLoop | None = ...) -> Future[_T]: ... + async def sleep(delay: float, result: _T = ..., *, loop: AbstractEventLoop | None = ...) -> _T: ... @overload - def wait(fs: Iterable[_FT], *, loop: AbstractEventLoop | None = ..., timeout: float | None = ..., return_when: str = ...) -> Future[tuple[set[_FT], set[_FT]]]: ... # type: ignore + async def wait( # type: ignore[misc] + fs: Iterable[_FT], *, loop: AbstractEventLoop | None = ..., timeout: float | None = ..., return_when: str = ... + ) -> tuple[set[_FT], set[_FT]]: ... @overload - def wait( + async def wait( fs: Iterable[Awaitable[_T]], *, loop: AbstractEventLoop | None = ..., timeout: float | None = ..., return_when: str = ... - ) -> Future[tuple[set[Task[_T]], set[Task[_T]]]]: ... - def wait_for(fut: _FutureT[_T], timeout: float | None, *, loop: AbstractEventLoop | None = ...) -> Future[_T]: ... + ) -> tuple[set[Task[_T]], set[Task[_T]]]: ... + async def wait_for(fut: _FutureT[_T], timeout: float | None, *, loop: AbstractEventLoop | None = ...) -> _T: ... class Task(Future[_T], Generic[_T]): if sys.version_info >= (3, 8): @@ -291,3 +293,7 @@ if sys.version_info >= (3, 7): else: def create_task(coro: Generator[_TaskYieldType, None, _T] | Awaitable[_T]) -> Task[_T]: ... def current_task(loop: AbstractEventLoop | None = ...) -> Task[Any] | None: ... + def _enter_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ... + def _leave_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ... + def _register_task(task: Task[Any]) -> None: ... + def _unregister_task(task: Task[Any]) -> None: ... diff --git a/mypy/typeshed/stdlib/asyncio/threads.pyi b/mypy/typeshed/stdlib/asyncio/threads.pyi index 3f798d8ac862..c13c0c6d1194 100644 --- a/mypy/typeshed/stdlib/asyncio/threads.pyi +++ b/mypy/typeshed/stdlib/asyncio/threads.pyi @@ -1,7 +1,9 @@ import sys -from typing import Any, Callable, TypeVar +from typing import Callable, TypeVar +from typing_extensions import ParamSpec -_T = TypeVar("_T") +_P = ParamSpec("_P") +_R = TypeVar("_R") if sys.version_info >= (3, 9): - async def to_thread(__func: Callable[..., _T], *args: Any, **kwargs: Any) -> _T: ... + async def to_thread(__func: Callable[_P, _R], *args: _P.args, **kwargs: _P.kwargs) -> _R: ... diff --git a/mypy/typeshed/stdlib/asyncio/trsock.pyi b/mypy/typeshed/stdlib/asyncio/trsock.pyi index 33ec5d67aaf9..55147f4fddd5 100644 --- a/mypy/typeshed/stdlib/asyncio/trsock.pyi +++ b/mypy/typeshed/stdlib/asyncio/trsock.pyi @@ -1,14 +1,14 @@ import socket import sys from types import TracebackType -from typing import Any, BinaryIO, Iterable, NoReturn, Tuple, Type, Union, overload +from typing import Any, BinaryIO, Iterable, NoReturn, Type, Union, overload if sys.version_info >= (3, 8): # These are based in socket, maybe move them out into _typeshed.pyi or such - _Address = Union[Tuple[Any, ...], str] + _Address = Union[tuple[Any, ...], str] _RetAddress = Any _WriteBuffer = Union[bytearray, memoryview] - _CMSG = Tuple[int, int, bytes] + _CMSG = tuple[int, int, bytes] class TransportSocket: def __init__(self, sock: socket.socket) -> None: ... def _na(self, what: str) -> None: ... diff --git a/mypy/typeshed/stdlib/asyncio/unix_events.pyi b/mypy/typeshed/stdlib/asyncio/unix_events.pyi index e8e57a20a765..de3b320a4e24 100644 --- a/mypy/typeshed/stdlib/asyncio/unix_events.pyi +++ b/mypy/typeshed/stdlib/asyncio/unix_events.pyi @@ -8,6 +8,9 @@ from .base_events import Server from .events import AbstractEventLoop, BaseDefaultEventLoopPolicy, _ProtocolFactory, _SSLContext from .selector_events import BaseSelectorEventLoop +# This is also technically not available on Win, +# but other parts of typeshed need this defintion. +# So, it is special cased. class AbstractChildWatcher: def add_child_handler(self, pid: int, callback: Callable[..., Any], *args: Any) -> None: ... def remove_child_handler(self, pid: int) -> bool: ... @@ -18,44 +21,40 @@ class AbstractChildWatcher: if sys.version_info >= (3, 8): def is_active(self) -> bool: ... -class BaseChildWatcher(AbstractChildWatcher): - def __init__(self) -> None: ... - -class SafeChildWatcher(BaseChildWatcher): - def __enter__(self: Self) -> Self: ... - -class FastChildWatcher(BaseChildWatcher): - def __enter__(self: Self) -> Self: ... - -class _UnixSelectorEventLoop(BaseSelectorEventLoop): - if sys.version_info < (3, 7): - async def create_unix_server( - self, - protocol_factory: _ProtocolFactory, - path: str | None = ..., - *, - sock: socket | None = ..., - backlog: int = ..., - ssl: _SSLContext = ..., - ) -> Server: ... - -class _UnixDefaultEventLoopPolicy(BaseDefaultEventLoopPolicy): - def get_child_watcher(self) -> AbstractChildWatcher: ... - def set_child_watcher(self, watcher: AbstractChildWatcher | None) -> None: ... - -SelectorEventLoop = _UnixSelectorEventLoop - -DefaultEventLoopPolicy = _UnixDefaultEventLoopPolicy - -if sys.version_info >= (3, 8): - - from typing import Protocol - class _Warn(Protocol): - def __call__( - self, message: str, category: Type[Warning] | None = ..., stacklevel: int = ..., source: Any | None = ... - ) -> None: ... - class MultiLoopChildWatcher(AbstractChildWatcher): +if sys.platform != "win32": + class BaseChildWatcher(AbstractChildWatcher): + def __init__(self) -> None: ... + class SafeChildWatcher(BaseChildWatcher): def __enter__(self: Self) -> Self: ... - class ThreadedChildWatcher(AbstractChildWatcher): + class FastChildWatcher(BaseChildWatcher): def __enter__(self: Self) -> Self: ... - def __del__(self, _warn: _Warn = ...) -> None: ... + class _UnixSelectorEventLoop(BaseSelectorEventLoop): + if sys.version_info < (3, 7): + async def create_unix_server( + self, + protocol_factory: _ProtocolFactory, + path: str | None = ..., + *, + sock: socket | None = ..., + backlog: int = ..., + ssl: _SSLContext = ..., + ) -> Server: ... + class _UnixDefaultEventLoopPolicy(BaseDefaultEventLoopPolicy): + def get_child_watcher(self) -> AbstractChildWatcher: ... + def set_child_watcher(self, watcher: AbstractChildWatcher | None) -> None: ... + SelectorEventLoop = _UnixSelectorEventLoop + + DefaultEventLoopPolicy = _UnixDefaultEventLoopPolicy + + if sys.version_info >= (3, 8): + + from typing import Protocol + class _Warn(Protocol): + def __call__( + self, message: str, category: Type[Warning] | None = ..., stacklevel: int = ..., source: Any | None = ... + ) -> None: ... + class MultiLoopChildWatcher(AbstractChildWatcher): + def __enter__(self: Self) -> Self: ... + class ThreadedChildWatcher(AbstractChildWatcher): + def __enter__(self: Self) -> Self: ... + def __del__(self, _warn: _Warn = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/asyncio/windows_events.pyi b/mypy/typeshed/stdlib/asyncio/windows_events.pyi index f0a206a4e139..d86b6af91a29 100644 --- a/mypy/typeshed/stdlib/asyncio/windows_events.pyi +++ b/mypy/typeshed/stdlib/asyncio/windows_events.pyi @@ -2,76 +2,76 @@ import socket import sys from _typeshed import WriteableBuffer from typing import IO, Any, Callable, ClassVar, NoReturn, Type +from typing_extensions import Literal from . import events, futures, proactor_events, selector_events, streams, windows_utils -__all__ = [ - "SelectorEventLoop", - "ProactorEventLoop", - "IocpProactor", - "DefaultEventLoopPolicy", - "WindowsSelectorEventLoopPolicy", - "WindowsProactorEventLoopPolicy", -] - -NULL: int -INFINITE: int -ERROR_CONNECTION_REFUSED: int -ERROR_CONNECTION_ABORTED: int -CONNECT_PIPE_INIT_DELAY: float -CONNECT_PIPE_MAX_DELAY: float - -class PipeServer: - def __init__(self, address: str) -> None: ... - def __del__(self) -> None: ... - def closed(self) -> bool: ... - def close(self) -> None: ... - -class _WindowsSelectorEventLoop(selector_events.BaseSelectorEventLoop): ... - -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]: ... - async def start_serving_pipe( - self, protocol_factory: Callable[[], streams.StreamReaderProtocol], address: str - ) -> list[PipeServer]: ... - -class IocpProactor: - def __init__(self, concurrency: int = ...) -> None: ... - def __repr__(self) -> str: ... - def __del__(self) -> None: ... - def set_loop(self, loop: events.AbstractEventLoop) -> None: ... - def select(self, timeout: int | None = ...) -> list[futures.Future[Any]]: ... - def recv(self, conn: socket.socket, nbytes: int, flags: int = ...) -> futures.Future[bytes]: ... - if sys.version_info >= (3, 7): - def recv_into(self, conn: socket.socket, buf: WriteableBuffer, flags: int = ...) -> futures.Future[Any]: ... - def send(self, conn: socket.socket, buf: WriteableBuffer, flags: int = ...) -> futures.Future[Any]: ... - def accept(self, listener: socket.socket) -> futures.Future[Any]: ... - def connect(self, conn: socket.socket, address: bytes) -> futures.Future[Any]: ... +if sys.platform == "win32": if sys.version_info >= (3, 7): - def sendfile(self, sock: socket.socket, file: IO[bytes], offset: int, count: int) -> futures.Future[Any]: ... - def accept_pipe(self, pipe: socket.socket) -> futures.Future[Any]: ... - async def connect_pipe(self, address: bytes) -> windows_utils.PipeHandle: ... - def wait_for_handle(self, handle: windows_utils.PipeHandle, timeout: int | None = ...) -> bool: ... - def close(self) -> None: ... + __all__ = ( + "SelectorEventLoop", + "ProactorEventLoop", + "IocpProactor", + "DefaultEventLoopPolicy", + "WindowsSelectorEventLoopPolicy", + "WindowsProactorEventLoopPolicy", + ) + else: + __all__ = ["SelectorEventLoop", "ProactorEventLoop", "IocpProactor", "DefaultEventLoopPolicy"] -SelectorEventLoop = _WindowsSelectorEventLoop + NULL: Literal[0] + INFINITE: Literal[0xFFFFFFFF] + ERROR_CONNECTION_REFUSED: Literal[1225] + ERROR_CONNECTION_ABORTED: Literal[1236] + CONNECT_PIPE_INIT_DELAY: float + CONNECT_PIPE_MAX_DELAY: float + class PipeServer: + def __init__(self, address: str) -> None: ... + def __del__(self) -> None: ... + def closed(self) -> bool: ... + def close(self) -> None: ... + class _WindowsSelectorEventLoop(selector_events.BaseSelectorEventLoop): ... + 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]: ... + async def start_serving_pipe( + self, protocol_factory: Callable[[], streams.StreamReaderProtocol], address: str + ) -> list[PipeServer]: ... + class IocpProactor: + def __init__(self, concurrency: int = ...) -> None: ... + def __repr__(self) -> str: ... + def __del__(self) -> None: ... + def set_loop(self, loop: events.AbstractEventLoop) -> None: ... + def select(self, timeout: int | None = ...) -> list[futures.Future[Any]]: ... + def recv(self, conn: socket.socket, nbytes: int, flags: int = ...) -> futures.Future[bytes]: ... + if sys.version_info >= (3, 7): + def recv_into(self, conn: socket.socket, buf: WriteableBuffer, flags: int = ...) -> futures.Future[Any]: ... + def send(self, conn: socket.socket, buf: WriteableBuffer, flags: int = ...) -> futures.Future[Any]: ... + def accept(self, listener: socket.socket) -> futures.Future[Any]: ... + def connect(self, conn: socket.socket, address: bytes) -> futures.Future[Any]: ... + if sys.version_info >= (3, 7): + def sendfile(self, sock: socket.socket, file: IO[bytes], offset: int, count: int) -> futures.Future[Any]: ... + def accept_pipe(self, pipe: socket.socket) -> futures.Future[Any]: ... + async def connect_pipe(self, address: bytes) -> windows_utils.PipeHandle: ... + def wait_for_handle(self, handle: windows_utils.PipeHandle, timeout: int | None = ...) -> bool: ... + def close(self) -> None: ... + SelectorEventLoop = _WindowsSelectorEventLoop -if sys.version_info >= (3, 7): - class WindowsSelectorEventLoopPolicy(events.BaseDefaultEventLoopPolicy): - _loop_factory: ClassVar[Type[SelectorEventLoop]] - def get_child_watcher(self) -> NoReturn: ... - def set_child_watcher(self, watcher: Any) -> NoReturn: ... - class WindowsProactorEventLoopPolicy(events.BaseDefaultEventLoopPolicy): - _loop_factory: ClassVar[Type[ProactorEventLoop]] - def get_child_watcher(self) -> NoReturn: ... - def set_child_watcher(self, watcher: Any) -> NoReturn: ... - DefaultEventLoopPolicy = WindowsSelectorEventLoopPolicy -else: - class _WindowsDefaultEventLoopPolicy(events.BaseDefaultEventLoopPolicy): - _loop_factory: ClassVar[Type[SelectorEventLoop]] - def get_child_watcher(self) -> NoReturn: ... - def set_child_watcher(self, watcher: Any) -> NoReturn: ... - DefaultEventLoopPolicy = _WindowsDefaultEventLoopPolicy + if sys.version_info >= (3, 7): + class WindowsSelectorEventLoopPolicy(events.BaseDefaultEventLoopPolicy): + _loop_factory: ClassVar[Type[SelectorEventLoop]] + def get_child_watcher(self) -> NoReturn: ... + def set_child_watcher(self, watcher: Any) -> NoReturn: ... + class WindowsProactorEventLoopPolicy(events.BaseDefaultEventLoopPolicy): + _loop_factory: ClassVar[Type[ProactorEventLoop]] + def get_child_watcher(self) -> NoReturn: ... + def set_child_watcher(self, watcher: Any) -> NoReturn: ... + DefaultEventLoopPolicy = WindowsSelectorEventLoopPolicy + else: + class _WindowsDefaultEventLoopPolicy(events.BaseDefaultEventLoopPolicy): + _loop_factory: ClassVar[Type[SelectorEventLoop]] + def get_child_watcher(self) -> NoReturn: ... + def set_child_watcher(self, watcher: Any) -> NoReturn: ... + DefaultEventLoopPolicy = _WindowsDefaultEventLoopPolicy diff --git a/mypy/typeshed/stdlib/asyncio/windows_utils.pyi b/mypy/typeshed/stdlib/asyncio/windows_utils.pyi index bf9cdde25a78..c387fc40f211 100644 --- a/mypy/typeshed/stdlib/asyncio/windows_utils.pyi +++ b/mypy/typeshed/stdlib/asyncio/windows_utils.pyi @@ -1,27 +1,29 @@ +import subprocess import sys from _typeshed import Self from types import TracebackType from typing import Callable, Protocol, Type +from typing_extensions import Literal -class _WarnFunction(Protocol): - def __call__(self, message: str, category: Type[Warning] = ..., stacklevel: int = ..., source: PipeHandle = ...) -> None: ... - -BUFSIZE: int -PIPE: int -STDOUT: int - -def pipe(*, duplex: bool = ..., overlapped: tuple[bool, bool] = ..., bufsize: int = ...) -> tuple[int, int]: ... - -class PipeHandle: - def __init__(self, handle: int) -> None: ... - def __repr__(self) -> str: ... - if sys.version_info >= (3, 8): - def __del__(self, _warn: _WarnFunction = ...) -> None: ... - else: - def __del__(self) -> None: ... - def __enter__(self: Self) -> Self: ... - def __exit__(self, t: type | None, v: BaseException | None, tb: TracebackType | None) -> None: ... - @property - def handle(self) -> int: ... - def fileno(self) -> int: ... - def close(self, *, CloseHandle: Callable[[int], None] = ...) -> None: ... +if sys.platform == "win32": + class _WarnFunction(Protocol): + def __call__( + self, message: str, category: Type[Warning] = ..., stacklevel: int = ..., source: PipeHandle = ... + ) -> None: ... + BUFSIZE: Literal[8192] + PIPE = subprocess.PIPE + STDOUT = subprocess.STDOUT + def pipe(*, duplex: bool = ..., overlapped: tuple[bool, bool] = ..., bufsize: int = ...) -> tuple[int, int]: ... + class PipeHandle: + def __init__(self, handle: int) -> None: ... + def __repr__(self) -> str: ... + if sys.version_info >= (3, 8): + def __del__(self, _warn: _WarnFunction = ...) -> None: ... + else: + def __del__(self) -> None: ... + def __enter__(self: Self) -> Self: ... + def __exit__(self, t: type | None, v: BaseException | None, tb: TracebackType | None) -> None: ... + @property + def handle(self) -> int: ... + def fileno(self) -> int: ... + def close(self, *, CloseHandle: Callable[[int], None] = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/asyncore.pyi b/mypy/typeshed/stdlib/asyncore.pyi index e135221134a5..123da2677a7e 100644 --- a/mypy/typeshed/stdlib/asyncore.pyi +++ b/mypy/typeshed/stdlib/asyncore.pyi @@ -1,10 +1,10 @@ import sys from _typeshed import FileDescriptorLike from socket import socket -from typing import Any, Dict, Tuple, overload +from typing import Any, overload # cyclic dependence with asynchat -_maptype = Dict[int, Any] +_maptype = dict[int, Any] _socket = socket socket_map: _maptype # undocumented @@ -41,8 +41,8 @@ class dispatcher: def readable(self) -> bool: ... def writable(self) -> bool: ... def listen(self, num: int) -> None: ... - def bind(self, addr: Tuple[Any, ...] | str) -> None: ... - def connect(self, address: Tuple[Any, ...] | str) -> 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 send(self, data: bytes) -> int: ... def recv(self, buffer_size: int) -> bytes: ... diff --git a/mypy/typeshed/stdlib/atexit.pyi b/mypy/typeshed/stdlib/atexit.pyi index 9395c60678b8..ba0c7dfaf6b1 100644 --- a/mypy/typeshed/stdlib/atexit.pyi +++ b/mypy/typeshed/stdlib/atexit.pyi @@ -7,5 +7,5 @@ _P = ParamSpec("_P") def _clear() -> None: ... def _ncallbacks() -> int: ... def _run_exitfuncs() -> None: ... -def register(func: Callable[_P, _T], *args: _P.args, **kwargs: _P.kwargs) -> Callable[_P, _T]: ... # type: ignore +def register(func: Callable[_P, _T], *args: _P.args, **kwargs: _P.kwargs) -> Callable[_P, _T]: ... def unregister(func: Callable[..., Any]) -> None: ... diff --git a/mypy/typeshed/stdlib/audioop.pyi b/mypy/typeshed/stdlib/audioop.pyi index 321bfe55c4b0..b08731b85b0b 100644 --- a/mypy/typeshed/stdlib/audioop.pyi +++ b/mypy/typeshed/stdlib/audioop.pyi @@ -1,7 +1,5 @@ -from typing import Tuple - -AdpcmState = Tuple[int, int] -RatecvState = Tuple[int, Tuple[Tuple[int, int], ...]] +AdpcmState = tuple[int, int] +RatecvState = tuple[int, tuple[tuple[int, int], ...]] class error(Exception): ... diff --git a/mypy/typeshed/stdlib/bdb.pyi b/mypy/typeshed/stdlib/bdb.pyi index 1d03ddf19a0e..3f6b6d3d8b7b 100644 --- a/mypy/typeshed/stdlib/bdb.pyi +++ b/mypy/typeshed/stdlib/bdb.pyi @@ -1,9 +1,9 @@ from types import CodeType, FrameType, TracebackType -from typing import IO, Any, Callable, Iterable, Mapping, SupportsInt, Tuple, Type, TypeVar +from typing import IO, Any, Callable, Iterable, Mapping, SupportsInt, Type, TypeVar _T = TypeVar("_T") _TraceDispatch = Callable[[FrameType, str, Any], Any] # TODO: Recursive type -_ExcInfo = Tuple[Type[BaseException], BaseException, FrameType] +_ExcInfo = tuple[Type[BaseException], BaseException, FrameType] GENERATOR_AND_COROUTINE_FLAGS: int diff --git a/mypy/typeshed/stdlib/binascii.pyi b/mypy/typeshed/stdlib/binascii.pyi index 962f5666b284..317bb9979b92 100644 --- a/mypy/typeshed/stdlib/binascii.pyi +++ b/mypy/typeshed/stdlib/binascii.pyi @@ -12,10 +12,13 @@ def a2b_base64(__data: str | bytes) -> bytes: ... def b2a_base64(__data: bytes, *, newline: bool = ...) -> bytes: ... def a2b_qp(data: str | bytes, header: bool = ...) -> bytes: ... def b2a_qp(data: bytes, quotetabs: bool = ..., istext: bool = ..., header: bool = ...) -> bytes: ... -def a2b_hqx(__data: str | bytes) -> bytes: ... -def rledecode_hqx(__data: bytes) -> bytes: ... -def rlecode_hqx(__data: bytes) -> bytes: ... -def b2a_hqx(__data: bytes) -> bytes: ... + +if sys.version_info < (3, 11): + def a2b_hqx(__data: str | bytes) -> bytes: ... + def rledecode_hqx(__data: bytes) -> bytes: ... + def rlecode_hqx(__data: bytes) -> bytes: ... + def b2a_hqx(__data: bytes) -> bytes: ... + def crc_hqx(__data: bytes, __crc: int) -> int: ... def crc32(__data: bytes, __crc: int = ...) -> int: ... def b2a_hex(__data: bytes) -> bytes: ... diff --git a/mypy/typeshed/stdlib/binhex.pyi b/mypy/typeshed/stdlib/binhex.pyi index 02d094faf923..4e295b8ed903 100644 --- a/mypy/typeshed/stdlib/binhex.pyi +++ b/mypy/typeshed/stdlib/binhex.pyi @@ -1,4 +1,4 @@ -from typing import IO, Any, Tuple, Union +from typing import IO, Any, Union class Error(Exception): ... @@ -12,7 +12,7 @@ class FInfo: Creator: str Flags: int -_FileInfoTuple = Tuple[str, FInfo, int, int] +_FileInfoTuple = tuple[str, FInfo, int, int] _FileHandleUnion = Union[str, IO[bytes]] def getfileinfo(name: str) -> _FileInfoTuple: ... diff --git a/mypy/typeshed/stdlib/builtins.pyi b/mypy/typeshed/stdlib/builtins.pyi index 71efda9b979a..5547afc217f6 100644 --- a/mypy/typeshed/stdlib/builtins.pyi +++ b/mypy/typeshed/stdlib/builtins.pyi @@ -23,13 +23,11 @@ from _typeshed import ( SupportsWrite, ) from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper -from types import CodeType, TracebackType +from types import CodeType, TracebackType, _Cell from typing import ( IO, AbstractSet, Any, - AsyncIterable, - AsyncIterator, BinaryIO, ByteString, Callable, @@ -51,7 +49,6 @@ from typing import ( SupportsFloat, SupportsInt, SupportsRound, - Tuple, Type, TypeVar, Union, @@ -76,6 +73,14 @@ _T5 = TypeVar("_T5") _TT = TypeVar("_TT", bound="type") _TBE = TypeVar("_TBE", bound="BaseException") _R = TypeVar("_R") # Return-type TypeVar +_SupportsNextT = TypeVar("_SupportsNextT", bound=SupportsNext[Any], covariant=True) +_SupportsAnextT = TypeVar("_SupportsAnextT", bound=SupportsAnext[Any], covariant=True) + +class _SupportsIter(Protocol[_T_co]): + def __iter__(self) -> _T_co: ... + +class _SupportsAiter(Protocol[_T_co]): + def __aiter__(self) -> _T_co: ... class object: __doc__: str | None @@ -100,11 +105,13 @@ class object: def __getattribute__(self, __name: str) -> Any: ... def __delattr__(self, __name: str) -> None: ... def __sizeof__(self) -> int: ... - def __reduce__(self) -> str | Tuple[object, ...]: ... + # return type of pickle methods is rather hard to express in the current type system + # see #6661 and https://docs.python.org/3/library/pickle.html#object.__reduce__ + def __reduce__(self) -> str | tuple[Any, ...]: ... if sys.version_info >= (3, 8): - def __reduce_ex__(self, __protocol: SupportsIndex) -> str | Tuple[object, ...]: ... + def __reduce_ex__(self, __protocol: SupportsIndex) -> str | tuple[Any, ...]: ... else: - def __reduce_ex__(self, __protocol: int) -> str | Tuple[object, ...]: ... + def __reduce_ex__(self, __protocol: int) -> str | tuple[Any, ...]: ... def __dir__(self) -> Iterable[str]: ... def __init_subclass__(cls) -> None: ... @@ -131,16 +138,16 @@ class classmethod(Generic[_R]): # Special, only valid as a decorator. __qualname__: str __wrapped__: Callable[..., _R] -class type(object): +class type: __base__: type - __bases__: Tuple[type, ...] + __bases__: tuple[type, ...] __basicsize__: int __dict__: dict[str, Any] __dictoffset__: int __flags__: int __itemsize__: int __module__: str - __mro__: Tuple[type, ...] + __mro__: tuple[type, ...] __name__: str __qualname__: str __text_signature__: str | None @@ -148,11 +155,11 @@ class type(object): @overload 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: ... @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 doesn't specify what the return type is, the standard @@ -161,12 +168,12 @@ class type(object): 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, object]: ... + 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: ... -class super(object): +class super: @overload def __init__(self, __t: Any, __obj: Any) -> None: ... @overload @@ -345,6 +352,8 @@ class complex: def __abs__(self) -> float: ... def __hash__(self) -> int: ... def __bool__(self) -> bool: ... + if sys.version_info >= (3, 11): + def __complex__(self) -> complex: ... class _FormatMapMapping(Protocol): def __getitem__(self, __key: str) -> Any: ... @@ -360,7 +369,7 @@ class str(Sequence[str]): def count(self, x: str, __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ...) -> int: ... def encode(self, encoding: str = ..., errors: str = ...) -> bytes: ... def endswith( - self, __suffix: str | Tuple[str, ...], __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ... + self, __suffix: str | tuple[str, ...], __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ... ) -> bool: ... if sys.version_info >= (3, 8): def expandtabs(self, tabsize: SupportsIndex = ...) -> str: ... @@ -401,7 +410,7 @@ class str(Sequence[str]): def split(self, sep: str | None = ..., maxsplit: SupportsIndex = ...) -> list[str]: ... def splitlines(self, keepends: bool = ...) -> list[str]: ... def startswith( - self, __prefix: str | Tuple[str, ...], __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ... + self, __prefix: str | tuple[str, ...], __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ... ) -> bool: ... def strip(self, __chars: str | None = ...) -> str: ... def swapcase(self) -> str: ... @@ -420,7 +429,7 @@ class str(Sequence[str]): 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 __getitem__(self, __i: SupportsIndex | slice) -> str: ... def __gt__(self, __x: str) -> bool: ... def __hash__(self) -> int: ... def __iter__(self) -> Iterator[str]: ... @@ -453,7 +462,7 @@ class bytes(ByteString): ) -> int: ... def decode(self, encoding: str = ..., errors: str = ...) -> str: ... def endswith( - self, __suffix: bytes | Tuple[bytes, ...], __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ... + self, __suffix: bytes | tuple[bytes, ...], __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ... ) -> bool: ... if sys.version_info >= (3, 8): def expandtabs(self, tabsize: SupportsIndex = ...) -> bytes: ... @@ -500,7 +509,7 @@ class bytes(ByteString): def split(self, sep: bytes | None = ..., maxsplit: SupportsIndex = ...) -> list[bytes]: ... def splitlines(self, keepends: bool = ...) -> list[bytes]: ... def startswith( - self, __prefix: bytes | Tuple[bytes, ...], __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ... + self, __prefix: bytes | tuple[bytes, ...], __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ... ) -> bool: ... def strip(self, __bytes: bytes | None = ...) -> bytes: ... def swapcase(self) -> bytes: ... @@ -534,6 +543,8 @@ class bytes(ByteString): def __gt__(self, __x: bytes) -> bool: ... def __ge__(self, __x: bytes) -> bool: ... def __getnewargs__(self) -> tuple[bytes]: ... + if sys.version_info >= (3, 11): + def __bytes__(self) -> bytes: ... class bytearray(MutableSequence[int], ByteString): @overload @@ -553,7 +564,7 @@ class bytearray(MutableSequence[int], ByteString): def copy(self) -> bytearray: ... def decode(self, encoding: str = ..., errors: str = ...) -> str: ... def endswith( - self, __suffix: bytes | Tuple[bytes, ...], __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ... + self, __suffix: bytes | tuple[bytes, ...], __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ... ) -> bool: ... if sys.version_info >= (3, 8): def expandtabs(self, tabsize: SupportsIndex = ...) -> bytearray: ... @@ -602,7 +613,7 @@ class bytearray(MutableSequence[int], ByteString): def split(self, sep: bytes | None = ..., maxsplit: SupportsIndex = ...) -> list[bytearray]: ... def splitlines(self, keepends: bool = ...) -> list[bytearray]: ... def startswith( - self, __prefix: bytes | Tuple[bytes, ...], __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ... + self, __prefix: bytes | tuple[bytes, ...], __start: SupportsIndex | None = ..., __end: SupportsIndex | None = ... ) -> bool: ... def strip(self, __bytes: bytes | None = ...) -> bytearray: ... def swapcase(self) -> bytearray: ... @@ -647,9 +658,9 @@ class bytearray(MutableSequence[int], ByteString): class memoryview(Sized, Sequence[int]): format: str itemsize: int - shape: Tuple[int, ...] | None - strides: Tuple[int, ...] | None - suboffsets: Tuple[int, ...] | None + shape: tuple[int, ...] | None + strides: tuple[int, ...] | None + suboffsets: tuple[int, ...] | None readonly: bool ndim: int @@ -663,7 +674,7 @@ class memoryview(Sized, Sequence[int]): def __exit__( 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: ... + def cast(self, format: str, shape: list[int] | tuple[int, ...] = ...) -> memoryview: ... @overload def __getitem__(self, __i: SupportsIndex) -> int: ... @overload @@ -718,7 +729,7 @@ class bool(int): def __getnewargs__(self) -> tuple[int]: ... @final -class slice(object): +class slice: start: Any step: Any stop: Any @@ -734,48 +745,57 @@ class tuple(Sequence[_T_co], Generic[_T_co]): def __len__(self) -> int: ... def __contains__(self, __x: object) -> bool: ... @overload - def __getitem__(self, __x: int) -> _T_co: ... + def __getitem__(self, __x: SupportsIndex) -> _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: ... +# Doesn't exist at runtime, but deleting this breaks mypy. See #2999 +@final class function: - # TODO not defined in builtins! - __name__: str - __module__: str + # Make sure this class definition stays roughly in line with `types.FunctionType` + __closure__: tuple[_Cell, ...] | None __code__: CodeType + __defaults__: tuple[Any, ...] | None + __dict__: dict[str, Any] + __globals__: dict[str, Any] + __name__: str __qualname__: str __annotations__: dict[str, Any] + __kwdefaults__: dict[str, Any] + __module__: str + # mypy uses `builtins.function.__get__` to represent methods, properties, and getset_descriptors so we type the return as Any. + def __get__(self, obj: object | None, type: type | None = ...) -> Any: ... class list(MutableSequence[_T], Generic[_T]): @overload def __init__(self) -> None: ... @overload def __init__(self, __iterable: Iterable[_T]) -> None: ... - def clear(self) -> None: ... def copy(self) -> list[_T]: ... def append(self, __object: _T) -> None: ... def extend(self, __iterable: Iterable[_T]) -> None: ... def pop(self, __index: SupportsIndex = ...) -> _T: ... + # Signature of `list.index` should be kept in line with `collections.UserList.index()` def index(self, __value: _T, __start: SupportsIndex = ..., __stop: SupportsIndex = ...) -> int: ... def count(self, __value: _T) -> int: ... def insert(self, __index: SupportsIndex, __object: _T) -> None: ... def remove(self, __value: _T) -> None: ... - def reverse(self) -> None: ... + # Signature of `list.sort` should be kept inline with `collections.UserList.sort()` @overload def sort(self: list[SupportsRichComparisonT], *, key: None = ..., reverse: bool = ...) -> None: ... @overload @@ -808,6 +828,7 @@ class list(MutableSequence[_T], Generic[_T]): def __class_getitem__(cls, __item: Any) -> GenericAlias: ... class dict(MutableMapping[_KT, _VT], Generic[_KT, _VT]): + # __init__ should be kept roughly in line with `collections.UserDict.__init__`, which has similar semantics @overload def __init__(self: dict[_KT, _VT]) -> None: ... @overload @@ -821,19 +842,13 @@ class dict(MutableMapping[_KT, _VT], Generic[_KT, _VT]): @overload 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 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: ... - @overload - def update(self, **kwargs: _VT) -> None: ... def keys(self) -> dict_keys[_KT, _VT]: ... def values(self) -> dict_values[_KT, _VT]: ... def items(self) -> dict_items[_KT, _VT]: ... + # Signature of `dict.fromkeys` should be kept identical to `fromkeys` methods of `OrderedDict`/`ChainMap`/`UserDict` in `collections` + # TODO: the true signature of `dict.fromkeys` is not expressable in the current type system. + # See #3800 & https://github.com/python/typing/issues/548#issuecomment-683336963. @classmethod @overload def fromkeys(cls, __iterable: Iterable[_T], __value: None = ...) -> dict[_T, Any | None]: ... @@ -858,7 +873,6 @@ class dict(MutableMapping[_KT, _VT], Generic[_KT, _VT]): class set(MutableSet[_T], Generic[_T]): 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 difference_update(self, *s: Iterable[Any]) -> None: ... @@ -868,7 +882,6 @@ class set(MutableSet[_T], Generic[_T]): 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: ... @@ -919,7 +932,7 @@ class frozenset(AbstractSet[_T_co], Generic[_T_co]): if sys.version_info >= (3, 9): def __class_getitem__(cls, __item: Any) -> GenericAlias: ... -class enumerate(Iterator[Tuple[int, _T]], Generic[_T]): +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]: ... @@ -947,7 +960,7 @@ class range(Sequence[int]): def __repr__(self) -> str: ... def __reversed__(self) -> Iterator[int]: ... -class property(object): +class property: fget: Callable[[Any], Any] | None fset: Callable[[Any, Any], None] | None fdel: Callable[[Any], None] | None @@ -993,7 +1006,7 @@ class _PathLike(Protocol[_AnyStr_co]): def __fspath__(self) -> _AnyStr_co: ... if sys.version_info >= (3, 10): - def aiter(__iterable: AsyncIterable[_T]) -> AsyncIterator[_T]: ... + def aiter(__async_iterable: _SupportsAiter[_SupportsAnextT]) -> _SupportsAnextT: ... @overload async def anext(__i: SupportsAnext[_T]) -> _T: ... @overload @@ -1071,12 +1084,12 @@ 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 help(request: object = ...) -> None: ... def hex(__number: int | SupportsIndex) -> str: ... def id(__obj: object) -> int: ... def input(__prompt: object = ...) -> str: ... @overload -def iter(__iterable: Iterable[_T]) -> Iterator[_T]: ... +def iter(__iterable: _SupportsIter[_SupportsNextT]) -> _SupportsNextT: ... @overload def iter(__function: Callable[[], _T | None], __sentinel: None) -> Iterator[_T]: ... @overload @@ -1085,15 +1098,15 @@ 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, ...], ...] + __obj: object, __class_or_tuple: type | types.UnionType | tuple[type | types.UnionType | tuple[Any, ...], ...] ) -> bool: ... def issubclass( - __cls: type, __class_or_tuple: type | types.UnionType | Tuple[type | types.UnionType | Tuple[Any, ...], ...] + __cls: type, __class_or_tuple: type | types.UnionType | tuple[type | types.UnionType | tuple[Any, ...], ...] ) -> bool: ... else: - def isinstance(__obj: object, __class_or_tuple: type | Tuple[type | Tuple[Any, ...], ...]) -> bool: ... - def issubclass(__cls: type, __class_or_tuple: type | Tuple[type | Tuple[Any, ...], ...]) -> bool: ... + def isinstance(__obj: object, __class_or_tuple: type | tuple[type | tuple[Any, ...], ...]) -> bool: ... + def issubclass(__cls: type, __class_or_tuple: type | tuple[type | tuple[Any, ...], ...]) -> bool: ... def len(__obj: Sized) -> int: ... def license() -> None: ... @@ -1380,19 +1393,21 @@ def round(number: SupportsRound[_T], ndigits: SupportsIndex) -> _T: ... # 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[SupportsRichComparisonT], *, key: None = ..., reverse: bool = ...) -> list[SupportsRichComparisonT]: ... +def sorted( + __iterable: Iterable[SupportsRichComparisonT], *, key: None = ..., reverse: bool = ... +) -> list[SupportsRichComparisonT]: ... @overload def sorted(__iterable: Iterable[_T], *, key: Callable[[_T], SupportsRichComparison], reverse: bool = ...) -> list[_T]: ... if sys.version_info >= (3, 8): @overload - def sum(__iterable: Iterable[_T]) -> _T | int: ... + def sum(__iterable: Iterable[_T]) -> _T | Literal[0]: ... @overload def sum(__iterable: Iterable[_T], start: _S) -> _T | _S: ... else: @overload - def sum(__iterable: Iterable[_T]) -> _T | int: ... + def sum(__iterable: Iterable[_T]) -> _T | Literal[0]: ... @overload def sum(__iterable: Iterable[_T], __start: _S) -> _T | _S: ... @@ -1442,7 +1457,7 @@ class zip(Iterator[_T_co], Generic[_T_co]): __iter6: Iterable[Any], *iterables: Iterable[Any], strict: bool = ..., - ) -> zip[Tuple[Any, ...]]: ... + ) -> zip[tuple[Any, ...]]: ... else: @overload def __new__(cls, __iter1: Iterable[_T1]) -> zip[tuple[_T1]]: ... @@ -1473,7 +1488,7 @@ class zip(Iterator[_T_co], Generic[_T_co]): __iter5: Iterable[Any], __iter6: Iterable[Any], *iterables: Iterable[Any], - ) -> zip[Tuple[Any, ...]]: ... + ) -> zip[tuple[Any, ...]]: ... def __iter__(self) -> Iterator[_T_co]: ... def __next__(self) -> _T_co: ... @@ -1494,12 +1509,14 @@ class ellipsis: ... Ellipsis: ellipsis -class BaseException(object): - args: Tuple[Any, ...] +class BaseException: + args: tuple[Any, ...] __cause__: BaseException | None __context__: BaseException | None __suppress_context__: bool __traceback__: TracebackType | None + if sys.version_info >= (3, 11): + __note__: str | None def __init__(self, *args: object) -> None: ... def __str__(self) -> str: ... def __repr__(self) -> str: ... @@ -1622,7 +1639,14 @@ class UnicodeEncodeError(UnicodeError): reason: str def __init__(self, __encoding: str, __object: str, __start: int, __end: int, __reason: str) -> None: ... -class UnicodeTranslateError(UnicodeError): ... +class UnicodeTranslateError(UnicodeError): + encoding: None + object: str + start: int + end: int + reason: str + def __init__(self, __object: str, __start: int, __end: int, __reason: str) -> None: ... + class Warning(Exception): ... class UserWarning(Warning): ... class DeprecationWarning(Warning): ... @@ -1637,3 +1661,19 @@ class ResourceWarning(Warning): ... if sys.version_info >= (3, 10): class EncodingWarning(Warning): ... + +if sys.version_info >= (3, 11): + _SplitCondition = type[BaseException] | tuple[type[BaseException, ...]] | Callable[[BaseException], bool] + class BaseExceptionGroup(BaseException): + def __new__(cls, __message: str, __exceptions: Sequence[BaseException]) -> BaseExceptionGroup | ExceptionGroup: ... + @property + def message(self) -> str: ... + @property + def exceptions(self) -> Sequence[BaseException]: ... + def subgroup(self: Self, __condition: _SplitCondition) -> Self | None: ... + def split(self: Self, __condition: _SplitCondition) -> tuple[Self | None, Self | None]: ... + def derive(self: Self, __excs: Sequence[BaseException]) -> Self: ... + class ExceptionGroup(BaseExceptionGroup, Exception): + def __new__(cls, __message: str, exceptions: Sequence[Exception]) -> ExceptionGroup: ... + @property + def exceptions(self) -> Sequence[Exception]: ... diff --git a/mypy/typeshed/stdlib/bz2.pyi b/mypy/typeshed/stdlib/bz2.pyi index c49832759fa8..6aeaa3da4c60 100644 --- a/mypy/typeshed/stdlib/bz2.pyi +++ b/mypy/typeshed/stdlib/bz2.pyi @@ -80,6 +80,15 @@ def open( errors: str | None = ..., newline: str | None = ..., ) -> TextIO: ... +@overload +def open( + filename: StrOrBytesPath | _ReadableFileobj | _WritableFileobj, + mode: str, + compresslevel: int = ..., + encoding: str | None = ..., + errors: str | None = ..., + newline: str | None = ..., +) -> BZ2File | TextIO: ... class BZ2File(BaseStream, IO[bytes]): def __enter__(self: Self) -> Self: ... @@ -111,7 +120,7 @@ class BZ2File(BaseStream, IO[bytes]): ) -> None: ... def read(self, size: int | None = ...) -> bytes: ... def read1(self, size: int = ...) -> bytes: ... - def readline(self, size: SupportsIndex = ...) -> bytes: ... # type: ignore + def readline(self, size: SupportsIndex = ...) -> bytes: ... # type: ignore[override] def readinto(self, b: WriteableBuffer) -> int: ... def readlines(self, size: SupportsIndex = ...) -> list[bytes]: ... def seek(self, offset: int, whence: int = ...) -> int: ... @@ -119,13 +128,13 @@ class BZ2File(BaseStream, IO[bytes]): def writelines(self, seq: Iterable[ReadableBuffer]) -> None: ... @final -class BZ2Compressor(object): +class BZ2Compressor: def __init__(self, compresslevel: int = ...) -> None: ... def compress(self, __data: bytes) -> bytes: ... def flush(self) -> bytes: ... @final -class BZ2Decompressor(object): +class BZ2Decompressor: def decompress(self, data: bytes, max_length: int = ...) -> bytes: ... @property def eof(self) -> bool: ... diff --git a/mypy/typeshed/stdlib/cProfile.pyi b/mypy/typeshed/stdlib/cProfile.pyi index f4a7ab50cc11..e79524aa793e 100644 --- a/mypy/typeshed/stdlib/cProfile.pyi +++ b/mypy/typeshed/stdlib/cProfile.pyi @@ -1,7 +1,7 @@ import sys from _typeshed import Self, StrOrBytesPath from types import CodeType -from typing import Any, Callable, Tuple, TypeVar +from typing import Any, Callable, TypeVar def run(statement: str, filename: str | None = ..., sort: str | int = ...) -> None: ... def runctx( @@ -9,7 +9,7 @@ def runctx( ) -> None: ... _T = TypeVar("_T") -_Label = Tuple[str, int, str] +_Label = tuple[str, int, str] class Profile: stats: dict[_Label, tuple[int, int, int, int, dict[_Label, tuple[int, int, int, int]]]] # undocumented diff --git a/mypy/typeshed/stdlib/calendar.pyi b/mypy/typeshed/stdlib/calendar.pyi index 26073fb7281b..aa37928b87b1 100644 --- a/mypy/typeshed/stdlib/calendar.pyi +++ b/mypy/typeshed/stdlib/calendar.pyi @@ -1,9 +1,9 @@ import datetime import sys from time import struct_time -from typing import Any, Iterable, Optional, Sequence, Tuple +from typing import Any, Iterable, Optional, Sequence -_LocaleType = Tuple[Optional[str], Optional[str]] +_LocaleType = tuple[Optional[str], Optional[str]] class IllegalMonthError(ValueError): def __init__(self, month: int) -> None: ... @@ -97,7 +97,7 @@ c: TextCalendar def setfirstweekday(firstweekday: int) -> None: ... def format(cols: int, colwidth: int = ..., spacing: int = ...) -> str: ... def formatstring(cols: int, colwidth: int = ..., spacing: int = ...) -> str: ... -def timegm(tuple: Tuple[int, ...] | struct_time) -> int: ... +def timegm(tuple: tuple[int, ...] | struct_time) -> int: ... # Data attributes day_name: Sequence[str] diff --git a/mypy/typeshed/stdlib/cgi.pyi b/mypy/typeshed/stdlib/cgi.pyi index 3821de46ed75..c2c3ac261010 100644 --- a/mypy/typeshed/stdlib/cgi.pyi +++ b/mypy/typeshed/stdlib/cgi.pyi @@ -57,7 +57,7 @@ class MiniFieldStorage: _list = list -class FieldStorage(object): +class FieldStorage: FieldStorageClass: _type | None keep_blank_values: int strict_parsing: int diff --git a/mypy/typeshed/stdlib/cgitb.pyi b/mypy/typeshed/stdlib/cgitb.pyi index 7576740fc1c0..a8f3912aa04c 100644 --- a/mypy/typeshed/stdlib/cgitb.pyi +++ b/mypy/typeshed/stdlib/cgitb.pyi @@ -1,8 +1,8 @@ from _typeshed import StrOrBytesPath from types import FrameType, TracebackType -from typing import IO, Any, Callable, Optional, Tuple, Type +from typing import IO, Any, Callable, Optional, Type -_ExcInfo = Tuple[Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]] +_ExcInfo = tuple[Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]] def reset() -> str: ... # undocumented def small(text: str) -> str: ... # undocumented diff --git a/mypy/typeshed/stdlib/codecs.pyi b/mypy/typeshed/stdlib/codecs.pyi index ebd6911c3e63..e08672e51428 100644 --- a/mypy/typeshed/stdlib/codecs.pyi +++ b/mypy/typeshed/stdlib/codecs.pyi @@ -2,9 +2,14 @@ import sys import types from _typeshed import Self from abc import abstractmethod -from typing import IO, Any, BinaryIO, Callable, Generator, Iterable, Iterator, Protocol, TextIO, Tuple, Type, TypeVar, overload +from typing import IO, Any, BinaryIO, Callable, Generator, Iterable, Iterator, Protocol, TextIO, Type, TypeVar, overload from typing_extensions import Literal +BOM32_BE: bytes +BOM32_LE: bytes +BOM64_BE: bytes +BOM64_LE: bytes + # TODO: this only satisfies the most common interface, where # bytes is the raw form and str is the cooked form. # In the long run, both should become template parameters maybe? @@ -53,11 +58,11 @@ _BytesToBytesEncodingT = Literal[ @overload def encode(obj: bytes, encoding: _BytesToBytesEncodingT, errors: str = ...) -> bytes: ... @overload -def encode(obj: str, encoding: Literal["rot13", "rot_13"] = ..., errors: str = ...) -> str: ... # type: ignore +def encode(obj: str, encoding: Literal["rot13", "rot_13"] = ..., errors: str = ...) -> str: ... # type: ignore[misc] @overload def encode(obj: str, encoding: str = ..., errors: str = ...) -> bytes: ... @overload -def decode(obj: bytes, encoding: _BytesToBytesEncodingT, errors: str = ...) -> bytes: ... # type: ignore +def decode(obj: bytes, encoding: _BytesToBytesEncodingT, errors: str = ...) -> bytes: ... # type: ignore[misc] @overload def decode(obj: str, encoding: Literal["rot13", "rot_13"] = ..., errors: str = ...) -> str: ... @overload @@ -66,7 +71,7 @@ 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 -class CodecInfo(Tuple[_Encoder, _Decoder, _StreamReader, _StreamWriter]): +class CodecInfo(tuple[_Encoder, _Decoder, _StreamReader, _StreamWriter]): @property def encode(self) -> _Encoder: ... @property diff --git a/mypy/typeshed/stdlib/collections/__init__.pyi b/mypy/typeshed/stdlib/collections/__init__.pyi index 66a76941beee..adcdf29fa690 100644 --- a/mypy/typeshed/stdlib/collections/__init__.pyi +++ b/mypy/typeshed/stdlib/collections/__init__.pyi @@ -1,8 +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 +from _typeshed import Self, SupportsKeysAndGetItem, SupportsRichComparison, SupportsRichComparisonT +from typing import Any, Generic, NoReturn, Type, TypeVar, overload +from typing_extensions import SupportsIndex, final + +if sys.version_info >= (3, 9): + from types import GenericAlias if sys.version_info >= (3, 10): from typing import Callable, Iterable, Iterator, Mapping, MutableMapping, MutableSequence, Reversible, Sequence @@ -25,16 +28,26 @@ if sys.version_info >= (3, 7): rename: bool = ..., module: str | None = ..., defaults: Iterable[Any] | None = ..., - ) -> Type[Tuple[Any, ...]]: ... + ) -> Type[tuple[Any, ...]]: ... else: def namedtuple( typename: str, field_names: str | Iterable[str], *, verbose: bool = ..., rename: bool = ..., module: str | None = ... - ) -> Type[Tuple[Any, ...]]: ... + ) -> Type[tuple[Any, ...]]: ... -class UserDict(MutableMapping[_KT, _VT]): +class UserDict(MutableMapping[_KT, _VT], Generic[_KT, _VT]): data: dict[_KT, _VT] - def __init__(self, __dict: Mapping[_KT, _VT] | None = ..., **kwargs: _VT) -> None: ... + # __init__ should be kept roughly in line with `dict.__init__`, which has the same semantics + @overload + def __init__(self: UserDict[_KT, _VT], __dict: None = ...) -> None: ... + @overload + def __init__(self: UserDict[str, _VT], __dict: None = ..., **kwargs: _VT) -> None: ... + @overload + def __init__(self, __dict: SupportsKeysAndGetItem[_KT, _VT], **kwargs: _VT) -> None: ... + @overload + def __init__(self, __iterable: Iterable[tuple[_KT, _VT]], **kwargs: _VT) -> None: ... + @overload + def __init__(self: UserDict[str, str], __iterable: Iterable[list[str]]) -> None: ... def __len__(self) -> int: ... def __getitem__(self, key: _KT) -> _VT: ... def __setitem__(self, key: _KT, item: _VT) -> None: ... @@ -42,27 +55,34 @@ class UserDict(MutableMapping[_KT, _VT]): def __iter__(self) -> Iterator[_KT]: ... def __contains__(self, key: object) -> bool: ... def copy(self: Self) -> Self: ... + # `UserDict.fromkeys` has the same semantics as `dict.fromkeys`, so should be kept in line with `dict.fromkeys`. + # TODO: Much like `dict.fromkeys`, the true signature of `UserDict.fromkeys` is inexpressable in the current type system. + # See #3800 & https://github.com/python/typing/issues/548#issuecomment-683336963. + @classmethod + @overload + def fromkeys(cls, iterable: Iterable[_T], value: None = ...) -> UserDict[_T, Any | None]: ... @classmethod - def fromkeys(cls: Type[Self], iterable: Iterable[_KT], value: _VT | None = ...) -> Self: ... + @overload + def fromkeys(cls, iterable: Iterable[_T], value: _S) -> UserDict[_T, _S]: ... class UserList(MutableSequence[_T]): data: list[_T] def __init__(self, initlist: Iterable[_T] | None = ...) -> None: ... - def __lt__(self, other: object) -> bool: ... - def __le__(self, other: object) -> bool: ... - def __gt__(self, other: object) -> bool: ... - def __ge__(self, other: object) -> bool: ... + def __lt__(self, other: list[_T] | UserList[_T]) -> bool: ... + def __le__(self, other: list[_T] | UserList[_T]) -> bool: ... + def __gt__(self, other: list[_T] | UserList[_T]) -> bool: ... + def __ge__(self, other: list[_T] | UserList[_T]) -> bool: ... def __contains__(self, item: object) -> bool: ... def __len__(self) -> int: ... @overload - def __getitem__(self, i: int) -> _T: ... + def __getitem__(self, i: SupportsIndex) -> _T: ... @overload def __getitem__(self: Self, i: slice) -> Self: ... @overload - def __setitem__(self, i: int, o: _T) -> None: ... + def __setitem__(self, i: SupportsIndex, o: _T) -> None: ... @overload def __setitem__(self, i: slice, o: Iterable[_T]) -> None: ... - def __delitem__(self, i: int | slice) -> None: ... + def __delitem__(self, i: SupportsIndex | slice) -> None: ... def __add__(self: _S, other: Iterable[_T]) -> _S: ... def __iadd__(self: _S, other: Iterable[_T]) -> _S: ... def __mul__(self: _S, n: int) -> _S: ... @@ -71,12 +91,15 @@ class UserList(MutableSequence[_T]): def insert(self, i: int, item: _T) -> None: ... def pop(self, i: int = ...) -> _T: ... def remove(self, item: _T) -> None: ... - def clear(self) -> None: ... def copy(self: _S) -> _S: ... def count(self, item: _T) -> int: ... - def index(self, item: _T, *args: Any) -> int: ... - def reverse(self) -> None: ... - def sort(self, *args: Any, **kwds: Any) -> None: ... + # All arguments are passed to `list.index` at runtime, so the signature should be kept in line with `list.index`. + def index(self, item: _T, __start: SupportsIndex = ..., __stop: SupportsIndex = ...) -> int: ... + # All arguments are passed to `list.sort` at runtime, so the signature should be kept in line with `list.sort`. + @overload + def sort(self: UserList[SupportsRichComparisonT], *, key: None = ..., reverse: bool = ...) -> None: ... + @overload + def sort(self, *, key: Callable[[_T], SupportsRichComparison], reverse: bool = ...) -> None: ... def extend(self, other: Iterable[_T]) -> None: ... _UserStringT = TypeVar("_UserStringT", bound=UserString) @@ -95,9 +118,9 @@ class UserString(Sequence[str]): def __contains__(self, char: object) -> bool: ... def __len__(self) -> int: ... # It should return a str to implement Sequence correctly, but it doesn't. - def __getitem__(self: _UserStringT, i: int | slice) -> _UserStringT: ... # type: ignore - def __iter__(self: _UserStringT) -> Iterator[_UserStringT]: ... # type: ignore - def __reversed__(self: _UserStringT) -> Iterator[_UserStringT]: ... # type: ignore + def __getitem__(self: _UserStringT, i: SupportsIndex | slice) -> _UserStringT: ... # type: ignore[override] + def __iter__(self: _UserStringT) -> Iterator[_UserStringT]: ... # type: ignore[override] + def __reversed__(self: _UserStringT) -> Iterator[_UserStringT]: ... # type: ignore[override] def __add__(self: _UserStringT, other: object) -> _UserStringT: ... def __mul__(self: _UserStringT, n: int) -> _UserStringT: ... def __mod__(self: _UserStringT, args: Any) -> _UserStringT: ... @@ -109,7 +132,7 @@ class UserString(Sequence[str]): def encode(self: UserString, encoding: str | None = ..., errors: str | None = ...) -> bytes: ... else: def encode(self: _UserStringT, encoding: str | None = ..., errors: str | None = ...) -> _UserStringT: ... - def endswith(self, suffix: str | Tuple[str, ...], start: int | None = ..., end: int | None = ...) -> bool: ... + def endswith(self, suffix: str | tuple[str, ...], start: int | None = ..., end: int | None = ...) -> bool: ... def expandtabs(self: _UserStringT, tabsize: int = ...) -> _UserStringT: ... def find(self, sub: str | UserString, start: int = ..., end: int = ...) -> int: ... def format(self, *args: Any, **kwds: Any) -> str: ... @@ -126,6 +149,8 @@ class UserString(Sequence[str]): def isspace(self) -> bool: ... def istitle(self) -> bool: ... def isupper(self) -> bool: ... + if sys.version_info >= (3, 7): + def isascii(self) -> bool: ... def join(self, seq: Iterable[str]) -> str: ... def ljust(self: _UserStringT, width: int, *args: Any) -> _UserStringT: ... def lower(self: _UserStringT) -> _UserStringT: ... @@ -149,7 +174,7 @@ class UserString(Sequence[str]): def split(self, sep: str | None = ..., maxsplit: int = ...) -> list[str]: ... def rsplit(self, sep: str | None = ..., maxsplit: int = ...) -> list[str]: ... def splitlines(self, keepends: bool = ...) -> list[str]: ... - def startswith(self, prefix: str | Tuple[str, ...], start: int | None = ..., end: int | None = ...) -> bool: ... + def startswith(self, prefix: str | tuple[str, ...], start: int | None = ..., end: int | None = ...) -> bool: ... def strip(self: _UserStringT, chars: str | None = ...) -> _UserStringT: ... def swapcase(self: _UserStringT) -> _UserStringT: ... def title(self: _UserStringT) -> _UserStringT: ... @@ -163,56 +188,44 @@ class deque(MutableSequence[_T], Generic[_T]): def __init__(self, iterable: Iterable[_T] = ..., maxlen: int | None = ...) -> None: ... def append(self, __x: _T) -> None: ... def appendleft(self, __x: _T) -> None: ... - def clear(self) -> None: ... 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 pop(self) -> _T: ... # type: ignore[override] def popleft(self) -> _T: ... def remove(self, __value: _T) -> None: ... - def reverse(self) -> 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: ... - @overload - def __getitem__(self, __s: slice) -> MutableSequence[_T]: ... - @overload - def __setitem__(self, __i: int, __x: _T) -> None: ... - @overload - def __setitem__(self, __s: slice, __o: Iterable[_T]) -> None: ... - @overload - def __delitem__(self, __i: int) -> None: ... - @overload - def __delitem__(self, __s: slice) -> None: ... + # These methods of deque don't take slices, unlike MutableSequence, hence the type: ignores + def __getitem__(self, __index: SupportsIndex) -> _T: ... # type: ignore[override] + def __setitem__(self, __i: SupportsIndex, __x: _T) -> None: ... # type: ignore[override] + def __delitem__(self, __i: SupportsIndex) -> None: ... # type: ignore[override] 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: _S, __other: _S) -> _S: ... def __mul__(self: _S, __other: int) -> _S: ... def __imul__(self: _S, __other: int) -> _S: ... + if sys.version_info >= (3, 9): + def __class_getitem__(cls, __item: Any) -> GenericAlias: ... -class Counter(Dict[_T, int], Generic[_T]): +class Counter(dict[_T, int], Generic[_T]): @overload def __init__(self, __iterable: None = ..., **kwargs: int) -> None: ... @overload - def __init__(self, __mapping: Mapping[_T, int]) -> None: ... + def __init__(self, __mapping: SupportsKeysAndGetItem[_T, int]) -> None: ... @overload def __init__(self, __iterable: Iterable[_T]) -> None: ... def copy(self: Self) -> Self: ... def elements(self) -> Iterator[_T]: ... def most_common(self, n: int | None = ...) -> list[tuple[_T, int]]: ... @classmethod - def fromkeys(cls, iterable: Any, v: int | None = ...) -> NoReturn: ... # type: ignore + def fromkeys(cls, iterable: Any, v: int | None = ...) -> NoReturn: ... # type: ignore[override] @overload def subtract(self, __iterable: None = ...) -> None: ... @overload @@ -225,7 +238,7 @@ class Counter(Dict[_T, int], Generic[_T]): # Dict.update. Not sure if we should use '# type: ignore' instead # and omit the type from the union. @overload - def update(self, __m: Mapping[_T, int], **kwargs: int) -> None: ... + def update(self, __m: SupportsKeysAndGetItem[_T, int], **kwargs: int) -> None: ... @overload def update(self, __m: Iterable[_T] | Iterable[tuple[_T, int]], **kwargs: int) -> None: ... @overload @@ -233,27 +246,29 @@ class Counter(Dict[_T, int], Generic[_T]): def __add__(self, other: Counter[_T]) -> Counter[_T]: ... def __sub__(self, other: Counter[_T]) -> Counter[_T]: ... def __and__(self, other: Counter[_T]) -> Counter[_T]: ... - def __or__(self, other: Counter[_T]) -> Counter[_T]: ... # type: ignore + def __or__(self, other: Counter[_T]) -> Counter[_T]: ... # type: ignore[override] def __pos__(self) -> Counter[_T]: ... def __neg__(self) -> Counter[_T]: ... def __iadd__(self, other: Counter[_T]) -> Counter[_T]: ... def __isub__(self, other: Counter[_T]) -> Counter[_T]: ... def __iand__(self, other: Counter[_T]) -> Counter[_T]: ... - def __ior__(self, other: Counter[_T]) -> Counter[_T]: ... # type: ignore + def __ior__(self, other: Counter[_T]) -> Counter[_T]: ... # type: ignore[override] + if sys.version_info >= (3, 10): + def total(self) -> int: ... @final class _OrderedDictKeysView(dict_keys[_KT_co, _VT_co], Reversible[_KT_co]): # type: ignore[misc] def __reversed__(self) -> Iterator[_KT_co]: ... @final -class _OrderedDictItemsView(dict_items[_KT_co, _VT_co], Reversible[Tuple[_KT_co, _VT_co]]): # type: ignore[misc] +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]]: ... @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]): +class OrderedDict(dict[_KT, _VT], Reversible[_KT], Generic[_KT, _VT]): def popitem(self, last: bool = ...) -> tuple[_KT, _VT]: ... def move_to_end(self, key: _KT, last: bool = ...) -> None: ... def copy(self: Self) -> Self: ... @@ -261,8 +276,17 @@ class OrderedDict(Dict[_KT, _VT], Reversible[_KT], Generic[_KT, _VT]): def keys(self) -> _OrderedDictKeysView[_KT, _VT]: ... def items(self) -> _OrderedDictItemsView[_KT, _VT]: ... def values(self) -> _OrderedDictValuesView[_KT, _VT]: ... + # `fromkeys` is actually inherited from `dict` at runtime, so the signature should be kept in line with `dict.fromkeys`. + # Ideally we would not redefine it here, but the true signature of `dict.fromkeys` is not expressable in the current type system. + # See #3800 & https://github.com/python/typing/issues/548#issuecomment-683336963. + @classmethod + @overload + def fromkeys(cls, __iterable: Iterable[_T], __value: None = ...) -> OrderedDict[_T, Any | None]: ... + @classmethod + @overload + def fromkeys(cls, __iterable: Iterable[_T], __value: _S) -> OrderedDict[_T, _S]: ... -class defaultdict(Dict[_KT, _VT], Generic[_KT, _VT]): +class defaultdict(dict[_KT, _VT], Generic[_KT, _VT]): default_factory: Callable[[], _VT] | None @overload def __init__(self, **kwargs: _VT) -> None: ... @@ -271,9 +295,11 @@ class defaultdict(Dict[_KT, _VT], Generic[_KT, _VT]): @overload 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: SupportsKeysAndGetItem[_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: SupportsKeysAndGetItem[_KT, _VT], **kwargs: _VT + ) -> None: ... @overload def __init__(self, __default_factory: Callable[[], _VT] | None, __iterable: Iterable[tuple[_KT, _VT]]) -> None: ... @overload @@ -301,3 +327,11 @@ class ChainMap(MutableMapping[_KT, _VT], Generic[_KT, _VT]): def pop(self, key: _KT) -> _VT: ... @overload def pop(self, key: _KT, default: _VT | _T = ...) -> _VT | _T: ... + def copy(self: Self) -> Self: ... + # All arguments to `fromkeys` are passed to `dict.fromkeys` at runtime, so the signature should be kept in line with `dict.fromkeys`. + @classmethod + @overload + def fromkeys(cls, iterable: Iterable[_T], __value: None = ...) -> ChainMap[_T, Any | None]: ... + @classmethod + @overload + def fromkeys(cls, __iterable: Iterable[_T], __value: _S) -> ChainMap[_T, _S]: ... diff --git a/mypy/typeshed/stdlib/concurrent/futures/_base.pyi b/mypy/typeshed/stdlib/concurrent/futures/_base.pyi index fd7333420b39..b55351aacc6f 100644 --- a/mypy/typeshed/stdlib/concurrent/futures/_base.pyi +++ b/mypy/typeshed/stdlib/concurrent/futures/_base.pyi @@ -4,19 +4,20 @@ from _typeshed import Self from abc import abstractmethod from collections.abc import Container, Iterable, Iterator, Sequence from logging import Logger -from typing import Any, Callable, Generic, Protocol, Set, TypeVar, overload +from typing import Any, Callable, Generic, Protocol, TypeVar, overload +from typing_extensions import Literal, SupportsIndex if sys.version_info >= (3, 9): from types import GenericAlias -FIRST_COMPLETED: str -FIRST_EXCEPTION: str -ALL_COMPLETED: str -PENDING: str -RUNNING: str -CANCELLED: str -CANCELLED_AND_NOTIFIED: str -FINISHED: str +FIRST_COMPLETED: Literal["FIRST_COMPLETED"] +FIRST_EXCEPTION: Literal["FIRST_EXCEPTION"] +ALL_COMPLETED: Literal["ALL_COMPLETED"] +PENDING: Literal["PENDING"] +RUNNING: Literal["RUNNING"] +CANCELLED: Literal["CANCELLED"] +CANCELLED_AND_NOTIFIED: Literal["CANCELLED_AND_NOTIFIED"] +FINISHED: Literal["FINISHED"] _FUTURE_STATES: list[str] _STATE_TO_DESCRIPTION_MAP: dict[str, str] LOGGER: Logger @@ -75,13 +76,13 @@ class Executor: def as_completed(fs: Iterable[Future[_T]], timeout: float | None = ...) -> Iterator[Future[_T]]: ... # Ideally this would be a namedtuple, but mypy doesn't support generic tuple types. See #1976 -class DoneAndNotDoneFutures(Sequence[Set[Future[_T]]]): +class DoneAndNotDoneFutures(Sequence[set[Future[_T]]]): done: set[Future[_T]] not_done: set[Future[_T]] def __new__(_cls, done: set[Future[_T]], not_done: set[Future[_T]]) -> DoneAndNotDoneFutures[_T]: ... def __len__(self) -> int: ... @overload - def __getitem__(self, i: int) -> set[Future[_T]]: ... + def __getitem__(self, i: SupportsIndex) -> set[Future[_T]]: ... @overload def __getitem__(self, s: slice) -> DoneAndNotDoneFutures[_T]: ... diff --git a/mypy/typeshed/stdlib/concurrent/futures/process.pyi b/mypy/typeshed/stdlib/concurrent/futures/process.pyi index cc48f48f0023..6435901a8f13 100644 --- a/mypy/typeshed/stdlib/concurrent/futures/process.pyi +++ b/mypy/typeshed/stdlib/concurrent/futures/process.pyi @@ -5,7 +5,7 @@ from multiprocessing.context import BaseContext, Process from multiprocessing.queues import Queue, SimpleQueue from threading import Lock, Semaphore, Thread from types import TracebackType -from typing import Any, Callable, Generic, Tuple, TypeVar +from typing import Any, Callable, Generic, TypeVar from weakref import ref from ._base import Executor, Future @@ -37,7 +37,7 @@ class _ExceptionWithTraceback: exc: BaseException tb: TracebackType def __init__(self, exc: BaseException, tb: TracebackType) -> None: ... - def __reduce__(self) -> str | Tuple[Any, ...]: ... + def __reduce__(self) -> str | tuple[Any, ...]: ... def _rebuild_exc(exc: Exception, tb: str) -> Exception: ... @@ -84,7 +84,7 @@ if sys.version_info >= (3, 7): ) -> None: ... def _on_queue_feeder_error(self, e: Exception, obj: _CallItem) -> None: ... -def _get_chunks(*iterables: Any, chunksize: int) -> Generator[Tuple[Any, ...], None, 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 _sendback_result( result_queue: SimpleQueue[_WorkItem[Any]], work_id: int, result: Any | None = ..., exception: Exception | None = ... @@ -95,7 +95,7 @@ if sys.version_info >= (3, 7): call_queue: Queue[_CallItem], result_queue: SimpleQueue[_ResultItem], initializer: Callable[..., None] | None, - initargs: Tuple[Any, ...], + initargs: tuple[Any, ...], ) -> None: ... else: @@ -139,7 +139,7 @@ else: class ProcessPoolExecutor(Executor): _mp_context: BaseContext | None = ... _initializer: Callable[..., None] | None = ... - _initargs: Tuple[Any, ...] = ... + _initargs: tuple[Any, ...] = ... _executor_manager_thread: _ThreadWakeup _processes: MutableMapping[int, Process] _shutdown_thread: bool @@ -158,7 +158,7 @@ class ProcessPoolExecutor(Executor): max_workers: int | None = ..., mp_context: BaseContext | None = ..., initializer: Callable[..., None] | None = ..., - initargs: Tuple[Any, ...] = ..., + initargs: tuple[Any, ...] = ..., ) -> None: ... else: def __init__(self, max_workers: int | None = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/concurrent/futures/thread.pyi b/mypy/typeshed/stdlib/concurrent/futures/thread.pyi index 5ad5b65d3bec..f27c43c3403c 100644 --- a/mypy/typeshed/stdlib/concurrent/futures/thread.pyi +++ b/mypy/typeshed/stdlib/concurrent/futures/thread.pyi @@ -1,8 +1,8 @@ import queue import sys -from collections.abc import Iterable, Mapping, Set # equivalent to typing.AbstractSet, not builtins.set +from collections.abc import Iterable, Mapping, Set as AbstractSet from threading import Lock, Semaphore, Thread -from typing import Any, Callable, Generic, Tuple, TypeVar +from typing import Any, Callable, Generic, TypeVar from weakref import ref from ._base import Executor, Future @@ -33,7 +33,7 @@ if sys.version_info >= (3, 7): executor_reference: ref[Any], work_queue: queue.SimpleQueue[Any], initializer: Callable[..., None], - initargs: Tuple[Any, ...], + initargs: tuple[Any, ...], ) -> None: ... else: @@ -46,13 +46,13 @@ if sys.version_info >= (3, 7): class ThreadPoolExecutor(Executor): _max_workers: int _idle_semaphore: Semaphore - _threads: Set[Thread] + _threads: AbstractSet[Thread] _broken: bool _shutdown: bool _shutdown_lock: Lock _thread_name_prefix: str | None = ... _initializer: Callable[..., None] | None = ... - _initargs: Tuple[Any, ...] = ... + _initargs: tuple[Any, ...] = ... if sys.version_info >= (3, 7): _work_queue: queue.SimpleQueue[_WorkItem[Any]] else: @@ -63,7 +63,7 @@ class ThreadPoolExecutor(Executor): max_workers: int | None = ..., thread_name_prefix: str = ..., initializer: Callable[..., None] | None = ..., - initargs: Tuple[Any, ...] = ..., + initargs: tuple[Any, ...] = ..., ) -> None: ... else: def __init__(self, max_workers: int | None = ..., thread_name_prefix: str = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/configparser.pyi b/mypy/typeshed/stdlib/configparser.pyi index a0efa30416dd..dc81cb78577a 100644 --- a/mypy/typeshed/stdlib/configparser.pyi +++ b/mypy/typeshed/stdlib/configparser.pyi @@ -1,14 +1,14 @@ 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, Type, TypeVar, overload +from typing import Any, ClassVar, Optional, Pattern, Type, TypeVar, overload from typing_extensions import Literal # Internal type aliases _section = Mapping[str, str] _parser = MutableMapping[str, _section] _converter = Callable[[str], Any] -_converters = Dict[str, _converter] +_converters = dict[str, _converter] _T = TypeVar("_T") if sys.version_info >= (3, 7): @@ -122,7 +122,7 @@ class RawConfigParser(_parser): fallback: _T = ..., ) -> _T: ... # This is incompatible with MutableMapping so we ignore the type - @overload # type: ignore + @overload # type: ignore[override] def get(self, section: str, option: str, *, raw: bool = ..., vars: _section | None = ...) -> str: ... @overload def get(self, section: str, option: str, *, raw: bool = ..., vars: _section | None = ..., fallback: _T) -> str | _T: ... @@ -137,7 +137,9 @@ class RawConfigParser(_parser): def optionxform(self, optionstr: str) -> str: ... class ConfigParser(RawConfigParser): ... -class SafeConfigParser(ConfigParser): ... + +if sys.version_info < (3, 11): + class SafeConfigParser(ConfigParser): ... class SectionProxy(MutableMapping[str, str]): def __init__(self, parser: RawConfigParser, name: str) -> None: ... @@ -151,7 +153,16 @@ class SectionProxy(MutableMapping[str, str]): def parser(self) -> RawConfigParser: ... @property def name(self) -> str: ... - def get(self, option: str, fallback: str | None = ..., *, raw: bool = ..., vars: _section | None = ..., _impl: Any | None = ..., **kwargs: Any) -> str: ... # type: ignore + def get( # type: ignore[override] + self, + option: str, + fallback: str | None = ..., + *, + raw: bool = ..., + vars: _section | None = ..., + _impl: Any | None = ..., + **kwargs: Any, + ) -> str: ... # These are partially-applied version of the methods with the same names in # RawConfigParser; the stubs should be kept updated together @overload diff --git a/mypy/typeshed/stdlib/contextlib.pyi b/mypy/typeshed/stdlib/contextlib.pyi index 9d968e092ca5..b536c36678a2 100644 --- a/mypy/typeshed/stdlib/contextlib.pyi +++ b/mypy/typeshed/stdlib/contextlib.pyi @@ -4,18 +4,21 @@ from types import TracebackType from typing import ( IO, Any, + AsyncGenerator, AsyncIterator, Awaitable, Callable, ContextManager, + Generator, Generic, Iterator, Optional, + Protocol, Type, TypeVar, overload, ) -from typing_extensions import ParamSpec, Protocol +from typing_extensions import ParamSpec AbstractContextManager = ContextManager if sys.version_info >= (3, 7): @@ -32,14 +35,44 @@ _P = ParamSpec("_P") _ExitFunc = Callable[[Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]], bool] _CM_EF = TypeVar("_CM_EF", AbstractContextManager[Any], _ExitFunc) -class _GeneratorContextManager(AbstractContextManager[_T_co]): +class ContextDecorator: 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 +class _GeneratorContextManager(AbstractContextManager[_T_co], ContextDecorator, Generic[_T_co]): + # In Python <= 3.6, __init__ and all instance attributes are defined directly on this class. + # In Python >= 3.7, __init__ and all instance attributes are inherited from _GeneratorContextManagerBase + # _GeneratorContextManagerBase is more trouble than it's worth to include in the stub; see #6676 + def __init__(self, func: Callable[..., Iterator[_T_co]], args: tuple[Any, ...], kwds: dict[str, Any]) -> None: ... + gen: Generator[_T_co, Any, Any] + func: Callable[..., Generator[_T_co, Any, Any]] + args: tuple[Any, ...] + kwds: dict[str, Any] + +def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... + +if sys.version_info >= (3, 10): + _AF = TypeVar("_AF", bound=Callable[..., Awaitable[Any]]) + class AsyncContextDecorator: + def __call__(self, func: _AF) -> _AF: ... + class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co], AsyncContextDecorator, Generic[_T_co]): + # __init__ and these attributes are actually defined in the base class _GeneratorContextManagerBase, + # which is more trouble than it's worth to include in the stub (see #6676) + def __init__(self, func: Callable[..., AsyncIterator[_T_co]], args: tuple[Any, ...], kwds: dict[str, Any]) -> None: ... + gen: AsyncGenerator[_T_co, Any] + func: Callable[..., AsyncGenerator[_T_co, Any]] + args: tuple[Any, ...] + kwds: dict[str, Any] + +elif sys.version_info >= (3, 7): + class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co], Generic[_T_co]): + def __init__(self, func: Callable[..., AsyncIterator[_T_co]], args: tuple[Any, ...], kwds: dict[str, Any]) -> None: ... + gen: AsyncGenerator[_T_co, Any] + func: Callable[..., AsyncGenerator[_T_co, Any]] + args: tuple[Any, ...] + kwds: dict[str, Any] if sys.version_info >= (3, 7): - def asynccontextmanager(func: Callable[_P, AsyncIterator[_T]]) -> Callable[_P, AbstractAsyncContextManager[_T]]: ... # type: ignore + def asynccontextmanager(func: Callable[_P, AsyncIterator[_T_co]]) -> Callable[_P, _AsyncGeneratorContextManager[_T_co]]: ... class _SupportsClose(Protocol): def close(self) -> object: ... @@ -55,9 +88,6 @@ if sys.version_info >= (3, 10): _SupportsAcloseT = TypeVar("_SupportsAcloseT", bound=_SupportsAclose) 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(AbstractContextManager[None]): def __init__(self, *exceptions: Type[BaseException]) -> None: ... @@ -71,9 +101,6 @@ class redirect_stdout(AbstractContextManager[_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(AbstractContextManager[ExitStack]): def __init__(self) -> None: ... def enter_context(self, cm: AbstractContextManager[_T]) -> _T: ... diff --git a/mypy/typeshed/stdlib/copyreg.pyi b/mypy/typeshed/stdlib/copyreg.pyi index 320097b3a204..6097670833c0 100644 --- a/mypy/typeshed/stdlib/copyreg.pyi +++ b/mypy/typeshed/stdlib/copyreg.pyi @@ -1,7 +1,7 @@ -from typing import Any, Callable, Hashable, Optional, SupportsInt, Tuple, TypeVar, Union +from typing import Any, Callable, Hashable, Optional, SupportsInt, TypeVar, Union _TypeT = TypeVar("_TypeT", bound=type) -_Reduce = Union[Tuple[Callable[..., _TypeT], Tuple[Any, ...]], Tuple[Callable[..., _TypeT], Tuple[Any, ...], Optional[Any]]] +_Reduce = Union[tuple[Callable[..., _TypeT], tuple[Any, ...]], tuple[Callable[..., _TypeT], tuple[Any, ...], Optional[Any]]] __all__: list[str] diff --git a/mypy/typeshed/stdlib/crypt.pyi b/mypy/typeshed/stdlib/crypt.pyi index 27e30433f702..a8342859e770 100644 --- a/mypy/typeshed/stdlib/crypt.pyi +++ b/mypy/typeshed/stdlib/crypt.pyi @@ -1,20 +1,18 @@ import sys -class _Method: ... +if sys.platform != "win32": + class _Method: ... + METHOD_CRYPT: _Method + METHOD_MD5: _Method + METHOD_SHA256: _Method + METHOD_SHA512: _Method + if sys.version_info >= (3, 7): + METHOD_BLOWFISH: _Method -METHOD_CRYPT: _Method -METHOD_MD5: _Method -METHOD_SHA256: _Method -METHOD_SHA512: _Method -if sys.version_info >= (3, 7): - METHOD_BLOWFISH: _Method + methods: list[_Method] -methods: list[_Method] - -if sys.version_info >= (3, 7): - def mksalt(method: _Method | None = ..., *, rounds: int | None = ...) -> str: ... - -else: - def mksalt(method: _Method | None = ...) -> str: ... - -def crypt(word: str, salt: str | _Method | None = ...) -> str: ... + if sys.version_info >= (3, 7): + def mksalt(method: _Method | None = ..., *, rounds: int | None = ...) -> str: ... + else: + def mksalt(method: _Method | None = ...) -> str: ... + def crypt(word: str, salt: str | _Method | None = ...) -> str: ... diff --git a/mypy/typeshed/stdlib/csv.pyi b/mypy/typeshed/stdlib/csv.pyi index 0b69cb2272d3..63999be059f6 100644 --- a/mypy/typeshed/stdlib/csv.pyi +++ b/mypy/typeshed/stdlib/csv.pyi @@ -21,7 +21,7 @@ from collections.abc import Collection, Iterable, Iterator, Mapping, Sequence from typing import Any, Generic, Type, TypeVar, overload if sys.version_info >= (3, 8): - from typing import Dict as _DictReadMapping + from builtins import dict as _DictReadMapping else: from collections import OrderedDict as _DictReadMapping @@ -100,7 +100,7 @@ class DictWriter(Generic[_T]): def writerow(self, rowdict: Mapping[_T, Any]) -> Any: ... def writerows(self, rowdicts: Iterable[Mapping[_T, Any]]) -> None: ... -class Sniffer(object): +class Sniffer: preferred: list[str] def __init__(self) -> None: ... def sniff(self, sample: str, delimiters: str | None = ...) -> Type[Dialect]: ... diff --git a/mypy/typeshed/stdlib/ctypes/__init__.pyi b/mypy/typeshed/stdlib/ctypes/__init__.pyi index bbe083f5d4c4..7f2eba011d0f 100644 --- a/mypy/typeshed/stdlib/ctypes/__init__.pyi +++ b/mypy/typeshed/stdlib/ctypes/__init__.pyi @@ -1,5 +1,6 @@ import sys from _typeshed import ReadableBuffer, WriteableBuffer +from abc import abstractmethod from typing import ( Any, Callable, @@ -10,7 +11,6 @@ from typing import ( Mapping, Optional, Sequence, - Tuple, Type, TypeVar, Union as _UnionT, @@ -28,7 +28,7 @@ RTLD_GLOBAL: int RTLD_LOCAL: int DEFAULT_MODE: int -class CDLL(object): +class CDLL: _func_flags_: ClassVar[int] _func_restype_: ClassVar[_CData] _name: str @@ -76,8 +76,8 @@ class _CDataMeta(type): # By default mypy complains about the following two methods, because strictly speaking cls # might not be a Type[_CT]. However this can never actually happen, because the only class that # uses _CDataMeta as its metaclass is _CData. So it's safe to ignore the errors here. - def __mul__(cls: Type[_CT], other: int) -> Type[Array[_CT]]: ... # type: ignore - def __rmul__(cls: Type[_CT], other: int) -> Type[Array[_CT]]: ... # type: ignore + def __mul__(cls: Type[_CT], other: int) -> Type[Array[_CT]]: ... # type: ignore[misc] + def __rmul__(cls: Type[_CT], other: int) -> Type[Array[_CT]]: ... # type: ignore[misc] class _CData(metaclass=_CDataMeta): _b_base: int @@ -97,8 +97,8 @@ class _CData(metaclass=_CDataMeta): class _CanCastTo(_CData): ... class _PointerLike(_CanCastTo): ... -_ECT = Callable[[Optional[Type[_CData]], _FuncPointer, Tuple[_CData, ...]], _CData] -_PF = _UnionT[Tuple[int], Tuple[int, str], Tuple[int, str, Any]] +_ECT = Callable[[Optional[Type[_CData]], _FuncPointer, tuple[_CData, ...]], _CData] +_PF = _UnionT[tuple[int], tuple[int, str], tuple[int, str, Any]] class _FuncPointer(_PointerLike, _CData): restype: Type[_CData] | Callable[[int], Any] | None @@ -109,9 +109,9 @@ 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 __init__(self, vtlb_index: int, name: str, paramflags: tuple[_PF, ...] = ..., iid: pointer[c_int] = ...) -> None: ... def __call__(self, *args: Any, **kwargs: Any) -> Any: ... class _NamedFuncPointer(_FuncPointer): @@ -157,7 +157,7 @@ def create_unicode_buffer(init: int | str, size: int | None = ...) -> Array[c_wc if sys.platform == "win32": def DllCanUnloadNow() -> int: ... def DllGetClassObject(rclsid: Any, riid: Any, ppv: Any) -> int: ... # TODO not documented - def FormatError(code: int) -> str: ... + def FormatError(code: int = ...) -> str: ... def GetLastError() -> int: ... def get_errno() -> int: ... @@ -268,8 +268,16 @@ class BigEndianStructure(Structure): ... class LittleEndianStructure(Structure): ... class Array(Generic[_CT], _CData): - _length_: int - _type_: Type[_CT] + @property + @abstractmethod + def _length_(self) -> int: ... + @_length_.setter + def _length_(self, value: int) -> None: ... + @property + @abstractmethod + def _type_(self) -> Type[_CT]: ... + @_type_.setter + def _type_(self, value: Type[_CT]) -> None: ... 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/curses/__init__.pyi b/mypy/typeshed/stdlib/curses/__init__.pyi index 73e84fba3763..aef2d9b95ed5 100644 --- a/mypy/typeshed/stdlib/curses/__init__.pyi +++ b/mypy/typeshed/stdlib/curses/__init__.pyi @@ -1,15 +1,17 @@ -from _curses import * # noqa: F403 -from _curses import _CursesWindow as _CursesWindow +import sys from typing import Any, Callable, TypeVar -_T = TypeVar("_T") +if sys.platform != "win32": + from _curses import * # noqa: F403 + from _curses import _CursesWindow as _CursesWindow -# available after calling `curses.initscr()` -LINES: int -COLS: int + _T = TypeVar("_T") -# available after calling `curses.start_color()` -COLORS: int -COLOR_PAIRS: int + # available after calling `curses.initscr()` + LINES: int + COLS: int -def wrapper(__func: Callable[..., _T], *arg: Any, **kwds: Any) -> _T: ... + # available after calling `curses.start_color()` + COLORS: int + COLOR_PAIRS: int + def wrapper(__func: Callable[..., _T], *arg: Any, **kwds: Any) -> _T: ... diff --git a/mypy/typeshed/stdlib/curses/ascii.pyi b/mypy/typeshed/stdlib/curses/ascii.pyi index 66efbe36a7df..25de8f605bda 100644 --- a/mypy/typeshed/stdlib/curses/ascii.pyi +++ b/mypy/typeshed/stdlib/curses/ascii.pyi @@ -1,62 +1,63 @@ +import sys from typing import TypeVar -_CharT = TypeVar("_CharT", str, int) +if sys.platform != "win32": + _CharT = TypeVar("_CharT", str, int) -NUL: int -SOH: int -STX: int -ETX: int -EOT: int -ENQ: int -ACK: int -BEL: int -BS: int -TAB: int -HT: int -LF: int -NL: int -VT: int -FF: int -CR: int -SO: int -SI: int -DLE: int -DC1: int -DC2: int -DC3: int -DC4: int -NAK: int -SYN: int -ETB: int -CAN: int -EM: int -SUB: int -ESC: int -FS: int -GS: int -RS: int -US: int -SP: int -DEL: int + NUL: int + SOH: int + STX: int + ETX: int + EOT: int + ENQ: int + ACK: int + BEL: int + BS: int + TAB: int + HT: int + LF: int + NL: int + VT: int + FF: int + CR: int + SO: int + SI: int + DLE: int + DC1: int + DC2: int + DC3: int + DC4: int + NAK: int + SYN: int + ETB: int + CAN: int + EM: int + SUB: int + ESC: int + FS: int + GS: int + RS: int + US: int + SP: int + DEL: int -controlnames: list[int] - -def isalnum(c: str | int) -> bool: ... -def isalpha(c: str | int) -> bool: ... -def isascii(c: str | int) -> bool: ... -def isblank(c: str | int) -> bool: ... -def iscntrl(c: str | int) -> bool: ... -def isdigit(c: str | int) -> bool: ... -def isgraph(c: str | int) -> bool: ... -def islower(c: str | int) -> bool: ... -def isprint(c: str | int) -> bool: ... -def ispunct(c: str | int) -> bool: ... -def isspace(c: str | int) -> bool: ... -def isupper(c: str | int) -> bool: ... -def isxdigit(c: str | int) -> bool: ... -def isctrl(c: str | int) -> bool: ... -def ismeta(c: str | int) -> bool: ... -def ascii(c: _CharT) -> _CharT: ... -def ctrl(c: _CharT) -> _CharT: ... -def alt(c: _CharT) -> _CharT: ... -def unctrl(c: str | int) -> str: ... + controlnames: list[int] + def isalnum(c: str | int) -> bool: ... + def isalpha(c: str | int) -> bool: ... + def isascii(c: str | int) -> bool: ... + def isblank(c: str | int) -> bool: ... + def iscntrl(c: str | int) -> bool: ... + def isdigit(c: str | int) -> bool: ... + def isgraph(c: str | int) -> bool: ... + def islower(c: str | int) -> bool: ... + def isprint(c: str | int) -> bool: ... + def ispunct(c: str | int) -> bool: ... + def isspace(c: str | int) -> bool: ... + def isupper(c: str | int) -> bool: ... + def isxdigit(c: str | int) -> bool: ... + def isctrl(c: str | int) -> bool: ... + def ismeta(c: str | int) -> bool: ... + def ascii(c: _CharT) -> _CharT: ... + def ctrl(c: _CharT) -> _CharT: ... + def alt(c: _CharT) -> _CharT: ... + def unctrl(c: str | int) -> str: ... diff --git a/mypy/typeshed/stdlib/curses/panel.pyi b/mypy/typeshed/stdlib/curses/panel.pyi index 138e4a9f727e..ed13a6e050e9 100644 --- a/mypy/typeshed/stdlib/curses/panel.pyi +++ b/mypy/typeshed/stdlib/curses/panel.pyi @@ -1,20 +1,23 @@ -from _curses import _CursesWindow +import sys -class _Curses_Panel: # type is (note the space in the class name) - def above(self) -> _Curses_Panel: ... - def below(self) -> _Curses_Panel: ... - def bottom(self) -> None: ... - def hidden(self) -> bool: ... - def hide(self) -> None: ... - def move(self, y: int, x: int) -> None: ... - def replace(self, win: _CursesWindow) -> None: ... - def set_userptr(self, obj: object) -> None: ... - def show(self) -> None: ... - def top(self) -> None: ... - def userptr(self) -> object: ... - def window(self) -> _CursesWindow: ... +if sys.platform != "win32": + from _curses import _CursesWindow -def bottom_panel() -> _Curses_Panel: ... -def new_panel(__win: _CursesWindow) -> _Curses_Panel: ... -def top_panel() -> _Curses_Panel: ... -def update_panels() -> _Curses_Panel: ... + version: str + class _Curses_Panel: # type is (note the space in the class name) + def above(self) -> _Curses_Panel: ... + def below(self) -> _Curses_Panel: ... + def bottom(self) -> None: ... + def hidden(self) -> bool: ... + def hide(self) -> None: ... + def move(self, y: int, x: int) -> None: ... + def replace(self, win: _CursesWindow) -> None: ... + def set_userptr(self, obj: object) -> None: ... + def show(self) -> None: ... + def top(self) -> None: ... + def userptr(self) -> object: ... + def window(self) -> _CursesWindow: ... + def bottom_panel() -> _Curses_Panel: ... + def new_panel(__win: _CursesWindow) -> _Curses_Panel: ... + def top_panel() -> _Curses_Panel: ... + def update_panels() -> _Curses_Panel: ... diff --git a/mypy/typeshed/stdlib/curses/textpad.pyi b/mypy/typeshed/stdlib/curses/textpad.pyi index 578a579fda38..eb6879603853 100644 --- a/mypy/typeshed/stdlib/curses/textpad.pyi +++ b/mypy/typeshed/stdlib/curses/textpad.pyi @@ -1,11 +1,12 @@ -from _curses import _CursesWindow +import sys from typing import Callable -def rectangle(win: _CursesWindow, uly: int, ulx: int, lry: int, lrx: int) -> None: ... - -class Textbox: - stripspaces: bool - def __init__(self, win: _CursesWindow, insert_mode: bool = ...) -> None: ... - def edit(self, validate: Callable[[int], int] | None = ...) -> str: ... - def do_command(self, ch: str | int) -> None: ... - def gather(self) -> str: ... +if sys.platform != "win32": + from _curses import _CursesWindow + def rectangle(win: _CursesWindow, uly: int, ulx: int, lry: int, lrx: int) -> None: ... + class Textbox: + stripspaces: bool + def __init__(self, win: _CursesWindow, insert_mode: bool = ...) -> None: ... + def edit(self, validate: Callable[[int], int] | None = ...) -> str: ... + def do_command(self, ch: str | int) -> None: ... + def gather(self) -> str: ... diff --git a/mypy/typeshed/stdlib/dataclasses.pyi b/mypy/typeshed/stdlib/dataclasses.pyi index 59efbe77aed6..885facb9c0db 100644 --- a/mypy/typeshed/stdlib/dataclasses.pyi +++ b/mypy/typeshed/stdlib/dataclasses.pyi @@ -1,7 +1,6 @@ import sys import types -from typing import Any, Callable, Generic, Iterable, Mapping, Tuple, Type, TypeVar, overload -from typing_extensions import Protocol +from typing import Any, Callable, Generic, Iterable, Mapping, Protocol, Type, TypeVar, overload if sys.version_info >= (3, 9): from types import GenericAlias @@ -21,7 +20,7 @@ def asdict(obj: Any) -> dict[str, Any]: ... @overload def asdict(obj: Any, *, dict_factory: Callable[[list[tuple[str, Any]]], _T]) -> _T: ... @overload -def astuple(obj: Any) -> Tuple[Any, ...]: ... +def astuple(obj: Any) -> tuple[Any, ...]: ... @overload def astuple(obj: Any, *, tuple_factory: Callable[[list[Any]], _T]) -> _T: ... @@ -173,7 +172,7 @@ else: metadata: Mapping[Any, Any] | None = ..., ) -> Any: ... -def fields(class_or_instance: Any) -> Tuple[Field[Any], ...]: ... +def fields(class_or_instance: Any) -> tuple[Field[Any], ...]: ... def is_dataclass(obj: Any) -> bool: ... class FrozenInstanceError(AttributeError): ... @@ -192,7 +191,7 @@ if sys.version_info >= (3, 10): cls_name: str, fields: Iterable[str | tuple[str, type] | tuple[str, type, Field[Any]]], *, - bases: Tuple[type, ...] = ..., + bases: tuple[type, ...] = ..., namespace: dict[str, Any] | None = ..., init: bool = ..., repr: bool = ..., @@ -201,6 +200,7 @@ if sys.version_info >= (3, 10): unsafe_hash: bool = ..., frozen: bool = ..., match_args: bool = ..., + kw_only: bool = ..., slots: bool = ..., ) -> type: ... @@ -209,7 +209,7 @@ else: cls_name: str, fields: Iterable[str | tuple[str, type] | tuple[str, type, Field[Any]]], *, - bases: Tuple[type, ...] = ..., + bases: tuple[type, ...] = ..., namespace: dict[str, Any] | None = ..., init: bool = ..., repr: bool = ..., diff --git a/mypy/typeshed/stdlib/datetime.pyi b/mypy/typeshed/stdlib/datetime.pyi index bd4d47e051ec..e0ce085c2967 100644 --- a/mypy/typeshed/stdlib/datetime.pyi +++ b/mypy/typeshed/stdlib/datetime.pyi @@ -56,7 +56,7 @@ class date: @property def day(self) -> int: ... def ctime(self) -> str: ... - def strftime(self, fmt: str) -> str: ... + def strftime(self, __format: str) -> str: ... def __format__(self, __fmt: str) -> str: ... def isoformat(self) -> str: ... def timetuple(self) -> struct_time: ... @@ -128,7 +128,7 @@ class time: if sys.version_info >= (3, 7): @classmethod def fromisoformat(cls: Type[_S], __time_string: str) -> _S: ... - def strftime(self, fmt: str) -> str: ... + def strftime(self, __format: str) -> str: ... def __format__(self, __fmt: str) -> str: ... def utcoffset(self) -> timedelta | None: ... def tzname(self) -> str | None: ... @@ -276,10 +276,10 @@ class datetime(date): 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[override] + def __lt__(self, __other: datetime) -> bool: ... # type: ignore[override] + def __ge__(self, __other: datetime) -> bool: ... # type: ignore[override] + def __gt__(self, __other: datetime) -> bool: ... # type: ignore[override] if sys.version_info >= (3, 8): @overload # type: ignore[override] def __sub__(self: _D, __other: timedelta) -> _D: ... diff --git a/mypy/typeshed/stdlib/dbm/__init__.pyi b/mypy/typeshed/stdlib/dbm/__init__.pyi index 9b9f92ccaa86..5ecacd91b4ed 100644 --- a/mypy/typeshed/stdlib/dbm/__init__.pyi +++ b/mypy/typeshed/stdlib/dbm/__init__.pyi @@ -1,6 +1,6 @@ from _typeshed import Self from types import TracebackType -from typing import Iterator, MutableMapping, Tuple, Type, Union +from typing import Iterator, MutableMapping, Type, Union from typing_extensions import Literal _KeyType = Union[str, bytes] @@ -87,7 +87,7 @@ class _Database(MutableMapping[_KeyType, bytes]): class _error(Exception): ... -error = Tuple[Type[_error], Type[OSError]] +error: tuple[Type[_error], Type[OSError]] def whichdb(filename: str) -> str: ... def open(file: str, flag: _TFlags = ..., mode: int = ...) -> _Database: ... diff --git a/mypy/typeshed/stdlib/dbm/gnu.pyi b/mypy/typeshed/stdlib/dbm/gnu.pyi index 7cec827e8992..702f62d11b75 100644 --- a/mypy/typeshed/stdlib/dbm/gnu.pyi +++ b/mypy/typeshed/stdlib/dbm/gnu.pyi @@ -6,6 +6,8 @@ _T = TypeVar("_T") _KeyType = Union[str, bytes] _ValueType = Union[str, bytes] +open_flags: str + class error(OSError): ... # Actual typename gdbm, not exposed by the implementation @@ -31,7 +33,7 @@ class _gdbm: def keys(self) -> list[bytes]: ... def setdefault(self, k: _KeyType, default: _ValueType = ...) -> bytes: ... # Don't exist at runtime - __new__: None # type: ignore - __init__: None # type: ignore + __new__: None # type: ignore[assignment] + __init__: None # type: ignore[assignment] def open(__filename: str, __flags: str = ..., __mode: int = ...) -> _gdbm: ... diff --git a/mypy/typeshed/stdlib/dbm/ndbm.pyi b/mypy/typeshed/stdlib/dbm/ndbm.pyi index a4b35a309dbd..7b04c5385dbe 100644 --- a/mypy/typeshed/stdlib/dbm/ndbm.pyi +++ b/mypy/typeshed/stdlib/dbm/ndbm.pyi @@ -29,7 +29,7 @@ class _dbm: def keys(self) -> list[bytes]: ... def setdefault(self, k: _KeyType, default: _ValueType = ...) -> bytes: ... # Don't exist at runtime - __new__: None # type: ignore - __init__: None # type: ignore + __new__: None # type: ignore[assignment] + __init__: None # type: ignore[assignment] def open(__filename: str, __flags: str = ..., __mode: int = ...) -> _dbm: ... diff --git a/mypy/typeshed/stdlib/decimal.pyi b/mypy/typeshed/stdlib/decimal.pyi index 30c8e973348d..07f9ca1bfdf0 100644 --- a/mypy/typeshed/stdlib/decimal.pyi +++ b/mypy/typeshed/stdlib/decimal.pyi @@ -1,15 +1,16 @@ import numbers +import sys from types import TracebackType -from typing import Any, Container, NamedTuple, Sequence, Tuple, Type, TypeVar, Union, overload +from typing import Any, Container, NamedTuple, Sequence, Type, TypeVar, Union, overload _Decimal = Union[Decimal, int] -_DecimalNew = Union[Decimal, float, str, Tuple[int, Sequence[int], int]] +_DecimalNew = Union[Decimal, float, str, tuple[int, Sequence[int], int]] _ComparableNum = Union[Decimal, float, numbers.Rational] _DecimalT = TypeVar("_DecimalT", bound=Decimal) class DecimalTuple(NamedTuple): sign: int - digits: Tuple[int, ...] + digits: tuple[int, ...] exponent: int ROUND_DOWN: str @@ -21,6 +22,8 @@ ROUND_UP: str ROUND_HALF_DOWN: str ROUND_05UP: str +if sys.version_info >= (3, 7): + HAVE_CONTEXTVAR: bool HAVE_THREADS: bool MAX_EMAX: int MAX_PREC: int @@ -46,7 +49,7 @@ def setcontext(__context: Context) -> None: ... def getcontext() -> Context: ... def localcontext(ctx: Context | None = ...) -> _ContextManager: ... -class Decimal(object): +class Decimal: def __new__(cls: Type[_DecimalT], value: _DecimalNew = ..., context: Context | None = ...) -> _DecimalT: ... @classmethod def from_float(cls, __f: float) -> Decimal: ... @@ -148,7 +151,7 @@ class Decimal(object): def __deepcopy__(self, __memo: Any) -> Decimal: ... def __format__(self, __specifier: str, __context: Context | None = ...) -> str: ... -class _ContextManager(object): +class _ContextManager: new_context: Context saved_context: Context def __init__(self, new_context: Context) -> None: ... @@ -157,7 +160,7 @@ class _ContextManager(object): _TrapType = Type[DecimalException] -class Context(object): +class Context: prec: int rounding: str Emin: int @@ -181,7 +184,7 @@ class Context(object): # __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 __reduce__(self) -> tuple[Type[Context], tuple[Any, ...]]: ... def clear_flags(self) -> None: ... def clear_traps(self) -> None: ... def copy(self) -> Context: ... diff --git a/mypy/typeshed/stdlib/difflib.pyi b/mypy/typeshed/stdlib/difflib.pyi index 7c4ae8e2f246..d259e77dfe8c 100644 --- a/mypy/typeshed/stdlib/difflib.pyi +++ b/mypy/typeshed/stdlib/difflib.pyi @@ -34,9 +34,7 @@ class SequenceMatcher(Generic[_T]): # mypy thinks the signatures of the overloads overlap, but the types still work fine @overload -def get_close_matches( # type: ignore - word: AnyStr, possibilities: Iterable[AnyStr], n: int = ..., cutoff: float = ... -) -> list[AnyStr]: ... +def get_close_matches(word: AnyStr, possibilities: Iterable[AnyStr], n: int = ..., cutoff: float = ...) -> list[AnyStr]: ... # type: ignore[misc] @overload def get_close_matches( word: Sequence[_T], possibilities: Iterable[Sequence[_T]], n: int = ..., cutoff: float = ... @@ -72,7 +70,7 @@ def ndiff( a: Sequence[str], b: Sequence[str], linejunk: _JunkCallback | None = ..., charjunk: _JunkCallback | None = ... ) -> Iterator[str]: ... -class HtmlDiff(object): +class HtmlDiff: def __init__( self, tabsize: int = ..., diff --git a/mypy/typeshed/stdlib/dis.pyi b/mypy/typeshed/stdlib/dis.pyi index a6ea3e950b95..ac0632d25c9c 100644 --- a/mypy/typeshed/stdlib/dis.pyi +++ b/mypy/typeshed/stdlib/dis.pyi @@ -20,8 +20,8 @@ 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) -_have_code = Union[types.MethodType, types.FunctionType, types.CodeType, type, Callable[..., Any]] -_have_code_or_string = Union[_have_code, str, bytes] +_HaveCodeType = Union[types.MethodType, types.FunctionType, types.CodeType, type, Callable[..., Any]] +_HaveCodeOrStringType = Union[_HaveCodeType, str, bytes] class Instruction(NamedTuple): opname: str @@ -36,7 +36,7 @@ class Instruction(NamedTuple): class Bytecode: codeobj: types.CodeType first_line: int - def __init__(self, x: _have_code_or_string, *, first_line: int | None = ..., current_offset: int | None = ...) -> None: ... + def __init__(self, x: _HaveCodeOrStringType, *, first_line: int | None = ..., current_offset: int | None = ...) -> None: ... def __iter__(self) -> Iterator[Instruction]: ... def __repr__(self) -> str: ... def info(self) -> str: ... @@ -46,19 +46,19 @@ 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 findlabels(code: _HaveCodeType) -> list[int]: ... +def findlinestarts(code: _HaveCodeType) -> Iterator[tuple[int, int]]: ... def pretty_flags(flags: int) -> str: ... -def code_info(x: _have_code_or_string) -> str: ... +def code_info(x: _HaveCodeOrStringType) -> str: ... if sys.version_info >= (3, 7): - def dis(x: _have_code_or_string | None = ..., *, file: IO[str] | None = ..., depth: int | None = ...) -> None: ... + def dis(x: _HaveCodeOrStringType | None = ..., *, file: IO[str] | None = ..., depth: int | None = ...) -> None: ... else: - def dis(x: _have_code_or_string | None = ..., *, file: IO[str] | None = ...) -> None: ... + def dis(x: _HaveCodeOrStringType | None = ..., *, file: IO[str] | None = ...) -> None: ... def distb(tb: types.TracebackType | None = ..., *, file: IO[str] | None = ...) -> None: ... -def disassemble(co: _have_code, lasti: int = ..., *, file: IO[str] | None = ...) -> None: ... -def disco(co: _have_code, lasti: int = ..., *, file: IO[str] | None = ...) -> None: ... -def show_code(co: _have_code, *, file: IO[str] | None = ...) -> None: ... -def get_instructions(x: _have_code, *, first_line: int | None = ...) -> Iterator[Instruction]: ... +def disassemble(co: _HaveCodeType, lasti: int = ..., *, file: IO[str] | None = ...) -> None: ... +def disco(co: _HaveCodeType, lasti: int = ..., *, file: IO[str] | None = ...) -> None: ... +def show_code(co: _HaveCodeType, *, file: IO[str] | None = ...) -> None: ... +def get_instructions(x: _HaveCodeType, *, first_line: int | None = ...) -> Iterator[Instruction]: ... diff --git a/mypy/typeshed/stdlib/distutils/ccompiler.pyi b/mypy/typeshed/stdlib/distutils/ccompiler.pyi index d21de4691503..7c7023ed0b65 100644 --- a/mypy/typeshed/stdlib/distutils/ccompiler.pyi +++ b/mypy/typeshed/stdlib/distutils/ccompiler.pyi @@ -1,6 +1,6 @@ -from typing import Any, Callable, Optional, Tuple, Union +from typing import Any, Callable, Optional, Union -_Macro = Union[Tuple[str], Tuple[str, Optional[str]]] +_Macro = Union[tuple[str], tuple[str, Optional[str]]] def gen_lib_options( compiler: CCompiler, library_dirs: list[str], runtime_library_dirs: list[str], libraries: list[str] @@ -141,7 +141,7 @@ class CCompiler: def library_filename(self, libname: str, lib_type: str = ..., strip_dir: int = ..., output_dir: str = ...) -> str: ... def object_filenames(self, source_filenames: list[str], strip_dir: int = ..., output_dir: str = ...) -> list[str]: ... def shared_object_filename(self, basename: str, strip_dir: int = ..., output_dir: str = ...) -> str: ... - def execute(self, func: Callable[..., None], args: Tuple[Any, ...], msg: str | None = ..., level: int = ...) -> None: ... + def execute(self, func: Callable[..., None], args: tuple[Any, ...], msg: str | None = ..., level: int = ...) -> None: ... def spawn(self, cmd: list[str]) -> None: ... def mkpath(self, name: str, mode: int = ...) -> None: ... def move_file(self, src: str, dst: str) -> str: ... diff --git a/mypy/typeshed/stdlib/distutils/command/__init__.pyi b/mypy/typeshed/stdlib/distutils/command/__init__.pyi index e69de29bb2d1..a4b9b1c2bd1b 100644 --- a/mypy/typeshed/stdlib/distutils/command/__init__.pyi +++ b/mypy/typeshed/stdlib/distutils/command/__init__.pyi @@ -0,0 +1,40 @@ +from . import ( + bdist_dumb as bdist_dumb, + bdist_rpm as bdist_rpm, + build as build, + build_clib as build_clib, + build_ext as build_ext, + build_py as build_py, + build_scripts as build_scripts, + check as check, + clean as clean, + install as install, + install_data as install_data, + install_headers as install_headers, + install_lib as install_lib, + register as register, + sdist as sdist, + upload as upload, +) + +__all__ = [ + "build", + "build_py", + "build_ext", + "build_clib", + "build_scripts", + "clean", + "install", + "install_lib", + "install_headers", + "install_scripts", + "install_data", + "sdist", + "register", + "bdist", + "bdist_dumb", + "bdist_rpm", + "bdist_wininst", + "check", + "upload", +] diff --git a/mypy/typeshed/stdlib/distutils/command/check.pyi b/mypy/typeshed/stdlib/distutils/command/check.pyi index 9149b540f715..36895d2c16f1 100644 --- a/mypy/typeshed/stdlib/distutils/command/check.pyi +++ b/mypy/typeshed/stdlib/distutils/command/check.pyi @@ -5,7 +5,7 @@ from ..cmd import Command _Reporter = Any # really docutils.utils.Reporter # Only defined if docutils is installed. -class SilentReporter(_Reporter): # type: ignore +class SilentReporter(_Reporter): messages: Any def __init__( self, diff --git a/mypy/typeshed/stdlib/distutils/command/install.pyi b/mypy/typeshed/stdlib/distutils/command/install.pyi index 47fa8b08d1b2..661d256e6f07 100644 --- a/mypy/typeshed/stdlib/distutils/command/install.pyi +++ b/mypy/typeshed/stdlib/distutils/command/install.pyi @@ -1,9 +1,9 @@ -from typing import Any, Tuple +from typing import Any from ..cmd import Command HAS_USER_SITE: bool -SCHEME_KEYS: Tuple[str, ...] +SCHEME_KEYS: tuple[str, ...] INSTALL_SCHEMES: dict[str, dict[Any, Any]] class install(Command): diff --git a/mypy/typeshed/stdlib/distutils/fancy_getopt.pyi b/mypy/typeshed/stdlib/distutils/fancy_getopt.pyi index 06a0847e4687..dce8394b6289 100644 --- a/mypy/typeshed/stdlib/distutils/fancy_getopt.pyi +++ b/mypy/typeshed/stdlib/distutils/fancy_getopt.pyi @@ -1,7 +1,7 @@ -from typing import Any, Iterable, List, Mapping, Optional, Tuple, overload +from typing import Any, Iterable, Mapping, Optional, overload -_Option = Tuple[str, Optional[str], str] -_GR = Tuple[List[str], OptionDummy] +_Option = tuple[str, Optional[str], str] +_GR = tuple[list[str], OptionDummy] def fancy_getopt( options: list[_Option], negative_opt: Mapping[_Option, _Option], object: Any, args: list[str] | None diff --git a/mypy/typeshed/stdlib/distutils/util.pyi b/mypy/typeshed/stdlib/distutils/util.pyi index 9b0915570ece..03ee0185cac4 100644 --- a/mypy/typeshed/stdlib/distutils/util.pyi +++ b/mypy/typeshed/stdlib/distutils/util.pyi @@ -1,6 +1,6 @@ from _typeshed import StrPath from collections.abc import Callable, Container, Iterable, Mapping -from typing import Any, Tuple +from typing import Any def get_platform() -> str: ... def convert_path(pathname: str) -> str: ... @@ -9,7 +9,7 @@ def check_environ() -> None: ... def subst_vars(s: str, local_vars: Mapping[str, str]) -> None: ... def split_quoted(s: str) -> list[str]: ... def execute( - func: Callable[..., None], args: Tuple[Any, ...], msg: str | None = ..., verbose: bool = ..., dry_run: bool = ... + func: Callable[..., None], args: tuple[Any, ...], msg: str | None = ..., verbose: bool = ..., dry_run: bool = ... ) -> None: ... def strtobool(val: str) -> bool: ... def byte_compile( diff --git a/mypy/typeshed/stdlib/distutils/version.pyi b/mypy/typeshed/stdlib/distutils/version.pyi index 9921dde39af6..1908cdeda97a 100644 --- a/mypy/typeshed/stdlib/distutils/version.pyi +++ b/mypy/typeshed/stdlib/distutils/version.pyi @@ -1,5 +1,5 @@ from abc import abstractmethod -from typing import Pattern, Tuple, TypeVar +from typing import Pattern, TypeVar _T = TypeVar("_T", bound=Version) @@ -31,7 +31,7 @@ class StrictVersion(Version): class LooseVersion(Version): component_re: Pattern[str] vstring: str - version: Tuple[str | int, ...] + version: tuple[str | int, ...] def __init__(self, vstring: str | None = ...) -> None: ... def parse(self: _T, vstring: str) -> _T: ... def __str__(self) -> str: ... diff --git a/mypy/typeshed/stdlib/doctest.pyi b/mypy/typeshed/stdlib/doctest.pyi index 9a9f83b0d8fe..611137740ac4 100644 --- a/mypy/typeshed/stdlib/doctest.pyi +++ b/mypy/typeshed/stdlib/doctest.pyi @@ -1,6 +1,6 @@ import types import unittest -from typing import Any, Callable, NamedTuple, Tuple, Type +from typing import Any, Callable, NamedTuple, Type class TestResults(NamedTuple): failed: int @@ -86,7 +86,7 @@ class DocTestFinder: ) -> list[DocTest]: ... _Out = Callable[[str], Any] -_ExcInfo = Tuple[Type[BaseException], BaseException, types.TracebackType] +_ExcInfo = tuple[Type[BaseException], BaseException, types.TracebackType] class DocTestRunner: DIVIDER: str diff --git a/mypy/typeshed/stdlib/email/_header_value_parser.pyi b/mypy/typeshed/stdlib/email/_header_value_parser.pyi index f1b08b5d5805..ddb9d9e45913 100644 --- a/mypy/typeshed/stdlib/email/_header_value_parser.pyi +++ b/mypy/typeshed/stdlib/email/_header_value_parser.pyi @@ -1,7 +1,7 @@ import sys from email.errors import HeaderParseError, MessageDefect from email.policy import Policy -from typing import Any, Iterable, Iterator, List, Pattern, Type, TypeVar, Union +from typing import Any, Iterable, Iterator, Pattern, Type, TypeVar, Union from typing_extensions import Final _T = TypeVar("_T") @@ -23,7 +23,7 @@ def quote_string(value: Any) -> str: ... if sys.version_info >= (3, 7): rfc2047_matcher: Pattern[str] -class TokenList(List[Union[TokenList, Terminal]]): +class TokenList(list[Union[TokenList, Terminal]]): token_type: str | None syntactic_break: bool ew_combine_allowed: bool @@ -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[override] class WhiteSpaceTerminal(Terminal): @property diff --git a/mypy/typeshed/stdlib/email/base64mime.pyi b/mypy/typeshed/stdlib/email/base64mime.pyi new file mode 100644 index 000000000000..a8030a978923 --- /dev/null +++ b/mypy/typeshed/stdlib/email/base64mime.pyi @@ -0,0 +1,7 @@ +def header_length(bytearray: str | bytes) -> int: ... +def header_encode(header_bytes: str | bytes, charset: str = ...) -> str: ... +def body_encode(s: bytes, maxlinelen: int = ..., eol: str = ...) -> str: ... +def decode(string: str | bytes) -> bytes: ... + +body_decode = decode +decodestring = decode diff --git a/mypy/typeshed/stdlib/email/headerregistry.pyi b/mypy/typeshed/stdlib/email/headerregistry.pyi index 69e7bf315d9f..abf10ed4a4fd 100644 --- a/mypy/typeshed/stdlib/email/headerregistry.pyi +++ b/mypy/typeshed/stdlib/email/headerregistry.pyi @@ -1,5 +1,6 @@ import sys import types +from collections.abc import Iterable, Mapping from datetime import datetime as _datetime from email._header_value_parser import ( AddressList, @@ -12,28 +13,33 @@ from email._header_value_parser import ( ) from email.errors import MessageDefect from email.policy import Policy -from typing import Any, Iterable, Tuple, Type +from typing import Any, ClassVar, Type +from typing_extensions import Literal class BaseHeader(str): + # max_count is actually more of an abstract ClassVar (not defined on the base class, but expected to be defined in subclasses) + max_count: ClassVar[Literal[1] | None] @property def name(self) -> str: ... @property - def defects(self) -> Tuple[MessageDefect, ...]: ... - @property - def max_count(self) -> int | None: ... + def defects(self) -> tuple[MessageDefect, ...]: ... def __new__(cls, name: str, value: Any) -> BaseHeader: ... def init(self, name: str, *, parse_tree: TokenList, defects: Iterable[MessageDefect]) -> None: ... def fold(self, *, policy: Policy) -> str: ... class UnstructuredHeader: + max_count: ClassVar[Literal[1] | None] @staticmethod def value_parser(value: str) -> UnstructuredTokenList: ... @classmethod def parse(cls, value: str, kwds: dict[str, Any]) -> None: ... -class UniqueUnstructuredHeader(UnstructuredHeader): ... +class UniqueUnstructuredHeader(UnstructuredHeader): + max_count: ClassVar[Literal[1]] class DateHeader: + max_count: ClassVar[Literal[1] | None] + def init(self, name: str, *, parse_tree: TokenList, defects: Iterable[MessageDefect], datetime: _datetime) -> None: ... @property def datetime(self) -> _datetime: ... @staticmethod @@ -41,27 +47,43 @@ class DateHeader: @classmethod def parse(cls, value: str | _datetime, kwds: dict[str, Any]) -> None: ... -class UniqueDateHeader(DateHeader): ... +class UniqueDateHeader(DateHeader): + max_count: ClassVar[Literal[1]] class AddressHeader: + max_count: ClassVar[Literal[1] | None] + def init(self, name: str, *, parse_tree: TokenList, defects: Iterable[MessageDefect], groups: Iterable[Group]) -> None: ... @property - def groups(self) -> Tuple[Group, ...]: ... + def groups(self) -> tuple[Group, ...]: ... @property - def addresses(self) -> Tuple[Address, ...]: ... + def addresses(self) -> tuple[Address, ...]: ... @staticmethod def value_parser(value: str) -> AddressList: ... @classmethod def parse(cls, value: str, kwds: dict[str, Any]) -> None: ... -class UniqueAddressHeader(AddressHeader): ... +class UniqueAddressHeader(AddressHeader): + max_count: ClassVar[Literal[1]] class SingleAddressHeader(AddressHeader): @property def address(self) -> Address: ... -class UniqueSingleAddressHeader(SingleAddressHeader): ... +class UniqueSingleAddressHeader(SingleAddressHeader): + max_count: ClassVar[Literal[1]] class MIMEVersionHeader: + max_count: ClassVar[Literal[1]] + def init( + self, + name: str, + *, + parse_tree: TokenList, + defects: Iterable[MessageDefect], + version: str | None, + major: int | None, + minor: int | None, + ) -> None: ... @property def version(self) -> str | None: ... @property @@ -74,6 +96,8 @@ class MIMEVersionHeader: def parse(cls, value: str, kwds: dict[str, Any]) -> None: ... class ParameterizedMIMEHeader: + max_count: ClassVar[Literal[1]] + def init(self, name: str, *, parse_tree: TokenList, defects: Iterable[MessageDefect], params: Mapping[str, Any]) -> None: ... @property def params(self) -> types.MappingProxyType[str, Any]: ... @classmethod @@ -90,12 +114,15 @@ class ContentTypeHeader(ParameterizedMIMEHeader): def value_parser(value: str) -> ContentType: ... class ContentDispositionHeader(ParameterizedMIMEHeader): + # init is redefined but has the same signature as parent class, so is omitted from the stub @property - def content_disposition(self) -> str: ... + def content_disposition(self) -> str | None: ... @staticmethod def value_parser(value: str) -> ContentDisposition: ... class ContentTransferEncodingHeader: + max_count: ClassVar[Literal[1]] + def init(self, name: str, *, parse_tree: TokenList, defects: Iterable[MessageDefect]) -> None: ... @property def cte(self) -> str: ... @classmethod @@ -106,6 +133,7 @@ class ContentTransferEncodingHeader: if sys.version_info >= (3, 8): from email._header_value_parser import MessageID class MessageIDHeader: + max_count: ClassVar[Literal[1]] @classmethod def parse(cls, value: str, kwds: dict[str, Any]) -> None: ... @staticmethod @@ -137,6 +165,6 @@ class Group: @property def display_name(self) -> str | None: ... @property - def addresses(self) -> Tuple[Address, ...]: ... + def addresses(self) -> tuple[Address, ...]: ... def __init__(self, display_name: str | None = ..., addresses: Iterable[Address] | None = ...) -> None: ... def __str__(self) -> str: ... diff --git a/mypy/typeshed/stdlib/email/message.pyi b/mypy/typeshed/stdlib/email/message.pyi index a1749a4cfc2e..b89c8f8ec167 100644 --- a/mypy/typeshed/stdlib/email/message.pyi +++ b/mypy/typeshed/stdlib/email/message.pyi @@ -2,15 +2,16 @@ from email.charset import Charset from email.contentmanager import ContentManager from email.errors import MessageDefect from email.policy import Policy -from typing import Any, Generator, Iterator, List, Optional, Sequence, Tuple, TypeVar, Union + +# using a type alias ("_HeaderType = Any") breaks mypy, who knows why +from typing import Any, Any as _HeaderType, Generator, Iterator, Optional, Sequence, TypeVar, Union _T = TypeVar("_T") -_PayloadType = Union[List[Message], str, bytes] +_PayloadType = Union[list[Message], str, bytes] _CharsetType = Union[Charset, str, None] -_ParamsType = Union[str, None, Tuple[str, Optional[str], str]] -_ParamType = Union[str, Tuple[Optional[str], Optional[str], str]] -_HeaderType = Any +_ParamsType = Union[str, None, tuple[str, Optional[str], str]] +_ParamType = Union[str, tuple[Optional[str], Optional[str], str]] class Message: policy: Policy # undocumented @@ -69,6 +70,9 @@ class Message: replace: bool = ..., ) -> None: ... def __init__(self, policy: Policy = ...) -> None: ... + # The following two methods are undocumented, but a source code comment states that they are public API + def set_raw(self, name: str, value: str) -> None: ... + def raw_items(self) -> Iterator[tuple[str, str]]: ... class MIMEPart(Message): def __init__(self, policy: Policy | None = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/email/mime/application.pyi b/mypy/typeshed/stdlib/email/mime/application.pyi index 11fc470e9dd1..d176cd613e27 100644 --- a/mypy/typeshed/stdlib/email/mime/application.pyi +++ b/mypy/typeshed/stdlib/email/mime/application.pyi @@ -1,8 +1,8 @@ from email.mime.nonmultipart import MIMENonMultipart from email.policy import Policy -from typing import Callable, Optional, Tuple, Union +from typing import Callable, Optional, Union -_ParamsType = Union[str, None, Tuple[str, Optional[str], str]] +_ParamsType = Union[str, None, tuple[str, Optional[str], str]] class MIMEApplication(MIMENonMultipart): def __init__( diff --git a/mypy/typeshed/stdlib/email/mime/audio.pyi b/mypy/typeshed/stdlib/email/mime/audio.pyi index ee6de410bf53..38657c932e2f 100644 --- a/mypy/typeshed/stdlib/email/mime/audio.pyi +++ b/mypy/typeshed/stdlib/email/mime/audio.pyi @@ -1,8 +1,8 @@ from email.mime.nonmultipart import MIMENonMultipart from email.policy import Policy -from typing import Callable, Optional, Tuple, Union +from typing import Callable, Optional, Union -_ParamsType = Union[str, None, Tuple[str, Optional[str], str]] +_ParamsType = Union[str, None, tuple[str, Optional[str], str]] class MIMEAudio(MIMENonMultipart): def __init__( diff --git a/mypy/typeshed/stdlib/email/mime/base.pyi b/mypy/typeshed/stdlib/email/mime/base.pyi index b88dfd492554..cb655607b032 100644 --- a/mypy/typeshed/stdlib/email/mime/base.pyi +++ b/mypy/typeshed/stdlib/email/mime/base.pyi @@ -1,8 +1,8 @@ import email.message from email.policy import Policy -from typing import Optional, Tuple, Union +from typing import Optional, Union -_ParamsType = Union[str, None, Tuple[str, Optional[str], str]] +_ParamsType = Union[str, None, tuple[str, Optional[str], str]] class MIMEBase(email.message.Message): def __init__(self, _maintype: str, _subtype: str, *, policy: Policy | None = ..., **_params: _ParamsType) -> None: ... diff --git a/mypy/typeshed/stdlib/email/mime/image.pyi b/mypy/typeshed/stdlib/email/mime/image.pyi index 886aa74d5fe5..0325d9e594da 100644 --- a/mypy/typeshed/stdlib/email/mime/image.pyi +++ b/mypy/typeshed/stdlib/email/mime/image.pyi @@ -1,8 +1,8 @@ from email.mime.nonmultipart import MIMENonMultipart from email.policy import Policy -from typing import Callable, Optional, Tuple, Union +from typing import Callable, Optional, Union -_ParamsType = Union[str, None, Tuple[str, Optional[str], str]] +_ParamsType = Union[str, None, tuple[str, Optional[str], str]] class MIMEImage(MIMENonMultipart): def __init__( diff --git a/mypy/typeshed/stdlib/email/mime/multipart.pyi b/mypy/typeshed/stdlib/email/mime/multipart.pyi index 6259ddf5ab8f..6c316c055329 100644 --- a/mypy/typeshed/stdlib/email/mime/multipart.pyi +++ b/mypy/typeshed/stdlib/email/mime/multipart.pyi @@ -1,9 +1,9 @@ from email.message import Message from email.mime.base import MIMEBase from email.policy import Policy -from typing import Optional, Sequence, Tuple, Union +from typing import Optional, Sequence, Union -_ParamsType = Union[str, None, Tuple[str, Optional[str], str]] +_ParamsType = Union[str, None, tuple[str, Optional[str], str]] class MIMEMultipart(MIMEBase): def __init__( diff --git a/mypy/typeshed/stdlib/email/policy.pyi b/mypy/typeshed/stdlib/email/policy.pyi index 72a54bcfbf08..15991c7e084b 100644 --- a/mypy/typeshed/stdlib/email/policy.pyi +++ b/mypy/typeshed/stdlib/email/policy.pyi @@ -1,17 +1,27 @@ -from abc import abstractmethod +from abc import ABCMeta, abstractmethod 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 -class Policy: +class Policy(metaclass=ABCMeta): max_line_length: int | None linesep: str cte_type: str raise_on_defect: bool - mange_from: bool - def __init__(self, **kw: Any) -> None: ... + mangle_from_: bool + message_factory: Callable[[Policy], Message] | None + def __init__( + self, + *, + max_line_length: int | None = ..., + linesep: str = ..., + cte_type: str = ..., + raise_on_defect: bool = ..., + mangle_from_: bool = ..., + message_factory: Callable[[Policy], Message] | None = ..., + ) -> None: ... def clone(self, **kw: Any) -> Policy: ... def handle_defect(self, obj: Message, defect: MessageDefect) -> None: ... def register_defect(self, obj: Message, defect: MessageDefect) -> None: ... @@ -30,7 +40,7 @@ class Policy: 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_fetch_parse(self, name: str, value: str) -> str | Header: ... # type: ignore + def header_fetch_parse(self, name: str, value: str) -> str | Header: ... # type: ignore[override] def fold(self, name: str, value: str) -> str: ... def fold_binary(self, name: str, value: str) -> bytes: ... @@ -41,6 +51,20 @@ class EmailPolicy(Policy): refold_source: str header_factory: Callable[[str, str], str] content_manager: ContentManager + def __init__( + self, + *, + max_line_length: int | None = ..., + linesep: str = ..., + cte_type: str = ..., + raise_on_defect: bool = ..., + mangle_from_: bool = ..., + message_factory: Callable[[Policy], Message] | None = ..., + utf8: bool = ..., + refold_source: str = ..., + header_factory: Callable[[str, str], str] = ..., + content_manager: ContentManager = ..., + ) -> None: ... 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: ... diff --git a/mypy/typeshed/stdlib/email/quoprimime.pyi b/mypy/typeshed/stdlib/email/quoprimime.pyi new file mode 100644 index 000000000000..41c4bd8cca9e --- /dev/null +++ b/mypy/typeshed/stdlib/email/quoprimime.pyi @@ -0,0 +1,13 @@ +def header_check(octet: int) -> bool: ... +def body_check(octet: int) -> bool: ... +def header_length(bytearray: bytes) -> int: ... +def body_length(bytearray: bytes) -> int: ... +def unquote(s: str | bytes) -> str: ... +def quote(c: str | bytes) -> str: ... +def header_encode(header_bytes: bytes, charset: str = ...) -> str: ... +def body_encode(body: str, maxlinelen: int = ..., eol: str = ...) -> str: ... +def decode(encoded: str, eol: str = ...) -> str: ... +def header_decode(s: str) -> str: ... + +body_decode = decode +decodestring = decode diff --git a/mypy/typeshed/stdlib/email/utils.pyi b/mypy/typeshed/stdlib/email/utils.pyi index 3c07e98079fc..728a5a53f230 100644 --- a/mypy/typeshed/stdlib/email/utils.pyi +++ b/mypy/typeshed/stdlib/email/utils.pyi @@ -1,10 +1,10 @@ import datetime import sys from email.charset import Charset -from typing import Optional, Tuple, Union, overload +from typing import Optional, Union, overload -_ParamType = Union[str, Tuple[Optional[str], Optional[str], str]] -_PDTZ = Tuple[int, int, int, int, int, int, int, int, int, Optional[int]] +_ParamType = Union[str, tuple[Optional[str], Optional[str], str]] +_PDTZ = tuple[int, int, int, int, int, int, int, int, int, Optional[int]] def quote(str: str) -> str: ... def unquote(str: str) -> str: ... diff --git a/mypy/typeshed/stdlib/encodings/utf_8_sig.pyi b/mypy/typeshed/stdlib/encodings/utf_8_sig.pyi new file mode 100644 index 000000000000..bf52e8a6f3d3 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/utf_8_sig.pyi @@ -0,0 +1,27 @@ +import codecs + +class IncrementalEncoder(codecs.IncrementalEncoder): + def __init__(self, errors: str = ...) -> None: ... + def encode(self, input: str, final: bool = ...) -> bytes: ... + def reset(self) -> None: ... + def getstate(self) -> int: ... # type: ignore[override] + def setstate(self, state: int) -> None: ... # type: ignore[override] + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + def __init__(self, errors: str = ...) -> None: ... + def _buffer_decode(self, input: bytes, errors: str | None, final: bool) -> tuple[str, int]: ... + def reset(self) -> None: ... + def getstate(self) -> tuple[bytes, int]: ... + def setstate(self, state: tuple[bytes, int]) -> None: ... + +class StreamWriter(codecs.StreamWriter): + def reset(self) -> None: ... + def encode(self, input: str, errors: str | None = ...) -> tuple[bytes, int]: ... + +class StreamReader(codecs.StreamReader): + def reset(self) -> None: ... + def decode(self, input: bytes, errors: str | None = ...) -> tuple[str, int]: ... + +def getregentry() -> codecs.CodecInfo: ... +def encode(input: 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 07fea104cec7..a80a022ad6f5 100644 --- a/mypy/typeshed/stdlib/enum.pyi +++ b/mypy/typeshed/stdlib/enum.pyi @@ -2,17 +2,49 @@ import sys import types from abc import ABCMeta from builtins import property as _builtins_property -from typing import Any, Iterator, Type, TypeVar +from collections.abc import Iterable, Iterator, Mapping +from typing import Any, Type, TypeVar, Union, overload _T = TypeVar("_T") _S = TypeVar("_S", bound=Type[Enum]) +# The following all work: +# >>> from enum import Enum +# >>> from string import ascii_lowercase +# >>> Enum('Foo', names='RED YELLOW GREEN') +# +# >>> Enum('Foo', names=[('RED', 1), ('YELLOW, 2)]) +# +# >>> Enum('Foo', names=((x for x in (ascii_lowercase[i], i)) for i in range(5))) +# +# >>> Enum('Foo', names={'RED': 1, 'YELLOW': 2}) +# +_EnumNames = Union[str, Iterable[str], Iterable[Iterable[Union[str, Any]]], Mapping[str, Any]] + +class _EnumDict(dict[str, Any]): + def __init__(self) -> None: ... + # Note: EnumMeta actually subclasses type directly, not ABCMeta. # This is a temporary workaround to allow multiple creation of enums with builtins # such as str as mixins, which due to the handling of ABCs of builtin types, cause # spurious inconsistent metaclass structure. See #1595. # Structurally: Iterable[T], Reversible[T], Container[T] where T is the enum itself class EnumMeta(ABCMeta): + if sys.version_info >= (3, 11): + def __new__( + metacls: Type[_T], + cls: str, + bases: tuple[type, ...], + classdict: _EnumDict, + *, + boundary: FlagBoundary | None = ..., + _simple: bool = ..., + **kwds: Any, + ) -> _T: ... + elif sys.version_info >= (3, 9): + def __new__(metacls: Type[_T], cls: str, bases: tuple[type, ...], classdict: _EnumDict, **kwds: Any) -> _T: ... # type: ignore + else: + def __new__(metacls: Type[_T], cls: str, bases: tuple[type, ...], classdict: _EnumDict) -> _T: ... # type: ignore def __iter__(self: Type[_T]) -> Iterator[_T]: ... def __reversed__(self: Type[_T]) -> Iterator[_T]: ... def __contains__(self: Type[Any], member: object) -> bool: ... @@ -20,13 +52,56 @@ class EnumMeta(ABCMeta): @_builtins_property def __members__(self: Type[_T]) -> types.MappingProxyType[str, _T]: ... def __len__(self) -> int: ... + if sys.version_info >= (3, 11): + # Simple value lookup + @overload # type: ignore[override] + def __call__(cls: Type[_T], value: Any, names: None = ...) -> _T: ... + # Functional Enum API + @overload + def __call__( + cls, + value: str, + names: _EnumNames, + *, + module: str | None = ..., + qualname: str | None = ..., + type: type | None = ..., + start: int = ..., + boundary: FlagBoundary | None = ..., + ) -> Type[Enum]: ... + else: + @overload # type: ignore[override] + def __call__(cls: Type[_T], value: Any, names: None = ...) -> _T: ... + @overload + def __call__( + cls, + value: str, + names: _EnumNames, + *, + module: str | None = ..., + qualname: str | None = ..., + type: type | None = ..., + start: int = ..., + ) -> Type[Enum]: ... _member_names_: list[str] # undocumented _member_map_: dict[str, Enum] # undocumented _value2member_map_: dict[Any, Enum] # undocumented +if sys.version_info >= (3, 11): + # In 3.11 `EnumMeta` metaclass is renamed to `EnumType`, but old name also exists. + EnumType = EnumMeta + class Enum(metaclass=EnumMeta): - name: str - value: Any + if sys.version_info >= (3, 11): + @property + def name(self) -> str: ... + @property + def value(self) -> Any: ... + else: + @types.DynamicClassAttribute + def name(self) -> str: ... + @types.DynamicClassAttribute + def value(self) -> Any: ... _name_: str _value_: Any if sys.version_info >= (3, 7): @@ -46,7 +121,13 @@ class Enum(metaclass=EnumMeta): def __reduce_ex__(self, proto: object) -> Any: ... class IntEnum(int, Enum): - value: int + _value_: int + if sys.version_info >= (3, 11): + @property + def value(self) -> int: ... + else: + @types.DynamicClassAttribute + def value(self) -> int: ... def __new__(cls: Type[_T], value: int | _T) -> _T: ... def unique(enumeration: _S) -> _S: ... @@ -55,12 +136,28 @@ _auto_null: Any # subclassing IntFlag so it picks up all implemented base functions, best modeling behavior of enum.auto() class auto(IntFlag): - value: Any + _value_: Any + if sys.version_info >= (3, 11): + @property + def value(self) -> Any: ... + else: + @types.DynamicClassAttribute + def value(self) -> Any: ... def __new__(cls: Type[_T]) -> _T: ... class Flag(Enum): - name: str | None # type: ignore - value: int + _name_: str | None # type: ignore[assignment] + _value_: int + if sys.version_info >= (3, 11): + @property + def name(self) -> str | None: ... # type: ignore[override] + @property + def value(self) -> int: ... + else: + @types.DynamicClassAttribute + def name(self) -> str | None: ... # type: ignore[override] + @types.DynamicClassAttribute + def value(self) -> int: ... def __contains__(self: _T, other: _T) -> bool: ... def __repr__(self) -> str: ... def __str__(self) -> str: ... @@ -81,7 +178,10 @@ class IntFlag(int, Flag): if sys.version_info >= (3, 11): class StrEnum(str, Enum): - def __new__(cls: Type[_T], value: int | _T) -> _T: ... + def __new__(cls: Type[_T], value: str | _T) -> _T: ... + _value_: str + @property + def value(self) -> str: ... class FlagBoundary(StrEnum): STRICT: str CONFORM: str @@ -91,7 +191,10 @@ if sys.version_info >= (3, 11): CONFORM = FlagBoundary.CONFORM EJECT = FlagBoundary.EJECT KEEP = FlagBoundary.KEEP - class property(_builtins_property): ... + class property(types.DynamicClassAttribute): + def __set_name__(self, ownerclass: Type[Enum], name: str) -> None: ... + name: str + clsname: str def global_enum(cls: _S) -> _S: ... def global_enum_repr(self: Enum) -> str: ... def global_flag_repr(self: Flag) -> str: ... diff --git a/mypy/typeshed/stdlib/fcntl.pyi b/mypy/typeshed/stdlib/fcntl.pyi index 141f9ee9360a..47766357c83f 100644 --- a/mypy/typeshed/stdlib/fcntl.pyi +++ b/mypy/typeshed/stdlib/fcntl.pyi @@ -3,94 +3,94 @@ from _typeshed import FileDescriptorLike, ReadOnlyBuffer, WriteableBuffer from typing import Any, overload from typing_extensions import Literal -FASYNC: int -FD_CLOEXEC: int -DN_ACCESS: int -DN_ATTRIB: int -DN_CREATE: int -DN_DELETE: int -DN_MODIFY: int -DN_MULTISHOT: int -DN_RENAME: int -F_DUPFD: int -F_DUPFD_CLOEXEC: int -F_FULLFSYNC: int -F_EXLCK: int -F_GETFD: int -F_GETFL: int -F_GETLEASE: int -F_GETLK: int -F_GETLK64: int -F_GETOWN: int -F_NOCACHE: int -F_GETSIG: int -F_NOTIFY: int -F_RDLCK: int -F_SETFD: int -F_SETFL: int -F_SETLEASE: int -F_SETLK: int -F_SETLK64: int -F_SETLKW: int -F_SETLKW64: int -if sys.version_info >= (3, 9) and sys.platform == "linux": - F_OFD_GETLK: int - F_OFD_SETLK: int - F_OFD_SETLKW: int -F_SETOWN: int -F_SETSIG: int -F_SHLCK: int -F_UNLCK: int -F_WRLCK: int -I_ATMARK: int -I_CANPUT: int -I_CKBAND: int -I_FDINSERT: int -I_FIND: int -I_FLUSH: int -I_FLUSHBAND: int -I_GETBAND: int -I_GETCLTIME: int -I_GETSIG: int -I_GRDOPT: int -I_GWROPT: int -I_LINK: int -I_LIST: int -I_LOOK: int -I_NREAD: int -I_PEEK: int -I_PLINK: int -I_POP: int -I_PUNLINK: int -I_PUSH: int -I_RECVFD: int -I_SENDFD: int -I_SETCLTIME: int -I_SETSIG: int -I_SRDOPT: int -I_STR: int -I_SWROPT: int -I_UNLINK: int -LOCK_EX: int -LOCK_MAND: int -LOCK_NB: int -LOCK_READ: int -LOCK_RW: int -LOCK_SH: int -LOCK_UN: int -LOCK_WRITE: int - -@overload -def fcntl(__fd: FileDescriptorLike, __cmd: int, __arg: int = ...) -> int: ... -@overload -def fcntl(__fd: FileDescriptorLike, __cmd: int, __arg: bytes) -> bytes: ... -@overload -def ioctl(__fd: FileDescriptorLike, __request: int, __arg: int = ..., __mutate_flag: bool = ...) -> int: ... -@overload -def ioctl(__fd: FileDescriptorLike, __request: int, __arg: WriteableBuffer, __mutate_flag: Literal[True] = ...) -> int: ... -@overload -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 flock(__fd: FileDescriptorLike, __operation: int) -> None: ... -def lockf(__fd: FileDescriptorLike, __cmd: int, __len: int = ..., __start: int = ..., __whence: int = ...) -> Any: ... +if sys.platform != "win32": + FASYNC: int + FD_CLOEXEC: int + DN_ACCESS: int + DN_ATTRIB: int + DN_CREATE: int + DN_DELETE: int + DN_MODIFY: int + DN_MULTISHOT: int + DN_RENAME: int + F_DUPFD: int + F_DUPFD_CLOEXEC: int + F_FULLFSYNC: int + F_EXLCK: int + F_GETFD: int + F_GETFL: int + F_GETLEASE: int + F_GETLK: int + F_GETLK64: int + F_GETOWN: int + F_NOCACHE: int + F_GETSIG: int + F_NOTIFY: int + F_RDLCK: int + F_SETFD: int + F_SETFL: int + F_SETLEASE: int + F_SETLK: int + F_SETLK64: int + F_SETLKW: int + F_SETLKW64: int + if sys.version_info >= (3, 9) and sys.platform == "linux": + F_OFD_GETLK: int + F_OFD_SETLK: int + F_OFD_SETLKW: int + F_SETOWN: int + F_SETSIG: int + F_SHLCK: int + F_UNLCK: int + F_WRLCK: int + I_ATMARK: int + I_CANPUT: int + I_CKBAND: int + I_FDINSERT: int + I_FIND: int + I_FLUSH: int + I_FLUSHBAND: int + I_GETBAND: int + I_GETCLTIME: int + I_GETSIG: int + I_GRDOPT: int + I_GWROPT: int + I_LINK: int + I_LIST: int + I_LOOK: int + I_NREAD: int + I_PEEK: int + I_PLINK: int + I_POP: int + I_PUNLINK: int + I_PUSH: int + I_RECVFD: int + I_SENDFD: int + I_SETCLTIME: int + I_SETSIG: int + I_SRDOPT: int + I_STR: int + I_SWROPT: int + I_UNLINK: int + LOCK_EX: int + LOCK_MAND: int + LOCK_NB: int + LOCK_READ: int + LOCK_RW: int + LOCK_SH: int + LOCK_UN: int + LOCK_WRITE: int + @overload + def fcntl(__fd: FileDescriptorLike, __cmd: int, __arg: int = ...) -> int: ... + @overload + def fcntl(__fd: FileDescriptorLike, __cmd: int, __arg: bytes) -> bytes: ... + @overload + def ioctl(__fd: FileDescriptorLike, __request: int, __arg: int = ..., __mutate_flag: bool = ...) -> int: ... + @overload + def ioctl(__fd: FileDescriptorLike, __request: int, __arg: WriteableBuffer, __mutate_flag: Literal[True] = ...) -> int: ... + @overload + 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 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/fileinput.pyi b/mypy/typeshed/stdlib/fileinput.pyi index 3c14b736ca50..576822059560 100644 --- a/mypy/typeshed/stdlib/fileinput.pyi +++ b/mypy/typeshed/stdlib/fileinput.pyi @@ -85,7 +85,8 @@ class FileInput(Iterable[AnyStr], Generic[AnyStr]): def __exit__(self, type: Any, value: Any, traceback: Any) -> None: ... def __iter__(self) -> Iterator[AnyStr]: ... def __next__(self) -> AnyStr: ... - def __getitem__(self, i: int) -> AnyStr: ... + if sys.version_info < (3, 11): + def __getitem__(self, i: int) -> AnyStr: ... def nextfile(self) -> None: ... def readline(self) -> AnyStr: ... def filename(self) -> str: ... diff --git a/mypy/typeshed/stdlib/formatter.pyi b/mypy/typeshed/stdlib/formatter.pyi index 7c3b97688dbd..f5d8348d08a1 100644 --- a/mypy/typeshed/stdlib/formatter.pyi +++ b/mypy/typeshed/stdlib/formatter.pyi @@ -1,8 +1,8 @@ -from typing import IO, Any, Iterable, Tuple +from typing import IO, Any, Iterable AS_IS: None -_FontType = Tuple[str, bool, bool, bool] -_StylesType = Tuple[Any, ...] +_FontType = tuple[str, bool, bool, bool] +_StylesType = tuple[Any, ...] class NullFormatter: writer: NullWriter | None @@ -68,7 +68,7 @@ class NullWriter: def new_font(self, font: _FontType) -> None: ... def new_margin(self, margin: int, level: int) -> None: ... def new_spacing(self, spacing: str | None) -> None: ... - def new_styles(self, styles: Tuple[Any, ...]) -> None: ... + def new_styles(self, styles: tuple[Any, ...]) -> None: ... def send_paragraph(self, blankline: int) -> None: ... def send_line_break(self) -> None: ... def send_hor_rule(self, *args: Any, **kw: Any) -> None: ... @@ -81,7 +81,7 @@ class AbstractWriter(NullWriter): def new_font(self, font: _FontType) -> None: ... def new_margin(self, margin: int, level: int) -> None: ... def new_spacing(self, spacing: str | None) -> None: ... - def new_styles(self, styles: Tuple[Any, ...]) -> None: ... + def new_styles(self, styles: tuple[Any, ...]) -> None: ... def send_paragraph(self, blankline: int) -> None: ... def send_line_break(self) -> None: ... def send_hor_rule(self, *args: Any, **kw: Any) -> None: ... diff --git a/mypy/typeshed/stdlib/fractions.pyi b/mypy/typeshed/stdlib/fractions.pyi index 3c6808651275..8de5ae20971c 100644 --- a/mypy/typeshed/stdlib/fractions.pyi +++ b/mypy/typeshed/stdlib/fractions.pyi @@ -134,6 +134,8 @@ class Fraction(Rational): def __le__(self, other: _ComparableNum) -> bool: ... def __ge__(self, other: _ComparableNum) -> bool: ... def __bool__(self) -> bool: ... + if sys.version_info >= (3, 11): + def __int__(self) -> int: ... # Not actually defined within fractions.py, but provides more useful # overrides @property diff --git a/mypy/typeshed/stdlib/ftplib.pyi b/mypy/typeshed/stdlib/ftplib.pyi index 3f4f892bb516..f84199c168e9 100644 --- a/mypy/typeshed/stdlib/ftplib.pyi +++ b/mypy/typeshed/stdlib/ftplib.pyi @@ -3,7 +3,7 @@ from _typeshed import Self, SupportsRead, SupportsReadline from socket import socket from ssl import SSLContext from types import TracebackType -from typing import Any, Callable, Iterable, Iterator, TextIO, Tuple, Type +from typing import Any, Callable, Iterable, Iterator, TextIO, Type from typing_extensions import Literal MSG_OOB: int @@ -18,7 +18,7 @@ class error_temp(Error): ... class error_perm(Error): ... class error_proto(Error): ... -all_errors: Tuple[Type[Exception], ...] +all_errors: tuple[Type[Exception], ...] class FTP: debugging: int @@ -33,10 +33,6 @@ 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 diff --git a/mypy/typeshed/stdlib/functools.pyi b/mypy/typeshed/stdlib/functools.pyi index b5e52bf59920..990fed20d80d 100644 --- a/mypy/typeshed/stdlib/functools.pyi +++ b/mypy/typeshed/stdlib/functools.pyi @@ -1,7 +1,7 @@ import sys import types -from _typeshed import SupportsItems, SupportsLessThan -from typing import Any, Callable, Generic, Hashable, Iterable, NamedTuple, Sequence, Sized, Tuple, Type, TypeVar, overload +from _typeshed import SupportsAllComparisons, SupportsItems +from typing import Any, Callable, Generic, Hashable, Iterable, NamedTuple, Sequence, Sized, Type, TypeVar, overload from typing_extensions import final if sys.version_info >= (3, 9): @@ -45,13 +45,13 @@ WRAPPER_UPDATES: Sequence[str] def update_wrapper(wrapper: _T, wrapped: _AnyCallable, assigned: Sequence[str] = ..., updated: Sequence[str] = ...) -> _T: ... def wraps(wrapped: _AnyCallable, assigned: Sequence[str] = ..., updated: Sequence[str] = ...) -> Callable[[_T], _T]: ... def total_ordering(cls: Type[_T]) -> Type[_T]: ... -def cmp_to_key(mycmp: Callable[[_T, _T], int]) -> Callable[[_T], SupportsLessThan]: ... +def cmp_to_key(mycmp: Callable[[_T, _T], int]) -> Callable[[_T], SupportsAllComparisons]: ... class partial(Generic[_T]): func: Callable[..., _T] - args: Tuple[Any, ...] + args: tuple[Any, ...] keywords: dict[str, Any] - def __init__(self, func: Callable[..., _T], *args: Any, **kwargs: Any) -> None: ... + def __new__(cls: Type[_S], __func: Callable[..., _T], *args: Any, **kwargs: Any) -> _S: ... def __call__(self, *args: Any, **kwargs: Any) -> _T: ... if sys.version_info >= (3, 9): def __class_getitem__(cls, item: Any) -> GenericAlias: ... @@ -61,7 +61,7 @@ _Descriptor = Any class partialmethod(Generic[_T]): func: Callable[..., _T] | _Descriptor - args: Tuple[Any, ...] + args: tuple[Any, ...] keywords: dict[str, Any] @overload def __init__(self, __func: Callable[..., _T], *args: Any, **keywords: Any) -> None: ... @@ -120,10 +120,10 @@ if sys.version_info >= (3, 9): def cache(__user_function: Callable[..., _T]) -> _lru_cache_wrapper[_T]: ... def _make_key( - args: Tuple[Hashable, ...], + args: tuple[Hashable, ...], kwds: SupportsItems[Any, Any], typed: bool, - kwd_mark: Tuple[object, ...] = ..., + kwd_mark: tuple[object, ...] = ..., fasttypes: set[type] = ..., tuple: type = ..., type: Any = ..., diff --git a/mypy/typeshed/stdlib/genericpath.pyi b/mypy/typeshed/stdlib/genericpath.pyi index 56683e323178..f9518750d3f1 100644 --- a/mypy/typeshed/stdlib/genericpath.pyi +++ b/mypy/typeshed/stdlib/genericpath.pyi @@ -1,6 +1,6 @@ import os -from _typeshed import BytesPath, StrOrBytesPath, StrPath, SupportsLessThanT -from typing import Sequence, Tuple, overload +from _typeshed import BytesPath, StrOrBytesPath, StrPath, SupportsRichComparisonT +from typing import Sequence, overload from typing_extensions import Literal # All overloads can return empty string. Ideally, Literal[""] would be a valid @@ -11,9 +11,9 @@ def commonprefix(m: Sequence[StrPath]) -> str: ... @overload def commonprefix(m: Sequence[BytesPath]) -> bytes | Literal[""]: ... @overload -def commonprefix(m: Sequence[list[SupportsLessThanT]]) -> Sequence[SupportsLessThanT]: ... +def commonprefix(m: Sequence[list[SupportsRichComparisonT]]) -> Sequence[SupportsRichComparisonT]: ... @overload -def commonprefix(m: Sequence[Tuple[SupportsLessThanT, ...]]) -> Sequence[SupportsLessThanT]: ... +def commonprefix(m: Sequence[tuple[SupportsRichComparisonT, ...]]) -> Sequence[SupportsRichComparisonT]: ... def exists(path: StrOrBytesPath | int) -> bool: ... def getsize(filename: StrOrBytesPath | int) -> int: ... def isfile(path: StrOrBytesPath | int) -> bool: ... diff --git a/mypy/typeshed/stdlib/gettext.pyi b/mypy/typeshed/stdlib/gettext.pyi index b408d3f7485c..21be9fb1ff29 100644 --- a/mypy/typeshed/stdlib/gettext.pyi +++ b/mypy/typeshed/stdlib/gettext.pyi @@ -16,8 +16,9 @@ class NullTranslations: def npgettext(self, context: str, msgid1: str, msgid2: str, n: int) -> str: ... def info(self) -> Any: ... def charset(self) -> Any: ... - def output_charset(self) -> Any: ... - def set_output_charset(self, charset: str) -> None: ... + if sys.version_info < (3, 11): + def output_charset(self) -> Any: ... + def set_output_charset(self, charset: str) -> None: ... def install(self, names: Container[str] | None = ...) -> None: ... class GNUTranslations(NullTranslations): @@ -30,47 +31,71 @@ def find(domain: str, localedir: StrPath | None = ..., languages: Iterable[str] _T = TypeVar("_T") -@overload -def translation( - domain: str, - localedir: StrPath | None = ..., - languages: Iterable[str] | None = ..., - class_: None = ..., - fallback: bool = ..., - codeset: str | None = ..., -) -> NullTranslations: ... -@overload -def translation( - domain: str, - localedir: StrPath | None = ..., - languages: Iterable[str] | None = ..., - class_: Type[_T] = ..., - fallback: Literal[False] = ..., - codeset: str | None = ..., -) -> _T: ... -@overload -def translation( - domain: str, - localedir: StrPath | None = ..., - languages: Iterable[str] | None = ..., - class_: Type[Any] = ..., - fallback: Literal[True] = ..., - codeset: str | None = ..., -) -> Any: ... -def install( - domain: str, localedir: StrPath | None = ..., codeset: str | None = ..., names: Container[str] | None = ... -) -> None: ... +if sys.version_info >= (3, 11): + @overload + def translation( + domain: str, + localedir: StrPath | None = ..., + languages: Iterable[str] | None = ..., + class_: None = ..., + fallback: bool = ..., + ) -> NullTranslations: ... + @overload + def translation( + domain: str, + localedir: StrPath | None = ..., + languages: Iterable[str] | None = ..., + class_: Type[_T] = ..., + fallback: Literal[False] = ..., + ) -> _T: ... + @overload + def translation( + domain: str, + localedir: StrPath | None = ..., + languages: Iterable[str] | None = ..., + class_: Type[Any] = ..., + fallback: Literal[True] = ..., + ) -> Any: ... + def install(domain: str, localedir: StrPath | None = ..., names: Container[str] | None = ...) -> None: ... + +else: + @overload + def translation( + domain: str, + localedir: StrPath | None = ..., + languages: Iterable[str] | None = ..., + class_: None = ..., + fallback: bool = ..., + codeset: str | None = ..., + ) -> NullTranslations: ... + @overload + def translation( + domain: str, + localedir: StrPath | None = ..., + languages: Iterable[str] | None = ..., + class_: Type[_T] = ..., + fallback: Literal[False] = ..., + codeset: str | None = ..., + ) -> _T: ... + @overload + def translation( + domain: str, + localedir: StrPath | None = ..., + languages: Iterable[str] | None = ..., + class_: Type[Any] = ..., + fallback: Literal[True] = ..., + codeset: str | None = ..., + ) -> Any: ... + def install( + domain: str, localedir: StrPath | None = ..., codeset: str | None = ..., names: Container[str] | None = ... + ) -> None: ... + def textdomain(domain: str | None = ...) -> str: ... def bindtextdomain(domain: str, localedir: StrPath | None = ...) -> str: ... -def bind_textdomain_codeset(domain: str, codeset: str | None = ...) -> str: ... def dgettext(domain: str, message: str) -> str: ... -def ldgettext(domain: str, message: str) -> str: ... def dngettext(domain: str, msgid1: str, msgid2: str, n: int) -> str: ... -def ldngettext(domain: str, msgid1: str, msgid2: str, n: int) -> str: ... def gettext(message: str) -> str: ... -def lgettext(message: str) -> str: ... def ngettext(msgid1: str, msgid2: str, n: int) -> str: ... -def lngettext(msgid1: str, msgid2: str, n: int) -> str: ... if sys.version_info >= (3, 8): def pgettext(context: str, message: str) -> str: ... @@ -78,4 +103,11 @@ if sys.version_info >= (3, 8): def npgettext(context: str, msgid1: str, msgid2: str, n: int) -> str: ... def dnpgettext(domain: str, context: str, msgid1: str, msgid2: str, n: int) -> str: ... +if sys.version_info < (3, 11): + def lgettext(message: str) -> str: ... + def ldgettext(domain: str, message: str) -> str: ... + def lngettext(msgid1: str, msgid2: str, n: int) -> str: ... + def ldngettext(domain: str, msgid1: str, msgid2: str, n: int) -> str: ... + def bind_textdomain_codeset(domain: str, codeset: str | None = ...) -> str: ... + Catalog = translation diff --git a/mypy/typeshed/stdlib/graphlib.pyi b/mypy/typeshed/stdlib/graphlib.pyi index 0872af4a54a4..96d64cbce18c 100644 --- a/mypy/typeshed/stdlib/graphlib.pyi +++ b/mypy/typeshed/stdlib/graphlib.pyi @@ -1,5 +1,5 @@ from _typeshed import SupportsItems -from typing import Generic, Iterable, Tuple, TypeVar +from typing import Generic, Iterable, TypeVar _T = TypeVar("_T") @@ -10,7 +10,7 @@ class TopologicalSorter(Generic[_T]): def is_active(self) -> bool: ... def __bool__(self) -> bool: ... def done(self, *nodes: _T) -> None: ... - def get_ready(self) -> Tuple[_T, ...]: ... + def get_ready(self) -> tuple[_T, ...]: ... def static_order(self) -> Iterable[_T]: ... class CycleError(ValueError): ... diff --git a/mypy/typeshed/stdlib/grp.pyi b/mypy/typeshed/stdlib/grp.pyi index 08cbe6b86476..b416269921d6 100644 --- a/mypy/typeshed/stdlib/grp.pyi +++ b/mypy/typeshed/stdlib/grp.pyi @@ -1,11 +1,19 @@ -from typing import NamedTuple +import sys +from _typeshed import structseq +from typing import Any, Optional +from typing_extensions import final -class struct_group(NamedTuple): - gr_name: str - gr_passwd: str | None - gr_gid: int - gr_mem: list[str] - -def getgrall() -> list[struct_group]: ... -def getgrgid(id: int) -> struct_group: ... -def getgrnam(name: str) -> struct_group: ... +if sys.platform != "win32": + @final + class struct_group(structseq[Any], tuple[str, Optional[str], int, list[str]]): + @property + def gr_name(self) -> str: ... + @property + def gr_passwd(self) -> str | None: ... + @property + def gr_gid(self) -> int: ... + @property + def gr_mem(self) -> list[str]: ... + def getgrall() -> list[struct_group]: ... + def getgrgid(id: int) -> struct_group: ... + def getgrnam(name: str) -> struct_group: ... diff --git a/mypy/typeshed/stdlib/hashlib.pyi b/mypy/typeshed/stdlib/hashlib.pyi index e39f2f25326e..fad3c5aad457 100644 --- a/mypy/typeshed/stdlib/hashlib.pyi +++ b/mypy/typeshed/stdlib/hashlib.pyi @@ -2,7 +2,7 @@ import sys from _typeshed import ReadableBuffer, Self from typing import AbstractSet -class _Hash(object): +class _Hash: @property def digest_size(self) -> int: ... @property @@ -49,7 +49,7 @@ def pbkdf2_hmac( hash_name: str, password: ReadableBuffer, salt: ReadableBuffer, iterations: int, dklen: int | None = ... ) -> bytes: ... -class _VarLenHash(object): +class _VarLenHash: digest_size: int block_size: int name: str diff --git a/mypy/typeshed/stdlib/heapq.pyi b/mypy/typeshed/stdlib/heapq.pyi index 81ee02582a6a..fd3c2db8ad66 100644 --- a/mypy/typeshed/stdlib/heapq.pyi +++ b/mypy/typeshed/stdlib/heapq.pyi @@ -1,4 +1,4 @@ -from _typeshed import SupportsLessThan +from _typeshed import SupportsRichComparison from typing import Any, Callable, Iterable, TypeVar _T = TypeVar("_T") @@ -9,6 +9,6 @@ def heappushpop(__heap: list[_T], __item: _T) -> _T: ... def heapify(__heap: list[Any]) -> None: ... def heapreplace(__heap: list[_T], __item: _T) -> _T: ... def merge(*iterables: Iterable[_T], key: Callable[[_T], Any] | None = ..., reverse: bool = ...) -> Iterable[_T]: ... -def nlargest(n: int, iterable: Iterable[_T], key: Callable[[_T], SupportsLessThan] | None = ...) -> list[_T]: ... -def nsmallest(n: int, iterable: Iterable[_T], key: Callable[[_T], SupportsLessThan] | None = ...) -> list[_T]: ... +def nlargest(n: int, iterable: Iterable[_T], key: Callable[[_T], SupportsRichComparison] | None = ...) -> list[_T]: ... +def nsmallest(n: int, iterable: Iterable[_T], key: Callable[[_T], SupportsRichComparison] | None = ...) -> list[_T]: ... def _heapify_max(__x: list[Any]) -> None: ... # undocumented diff --git a/mypy/typeshed/stdlib/hmac.pyi b/mypy/typeshed/stdlib/hmac.pyi index 440bddd7919c..88c88631f99a 100644 --- a/mypy/typeshed/stdlib/hmac.pyi +++ b/mypy/typeshed/stdlib/hmac.pyi @@ -7,6 +7,9 @@ from typing import Any, AnyStr, Callable, Union, overload _Hash = Any _DigestMod = Union[str, Callable[[], _Hash], ModuleType] +trans_5C: bytes +trans_36: bytes + digest_size: None if sys.version_info >= (3, 8): diff --git a/mypy/typeshed/stdlib/html/parser.pyi b/mypy/typeshed/stdlib/html/parser.pyi index fec3f3509522..60e0de51d3b8 100644 --- a/mypy/typeshed/stdlib/html/parser.pyi +++ b/mypy/typeshed/stdlib/html/parser.pyi @@ -1,5 +1,5 @@ from _markupbase import ParserBase -from typing import Tuple +from typing import Pattern class HTMLParser(ParserBase): def __init__(self, *, convert_charrefs: bool = ...) -> None: ... @@ -18,7 +18,7 @@ class HTMLParser(ParserBase): def handle_decl(self, decl: str) -> None: ... def handle_pi(self, data: str) -> None: ... def unknown_decl(self, data: str) -> None: ... - CDATA_CONTENT_ELEMENTS: Tuple[str, ...] + CDATA_CONTENT_ELEMENTS: tuple[str, ...] def check_for_whole_start_tag(self, i: int) -> int: ... # undocumented def clear_cdata_mode(self) -> None: ... # undocumented def goahead(self, end: bool) -> None: ... # undocumented @@ -28,3 +28,8 @@ class HTMLParser(ParserBase): def parse_pi(self, i: int) -> int: ... # undocumented def parse_starttag(self, i: int) -> int: ... # undocumented def set_cdata_mode(self, elem: str) -> None: ... # undocumented + rawdata: str # undocumented + cdata_elem: str | None # undocumented + convert_charrefs: bool # undocumented + interesting: Pattern[str] # undocumented + lasttag: str # undocumented diff --git a/mypy/typeshed/stdlib/http/client.pyi b/mypy/typeshed/stdlib/http/client.pyi index c450db587135..1558f6ff46e8 100644 --- a/mypy/typeshed/stdlib/http/client.pyi +++ b/mypy/typeshed/stdlib/http/client.pyi @@ -96,7 +96,7 @@ class HTTPResponse(io.BufferedIOBase, BinaryIO): def read(self, amt: int | None = ...) -> bytes: ... def read1(self, n: int = ...) -> bytes: ... def readinto(self, b: WriteableBuffer) -> int: ... - def readline(self, limit: int = ...) -> bytes: ... # type: ignore + def readline(self, limit: int = ...) -> bytes: ... # type: ignore[override] @overload def getheader(self, name: str) -> str | None: ... @overload diff --git a/mypy/typeshed/stdlib/http/cookiejar.pyi b/mypy/typeshed/stdlib/http/cookiejar.pyi index f37fb19cebe9..6bfa7f385e69 100644 --- a/mypy/typeshed/stdlib/http/cookiejar.pyi +++ b/mypy/typeshed/stdlib/http/cookiejar.pyi @@ -1,7 +1,7 @@ import sys from _typeshed import StrPath from http.client import HTTPResponse -from typing import ClassVar, Iterable, Iterator, Pattern, Sequence, Tuple, TypeVar, overload +from typing import ClassVar, Iterable, Iterator, Pattern, Sequence, TypeVar, overload from urllib.request import Request _T = TypeVar("_T") @@ -102,10 +102,10 @@ class DefaultCookiePolicy(CookiePolicy): strict_ns_set_initial_dollar: bool = ..., strict_ns_set_path: bool = ..., ) -> None: ... - def blocked_domains(self) -> Tuple[str, ...]: ... + def blocked_domains(self) -> tuple[str, ...]: ... def set_blocked_domains(self, blocked_domains: Sequence[str]) -> None: ... def is_blocked(self, domain: str) -> bool: ... - def allowed_domains(self) -> Tuple[str, ...] | None: ... + def allowed_domains(self) -> tuple[str, ...] | None: ... def set_allowed_domains(self, allowed_domains: Sequence[str] | None) -> None: ... def is_not_allowed(self, domain: str) -> bool: ... def set_ok_version(self, cookie: Cookie, request: Request) -> bool: ... # undocumented diff --git a/mypy/typeshed/stdlib/http/cookies.pyi b/mypy/typeshed/stdlib/http/cookies.pyi index 7e9513adb1a1..211fd37662d4 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, TypeVar, Union, overload +from typing import Any, Generic, Iterable, Mapping, TypeVar, Union, overload if sys.version_info >= (3, 9): from types import GenericAlias @@ -18,7 +18,7 @@ def _unquote(str: str) -> str: ... class CookieError(Exception): ... -class Morsel(Dict[str, Any], Generic[_T]): +class Morsel(dict[str, Any], Generic[_T]): value: str coded_value: _T key: str @@ -29,7 +29,7 @@ class Morsel(Dict[str, Any], Generic[_T]): def set(self, key: str, val: str, coded_val: _T, LegalChars: str = ...) -> None: ... def setdefault(self, key: str, val: str | None = ...) -> str: ... # The dict update can also get a keywords argument so this is incompatible - @overload # type: ignore + @overload # type: ignore[override] def update(self, values: Mapping[str, str]) -> None: ... @overload def update(self, values: Iterable[tuple[str, str]]) -> None: ... @@ -40,7 +40,7 @@ class Morsel(Dict[str, Any], Generic[_T]): if sys.version_info >= (3, 9): def __class_getitem__(cls, item: Any) -> GenericAlias: ... -class BaseCookie(Dict[str, Morsel[_T]], Generic[_T]): +class BaseCookie(dict[str, Morsel[_T]], Generic[_T]): def __init__(self, input: _DataType | None = ...) -> None: ... def value_decode(self, val: str) -> _T: ... def value_encode(self, val: _T) -> str: ... diff --git a/mypy/typeshed/stdlib/imaplib.pyi b/mypy/typeshed/stdlib/imaplib.pyi index a9f19048c9ae..1b2774d8fde0 100644 --- a/mypy/typeshed/stdlib/imaplib.pyi +++ b/mypy/typeshed/stdlib/imaplib.pyi @@ -5,14 +5,14 @@ from _typeshed import Self from socket import socket as _socket from ssl import SSLContext, SSLSocket from types import TracebackType -from typing import IO, Any, Callable, List, Pattern, Tuple, Type, Union +from typing import IO, Any, Callable, Pattern, Type, Union from typing_extensions import Literal # TODO: Commands should use their actual return types, not this type alias. # E.g. Tuple[Literal["OK"], List[bytes]] -_CommandResults = Tuple[str, List[Any]] +_CommandResults = tuple[str, list[Any]] -_AnyResponseData = Union[List[None], List[Union[bytes, Tuple[bytes, bytes]]]] +_AnyResponseData = Union[list[None], list[Union[bytes, tuple[bytes, bytes]]]] _list = list # conflicts with a method named "list" diff --git a/mypy/typeshed/stdlib/importlib/abc.pyi b/mypy/typeshed/stdlib/importlib/abc.pyi index 2e18f3f899a2..9bb370dfd7e8 100644 --- a/mypy/typeshed/stdlib/importlib/abc.pyi +++ b/mypy/typeshed/stdlib/importlib/abc.pyi @@ -12,8 +12,8 @@ from _typeshed import ( from abc import ABCMeta, abstractmethod from importlib.machinery import ModuleSpec 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 +from typing import IO, Any, BinaryIO, Iterator, Mapping, NoReturn, Protocol, Sequence, Union, overload, runtime_checkable +from typing_extensions import Literal _Path = Union[bytes, str] @@ -85,8 +85,12 @@ if sys.version_info >= (3, 7): def open_resource(self, resource: StrOrBytesPath) -> IO[bytes]: ... @abstractmethod def resource_path(self, resource: StrOrBytesPath) -> str: ... - @abstractmethod - def is_resource(self, name: str) -> bool: ... + if sys.version_info >= (3, 10): + @abstractmethod + def is_resource(self, path: str) -> bool: ... + else: + @abstractmethod + def is_resource(self, name: str) -> bool: ... @abstractmethod def contents(self) -> Iterator[str]: ... @@ -169,3 +173,10 @@ if sys.version_info >= (3, 9): def read_bytes(self) -> bytes: ... @abstractmethod def read_text(self, encoding: str | None = ...) -> str: ... + class TraversableResources(ResourceReader): + @abstractmethod + def files(self) -> Traversable: ... + def open_resource(self, resource: StrPath) -> BufferedReader: ... # type: ignore[override] + def resource_path(self, resource: Any) -> NoReturn: ... + def is_resource(self, path: StrPath) -> bool: ... + def contents(self) -> Iterator[str]: ... diff --git a/mypy/typeshed/stdlib/importlib/machinery.pyi b/mypy/typeshed/stdlib/importlib/machinery.pyi index 432bec901161..b73f9c527583 100644 --- a/mypy/typeshed/stdlib/importlib/machinery.pyi +++ b/mypy/typeshed/stdlib/importlib/machinery.pyi @@ -1,6 +1,10 @@ import importlib.abc +import sys import types -from typing import Any, Callable, Sequence +from typing import Any, Callable, Iterable, Sequence + +if sys.version_info >= (3, 8): + from importlib.metadata import DistributionFinder, PathDistribution class ModuleSpec: def __init__( @@ -41,10 +45,16 @@ class BuiltinImporter(importlib.abc.MetaPathFinder, importlib.abc.InspectLoader) # Loader @staticmethod def module_repr(module: types.ModuleType) -> str: ... - @classmethod - def create_module(cls, spec: ModuleSpec) -> types.ModuleType | None: ... - @classmethod - def exec_module(cls, module: types.ModuleType) -> None: ... + if sys.version_info >= (3, 10): + @staticmethod + def create_module(spec: ModuleSpec) -> types.ModuleType | None: ... + @staticmethod + def exec_module(module: types.ModuleType) -> None: ... + else: + @classmethod + def create_module(cls, spec: ModuleSpec) -> types.ModuleType | None: ... + @classmethod + def exec_module(cls, module: types.ModuleType) -> None: ... class FrozenImporter(importlib.abc.MetaPathFinder, importlib.abc.InspectLoader): # MetaPathFinder @@ -66,8 +76,12 @@ class FrozenImporter(importlib.abc.MetaPathFinder, importlib.abc.InspectLoader): # Loader @staticmethod def module_repr(m: types.ModuleType) -> str: ... - @classmethod - def create_module(cls, spec: ModuleSpec) -> types.ModuleType | None: ... + if sys.version_info >= (3, 10): + @staticmethod + def create_module(spec: ModuleSpec) -> types.ModuleType | None: ... + else: + @classmethod + def create_module(cls, spec: ModuleSpec) -> types.ModuleType | None: ... @staticmethod def exec_module(module: types.ModuleType) -> None: ... @@ -80,8 +94,18 @@ class WindowsRegistryFinder(importlib.abc.MetaPathFinder): ) -> ModuleSpec | None: ... class PathFinder: - @classmethod - def invalidate_caches(cls) -> None: ... + if sys.version_info >= (3, 10): + @staticmethod + def invalidate_caches() -> None: ... + else: + @classmethod + def invalidate_caches(cls) -> None: ... + if sys.version_info >= (3, 10): + @staticmethod + def find_distributions(context: DistributionFinder.Context = ...) -> Iterable[PathDistribution]: ... + elif sys.version_info >= (3, 8): + @classmethod + def find_distributions(cls, context: DistributionFinder.Context = ...) -> Iterable[PathDistribution]: ... @classmethod def find_spec( cls, fullname: str, path: Sequence[bytes | str] | None = ..., target: types.ModuleType | None = ... diff --git a/mypy/typeshed/stdlib/importlib/metadata.pyi b/mypy/typeshed/stdlib/importlib/metadata/__init__.pyi similarity index 80% rename from mypy/typeshed/stdlib/importlib/metadata.pyi rename to mypy/typeshed/stdlib/importlib/metadata/__init__.pyi index 2c1041b76503..a9e223149b52 100644 --- a/mypy/typeshed/stdlib/importlib/metadata.pyi +++ b/mypy/typeshed/stdlib/importlib/metadata/__init__.pyi @@ -7,9 +7,10 @@ from email.message import Message from importlib.abc import MetaPathFinder from os import PathLike from pathlib import Path -from typing import Any, Iterable, NamedTuple, Tuple, overload +from typing import Any, ClassVar, Iterable, NamedTuple, Pattern, overload if sys.version_info >= (3, 10): + from importlib.metadata._meta import PackageMetadata as PackageMetadata def packages_distributions() -> Mapping[str, list[str]]: ... if sys.version_info >= (3, 8): @@ -19,9 +20,18 @@ if sys.version_info >= (3, 8): value: str group: str class EntryPoint(_EntryPointBase): + pattern: ClassVar[Pattern[str]] def load(self) -> Any: ... # Callable[[], Any] or an importable module @property def extras(self) -> list[str]: ... + if sys.version_info >= (3, 9): + @property + def module(self) -> str: ... + @property + def attr(self) -> str: ... + if sys.version_info >= (3, 10): + dist: ClassVar[Distribution | None] + def matches(self, **params: Any) -> bool: ... # undocumented class PackagePath(pathlib.PurePosixPath): def read_text(self, encoding: str = ...) -> str: ... def read_binary(self) -> bytes: ... @@ -61,6 +71,9 @@ if sys.version_info >= (3, 8): def files(self) -> list[PackagePath] | None: ... @property def requires(self) -> list[str] | None: ... + if sys.version_info >= (3, 10): + @property + def name(self) -> str: ... class DistributionFinder(MetaPathFinder): class Context: name: str | None @@ -72,6 +85,9 @@ if sys.version_info >= (3, 8): class MetadataPathFinder(DistributionFinder): @classmethod def find_distributions(cls, context: DistributionFinder.Context = ...) -> Iterable[PathDistribution]: ... + if sys.version_info >= (3, 10): + # Yes, this is an instance method that has argumend named "cls" + def invalidate_caches(cls) -> None: ... # type: ignore class PathDistribution(Distribution): def __init__(self, path: Path) -> None: ... def read_text(self, filename: StrPath) -> str: ... @@ -85,6 +101,6 @@ if sys.version_info >= (3, 8): ) -> Iterable[Distribution]: ... def metadata(distribution_name: str) -> Message: ... def version(distribution_name: str) -> str: ... - def entry_points() -> dict[str, Tuple[EntryPoint, ...]]: ... + def entry_points() -> dict[str, tuple[EntryPoint, ...]]: ... def files(distribution_name: str) -> list[PackagePath] | None: ... def requires(distribution_name: str) -> list[str] | None: ... diff --git a/mypy/typeshed/stdlib/importlib/metadata/_meta.pyi b/mypy/typeshed/stdlib/importlib/metadata/_meta.pyi new file mode 100644 index 000000000000..a5e5733396d7 --- /dev/null +++ b/mypy/typeshed/stdlib/importlib/metadata/_meta.pyi @@ -0,0 +1,18 @@ +from typing import Any, Iterator, Protocol, TypeVar + +_T = TypeVar("_T") + +class PackageMetadata(Protocol): + def __len__(self) -> int: ... + def __contains__(self, item: str) -> bool: ... + def __getitem__(self, key: str) -> str: ... + def __iter__(self) -> Iterator[str]: ... + def get_all(self, name: str, failobj: _T = ...) -> list[Any] | _T: ... + @property + def json(self) -> dict[str, str | list[str]]: ... + +class SimplePath(Protocol): + def joinpath(self) -> SimplePath: ... + def __div__(self) -> SimplePath: ... + def parent(self) -> SimplePath: ... + def read_text(self) -> str: ... diff --git a/mypy/typeshed/stdlib/importlib/resources.pyi b/mypy/typeshed/stdlib/importlib/resources.pyi index 194c0bac2b6a..b484d7126b21 100644 --- a/mypy/typeshed/stdlib/importlib/resources.pyi +++ b/mypy/typeshed/stdlib/importlib/resources.pyi @@ -23,3 +23,6 @@ if sys.version_info >= (3, 9): from importlib.abc import Traversable def files(package: Package) -> Traversable: ... def as_file(path: Traversable) -> AbstractContextManager[Path]: ... + +if sys.version_info >= (3, 10): + from importlib.abc import ResourceReader as ResourceReader diff --git a/mypy/typeshed/stdlib/importlib/util.pyi b/mypy/typeshed/stdlib/importlib/util.pyi index 30b8765fad04..c759d7def5be 100644 --- a/mypy/typeshed/stdlib/importlib/util.pyi +++ b/mypy/typeshed/stdlib/importlib/util.pyi @@ -1,5 +1,6 @@ import importlib.abc import importlib.machinery +import sys import types from _typeshed import StrOrBytesPath from typing import Any, Callable @@ -7,9 +8,9 @@ from typing_extensions import ParamSpec _P = ParamSpec("_P") -def module_for_loader(fxn: Callable[_P, types.ModuleType]) -> Callable[_P, types.ModuleType]: ... # type: ignore -def set_loader(fxn: Callable[_P, types.ModuleType]) -> Callable[_P, types.ModuleType]: ... # type: ignore -def set_package(fxn: Callable[_P, types.ModuleType]) -> Callable[_P, types.ModuleType]: ... # type: ignore +def module_for_loader(fxn: Callable[_P, types.ModuleType]) -> Callable[_P, types.ModuleType]: ... +def set_loader(fxn: Callable[_P, types.ModuleType]) -> Callable[_P, types.ModuleType]: ... +def set_package(fxn: Callable[_P, types.ModuleType]) -> Callable[_P, types.ModuleType]: ... def resolve_name(name: str, package: str | None) -> str: ... MAGIC_NUMBER: bytes @@ -36,3 +37,6 @@ class LazyLoader(importlib.abc.Loader): def factory(cls, loader: importlib.abc.Loader) -> Callable[..., LazyLoader]: ... def create_module(self, spec: importlib.machinery.ModuleSpec) -> types.ModuleType | None: ... def exec_module(self, module: types.ModuleType) -> None: ... + +if sys.version_info >= (3, 7): + def source_hash(source_bytes: bytes) -> int: ... diff --git a/mypy/typeshed/stdlib/inspect.pyi b/mypy/typeshed/stdlib/inspect.pyi index 88002cf205b1..a96e30865a59 100644 --- a/mypy/typeshed/stdlib/inspect.pyi +++ b/mypy/typeshed/stdlib/inspect.pyi @@ -23,7 +23,7 @@ from types import ( 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 import Any, ClassVar, Coroutine, NamedTuple, Protocol, Type, TypeVar, Union from typing_extensions import Literal, TypeGuard # @@ -41,17 +41,19 @@ class BlockFinder: last: int def tokeneater(self, type: int, token: str, srowcol: tuple[int, int], erowcol: tuple[int, int], line: str) -> None: ... -CO_OPTIMIZED: int -CO_NEWLOCALS: int -CO_VARARGS: int -CO_VARKEYWORDS: int -CO_NESTED: int -CO_GENERATOR: int -CO_NOFREE: int -CO_COROUTINE: int -CO_ITERABLE_COROUTINE: int -CO_ASYNC_GENERATOR: int -TPFLAGS_IS_ABSTRACT: int +CO_OPTIMIZED: Literal[1] +CO_NEWLOCALS: Literal[2] +CO_VARARGS: Literal[4] +CO_VARKEYWORDS: Literal[8] +CO_NESTED: Literal[16] +CO_GENERATOR: Literal[32] +CO_NOFREE: Literal[64] +CO_COROUTINE: Literal[128] +CO_ITERABLE_COROUTINE: Literal[256] +CO_ASYNC_GENERATOR: Literal[512] +TPFLAGS_IS_ABSTRACT: Literal[1048576] + +modulesbyfile: dict[str, Any] def getmembers(object: object, predicate: Callable[[Any], bool] | None = ...) -> list[tuple[str, Any]]: ... def getmodulename(path: str) -> str | None: ... @@ -93,14 +95,7 @@ def isframe(object: object) -> TypeGuard[FrameType]: ... def iscode(object: object) -> TypeGuard[CodeType]: ... def isbuiltin(object: object) -> TypeGuard[BuiltinFunctionType]: ... -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: +if sys.version_info >= (3, 7): def isroutine( object: object, ) -> TypeGuard[ @@ -116,6 +111,13 @@ else: def ismethoddescriptor(object: object) -> TypeGuard[MethodDescriptorType]: ... def ismemberdescriptor(object: object) -> TypeGuard[MemberDescriptorType]: ... +else: + def isroutine( + object: object, + ) -> TypeGuard[FunctionType | LambdaType | MethodType | BuiltinFunctionType | BuiltinMethodType]: ... + def ismethoddescriptor(object: object) -> bool: ... + def ismemberdescriptor(object: object) -> bool: ... + def isabstract(object: object) -> bool: ... def isgetsetdescriptor(object: object) -> TypeGuard[GetSetDescriptorType]: ... def isdatadescriptor(object: object) -> TypeGuard[_SupportsSet[Any, Any] | _SupportsDelete[Any]]: ... @@ -205,21 +207,26 @@ class _ParameterKind(enum.IntEnum): VAR_KEYWORD: int if sys.version_info >= (3, 8): - description: str + @property + def description(self) -> str: ... class Parameter: def __init__(self, name: str, kind: _ParameterKind, *, default: Any = ..., annotation: Any = ...) -> None: ... empty = _empty - name: str - default: Any - annotation: Any - kind: _ParameterKind POSITIONAL_ONLY: ClassVar[Literal[_ParameterKind.POSITIONAL_ONLY]] POSITIONAL_OR_KEYWORD: ClassVar[Literal[_ParameterKind.POSITIONAL_OR_KEYWORD]] VAR_POSITIONAL: ClassVar[Literal[_ParameterKind.VAR_POSITIONAL]] KEYWORD_ONLY: ClassVar[Literal[_ParameterKind.KEYWORD_ONLY]] VAR_KEYWORD: ClassVar[Literal[_ParameterKind.VAR_KEYWORD]] + @property + def name(self) -> str: ... + @property + def default(self) -> Any: ... + @property + def kind(self) -> _ParameterKind: ... + @property + def annotation(self) -> Any: ... def replace( self: Self, *, @@ -231,7 +238,7 @@ class Parameter: class BoundArguments: arguments: OrderedDict[str, Any] - args: Tuple[Any, ...] + args: tuple[Any, ...] kwargs: dict[str, Any] signature: Signature def __init__(self, signature: Signature, arguments: OrderedDict[str, Any]) -> None: ... @@ -247,25 +254,26 @@ class BoundArguments: def getclasstree(classes: list[type], unique: bool = ...) -> list[Any]: ... def walktree(classes: list[type], children: dict[Type[Any], list[type]], parent: Type[Any] | None) -> list[Any]: ... -class ArgSpec(NamedTuple): - args: list[str] - varargs: str | None - keywords: str | None - defaults: Tuple[Any, ...] - class Arguments(NamedTuple): args: list[str] varargs: str | None varkw: str | None def getargs(co: CodeType) -> Arguments: ... -def getargspec(func: object) -> ArgSpec: ... + +if sys.version_info < (3, 11): + class ArgSpec(NamedTuple): + args: list[str] + varargs: str | None + keywords: str | None + defaults: tuple[Any, ...] + def getargspec(func: object) -> ArgSpec: ... class FullArgSpec(NamedTuple): args: list[str] varargs: str | None varkw: str | None - defaults: Tuple[Any, ...] | None + defaults: tuple[Any, ...] | None kwonlyargs: list[str] kwonlydefaults: dict[str, Any] | None annotations: dict[str, Any] @@ -281,21 +289,24 @@ class ArgInfo(NamedTuple): def getargvalues(frame: FrameType) -> ArgInfo: ... def formatannotation(annotation: object, base_module: str | None = ...) -> str: ... def formatannotationrelativeto(object: object) -> Callable[[object], str]: ... -def formatargspec( - args: list[str], - varargs: str | None = ..., - varkw: str | None = ..., - defaults: Tuple[Any, ...] | None = ..., - kwonlyargs: Sequence[str] | None = ..., - kwonlydefaults: dict[str, Any] | None = ..., - annotations: dict[str, Any] = ..., - formatarg: Callable[[str], str] = ..., - formatvarargs: Callable[[str], str] = ..., - formatvarkw: Callable[[str], str] = ..., - formatvalue: Callable[[Any], str] = ..., - formatreturns: Callable[[Any], str] = ..., - formatannotation: Callable[[Any], str] = ..., -) -> str: ... + +if sys.version_info < (3, 11): + def formatargspec( + args: list[str], + varargs: str | None = ..., + varkw: str | None = ..., + defaults: tuple[Any, ...] | None = ..., + kwonlyargs: Sequence[str] | None = ..., + kwonlydefaults: dict[str, Any] | None = ..., + annotations: dict[str, Any] = ..., + formatarg: Callable[[str], str] = ..., + formatvarargs: Callable[[str], str] = ..., + formatvarkw: Callable[[str], str] = ..., + formatvalue: Callable[[Any], str] = ..., + formatreturns: Callable[[Any], str] = ..., + formatannotation: Callable[[Any], str] = ..., + ) -> str: ... + def formatargvalues( args: list[str], varargs: str | None, @@ -306,7 +317,7 @@ def formatargvalues( formatvarkw: Callable[[str], str] | None = ..., formatvalue: Callable[[Any], str] | None = ..., ) -> str: ... -def getmro(cls: type) -> Tuple[type, ...]: ... +def getmro(cls: type) -> tuple[type, ...]: ... def getcallargs(__func: Callable[..., Any], *args: Any, **kwds: Any) -> dict[str, Any]: ... class ClosureVars(NamedTuple): @@ -327,7 +338,7 @@ class Traceback(NamedTuple): lineno: int function: str code_context: list[str] | None - index: int | None # type: ignore + index: int | None # type: ignore[assignment] class FrameInfo(NamedTuple): frame: FrameType @@ -335,7 +346,7 @@ class FrameInfo(NamedTuple): lineno: int function: str code_context: list[str] | None - index: int | None # type: ignore + index: int | None # type: ignore[assignment] def getframeinfo(frame: FrameType | TracebackType, context: int = ...) -> Traceback: ... def getouterframes(frame: Any, context: int = ...) -> list[FrameInfo]: ... @@ -355,26 +366,25 @@ def getattr_static(obj: object, attr: str, default: Any | None = ...) -> Any: .. # Current State of Generators and Coroutines # -# TODO In the next two blocks of code, can we be more specific regarding the -# type of the "enums"? +GEN_CREATED: Literal["GEN_CREATED"] +GEN_RUNNING: Literal["GEN_RUNNING"] +GEN_SUSPENDED: Literal["GEN_SUSPENDED"] +GEN_CLOSED: Literal["GEN_CLOSED"] -GEN_CREATED: str -GEN_RUNNING: str -GEN_SUSPENDED: str -GEN_CLOSED: str +def getgeneratorstate( + generator: Generator[Any, Any, Any] +) -> Literal["GEN_CREATED", "GEN_RUNNING", "GEN_SUSPENDED", "GEN_CLOSED"]: ... -def getgeneratorstate(generator: Generator[Any, Any, Any]) -> str: ... +CORO_CREATED: Literal["CORO_CREATED"] +CORO_RUNNING: Literal["CORO_RUNNING"] +CORO_SUSPENDED: Literal["CORO_SUSPENDED"] +CORO_CLOSED: Literal["CORO_CLOSED"] -CORO_CREATED: str -CORO_RUNNING: str -CORO_SUSPENDED: str -CORO_CLOSED: str -# TODO can we be more specific than "object"? -def getcoroutinestate(coroutine: object) -> str: ... +def getcoroutinestate( + coroutine: Coroutine[Any, Any, Any] +) -> Literal["CORO_CREATED", "CORO_RUNNING", "CORO_SUSPENDED", "CORO_CLOSED"]: ... def getgeneratorlocals(generator: Generator[Any, Any, Any]) -> dict[str, Any]: ... - -# TODO can we be more specific than "object"? -def getcoroutinelocals(coroutine: object) -> dict[str, Any]: ... +def getcoroutinelocals(coroutine: Coroutine[Any, Any, Any]) -> dict[str, Any]: ... # Create private type alias to avoid conflict with symbol of same # name created in Attribute class. diff --git a/mypy/typeshed/stdlib/io.pyi b/mypy/typeshed/stdlib/io.pyi index 6342907004d5..50452917c6f3 100644 --- a/mypy/typeshed/stdlib/io.pyi +++ b/mypy/typeshed/stdlib/io.pyi @@ -4,7 +4,7 @@ import sys from _typeshed import ReadableBuffer, Self, StrOrBytesPath, WriteableBuffer from os import _Opener from types import TracebackType -from typing import IO, Any, BinaryIO, Callable, Iterable, Iterator, TextIO, Tuple, Type +from typing import IO, Any, BinaryIO, Callable, Iterable, Iterator, TextIO, Type DEFAULT_BUFFER_SIZE: int @@ -65,7 +65,7 @@ class BufferedIOBase(IOBase): class FileIO(RawIOBase, BinaryIO): mode: str - name: StrOrBytesPath | int # type: ignore + name: StrOrBytesPath | int # type: ignore[assignment] def __init__( self, file: StrOrBytesPath | int, mode: str = ..., closefd: bool = ..., opener: _Opener | None = ... ) -> None: ... @@ -87,7 +87,7 @@ class BytesIO(BufferedIOBase, BinaryIO): if sys.version_info >= (3, 7): def read1(self, __size: int | None = ...) -> bytes: ... else: - def read1(self, __size: int | None) -> bytes: ... # type: ignore + def read1(self, __size: int | None) -> bytes: ... # type: ignore[override] class BufferedReader(BufferedIOBase, BinaryIO): def __enter__(self: Self) -> Self: ... @@ -96,7 +96,7 @@ class BufferedReader(BufferedIOBase, BinaryIO): if sys.version_info >= (3, 7): def read1(self, __size: int = ...) -> bytes: ... else: - def read1(self, __size: int) -> bytes: ... # type: ignore + def read1(self, __size: int) -> bytes: ... # type: ignore[override] class BufferedWriter(BufferedIOBase, BinaryIO): def __enter__(self: Self) -> Self: ... @@ -110,7 +110,7 @@ class BufferedRandom(BufferedReader, BufferedWriter): if sys.version_info >= (3, 7): def read1(self, __size: int = ...) -> bytes: ... else: - def read1(self, __size: int) -> bytes: ... # type: ignore + def read1(self, __size: int) -> bytes: ... # type: ignore[override] class BufferedRWPair(BufferedIOBase): def __init__(self, reader: RawIOBase, writer: RawIOBase, buffer_size: int = ...) -> None: ... @@ -119,14 +119,14 @@ class BufferedRWPair(BufferedIOBase): class TextIOBase(IOBase): encoding: str errors: str | None - newlines: str | Tuple[str, ...] | None - def __iter__(self) -> Iterator[str]: ... # type: ignore - def __next__(self) -> str: ... # type: ignore + newlines: str | tuple[str, ...] | None + def __iter__(self) -> Iterator[str]: ... # type: ignore[override] + def __next__(self) -> str: ... # type: ignore[override] def detach(self) -> BinaryIO: ... def write(self, __s: str) -> int: ... - def writelines(self, __lines: Iterable[str]) -> None: ... # type: ignore - def readline(self, __size: int = ...) -> str: ... # type: ignore - def readlines(self, __hint: int = ...) -> list[str]: ... # type: ignore + def writelines(self, __lines: Iterable[str]) -> None: ... # type: ignore[override] + def readline(self, __size: int = ...) -> str: ... # type: ignore[override] + def readlines(self, __hint: int = ...) -> list[str]: ... # type: ignore[override] def read(self, __size: int | None = ...) -> str: ... def tell(self) -> int: ... @@ -160,11 +160,11 @@ class TextIOWrapper(TextIOBase, TextIO): ) -> None: ... # These are inherited from TextIOBase, but must exist in the stub to satisfy mypy. def __enter__(self: Self) -> Self: ... - def __iter__(self) -> Iterator[str]: ... # type: ignore - def __next__(self) -> str: ... # type: ignore - def writelines(self, __lines: Iterable[str]) -> None: ... # type: ignore - def readline(self, __size: int = ...) -> str: ... # type: ignore - def readlines(self, __hint: int = ...) -> list[str]: ... # type: ignore + def __iter__(self) -> Iterator[str]: ... # type: ignore[override] + def __next__(self) -> str: ... # type: ignore[override] + def writelines(self, __lines: Iterable[str]) -> None: ... # type: ignore[override] + def readline(self, __size: int = ...) -> str: ... # type: ignore[override] + def readlines(self, __hint: int = ...) -> list[str]: ... # type: ignore[override] def seek(self, __cookie: int, __whence: int = ...) -> int: ... class StringIO(TextIOWrapper): @@ -179,4 +179,4 @@ class IncrementalNewlineDecoder(codecs.IncrementalDecoder): def __init__(self, decoder: codecs.IncrementalDecoder | None, translate: bool, errors: str = ...) -> None: ... def decode(self, input: bytes | str, final: bool = ...) -> str: ... @property - def newlines(self) -> str | Tuple[str, ...] | None: ... + def newlines(self) -> str | tuple[str, ...] | None: ... diff --git a/mypy/typeshed/stdlib/ipaddress.pyi b/mypy/typeshed/stdlib/ipaddress.pyi index 0ded1ef19b47..1cfd9a7c9378 100644 --- a/mypy/typeshed/stdlib/ipaddress.pyi +++ b/mypy/typeshed/stdlib/ipaddress.pyi @@ -9,9 +9,9 @@ _A = TypeVar("_A", IPv4Address, IPv6Address) _N = TypeVar("_N", IPv4Network, IPv6Network) _T = TypeVar("_T") -def ip_address(address: object) -> Any: ... # morally IPv4Address | IPv6Address -def ip_network(address: object, strict: bool = ...) -> Any: ... # morally IPv4Network | IPv6Network -def ip_interface(address: object) -> Any: ... # morally IPv4Interface | IPv6Interface +def ip_address(address: object) -> IPv4Address | IPv6Address: ... +def ip_network(address: object, strict: bool = ...) -> IPv4Network | IPv6Network: ... +def ip_interface(address: object) -> IPv4Interface | IPv6Interface: ... class _IPAddressBase: def __eq__(self, other: Any) -> bool: ... @@ -84,7 +84,7 @@ class _BaseNetwork(_IPAddressBase, Container[_A], Iterable[_A], Generic[_A]): def max_prefixlen(self) -> int: ... @property def num_addresses(self) -> int: ... - def overlaps(self, other: _BaseNetwork[_A]) -> bool: ... + def overlaps(self, other: _BaseNetwork[IPv4Address] | _BaseNetwork[IPv6Address]) -> bool: ... @property def prefixlen(self) -> int: ... if sys.version_info >= (3, 7): @@ -127,6 +127,9 @@ class IPv6Address(_BaseAddress): def sixtofour(self) -> IPv4Address | None: ... @property def teredo(self) -> tuple[IPv4Address, IPv4Address] | None: ... + if sys.version_info >= (3, 9): + @property + def scope_id(self) -> str | None: ... class IPv6Network(_BaseNetwork[IPv6Address]): @property @@ -136,10 +139,16 @@ class IPv6Interface(IPv6Address, _BaseInterface[IPv6Address, IPv6Network]): ... def v4_int_to_packed(address: int) -> bytes: ... def v6_int_to_packed(address: int) -> bytes: ... + +# Third overload is technically incorrect, but convenient when first and last are return values of ip_address() @overload def summarize_address_range(first: IPv4Address, last: IPv4Address) -> Iterator[IPv4Network]: ... @overload def summarize_address_range(first: IPv6Address, last: IPv6Address) -> Iterator[IPv6Network]: ... +@overload +def summarize_address_range( + first: IPv4Address | IPv6Address, last: IPv4Address | IPv6Address +) -> Iterator[IPv4Network] | Iterator[IPv6Network]: ... def collapse_addresses(addresses: Iterable[_N]) -> Iterator[_N]: ... @overload def get_mixed_type_key(obj: _A) -> tuple[int, _A]: ... diff --git a/mypy/typeshed/stdlib/itertools.pyi b/mypy/typeshed/stdlib/itertools.pyi index 9d666d681781..a5a7f4f1b62f 100644 --- a/mypy/typeshed/stdlib/itertools.pyi +++ b/mypy/typeshed/stdlib/itertools.pyi @@ -9,7 +9,6 @@ from typing import ( SupportsComplex, SupportsFloat, SupportsInt, - Tuple, Type, TypeVar, Union, @@ -17,6 +16,9 @@ from typing import ( ) from typing_extensions import Literal, SupportsIndex +if sys.version_info >= (3, 9): + from types import GenericAlias + _T = TypeVar("_T") _S = TypeVar("_S") _N = TypeVar("_N", int, float, SupportsFloat, SupportsInt, SupportsIndex, SupportsComplex) @@ -67,6 +69,8 @@ class chain(Iterator[_T], Generic[_T]): @classmethod # We use Type and not Type[_S] to not lose the type inference from __iterable def from_iterable(cls: Type[Any], __iterable: Iterable[Iterable[_S]]) -> Iterator[_S]: ... + if sys.version_info >= (3, 9): + def __class_getitem__(cls, __item: Any) -> GenericAlias: ... class compress(Iterator[_T], Generic[_T]): def __init__(self, data: Iterable[_T], selectors: Iterable[Any]) -> None: ... @@ -86,7 +90,7 @@ class filterfalse(Iterator[_T], Generic[_T]): _T1 = TypeVar("_T1") _T2 = TypeVar("_T2") -class groupby(Iterator[Tuple[_T, Iterator[_S]]], Generic[_T, _S]): +class groupby(Iterator[tuple[_T, Iterator[_S]]], Generic[_T, _S]): @overload def __new__(cls, iterable: Iterable[_T1], key: None = ...) -> groupby[_T1, _T1]: ... @overload @@ -112,7 +116,7 @@ class takewhile(Iterator[_T], Generic[_T]): def __iter__(self) -> Iterator[_T]: ... def __next__(self) -> _T: ... -def tee(__iterable: Iterable[_T], __n: int = ...) -> Tuple[Iterator[_T], ...]: ... +def tee(__iterable: Iterable[_T], __n: int = ...) -> tuple[Iterator[_T], ...]: ... class zip_longest(Iterator[Any]): def __init__(self, *p: Iterable[Any], fillvalue: Any = ...) -> None: ... @@ -165,18 +169,18 @@ class product(Iterator[_T_co], Generic[_T_co]): __iter6: Iterable[Any], __iter7: Iterable[Any], *iterables: Iterable[Any], - ) -> product[Tuple[Any, ...]]: ... + ) -> product[tuple[Any, ...]]: ... @overload - def __new__(cls, *iterables: Iterable[_T1], repeat: int) -> product[Tuple[_T1, ...]]: ... + def __new__(cls, *iterables: Iterable[_T1], repeat: int) -> product[tuple[_T1, ...]]: ... @overload - def __new__(cls, *iterables: Iterable[Any], repeat: int = ...) -> product[Tuple[Any, ...]]: ... + def __new__(cls, *iterables: Iterable[Any], repeat: int = ...) -> product[tuple[Any, ...]]: ... def __iter__(self) -> Iterator[_T_co]: ... def __next__(self) -> _T_co: ... -class permutations(Iterator[Tuple[_T, ...]], Generic[_T]): +class permutations(Iterator[tuple[_T, ...]], Generic[_T]): def __init__(self, iterable: Iterable[_T], r: int | None = ...) -> None: ... - def __iter__(self) -> Iterator[Tuple[_T, ...]]: ... - def __next__(self) -> Tuple[_T, ...]: ... + def __iter__(self) -> Iterator[tuple[_T, ...]]: ... + def __next__(self) -> tuple[_T, ...]: ... class combinations(Iterator[_T_co], Generic[_T_co]): @overload @@ -188,14 +192,14 @@ class combinations(Iterator[_T_co], Generic[_T_co]): @overload 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 __new__(cls, iterable: Iterable[_T], r: int) -> combinations[tuple[_T, ...]]: ... def __iter__(self) -> Iterator[_T_co]: ... def __next__(self) -> _T_co: ... -class combinations_with_replacement(Iterator[Tuple[_T, ...]], Generic[_T]): +class combinations_with_replacement(Iterator[tuple[_T, ...]], Generic[_T]): def __init__(self, iterable: Iterable[_T], r: int) -> None: ... - def __iter__(self) -> Iterator[Tuple[_T, ...]]: ... - def __next__(self) -> Tuple[_T, ...]: ... + def __iter__(self) -> Iterator[tuple[_T, ...]]: ... + def __next__(self) -> tuple[_T, ...]: ... if sys.version_info >= (3, 10): class pairwise(Iterator[_T_co], Generic[_T_co]): diff --git a/mypy/typeshed/stdlib/json/encoder.pyi b/mypy/typeshed/stdlib/json/encoder.pyi index 9557a96eee78..6dd74896e5a0 100644 --- a/mypy/typeshed/stdlib/json/encoder.pyi +++ b/mypy/typeshed/stdlib/json/encoder.pyi @@ -1,4 +1,10 @@ -from typing import Any, Callable, Iterator +from typing import Any, Callable, Iterator, Pattern + +ESCAPE: Pattern[str] +ESCAPE_ASCII: Pattern[str] +HAS_UTF8: Pattern[bytes] +ESCAPE_DCT: dict[str, str] +INFINITY: float def py_encode_basestring(s: str) -> str: ... # undocumented def py_encode_basestring_ascii(s: str) -> str: ... # undocumented diff --git a/mypy/typeshed/stdlib/lib2to3/pgen2/grammar.pyi b/mypy/typeshed/stdlib/lib2to3/pgen2/grammar.pyi index 48cb4eae916c..77cc6aec3d67 100644 --- a/mypy/typeshed/stdlib/lib2to3/pgen2/grammar.pyi +++ b/mypy/typeshed/stdlib/lib2to3/pgen2/grammar.pyi @@ -1,10 +1,10 @@ from _typeshed import StrPath -from typing import Dict, List, Optional, Tuple, TypeVar +from typing import Optional, TypeVar _P = TypeVar("_P") -_Label = Tuple[int, Optional[str]] -_DFA = List[List[Tuple[int, int]]] -_DFAS = Tuple[_DFA, Dict[int, int]] +_Label = tuple[int, Optional[str]] +_DFA = list[list[tuple[int, int]]] +_DFAS = tuple[_DFA, dict[int, int]] class Grammar: symbol2number: dict[str, int] diff --git a/mypy/typeshed/stdlib/lib2to3/pgen2/token.pyi b/mypy/typeshed/stdlib/lib2to3/pgen2/token.pyi index c4ab376eca64..2f944c40a02c 100644 --- a/mypy/typeshed/stdlib/lib2to3/pgen2/token.pyi +++ b/mypy/typeshed/stdlib/lib2to3/pgen2/token.pyi @@ -1,3 +1,5 @@ +import sys + ENDMARKER: int NAME: int NUMBER: int @@ -57,6 +59,8 @@ ATEQUAL: int AWAIT: int ASYNC: int ERRORTOKEN: int +if sys.version_info >= (3, 7): + COLONEQUAL: int N_TOKENS: int NT_OFFSET: int tok_name: dict[int, str] diff --git a/mypy/typeshed/stdlib/lib2to3/pgen2/tokenize.pyi b/mypy/typeshed/stdlib/lib2to3/pgen2/tokenize.pyi index e96a0d8c8eb3..3679caee9314 100644 --- a/mypy/typeshed/stdlib/lib2to3/pgen2/tokenize.pyi +++ b/mypy/typeshed/stdlib/lib2to3/pgen2/tokenize.pyi @@ -1,9 +1,9 @@ from lib2to3.pgen2.token import * # noqa -from typing import Callable, Iterable, Iterator, Tuple +from typing import Callable, Iterable, Iterator -_Coord = Tuple[int, int] +_Coord = tuple[int, int] _TokenEater = Callable[[int, str, _Coord, _Coord, str], None] -_TokenInfo = Tuple[int, str, _Coord, _Coord, str] +_TokenInfo = tuple[int, str, _Coord, _Coord, str] class TokenError(Exception): ... class StopTokenizing(Exception): ... diff --git a/mypy/typeshed/stdlib/lib2to3/pytree.pyi b/mypy/typeshed/stdlib/lib2to3/pytree.pyi index eab82cbc200d..2ed9a2788d84 100644 --- a/mypy/typeshed/stdlib/lib2to3/pytree.pyi +++ b/mypy/typeshed/stdlib/lib2to3/pytree.pyi @@ -1,11 +1,11 @@ from lib2to3.pgen2.grammar import Grammar -from typing import Any, Callable, Dict, Iterator, List, Optional, Tuple, TypeVar, Union +from typing import Any, Callable, Iterator, Optional, TypeVar, Union _P = TypeVar("_P") _NL = Union[Node, Leaf] -_Context = Tuple[str, int, int] -_Results = Dict[str, _NL] -_RawNode = Tuple[int, str, _Context, Optional[List[_NL]]] +_Context = tuple[str, int, int] +_Results = dict[str, _NL] +_RawNode = tuple[int, str, _Context, Optional[list[_NL]]] _Convert = Callable[[Grammar, _RawNode], Any] HUGE: int diff --git a/mypy/typeshed/stdlib/linecache.pyi b/mypy/typeshed/stdlib/linecache.pyi index a66614bf6b37..e53d3efea5b2 100644 --- a/mypy/typeshed/stdlib/linecache.pyi +++ b/mypy/typeshed/stdlib/linecache.pyi @@ -1,7 +1,7 @@ -from typing import Any, Dict, List, Protocol, Tuple +from typing import Any, Protocol -_ModuleGlobals = Dict[str, Any] -_ModuleMetadata = Tuple[int, float, List[str], str] +_ModuleGlobals = dict[str, Any] +_ModuleMetadata = tuple[int, float, list[str], str] class _SourceLoader(Protocol): def __call__(self) -> str | None: ... diff --git a/mypy/typeshed/stdlib/locale.pyi b/mypy/typeshed/stdlib/locale.pyi index 1f80c8a62483..f3942102716a 100644 --- a/mypy/typeshed/stdlib/locale.pyi +++ b/mypy/typeshed/stdlib/locale.pyi @@ -4,7 +4,7 @@ import sys # as a type annotation or type alias. from builtins import str as _str from decimal import Decimal -from typing import Any, Callable, Iterable, Mapping, Sequence, Tuple +from typing import Any, Callable, Iterable, Mapping, Sequence CODESET: int D_T_FMT: int @@ -82,13 +82,13 @@ 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: ... def resetlocale(category: int = ...) -> None: ... -def strcoll(string1: _str, string2: _str) -> int: ... -def strxfrm(string: _str) -> _str: ... +def strcoll(__os1: _str, __os2: _str) -> int: ... +def strxfrm(__string: _str) -> _str: ... def format(percent: _str, value: float | Decimal, grouping: bool = ..., monetary: bool = ..., *additional: Any) -> _str: ... if sys.version_info >= (3, 7): diff --git a/mypy/typeshed/stdlib/logging/__init__.pyi b/mypy/typeshed/stdlib/logging/__init__.pyi index c972559c9b60..442e79a9c6f3 100644 --- a/mypy/typeshed/stdlib/logging/__init__.pyi +++ b/mypy/typeshed/stdlib/logging/__init__.pyi @@ -1,17 +1,17 @@ import sys import threading -from _typeshed import StrPath, SupportsWrite +from _typeshed import Self, StrPath, SupportsWrite from collections.abc import Callable, Iterable, Mapping, MutableMapping, Sequence from io import TextIOWrapper from string import Template from time import struct_time from types import FrameType, TracebackType -from typing import Any, ClassVar, Generic, Optional, Pattern, TextIO, Tuple, Type, TypeVar, Union, overload +from typing import Any, ClassVar, Generic, Optional, Pattern, TextIO, Type, TypeVar, Union, overload from typing_extensions import Literal -_SysExcInfoType = Union[Tuple[Type[BaseException], BaseException, Optional[TracebackType]], Tuple[None, None, None]] +_SysExcInfoType = Union[tuple[Type[BaseException], BaseException, Optional[TracebackType]], tuple[None, None, None]] _ExcInfoType = Union[None, bool, _SysExcInfoType, BaseException] -_ArgsType = Union[Tuple[object, ...], Mapping[str, object]] +_ArgsType = Union[tuple[object, ...], Mapping[str, object]] _FilterType = Union[Filter, Callable[[LogRecord], int]] _Level = Union[int, str] _FormatStyle = Literal["%", "{", "$"] @@ -27,14 +27,14 @@ def currentframe() -> FrameType: ... _levelToName: dict[int, str] _nameToLevel: dict[str, int] -class Filterer(object): +class Filterer: filters: list[Filter] def __init__(self) -> None: ... def addFilter(self, filter: _FilterType) -> None: ... def removeFilter(self, filter: _FilterType) -> None: ... def filter(self, record: LogRecord) -> bool: ... -class Manager(object): # undocumented +class Manager: # undocumented root: RootLogger disable: int emittedNoHandlerWarning: bool @@ -59,7 +59,7 @@ class Logger(Filterer): def setLevel(self, level: _Level) -> None: ... def isEnabledFor(self, level: int) -> bool: ... def getEffectiveLevel(self) -> int: ... - def getChild(self, suffix: str) -> Logger: ... + def getChild(self: Self, suffix: str) -> Self: ... # see python/typing#980 if sys.version_info >= (3, 8): def debug( self, @@ -285,7 +285,17 @@ class Formatter: else: default_msec_format: str - if sys.version_info >= (3, 8): + if sys.version_info >= (3, 10): + def __init__( + self, + fmt: str | None = ..., + datefmt: str | None = ..., + style: _FormatStyle = ..., + validate: bool = ..., + *, + defaults: Mapping[str, Any] | None = ..., + ) -> None: ... + elif sys.version_info >= (3, 8): def __init__( self, fmt: str | None = ..., datefmt: str | None = ..., style: _FormatStyle = ..., validate: bool = ... ) -> None: ... @@ -326,6 +336,7 @@ class LogRecord: lineno: int module: str msecs: float + # Only created when logging.Formatter.format is called. See #6132. message: str msg: str name: str @@ -357,7 +368,7 @@ class LoggerAdapter(Generic[_L]): manager: Manager # undocumented if sys.version_info >= (3, 10): extra: Mapping[str, object] | None - def __init__(self, logger: _L, extra: Mapping[str, object] | None) -> None: ... + def __init__(self, logger: _L, extra: Mapping[str, object] | None = ...) -> None: ... else: extra: Mapping[str, object] def __init__(self, logger: _L, extra: Mapping[str, object]) -> None: ... @@ -738,14 +749,17 @@ class RootLogger(Logger): root: RootLogger -class PercentStyle(object): # undocumented +class PercentStyle: # undocumented default_format: str asctime_format: str asctime_search: str if sys.version_info >= (3, 8): validation_pattern: Pattern[str] _fmt: str - def __init__(self, fmt: str) -> None: ... + if sys.version_info >= (3, 10): + def __init__(self, fmt: str, *, defaults: Mapping[str, Any] | None = ...) -> None: ... + else: + def __init__(self, fmt: str) -> None: ... def usesTime(self) -> bool: ... if sys.version_info >= (3, 8): def validate(self) -> None: ... diff --git a/mypy/typeshed/stdlib/logging/handlers.pyi b/mypy/typeshed/stdlib/logging/handlers.pyi index 5be624872a14..50d6d0583556 100644 --- a/mypy/typeshed/stdlib/logging/handlers.pyi +++ b/mypy/typeshed/stdlib/logging/handlers.pyi @@ -128,7 +128,7 @@ class SocketHandler(Handler): def createSocket(self) -> None: ... class DatagramHandler(SocketHandler): - def makeSocket(self) -> socket: ... # type: ignore + def makeSocket(self) -> socket: ... # type: ignore[override] class SysLogHandler(Handler): LOG_EMERG: int diff --git a/mypy/typeshed/stdlib/lzma.pyi b/mypy/typeshed/stdlib/lzma.pyi index e1da3024c4ac..e4bd977d7eab 100644 --- a/mypy/typeshed/stdlib/lzma.pyi +++ b/mypy/typeshed/stdlib/lzma.pyi @@ -41,7 +41,7 @@ PRESET_EXTREME: int # from _lzma.c @final -class LZMADecompressor(object): +class LZMADecompressor: def __init__(self, format: int | None = ..., memlimit: int | None = ..., filters: _FilterChain | None = ...) -> None: ... def decompress(self, data: bytes, max_length: int = ...) -> bytes: ... @property @@ -55,7 +55,7 @@ class LZMADecompressor(object): # from _lzma.c @final -class LZMACompressor(object): +class LZMACompressor: def __init__( self, format: int | None = ..., check: int = ..., preset: int | None = ..., filters: _FilterChain | None = ... ) -> None: ... diff --git a/mypy/typeshed/stdlib/mailcap.pyi b/mypy/typeshed/stdlib/mailcap.pyi index 9eaa771ed3d3..56218d1370fe 100644 --- a/mypy/typeshed/stdlib/mailcap.pyi +++ b/mypy/typeshed/stdlib/mailcap.pyi @@ -1,6 +1,6 @@ -from typing import Dict, Mapping, Sequence, Union +from typing import Mapping, Sequence, Union -_Cap = Dict[str, Union[str, int]] +_Cap = dict[str, Union[str, int]] def findmatch( caps: Mapping[str, list[_Cap]], MIMEtype: str, key: str = ..., filename: str = ..., plist: Sequence[str] = ... diff --git a/mypy/typeshed/stdlib/math.pyi b/mypy/typeshed/stdlib/math.pyi index f92a3d94f978..d5e6f99dfa68 100644 --- a/mypy/typeshed/stdlib/math.pyi +++ b/mypy/typeshed/stdlib/math.pyi @@ -21,6 +21,10 @@ def asinh(__x: _SupportsFloatOrIndex) -> float: ... def atan(__x: _SupportsFloatOrIndex) -> float: ... def atan2(__y: _SupportsFloatOrIndex, __x: _SupportsFloatOrIndex) -> float: ... def atanh(__x: _SupportsFloatOrIndex) -> float: ... + +if sys.version_info >= (3, 11): + def cbrt(__x: _SupportsFloatOrIndex) -> float: ... + def ceil(__x: _SupportsFloatOrIndex) -> int: ... if sys.version_info >= (3, 8): @@ -99,7 +103,7 @@ def pow(__x: _SupportsFloatOrIndex, __y: _SupportsFloatOrIndex) -> float: ... if sys.version_info >= (3, 8): @overload - def prod(__iterable: Iterable[SupportsIndex], *, start: SupportsIndex = ...) -> int: ... # type: ignore + def prod(__iterable: Iterable[SupportsIndex], *, start: SupportsIndex = ...) -> int: ... # type: ignore[misc] @overload def prod(__iterable: Iterable[_SupportsFloatOrIndex], *, start: _SupportsFloatOrIndex = ...) -> float: ... diff --git a/mypy/typeshed/stdlib/mimetypes.pyi b/mypy/typeshed/stdlib/mimetypes.pyi index 90c87d2cf385..8f51c1580eec 100644 --- a/mypy/typeshed/stdlib/mimetypes.pyi +++ b/mypy/typeshed/stdlib/mimetypes.pyi @@ -1,6 +1,6 @@ import sys from _typeshed import StrPath -from typing import IO, Sequence, Tuple +from typing import IO, Sequence if sys.version_info >= (3, 8): def guess_type(url: StrPath, strict: bool = ...) -> tuple[str | None, str | None]: ... @@ -26,9 +26,12 @@ class MimeTypes: encodings_map: 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 __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]: ... + if sys.version_info >= (3, 8): + def guess_type(self, url: StrPath, strict: bool = ...) -> tuple[str | None, str | None]: ... + else: + 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/mmap.pyi b/mypy/typeshed/stdlib/mmap.pyi index 4dd8f8cd2cdd..b79ab92f0c87 100644 --- a/mypy/typeshed/stdlib/mmap.pyi +++ b/mypy/typeshed/stdlib/mmap.pyi @@ -1,6 +1,7 @@ import sys from _typeshed import ReadableBuffer -from typing import ContextManager, Iterable, Iterator, NoReturn, Sized, overload +from contextlib import AbstractContextManager +from typing import Iterable, Iterator, NoReturn, Sized, overload ACCESS_DEFAULT: int ACCESS_READ: int @@ -24,7 +25,7 @@ if sys.platform != "win32": PAGESIZE: int -class mmap(ContextManager[mmap], Iterable[int], Sized): +class mmap(AbstractContextManager[mmap], Iterable[int], Sized): if sys.platform == "win32": def __init__(self, fileno: int, length: int, tagname: str | None = ..., access: int = ..., offset: int = ...) -> None: ... else: diff --git a/mypy/typeshed/stdlib/modulefinder.pyi b/mypy/typeshed/stdlib/modulefinder.pyi index e77a108e9525..3e7694ccffc9 100644 --- a/mypy/typeshed/stdlib/modulefinder.pyi +++ b/mypy/typeshed/stdlib/modulefinder.pyi @@ -1,6 +1,6 @@ import sys from types import CodeType -from typing import IO, Any, Container, Iterable, Iterator, Sequence, Tuple +from typing import IO, Any, Container, Iterable, Iterator, Sequence LOAD_CONST: int # undocumented IMPORT_NAME: int # undocumented @@ -62,7 +62,7 @@ class ModuleFinder: 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 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 diff --git a/mypy/typeshed/stdlib/msilib/__init__.pyi b/mypy/typeshed/stdlib/msilib/__init__.pyi index 4e1a7e6a7c02..b5866492a097 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, Tuple, Type +from typing import Any, Container, Iterable, Sequence, Type from typing_extensions import Literal if sys.platform == "win32": @@ -37,7 +37,7 @@ if sys.platform == "win32": seqno: int | Type[_Unspecified] = ..., cond: str | Type[_Unspecified] = ..., ) -> None: ... - def add_data(db: _Database, table: str, values: Iterable[Tuple[Any, ...]]) -> None: ... + def add_data(db: _Database, table: str, values: Iterable[tuple[Any, ...]]) -> None: ... def add_stream(db: _Database, name: str, path: str) -> None: ... def init_database( name: str, schema: ModuleType, ProductName: str, ProductCode: str, ProductVersion: str, Manufacturer: str diff --git a/mypy/typeshed/stdlib/msilib/sequence.pyi b/mypy/typeshed/stdlib/msilib/sequence.pyi index 123d232886f7..87dff754009d 100644 --- a/mypy/typeshed/stdlib/msilib/sequence.pyi +++ b/mypy/typeshed/stdlib/msilib/sequence.pyi @@ -1,9 +1,9 @@ import sys -from typing import List, Optional, Tuple +from typing import Optional if sys.platform == "win32": - _SequenceType = List[Tuple[str, Optional[str], int]] + _SequenceType = list[tuple[str, Optional[str], int]] AdminExecuteSequence: _SequenceType AdminUISequence: _SequenceType diff --git a/mypy/typeshed/stdlib/multiprocessing/connection.pyi b/mypy/typeshed/stdlib/multiprocessing/connection.pyi index 56ea5c7c0b0b..56db4594edc0 100644 --- a/mypy/typeshed/stdlib/multiprocessing/connection.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/connection.pyi @@ -2,13 +2,13 @@ import socket import sys import types from _typeshed import Self -from typing import Any, Iterable, Tuple, Type, Union +from typing import Any, Iterable, Type, Union if sys.version_info >= (3, 8): from typing import SupportsIndex # https://docs.python.org/3/library/multiprocessing.html#address-formats -_Address = Union[str, Tuple[str, int]] +_Address = Union[str, tuple[str, int]] class _ConnectionBase: if sys.version_info >= (3, 8): diff --git a/mypy/typeshed/stdlib/multiprocessing/context.pyi b/mypy/typeshed/stdlib/multiprocessing/context.pyi index e65a387819bc..83e1b7884efc 100644 --- a/mypy/typeshed/stdlib/multiprocessing/context.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/context.pyi @@ -19,7 +19,7 @@ class BufferTooShort(ProcessError): ... class TimeoutError(ProcessError): ... class AuthenticationError(ProcessError): ... -class BaseContext(object): +class BaseContext: Process: Type[BaseProcess] ProcessError: Type[Exception] BufferTooShort: Type[Exception] diff --git a/mypy/typeshed/stdlib/multiprocessing/dummy/connection.pyi b/mypy/typeshed/stdlib/multiprocessing/dummy/connection.pyi index 4ef3d095911f..9500a38364f0 100644 --- a/mypy/typeshed/stdlib/multiprocessing/dummy/connection.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/dummy/connection.pyi @@ -1,13 +1,13 @@ from _typeshed import Self from queue import Queue from types import TracebackType -from typing import Any, Tuple, Type, Union +from typing import Any, Type, Union families: list[None] -_Address = Union[str, Tuple[str, int]] +_Address = Union[str, tuple[str, int]] -class Connection(object): +class Connection: _in: Any _out: Any recv: Any @@ -22,7 +22,7 @@ class Connection(object): def close(self) -> None: ... def poll(self, timeout: float = ...) -> bool: ... -class Listener(object): +class Listener: _backlog_queue: Queue[Any] | None @property def address(self) -> Queue[Any] | None: ... diff --git a/mypy/typeshed/stdlib/multiprocessing/managers.pyi b/mypy/typeshed/stdlib/multiprocessing/managers.pyi index 22a33f226c0b..79310614efc1 100644 --- a/mypy/typeshed/stdlib/multiprocessing/managers.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/managers.pyi @@ -1,9 +1,8 @@ -# NOTE: These are incomplete! - import queue import sys import threading -from typing import Any, AnyStr, Callable, ContextManager, Generic, Iterable, Mapping, Sequence, Tuple, TypeVar +from contextlib import AbstractContextManager +from typing import Any, AnyStr, Callable, Generic, Iterable, Mapping, Sequence, TypeVar from .connection import Connection from .context import BaseContext @@ -28,7 +27,7 @@ class Namespace: _Namespace = Namespace -class Token(object): +class Token: typeid: str | bytes | None address: tuple[str | bytes, int] id: str | bytes | int | None @@ -37,7 +36,7 @@ class Token(object): 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): +class BaseProxy: _address_to_local: dict[Any, Any] _mutex: Any def __init__( @@ -51,7 +50,7 @@ class BaseProxy(object): manager_owned: bool = ..., ) -> None: ... def __deepcopy__(self, memo: Any | None) -> Any: ... - def _callmethod(self, methodname: str, args: Tuple[Any, ...] = ..., kwds: dict[Any, Any] = ...) -> None: ... + 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]]]: ... @@ -71,7 +70,7 @@ class Server: def serve_forever(self) -> None: ... def accept_connection(self, c: Connection, name: str) -> None: ... -class BaseManager(ContextManager[BaseManager]): +class BaseManager(AbstractContextManager[BaseManager]): def __init__( self, address: Any | None = ..., authkey: bytes | None = ..., serializer: str = ..., ctx: BaseContext | None = ... ) -> None: ... @@ -97,7 +96,7 @@ class BaseManager(ContextManager[BaseManager]): _dict = dict _list = list -class SyncManager(BaseManager, ContextManager[SyncManager]): +class SyncManager(BaseManager, AbstractContextManager[SyncManager]): def BoundedSemaphore(self, value: Any = ...) -> threading.BoundedSemaphore: ... def Condition(self, lock: Any = ...) -> threading.Condition: ... def Event(self) -> threading.Event: ... diff --git a/mypy/typeshed/stdlib/multiprocessing/pool.pyi b/mypy/typeshed/stdlib/multiprocessing/pool.pyi index 75583aae8012..518e4b7364d7 100644 --- a/mypy/typeshed/stdlib/multiprocessing/pool.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/pool.pyi @@ -1,10 +1,14 @@ import sys from _typeshed import Self -from typing import Any, Callable, ContextManager, Generic, Iterable, Iterator, List, Mapping, TypeVar +from contextlib import AbstractContextManager +from typing import Any, Callable, Generic, Iterable, Iterator, Mapping, TypeVar +from typing_extensions import Literal if sys.version_info >= (3, 9): from types import GenericAlias +__all__ = ["Pool", "ThreadPool"] + _PT = TypeVar("_PT", bound=Pool) _S = TypeVar("_S") _T = TypeVar("_T") @@ -31,7 +35,7 @@ class ApplyResult(Generic[_T]): # alias created during issue #17805 AsyncResult = ApplyResult -class MapResult(ApplyResult[List[_T]]): +class MapResult(ApplyResult[list[_T]]): if sys.version_info >= (3, 8): def __init__( self, @@ -62,7 +66,7 @@ class IMapIterator(Iterator[_T]): class IMapUnorderedIterator(IMapIterator[_T]): ... -class Pool(ContextManager[Pool]): +class Pool(AbstractContextManager[Pool]): def __init__( self, processes: int | None = ..., @@ -107,18 +111,18 @@ class Pool(ContextManager[Pool]): def join(self) -> None: ... def __enter__(self: Self) -> Self: ... -class ThreadPool(Pool, ContextManager[ThreadPool]): +class ThreadPool(Pool, AbstractContextManager[ThreadPool]): def __init__( self, processes: int | None = ..., initializer: Callable[..., Any] | None = ..., initargs: Iterable[Any] = ... ) -> None: ... # undocumented if sys.version_info >= (3, 8): - INIT: str - RUN: str - CLOSE: str - TERMINATE: str + INIT: Literal["INIT"] + RUN: Literal["RUN"] + CLOSE: Literal["CLOSE"] + TERMINATE: Literal["TERMINATE"] else: - RUN: int - CLOSE: int - TERMINATE: int + RUN: Literal[0] + CLOSE: Literal[1] + TERMINATE: Literal[2] diff --git a/mypy/typeshed/stdlib/multiprocessing/process.pyi b/mypy/typeshed/stdlib/multiprocessing/process.pyi index 32c22d19f6e5..4746c78b1b4d 100644 --- a/mypy/typeshed/stdlib/multiprocessing/process.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/process.pyi @@ -1,17 +1,17 @@ import sys -from typing import Any, Callable, Mapping, Tuple +from typing import Any, Callable, Mapping class BaseProcess: name: str daemon: bool authkey: bytes - _identity: Tuple[int, ...] # undocumented + _identity: tuple[int, ...] # undocumented def __init__( self, group: None = ..., target: Callable[..., Any] | None = ..., name: str | None = ..., - args: Tuple[Any, ...] = ..., + args: tuple[Any, ...] = ..., kwargs: Mapping[str, Any] = ..., *, daemon: bool | None = ..., diff --git a/mypy/typeshed/stdlib/multiprocessing/shared_memory.pyi b/mypy/typeshed/stdlib/multiprocessing/shared_memory.pyi index 6ffc2542087a..1b51da38bc43 100644 --- a/mypy/typeshed/stdlib/multiprocessing/shared_memory.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/shared_memory.pyi @@ -1,5 +1,5 @@ import sys -from typing import Any, Generic, Iterable, Tuple, TypeVar +from typing import Any, Generic, Iterable, TypeVar if sys.version_info >= (3, 9): from types import GenericAlias @@ -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/multiprocessing/synchronize.pyi b/mypy/typeshed/stdlib/multiprocessing/synchronize.pyi index 1741885f13bf..c32c9aafe9a4 100644 --- a/mypy/typeshed/stdlib/multiprocessing/synchronize.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/synchronize.pyi @@ -1,7 +1,8 @@ import sys import threading +from contextlib import AbstractContextManager from multiprocessing.context import BaseContext -from typing import Any, Callable, ContextManager, Union +from typing import Any, Callable, Union _LockLike = Union[Lock, RLock] @@ -13,7 +14,7 @@ class Barrier(threading.Barrier): class BoundedSemaphore(Semaphore): def __init__(self, value: int = ..., *, ctx: BaseContext) -> None: ... -class Condition(ContextManager[bool]): +class Condition(AbstractContextManager[bool]): def __init__(self, lock: _LockLike | None = ..., *, ctx: BaseContext) -> None: ... if sys.version_info >= (3, 7): def notify(self, n: int = ...) -> None: ... @@ -25,7 +26,7 @@ class Condition(ContextManager[bool]): def acquire(self, block: bool = ..., timeout: float | None = ...) -> bool: ... def release(self) -> None: ... -class Event(ContextManager[bool]): +class Event(AbstractContextManager[bool]): def __init__(self, lock: _LockLike | None = ..., *, ctx: BaseContext) -> None: ... def is_set(self) -> bool: ... def set(self) -> None: ... @@ -42,6 +43,6 @@ class Semaphore(SemLock): def __init__(self, value: int = ..., *, ctx: BaseContext) -> None: ... # Not part of public API -class SemLock(ContextManager[bool]): +class SemLock(AbstractContextManager[bool]): def acquire(self, block: bool = ..., timeout: float | None = ...) -> bool: ... def release(self) -> None: ... diff --git a/mypy/typeshed/stdlib/netrc.pyi b/mypy/typeshed/stdlib/netrc.pyi index b8eac307740a..7c1c2068aff6 100644 --- a/mypy/typeshed/stdlib/netrc.pyi +++ b/mypy/typeshed/stdlib/netrc.pyi @@ -1,5 +1,5 @@ from _typeshed import StrOrBytesPath -from typing import Optional, Tuple +from typing import Optional class NetrcParseError(Exception): filename: str | None @@ -8,7 +8,7 @@ class NetrcParseError(Exception): def __init__(self, msg: str, filename: StrOrBytesPath | None = ..., lineno: int | None = ...) -> None: ... # (login, account, password) tuple -_NetrcTuple = Tuple[str, Optional[str], Optional[str]] +_NetrcTuple = tuple[str, Optional[str], Optional[str]] class netrc: hosts: dict[str, _NetrcTuple] diff --git a/mypy/typeshed/stdlib/nntplib.pyi b/mypy/typeshed/stdlib/nntplib.pyi index 508b5f679bc3..f0a0fb42da5c 100644 --- a/mypy/typeshed/stdlib/nntplib.pyi +++ b/mypy/typeshed/stdlib/nntplib.pyi @@ -3,7 +3,7 @@ import socket import ssl import sys from _typeshed import Self -from typing import IO, Any, Iterable, NamedTuple, Tuple, Union +from typing import IO, Any, Iterable, NamedTuple, Union _File = Union[IO[bytes], bytes, str, None] @@ -72,7 +72,7 @@ class _NNTPBase: 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 = ... + self, message_spec: None | str | _list[Any] | tuple[Any, ...], *, file: _File = ... ) -> 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]]]: ... diff --git a/mypy/typeshed/stdlib/ntpath.pyi b/mypy/typeshed/stdlib/ntpath.pyi index 45d715704157..f691356cb702 100644 --- a/mypy/typeshed/stdlib/ntpath.pyi +++ b/mypy/typeshed/stdlib/ntpath.pyi @@ -48,11 +48,13 @@ altsep: str if sys.version_info < (3, 7) and sys.platform == "win32": def splitunc(p: AnyStr) -> tuple[AnyStr, AnyStr]: ... # deprecated -# Similar to posixpath, but have slightly different argument names +# First parameter is not actually pos-only, +# but must be defined as pos-only in the stub or cross-platform code doesn't type-check, +# as the parameter name is different in posixpath.join() @overload -def join(path: StrPath, *paths: StrPath) -> str: ... +def join(__path: StrPath, *paths: StrPath) -> str: ... @overload -def join(path: BytesPath, *paths: BytesPath) -> bytes: ... +def join(__path: BytesPath, *paths: BytesPath) -> bytes: ... if sys.platform == "win32": if sys.version_info >= (3, 10): diff --git a/mypy/typeshed/stdlib/operator.pyi b/mypy/typeshed/stdlib/operator.pyi index bb8e23733f87..180bd161c045 100644 --- a/mypy/typeshed/stdlib/operator.pyi +++ b/mypy/typeshed/stdlib/operator.pyi @@ -1,179 +1,51 @@ -from typing import ( - Any, - Container, - Generic, - Mapping, - MutableMapping, - MutableSequence, - Sequence, - SupportsAbs, - Tuple, - TypeVar, - overload, -) -from typing_extensions import final +import sys -_T = TypeVar("_T") -_T_co = TypeVar("_T_co", covariant=True) -_K = TypeVar("_K") -_V = TypeVar("_V") +from _operator import * -def lt(__a: Any, __b: Any) -> Any: ... -def le(__a: Any, __b: Any) -> Any: ... -def eq(__a: Any, __b: Any) -> Any: ... -def ne(__a: Any, __b: Any) -> Any: ... -def ge(__a: Any, __b: Any) -> Any: ... -def gt(__a: Any, __b: Any) -> Any: ... -def __lt__(a: Any, b: Any) -> Any: ... -def __le__(a: Any, b: Any) -> Any: ... -def __eq__(a: Any, b: Any) -> Any: ... -def __ne__(a: Any, b: Any) -> Any: ... -def __ge__(a: Any, b: Any) -> Any: ... -def __gt__(a: Any, b: Any) -> Any: ... -def not_(__a: Any) -> bool: ... -def __not__(a: Any) -> bool: ... -def truth(__a: Any) -> bool: ... -def is_(__a: Any, __b: Any) -> bool: ... -def is_not(__a: Any, __b: Any) -> bool: ... -def abs(__a: SupportsAbs[_T]) -> _T: ... -def __abs__(a: SupportsAbs[_T]) -> _T: ... -def add(__a: Any, __b: Any) -> Any: ... -def __add__(a: Any, b: Any) -> Any: ... -def and_(__a: Any, __b: Any) -> Any: ... -def __and__(a: Any, b: Any) -> Any: ... -def floordiv(__a: Any, __b: Any) -> Any: ... -def __floordiv__(a: Any, b: Any) -> Any: ... -def index(__a: Any) -> int: ... -def __index__(a: Any) -> int: ... -def inv(__a: Any) -> Any: ... -def invert(__a: Any) -> Any: ... -def __inv__(a: Any) -> Any: ... -def __invert__(a: Any) -> Any: ... -def lshift(__a: Any, __b: Any) -> Any: ... -def __lshift__(a: Any, b: Any) -> Any: ... -def mod(__a: Any, __b: Any) -> Any: ... -def __mod__(a: Any, b: Any) -> Any: ... -def mul(__a: Any, __b: Any) -> Any: ... -def __mul__(a: Any, b: Any) -> Any: ... -def matmul(__a: Any, __b: Any) -> Any: ... -def __matmul__(a: Any, b: Any) -> Any: ... -def neg(__a: Any) -> Any: ... -def __neg__(a: Any) -> Any: ... -def or_(__a: Any, __b: Any) -> Any: ... -def __or__(a: Any, b: Any) -> Any: ... -def pos(__a: Any) -> Any: ... -def __pos__(a: Any) -> Any: ... -def pow(__a: Any, __b: Any) -> Any: ... -def __pow__(a: Any, b: Any) -> Any: ... -def rshift(__a: Any, __b: Any) -> Any: ... -def __rshift__(a: Any, b: Any) -> Any: ... -def sub(__a: Any, __b: Any) -> Any: ... -def __sub__(a: Any, b: Any) -> Any: ... -def truediv(__a: Any, __b: Any) -> Any: ... -def __truediv__(a: Any, b: Any) -> Any: ... -def xor(__a: Any, __b: Any) -> Any: ... -def __xor__(a: Any, b: Any) -> Any: ... -def concat(__a: Sequence[_T], __b: Sequence[_T]) -> Sequence[_T]: ... -def __concat__(a: Sequence[_T], b: Sequence[_T]) -> Sequence[_T]: ... -def contains(__a: Container[Any], __b: Any) -> bool: ... -def __contains__(a: Container[Any], b: Any) -> bool: ... -def countOf(__a: Container[Any], __b: Any) -> int: ... -@overload -def delitem(__a: MutableSequence[Any], __b: int) -> None: ... -@overload -def delitem(__a: MutableSequence[Any], __b: slice) -> None: ... -@overload -def delitem(__a: MutableMapping[_K, Any], __b: _K) -> None: ... -@overload -def __delitem__(a: MutableSequence[Any], b: int) -> None: ... -@overload -def __delitem__(a: MutableSequence[Any], b: slice) -> None: ... -@overload -def __delitem__(a: MutableMapping[_K, Any], b: _K) -> None: ... -@overload -def getitem(__a: Sequence[_T], __b: int) -> _T: ... -@overload -def getitem(__a: Sequence[_T], __b: slice) -> Sequence[_T]: ... -@overload -def getitem(__a: Mapping[_K, _V], __b: _K) -> _V: ... -@overload -def __getitem__(a: Sequence[_T], b: int) -> _T: ... -@overload -def __getitem__(a: Sequence[_T], b: slice) -> Sequence[_T]: ... -@overload -def __getitem__(a: Mapping[_K, _V], b: _K) -> _V: ... -def indexOf(__a: Sequence[_T], __b: _T) -> int: ... -@overload -def setitem(__a: MutableSequence[_T], __b: int, __c: _T) -> None: ... -@overload -def setitem(__a: MutableSequence[_T], __b: slice, __c: Sequence[_T]) -> None: ... -@overload -def setitem(__a: MutableMapping[_K, _V], __b: _K, __c: _V) -> None: ... -@overload -def __setitem__(a: MutableSequence[_T], b: int, c: _T) -> None: ... -@overload -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]]: ... - @overload - def __new__(cls, attr: str, __attr2: str, __attr3: str) -> attrgetter[tuple[Any, Any, Any]]: ... - @overload - def __new__(cls, attr: str, __attr2: str, __attr3: str, __attr4: str) -> attrgetter[tuple[Any, Any, Any, Any]]: ... - @overload - def __new__(cls, attr: str, *attrs: str) -> attrgetter[Tuple[Any, ...]]: ... - def __call__(self, obj: Any) -> _T_co: ... - -@final -class itemgetter(Generic[_T_co]): - @overload - def __new__(cls, item: Any) -> itemgetter[Any]: ... - @overload - 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]]: ... - @overload - 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: ... - -def iadd(__a: Any, __b: Any) -> Any: ... -def __iadd__(a: Any, b: Any) -> Any: ... -def iand(__a: Any, __b: Any) -> Any: ... -def __iand__(a: Any, b: Any) -> Any: ... -def iconcat(__a: Any, __b: Any) -> Any: ... -def __iconcat__(a: Any, b: Any) -> Any: ... -def ifloordiv(__a: Any, __b: Any) -> Any: ... -def __ifloordiv__(a: Any, b: Any) -> Any: ... -def ilshift(__a: Any, __b: Any) -> Any: ... -def __ilshift__(a: Any, b: Any) -> Any: ... -def imod(__a: Any, __b: Any) -> Any: ... -def __imod__(a: Any, b: Any) -> Any: ... -def imul(__a: Any, __b: Any) -> Any: ... -def __imul__(a: Any, b: Any) -> Any: ... -def imatmul(__a: Any, __b: Any) -> Any: ... -def __imatmul__(a: Any, b: Any) -> Any: ... -def ior(__a: Any, __b: Any) -> Any: ... -def __ior__(a: Any, b: Any) -> Any: ... -def ipow(__a: Any, __b: Any) -> Any: ... -def __ipow__(a: Any, b: Any) -> Any: ... -def irshift(__a: Any, __b: Any) -> Any: ... -def __irshift__(a: Any, b: Any) -> Any: ... -def isub(__a: Any, __b: Any) -> Any: ... -def __isub__(a: Any, b: Any) -> Any: ... -def itruediv(__a: Any, __b: Any) -> Any: ... -def __itruediv__(a: Any, b: Any) -> Any: ... -def ixor(__a: Any, __b: Any) -> Any: ... -def __ixor__(a: Any, b: Any) -> Any: ... +__lt__ = lt +__le__ = le +__eq__ = eq +__ne__ = ne +__ge__ = ge +__gt__ = gt +__not__ = not_ +__abs__ = abs +__add__ = add +__and__ = and_ +__floordiv__ = floordiv +__index__ = index +__inv__ = inv +__invert__ = invert +__lshift__ = lshift +__mod__ = mod +__mul__ = mul +__matmul__ = matmul +__neg__ = neg +__or__ = or_ +__pos__ = pos +__pow__ = pow +__rshift__ = rshift +__sub__ = sub +__truediv__ = truediv +__xor__ = xor +__concat__ = concat +__contains__ = contains +__delitem__ = delitem +__getitem__ = getitem +__setitem__ = setitem +__iadd__ = iadd +__iand__ = iand +__iconcat__ = iconcat +__ifloordiv__ = ifloordiv +__ilshift__ = ilshift +__imod__ = imod +__imul__ = imul +__imatmul__ = imatmul +__ior__ = ior +__ipow__ = ipow +__irshift__ = irshift +__isub__ = isub +__itruediv__ = itruediv +__ixor__ = ixor +if sys.version_info >= (3, 11): + __call__ = call diff --git a/mypy/typeshed/stdlib/optparse.pyi b/mypy/typeshed/stdlib/optparse.pyi index b8ea9d2fff38..416bc5446cc5 100644 --- a/mypy/typeshed/stdlib/optparse.pyi +++ b/mypy/typeshed/stdlib/optparse.pyi @@ -1,6 +1,6 @@ -from typing import IO, Any, AnyStr, Callable, Iterable, Mapping, Sequence, Tuple, Type, overload +from typing import IO, Any, AnyStr, Callable, Iterable, Mapping, Sequence, Type, overload -NO_DEFAULT: Tuple[str, ...] +NO_DEFAULT: tuple[str, ...] SUPPRESS_HELP: str SUPPRESS_USAGE: str @@ -72,14 +72,14 @@ class TitledHelpFormatter(HelpFormatter): def format_usage(self, usage: str) -> str: ... class Option: - ACTIONS: Tuple[str, ...] - ALWAYS_TYPED_ACTIONS: Tuple[str, ...] + ACTIONS: tuple[str, ...] + ALWAYS_TYPED_ACTIONS: tuple[str, ...] ATTRS: list[str] CHECK_METHODS: list[Callable[..., Any]] | None - CONST_ACTIONS: Tuple[str, ...] - STORE_ACTIONS: Tuple[str, ...] - TYPED_ACTIONS: Tuple[str, ...] - TYPES: Tuple[str, ...] + CONST_ACTIONS: tuple[str, ...] + STORE_ACTIONS: tuple[str, ...] + TYPED_ACTIONS: tuple[str, ...] + TYPES: tuple[str, ...] TYPE_CHECKER: dict[str, Callable[..., Any]] _long_opts: list[str] _short_opts: list[str] @@ -89,7 +89,7 @@ class Option: nargs: int type: Any callback: Callable[..., Any] | None - callback_args: Tuple[Any, ...] | None + callback_args: tuple[Any, ...] | None callback_kwargs: dict[str, Any] | None help: str | None metavar: str | None diff --git a/mypy/typeshed/stdlib/os/__init__.pyi b/mypy/typeshed/stdlib/os/__init__.pyi index b432f6931a3f..5308416adff4 100644 --- a/mypy/typeshed/stdlib/os/__init__.pyi +++ b/mypy/typeshed/stdlib/os/__init__.pyi @@ -9,10 +9,11 @@ from _typeshed import ( Self, StrOrBytesPath, StrPath, + structseq, ) from builtins import OSError +from contextlib import AbstractContextManager from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper as _TextIOWrapper -from posix import listdir as listdir, times_result from subprocess import Popen from typing import ( IO, @@ -20,17 +21,14 @@ from typing import ( AnyStr, BinaryIO, Callable, - ContextManager, Generic, Iterable, Iterator, - List, Mapping, MutableMapping, NoReturn, Protocol, Sequence, - Tuple, TypeVar, Union, overload, @@ -92,6 +90,9 @@ if sys.platform != "win32": P_PGID: int P_ALL: int + if sys.platform == "linux" and sys.version_info >= (3, 9): + P_PIDFD: int + WEXITED: int WSTOPPED: int WNOWAIT: int @@ -101,6 +102,12 @@ if sys.platform != "win32": CLD_TRAPPED: int CLD_CONTINUED: int + if sys.version_info >= (3, 9): + CLD_KILLED: int + CLD_STOPPED: int + + # TODO: SCHED_RESET_ON_FORK not available on darwin? + # TODO: SCHED_BATCH and SCHED_IDLE are linux only? SCHED_OTHER: int # some flavors of Unix SCHED_BATCH: int # some flavors of Unix SCHED_IDLE: int # some flavors of Unix @@ -119,6 +126,8 @@ if sys.platform != "win32": if sys.platform == "linux": RTLD_DEEPBIND: int + GRND_NONBLOCK: int + GRND_RANDOM: int SEEK_SET: int SEEK_CUR: int @@ -161,6 +170,24 @@ O_NOATIME: int # Gnu extension if in C library O_PATH: int # Gnu extension if in C library O_TMPFILE: int # Gnu extension if in C library O_LARGEFILE: int # Gnu extension if in C library +O_ACCMODE: int # TODO: when does this exist? + +if sys.platform != "win32" and sys.platform != "darwin": + # posix, but apparently missing on macos + ST_APPEND: int + ST_MANDLOCK: int + ST_NOATIME: int + ST_NODEV: int + ST_NODIRATIME: int + ST_NOEXEC: int + ST_RELATIME: int + ST_SYNCHRONOUS: int + ST_WRITE: int + +if sys.platform != "win32": + NGROUPS_MAX: int + ST_NOSUID: int + ST_RDONLY: int curdir: str pardir: str @@ -210,7 +237,7 @@ class _Environ(MutableMapping[AnyStr, AnyStr], Generic[AnyStr]): putenv: Callable[[AnyStr, AnyStr], None], unsetenv: Callable[[AnyStr, AnyStr], None], ) -> None: ... - def setdefault(self, key: AnyStr, value: AnyStr) -> AnyStr: ... # type: ignore + def setdefault(self, key: AnyStr, value: AnyStr) -> AnyStr: ... # type: ignore[override] def copy(self) -> dict[AnyStr, AnyStr]: ... def __delitem__(self, key: AnyStr) -> None: ... def __getitem__(self, key: AnyStr) -> AnyStr: ... @@ -262,55 +289,84 @@ 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 - # (and portable) members of the stat structure, in the order st_mode, - # st_ino, st_dev, st_nlink, st_uid, st_gid, st_size, st_atime, st_mtime, - # st_ctime. More items may be added at the end by some implementations. - - st_mode: int # protection bits, - st_ino: int # inode number, - st_dev: int # device, - st_nlink: int # number of hard links, - st_uid: int # user id of owner, - st_gid: int # group id of owner, - st_size: int # size of file, in bytes, - st_atime: float # time of most recent access, - st_mtime: float # time of most recent content modification, - st_ctime: float # platform dependent (time of most recent metadata change on Unix, or the time of creation on Windows) - st_atime_ns: int # time of most recent access, in nanoseconds - st_mtime_ns: int # time of most recent content modification in nanoseconds - st_ctime_ns: int # platform dependent (time of most recent metadata change on Unix, or the time of creation on Windows) in nanoseconds - if sys.version_info >= (3, 8) and sys.platform == "win32": - st_reparse_tag: int +class stat_result(structseq[float], tuple[int, int, int, int, int, int, int, float, float, float]): + # The constructor of this class takes an iterable of variable length (though it must be at least 10). + # + # However, this class behaves like a tuple of 10 elements, + # no matter how long the iterable supplied to the constructor is. + # https://github.com/python/typeshed/pull/6560#discussion_r767162532 + # + # The 10 elements always present are st_mode, st_ino, st_dev, st_nlink, + # st_uid, st_gid, st_size, st_atime, st_mtime, st_ctime. + # + # More items may be added at the end by some implementations. + @property + def st_mode(self) -> int: ... # protection bits, + @property + def st_ino(self) -> int: ... # inode number, + @property + def st_dev(self) -> int: ... # device, + @property + def st_nlink(self) -> int: ... # number of hard links, + @property + def st_uid(self) -> int: ... # user id of owner, + @property + def st_gid(self) -> int: ... # group id of owner, + @property + def st_size(self) -> int: ... # size of file, in bytes, + @property + def st_atime(self) -> float: ... # time of most recent access, + @property + def st_mtime(self) -> float: ... # time of most recent content modification, + # platform dependent (time of most recent metadata change on Unix, or the time of creation on Windows) + @property + def st_ctime(self) -> float: ... + @property + def st_atime_ns(self) -> int: ... # time of most recent access, in nanoseconds + @property + def st_mtime_ns(self) -> int: ... # time of most recent content modification in nanoseconds + # platform dependent (time of most recent metadata change on Unix, or the time of creation on Windows) in nanoseconds + @property + def st_ctime_ns(self) -> int: ... if sys.platform == "win32": - st_file_attributes: int - def __getitem__(self, i: int) -> int: ... - # not documented - def __init__(self, tuple: Tuple[int, ...]) -> None: ... - # On some Unix systems (such as Linux), the following attributes may also - # be available: - st_blocks: int # number of blocks allocated for file - st_blksize: int # filesystem blocksize - st_rdev: int # type of device if an inode device - st_flags: int # user defined flags for file - - # On other Unix systems (such as FreeBSD), the following attributes may be - # available (but may be only filled out if root tries to use them): - st_gen: int # file generation number - st_birthtime: int # time of file creation - - # On Mac OS systems, the following attributes may also be available: - st_rsize: int - st_creator: int - st_type: int + @property + def st_file_attributes(self) -> int: ... + if sys.version_info >= (3, 8): + @property + def st_reparse_tag(self) -> int: ... + else: + @property + def st_blocks(self) -> int: ... # number of blocks allocated for file + @property + def st_blksize(self) -> int: ... # filesystem blocksize + @property + def st_rdev(self) -> int: ... # type of device if an inode device + if sys.platform != "linux": + # These properties are available on MacOS, but not on Windows or Ubuntu. + # On other Unix systems (such as FreeBSD), the following attributes may be + # available (but may be only filled out if root tries to use them): + @property + def st_gen(self) -> int: ... # file generation number + @property + def st_birthtime(self) -> int: ... # time of file creation + if sys.platform == "darwin": + @property + def st_flags(self) -> int: ... # user defined flags for file + # Atributes documented as sometimes appearing, but deliberately omitted from the stub: `st_creator`, `st_rsize`, `st_type`. + # See https://github.com/python/typeshed/pull/6560#issuecomment-991253327 @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: ... + +@overload +def listdir(path: str | None = ...) -> list[str]: ... +@overload +def listdir(path: bytes) -> list[bytes]: ... +@overload +def listdir(path: int) -> list[str]: ... +@overload +def listdir(path: PathLike[str]) -> list[str]: ... _FdOrAnyPath = Union[int, StrOrBytesPath] @@ -330,45 +386,55 @@ class DirEntry(Generic[AnyStr]): if sys.version_info >= (3, 9): def __class_getitem__(cls, item: Any) -> GenericAlias: ... -if sys.platform != "win32": - _Tuple10Int = Tuple[int, int, int, int, int, int, int, int, int, int] - _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 - n_sequence_fields: int - n_unnamed_fields: int - - f_bsize: int - f_frsize: int - f_blocks: int - f_bfree: int - f_bavail: int - f_files: int - f_ffree: int - f_favail: int - f_flag: int - f_namemax: int - f_fsid: int - else: - class statvfs_result(_Tuple10Int): # Unix only - n_fields: int - n_sequence_fields: int - n_unnamed_fields: int - - f_bsize: int - f_frsize: int - f_blocks: int - f_bfree: int - f_bavail: int - f_files: int - f_ffree: int - f_favail: int - f_flag: int - f_namemax: int +if sys.version_info >= (3, 7): + @final + class statvfs_result(structseq[int], tuple[int, int, int, int, int, int, int, int, int, int, int]): + @property + def f_bsize(self) -> int: ... + @property + def f_frsize(self) -> int: ... + @property + def f_blocks(self) -> int: ... + @property + def f_bfree(self) -> int: ... + @property + def f_bavail(self) -> int: ... + @property + def f_files(self) -> int: ... + @property + def f_ffree(self) -> int: ... + @property + def f_favail(self) -> int: ... + @property + def f_flag(self) -> int: ... + @property + def f_namemax(self) -> int: ... + @property + def f_fsid(self) -> int: ... + +else: + @final + class statvfs_result(structseq[int], tuple[int, int, int, int, int, int, int, int, int, int]): + @property + def f_bsize(self) -> int: ... + @property + def f_frsize(self) -> int: ... + @property + def f_blocks(self) -> int: ... + @property + def f_bfree(self) -> int: ... + @property + def f_bavail(self) -> int: ... + @property + def f_files(self) -> int: ... + @property + def f_ffree(self) -> int: ... + @property + def f_favail(self) -> int: ... + @property + def f_flag(self) -> int: ... + @property + def f_namemax(self) -> int: ... # ----- os function stubs ----- def fsencode(filename: StrOrBytesPath) -> bytes: ... @@ -385,9 +451,20 @@ def getpid() -> int: ... def getppid() -> int: ... def strerror(__code: int) -> str: ... def umask(__mask: int) -> int: ... +@final +class uname_result(structseq[str], tuple[str, str, str, str, str]): + @property + def sysname(self) -> str: ... + @property + def nodename(self) -> str: ... + @property + def release(self) -> str: ... + @property + def version(self) -> str: ... + @property + def machine(self) -> str: ... if sys.platform != "win32": - # Unix only def ctermid() -> str: ... def getegid() -> int: ... def geteuid() -> int: ... @@ -417,7 +494,6 @@ if sys.platform != "win32": def getsid(__pid: int) -> int: ... def setsid() -> None: ... def setuid(__uid: int) -> None: ... - from posix import uname_result def uname() -> uname_result: ... @overload @@ -433,7 +509,7 @@ if sys.platform != "win32": def putenv(__name: bytes | str, __value: bytes | str) -> None: ... -if sys.platform != "win32": +if sys.platform != "win32" or sys.version_info >= (3, 9): def unsetenv(__name: bytes | str) -> None: ... _Opener = Callable[[str, int], int] @@ -527,7 +603,9 @@ else: def dup2(fd: int, fd2: int, inheritable: bool = ...) -> None: ... def fstat(fd: int) -> stat_result: ... +def ftruncate(__fd: int, __length: int) -> None: ... def fsync(fd: FileDescriptorLike) -> None: ... +def isatty(__fd: int) -> bool: ... 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]: ... @@ -537,22 +615,29 @@ if sys.platform != "win32": # Unix only def fchmod(fd: int, mode: int) -> None: ... def fchown(fd: int, uid: int, gid: int) -> None: ... - if sys.platform != "darwin": - def fdatasync(fd: FileDescriptorLike) -> None: ... # Unix only, not Mac def fpathconf(__fd: int, __name: str | int) -> int: ... def fstatvfs(__fd: int) -> statvfs_result: ... - def ftruncate(__fd: int, __length: int) -> None: ... def get_blocking(__fd: int) -> bool: ... 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 if sys.platform != "darwin": - def pipe2(flags: int) -> tuple[int, int]: ... # some flavors of Unix + def fdatasync(fd: FileDescriptorLike) -> None: ... + 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: ... def pwrite(__fd: int, __buffer: bytes, __offset: int) -> int: ... + if sys.platform != "darwin": + if sys.version_info >= (3, 10): + RWF_APPEND: int # docs say available on 3.7+, stubtest says otherwise + if sys.version_info >= (3, 7): + def preadv(__fd: int, __buffers: Iterable[bytes], __offset: int, __flags: int = ...) -> int: ... + def pwritev(__fd: int, __buffers: Iterable[bytes], __offset: int, __flags: int = ...) -> int: ... + RWF_DSYNC: int + RWF_SYNC: int + RWF_HIPRI: int + RWF_NOWAIT: int @overload def sendfile(out_fd: int, in_fd: int, offset: int | None, count: int) -> int: ... @overload @@ -569,9 +654,11 @@ if sys.platform != "win32": def writev(__fd: int, __buffers: Sequence[bytes]) -> int: ... @final -class terminal_size(Tuple[int, int]): - columns: int - lines: int +class terminal_size(structseq[int], tuple[int, int]): + @property + def columns(self) -> int: ... + @property + def lines(self) -> int: ... def get_terminal_size(fd: int = ...) -> terminal_size: ... def get_inheritable(__fd: int) -> bool: ... @@ -596,17 +683,14 @@ def getcwd() -> str: ... def getcwdb() -> bytes: ... def chmod(path: _FdOrAnyPath, mode: int, *, dir_fd: int | None = ..., follow_symlinks: bool = ...) -> None: ... -if sys.platform != "win32": +if sys.platform != "win32" and sys.platform != "linux": def chflags(path: StrOrBytesPath, flags: int, follow_symlinks: bool = ...) -> None: ... # some flavors of Unix - def chown( - path: _FdOrAnyPath, uid: int, gid: int, *, dir_fd: int | None = ..., follow_symlinks: bool = ... - ) -> None: ... # Unix only + def lchflags(path: StrOrBytesPath, flags: int) -> None: ... + def lchmod(path: StrOrBytesPath, mode: int) -> None: ... if sys.platform != "win32": - # Unix only def chroot(path: StrOrBytesPath) -> None: ... - def lchflags(path: StrOrBytesPath, flags: int) -> None: ... - def lchmod(path: StrOrBytesPath, mode: int) -> None: ... + def chown(path: _FdOrAnyPath, uid: int, gid: int, *, dir_fd: int | None = ..., follow_symlinks: bool = ...) -> None: ... def lchown(path: StrOrBytesPath, uid: int, gid: int) -> None: ... def link( @@ -640,7 +724,7 @@ def renames(old: StrOrBytesPath, new: StrOrBytesPath) -> None: ... def replace(src: StrOrBytesPath, dst: StrOrBytesPath, *, src_dir_fd: int | None = ..., dst_dir_fd: int | None = ...) -> None: ... def rmdir(path: StrOrBytesPath, *, dir_fd: int | None = ...) -> None: ... -class _ScandirIterator(Iterator[DirEntry[AnyStr]], ContextManager[_ScandirIterator[AnyStr]]): +class _ScandirIterator(Iterator[DirEntry[AnyStr]], AbstractContextManager[_ScandirIterator[AnyStr]]): def __next__(self) -> DirEntry[AnyStr]: ... def close(self) -> None: ... @@ -744,14 +828,14 @@ def execlpe(file: StrOrBytesPath, __arg0: StrOrBytesPath, *args: Any) -> NoRetur # in practice, and doing so would explode the number of combinations in this already long union. # All these combinations are necessary due to list being invariant. _ExecVArgs = Union[ - Tuple[StrOrBytesPath, ...], - List[bytes], - List[str], - List[PathLike[Any]], - List[Union[bytes, str]], - List[Union[bytes, PathLike[Any]]], - List[Union[str, PathLike[Any]]], - List[Union[bytes, str, PathLike[Any]]], + tuple[StrOrBytesPath, ...], + list[bytes], + list[str], + list[PathLike[Any]], + list[Union[bytes, str]], + list[Union[bytes, PathLike[Any]]], + list[Union[str, PathLike[Any]]], + list[Union[bytes, str, PathLike[Any]]], ] _ExecEnv = Union[Mapping[bytes, Union[bytes, str]], Mapping[str, Union[bytes, str]]] @@ -773,7 +857,7 @@ if sys.platform != "win32": class _wrap_close(_TextIOWrapper): def __init__(self, stream: _TextIOWrapper, proc: Popen[str]) -> None: ... - def close(self) -> int | None: ... # type: ignore + def close(self) -> int | None: ... # type: ignore[override] def popen(cmd: str, mode: str = ..., buffering: int = ...) -> _wrap_close: ... def spawnl(mode: int, file: StrOrBytesPath, arg0: StrOrBytesPath, *args: StrOrBytesPath) -> int: ... @@ -788,6 +872,19 @@ else: def spawnve(__mode: int, __path: StrOrBytesPath, __argv: _ExecVArgs, __env: _ExecEnv) -> int: ... def system(command: StrOrBytesPath) -> int: ... +@final +class times_result(structseq[float], tuple[float, float, float, float, float]): + @property + def user(self) -> float: ... + @property + def system(self) -> float: ... + @property + def children_user(self) -> float: ... + @property + def children_system(self) -> float: ... + @property + def elapsed(self) -> float: ... + def times() -> times_result: ... def waitpid(__pid: int, __options: int) -> tuple[int, int]: ... @@ -795,14 +892,24 @@ if sys.platform == "win32": def startfile(path: StrOrBytesPath, operation: str | None = ...) -> None: ... else: - # Unix only def spawnlp(mode: int, file: StrOrBytesPath, arg0: StrOrBytesPath, *args: StrOrBytesPath) -> int: ... 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 if sys.platform != "darwin": - from posix import waitid_result + @final + class waitid_result(structseq[int], tuple[int, int, int, int, int]): + @property + def si_pid(self) -> int: ... + @property + def si_uid(self) -> int: ... + @property + def si_signo(self) -> int: ... + @property + def si_status(self) -> int: ... + @property + def si_code(self) -> int: ... 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]: ... @@ -815,10 +922,42 @@ else: def WSTOPSIG(status: int) -> int: ... def WTERMSIG(status: int) -> int: ... if sys.version_info >= (3, 8): - from posix import posix_spawn as posix_spawn, posix_spawnp as posix_spawnp + def posix_spawn( + path: StrOrBytesPath, + argv: _ExecVArgs, + env: _ExecEnv, + *, + file_actions: Sequence[tuple[Any, ...]] | None = ..., + setpgroup: int | None = ..., + resetids: bool = ..., + setsid: bool = ..., + setsigmask: Iterable[int] = ..., + setsigdef: Iterable[int] = ..., + scheduler: tuple[Any, sched_param] | None = ..., + ) -> int: ... + def posix_spawnp( + path: StrOrBytesPath, + argv: _ExecVArgs, + env: _ExecEnv, + *, + file_actions: Sequence[tuple[Any, ...]] | None = ..., + setpgroup: int | None = ..., + resetids: bool = ..., + setsid: bool = ..., + setsigmask: Iterable[int] = ..., + setsigdef: Iterable[int] = ..., + scheduler: tuple[Any, sched_param] | None = ..., + ) -> int: ... + POSIX_SPAWN_OPEN: int + POSIX_SPAWN_CLOSE: int + POSIX_SPAWN_DUP2: int if sys.platform != "win32": - from posix import sched_param + @final + class sched_param(structseq[int], tuple[int]): + def __new__(cls, sched_priority: int) -> sched_param: ... + @property + def sched_priority(self) -> int: ... def sched_get_priority_min(policy: int) -> int: ... # some flavors of Unix def sched_get_priority_max(policy: int) -> int: ... # some flavors of Unix def sched_yield() -> None: ... # some flavors of Unix @@ -880,3 +1019,6 @@ if sys.version_info >= (3, 8): MFD_HUGE_2GB: int MFD_HUGE_16GB: int def memfd_create(name: str, flags: int = ...) -> int: ... + +if sys.version_info >= (3, 9): + def waitstatus_to_exitcode(status: int) -> int: ... diff --git a/mypy/typeshed/stdlib/parser.pyi b/mypy/typeshed/stdlib/parser.pyi index aecf3244ca8d..ab819a71a15f 100644 --- a/mypy/typeshed/stdlib/parser.pyi +++ b/mypy/typeshed/stdlib/parser.pyi @@ -1,13 +1,13 @@ from _typeshed import StrOrBytesPath from types import CodeType -from typing import Any, Sequence, Tuple +from typing import Any, Sequence def expr(source: str) -> STType: ... 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 7d5f7ff2dba8..b541345c06d4 100644 --- a/mypy/typeshed/stdlib/pathlib.pyi +++ b/mypy/typeshed/stdlib/pathlib.pyi @@ -11,7 +11,7 @@ from _typeshed import ( from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper from os import PathLike, stat_result from types import TracebackType -from typing import IO, Any, BinaryIO, Generator, Sequence, Tuple, Type, TypeVar, overload +from typing import IO, Any, BinaryIO, Generator, Sequence, Type, TypeVar, overload from typing_extensions import Literal if sys.version_info >= (3, 9): @@ -20,7 +20,7 @@ if sys.version_info >= (3, 9): _P = TypeVar("_P", bound=PurePath) class PurePath(PathLike[str]): - parts: Tuple[str, ...] + parts: tuple[str, ...] drive: str root: str anchor: str diff --git a/mypy/typeshed/stdlib/pickle.pyi b/mypy/typeshed/stdlib/pickle.pyi index cef1ffe9eb9b..46c349137459 100644 --- a/mypy/typeshed/stdlib/pickle.pyi +++ b/mypy/typeshed/stdlib/pickle.pyi @@ -1,11 +1,11 @@ import sys -from typing import Any, Callable, ClassVar, Iterable, Iterator, Mapping, Optional, Protocol, Tuple, Type, Union +from typing import Any, Callable, ClassVar, Iterable, Iterator, Mapping, Optional, Protocol, Type, Union from typing_extensions import final HIGHEST_PROTOCOL: int DEFAULT_PROTOCOL: int -bytes_types: Tuple[Type[Any], ...] # undocumented +bytes_types: tuple[Type[Any], ...] # undocumented class _ReadableFileobj(Protocol): def read(self, __n: int) -> bytes: ... @@ -58,10 +58,10 @@ class UnpicklingError(PickleError): ... _reducedtype = Union[ str, - Tuple[Callable[..., Any], Tuple[Any, ...]], - Tuple[Callable[..., Any], Tuple[Any, ...], Any], - Tuple[Callable[..., Any], Tuple[Any, ...], Any, Optional[Iterator[Any]]], - Tuple[Callable[..., Any], Tuple[Any, ...], Any, Optional[Iterator[Any]], Optional[Iterator[Any]]], + tuple[Callable[..., Any], tuple[Any, ...]], + tuple[Callable[..., Any], tuple[Any, ...], Any], + tuple[Callable[..., Any], tuple[Any, ...], Any, Optional[Iterator[Any]]], + tuple[Callable[..., Any], tuple[Any, ...], Any, Optional[Iterator[Any]], Optional[Iterator[Any]]], ] class Pickler: diff --git a/mypy/typeshed/stdlib/pickletools.pyi b/mypy/typeshed/stdlib/pickletools.pyi index 9fa51a3848ee..04a695f5f103 100644 --- a/mypy/typeshed/stdlib/pickletools.pyi +++ b/mypy/typeshed/stdlib/pickletools.pyi @@ -1,7 +1,7 @@ -from typing import IO, Any, Callable, Iterator, MutableMapping, Tuple, Type +from typing import IO, Any, Callable, Iterator, MutableMapping, Type _Reader = Callable[[IO[bytes]], Any] -bytes_types: Tuple[Type[Any], ...] +bytes_types: tuple[Type[Any], ...] UP_TO_NEWLINE: int TAKEN_FROM_ARGUMENT1: int @@ -9,7 +9,7 @@ TAKEN_FROM_ARGUMENT4: int TAKEN_FROM_ARGUMENT4U: int TAKEN_FROM_ARGUMENT8U: int -class ArgumentDescriptor(object): +class ArgumentDescriptor: name: str n: int reader: _Reader @@ -106,11 +106,11 @@ def read_long4(f: IO[bytes]) -> int: ... long4: ArgumentDescriptor -class StackObject(object): +class StackObject: name: str - obtype: Type[Any] | Tuple[Type[Any], ...] + obtype: Type[Any] | tuple[Type[Any], ...] doc: str - def __init__(self, name: str, obtype: Type[Any] | Tuple[Type[Any], ...], doc: str) -> None: ... + def __init__(self, name: str, obtype: Type[Any] | tuple[Type[Any], ...], doc: str) -> None: ... pyint: StackObject pylong: StackObject @@ -131,7 +131,7 @@ anyobject: StackObject markobject: StackObject stackslice: StackObject -class OpcodeInfo(object): +class OpcodeInfo: name: str code: str arg: ArgumentDescriptor | None diff --git a/mypy/typeshed/stdlib/platform.pyi b/mypy/typeshed/stdlib/platform.pyi index 7db2d59ff7ea..765a7a5ea5f9 100644 --- a/mypy/typeshed/stdlib/platform.pyi +++ b/mypy/typeshed/stdlib/platform.pyi @@ -4,7 +4,7 @@ if sys.version_info < (3, 8): import os DEV_NULL = os.devnull -from typing import NamedTuple, Tuple +from typing import NamedTuple if sys.version_info >= (3, 8): def libc_ver(executable: str | None = ..., lib: str = ..., version: str = ..., chunksize: int = ...) -> tuple[str, str]: ... @@ -17,11 +17,11 @@ if sys.version_info < (3, 8): distname: str = ..., version: str = ..., id: str = ..., - supported_dists: Tuple[str, ...] = ..., + supported_dists: tuple[str, ...] = ..., full_distribution_name: bool = ..., ) -> tuple[str, str, str]: ... def dist( - distname: str = ..., version: str = ..., id: str = ..., supported_dists: Tuple[str, ...] = ... + distname: str = ..., version: str = ..., id: str = ..., supported_dists: tuple[str, ...] = ... ) -> tuple[str, str, str]: ... def win32_ver(release: str = ..., version: str = ..., csd: str = ..., ptype: str = ...) -> tuple[str, str, str, str]: ... @@ -62,3 +62,6 @@ def python_revision() -> str: ... def python_build() -> tuple[str, str]: ... def python_compiler() -> str: ... def platform(aliased: bool = ..., terse: bool = ...) -> str: ... + +if sys.version_info >= (3, 10): + def freedesktop_os_release() -> dict[str, str]: ... diff --git a/mypy/typeshed/stdlib/plistlib.pyi b/mypy/typeshed/stdlib/plistlib.pyi index 07b6963746be..7abe9dd2942b 100644 --- a/mypy/typeshed/stdlib/plistlib.pyi +++ b/mypy/typeshed/stdlib/plistlib.pyi @@ -1,7 +1,7 @@ import sys from datetime import datetime from enum import Enum -from typing import IO, Any, Dict as _Dict, Mapping, MutableMapping, Tuple, Type +from typing import IO, Any, Mapping, MutableMapping, Type class PlistFormat(Enum): FMT_XML: int @@ -31,7 +31,7 @@ else: ) -> Any: ... def dump( - value: Mapping[str, Any] | list[Any] | Tuple[Any, ...] | str | bool | float | bytes | datetime, + value: Mapping[str, Any] | list[Any] | tuple[Any, ...] | str | bool | float | bytes | datetime, fp: IO[bytes], *, fmt: PlistFormat = ..., @@ -39,7 +39,7 @@ def dump( skipkeys: bool = ..., ) -> None: ... def dumps( - value: Mapping[str, Any] | list[Any] | Tuple[Any, ...] | str | bool | float | bytes | datetime, + value: Mapping[str, Any] | list[Any] | tuple[Any, ...] | str | bool | float | bytes | datetime, *, fmt: PlistFormat = ..., skipkeys: bool = ..., @@ -53,7 +53,7 @@ if sys.version_info < (3, 9): def writePlistToBytes(value: Mapping[str, Any]) -> bytes: ... if sys.version_info < (3, 7): - class Dict(_Dict[str, Any]): + class Dict(dict[str, Any]): def __getattr__(self, attr: str) -> Any: ... def __setattr__(self, attr: str, value: Any) -> None: ... def __delattr__(self, attr: str) -> None: ... diff --git a/mypy/typeshed/stdlib/poplib.pyi b/mypy/typeshed/stdlib/poplib.pyi index 28fba4ce951f..028af412847b 100644 --- a/mypy/typeshed/stdlib/poplib.pyi +++ b/mypy/typeshed/stdlib/poplib.pyi @@ -1,8 +1,8 @@ import socket import ssl -from typing import Any, BinaryIO, List, Pattern, Tuple, overload +from typing import Any, BinaryIO, Pattern, overload -_LongResp = Tuple[bytes, List[bytes], int] +_LongResp = tuple[bytes, list[bytes], int] class error_proto(Exception): ... diff --git a/mypy/typeshed/stdlib/posix.pyi b/mypy/typeshed/stdlib/posix.pyi index 14cea87cde29..9f658039bcf2 100644 --- a/mypy/typeshed/stdlib/posix.pyi +++ b/mypy/typeshed/stdlib/posix.pyi @@ -1,204 +1,322 @@ 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 - release: str - version: str - machine: str +if sys.platform != "win32": + # Actually defined here, but defining in os allows sharing code with windows + from os import ( + CLD_CONTINUED as CLD_CONTINUED, + CLD_DUMPED as CLD_DUMPED, + CLD_EXITED as CLD_EXITED, + CLD_TRAPPED as CLD_TRAPPED, + EX_CANTCREAT as EX_CANTCREAT, + EX_CONFIG as EX_CONFIG, + EX_DATAERR as EX_DATAERR, + EX_IOERR as EX_IOERR, + EX_NOHOST as EX_NOHOST, + EX_NOINPUT as EX_NOINPUT, + EX_NOPERM as EX_NOPERM, + EX_NOTFOUND as EX_NOTFOUND, + EX_NOUSER as EX_NOUSER, + EX_OK as EX_OK, + EX_OSERR as EX_OSERR, + EX_OSFILE as EX_OSFILE, + EX_PROTOCOL as EX_PROTOCOL, + EX_SOFTWARE as EX_SOFTWARE, + EX_TEMPFAIL as EX_TEMPFAIL, + EX_UNAVAILABLE as EX_UNAVAILABLE, + EX_USAGE as EX_USAGE, + F_LOCK as F_LOCK, + F_OK as F_OK, + F_TEST as F_TEST, + F_TLOCK as F_TLOCK, + F_ULOCK as F_ULOCK, + O_APPEND as O_APPEND, + O_ASYNC as O_ASYNC, + O_CREAT as O_CREAT, + O_DIRECT as O_DIRECT, + O_DIRECTORY as O_DIRECTORY, + O_DSYNC as O_DSYNC, + O_EXCL as O_EXCL, + O_LARGEFILE as O_LARGEFILE, + O_NDELAY as O_NDELAY, + O_NOATIME as O_NOATIME, + O_NOCTTY as O_NOCTTY, + O_NOFOLLOW as O_NOFOLLOW, + O_NONBLOCK as O_NONBLOCK, + O_RDONLY as O_RDONLY, + O_RDWR as O_RDWR, + O_RSYNC as O_RSYNC, + O_SYNC as O_SYNC, + O_TRUNC as O_TRUNC, + O_WRONLY as O_WRONLY, + P_ALL as P_ALL, + P_PGID as P_PGID, + P_PID as P_PID, + PRIO_PGRP as PRIO_PGRP, + PRIO_PROCESS as PRIO_PROCESS, + PRIO_USER as PRIO_USER, + R_OK as R_OK, + RTLD_GLOBAL as RTLD_GLOBAL, + RTLD_LAZY as RTLD_LAZY, + RTLD_LOCAL as RTLD_LOCAL, + RTLD_NODELETE as RTLD_NODELETE, + RTLD_NOLOAD as RTLD_NOLOAD, + RTLD_NOW as RTLD_NOW, + SCHED_BATCH as SCHED_BATCH, + SCHED_FIFO as SCHED_FIFO, + SCHED_IDLE as SCHED_IDLE, + SCHED_OTHER as SCHED_OTHER, + SCHED_RESET_ON_FORK as SCHED_RESET_ON_FORK, + SCHED_RR as SCHED_RR, + SCHED_SPORADIC as SCHED_SPORADIC, + SEEK_DATA as SEEK_DATA, + SEEK_HOLE as SEEK_HOLE, + ST_NOSUID as ST_NOSUID, + ST_RDONLY as ST_RDONLY, + TMP_MAX as TMP_MAX, + W_OK as W_OK, + WCONTINUED as WCONTINUED, + WCOREDUMP as WCOREDUMP, + WEXITED as WEXITED, + WEXITSTATUS as WEXITSTATUS, + WIFCONTINUED as WIFCONTINUED, + WIFEXITED as WIFEXITED, + WIFSIGNALED as WIFSIGNALED, + WIFSTOPPED as WIFSTOPPED, + WNOHANG as WNOHANG, + WNOWAIT as WNOWAIT, + WSTOPPED as WSTOPPED, + WSTOPSIG as WSTOPSIG, + WTERMSIG as WTERMSIG, + WUNTRACED as WUNTRACED, + X_OK as X_OK, + DirEntry as DirEntry, + _exit as _exit, + abort as abort, + access as access, + chdir as chdir, + chmod as chmod, + chown as chown, + chroot as chroot, + close as close, + closerange as closerange, + confstr as confstr, + confstr_names as confstr_names, + cpu_count as cpu_count, + ctermid as ctermid, + device_encoding as device_encoding, + dup as dup, + dup2 as dup2, + error as error, + execv as execv, + execve as execve, + fchdir as fchdir, + fchmod as fchmod, + fchown as fchown, + fork as fork, + forkpty as forkpty, + fpathconf as fpathconf, + fspath as fspath, + fstat as fstat, + fstatvfs as fstatvfs, + fsync as fsync, + ftruncate as ftruncate, + get_blocking as get_blocking, + get_inheritable as get_inheritable, + get_terminal_size as get_terminal_size, + getcwd as getcwd, + getcwdb as getcwdb, + getegid as getegid, + geteuid as geteuid, + getgid as getgid, + getgrouplist as getgrouplist, + getgroups as getgroups, + getloadavg as getloadavg, + getlogin as getlogin, + getpgid as getpgid, + getpgrp as getpgrp, + getpid as getpid, + getppid as getppid, + getpriority as getpriority, + getsid as getsid, + getuid as getuid, + initgroups as initgroups, + isatty as isatty, + kill as kill, + killpg as killpg, + lchown as lchown, + link as link, + listdir as listdir, + lockf as lockf, + lseek as lseek, + lstat as lstat, + major as major, + makedev as makedev, + minor as minor, + mkdir as mkdir, + mkfifo as mkfifo, + mknod as mknod, + nice as nice, + open as open, + openpty as openpty, + pathconf as pathconf, + pathconf_names as pathconf_names, + pipe as pipe, + pread as pread, + putenv as putenv, + pwrite as pwrite, + read as read, + readlink as readlink, + readv as readv, + remove as remove, + rename as rename, + replace as replace, + rmdir as rmdir, + scandir as scandir, + sched_get_priority_max as sched_get_priority_max, + sched_get_priority_min as sched_get_priority_min, + sched_param as sched_param, + sched_yield as sched_yield, + sendfile as sendfile, + set_blocking as set_blocking, + set_inheritable as set_inheritable, + setegid as setegid, + seteuid as seteuid, + setgid as setgid, + setgroups as setgroups, + setpgid as setpgid, + setpgrp as setpgrp, + setpriority as setpriority, + setregid as setregid, + setreuid as setreuid, + setsid as setsid, + setuid as setuid, + stat as stat, + stat_result as stat_result, + statvfs as statvfs, + statvfs_result as statvfs_result, + strerror as strerror, + symlink as symlink, + sync as sync, + sysconf as sysconf, + sysconf_names as sysconf_names, + system as system, + tcgetpgrp as tcgetpgrp, + tcsetpgrp as tcsetpgrp, + terminal_size as terminal_size, + times as times, + times_result as times_result, + truncate as truncate, + ttyname as ttyname, + umask as umask, + uname as uname, + uname_result as uname_result, + unlink as unlink, + unsetenv as unsetenv, + urandom as urandom, + utime as utime, + wait as wait, + wait3 as wait3, + wait4 as wait4, + waitpid as waitpid, + write as write, + writev as writev, + ) -@final -class times_result(NamedTuple): - user: float - system: float - children_user: float - children_system: float - elapsed: float + if sys.platform == "linux": + from os import ( + GRND_NONBLOCK as GRND_NONBLOCK, + GRND_RANDOM as GRND_RANDOM, + RTLD_DEEPBIND as RTLD_DEEPBIND, + XATTR_CREATE as XATTR_CREATE, + XATTR_REPLACE as XATTR_REPLACE, + XATTR_SIZE_MAX as XATTR_SIZE_MAX, + getrandom as getrandom, + getxattr as getxattr, + listxattr as listxattr, + removexattr as removexattr, + setxattr as setxattr, + ) + else: + from os import chflags as chflags, lchflags as lchflags, lchmod as lchmod -if sys.platform != "darwin": - class waitid_result(NamedTuple): - si_pid: int - si_uid: int - si_signo: int - si_status: int - si_code: int + if sys.platform != "darwin": + from os import ( + POSIX_FADV_DONTNEED as POSIX_FADV_DONTNEED, + POSIX_FADV_NOREUSE as POSIX_FADV_NOREUSE, + POSIX_FADV_NORMAL as POSIX_FADV_NORMAL, + POSIX_FADV_RANDOM as POSIX_FADV_RANDOM, + POSIX_FADV_SEQUENTIAL as POSIX_FADV_SEQUENTIAL, + POSIX_FADV_WILLNEED as POSIX_FADV_WILLNEED, + fdatasync as fdatasync, + getresgid as getresgid, + getresuid as getresuid, + pipe2 as pipe2, + posix_fadvise as posix_fadvise, + posix_fallocate as posix_fallocate, + sched_getaffinity as sched_getaffinity, + sched_getparam as sched_getparam, + sched_getscheduler as sched_getscheduler, + sched_rr_get_interval as sched_rr_get_interval, + sched_setaffinity as sched_setaffinity, + sched_setparam as sched_setparam, + sched_setscheduler as sched_setscheduler, + setresgid as setresgid, + setresuid as setresuid, + waitid as waitid, + waitid_result as waitid_result, + ) -class sched_param(NamedTuple): - sched_priority: int + if sys.version_info >= (3, 10): + from os import RWF_APPEND as RWF_APPEND -CLD_CONTINUED: int -CLD_DUMPED: int -CLD_EXITED: int -CLD_TRAPPED: int + if sys.version_info >= (3, 9): + from os import CLD_KILLED as CLD_KILLED, CLD_STOPPED as CLD_STOPPED, waitstatus_to_exitcode as waitstatus_to_exitcode -EX_CANTCREAT: int -EX_CONFIG: int -EX_DATAERR: int -EX_IOERR: int -EX_NOHOST: int -EX_NOINPUT: int -EX_NOPERM: int -EX_NOTFOUND: int -EX_NOUSER: int -EX_OK: int -EX_OSERR: int -EX_OSFILE: int -EX_PROTOCOL: int -EX_SOFTWARE: int -EX_TEMPFAIL: int -EX_UNAVAILABLE: int -EX_USAGE: int + if sys.platform == "linux": + from os import P_PIDFD as P_PIDFD + if sys.version_info >= (3, 8): + from os import ( + POSIX_SPAWN_CLOSE as POSIX_SPAWN_CLOSE, + POSIX_SPAWN_DUP2 as POSIX_SPAWN_DUP2, + POSIX_SPAWN_OPEN as POSIX_SPAWN_OPEN, + posix_spawn as posix_spawn, + posix_spawnp as posix_spawnp, + ) -F_OK: int -R_OK: int -W_OK: int -X_OK: int + if sys.platform == "linux": + from os import ( + MFD_ALLOW_SEALING as MFD_ALLOW_SEALING, + MFD_CLOEXEC as MFD_CLOEXEC, + MFD_HUGE_1GB as MFD_HUGE_1GB, + MFD_HUGE_1MB as MFD_HUGE_1MB, + MFD_HUGE_2GB as MFD_HUGE_2GB, + MFD_HUGE_2MB as MFD_HUGE_2MB, + MFD_HUGE_8MB as MFD_HUGE_8MB, + MFD_HUGE_16GB as MFD_HUGE_16GB, + MFD_HUGE_16MB as MFD_HUGE_16MB, + MFD_HUGE_32MB as MFD_HUGE_32MB, + MFD_HUGE_64KB as MFD_HUGE_64KB, + MFD_HUGE_256MB as MFD_HUGE_256MB, + MFD_HUGE_512KB as MFD_HUGE_512KB, + MFD_HUGE_512MB as MFD_HUGE_512MB, + MFD_HUGE_MASK as MFD_HUGE_MASK, + MFD_HUGE_SHIFT as MFD_HUGE_SHIFT, + MFD_HUGETLB as MFD_HUGETLB, + memfd_create as memfd_create, + ) + if sys.version_info >= (3, 7): + from os import register_at_fork as register_at_fork -F_LOCK: int -F_TEST: int -F_TLOCK: int -F_ULOCK: int + if sys.platform != "darwin": + from os import ( + RWF_DSYNC as RWF_DSYNC, + RWF_HIPRI as RWF_HIPRI, + RWF_NOWAIT as RWF_NOWAIT, + RWF_SYNC as RWF_SYNC, + preadv as preadv, + pwritev as pwritev, + ) -if sys.platform == "linux": - GRND_NONBLOCK: int - GRND_RANDOM: int -NGROUPS_MAX: int - -O_APPEND: int -O_ACCMODE: int -O_ASYNC: int -O_CREAT: int -O_DIRECT: int -O_DIRECTORY: int -O_DSYNC: int -O_EXCL: int -O_LARGEFILE: int -O_NDELAY: int -O_NOATIME: int -O_NOCTTY: int -O_NOFOLLOW: int -O_NONBLOCK: int -O_RDONLY: int -O_RDWR: int -O_RSYNC: int -O_SYNC: int -O_TRUNC: int -O_WRONLY: int - -if sys.platform != "darwin": - POSIX_FADV_DONTNEED: int - POSIX_FADV_NOREUSE: int - POSIX_FADV_NORMAL: int - POSIX_FADV_RANDOM: int - POSIX_FADV_SEQUENTIAL: int - POSIX_FADV_WILLNEED: int - -PRIO_PGRP: int -PRIO_PROCESS: int -PRIO_USER: int - -P_ALL: int -P_PGID: int -P_PID: int - -if sys.platform == "linux": - RTLD_DEEPBIND: int -RTLD_GLOBAL: int -RTLD_LAZY: int -RTLD_LOCAL: int -RTLD_NODELETE: int -RTLD_NOLOAD: int -RTLD_NOW: int - -SCHED_FIFO: int -SCHED_OTHER: int -SCHED_RR: int - -if sys.platform == "linux": - SCHED_BATCH: int - SCHED_IDLE: int -if sys.platform != "darwin": - SCHED_RESET_ON_FORK: int - -SEEK_DATA: int -SEEK_HOLE: int - -ST_APPEND: int -ST_MANDLOCK: int -ST_NOATIME: int -ST_NODEV: int -ST_NODIRATIME: int -ST_NOEXEC: int -ST_NOSUID: int -ST_RDONLY: int -ST_RELATIME: int -ST_SYNCHRONOUS: int -ST_WRITE: int - -TMP_MAX: int -WCONTINUED: int - -def WCOREDUMP(__status: int) -> bool: ... -def WEXITSTATUS(status: int) -> int: ... -def WIFCONTINUED(status: int) -> bool: ... -def WIFEXITED(status: int) -> bool: ... -def WIFSIGNALED(status: int) -> bool: ... -def WIFSTOPPED(status: int) -> bool: ... - -WNOHANG: int - -def WSTOPSIG(status: int) -> int: ... -def WTERMSIG(status: int) -> int: ... - -WUNTRACED: int - -XATTR_CREATE: int -XATTR_REPLACE: int -XATTR_SIZE_MAX: int - -@overload -def listdir(path: str | None = ...) -> list[str]: ... -@overload -def listdir(path: bytes) -> list[bytes]: ... -@overload -def listdir(path: int) -> list[str]: ... -@overload -def listdir(path: PathLike[str]) -> list[str]: ... - -if sys.platform != "win32" and sys.version_info >= (3, 8): - def posix_spawn( - path: StrOrBytesPath, - argv: _ExecVArgs, - env: _ExecEnv, - *, - file_actions: Sequence[Tuple[Any, ...]] | None = ..., - setpgroup: int | None = ..., - resetids: bool = ..., - setsid: bool = ..., - setsigmask: Iterable[int] = ..., - setsigdef: Iterable[int] = ..., - scheduler: tuple[Any, sched_param] | None = ..., - ) -> int: ... - def posix_spawnp( - path: StrOrBytesPath, - argv: _ExecVArgs, - env: _ExecEnv, - *, - file_actions: Sequence[Tuple[Any, ...]] | None = ..., - setpgroup: int | None = ..., - resetids: bool = ..., - setsid: bool = ..., - setsigmask: Iterable[int] = ..., - setsigdef: Iterable[int] = ..., - scheduler: tuple[Any, sched_param] | None = ..., - ) -> int: ... - -if sys.platform == "win32": - environ: dict[str, str] -else: + # Not same as os.environ or os.environb + # Because of this variable, we can't do "from posix import *" in os/__init__.pyi environ: dict[bytes, bytes] diff --git a/mypy/typeshed/stdlib/posixpath.pyi b/mypy/typeshed/stdlib/posixpath.pyi index ae3d0d5cc65f..58cadb4de03c 100644 --- a/mypy/typeshed/stdlib/posixpath.pyi +++ b/mypy/typeshed/stdlib/posixpath.pyi @@ -60,10 +60,14 @@ def normpath(path: AnyStr) -> AnyStr: ... def commonpath(paths: Sequence[StrPath]) -> str: ... @overload def commonpath(paths: Sequence[BytesPath]) -> bytes: ... + +# First parameter is not actually pos-only, +# but must be defined as pos-only in the stub or cross-platform code doesn't type-check, +# as the parameter name is different in ntpath.join() @overload -def join(a: StrPath, *paths: StrPath) -> str: ... +def join(__a: StrPath, *paths: StrPath) -> str: ... @overload -def join(a: BytesPath, *paths: BytesPath) -> bytes: ... +def join(__a: BytesPath, *paths: BytesPath) -> bytes: ... if sys.version_info >= (3, 10): @overload diff --git a/mypy/typeshed/stdlib/profile.pyi b/mypy/typeshed/stdlib/profile.pyi index cb0cbf7c9388..7581c0122c9c 100644 --- a/mypy/typeshed/stdlib/profile.pyi +++ b/mypy/typeshed/stdlib/profile.pyi @@ -1,5 +1,5 @@ from _typeshed import StrOrBytesPath -from typing import Any, Callable, Tuple, TypeVar +from typing import Any, Callable, TypeVar def run(statement: str, filename: str | None = ..., sort: str | int = ...) -> None: ... def runctx( @@ -8,7 +8,7 @@ def runctx( _SelfT = TypeVar("_SelfT", bound=Profile) _T = TypeVar("_T") -_Label = Tuple[str, int, str] +_Label = tuple[str, int, str] class Profile: bias: int diff --git a/mypy/typeshed/stdlib/pstats.pyi b/mypy/typeshed/stdlib/pstats.pyi index e8256f9f98ab..6e008c823ff2 100644 --- a/mypy/typeshed/stdlib/pstats.pyi +++ b/mypy/typeshed/stdlib/pstats.pyi @@ -2,7 +2,7 @@ import sys from _typeshed import StrOrBytesPath from cProfile import Profile as _cProfile from profile import Profile -from typing import IO, Any, Iterable, Tuple, TypeVar, Union, overload +from typing import IO, Any, Iterable, TypeVar, Union, overload _Selector = Union[str, float, int] _T = TypeVar("_T", bound=Stats) @@ -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 diff --git a/mypy/typeshed/stdlib/pty.pyi b/mypy/typeshed/stdlib/pty.pyi index f943cebdb157..73c6ddfbd0c4 100644 --- a/mypy/typeshed/stdlib/pty.pyi +++ b/mypy/typeshed/stdlib/pty.pyi @@ -1,15 +1,18 @@ +import sys from typing import Callable, Iterable +from typing_extensions import Literal -_Reader = Callable[[int], bytes] +if sys.platform != "win32": + __all__ = ["openpty", "fork", "spawn"] + _Reader = Callable[[int], bytes] -STDIN_FILENO: int -STDOUT_FILENO: int -STDERR_FILENO: int + STDIN_FILENO: Literal[0] + STDOUT_FILENO: Literal[1] + STDERR_FILENO: Literal[2] -CHILD: int - -def openpty() -> tuple[int, int]: ... -def master_open() -> tuple[int, str]: ... -def slave_open(tty_name: str) -> int: ... -def fork() -> tuple[int, int]: ... -def spawn(argv: str | Iterable[str], master_read: _Reader = ..., stdin_read: _Reader = ...) -> int: ... + CHILD: Literal[0] + def openpty() -> tuple[int, int]: ... + def master_open() -> tuple[int, str]: ... # deprecated, use openpty() + def slave_open(tty_name: str) -> int: ... # deprecated, use openpty() + def fork() -> tuple[int, int]: ... + def spawn(argv: str | Iterable[str], master_read: _Reader = ..., stdin_read: _Reader = ...) -> int: ... diff --git a/mypy/typeshed/stdlib/pwd.pyi b/mypy/typeshed/stdlib/pwd.pyi index 2b931248edda..08a9facf642e 100644 --- a/mypy/typeshed/stdlib/pwd.pyi +++ b/mypy/typeshed/stdlib/pwd.pyi @@ -1,18 +1,25 @@ -from typing import ClassVar, Tuple +import sys +from _typeshed import structseq +from typing import Any +from typing_extensions import final -class struct_passwd(Tuple[str, str, int, int, str, str, str]): - pw_name: str - pw_passwd: str - pw_uid: int - pw_gid: int - pw_gecos: str - pw_dir: str - pw_shell: str - - n_fields: ClassVar[int] - n_sequence_fields: ClassVar[int] - n_unnamed_fields: ClassVar[int] - -def getpwall() -> list[struct_passwd]: ... -def getpwuid(__uid: int) -> struct_passwd: ... -def getpwnam(__name: str) -> struct_passwd: ... +if sys.platform != "win32": + @final + class struct_passwd(structseq[Any], tuple[str, str, int, int, str, str, str]): + @property + def pw_name(self) -> str: ... + @property + def pw_passwd(self) -> str: ... + @property + def pw_uid(self) -> int: ... + @property + def pw_gid(self) -> int: ... + @property + def pw_gecos(self) -> str: ... + @property + def pw_dir(self) -> str: ... + @property + def pw_shell(self) -> str: ... + def getpwall() -> list[struct_passwd]: ... + def getpwuid(__uid: int) -> struct_passwd: ... + def getpwnam(__name: str) -> struct_passwd: ... diff --git a/mypy/typeshed/stdlib/pydoc.pyi b/mypy/typeshed/stdlib/pydoc.pyi index 97e71f389616..a1d4359d28fc 100644 --- a/mypy/typeshed/stdlib/pydoc.pyi +++ b/mypy/typeshed/stdlib/pydoc.pyi @@ -1,10 +1,10 @@ from _typeshed import SupportsWrite from reprlib import Repr from types import MethodType, ModuleType, TracebackType -from typing import IO, Any, AnyStr, Callable, Container, Mapping, MutableMapping, NoReturn, Optional, Tuple, Type +from typing import IO, Any, AnyStr, Callable, Container, Mapping, MutableMapping, NoReturn, Optional, Type # the return type of sys.exc_info(), used by ErrorDuringImport.__init__ -_Exc_Info = Tuple[Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]] +_Exc_Info = tuple[Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]] __author__: str __date__: 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( @@ -109,7 +109,7 @@ class HTMLDoc(Doc): *ignored: Any, ) -> str: ... def formatvalue(self, object: object) -> str: ... - def docroutine( + def docroutine( # type: ignore[override] self, object: object, name: str | None = ..., @@ -118,15 +118,10 @@ class HTMLDoc(Doc): classes: Mapping[str, str] = ..., methods: Mapping[str, str] = ..., cl: type | None = ..., - *ignored: Any, - ) -> str: ... - def docproperty( - self, object: object, name: str | None = ..., mod: str | None = ..., cl: Any | None = ..., *ignored: Any ) -> str: ... + def docproperty(self, object: object, name: str | None = ..., mod: str | None = ..., cl: Any | None = ...) -> str: ... # type: ignore[override] def docother(self, object: object, name: str | None = ..., mod: Any | None = ..., *ignored: Any) -> str: ... - def docdata( - self, object: object, name: str | None = ..., mod: Any | None = ..., cl: Any | None = ..., *ignored: Any - ) -> str: ... + def docdata(self, object: object, name: str | None = ..., mod: Any | None = ..., cl: Any | None = ...) -> str: ... # type: ignore[override] def index(self, dir: str, shadowed: MutableMapping[str, bool] | None = ...) -> str: ... def filelink(self, url: str, path: str) -> str: ... @@ -148,21 +143,15 @@ 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 docmodule(self, object: object, name: str | None = ..., mod: Any | None = ...) -> str: ... # type: ignore[override] def docclass(self, object: object, name: str | None = ..., mod: str | None = ..., *ignored: Any) -> str: ... def formatvalue(self, object: object) -> str: ... - def docroutine( - self, object: object, name: str | None = ..., mod: str | None = ..., cl: Any | None = ..., *ignored: Any - ) -> str: ... - def docproperty( - self, object: object, name: str | None = ..., mod: Any | None = ..., cl: Any | None = ..., *ignored: Any - ) -> str: ... - def docdata( - self, object: object, name: str | None = ..., mod: str | None = ..., cl: Any | None = ..., *ignored: Any - ) -> str: ... - def docother( + def docroutine(self, object: object, name: str | None = ..., mod: str | None = ..., cl: Any | None = ...) -> str: ... # type: ignore[override] + def docproperty(self, object: object, name: str | None = ..., mod: Any | None = ..., cl: Any | None = ...) -> str: ... # type: ignore[override] + def docdata(self, object: object, name: str | None = ..., mod: str | None = ..., cl: Any | None = ...) -> str: ... # type: ignore[override] + def docother( # type: ignore[override] self, object: object, name: str | None = ..., @@ -170,7 +159,6 @@ class TextDoc(Doc): parent: str | None = ..., maxlen: int | None = ..., doc: Any | None = ..., - *ignored: Any, ) -> str: ... def pager(text: str) -> None: ... @@ -199,7 +187,7 @@ _list = list # "list" conflicts with method name class Helper: keywords: dict[str, str | tuple[str, str]] symbols: dict[str, str] - topics: dict[str, str | Tuple[str, ...]] + topics: dict[str, str | tuple[str, ...]] def __init__(self, input: IO[str] | None = ..., output: IO[str] | None = ...) -> None: ... input: IO[str] output: IO[str] diff --git a/mypy/typeshed/stdlib/pyexpat/__init__.pyi b/mypy/typeshed/stdlib/pyexpat/__init__.pyi index 6a3d6cd56791..5aca55c2b813 100644 --- a/mypy/typeshed/stdlib/pyexpat/__init__.pyi +++ b/mypy/typeshed/stdlib/pyexpat/__init__.pyi @@ -1,7 +1,7 @@ import pyexpat.errors as errors import pyexpat.model as model from _typeshed import SupportsRead -from typing import Any, Callable, Optional, Tuple +from typing import Any, Callable, Optional from typing_extensions import final EXPAT_VERSION: str # undocumented @@ -20,10 +20,10 @@ XML_PARAM_ENTITY_PARSING_NEVER: int XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE: int XML_PARAM_ENTITY_PARSING_ALWAYS: int -_Model = Tuple[int, int, Optional[str], Tuple[Any, ...]] +_Model = tuple[int, int, Optional[str], tuple[Any, ...]] @final -class XMLParserType(object): +class XMLParserType: def Parse(self, __data: str | bytes, __isfinal: bool = ...) -> int: ... def ParseFile(self, __file: SupportsRead[bytes]) -> int: ... def SetBase(self, __base: str) -> None: ... diff --git a/mypy/typeshed/stdlib/random.pyi b/mypy/typeshed/stdlib/random.pyi index 73c29d2f78c3..ffa866ef9aa0 100644 --- a/mypy/typeshed/stdlib/random.pyi +++ b/mypy/typeshed/stdlib/random.pyi @@ -1,25 +1,27 @@ import _random import sys +from _typeshed import SupportsLenAndGetItem from collections.abc import Callable, Iterable, MutableSequence, Sequence, Set as AbstractSet from fractions import Fraction -from typing import Any, NoReturn, Tuple, TypeVar +from typing import Any, ClassVar, NoReturn, TypeVar _T = TypeVar("_T") class Random(_random.Random): + VERSION: ClassVar[int] def __init__(self, x: Any = ...) -> None: ... def seed(self, a: Any = ..., version: int = ...) -> None: ... - def getstate(self) -> Tuple[Any, ...]: ... - def setstate(self, state: Tuple[Any, ...]) -> None: ... + def getstate(self) -> tuple[Any, ...]: ... + def setstate(self, state: tuple[Any, ...]) -> None: ... def getrandbits(self, __k: int) -> int: ... def randrange(self, start: int, stop: int | None = ..., step: int = ...) -> int: ... def randint(self, a: int, b: int) -> int: ... if sys.version_info >= (3, 9): def randbytes(self, n: int) -> bytes: ... - def choice(self, seq: Sequence[_T]) -> _T: ... + def choice(self, seq: SupportsLenAndGetItem[_T]) -> _T: ... def choices( self, - population: Sequence[_T], + population: SupportsLenAndGetItem[_T], weights: Sequence[float | Fraction] | None = ..., *, cum_weights: Sequence[float | Fraction] | None = ..., @@ -27,7 +29,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] | AbstractSet[_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] | AbstractSet[_T], k: int) -> list[_T]: ... def random(self) -> float: ... @@ -45,6 +49,7 @@ class Random(_random.Random): # SystemRandom is not implemented for all OS's; good on Windows & Linux class SystemRandom(Random): + def getrandbits(self, k: int) -> int: ... # k can be passed by keyword def getstate(self, *args: Any, **kwds: Any) -> NoReturn: ... def setstate(self, *args: Any, **kwds: Any) -> NoReturn: ... @@ -59,9 +64,13 @@ def randint(a: int, b: int) -> int: ... if sys.version_info >= (3, 9): def randbytes(n: int) -> bytes: ... -def choice(seq: Sequence[_T]) -> _T: ... +def choice(seq: SupportsLenAndGetItem[_T]) -> _T: ... def choices( - population: Sequence[_T], weights: Sequence[float] | None = ..., *, cum_weights: Sequence[float] | None = ..., k: int = ... + population: SupportsLenAndGetItem[_T], + weights: Sequence[float] | None = ..., + *, + cum_weights: Sequence[float] | None = ..., + k: int = ..., ) -> list[_T]: ... def shuffle(x: MutableSequence[Any], random: Callable[[], float] | None = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/readline.pyi b/mypy/typeshed/stdlib/readline.pyi index 2de749b2c216..fd3a4b1dcc65 100644 --- a/mypy/typeshed/stdlib/readline.pyi +++ b/mypy/typeshed/stdlib/readline.pyi @@ -1,33 +1,34 @@ +import sys from _typeshed import StrOrBytesPath from typing import Callable, Optional, Sequence -_CompleterT = Optional[Callable[[str, int], Optional[str]]] -_CompDispT = Optional[Callable[[str, Sequence[str], int], None]] - -def parse_and_bind(__string: str) -> None: ... -def read_init_file(__filename: StrOrBytesPath | None = ...) -> None: ... -def get_line_buffer() -> str: ... -def insert_text(__string: str) -> None: ... -def redisplay() -> None: ... -def read_history_file(__filename: StrOrBytesPath | None = ...) -> None: ... -def write_history_file(__filename: StrOrBytesPath | None = ...) -> None: ... -def append_history_file(__nelements: int, __filename: StrOrBytesPath | None = ...) -> None: ... -def get_history_length() -> int: ... -def set_history_length(__length: int) -> None: ... -def clear_history() -> None: ... -def get_current_history_length() -> int: ... -def get_history_item(__index: int) -> str: ... -def remove_history_item(__pos: int) -> None: ... -def replace_history_item(__pos: int, __line: str) -> None: ... -def add_history(__string: str) -> None: ... -def set_auto_history(__enabled: bool) -> None: ... -def set_startup_hook(__function: Callable[[], None] | None = ...) -> None: ... -def set_pre_input_hook(__function: Callable[[], None] | None = ...) -> None: ... -def set_completer(__function: _CompleterT = ...) -> None: ... -def get_completer() -> _CompleterT: ... -def get_completion_type() -> int: ... -def get_begidx() -> int: ... -def get_endidx() -> int: ... -def set_completer_delims(__string: str) -> None: ... -def get_completer_delims() -> str: ... -def set_completion_display_matches_hook(__function: _CompDispT = ...) -> None: ... +if sys.platform != "win32": + _CompleterT = Optional[Callable[[str, int], Optional[str]]] + _CompDispT = Optional[Callable[[str, Sequence[str], int], None]] + def parse_and_bind(__string: str) -> None: ... + def read_init_file(__filename: StrOrBytesPath | None = ...) -> None: ... + def get_line_buffer() -> str: ... + def insert_text(__string: str) -> None: ... + def redisplay() -> None: ... + def read_history_file(__filename: StrOrBytesPath | None = ...) -> None: ... + def write_history_file(__filename: StrOrBytesPath | None = ...) -> None: ... + def append_history_file(__nelements: int, __filename: StrOrBytesPath | None = ...) -> None: ... + def get_history_length() -> int: ... + def set_history_length(__length: int) -> None: ... + def clear_history() -> None: ... + def get_current_history_length() -> int: ... + def get_history_item(__index: int) -> str: ... + def remove_history_item(__pos: int) -> None: ... + def replace_history_item(__pos: int, __line: str) -> None: ... + def add_history(__string: str) -> None: ... + def set_auto_history(__enabled: bool) -> None: ... + def set_startup_hook(__function: Callable[[], None] | None = ...) -> None: ... + def set_pre_input_hook(__function: Callable[[], None] | None = ...) -> None: ... + def set_completer(__function: _CompleterT = ...) -> None: ... + def get_completer() -> _CompleterT: ... + def get_completion_type() -> int: ... + def get_begidx() -> int: ... + def get_endidx() -> int: ... + def set_completer_delims(__string: str) -> None: ... + def get_completer_delims() -> str: ... + def set_completion_display_matches_hook(__function: _CompDispT = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/reprlib.pyi b/mypy/typeshed/stdlib/reprlib.pyi index 4d400554a4ff..2095c0af6983 100644 --- a/mypy/typeshed/stdlib/reprlib.pyi +++ b/mypy/typeshed/stdlib/reprlib.pyi @@ -1,6 +1,6 @@ from array import array from collections import deque -from typing import Any, Callable, Tuple +from typing import Any, Callable _ReprFunc = Callable[[Any], str] @@ -21,7 +21,7 @@ class Repr: def __init__(self) -> None: ... def repr(self, x: Any) -> str: ... def repr1(self, x: Any, level: int) -> str: ... - def repr_tuple(self, x: Tuple[Any, ...], level: int) -> str: ... + 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: ... diff --git a/mypy/typeshed/stdlib/resource.pyi b/mypy/typeshed/stdlib/resource.pyi index d7124edcc2fa..19a6f470b775 100644 --- a/mypy/typeshed/stdlib/resource.pyi +++ b/mypy/typeshed/stdlib/resource.pyi @@ -1,58 +1,73 @@ import sys -from typing import Any, Tuple, overload +from _typeshed import structseq +from typing import overload +from typing_extensions import final -RLIMIT_AS: int -RLIMIT_CORE: int -RLIMIT_CPU: int -RLIMIT_DATA: int -RLIMIT_FSIZE: int -RLIMIT_MEMLOCK: int -RLIMIT_NOFILE: int -RLIMIT_NPROC: int -RLIMIT_RSS: int -RLIMIT_STACK: int -RLIM_INFINITY: int -RUSAGE_CHILDREN: int -RUSAGE_SELF: int -if sys.platform == "linux": - RLIMIT_MSGQUEUE: int - RLIMIT_NICE: int - RLIMIT_OFILE: int - RLIMIT_RTPRIO: int - RLIMIT_RTTIME: int - RLIMIT_SIGPENDING: int - RUSAGE_THREAD: int - -_Tuple16 = Tuple[float, float, int, int, int, int, int, int, int, int, int, int, int, int, int, int] - -class struct_rusage(_Tuple16): - def __new__(cls, sequence: _Tuple16, dict: dict[str, Any] = ...) -> struct_rusage: ... - ru_utime: float - ru_stime: float - ru_maxrss: int - ru_ixrss: int - ru_idrss: int - ru_isrss: int - ru_minflt: int - ru_majflt: int - ru_nswap: int - ru_inblock: int - ru_oublock: int - ru_msgsnd: int - ru_msgrcv: int - ru_nsignals: int - ru_nvcsw: int - ru_nivcsw: int - -def getpagesize() -> int: ... -def getrlimit(__resource: int) -> tuple[int, int]: ... -def getrusage(__who: int) -> struct_rusage: ... -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]: ... - @overload - def prlimit(pid: int, resource: int) -> tuple[int, int]: ... - -error = OSError +if sys.platform != "win32": + RLIMIT_AS: int + RLIMIT_CORE: int + RLIMIT_CPU: int + RLIMIT_DATA: int + RLIMIT_FSIZE: int + RLIMIT_MEMLOCK: int + RLIMIT_NOFILE: int + RLIMIT_NPROC: int + RLIMIT_RSS: int + RLIMIT_STACK: int + RLIM_INFINITY: int + RUSAGE_CHILDREN: int + RUSAGE_SELF: int + if sys.platform == "linux": + RLIMIT_MSGQUEUE: int + RLIMIT_NICE: int + RLIMIT_OFILE: int + RLIMIT_RTPRIO: int + RLIMIT_RTTIME: int + RLIMIT_SIGPENDING: int + RUSAGE_THREAD: int + @final + class struct_rusage( + structseq[float], tuple[float, float, int, int, int, int, int, int, int, int, int, int, int, int, int, int] + ): + @property + def ru_utime(self) -> float: ... + @property + def ru_stime(self) -> float: ... + @property + def ru_maxrss(self) -> int: ... + @property + def ru_ixrss(self) -> int: ... + @property + def ru_idrss(self) -> int: ... + @property + def ru_isrss(self) -> int: ... + @property + def ru_minflt(self) -> int: ... + @property + def ru_majflt(self) -> int: ... + @property + def ru_nswap(self) -> int: ... + @property + def ru_inblock(self) -> int: ... + @property + def ru_oublock(self) -> int: ... + @property + def ru_msgsnd(self) -> int: ... + @property + def ru_msgrcv(self) -> int: ... + @property + def ru_nsignals(self) -> int: ... + @property + def ru_nvcsw(self) -> int: ... + @property + def ru_nivcsw(self) -> int: ... + def getpagesize() -> int: ... + def getrlimit(__resource: int) -> tuple[int, int]: ... + def getrusage(__who: int) -> struct_rusage: ... + 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]: ... + @overload + def prlimit(pid: int, resource: int) -> tuple[int, int]: ... + error = OSError diff --git a/mypy/typeshed/stdlib/sched.pyi b/mypy/typeshed/stdlib/sched.pyi index cb96dc2bbf4a..71aacc5c2610 100644 --- a/mypy/typeshed/stdlib/sched.pyi +++ b/mypy/typeshed/stdlib/sched.pyi @@ -1,10 +1,10 @@ -from typing import Any, Callable, NamedTuple, Tuple +from typing import Any, Callable, NamedTuple class Event(NamedTuple): time: float priority: Any action: Callable[..., Any] - argument: Tuple[Any, ...] + argument: tuple[Any, ...] kwargs: dict[str, Any] class scheduler: @@ -14,7 +14,7 @@ class scheduler: time: float, priority: Any, action: Callable[..., Any], - argument: Tuple[Any, ...] = ..., + argument: tuple[Any, ...] = ..., kwargs: dict[str, Any] = ..., ) -> Event: ... def enter( @@ -22,7 +22,7 @@ class scheduler: delay: float, priority: Any, action: Callable[..., Any], - argument: Tuple[Any, ...] = ..., + argument: tuple[Any, ...] = ..., kwargs: dict[str, Any] = ..., ) -> Event: ... def run(self, blocking: bool = ...) -> float | None: ... diff --git a/mypy/typeshed/stdlib/secrets.pyi b/mypy/typeshed/stdlib/secrets.pyi index 6752a30f431e..f57eef8492d7 100644 --- a/mypy/typeshed/stdlib/secrets.pyi +++ b/mypy/typeshed/stdlib/secrets.pyi @@ -1,12 +1,13 @@ +from _typeshed import SupportsLenAndGetItem from hmac import compare_digest as compare_digest from random import SystemRandom as SystemRandom -from typing import Sequence, TypeVar +from typing import TypeVar _T = TypeVar("_T") def randbelow(exclusive_upper_bound: int) -> int: ... def randbits(k: int) -> int: ... -def choice(seq: Sequence[_T]) -> _T: ... +def choice(seq: SupportsLenAndGetItem[_T]) -> _T: ... def token_bytes(nbytes: int | None = ...) -> bytes: ... def token_hex(nbytes: int | None = ...) -> str: ... def token_urlsafe(nbytes: int | None = ...) -> str: ... diff --git a/mypy/typeshed/stdlib/select.pyi b/mypy/typeshed/stdlib/select.pyi index 0329dbaa2c11..e57504b5b447 100644 --- a/mypy/typeshed/stdlib/select.pyi +++ b/mypy/typeshed/stdlib/select.pyi @@ -13,6 +13,7 @@ if sys.platform != "win32": POLLOUT: int POLLPRI: int POLLRDBAND: int + POLLRDHUP: int POLLRDNORM: int POLLWRBAND: int POLLWRNORM: int @@ -32,7 +33,7 @@ error = OSError if sys.platform != "linux" and sys.platform != "win32": # BSD only - class kevent(object): + class kevent: data: Any fflags: int filter: int @@ -49,7 +50,7 @@ if sys.platform != "linux" and sys.platform != "win32": udata: Any = ..., ) -> None: ... # BSD only - class kqueue(object): + class kqueue: closed: bool def __init__(self) -> None: ... def close(self) -> None: ... @@ -99,7 +100,7 @@ if sys.platform != "linux" and sys.platform != "win32": KQ_NOTE_WRITE: int if sys.platform == "linux": - class epoll(object): + class epoll: def __init__(self, sizehint: int = ..., flags: int = ...) -> None: ... def __enter__(self: Self) -> Self: ... def __exit__( @@ -118,6 +119,7 @@ if sys.platform == "linux": @classmethod def fromfd(cls, __fd: FileDescriptorLike) -> epoll: ... EPOLLERR: int + EPOLLEXCLUSIVE: int EPOLLET: int EPOLLHUP: int EPOLLIN: int @@ -126,10 +128,12 @@ if sys.platform == "linux": EPOLLOUT: int EPOLLPRI: int EPOLLRDBAND: int + EPOLLRDHUP: int EPOLLRDNORM: int EPOLLWRBAND: int EPOLLWRNORM: int EPOLL_RDHUP: int + EPOLL_CLOEXEC: int if sys.platform != "linux" and sys.platform != "darwin" and sys.platform != "win32": # Solaris only diff --git a/mypy/typeshed/stdlib/signal.pyi b/mypy/typeshed/stdlib/signal.pyi index d617e24f227f..777391662aa3 100644 --- a/mypy/typeshed/stdlib/signal.pyi +++ b/mypy/typeshed/stdlib/signal.pyi @@ -1,56 +1,40 @@ import sys +from _typeshed import structseq from enum import IntEnum from types import FrameType -from typing import Any, Callable, Iterable, Optional, Tuple, Union - -if sys.platform != "win32": - class ItimerError(IOError): ... - ITIMER_PROF: int - ITIMER_REAL: int - ITIMER_VIRTUAL: int +from typing import Any, Callable, Iterable, Optional, Union +from typing_extensions import final NSIG: int class Signals(IntEnum): SIGABRT: int - if sys.platform != "win32": - SIGALRM: int + SIGEMT: int + SIGFPE: int + SIGILL: int + SIGINFO: int + SIGINT: int + SIGSEGV: int + SIGTERM: int + if sys.platform == "win32": SIGBREAK: int - if sys.platform != "win32": + CTRL_C_EVENT: int + CTRL_BREAK_EVENT: int + else: + SIGALRM: int SIGBUS: int SIGCHLD: int - if sys.platform != "darwin" and sys.platform != "win32": - SIGCLD: int - if sys.platform != "win32": SIGCONT: int - SIGEMT: int - SIGFPE: int - if sys.platform != "win32": SIGHUP: int - SIGILL: int - SIGINFO: int - SIGINT: int - if sys.platform != "win32": SIGIO: int SIGIOT: int SIGKILL: int SIGPIPE: int - if sys.platform != "darwin" and sys.platform != "win32": - SIGPOLL: int - SIGPWR: int - if sys.platform != "win32": SIGPROF: int SIGQUIT: int - if sys.platform != "darwin" and sys.platform != "win32": - SIGRTMAX: int - SIGRTMIN: int - SIGSEGV: int - if sys.platform != "win32": SIGSTOP: int SIGSYS: int - SIGTERM: int - if sys.platform != "win32": SIGTRAP: int SIGTSTP: int SIGTTIN: int @@ -62,65 +46,54 @@ class Signals(IntEnum): SIGWINCH: int SIGXCPU: int SIGXFSZ: int + if sys.platform != "darwin": + SIGCLD: int + SIGPOLL: int + SIGPWR: int + SIGRTMAX: int + SIGRTMIN: int class Handlers(IntEnum): SIG_DFL: int SIG_IGN: int -SIG_DFL = Handlers.SIG_DFL -SIG_IGN = Handlers.SIG_IGN - -if sys.platform != "win32": - class Sigmasks(IntEnum): - SIG_BLOCK: int - SIG_UNBLOCK: int - SIG_SETMASK: int - SIG_BLOCK = Sigmasks.SIG_BLOCK - SIG_UNBLOCK = Sigmasks.SIG_UNBLOCK - SIG_SETMASK = Sigmasks.SIG_SETMASK +SIG_DFL: Handlers +SIG_IGN: Handlers _SIGNUM = Union[int, Signals] _HANDLER = Union[Callable[[int, Optional[FrameType]], Any], int, Handlers, None] +def default_int_handler(signum: int, frame: FrameType | None) -> None: ... +def getsignal(__signalnum: _SIGNUM) -> _HANDLER: ... +def signal(__signalnum: _SIGNUM, __handler: _HANDLER) -> _HANDLER: ... + SIGABRT: Signals -if sys.platform != "win32": - SIGALRM: Signals +SIGEMT: Signals +SIGFPE: Signals +SIGILL: Signals +SIGINFO: Signals +SIGINT: Signals +SIGSEGV: Signals +SIGTERM: Signals + if sys.platform == "win32": SIGBREAK: Signals -if sys.platform != "win32": + CTRL_C_EVENT: Signals + CTRL_BREAK_EVENT: Signals +else: + SIGALRM: Signals SIGBUS: Signals SIGCHLD: Signals -if sys.platform != "darwin" and sys.platform != "win32": - SIGCLD: Signals -if sys.platform != "win32": SIGCONT: Signals -SIGEMT: Signals -SIGFPE: Signals -if sys.platform != "win32": SIGHUP: Signals -SIGILL: Signals -SIGINFO: Signals -SIGINT: Signals -if sys.platform != "win32": SIGIO: Signals SIGIOT: Signals SIGKILL: Signals SIGPIPE: Signals -if sys.platform != "darwin" and sys.platform != "win32": - SIGPOLL: Signals - SIGPWR: Signals -if sys.platform != "win32": SIGPROF: Signals SIGQUIT: Signals -if sys.platform != "darwin" and sys.platform != "win32": - SIGRTMAX: Signals - SIGRTMIN: Signals -SIGSEGV: Signals -if sys.platform != "win32": SIGSTOP: Signals SIGSYS: Signals -SIGTERM: Signals -if sys.platform != "win32": SIGTRAP: Signals SIGTSTP: Signals SIGTTIN: Signals @@ -132,64 +105,58 @@ if sys.platform != "win32": SIGWINCH: Signals SIGXCPU: Signals SIGXFSZ: Signals - -if sys.platform == "win32": - CTRL_C_EVENT: int - CTRL_BREAK_EVENT: int - -if sys.platform != "win32" and sys.platform != "darwin": - class struct_siginfo(Tuple[int, int, int, int, int, int, int]): - def __init__(self, sequence: Iterable[int]) -> None: ... - @property - def si_signo(self) -> int: ... - @property - def si_code(self) -> int: ... - @property - def si_errno(self) -> int: ... - @property - def si_pid(self) -> int: ... - @property - def si_uid(self) -> int: ... - @property - def si_status(self) -> int: ... - @property - def si_band(self) -> int: ... - -if sys.platform != "win32": + class ItimerError(IOError): ... + ITIMER_PROF: int + ITIMER_REAL: int + ITIMER_VIRTUAL: int + class Sigmasks(IntEnum): + SIG_BLOCK: int + SIG_UNBLOCK: int + SIG_SETMASK: int + SIG_BLOCK = Sigmasks.SIG_BLOCK + SIG_UNBLOCK = Sigmasks.SIG_UNBLOCK + SIG_SETMASK = Sigmasks.SIG_SETMASK def alarm(__seconds: int) -> int: ... - -def default_int_handler(signum: int, frame: FrameType) -> None: ... - -if sys.platform != "win32": def getitimer(__which: int) -> tuple[float, float]: ... - -def getsignal(__signalnum: _SIGNUM) -> _HANDLER: ... + def pause() -> None: ... + def pthread_kill(__thread_id: int, __signalnum: int) -> None: ... + def pthread_sigmask(__how: int, __mask: Iterable[int]) -> set[_SIGNUM]: ... + def setitimer(__which: int, __seconds: float, __interval: float = ...) -> tuple[float, float]: ... + def siginterrupt(__signalnum: int, __flag: bool) -> None: ... + def sigpending() -> Any: ... + def sigwait(__sigset: Iterable[int]) -> _SIGNUM: ... + if sys.platform != "darwin": + SIGCLD: Signals + SIGPOLL: Signals + SIGPWR: Signals + SIGRTMAX: Signals + SIGRTMIN: Signals + @final + class struct_siginfo(structseq[int], tuple[int, int, int, int, int, int, int]): + @property + def si_signo(self) -> int: ... + @property + def si_code(self) -> int: ... + @property + def si_errno(self) -> int: ... + @property + def si_pid(self) -> int: ... + @property + def si_uid(self) -> int: ... + @property + def si_status(self) -> int: ... + @property + def si_band(self) -> int: ... + def sigtimedwait(sigset: Iterable[int], timeout: float) -> struct_siginfo | None: ... + def sigwaitinfo(sigset: Iterable[int]) -> struct_siginfo: ... if sys.version_info >= (3, 8): def strsignal(__signalnum: _SIGNUM) -> str | None: ... 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]: ... - if sys.version_info >= (3, 7): def set_wakeup_fd(fd: int, *, warn_on_full_buffer: bool = ...) -> int: ... else: def set_wakeup_fd(fd: int) -> int: ... - -if sys.platform != "win32": - 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: ... - -if sys.platform != "win32": - def sigpending() -> Any: ... - def sigwait(__sigset: Iterable[int]) -> _SIGNUM: ... - if sys.platform != "darwin": - def sigtimedwait(sigset: Iterable[int], timeout: float) -> struct_siginfo | None: ... - def sigwaitinfo(sigset: Iterable[int]) -> struct_siginfo: ... diff --git a/mypy/typeshed/stdlib/smtpd.pyi b/mypy/typeshed/stdlib/smtpd.pyi index 2b6020524827..e5401552caae 100644 --- a/mypy/typeshed/stdlib/smtpd.pyi +++ b/mypy/typeshed/stdlib/smtpd.pyi @@ -2,9 +2,9 @@ import asynchat import asyncore import socket from collections import defaultdict -from typing import Any, Tuple, Type +from typing import Any, Type -_Address = Tuple[str, int] # (host, port) +_Address = tuple[str, int] # (host, port) class SMTPChannel(asynchat.async_chat): COMMAND: int @@ -40,7 +40,7 @@ class SMTPChannel(asynchat.async_chat): decode_data: bool = ..., ) -> None: ... # base asynchat.async_chat.push() accepts bytes - def push(self, msg: str) -> None: ... # type: ignore + def push(self, msg: str) -> None: ... # type: ignore[override] def collect_incoming_data(self, data: bytes) -> None: ... def found_terminator(self) -> None: ... def smtp_HELO(self, arg: str) -> None: ... @@ -77,11 +77,7 @@ class SMTPServer(asyncore.dispatcher): class DebuggingServer(SMTPServer): ... class PureProxy(SMTPServer): - def process_message( # type: ignore - self, peer: _Address, mailfrom: str, rcpttos: list[str], data: bytes | str - ) -> str | None: ... + def process_message(self, peer: _Address, mailfrom: str, rcpttos: list[str], data: bytes | str) -> str | None: ... # type: ignore[override] class MailmanProxy(PureProxy): - def process_message( # type: ignore - self, peer: _Address, mailfrom: str, rcpttos: list[str], data: bytes | str - ) -> str | None: ... + def process_message(self, peer: _Address, mailfrom: str, rcpttos: list[str], data: bytes | str) -> str | None: ... # type: ignore[override] diff --git a/mypy/typeshed/stdlib/smtplib.pyi b/mypy/typeshed/stdlib/smtplib.pyi index 5dbdf5d44c29..0a57f1f5d2de 100644 --- a/mypy/typeshed/stdlib/smtplib.pyi +++ b/mypy/typeshed/stdlib/smtplib.pyi @@ -1,14 +1,15 @@ +import sys from _typeshed import Self from email.message import Message as _Message from socket import socket from ssl import SSLContext from types import TracebackType -from typing import Any, Dict, Pattern, Protocol, Sequence, Tuple, Type, Union, overload +from typing import Any, Pattern, Protocol, Sequence, Type, Union, overload -_Reply = Tuple[int, bytes] -_SendErrs = Dict[str, _Reply] +_Reply = tuple[int, bytes] +_SendErrs = dict[str, _Reply] # Should match source_address for socket.create_connection -_SourceAddress = Tuple[Union[bytearray, bytes, str], int] +_SourceAddress = tuple[Union[bytearray, bytes, str], int] SMTP_PORT: int SMTP_SSL_PORT: int @@ -149,6 +150,16 @@ class SMTP_SSL(SMTP): LMTP_PORT: int class LMTP(SMTP): - def __init__( - self, host: str = ..., port: int = ..., local_hostname: str | None = ..., source_address: _SourceAddress | None = ... - ) -> None: ... + if sys.version_info >= (3, 9): + def __init__( + self, + host: str = ..., + port: int = ..., + local_hostname: str | None = ..., + source_address: _SourceAddress | None = ..., + timeout: float = ..., + ) -> None: ... + else: + def __init__( + self, host: str = ..., port: int = ..., local_hostname: str | None = ..., source_address: _SourceAddress | None = ... + ) -> None: ... diff --git a/mypy/typeshed/stdlib/socket.pyi b/mypy/typeshed/stdlib/socket.pyi index 1f5ae6eb76c8..430fef4ff344 100644 --- a/mypy/typeshed/stdlib/socket.pyi +++ b/mypy/typeshed/stdlib/socket.pyi @@ -570,9 +570,9 @@ class socket(_socket.socket): ) -> BinaryIO: ... def sendfile(self, file: BinaryIO, offset: int = ..., count: int | None = ...) -> int: ... @property - def family(self) -> AddressFamily: ... # type: ignore + def family(self) -> AddressFamily: ... # type: ignore[override] @property - def type(self) -> SocketKind: ... # type: ignore + def type(self) -> SocketKind: ... # type: ignore[override] def get_inheritable(self) -> bool: ... def set_inheritable(self, inheritable: bool) -> None: ... @@ -593,7 +593,7 @@ if sys.platform == "win32": def socketpair(family: int = ..., type: int = ..., proto: int = ...) -> tuple[socket, socket]: ... else: - def socketpair( # type: ignore + def socketpair( family: int | AddressFamily | None = ..., type: SocketType | int = ..., proto: int = ... ) -> tuple[socket, socket]: ... diff --git a/mypy/typeshed/stdlib/socketserver.pyi b/mypy/typeshed/stdlib/socketserver.pyi index 6f5eeefb84fd..c663e73bef50 100644 --- a/mypy/typeshed/stdlib/socketserver.pyi +++ b/mypy/typeshed/stdlib/socketserver.pyi @@ -2,11 +2,11 @@ import sys import types from _typeshed import Self from socket import socket as _socket -from typing import Any, BinaryIO, Callable, ClassVar, Tuple, Type, TypeVar, Union +from typing import Any, BinaryIO, Callable, ClassVar, Type, TypeVar, Union _T = TypeVar("_T") -_RequestType = Union[_socket, Tuple[bytes, _socket]] -_AddressType = Union[Tuple[str, int], str] +_RequestType = Union[_socket, tuple[bytes, _socket]] +_AddressType = Union[tuple[str, int], str] class BaseServer: address_family: int @@ -55,6 +55,7 @@ class TCPServer(BaseServer): def close_request(self, request: _RequestType) -> None: ... # undocumented class UDPServer(BaseServer): + max_packet_size: ClassVar[int] def __init__( self, server_address: tuple[str, int], diff --git a/mypy/typeshed/stdlib/spwd.pyi b/mypy/typeshed/stdlib/spwd.pyi index 0f8d36fee945..7a62d62523f5 100644 --- a/mypy/typeshed/stdlib/spwd.pyi +++ b/mypy/typeshed/stdlib/spwd.pyi @@ -1,15 +1,28 @@ -from typing import NamedTuple +import sys +from _typeshed import structseq +from typing import Any +from typing_extensions import final -class struct_spwd(NamedTuple): - sp_namp: str - sp_pwdp: str - sp_lstchg: int - sp_min: int - sp_max: int - sp_warn: int - sp_inact: int - sp_expire: int - sp_flag: int - -def getspall() -> list[struct_spwd]: ... -def getspnam(__arg: str) -> struct_spwd: ... +if sys.platform != "win32": + @final + class struct_spwd(structseq[Any], tuple[str, str, int, int, int, int, int, int, int]): + @property + def sp_namp(self) -> str: ... + @property + def sp_pwdp(self) -> str: ... + @property + def sp_lstchg(self) -> int: ... + @property + def sp_min(self) -> int: ... + @property + def sp_max(self) -> int: ... + @property + def sp_warn(self) -> int: ... + @property + def sp_inact(self) -> int: ... + @property + def sp_expire(self) -> int: ... + @property + def sp_flag(self) -> int: ... + def getspall() -> list[struct_spwd]: ... + def getspnam(__arg: str) -> struct_spwd: ... diff --git a/mypy/typeshed/stdlib/sqlite3/dbapi2.pyi b/mypy/typeshed/stdlib/sqlite3/dbapi2.pyi index e2e45d538da9..ea9098940d4b 100644 --- a/mypy/typeshed/stdlib/sqlite3/dbapi2.pyi +++ b/mypy/typeshed/stdlib/sqlite3/dbapi2.pyi @@ -40,6 +40,8 @@ if sys.version_info >= (3, 7): SQLITE_DELETE: int SQLITE_DENY: int SQLITE_DETACH: int +if sys.version_info >= (3, 7): + SQLITE_DONE: int SQLITE_DROP_INDEX: int SQLITE_DROP_TABLE: int SQLITE_DROP_TEMP_INDEX: int @@ -83,7 +85,7 @@ version: str # TODO: adapt needs to get probed def adapt(obj, protocol, alternate): ... -def complete_statement(sql: str) -> bool: ... +def complete_statement(statement: str) -> bool: ... if sys.version_info >= (3, 7): def connect( @@ -115,7 +117,7 @@ def register_adapter(__type: Type[_T], __caster: Callable[[_T], int | float | st def register_converter(__name: str, __converter: Callable[[bytes], Any]) -> None: ... if sys.version_info < (3, 8): - class Cache(object): + class Cache: def __init__(self, *args, **kwargs) -> None: ... def display(self, *args, **kwargs) -> None: ... def get(self, *args, **kwargs) -> None: ... @@ -124,7 +126,7 @@ class _AggregateProtocol(Protocol): def step(self, value: int) -> None: ... def finalize(self) -> int: ... -class Connection(object): +class Connection: DataError: Any DatabaseError: Any Error: Any @@ -154,16 +156,14 @@ class Connection(object): # TODO: please check in executemany() if seq_of_parameters type is possible like this def executemany(self, __sql: str, __parameters: Iterable[Iterable[Any]]) -> Cursor: ... def executescript(self, __sql_script: bytes | str) -> Cursor: ... - def interrupt(self, *args: Any, **kwargs: Any) -> None: ... - def iterdump(self, *args: Any, **kwargs: Any) -> Generator[str, None, None]: ... - def rollback(self, *args: Any, **kwargs: Any) -> None: ... - # TODO: set_authorizer(authorzer_callback) - # see https://docs.python.org/2/library/sqlite3.html#sqlite3.Connection.set_authorizer - # returns [SQLITE_OK, SQLITE_DENY, SQLITE_IGNORE] so perhaps int - def set_authorizer(self, *args: Any, **kwargs: Any) -> None: ... - # set_progress_handler(handler, n) -> see https://docs.python.org/2/library/sqlite3.html#sqlite3.Connection.set_progress_handler - def set_progress_handler(self, *args: Any, **kwargs: Any) -> None: ... - def set_trace_callback(self, *args: Any, **kwargs: Any) -> None: ... + def interrupt(self) -> None: ... + def iterdump(self) -> Generator[str, None, None]: ... + def rollback(self) -> None: ... + def set_authorizer( + self, authorizer_callback: Callable[[int, str | None, str | None, str | None, str | None], int] | None + ) -> None: ... + def set_progress_handler(self, progress_handler: Callable[[], bool | None] | None, n: int) -> None: ... + def set_trace_callback(self, trace_callback: Callable[[str], object] | None) -> None: ... # enable_load_extension and load_extension is not available on python distributions compiled # without sqlite3 loadable extension support. see footnotes https://docs.python.org/3/library/sqlite3.html#f1 def enable_load_extension(self, enabled: bool) -> None: ... @@ -193,21 +193,26 @@ class Cursor(Iterator[Any]): # required type is sqlite3.Connection (which is imported as _Connection) # however, the name of the __init__ variable is unknown def __init__(self, *args: Any, **kwargs: Any) -> None: ... - def close(self, *args: Any, **kwargs: Any) -> None: ... + def close(self) -> None: ... def execute(self, __sql: str, __parameters: Iterable[Any] = ...) -> Cursor: ... def executemany(self, __sql: str, __seq_of_parameters: Iterable[Iterable[Any]]) -> Cursor: ... def executescript(self, __sql_script: bytes | str) -> Cursor: ... def fetchall(self) -> list[Any]: ... def fetchmany(self, size: int | None = ...) -> list[Any]: ... def fetchone(self) -> Any: ... - def setinputsizes(self, *args: Any, **kwargs: Any) -> None: ... - def setoutputsize(self, *args: Any, **kwargs: Any) -> None: ... + def setinputsizes(self, __sizes: object) -> None: ... # does nothing + def setoutputsize(self, __size: object, __column: object = ...) -> None: ... # does nothing def __iter__(self) -> Cursor: ... def __next__(self) -> Any: ... class DataError(DatabaseError): ... class DatabaseError(Error): ... -class Error(Exception): ... + +class Error(Exception): + if sys.version_info >= (3, 11): + sqlite_errorcode: int + sqlite_errorname: str + class IntegrityError(DatabaseError): ... class InterfaceError(Error): ... class InternalError(DatabaseError): ... @@ -216,14 +221,14 @@ class OperationalError(DatabaseError): ... OptimizedUnicode = str -class PrepareProtocol(object): +class PrepareProtocol: def __init__(self, *args: Any, **kwargs: Any) -> None: ... class ProgrammingError(DatabaseError): ... -class Row(object): +class Row: def __init__(self, *args: Any, **kwargs: Any) -> None: ... - def keys(self, *args: Any, **kwargs: Any): ... + def keys(self): ... def __eq__(self, other): ... def __ge__(self, other): ... def __getitem__(self, index): ... @@ -236,7 +241,7 @@ class Row(object): def __ne__(self, other): ... if sys.version_info < (3, 8): - class Statement(object): + class Statement: def __init__(self, *args, **kwargs): ... class Warning(Exception): ... diff --git a/mypy/typeshed/stdlib/sre_compile.pyi b/mypy/typeshed/stdlib/sre_compile.pyi index aac8c0242764..98a9f4dad008 100644 --- a/mypy/typeshed/stdlib/sre_compile.pyi +++ b/mypy/typeshed/stdlib/sre_compile.pyi @@ -1,18 +1,5 @@ -from sre_constants import ( - SRE_FLAG_ASCII as SRE_FLAG_ASCII, - SRE_FLAG_DEBUG as SRE_FLAG_DEBUG, - SRE_FLAG_DOTALL as SRE_FLAG_DOTALL, - SRE_FLAG_IGNORECASE as SRE_FLAG_IGNORECASE, - SRE_FLAG_LOCALE as SRE_FLAG_LOCALE, - SRE_FLAG_MULTILINE as SRE_FLAG_MULTILINE, - SRE_FLAG_TEMPLATE as SRE_FLAG_TEMPLATE, - SRE_FLAG_UNICODE as SRE_FLAG_UNICODE, - SRE_FLAG_VERBOSE as SRE_FLAG_VERBOSE, - SRE_INFO_CHARSET as SRE_INFO_CHARSET, - SRE_INFO_LITERAL as SRE_INFO_LITERAL, - SRE_INFO_PREFIX as SRE_INFO_PREFIX, - _NamedIntConstant, -) +from sre_constants import * +from sre_constants import _NamedIntConstant from sre_parse import SubPattern from typing import Any, Pattern diff --git a/mypy/typeshed/stdlib/sre_constants.pyi b/mypy/typeshed/stdlib/sre_constants.pyi index 4658d0e4b175..df7e1a28007b 100644 --- a/mypy/typeshed/stdlib/sre_constants.pyi +++ b/mypy/typeshed/stdlib/sre_constants.pyi @@ -1,6 +1,8 @@ import sys from typing import Any +MAXGROUPS: int + MAGIC: int class error(Exception): @@ -20,6 +22,9 @@ OPCODES: list[_NamedIntConstant] ATCODES: list[_NamedIntConstant] CHCODES: list[_NamedIntConstant] OP_IGNORE: dict[_NamedIntConstant, _NamedIntConstant] +if sys.version_info >= (3, 7): + OP_LOCALE_IGNORE: dict[_NamedIntConstant, _NamedIntConstant] + OP_UNICODE_IGNORE: dict[_NamedIntConstant, _NamedIntConstant] AT_MULTILINE: dict[_NamedIntConstant, _NamedIntConstant] AT_LOCALE: dict[_NamedIntConstant, _NamedIntConstant] AT_UNICODE: dict[_NamedIntConstant, _NamedIntConstant] @@ -75,6 +80,14 @@ SUBPATTERN: _NamedIntConstant MIN_REPEAT_ONE: _NamedIntConstant if sys.version_info >= (3, 7): RANGE_UNI_IGNORE: _NamedIntConstant + GROUPREF_LOC_IGNORE: _NamedIntConstant + GROUPREF_UNI_IGNORE: _NamedIntConstant + IN_LOC_IGNORE: _NamedIntConstant + IN_UNI_IGNORE: _NamedIntConstant + LITERAL_LOC_IGNORE: _NamedIntConstant + LITERAL_UNI_IGNORE: _NamedIntConstant + NOT_LITERAL_LOC_IGNORE: _NamedIntConstant + NOT_LITERAL_UNI_IGNORE: _NamedIntConstant else: RANGE_IGNORE: _NamedIntConstant MIN_REPEAT: _NamedIntConstant diff --git a/mypy/typeshed/stdlib/sre_parse.pyi b/mypy/typeshed/stdlib/sre_parse.pyi index 2d00bedc2c81..c4de55bcbf7e 100644 --- a/mypy/typeshed/stdlib/sre_parse.pyi +++ b/mypy/typeshed/stdlib/sre_parse.pyi @@ -1,6 +1,7 @@ import sys +from sre_constants import * from sre_constants import _NamedIntConstant as _NIC, error as _Error -from typing import Any, Iterable, List, Match, Optional, Pattern as _Pattern, Tuple, Union, overload +from typing import Any, Iterable, Match, Optional, Pattern as _Pattern, Union, overload SPECIAL_CHARS: str REPEAT_CHARS: str @@ -12,6 +13,8 @@ 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] +if sys.version_info >= (3, 7): + TYPE_FLAGS: int GLOBAL_FLAGS: int class Verbose(Exception): ... @@ -24,7 +27,7 @@ class _State: def __init__(self) -> None: ... @property def groups(self) -> int: ... - def opengroup(self, name: str = ...) -> int: ... + def opengroup(self, name: str | None = ...) -> int: ... def closegroup(self, gid: int, p: SubPattern) -> None: ... def checkgroup(self, gid: int) -> bool: ... def checklookbehindgroup(self, gid: int, source: Tokenizer) -> None: ... @@ -34,12 +37,12 @@ if sys.version_info >= (3, 8): else: Pattern = _State -_OpSubpatternType = Tuple[Optional[int], int, int, SubPattern] -_OpGroupRefExistsType = Tuple[int, SubPattern, SubPattern] -_OpInType = List[Tuple[_NIC, int]] -_OpBranchType = Tuple[None, List[SubPattern]] +_OpSubpatternType = tuple[Optional[int], int, int, SubPattern] +_OpGroupRefExistsType = tuple[int, SubPattern, SubPattern] +_OpInType = list[tuple[_NIC, int]] +_OpBranchType = tuple[None, list[SubPattern]] _AvType = Union[_OpInType, _OpBranchType, Iterable[SubPattern], _OpGroupRefExistsType, _OpSubpatternType] -_CodeType = Tuple[_NIC, _AvType] +_CodeType = tuple[_NIC, _AvType] class SubPattern: data: list[_CodeType] @@ -82,8 +85,8 @@ class Tokenizer: def fix_flags(src: str | bytes, flags: int) -> int: ... -_TemplateType = Tuple[List[Tuple[int, int]], List[Optional[str]]] -_TemplateByteType = Tuple[List[Tuple[int, int]], List[Optional[bytes]]] +_TemplateType = tuple[list[tuple[int, int]], list[Optional[str]]] +_TemplateByteType = tuple[list[tuple[int, int]], list[Optional[bytes]]] if sys.version_info >= (3, 8): def parse(str: str, flags: int = ..., state: State | None = ...) -> SubPattern: ... @overload diff --git a/mypy/typeshed/stdlib/ssl.pyi b/mypy/typeshed/stdlib/ssl.pyi index 689b083d764c..cdb727285647 100644 --- a/mypy/typeshed/stdlib/ssl.pyi +++ b/mypy/typeshed/stdlib/ssl.pyi @@ -2,14 +2,14 @@ import enum import socket import sys from _typeshed import ReadableBuffer, Self, StrOrBytesPath, WriteableBuffer -from typing import Any, Callable, ClassVar, Dict, Iterable, List, NamedTuple, Optional, Set, Tuple, Type, Union, overload +from typing import Any, Callable, ClassVar, Iterable, NamedTuple, Optional, Type, Union, overload from typing_extensions import Literal, TypedDict -_PCTRTT = Tuple[Tuple[str, str], ...] -_PCTRTTT = Tuple[_PCTRTT, ...] -_PeerCertRetDictType = Dict[str, Union[str, _PCTRTTT, _PCTRTT]] +_PCTRTT = tuple[tuple[str, str], ...] +_PCTRTTT = tuple[_PCTRTT, ...] +_PeerCertRetDictType = dict[str, Union[str, _PCTRTTT, _PCTRTT]] _PeerCertRetType = Union[_PeerCertRetDictType, bytes, None] -_EnumRetType = List[Tuple[bytes, str, Union[Set[str], bool]]] +_EnumRetType = list[tuple[bytes, str, Union[set[str], bool]]] _PasswordType = Union[Callable[[], Union[str, bytes]], str, bytes] _SrvnmeCbType = Callable[[Union[SSLSocket, SSLObject], Optional[str], SSLSocket], Optional[int]] @@ -102,7 +102,15 @@ 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: ... + +if sys.version_info >= (3, 10): + def get_server_certificate( + addr: tuple[str, int], ssl_version: int = ..., ca_certs: str | None = ..., timeout: float = ... + ) -> str: ... + +else: + 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: ... @@ -135,6 +143,9 @@ class VerifyFlags(enum.IntFlag): VERIFY_CRL_CHECK_CHAIN: int VERIFY_X509_STRICT: int VERIFY_X509_TRUSTED_FIRST: int + if sys.version_info >= (3, 10): + VERIFY_ALLOW_PROXY_CERTS: int + VERIFY_X509_PARTIAL_CHAIN: int VERIFY_DEFAULT: VerifyFlags VERIFY_CRL_CHECK_LEAF: VerifyFlags @@ -142,6 +153,10 @@ VERIFY_CRL_CHECK_CHAIN: VerifyFlags VERIFY_X509_STRICT: VerifyFlags VERIFY_X509_TRUSTED_FIRST: VerifyFlags +if sys.version_info >= (3, 10): + VERIFY_ALLOW_PROXY_CERTS: VerifyFlags + VERIFY_X509_PARTIAL_CHAIN: VerifyFlags + class _SSLMethod(enum.IntEnum): PROTOCOL_SSLv23: int PROTOCOL_SSLv2: int @@ -205,7 +220,7 @@ if sys.version_info >= (3, 7): HAS_TLSv1: bool HAS_TLSv1_1: bool HAS_TLSv1_2: bool - HAS_TLSv1_3: bool +HAS_TLSv1_3: bool HAS_ALPN: bool HAS_ECDH: bool HAS_SNI: bool @@ -293,7 +308,9 @@ class SSLSocket(socket.socket): server_hostname: str | None session: SSLSession | None session_reused: bool | None - if sys.version_info < (3, 7): + if sys.version_info >= (3, 7): + def __init__(self, *args: Any, **kwargs: Any) -> None: ... + else: def __init__( self, sock: socket.socket | None = ..., @@ -315,8 +332,6 @@ class SSLSocket(socket.socket): _context: SSLContext | None = ..., _session: Any | None = ..., ) -> None: ... - else: - def __init__(self, *args: Any, **kwargs: Any) -> None: ... def connect(self, addr: socket._Address | bytes) -> None: ... def connect_ex(self, addr: socket._Address | bytes) -> int: ... def recv(self, buflen: int = ..., flags: int = ...) -> bytes: ... diff --git a/mypy/typeshed/stdlib/stat.pyi b/mypy/typeshed/stdlib/stat.pyi index d6450fe77817..4518acb5a162 100644 --- a/mypy/typeshed/stdlib/stat.pyi +++ b/mypy/typeshed/stdlib/stat.pyi @@ -1,97 +1 @@ -import sys - -def S_ISDIR(mode: int) -> bool: ... -def S_ISCHR(mode: int) -> bool: ... -def S_ISBLK(mode: int) -> bool: ... -def S_ISREG(mode: int) -> bool: ... -def S_ISFIFO(mode: int) -> bool: ... -def S_ISLNK(mode: int) -> bool: ... -def S_ISSOCK(mode: int) -> bool: ... -def S_IMODE(mode: int) -> int: ... -def S_IFMT(mode: int) -> int: ... -def S_ISDOOR(mode: int) -> int: ... -def S_ISPORT(mode: int) -> int: ... -def S_ISWHT(mode: int) -> int: ... -def filemode(mode: int) -> str: ... - -ST_MODE: int -ST_INO: int -ST_DEV: int -ST_NLINK: int -ST_UID: int -ST_GID: int -ST_SIZE: int -ST_ATIME: int -ST_MTIME: int -ST_CTIME: int - -S_IFSOCK: int -S_IFLNK: int -S_IFREG: int -S_IFBLK: int -S_IFDIR: int -S_IFCHR: int -S_IFIFO: int -S_IFDOOR: int -S_IFPORT: int -S_IFWHT: int -S_ISUID: int -S_ISGID: int -S_ISVTX: int - -S_IRWXU: int -S_IRUSR: int -S_IWUSR: int -S_IXUSR: int - -S_IRWXG: int -S_IRGRP: int -S_IWGRP: int -S_IXGRP: int - -S_IRWXO: int -S_IROTH: int -S_IWOTH: int -S_IXOTH: int - -S_ENFMT: int -S_IREAD: int -S_IWRITE: int -S_IEXEC: int - -UF_NODUMP: int -UF_IMMUTABLE: int -UF_APPEND: int -UF_OPAQUE: int -UF_NOUNLINK: int -if sys.platform == "darwin": - UF_COMPRESSED: int # OS X 10.6+ only - UF_HIDDEN: int # OX X 10.5+ only -SF_ARCHIVED: int -SF_IMMUTABLE: int -SF_APPEND: int -SF_NOUNLINK: int -SF_SNAPSHOT: int - -FILE_ATTRIBUTE_ARCHIVE: int -FILE_ATTRIBUTE_COMPRESSED: int -FILE_ATTRIBUTE_DEVICE: int -FILE_ATTRIBUTE_DIRECTORY: int -FILE_ATTRIBUTE_ENCRYPTED: int -FILE_ATTRIBUTE_HIDDEN: int -FILE_ATTRIBUTE_INTEGRITY_STREAM: int -FILE_ATTRIBUTE_NORMAL: int -FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: int -FILE_ATTRIBUTE_NO_SCRUB_DATA: int -FILE_ATTRIBUTE_OFFLINE: int -FILE_ATTRIBUTE_READONLY: int -FILE_ATTRIBUTE_REPARSE_POINT: int -FILE_ATTRIBUTE_SPARSE_FILE: int -FILE_ATTRIBUTE_SYSTEM: int -FILE_ATTRIBUTE_TEMPORARY: int -FILE_ATTRIBUTE_VIRTUAL: int - -if sys.platform == "win32" and sys.version_info >= (3, 8): - IO_REPARSE_TAG_SYMLINK: int - IO_REPARSE_TAG_MOUNT_POINT: int - IO_REPARSE_TAG_APPEXECLINK: int +from _stat import * diff --git a/mypy/typeshed/stdlib/statistics.pyi b/mypy/typeshed/stdlib/statistics.pyi index ec3574ab12b1..908d6adaf45d 100644 --- a/mypy/typeshed/stdlib/statistics.pyi +++ b/mypy/typeshed/stdlib/statistics.pyi @@ -1,5 +1,5 @@ import sys -from _typeshed import SupportsLessThanT +from _typeshed import SupportsRichComparisonT from decimal import Decimal from fractions import Fraction from typing import Any, Hashable, Iterable, NamedTuple, Sequence, SupportsFloat, Type, TypeVar, Union @@ -27,8 +27,8 @@ else: def harmonic_mean(data: Iterable[_NumberT]) -> _NumberT: ... def median(data: Iterable[_NumberT]) -> _NumberT: ... -def median_low(data: Iterable[SupportsLessThanT]) -> SupportsLessThanT: ... -def median_high(data: Iterable[SupportsLessThanT]) -> SupportsLessThanT: ... +def median_low(data: Iterable[SupportsRichComparisonT]) -> SupportsRichComparisonT: ... +def median_high(data: Iterable[SupportsRichComparisonT]) -> SupportsRichComparisonT: ... def median_grouped(data: Iterable[_NumberT], interval: _NumberT = ...) -> _NumberT: ... def mode(data: Iterable[_HashableT]) -> _HashableT: ... diff --git a/mypy/typeshed/stdlib/stringprep.pyi b/mypy/typeshed/stdlib/stringprep.pyi index cbc562d460f6..fc28c027ca9b 100644 --- a/mypy/typeshed/stdlib/stringprep.pyi +++ b/mypy/typeshed/stdlib/stringprep.pyi @@ -1,3 +1,11 @@ +b1_set: set[int] +b3_exceptions: dict[int, str] +c22_specials: set[int] +c6_set: set[int] +c7_set: set[int] +c8_set: set[int] +c9_set: set[int] + def in_table_a1(code: str) -> bool: ... def in_table_b1(code: str) -> bool: ... def map_table_b3(code: str) -> str: ... diff --git a/mypy/typeshed/stdlib/struct.pyi b/mypy/typeshed/stdlib/struct.pyi index d7c9cbef7dce..47af62973259 100644 --- a/mypy/typeshed/stdlib/struct.pyi +++ b/mypy/typeshed/stdlib/struct.pyi @@ -1,14 +1,14 @@ import sys from _typeshed import ReadableBuffer, WriteableBuffer -from typing import Any, Iterator, Tuple +from typing import Any, Iterator class error(Exception): ... def pack(fmt: str | bytes, *v: Any) -> bytes: ... def pack_into(fmt: str | bytes, buffer: WriteableBuffer, offset: int, *v: Any) -> None: ... -def unpack(__format: str | bytes, __buffer: ReadableBuffer) -> Tuple[Any, ...]: ... -def unpack_from(__format: str | bytes, buffer: ReadableBuffer, offset: int = ...) -> Tuple[Any, ...]: ... -def iter_unpack(__format: str | bytes, __buffer: ReadableBuffer) -> Iterator[Tuple[Any, ...]]: ... +def unpack(__format: str | bytes, __buffer: ReadableBuffer) -> tuple[Any, ...]: ... +def unpack_from(__format: str | bytes, buffer: ReadableBuffer, offset: int = ...) -> tuple[Any, ...]: ... +def iter_unpack(__format: str | bytes, __buffer: ReadableBuffer) -> Iterator[tuple[Any, ...]]: ... def calcsize(__format: str | bytes) -> int: ... class Struct: @@ -20,6 +20,6 @@ class Struct: def __init__(self, format: str | bytes) -> None: ... def pack(self, *v: Any) -> bytes: ... def pack_into(self, buffer: WriteableBuffer, offset: int, *v: Any) -> None: ... - def unpack(self, __buffer: ReadableBuffer) -> Tuple[Any, ...]: ... - def unpack_from(self, buffer: ReadableBuffer, offset: int = ...) -> Tuple[Any, ...]: ... - def iter_unpack(self, __buffer: ReadableBuffer) -> Iterator[Tuple[Any, ...]]: ... + def unpack(self, __buffer: ReadableBuffer) -> tuple[Any, ...]: ... + def unpack_from(self, buffer: ReadableBuffer, offset: int = ...) -> tuple[Any, ...]: ... + def iter_unpack(self, __buffer: ReadableBuffer) -> Iterator[tuple[Any, ...]]: ... diff --git a/mypy/typeshed/stdlib/symbol.pyi b/mypy/typeshed/stdlib/symbol.pyi index 2d3bd83087c7..234c814b55b5 100644 --- a/mypy/typeshed/stdlib/symbol.pyi +++ b/mypy/typeshed/stdlib/symbol.pyi @@ -1,3 +1,5 @@ +import sys + single_input: int file_input: int eval_input: int @@ -84,5 +86,13 @@ comp_if: int encoding_decl: int yield_expr: int yield_arg: int +if sys.version_info >= (3, 7): + sync_comp_for: int +if sys.version_info >= (3, 8): + func_body_suite: int + func_type: int + func_type_input: int + namedexpr_test: int + typelist: int sym_name: dict[int, str] diff --git a/mypy/typeshed/stdlib/symtable.pyi b/mypy/typeshed/stdlib/symtable.pyi index 613ac90ef7a9..bc25a4c4639b 100644 --- a/mypy/typeshed/stdlib/symtable.pyi +++ b/mypy/typeshed/stdlib/symtable.pyi @@ -1,9 +1,9 @@ import sys -from typing import Any, Sequence, Tuple +from typing import Any, Sequence def symtable(code: str, filename: str, compile_type: str) -> SymbolTable: ... -class SymbolTable(object): +class SymbolTable: def __init__(self, raw_table: Any, filename: str) -> None: ... def get_type(self) -> str: ... def get_id(self) -> int: ... @@ -19,19 +19,22 @@ class SymbolTable(object): def get_children(self) -> list[SymbolTable]: ... class Function(SymbolTable): - def get_parameters(self) -> Tuple[str, ...]: ... - def get_locals(self) -> Tuple[str, ...]: ... - def get_globals(self) -> Tuple[str, ...]: ... - def get_frees(self) -> Tuple[str, ...]: ... + def get_parameters(self) -> tuple[str, ...]: ... + def get_locals(self) -> tuple[str, ...]: ... + def get_globals(self) -> tuple[str, ...]: ... + def get_frees(self) -> tuple[str, ...]: ... + if sys.version_info >= (3, 8): + def get_nonlocals(self) -> tuple[str, ...]: ... class Class(SymbolTable): - def get_methods(self) -> Tuple[str, ...]: ... + def get_methods(self) -> tuple[str, ...]: ... -class Symbol(object): +class Symbol: if sys.version_info >= (3, 8): def __init__( self, name: str, flags: int, namespaces: Sequence[SymbolTable] | None = ..., *, module_scope: bool = ... ) -> None: ... + def is_nonlocal(self) -> bool: ... else: def __init__(self, name: str, flags: int, namespaces: Sequence[SymbolTable] | None = ...) -> None: ... def get_name(self) -> str: ... @@ -48,7 +51,7 @@ class Symbol(object): def get_namespaces(self) -> Sequence[SymbolTable]: ... def get_namespace(self) -> SymbolTable: ... -class SymbolTableFactory(object): +class SymbolTableFactory: def __init__(self) -> None: ... def new(self, table: Any, filename: str) -> SymbolTable: ... def __call__(self, table: Any, filename: str) -> SymbolTable: ... diff --git a/mypy/typeshed/stdlib/sys.pyi b/mypy/typeshed/stdlib/sys.pyi index 274e4b90fd6e..cb1545711d69 100644 --- a/mypy/typeshed/stdlib/sys.pyi +++ b/mypy/typeshed/stdlib/sys.pyi @@ -1,31 +1,18 @@ import sys +from _typeshed import structseq from builtins import object as _object from importlib.abc import PathEntryFinder from importlib.machinery import ModuleSpec from io import TextIOWrapper from types import FrameType, ModuleType, TracebackType -from typing import ( - Any, - AsyncGenerator, - Callable, - NoReturn, - Optional, - Protocol, - Sequence, - TextIO, - Tuple, - Type, - TypeVar, - Union, - overload, -) -from typing_extensions import Literal +from typing import Any, AsyncGenerator, Callable, NoReturn, Optional, Protocol, Sequence, TextIO, Type, TypeVar, Union, overload +from typing_extensions import Literal, final _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]] +_ExcInfo = tuple[Type[BaseException], BaseException, TracebackType] +_OptExcInfo = Union[_ExcInfo, tuple[None, None, None]] # Intentionally omits one deprecated and one optional method of `importlib.abc.MetaPathFinder` class _MetaPathFinder(Protocol): @@ -146,12 +133,18 @@ class _int_info: bits_per_digit: int sizeof_digit: int -class _version_info(Tuple[int, int, int, str, int]): - major: int - minor: int - micro: int - releaselevel: str - serial: int +@final +class _version_info(structseq[Any | int], tuple[int, int, int, str, int]): + @property + def major(self) -> int: ... + @property + def minor(self) -> int: ... + @property + def micro(self) -> int: ... + @property + def releaselevel(self) -> str: ... + @property + def serial(self) -> int: ... version_info: _version_info @@ -161,7 +154,7 @@ def _current_frames() -> dict[int, FrameType]: ... def _getframe(__depth: int = ...) -> FrameType: ... def _debugmallocstats() -> None: ... def __displayhook__(value: object) -> None: ... -def __excepthook__(type_: Type[BaseException], value: BaseException, traceback: TracebackType) -> None: ... +def __excepthook__(type_: Type[BaseException], value: BaseException, traceback: TracebackType | None) -> None: ... def exc_info() -> _OptExcInfo: ... # sys.exit() accepts an optional argument of anything printable @@ -192,7 +185,7 @@ _TraceFunc = Callable[[FrameType, str, Any], Optional[Callable[[FrameType, str, def gettrace() -> _TraceFunc | None: ... def settrace(tracefunc: _TraceFunc | None) -> None: ... -class _WinVersion(Tuple[int, int, int, int, str, int, int, int, int, Tuple[int, int, int]]): +class _WinVersion(tuple[int, int, int, int, str, int, int, int, int, tuple[int, int, int]]): major: int minor: int build: int @@ -234,12 +227,12 @@ if sys.version_info >= (3, 8): err_msg: str | None object: _object | None unraisablehook: Callable[[UnraisableHookArgs], Any] - def addaudithook(hook: Callable[[str, Tuple[Any, ...]], Any]) -> None: ... + def addaudithook(hook: Callable[[str, tuple[Any, ...]], Any]) -> None: ... def audit(__event: str, *args: Any) -> None: ... _AsyncgenHook = Optional[Callable[[AsyncGenerator[Any, Any]], None]] -class _asyncgen_hooks(Tuple[_AsyncgenHook, _AsyncgenHook]): +class _asyncgen_hooks(tuple[_AsyncgenHook, _AsyncgenHook]): firstiter: _AsyncgenHook finalizer: _AsyncgenHook diff --git a/mypy/typeshed/stdlib/sysconfig.pyi b/mypy/typeshed/stdlib/sysconfig.pyi index ff828d519912..17077144f6e9 100644 --- a/mypy/typeshed/stdlib/sysconfig.pyi +++ b/mypy/typeshed/stdlib/sysconfig.pyi @@ -1,12 +1,12 @@ -from typing import IO, Any, Tuple, overload +from typing import IO, Any, overload def get_config_var(name: str) -> str | None: ... @overload def get_config_vars() -> dict[str, Any]: ... @overload def get_config_vars(arg: str, *args: str) -> list[Any]: ... -def get_scheme_names() -> Tuple[str, ...]: ... -def get_path_names() -> Tuple[str, ...]: ... +def get_scheme_names() -> tuple[str, ...]: ... +def get_path_names() -> tuple[str, ...]: ... def get_path(name: str, scheme: str = ..., vars: dict[str, Any] | None = ..., expand: bool = ...) -> str: ... def get_paths(scheme: str = ..., vars: dict[str, Any] | None = ..., expand: bool = ...) -> dict[str, str]: ... def get_python_version() -> str: ... diff --git a/mypy/typeshed/stdlib/syslog.pyi b/mypy/typeshed/stdlib/syslog.pyi index 49169f40db5c..cfa8df887c1b 100644 --- a/mypy/typeshed/stdlib/syslog.pyi +++ b/mypy/typeshed/stdlib/syslog.pyi @@ -1,43 +1,47 @@ +import sys from typing import overload +from typing_extensions import Literal -LOG_ALERT: int -LOG_AUTH: int -LOG_CONS: int -LOG_CRIT: int -LOG_CRON: int -LOG_DAEMON: int -LOG_DEBUG: int -LOG_EMERG: int -LOG_ERR: int -LOG_INFO: int -LOG_KERN: int -LOG_LOCAL0: int -LOG_LOCAL1: int -LOG_LOCAL2: int -LOG_LOCAL3: int -LOG_LOCAL4: int -LOG_LOCAL5: int -LOG_LOCAL6: int -LOG_LOCAL7: int -LOG_LPR: int -LOG_MAIL: int -LOG_NDELAY: int -LOG_NEWS: int -LOG_NOTICE: int -LOG_NOWAIT: int -LOG_PERROR: int -LOG_PID: int -LOG_SYSLOG: int -LOG_USER: int -LOG_UUCP: int -LOG_WARNING: int - -def LOG_MASK(a: int) -> int: ... -def LOG_UPTO(a: int) -> int: ... -def closelog() -> None: ... -def openlog(ident: str = ..., logoption: int = ..., facility: int = ...) -> None: ... -def setlogmask(x: int) -> int: ... -@overload -def syslog(priority: int, message: str) -> None: ... -@overload -def syslog(message: str) -> None: ... +if sys.platform != "win32": + LOG_ALERT: Literal[1] + LOG_AUTH: Literal[32] + LOG_AUTHPRIV: Literal[80] + LOG_CONS: Literal[2] + LOG_CRIT: Literal[2] + LOG_CRON: Literal[72] + LOG_DAEMON: Literal[24] + LOG_DEBUG: Literal[7] + LOG_EMERG: Literal[0] + LOG_ERR: Literal[3] + LOG_INFO: Literal[6] + LOG_KERN: Literal[0] + LOG_LOCAL0: Literal[128] + LOG_LOCAL1: Literal[136] + LOG_LOCAL2: Literal[144] + LOG_LOCAL3: Literal[152] + LOG_LOCAL4: Literal[160] + LOG_LOCAL5: Literal[168] + LOG_LOCAL6: Literal[176] + LOG_LOCAL7: Literal[184] + LOG_LPR: Literal[48] + LOG_MAIL: Literal[16] + LOG_NDELAY: Literal[8] + LOG_NEWS: Literal[56] + LOG_NOTICE: Literal[5] + LOG_NOWAIT: Literal[16] + LOG_ODELAY: Literal[4] + LOG_PERROR: Literal[32] + LOG_PID: Literal[1] + LOG_SYSLOG: Literal[40] + LOG_USER: Literal[8] + LOG_UUCP: Literal[64] + LOG_WARNING: Literal[4] + def LOG_MASK(a: int) -> int: ... + def LOG_UPTO(a: int) -> int: ... + def closelog() -> None: ... + def openlog(ident: str = ..., logoption: int = ..., facility: int = ...) -> None: ... + def setlogmask(x: int) -> int: ... + @overload + def syslog(priority: int, message: str) -> None: ... + @overload + def syslog(message: str) -> None: ... diff --git a/mypy/typeshed/stdlib/tarfile.pyi b/mypy/typeshed/stdlib/tarfile.pyi index 0134316d8107..4931a6f0e679 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, Tuple, Type, TypeVar, overload +from typing import IO, Protocol, Type, TypeVar, overload from typing_extensions import Literal _TF = TypeVar("_TF", bound=TarFile) @@ -62,10 +62,10 @@ DEFAULT_FORMAT: int # tarfile constants -SUPPORTED_TYPES: Tuple[bytes, ...] -REGULAR_TYPES: Tuple[bytes, ...] -GNU_TYPES: Tuple[bytes, ...] -PAX_FIELDS: Tuple[str, ...] +SUPPORTED_TYPES: tuple[bytes, ...] +REGULAR_TYPES: tuple[bytes, ...] +GNU_TYPES: tuple[bytes, ...] +PAX_FIELDS: tuple[str, ...] PAX_NUMBER_FIELDS: dict[str, type] PAX_NAME_FIELDS: set[str] diff --git a/mypy/typeshed/stdlib/tempfile.pyi b/mypy/typeshed/stdlib/tempfile.pyi index 119c111bc4e1..4aec26175a48 100644 --- a/mypy/typeshed/stdlib/tempfile.pyi +++ b/mypy/typeshed/stdlib/tempfile.pyi @@ -2,7 +2,7 @@ import os import sys from _typeshed import Self from types import TracebackType -from typing import IO, Any, AnyStr, Generic, Iterable, Iterator, Tuple, Type, Union, overload +from typing import IO, Any, AnyStr, Generic, Iterable, Iterator, Type, Union, overload from typing_extensions import Literal if sys.version_info >= (3, 9): @@ -206,7 +206,7 @@ class SpooledTemporaryFile(IO[AnyStr]): @property def encoding(self) -> str: ... # undocumented @property - def newlines(self) -> str | Tuple[str, ...] | None: ... # undocumented + def newlines(self) -> str | tuple[str, ...] | None: ... # undocumented # bytes needs to go first, as default mode is to open as bytes if sys.version_info >= (3, 8): @overload diff --git a/mypy/typeshed/stdlib/termios.pyi b/mypy/typeshed/stdlib/termios.pyi index ed8522dccc51..7142df15715d 100644 --- a/mypy/typeshed/stdlib/termios.pyi +++ b/mypy/typeshed/stdlib/termios.pyi @@ -1,246 +1,246 @@ +import sys from _typeshed import FileDescriptorLike -from typing import Any, List, Union +from typing import Any, Union -_Attr = List[Union[int, List[Union[bytes, int]]]] +if sys.platform != "win32": + _Attr = list[Union[int, list[Union[bytes, int]]]] -# TODO constants not really documented -B0: int -B1000000: int -B110: int -B115200: int -B1152000: int -B1200: int -B134: int -B150: int -B1500000: int -B1800: int -B19200: int -B200: int -B2000000: int -B230400: int -B2400: int -B2500000: int -B300: int -B3000000: int -B3500000: int -B38400: int -B4000000: int -B460800: int -B4800: int -B50: int -B500000: int -B57600: int -B576000: int -B600: int -B75: int -B921600: int -B9600: int -BRKINT: int -BS0: int -BS1: int -BSDLY: int -CBAUD: int -CBAUDEX: int -CDSUSP: int -CEOF: int -CEOL: int -CEOT: int -CERASE: int -CFLUSH: int -CIBAUD: int -CINTR: int -CKILL: int -CLNEXT: int -CLOCAL: int -CQUIT: int -CR0: int -CR1: int -CR2: int -CR3: int -CRDLY: int -CREAD: int -CRPRNT: int -CRTSCTS: int -CS5: int -CS6: int -CS7: int -CS8: int -CSIZE: int -CSTART: int -CSTOP: int -CSTOPB: int -CSUSP: int -CWERASE: int -ECHO: int -ECHOCTL: int -ECHOE: int -ECHOK: int -ECHOKE: int -ECHONL: int -ECHOPRT: int -EXTA: int -EXTB: int -FF0: int -FF1: int -FFDLY: int -FIOASYNC: int -FIOCLEX: int -FIONBIO: int -FIONCLEX: int -FIONREAD: int -FLUSHO: int -HUPCL: int -ICANON: int -ICRNL: int -IEXTEN: int -IGNBRK: int -IGNCR: int -IGNPAR: int -IMAXBEL: int -INLCR: int -INPCK: int -IOCSIZE_MASK: int -IOCSIZE_SHIFT: int -ISIG: int -ISTRIP: int -IUCLC: int -IXANY: int -IXOFF: int -IXON: int -NCC: int -NCCS: int -NL0: int -NL1: int -NLDLY: int -NOFLSH: int -N_MOUSE: int -N_PPP: int -N_SLIP: int -N_STRIP: int -N_TTY: int -OCRNL: int -OFDEL: int -OFILL: int -OLCUC: int -ONLCR: int -ONLRET: int -ONOCR: int -OPOST: int -PARENB: int -PARMRK: int -PARODD: int -PENDIN: int -TAB0: int -TAB1: int -TAB2: int -TAB3: int -TABDLY: int -TCFLSH: int -TCGETA: int -TCGETS: int -TCIFLUSH: int -TCIOFF: int -TCIOFLUSH: int -TCION: int -TCOFLUSH: int -TCOOFF: int -TCOON: int -TCSADRAIN: int -TCSAFLUSH: int -TCSANOW: int -TCSBRK: int -TCSBRKP: int -TCSETA: int -TCSETAF: int -TCSETAW: int -TCSETS: int -TCSETSF: int -TCSETSW: int -TCXONC: int -TIOCCONS: int -TIOCEXCL: int -TIOCGETD: int -TIOCGICOUNT: int -TIOCGLCKTRMIOS: int -TIOCGPGRP: int -TIOCGSERIAL: int -TIOCGSOFTCAR: int -TIOCGWINSZ: int -TIOCINQ: int -TIOCLINUX: int -TIOCMBIC: int -TIOCMBIS: int -TIOCMGET: int -TIOCMIWAIT: int -TIOCMSET: int -TIOCM_CAR: int -TIOCM_CD: int -TIOCM_CTS: int -TIOCM_DSR: int -TIOCM_DTR: int -TIOCM_LE: int -TIOCM_RI: int -TIOCM_RNG: int -TIOCM_RTS: int -TIOCM_SR: int -TIOCM_ST: int -TIOCNOTTY: int -TIOCNXCL: int -TIOCOUTQ: int -TIOCPKT: int -TIOCPKT_DATA: int -TIOCPKT_DOSTOP: int -TIOCPKT_FLUSHREAD: int -TIOCPKT_FLUSHWRITE: int -TIOCPKT_NOSTOP: int -TIOCPKT_START: int -TIOCPKT_STOP: int -TIOCSCTTY: int -TIOCSERCONFIG: int -TIOCSERGETLSR: int -TIOCSERGETMULTI: int -TIOCSERGSTRUCT: int -TIOCSERGWILD: int -TIOCSERSETMULTI: int -TIOCSERSWILD: int -TIOCSER_TEMT: int -TIOCSETD: int -TIOCSLCKTRMIOS: int -TIOCSPGRP: int -TIOCSSERIAL: int -TIOCSSOFTCAR: int -TIOCSTI: int -TIOCSWINSZ: int -TOSTOP: int -VDISCARD: int -VEOF: int -VEOL: int -VEOL2: int -VERASE: int -VINTR: int -VKILL: int -VLNEXT: int -VMIN: int -VQUIT: int -VREPRINT: int -VSTART: int -VSTOP: int -VSUSP: int -VSWTC: int -VSWTCH: int -VT0: int -VT1: int -VTDLY: int -VTIME: int -VWERASE: int -XCASE: int -XTABS: int - -def tcgetattr(__fd: FileDescriptorLike) -> list[Any]: ... -def tcsetattr(__fd: FileDescriptorLike, __when: int, __attributes: _Attr) -> None: ... -def tcsendbreak(__fd: FileDescriptorLike, __duration: int) -> None: ... -def tcdrain(__fd: FileDescriptorLike) -> None: ... -def tcflush(__fd: FileDescriptorLike, __queue: int) -> None: ... -def tcflow(__fd: FileDescriptorLike, __action: int) -> None: ... - -class error(Exception): ... + # TODO constants not really documented + B0: int + B1000000: int + B110: int + B115200: int + B1152000: int + B1200: int + B134: int + B150: int + B1500000: int + B1800: int + B19200: int + B200: int + B2000000: int + B230400: int + B2400: int + B2500000: int + B300: int + B3000000: int + B3500000: int + B38400: int + B4000000: int + B460800: int + B4800: int + B50: int + B500000: int + B57600: int + B576000: int + B600: int + B75: int + B921600: int + B9600: int + BRKINT: int + BS0: int + BS1: int + BSDLY: int + CBAUD: int + CBAUDEX: int + CDSUSP: int + CEOF: int + CEOL: int + CEOT: int + CERASE: int + CFLUSH: int + CIBAUD: int + CINTR: int + CKILL: int + CLNEXT: int + CLOCAL: int + CQUIT: int + CR0: int + CR1: int + CR2: int + CR3: int + CRDLY: int + CREAD: int + CRPRNT: int + CRTSCTS: int + CS5: int + CS6: int + CS7: int + CS8: int + CSIZE: int + CSTART: int + CSTOP: int + CSTOPB: int + CSUSP: int + CWERASE: int + ECHO: int + ECHOCTL: int + ECHOE: int + ECHOK: int + ECHOKE: int + ECHONL: int + ECHOPRT: int + EXTA: int + EXTB: int + FF0: int + FF1: int + FFDLY: int + FIOASYNC: int + FIOCLEX: int + FIONBIO: int + FIONCLEX: int + FIONREAD: int + FLUSHO: int + HUPCL: int + ICANON: int + ICRNL: int + IEXTEN: int + IGNBRK: int + IGNCR: int + IGNPAR: int + IMAXBEL: int + INLCR: int + INPCK: int + IOCSIZE_MASK: int + IOCSIZE_SHIFT: int + ISIG: int + ISTRIP: int + IUCLC: int + IXANY: int + IXOFF: int + IXON: int + NCC: int + NCCS: int + NL0: int + NL1: int + NLDLY: int + NOFLSH: int + N_MOUSE: int + N_PPP: int + N_SLIP: int + N_STRIP: int + N_TTY: int + OCRNL: int + OFDEL: int + OFILL: int + OLCUC: int + ONLCR: int + ONLRET: int + ONOCR: int + OPOST: int + PARENB: int + PARMRK: int + PARODD: int + PENDIN: int + TAB0: int + TAB1: int + TAB2: int + TAB3: int + TABDLY: int + TCFLSH: int + TCGETA: int + TCGETS: int + TCIFLUSH: int + TCIOFF: int + TCIOFLUSH: int + TCION: int + TCOFLUSH: int + TCOOFF: int + TCOON: int + TCSADRAIN: int + TCSAFLUSH: int + TCSANOW: int + TCSBRK: int + TCSBRKP: int + TCSETA: int + TCSETAF: int + TCSETAW: int + TCSETS: int + TCSETSF: int + TCSETSW: int + TCXONC: int + TIOCCONS: int + TIOCEXCL: int + TIOCGETD: int + TIOCGICOUNT: int + TIOCGLCKTRMIOS: int + TIOCGPGRP: int + TIOCGSERIAL: int + TIOCGSOFTCAR: int + TIOCGWINSZ: int + TIOCINQ: int + TIOCLINUX: int + TIOCMBIC: int + TIOCMBIS: int + TIOCMGET: int + TIOCMIWAIT: int + TIOCMSET: int + TIOCM_CAR: int + TIOCM_CD: int + TIOCM_CTS: int + TIOCM_DSR: int + TIOCM_DTR: int + TIOCM_LE: int + TIOCM_RI: int + TIOCM_RNG: int + TIOCM_RTS: int + TIOCM_SR: int + TIOCM_ST: int + TIOCNOTTY: int + TIOCNXCL: int + TIOCOUTQ: int + TIOCPKT: int + TIOCPKT_DATA: int + TIOCPKT_DOSTOP: int + TIOCPKT_FLUSHREAD: int + TIOCPKT_FLUSHWRITE: int + TIOCPKT_NOSTOP: int + TIOCPKT_START: int + TIOCPKT_STOP: int + TIOCSCTTY: int + TIOCSERCONFIG: int + TIOCSERGETLSR: int + TIOCSERGETMULTI: int + TIOCSERGSTRUCT: int + TIOCSERGWILD: int + TIOCSERSETMULTI: int + TIOCSERSWILD: int + TIOCSER_TEMT: int + TIOCSETD: int + TIOCSLCKTRMIOS: int + TIOCSPGRP: int + TIOCSSERIAL: int + TIOCSSOFTCAR: int + TIOCSTI: int + TIOCSWINSZ: int + TOSTOP: int + VDISCARD: int + VEOF: int + VEOL: int + VEOL2: int + VERASE: int + VINTR: int + VKILL: int + VLNEXT: int + VMIN: int + VQUIT: int + VREPRINT: int + VSTART: int + VSTOP: int + VSUSP: int + VSWTC: int + VSWTCH: int + VT0: int + VT1: int + VTDLY: int + VTIME: int + VWERASE: int + XCASE: int + XTABS: int + def tcgetattr(__fd: FileDescriptorLike) -> list[Any]: ... + def tcsetattr(__fd: FileDescriptorLike, __when: int, __attributes: _Attr) -> None: ... + def tcsendbreak(__fd: FileDescriptorLike, __duration: int) -> None: ... + def tcdrain(__fd: FileDescriptorLike) -> None: ... + def tcflush(__fd: FileDescriptorLike, __queue: int) -> None: ... + def tcflow(__fd: FileDescriptorLike, __action: int) -> None: ... + class error(Exception): ... diff --git a/mypy/typeshed/stdlib/threading.pyi b/mypy/typeshed/stdlib/threading.pyi index 64998d86bf9f..3e91221baed2 100644 --- a/mypy/typeshed/stdlib/threading.pyi +++ b/mypy/typeshed/stdlib/threading.pyi @@ -11,8 +11,9 @@ _T = TypeVar("_T") __all__: list[str] def active_count() -> int: ... +def activeCount() -> int: ... # deprecated alias for active_count() def current_thread() -> Thread: ... -def currentThread() -> Thread: ... +def currentThread() -> Thread: ... # deprecated alias for current_thread() def get_ident() -> int: ... def enumerate() -> list[Thread]: ... def main_thread() -> Thread: ... @@ -22,13 +23,18 @@ if sys.version_info >= (3, 8): def settrace(func: _TF) -> None: ... def setprofile(func: _PF | None) -> None: ... + +if sys.version_info >= (3, 10): + def gettrace() -> _TF | None: ... + def getprofile() -> _PF | None: ... + def stack_size(size: int = ...) -> int: ... TIMEOUT_MAX: float class ThreadError(Exception): ... -class local(object): +class local: def __getattribute__(self, name: str) -> Any: ... def __setattr__(self, name: str, value: Any) -> None: ... def __delattr__(self, name: str) -> None: ... @@ -50,18 +56,20 @@ class Thread: def start(self) -> None: ... def run(self) -> None: ... def join(self, timeout: float | None = ...) -> None: ... - def getName(self) -> str: ... - def setName(self, name: str) -> None: ... if sys.version_info >= (3, 8): @property def native_id(self) -> int | None: ... # only available on some platforms def is_alive(self) -> bool: ... if sys.version_info < (3, 9): def isAlive(self) -> bool: ... + # the following methods are all deprecated + def getName(self) -> str: ... + def setName(self, name: str) -> None: ... def isDaemon(self) -> bool: ... def setDaemon(self, daemonic: bool) -> None: ... -class _DummyThread(Thread): ... +class _DummyThread(Thread): + def __init__(self) -> None: ... class Lock: def __init__(self) -> None: ... @@ -75,12 +83,12 @@ class Lock: class _RLock: def __init__(self) -> None: ... - def __enter__(self) -> bool: ... + def acquire(self, blocking: bool = ..., timeout: float = ...) -> bool: ... + def release(self) -> None: ... + __enter__ = acquire def __exit__( self, exc_type: Type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None ) -> bool | None: ... - def acquire(self, blocking: bool = ..., timeout: float = ...) -> bool: ... - def release(self) -> None: ... RLock = _RLock @@ -96,7 +104,7 @@ class Condition: def wait_for(self, predicate: Callable[[], _T], timeout: float | None = ...) -> _T: ... def notify(self, n: int = ...) -> None: ... def notify_all(self) -> None: ... - def notifyAll(self) -> None: ... + def notifyAll(self) -> None: ... # deprecated alias for notify_all() class Semaphore: def __init__(self, value: int = ...) -> None: ... @@ -115,6 +123,7 @@ class BoundedSemaphore(Semaphore): ... class Event: def __init__(self) -> None: ... def is_set(self) -> bool: ... + def isSet(self) -> bool: ... # deprecated alias for is_set() def set(self) -> None: ... def clear(self) -> None: ... def wait(self, timeout: float | None = ...) -> bool: ... diff --git a/mypy/typeshed/stdlib/time.pyi b/mypy/typeshed/stdlib/time.pyi index bf370d68e83d..6e23b331d1c8 100644 --- a/mypy/typeshed/stdlib/time.pyi +++ b/mypy/typeshed/stdlib/time.pyi @@ -1,9 +1,10 @@ import sys +from _typeshed import structseq from types import SimpleNamespace -from typing import Any, NamedTuple, Tuple +from typing import Any, Union from typing_extensions import final -_TimeTuple = Tuple[int, int, int, int, int, int, int, int, int] +_TimeTuple = tuple[int, int, int, int, int, int, int, int, int] altzone: int daylight: int @@ -32,39 +33,31 @@ if sys.version_info >= (3, 8) and sys.platform == "darwin": if sys.version_info >= (3, 9) and sys.platform == "linux": CLOCK_TAI: int -class _struct_time(NamedTuple): - tm_year: int - tm_mon: int - tm_mday: int - tm_hour: int - tm_min: int - tm_sec: int - tm_wday: int - tm_yday: int - tm_isdst: int +# Constructor takes an iterable of any type, of length between 9 and 11 elements. +# However, it always *behaves* like a tuple of 9 elements, +# even if an iterable with length >9 is passed. +# https://github.com/python/typeshed/pull/6560#discussion_r767162532 +@final +class struct_time(structseq[Union[Any, int]], _TimeTuple): @property - def n_fields(self) -> int: ... + def tm_year(self) -> int: ... @property - def n_sequence_fields(self) -> int: ... + def tm_mon(self) -> int: ... @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], - _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], - _arg: Any = ..., - ) -> struct_time: ... + def tm_mday(self) -> int: ... + @property + def tm_hour(self) -> int: ... + @property + def tm_min(self) -> int: ... + @property + def tm_sec(self) -> int: ... + @property + def tm_wday(self) -> int: ... + @property + def tm_yday(self) -> int: ... + @property + def tm_isdst(self) -> int: ... + # These final two properties only exist if a 10- or 11-item sequence was passed to the constructor. @property def tm_zone(self) -> str: ... @property diff --git a/mypy/typeshed/stdlib/tkinter/__init__.pyi b/mypy/typeshed/stdlib/tkinter/__init__.pyi index bda37b406fc3..50de97f48fdc 100644 --- a/mypy/typeshed/stdlib/tkinter/__init__.pyi +++ b/mypy/typeshed/stdlib/tkinter/__init__.pyi @@ -2,10 +2,10 @@ import _tkinter import sys from _typeshed import StrOrBytesPath from enum import Enum -from tkinter.constants import * # comment this out to find undefined identifier names with flake8 +from tkinter.constants import * from tkinter.font import _FontDescription from types import TracebackType -from typing import Any, Callable, Generic, List, Mapping, Optional, Protocol, Sequence, Tuple, Type, TypeVar, Union, overload +from typing import Any, Callable, Generic, Mapping, Optional, Protocol, Sequence, Type, TypeVar, Union, overload from typing_extensions import Literal, TypedDict # Using anything from tkinter.font in this file means that 'import tkinter' @@ -24,93 +24,46 @@ EXCEPTION = _tkinter.EXCEPTION # - Misc: any widget (don't use BaseWidget because Tk doesn't inherit from BaseWidget) # - Widget: anything that is meant to be put into another widget with e.g. pack or grid # -# Instructions for figuring out the correct type of each widget option: -# - See discussion on #4363. +# Don't trust tkinter's docstrings, because they have been created by copy/pasting from +# Tk's manual pages more than 10 years ago. Use the latest manual pages instead: # -# - Find the option from the manual page of the widget. Usually the manual -# page of a non-ttk widget has the same name as the tkinter class, in the -# 3tk section: +# $ sudo apt install tk-doc tcl-doc +# $ man 3tk label # tkinter.Label +# $ man 3tk ttk_label # tkinter.ttk.Label +# $ man 3tcl after # tkinter.Misc.after # -# $ sudo apt install tk-doc -# $ man 3tk label -# -# Ttk manual pages tend to have ttk_ prefixed names: -# -# $ man 3tk ttk_label -# -# Non-GUI things like the .after() method are often in the 3tcl section: -# -# $ sudo apt install tcl-doc -# $ man 3tcl after -# -# If you don't have man or apt, you can read these manual pages online: -# -# https://www.tcl.tk/doc/ -# -# Every option has '-' in front of its name in the manual page (and in Tcl). -# For example, there's an option named '-text' in the label manual page. -# -# - Tkinter has some options documented in docstrings, but don't rely on them. -# They aren't updated when a new version of Tk comes out, so the latest Tk -# manual pages (see above) are much more likely to actually contain all -# possible options. -# -# Also, reading tkinter's source code typically won't help much because it -# uses a lot of **kwargs and duck typing. Typically every argument goes into -# self.tk.call, which is _tkinter.TkappType.call, and the return value is -# whatever that returns. The type of that depends on how the Tcl interpreter -# represents the return value of the executed Tcl code. -# -# - If you think that int is an appropriate type for something, then you may -# actually want _ScreenUnits instead. -# -# - If you think that Callable[something] is an appropriate type for -# 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. +# You can also read the manual pages online: https://www.tcl.tk/doc/ # 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 _Bitmap = str # manual page: Tk_GetBitmap -_ButtonCommand = Union[str, Callable[[], Any]] # return value is returned from Button.invoke() +_ButtonCommand = Union[str, Callable[[], Any]] # accepts string of tcl code, return value is returned from Button.invoke() _CanvasItemId = int _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 +_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, List[str], Tuple[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() _Padding = Union[ _ScreenUnits, - Tuple[_ScreenUnits], - Tuple[_ScreenUnits, _ScreenUnits], - Tuple[_ScreenUnits, _ScreenUnits, _ScreenUnits], - Tuple[_ScreenUnits, _ScreenUnits, _ScreenUnits, _ScreenUnits], + tuple[_ScreenUnits], + tuple[_ScreenUnits, _ScreenUnits], + tuple[_ScreenUnits, _ScreenUnits, _ScreenUnits], + tuple[_ScreenUnits, _ScreenUnits, _ScreenUnits, _ScreenUnits], ] _Relief = Literal["raised", "sunken", "flat", "ridge", "solid", "groove"] # manual page: Tk_GetRelief -_ScreenUnits = Union[str, float] # manual page: Tk_GetPixels +_ScreenUnits = Union[str, float] # Often the right type instead of int. Manual page: Tk_GetPixels _XYScrollCommand = Union[str, Callable[[float, float], Any]] # -xscrollcommand and -yscrollcommand in 'options' manual page _TakeFocusValue = Union[int, Literal[""], Callable[[str], Optional[bool]]] # -takefocus in manual page named 'options' class EventType(str, Enum): Activate: str ButtonPress: str + Button = ButtonPress ButtonRelease: str Circulate: str CirculateRequest: str @@ -128,6 +81,7 @@ class EventType(str, Enum): GraphicsExpose: str Gravity: str KeyPress: str + Key = KeyPress KeyRelease: str Keymap: str Leave: str @@ -183,7 +137,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 @@ -295,7 +249,7 @@ class Misc: def winfo_geometry(self) -> str: ... def winfo_height(self) -> int: ... def winfo_id(self) -> int: ... - def winfo_interps(self, displayof: Literal[0] | Misc | None = ...) -> Tuple[str, ...]: ... + def winfo_interps(self, displayof: Literal[0] | Misc | None = ...) -> tuple[str, ...]: ... def winfo_ismapped(self) -> bool: ... def winfo_manager(self) -> str: ... def winfo_name(self) -> str: ... @@ -466,9 +420,9 @@ class Misc: x: _ScreenUnits = ..., y: _ScreenUnits = ..., ) -> None: ... - def event_info(self, virtual: str | None = ...) -> Tuple[str, ...]: ... - def image_names(self) -> Tuple[str, ...]: ... - def image_types(self) -> Tuple[str, ...]: ... + def event_info(self, virtual: str | None = ...) -> tuple[str, ...]: ... + def image_names(self) -> tuple[str, ...]: ... + def image_types(self) -> tuple[str, ...]: ... # See #4363 and #4891 def __setitem__(self, key: str, value: Any) -> None: ... def __getitem__(self, key: str) -> Any: ... @@ -514,7 +468,7 @@ class Wm: ) -> tuple[int, int, int, int] | None: ... aspect = wm_aspect @overload - def wm_attributes(self) -> Tuple[Any, ...]: ... + def wm_attributes(self) -> tuple[Any, ...]: ... @overload def wm_attributes(self, __option: str) -> Any: ... @overload @@ -525,7 +479,7 @@ class Wm: @overload def wm_colormapwindows(self) -> list[Misc]: ... @overload - def wm_colormapwindows(self, __wlist: list[Misc] | Tuple[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 @@ -589,7 +543,7 @@ class Wm: @overload def wm_protocol(self, name: str, func: None = ...) -> str: ... @overload - def wm_protocol(self, name: None = ..., func: None = ...) -> Tuple[str, ...]: ... + 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]: ... @@ -688,7 +642,8 @@ class Tk(Misc, Wm): quit: Any record: Any setvar: Any - split: Any + if sys.version_info < (3, 11): + split: Any splitlist: Any unsetvar: Any wantobjects: Any @@ -739,14 +694,6 @@ class Pack: pack = pack_configure forget = pack_forget propagate = Misc.pack_propagate - # commented out to avoid mypy getting confused with multiple - # inheritance and how things get overridden with different things - # info = pack_info - # pack_propagate = Misc.pack_propagate - # configure = pack_configure - # config = pack_configure - # slaves = Misc.pack_slaves - # pack_slaves = Misc.pack_slaves class _PlaceInfo(_InMiscNonTotal): # empty dict if widget hasn't been placed anchor: _Anchor @@ -783,13 +730,6 @@ class Place: def place_info(self) -> _PlaceInfo: ... place = place_configure info = place_info - # commented out to avoid mypy getting confused with multiple - # inheritance and how things get overridden with different things - # config = place_configure - # configure = place_configure - # forget = place_forget - # slaves = Misc.place_slaves - # place_slaves = Misc.place_slaves class _GridInfo(_InMiscNonTotal): # empty dict if widget hasn't been gridded column: int @@ -825,24 +765,6 @@ class Grid: grid = grid_configure location = Misc.grid_location size = Misc.grid_size - # commented out to avoid mypy getting confused with multiple - # inheritance and how things get overridden with different things - # bbox = Misc.grid_bbox - # grid_bbox = Misc.grid_bbox - # forget = grid_forget - # info = grid_info - # grid_location = Misc.grid_location - # grid_propagate = Misc.grid_propagate - # grid_size = Misc.grid_size - # rowconfigure = Misc.grid_rowconfigure - # grid_rowconfigure = Misc.grid_rowconfigure - # grid_columnconfigure = Misc.grid_columnconfigure - # columnconfigure = Misc.grid_columnconfigure - # config = grid_configure - # configure = grid_configure - # propagate = Misc.grid_propagate - # slaves = Misc.grid_slaves - # grid_slaves = Misc.grid_slaves class BaseWidget(Misc): master: Misc @@ -1121,21 +1043,19 @@ class Canvas(Widget, XView, YView): def addtag_overlapping(self, newtag: str, x1: _ScreenUnits, y1: _ScreenUnits, x2: _ScreenUnits, y2: _ScreenUnits) -> None: ... def addtag_withtag(self, newtag: str, tagOrId: str | _CanvasItemId) -> None: ... def find(self, *args): ... # internal method - def find_above(self, tagOrId: str | _CanvasItemId) -> Tuple[_CanvasItemId, ...]: ... - def find_all(self) -> Tuple[_CanvasItemId, ...]: ... - def find_below(self, tagOrId: str | _CanvasItemId) -> Tuple[_CanvasItemId, ...]: ... + def find_above(self, tagOrId: str | _CanvasItemId) -> tuple[_CanvasItemId, ...]: ... + def find_all(self) -> tuple[_CanvasItemId, ...]: ... + def find_below(self, tagOrId: str | _CanvasItemId) -> tuple[_CanvasItemId, ...]: ... def find_closest( self, x: _ScreenUnits, y: _ScreenUnits, halo: _ScreenUnits | None = ..., start: str | _CanvasItemId | None = ... - ) -> Tuple[_CanvasItemId, ...]: ... + ) -> tuple[_CanvasItemId, ...]: ... def find_enclosed( self, x1: _ScreenUnits, y1: _ScreenUnits, x2: _ScreenUnits, y2: _ScreenUnits - ) -> Tuple[_CanvasItemId, ...]: ... - def find_overlapping(self, x1: _ScreenUnits, y1: _ScreenUnits, x2: _ScreenUnits, y2: float) -> Tuple[_CanvasItemId, ...]: ... - def find_withtag(self, tagOrId: str | _CanvasItemId) -> Tuple[_CanvasItemId, ...]: ... - # 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 + ) -> tuple[_CanvasItemId, ...]: ... + def find_overlapping(self, x1: _ScreenUnits, y1: _ScreenUnits, x2: _ScreenUnits, y2: float) -> tuple[_CanvasItemId, ...]: ... + def find_withtag(self, tagOrId: str | _CanvasItemId) -> tuple[_CanvasItemId, ...]: ... + # Incompatible with Misc.bbox(), tkinter violates LSP + def bbox(self, *args: str | _CanvasItemId) -> tuple[int, int, int, int]: ... # type: ignore[override] @overload def tag_bind( self, @@ -1156,7 +1076,7 @@ class Canvas(Widget, XView, YView): @overload def coords(self) -> list[float]: ... @overload - def coords(self, __args: list[int] | list[float] | Tuple[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. @@ -1172,16 +1092,16 @@ class Canvas(Widget, XView, YView): __x1: float, __y1: float, *, - activedash: str | list[int] | Tuple[int, ...] = ..., + activedash: str | list[int] | tuple[int, ...] = ..., activefill: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., arrow: Literal["first", "last", "both"] = ..., arrowshape: tuple[float, float, float] = ..., capstyle: Literal["round", "projecting", "butt"] = ..., - dash: str | list[int] | Tuple[int, ...] = ..., + dash: str | list[int] | tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | list[int] | Tuple[int, ...] = ..., + disableddash: str | list[int] | tuple[int, ...] = ..., disabledfill: _Color = ..., disabledstipple: _Bitmap = ..., disabledwidth: _ScreenUnits = ..., @@ -1192,7 +1112,7 @@ class Canvas(Widget, XView, YView): splinesteps: float = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | list[str] | Tuple[str, ...] = ..., + tags: str | list[str] | tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1200,16 +1120,16 @@ class Canvas(Widget, XView, YView): self, __coords: tuple[float, float, float, float] | list[int] | list[float], *, - activedash: str | list[int] | Tuple[int, ...] = ..., + activedash: str | list[int] | tuple[int, ...] = ..., activefill: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., arrow: Literal["first", "last", "both"] = ..., arrowshape: tuple[float, float, float] = ..., capstyle: Literal["round", "projecting", "butt"] = ..., - dash: str | list[int] | Tuple[int, ...] = ..., + dash: str | list[int] | tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | list[int] | Tuple[int, ...] = ..., + disableddash: str | list[int] | tuple[int, ...] = ..., disabledfill: _Color = ..., disabledstipple: _Bitmap = ..., disabledwidth: _ScreenUnits = ..., @@ -1220,7 +1140,7 @@ class Canvas(Widget, XView, YView): splinesteps: float = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | list[str] | Tuple[str, ...] = ..., + tags: str | list[str] | tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1231,15 +1151,15 @@ class Canvas(Widget, XView, YView): __x1: float, __y1: float, *, - activedash: str | list[int] | Tuple[int, ...] = ..., + activedash: str | list[int] | tuple[int, ...] = ..., activefill: _Color = ..., activeoutline: _Color = ..., activeoutlinestipple: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., - dash: str | list[int] | Tuple[int, ...] = ..., + dash: str | list[int] | tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | list[int] | Tuple[int, ...] = ..., + disableddash: str | list[int] | tuple[int, ...] = ..., disabledfill: _Color = ..., disabledoutline: _Color = ..., disabledoutlinestipple: _Color = ..., @@ -1252,7 +1172,7 @@ class Canvas(Widget, XView, YView): outlinestipple: _Bitmap = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | list[str] | Tuple[str, ...] = ..., + tags: str | list[str] | tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1260,15 +1180,15 @@ class Canvas(Widget, XView, YView): self, __coords: tuple[float, float, float, float] | list[int] | list[float], *, - activedash: str | list[int] | Tuple[int, ...] = ..., + activedash: str | list[int] | tuple[int, ...] = ..., activefill: _Color = ..., activeoutline: _Color = ..., activeoutlinestipple: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., - dash: str | list[int] | Tuple[int, ...] = ..., + dash: str | list[int] | tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | list[int] | Tuple[int, ...] = ..., + disableddash: str | list[int] | tuple[int, ...] = ..., disabledfill: _Color = ..., disabledoutline: _Color = ..., disabledoutlinestipple: _Color = ..., @@ -1281,7 +1201,7 @@ class Canvas(Widget, XView, YView): outlinestipple: _Bitmap = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | list[str] | Tuple[str, ...] = ..., + tags: str | list[str] | tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1292,15 +1212,15 @@ class Canvas(Widget, XView, YView): __x1: float, __y1: float, *xy_pairs: float, - activedash: str | list[int] | Tuple[int, ...] = ..., + activedash: str | list[int] | tuple[int, ...] = ..., activefill: _Color = ..., activeoutline: _Color = ..., activeoutlinestipple: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., - dash: str | list[int] | Tuple[int, ...] = ..., + dash: str | list[int] | tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | list[int] | Tuple[int, ...] = ..., + disableddash: str | list[int] | tuple[int, ...] = ..., disabledfill: _Color = ..., disabledoutline: _Color = ..., disabledoutlinestipple: _Color = ..., @@ -1316,23 +1236,23 @@ class Canvas(Widget, XView, YView): splinesteps: float = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | list[str] | Tuple[str, ...] = ..., + tags: str | list[str] | tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload def create_polygon( self, - __coords: Tuple[float, ...] | list[int] | list[float], + __coords: tuple[float, ...] | list[int] | list[float], *, - activedash: str | list[int] | Tuple[int, ...] = ..., + activedash: str | list[int] | tuple[int, ...] = ..., activefill: _Color = ..., activeoutline: _Color = ..., activeoutlinestipple: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., - dash: str | list[int] | Tuple[int, ...] = ..., + dash: str | list[int] | tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | list[int] | Tuple[int, ...] = ..., + disableddash: str | list[int] | tuple[int, ...] = ..., disabledfill: _Color = ..., disabledoutline: _Color = ..., disabledoutlinestipple: _Color = ..., @@ -1348,7 +1268,7 @@ class Canvas(Widget, XView, YView): splinesteps: float = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | list[str] | Tuple[str, ...] = ..., + tags: str | list[str] | tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1359,15 +1279,15 @@ class Canvas(Widget, XView, YView): __x1: float, __y1: float, *, - activedash: str | list[int] | Tuple[int, ...] = ..., + activedash: str | list[int] | tuple[int, ...] = ..., activefill: _Color = ..., activeoutline: _Color = ..., activeoutlinestipple: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., - dash: str | list[int] | Tuple[int, ...] = ..., + dash: str | list[int] | tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | list[int] | Tuple[int, ...] = ..., + disableddash: str | list[int] | tuple[int, ...] = ..., disabledfill: _Color = ..., disabledoutline: _Color = ..., disabledoutlinestipple: _Color = ..., @@ -1380,7 +1300,7 @@ class Canvas(Widget, XView, YView): outlinestipple: _Bitmap = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | list[str] | Tuple[str, ...] = ..., + tags: str | list[str] | tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1388,15 +1308,15 @@ class Canvas(Widget, XView, YView): self, __coords: tuple[float, float, float, float] | list[int] | list[float], *, - activedash: str | list[int] | Tuple[int, ...] = ..., + activedash: str | list[int] | tuple[int, ...] = ..., activefill: _Color = ..., activeoutline: _Color = ..., activeoutlinestipple: _Color = ..., activestipple: str = ..., activewidth: _ScreenUnits = ..., - dash: str | list[int] | Tuple[int, ...] = ..., + dash: str | list[int] | tuple[int, ...] = ..., dashoffset: _ScreenUnits = ..., - disableddash: str | list[int] | Tuple[int, ...] = ..., + disableddash: str | list[int] | tuple[int, ...] = ..., disabledfill: _Color = ..., disabledoutline: _Color = ..., disabledoutlinestipple: _Color = ..., @@ -1409,7 +1329,7 @@ class Canvas(Widget, XView, YView): outlinestipple: _Bitmap = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | list[str] | Tuple[str, ...] = ..., + tags: str | list[str] | tuple[str, ...] = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @overload @@ -1429,7 +1349,7 @@ class Canvas(Widget, XView, YView): offset: _ScreenUnits = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | list[str] | Tuple[str, ...] = ..., + tags: str | list[str] | tuple[str, ...] = ..., text: float | str = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @@ -1449,7 +1369,7 @@ class Canvas(Widget, XView, YView): offset: _ScreenUnits = ..., state: Literal["normal", "active", "disabled"] = ..., stipple: _Bitmap = ..., - tags: str | list[str] | Tuple[str, ...] = ..., + tags: str | list[str] | tuple[str, ...] = ..., text: float | str = ..., width: _ScreenUnits = ..., ) -> _CanvasItemId: ... @@ -1462,7 +1382,7 @@ class Canvas(Widget, XView, YView): anchor: _Anchor = ..., height: _ScreenUnits = ..., state: Literal["normal", "active", "disabled"] = ..., - tags: str | list[str] | Tuple[str, ...] = ..., + tags: str | list[str] | tuple[str, ...] = ..., width: _ScreenUnits = ..., window: Widget = ..., ) -> _CanvasItemId: ... @@ -1474,7 +1394,7 @@ class Canvas(Widget, XView, YView): anchor: _Anchor = ..., height: _ScreenUnits = ..., state: Literal["normal", "active", "disabled"] = ..., - tags: str | list[str] | Tuple[str, ...] = ..., + tags: str | list[str] | tuple[str, ...] = ..., width: _ScreenUnits = ..., window: Widget = ..., ) -> _CanvasItemId: ... @@ -1485,7 +1405,7 @@ class Canvas(Widget, XView, YView): @overload def dtag(self, __id: _CanvasItemId, __tag_to_delete: str) -> None: ... def focus(self, *args): ... - def gettags(self, __tagOrId: str | _CanvasItemId) -> Tuple[str, ...]: ... + def gettags(self, __tagOrId: str | _CanvasItemId) -> tuple[str, ...]: ... def icursor(self, *args): ... def index(self, *args): ... def insert(self, *args): ... @@ -1505,10 +1425,10 @@ class Canvas(Widget, XView, YView): # # But mypy doesn't like aliasing here (maybe because Misc defines the same names) def tag_lower(self, __first: str | _CanvasItemId, __second: str | _CanvasItemId | None = ...) -> None: ... - def lower(self, __first: str | _CanvasItemId, __second: str | _CanvasItemId | None = ...) -> None: ... # type: ignore + def lower(self, __first: str | _CanvasItemId, __second: str | _CanvasItemId | None = ...) -> None: ... # type: ignore[override] def tag_raise(self, __first: str | _CanvasItemId, __second: str | _CanvasItemId | None = ...) -> None: ... - def tkraise(self, __first: str | _CanvasItemId, __second: str | _CanvasItemId | None = ...) -> None: ... # type: ignore - def lift(self, __first: str | _CanvasItemId, __second: str | _CanvasItemId | None = ...) -> None: ... # type: ignore + def tkraise(self, __first: str | _CanvasItemId, __second: str | _CanvasItemId | None = ...) -> None: ... # type: ignore[override] + def lift(self, __first: str | _CanvasItemId, __second: str | _CanvasItemId | None = ...) -> None: ... # type: ignore[override] def scale(self, *args): ... def scan_mark(self, x, y): ... def scan_dragto(self, x, y, gain: int = ...): ... @@ -1737,7 +1657,7 @@ class Entry(Widget, XView): def scan_mark(self, x): ... def scan_dragto(self, x): ... def selection_adjust(self, index: _EntryIndex) -> None: ... - def selection_clear(self) -> None: ... # type: ignore + def selection_clear(self) -> None: ... # type: ignore[override] def selection_from(self, index: _EntryIndex) -> None: ... def selection_present(self) -> bool: ... def selection_range(self, start: _EntryIndex, end: _EntryIndex) -> None: ... @@ -1760,9 +1680,9 @@ class Frame(Widget): bg: _Color = ..., border: _ScreenUnits = ..., borderwidth: _ScreenUnits = ..., - class_: str = ..., - colormap: Literal["new", ""] | Misc = ..., - container: bool = ..., + class_: str = ..., # can't be changed with configure() + colormap: Literal["new", ""] | Misc = ..., # can't be changed with configure() + container: bool = ..., # can't be changed with configure() cursor: _Cursor = ..., height: _ScreenUnits = ..., highlightbackground: _Color = ..., @@ -1773,7 +1693,7 @@ class Frame(Widget): pady: _ScreenUnits = ..., relief: _Relief = ..., takefocus: _TakeFocusValue = ..., - visual: str | tuple[str, int] = ..., + visual: str | tuple[str, int] = ..., # can't be changed with configure() width: _ScreenUnits = ..., ) -> None: ... @overload @@ -1983,7 +1903,7 @@ class Listbox(Widget, XView, YView): def see(self, index): ... def selection_anchor(self, index): ... select_anchor: Any - def selection_clear(self, first, last: Any | None = ...): ... # type: ignore + def selection_clear(self, first, last: Any | None = ...): ... # type: ignore[override] select_clear: Any def selection_includes(self, index): ... select_includes: Any @@ -2730,7 +2650,7 @@ class Text(Widget, XView, YView): startline: int | Literal[""] = ..., state: Literal["normal", "disabled"] = ..., # Literal inside Tuple doesn't actually work - tabs: _ScreenUnits | str | Tuple[_ScreenUnits | str, ...] = ..., + tabs: _ScreenUnits | str | tuple[_ScreenUnits | str, ...] = ..., tabstyle: Literal["tabular", "wordprocessor"] = ..., takefocus: _TakeFocusValue = ..., undo: bool = ..., @@ -2781,7 +2701,7 @@ class Text(Widget, XView, YView): spacing3: _ScreenUnits = ..., startline: int | Literal[""] = ..., state: Literal["normal", "disabled"] = ..., - tabs: _ScreenUnits | str | Tuple[_ScreenUnits | str, ...] = ..., + tabs: _ScreenUnits | str | tuple[_ScreenUnits | str, ...] = ..., tabstyle: Literal["tabular", "wordprocessor"] = ..., takefocus: _TakeFocusValue = ..., undo: bool = ..., @@ -2793,7 +2713,7 @@ class Text(Widget, XView, YView): @overload 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[override] def compare(self, index1: _TextIndex, op: Literal["<", "<=", "==", ">=", ">", "!="], index2: _TextIndex) -> bool: ... def count(self, index1, index2, *args): ... # TODO @overload @@ -2860,20 +2780,20 @@ 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 | list[str] | Tuple[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 def mark_gravity(self, markName: str, direction: Literal["left", "right"]) -> None: ... # actually returns empty string - def mark_names(self) -> Tuple[str, ...]: ... + def mark_names(self) -> tuple[str, ...]: ... def mark_set(self, markName: str, index: _TextIndex) -> None: ... def mark_unset(self, *markNames: str) -> None: ... def mark_next(self, index: _TextIndex) -> str | None: ... def mark_previous(self, index: _TextIndex) -> str | None: ... # **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 | list[str] | Tuple[str, ...]) -> None: ... + def peer_names(self) -> tuple[_tkinter.Tcl_Obj, ...]: ... + 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( @@ -2945,11 +2865,11 @@ class Text(Widget, XView, YView): 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_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_raise(self, tagName: str, aboveThis: str | None = ...) -> None: ... - def tag_ranges(self, tagName: str) -> Tuple[_tkinter.Tcl_Obj, ...]: ... + def tag_ranges(self, tagName: str) -> tuple[_tkinter.Tcl_Obj, ...]: ... # tag_remove and tag_delete are different def tag_remove(self, tagName: str, index1: _TextIndex, index2: _TextIndex | None = ...) -> None: ... # TODO: window_* methods @@ -3039,10 +2959,10 @@ class PhotoImage(Image): str | list[str] | list[list[_Color]] - | list[Tuple[_Color, ...]] - | Tuple[str, ...] - | Tuple[list[_Color], ...] - | Tuple[Tuple[_Color, ...], ...] + | list[tuple[_Color, ...]] + | tuple[str, ...] + | tuple[list[_Color], ...] + | tuple[tuple[_Color, ...], ...] ), to: tuple[int, int] | None = ..., ) -> None: ... @@ -3066,8 +2986,8 @@ class BitmapImage(Image): maskfile: StrOrBytesPath = ..., ) -> None: ... -def image_names() -> Tuple[str, ...]: ... -def image_types() -> Tuple[str, ...]: ... +def image_names() -> tuple[str, ...]: ... +def image_types() -> tuple[str, ...]: ... class Spinbox(Widget, XView): def __init__( @@ -3086,7 +3006,7 @@ class Spinbox(Widget, XView): buttondownrelief: _Relief = ..., buttonuprelief: _Relief = ..., # percent substitutions don't seem to be supported, it's similar to Entry's validation stuff - command: Callable[[], Any] | str | list[str] | Tuple[str, ...] = ..., + command: Callable[[], Any] | str | list[str] | tuple[str, ...] = ..., cursor: _Cursor = ..., disabledbackground: _Color = ..., disabledforeground: _Color = ..., @@ -3123,7 +3043,7 @@ class Spinbox(Widget, XView): validate: Literal["none", "focus", "focusin", "focusout", "key", "all"] = ..., validatecommand: _EntryValidateCommand = ..., vcmd: _EntryValidateCommand = ..., - values: list[str] | Tuple[str, ...] = ..., + values: list[str] | tuple[str, ...] = ..., width: int = ..., wrap: bool = ..., xscrollcommand: _XYScrollCommand = ..., @@ -3143,7 +3063,7 @@ class Spinbox(Widget, XView): buttoncursor: _Cursor = ..., buttondownrelief: _Relief = ..., buttonuprelief: _Relief = ..., - command: Callable[[], Any] | str | list[str] | Tuple[str, ...] = ..., + command: Callable[[], Any] | str | list[str] | tuple[str, ...] = ..., cursor: _Cursor = ..., disabledbackground: _Color = ..., disabledforeground: _Color = ..., @@ -3179,7 +3099,7 @@ class Spinbox(Widget, XView): validate: Literal["none", "focus", "focusin", "focusout", "key", "all"] = ..., validatecommand: _EntryValidateCommand = ..., vcmd: _EntryValidateCommand = ..., - values: list[str] | Tuple[str, ...] = ..., + values: list[str] | tuple[str, ...] = ..., width: int = ..., wrap: bool = ..., xscrollcommand: _XYScrollCommand = ..., @@ -3199,7 +3119,7 @@ class Spinbox(Widget, XView): def scan(self, *args): ... def scan_mark(self, x): ... def scan_dragto(self, x): ... - def selection(self, *args: Any) -> Tuple[int, ...]: ... + def selection(self, *args: Any) -> tuple[int, ...]: ... def selection_adjust(self, index): ... def selection_clear(self): ... def selection_element(self, element: Any | None = ...): ... @@ -3220,9 +3140,9 @@ class LabelFrame(Widget): bg: _Color = ..., border: _ScreenUnits = ..., borderwidth: _ScreenUnits = ..., - class_: str = ..., - colormap: Literal["new", ""] | Misc = ..., - container: bool = ..., # undocumented + class_: str = ..., # can't be changed with configure() + colormap: Literal["new", ""] | Misc = ..., # can't be changed with configure() + container: bool = ..., # undocumented, can't be changed with configure() cursor: _Cursor = ..., fg: _Color = ..., font: _FontDescription = ..., @@ -3240,7 +3160,7 @@ class LabelFrame(Widget): relief: _Relief = ..., takefocus: _TakeFocusValue = ..., text: float | str = ..., - visual: str | tuple[str, int] = ..., + visual: str | tuple[str, int] = ..., # can't be changed with configure() width: _ScreenUnits = ..., ) -> None: ... @overload diff --git a/mypy/typeshed/stdlib/tkinter/filedialog.pyi b/mypy/typeshed/stdlib/tkinter/filedialog.pyi index 0fc7d6e8a3bc..b818d5e8253e 100644 --- a/mypy/typeshed/stdlib/tkinter/filedialog.pyi +++ b/mypy/typeshed/stdlib/tkinter/filedialog.pyi @@ -1,6 +1,6 @@ from _typeshed import StrOrBytesPath from tkinter import Button, Entry, Frame, Listbox, Misc, Scrollbar, StringVar, Toplevel, commondialog -from typing import IO, Any, ClassVar, Iterable, Tuple +from typing import IO, Any, ClassVar, Iterable from typing_extensions import Literal dialogstates: dict[Any, tuple[Any, Any]] @@ -64,7 +64,7 @@ def asksaveasfilename( *, confirmoverwrite: bool | None = ..., defaultextension: str | None = ..., - filetypes: Iterable[tuple[str, str | list[str] | Tuple[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 | list[str] | Tuple[str, ...]]] | None = ..., + filetypes: Iterable[tuple[str, str | list[str] | tuple[str, ...]]] | None = ..., initialdir: StrOrBytesPath | None = ..., initialfile: StrOrBytesPath | None = ..., parent: Misc | None = ..., @@ -84,13 +84,13 @@ def askopenfilename( def askopenfilenames( *, defaultextension: str | None = ..., - filetypes: Iterable[tuple[str, str | list[str] | Tuple[str, ...]]] | None = ..., + filetypes: Iterable[tuple[str, str | list[str] | tuple[str, ...]]] | None = ..., initialdir: StrOrBytesPath | None = ..., initialfile: StrOrBytesPath | None = ..., parent: Misc | None = ..., title: str | None = ..., typevariable: StringVar | str | None = ..., -) -> Literal[""] | Tuple[str, ...]: ... +) -> Literal[""] | tuple[str, ...]: ... def askdirectory( *, initialdir: StrOrBytesPath | None = ..., mustexist: bool | None = ..., parent: Misc | None = ..., title: str | None = ... ) -> str: ... # can be empty string @@ -101,7 +101,7 @@ def asksaveasfile( *, confirmoverwrite: bool | None = ..., defaultextension: str | None = ..., - filetypes: Iterable[tuple[str, str | list[str] | Tuple[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 | list[str] | Tuple[str, ...]]] | None = ..., + filetypes: Iterable[tuple[str, str | list[str] | tuple[str, ...]]] | None = ..., initialdir: StrOrBytesPath | None = ..., initialfile: StrOrBytesPath | None = ..., parent: Misc | None = ..., @@ -123,11 +123,11 @@ def askopenfiles( mode: str = ..., *, defaultextension: str | None = ..., - filetypes: Iterable[tuple[str, str | list[str] | Tuple[str, ...]]] | None = ..., + filetypes: Iterable[tuple[str, str | list[str] | tuple[str, ...]]] | None = ..., initialdir: StrOrBytesPath | None = ..., initialfile: StrOrBytesPath | None = ..., parent: Misc | None = ..., title: str | None = ..., typevariable: StringVar | str | None = ..., -) -> Tuple[IO[Any], ...]: ... # can be empty tuple +) -> tuple[IO[Any], ...]: ... # can be empty tuple def test() -> None: ... diff --git a/mypy/typeshed/stdlib/tkinter/font.pyi b/mypy/typeshed/stdlib/tkinter/font.pyi index fccc0fbf1f0a..211e8ec9a0be 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, List, Tuple, Union, overload +from typing import Any, Union, overload from typing_extensions import Literal, TypedDict NORMAL: Literal["normal"] @@ -15,8 +15,8 @@ _FontDescription = Union[ # A font object constructed in Python Font, # ("Helvetica", 12, BOLD) - List[Any], - Tuple[Any, ...], + list[Any], + tuple[Any, ...], # A font object constructed in Tcl _tkinter.Tcl_Obj, ] @@ -102,8 +102,8 @@ class Font: def metrics(self, *, displayof: tkinter.Misc | None = ...) -> _MetricsDict: ... def measure(self, text: str, displayof: tkinter.Misc | None = ...) -> int: ... -def families(root: tkinter.Misc | None = ..., displayof: tkinter.Misc | None = ...) -> Tuple[str, ...]: ... -def names(root: tkinter.Misc | None = ...) -> Tuple[str, ...]: ... +def families(root: tkinter.Misc | None = ..., displayof: tkinter.Misc | None = ...) -> tuple[str, ...]: ... +def names(root: tkinter.Misc | None = ...) -> tuple[str, ...]: ... if sys.version_info >= (3, 10): def nametofont(name: str, root: tkinter.Misc | None = ...) -> Font: ... diff --git a/mypy/typeshed/stdlib/tkinter/tix.pyi b/mypy/typeshed/stdlib/tkinter/tix.pyi index 3037212c0ad1..6842ab7b1108 100644 --- a/mypy/typeshed/stdlib/tkinter/tix.pyi +++ b/mypy/typeshed/stdlib/tkinter/tix.pyi @@ -1,5 +1,5 @@ import tkinter -from typing import Any, Tuple +from typing import Any from typing_extensions import Literal WINDOW: Literal["window"] @@ -194,7 +194,7 @@ class HList(TixWidget, tkinter.XView, tkinter.YView): 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_children(self, entry: str | None = ...) -> Tuple[str, ...]: ... + def info_children(self, entry: str | None = ...) -> tuple[str, ...]: ... def info_data(self, entry: str) -> Any: ... def info_dragsite(self) -> str: ... def info_dropsite(self) -> str: ... @@ -203,7 +203,7 @@ class HList(TixWidget, tkinter.XView, tkinter.YView): def info_next(self, entry: str) -> str: ... def info_parent(self, entry: str) -> str: ... def info_prev(self, entry: str) -> str: ... - def info_selection(self) -> Tuple[str, ...]: ... + def info_selection(self) -> tuple[str, ...]: ... def item_cget(self, entry: str, col: int, opt: Any) -> Any: ... def item_configure(self, entry: str, col: int, cnf: dict[str, Any] = ..., **kw: Any) -> Any | None: ... def item_create(self, entry: str, col: int, cnf: dict[str, Any] = ..., **kw: Any) -> None: ... @@ -224,7 +224,7 @@ class CheckList(TixWidget): def close(self, entrypath: str) -> None: ... def getmode(self, entrypath: str) -> str: ... def open(self, entrypath: str) -> None: ... - def getselection(self, mode: str = ...) -> Tuple[str, ...]: ... + def getselection(self, mode: str = ...) -> tuple[str, ...]: ... def getstatus(self, entrypath: str) -> str: ... def setstatus(self, entrypath: str, mode: str = ...) -> None: ... @@ -253,7 +253,7 @@ class TList(TixWidget, tkinter.XView, tkinter.YView): def info_down(self, index: int) -> int: ... def info_left(self, index: int) -> int: ... def info_right(self, index: int) -> int: ... - def info_selection(self) -> Tuple[int, ...]: ... + def info_selection(self) -> tuple[int, ...]: ... def info_size(self) -> int: ... def info_up(self, index: int) -> int: ... def nearest(self, x: int, y: int) -> int: ... @@ -266,7 +266,7 @@ class PanedWindow(TixWidget): def __init__(self, master: tkinter.Widget | None, cnf: dict[str, Any] = ..., **kw: Any) -> None: ... def add(self, name: str, cnf: dict[str, Any] = ..., **kw: Any) -> None: ... def delete(self, name: str) -> None: ... - def forget(self, name: str) -> None: ... # type: ignore + def forget(self, name: str) -> None: ... # type: ignore[override] def panecget(self, entry: str, opt: Any) -> Any: ... def paneconfigure(self, entry: str, cnf: dict[str, Any] = ..., **kw: Any) -> Any | None: ... def panes(self) -> list[tkinter.Widget]: ... diff --git a/mypy/typeshed/stdlib/tkinter/ttk.pyi b/mypy/typeshed/stdlib/tkinter/ttk.pyi index be0713ec2e4b..f7319291da6d 100644 --- a/mypy/typeshed/stdlib/tkinter/ttk.pyi +++ b/mypy/typeshed/stdlib/tkinter/ttk.pyi @@ -2,7 +2,7 @@ import _tkinter import sys import tkinter from tkinter.font import _FontDescription -from typing import Any, Callable, Tuple, Union, overload +from typing import Any, Callable, Union, overload from typing_extensions import Literal, TypedDict def tclobjs_to_py(adict): ... @@ -24,7 +24,7 @@ class Style: def element_options(self, elementname): ... def theme_create(self, themename, parent: Any | None = ..., settings: Any | None = ...): ... def theme_settings(self, themename, settings): ... - def theme_names(self) -> Tuple[str, ...]: ... + def theme_names(self) -> tuple[str, ...]: ... @overload def theme_use(self, themename: str) -> None: ... @overload @@ -158,7 +158,7 @@ class Entry(Widget, tkinter.Entry): width: int = ..., xscrollcommand: tkinter._XYScrollCommand = ..., ) -> None: ... - @overload # type: ignore + @overload # type: ignore[override] def configure( self, cnf: dict[str, Any] | None = ..., @@ -183,7 +183,7 @@ class Entry(Widget, tkinter.Entry): @overload 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 + @overload # type: ignore[override] def config( self, cnf: dict[str, Any] | None = ..., @@ -234,11 +234,11 @@ class Combobox(Entry): textvariable: tkinter.Variable = ..., validate: Literal["none", "focus", "focusin", "focusout", "key", "all"] = ..., # undocumented validatecommand: tkinter._EntryValidateCommand = ..., # undocumented - values: list[str] | Tuple[str, ...] = ..., + values: list[str] | tuple[str, ...] = ..., width: int = ..., xscrollcommand: tkinter._XYScrollCommand = ..., # undocumented ) -> None: ... - @overload # type: ignore + @overload # type: ignore[override] def configure( self, cnf: dict[str, Any] | None = ..., @@ -259,14 +259,14 @@ class Combobox(Entry): textvariable: tkinter.Variable = ..., validate: Literal["none", "focus", "focusin", "focusout", "key", "all"] = ..., validatecommand: tkinter._EntryValidateCommand = ..., - values: list[str] | Tuple[str, ...] = ..., + values: list[str] | tuple[str, ...] = ..., width: int = ..., xscrollcommand: tkinter._XYScrollCommand = ..., ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload 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 + @overload # type: ignore[override] def config( self, cnf: dict[str, Any] | None = ..., @@ -287,7 +287,7 @@ class Combobox(Entry): textvariable: tkinter.Variable = ..., validate: Literal["none", "focus", "focusin", "focusout", "key", "all"] = ..., validatecommand: tkinter._EntryValidateCommand = ..., - values: list[str] | Tuple[str, ...] = ..., + values: list[str] | tuple[str, ...] = ..., width: int = ..., xscrollcommand: tkinter._XYScrollCommand = ..., ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @@ -541,13 +541,13 @@ class Panedwindow(Widget, tkinter.PanedWindow): # width and height for tkinter.ttk.Panedwindow are int but for tkinter.PanedWindow they are screen units height: int = ..., name: str = ..., - orient: Literal["vertical", "horizontal"] = ..., + orient: Literal["vertical", "horizontal"] = ..., # can't be changed with configure() style: str = ..., takefocus: tkinter._TakeFocusValue = ..., width: int = ..., ) -> None: ... def add(self, child: tkinter.Widget, *, weight: int = ..., **kw) -> None: ... - @overload # type: ignore + @overload # type: ignore[override] def configure( self, cnf: dict[str, Any] | None = ..., @@ -561,7 +561,7 @@ class Panedwindow(Widget, tkinter.PanedWindow): @overload 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 + @overload # type: ignore[override] def config( self, cnf: dict[str, Any] | None = ..., @@ -688,7 +688,7 @@ class Scale(Widget, tkinter.Scale): value: float = ..., variable: tkinter.IntVar | tkinter.DoubleVar = ..., ) -> None: ... - @overload # type: ignore + @overload # type: ignore[override] def configure( self, cnf: dict[str, Any] | None = ..., @@ -708,7 +708,7 @@ class Scale(Widget, tkinter.Scale): @overload 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 + @overload # type: ignore[override] def config( self, cnf: dict[str, Any] | None = ..., @@ -742,7 +742,7 @@ class Scrollbar(Widget, tkinter.Scrollbar): style: str = ..., takefocus: tkinter._TakeFocusValue = ..., ) -> None: ... - @overload # type: ignore + @overload # type: ignore[override] def configure( self, cnf: dict[str, Any] | None = ..., @@ -756,7 +756,7 @@ class Scrollbar(Widget, tkinter.Scrollbar): @overload 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 + @overload # type: ignore[override] def config( self, cnf: dict[str, Any] | None = ..., @@ -828,7 +828,7 @@ if sys.version_info >= (3, 7): *, background: tkinter._Color = ..., # undocumented class_: str = ..., - command: Callable[[], Any] | str | list[str] | Tuple[str, ...] = ..., + command: Callable[[], Any] | str | list[str] | tuple[str, ...] = ..., cursor: tkinter._Cursor = ..., exportselection: bool = ..., # undocumented font: _FontDescription = ..., # undocumented @@ -847,18 +847,18 @@ if sys.version_info >= (3, 7): to: float = ..., validate: Literal["none", "focus", "focusin", "focusout", "key", "all"] = ..., validatecommand: tkinter._EntryValidateCommand = ..., - values: list[str] | Tuple[str, ...] = ..., + values: list[str] | tuple[str, ...] = ..., width: int = ..., # undocumented wrap: bool = ..., xscrollcommand: tkinter._XYScrollCommand = ..., ) -> None: ... - @overload # type: ignore + @overload # type: ignore[override] def configure( self, cnf: dict[str, Any] | None = ..., *, background: tkinter._Color = ..., - command: Callable[[], Any] | str | list[str] | Tuple[str, ...] = ..., + command: Callable[[], Any] | str | list[str] | tuple[str, ...] = ..., cursor: tkinter._Cursor = ..., exportselection: bool = ..., font: _FontDescription = ..., @@ -876,14 +876,14 @@ if sys.version_info >= (3, 7): to: float = ..., validate: Literal["none", "focus", "focusin", "focusout", "key", "all"] = ..., validatecommand: tkinter._EntryValidateCommand = ..., - values: list[str] | Tuple[str, ...] = ..., + values: list[str] | tuple[str, ...] = ..., width: int = ..., wrap: bool = ..., xscrollcommand: tkinter._XYScrollCommand = ..., ) -> dict[str, tuple[str, str, str, Any, Any]] | None: ... @overload def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... - config = configure # type: ignore + config = configure # type: ignore[assignment] def set(self, value: Any) -> None: ... class _TreeviewItemDict(TypedDict): @@ -922,9 +922,9 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): master: tkinter.Misc | None = ..., *, class_: str = ..., - columns: str | list[str] | Tuple[str, ...] = ..., + columns: str | list[str] | tuple[str, ...] = ..., cursor: tkinter._Cursor = ..., - displaycolumns: str | list[str] | Tuple[str, ...] | list[int] | Tuple[int, ...] | Literal["#all"] = ..., + displaycolumns: str | list[str] | tuple[str, ...] | list[int] | tuple[int, ...] | Literal["#all"] = ..., height: int = ..., name: str = ..., padding: tkinter._Padding = ..., @@ -933,7 +933,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): # # 'tree headings' is same as ['tree', 'headings'], and I wouldn't be # surprised if someone is using it. - show: Literal["tree", "headings", "tree headings", ""] | list[str] | Tuple[str, ...] = ..., + show: Literal["tree", "headings", "tree headings", ""] | list[str] | tuple[str, ...] = ..., style: str = ..., takefocus: tkinter._TakeFocusValue = ..., xscrollcommand: tkinter._XYScrollCommand = ..., @@ -944,13 +944,13 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): self, cnf: dict[str, Any] | None = ..., *, - columns: str | list[str] | Tuple[str, ...] = ..., + columns: str | list[str] | tuple[str, ...] = ..., cursor: tkinter._Cursor = ..., - displaycolumns: str | list[str] | Tuple[str, ...] | list[int] | Tuple[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", ""] | list[str] | Tuple[str, ...] = ..., + show: Literal["tree", "headings", "tree headings", ""] | list[str] | tuple[str, ...] = ..., style: str = ..., takefocus: tkinter._TakeFocusValue = ..., xscrollcommand: tkinter._XYScrollCommand = ..., @@ -959,8 +959,8 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): @overload 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 get_children(self, item: str | None = ...) -> Tuple[str, ...]: ... + def bbox(self, item, column: _TreeviewColumnId | None = ...) -> tuple[int, int, int, int] | Literal[""]: ... # type: ignore[override] + def get_children(self, item: str | None = ...) -> tuple[str, ...]: ... def set_children(self, item: str, *newchildren: str) -> None: ... @overload def column(self, column: _TreeviewColumnId, option: Literal["width", "minwidth"]) -> int: ... @@ -987,7 +987,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): def delete(self, *items: str) -> None: ... def detach(self, *items: str) -> None: ... def exists(self, item: str) -> bool: ... - @overload # type: ignore + @overload # type: ignore[override] def focus(self, item: None = ...) -> str: ... # can return empty string @overload def focus(self, item: str) -> Literal[""]: ... @@ -1027,20 +1027,20 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): id: str = ..., # same as iid text: str = ..., image: tkinter._ImageSpec = ..., - values: list[Any] | Tuple[Any, ...] = ..., + values: list[Any] | tuple[Any, ...] = ..., open: bool = ..., - tags: str | list[str] | Tuple[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"]) -> tuple[str] | Literal[""]: ... @overload - def item(self, item: str, option: Literal["values"]) -> Tuple[Any, ...] | Literal[""]: ... + 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"]) -> Tuple[str, ...] | Literal[""]: ... + 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: list[Any] | Tuple[Any, ...] | Literal[""] = ..., + values: list[Any] | tuple[Any, ...] | Literal[""] = ..., open: bool = ..., - tags: str | list[str] | Tuple[str, ...] = ..., + tags: str | list[str] | tuple[str, ...] = ..., ) -> _TreeviewItemDict | None: ... def move(self, item: str, parent: str, index: int) -> None: ... reattach = move @@ -1062,13 +1062,13 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): def prev(self, item: str) -> str: ... # returning empty string means first item def see(self, item: str) -> None: ... if sys.version_info >= (3, 8): - def selection(self) -> Tuple[str, ...]: ... + def selection(self) -> tuple[str, ...]: ... else: - def selection(self, selop: Any | None = ..., items: Any | None = ...) -> Tuple[str, ...]: ... - 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: ... + def selection(self, selop: Any | None = ..., items: Any | None = ...) -> tuple[str, ...]: ... + 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 @@ -1104,7 +1104,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): image: tkinter._ImageSpec = ..., ) -> _TreeviewTagDict | Any: ... # can be None but annoying to check @overload - def tag_has(self, tagname: str, item: None = ...) -> Tuple[str, ...]: ... + def tag_has(self, tagname: str, item: None = ...) -> tuple[str, ...]: ... @overload def tag_has(self, tagname: str, item: str) -> bool: ... diff --git a/mypy/typeshed/stdlib/token.pyi b/mypy/typeshed/stdlib/token.pyi index 90381833511b..9451015e9df5 100644 --- a/mypy/typeshed/stdlib/token.pyi +++ b/mypy/typeshed/stdlib/token.pyi @@ -71,6 +71,8 @@ if sys.version_info >= (3, 8): TYPE_IGNORE: int COLONEQUAL: int EXACT_TOKEN_TYPES: dict[str, int] +if sys.version_info >= (3, 10): + SOFT_KEYWORD: int def ISTERMINAL(x: int) -> bool: ... def ISNONTERMINAL(x: int) -> bool: ... diff --git a/mypy/typeshed/stdlib/tokenize.pyi b/mypy/typeshed/stdlib/tokenize.pyi index a8294adb653f..7614ebfe403e 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, TextIO, Tuple, Union +from typing import Any, Callable, Generator, Iterable, NamedTuple, Pattern, Sequence, TextIO, Union if sys.version_info < (3, 7): COMMENT: int @@ -12,7 +12,7 @@ if sys.version_info < (3, 7): cookie_re: Pattern[str] blank_re: Pattern[bytes] -_Position = Tuple[int, int] +_Position = tuple[int, int] class _TokenInfo(NamedTuple): type: int diff --git a/mypy/typeshed/stdlib/trace.pyi b/mypy/typeshed/stdlib/trace.pyi index bab75c9ada8d..ee8dffa67820 100644 --- a/mypy/typeshed/stdlib/trace.pyi +++ b/mypy/typeshed/stdlib/trace.pyi @@ -1,13 +1,13 @@ import sys import types from _typeshed import StrPath -from typing import Any, Callable, Mapping, Optional, Sequence, Tuple, TypeVar +from typing import Any, Callable, Mapping, Optional, Sequence, TypeVar from typing_extensions import ParamSpec _T = TypeVar("_T") _P = ParamSpec("_P") _localtrace = Callable[[types.FrameType, str, Any], Callable[..., Any]] -_fileModuleFunction = Tuple[str, Optional[str], str] +_fileModuleFunction = tuple[str, Optional[str], str] class CoverageResults: def __init__( @@ -43,9 +43,9 @@ class Trace: self, cmd: str | types.CodeType, globals: Mapping[str, Any] | None = ..., locals: Mapping[str, Any] | None = ... ) -> None: ... if sys.version_info >= (3, 9): - def runfunc(self, __func: Callable[_P, _T], *args: _P.args, **kw: _P.kwargs) -> _T: ... # type: ignore + def runfunc(self, __func: Callable[_P, _T], *args: _P.args, **kw: _P.kwargs) -> _T: ... else: - def runfunc(self, func: Callable[_P, _T], *args: _P.args, **kw: _P.kwargs) -> _T: ... # type: ignore + def runfunc(self, func: Callable[_P, _T], *args: _P.args, **kw: _P.kwargs) -> _T: ... def file_module_function_of(self, frame: types.FrameType) -> _fileModuleFunction: ... def globaltrace_trackcallers(self, frame: types.FrameType, why: str, arg: Any) -> None: ... def globaltrace_countfuncs(self, frame: types.FrameType, why: str, arg: Any) -> None: ... diff --git a/mypy/typeshed/stdlib/traceback.pyi b/mypy/typeshed/stdlib/traceback.pyi index e685b09a6ae4..4e36490c24e4 100644 --- a/mypy/typeshed/stdlib/traceback.pyi +++ b/mypy/typeshed/stdlib/traceback.pyi @@ -1,13 +1,14 @@ import sys from _typeshed import SupportsWrite from types import FrameType, TracebackType -from typing import IO, Any, Generator, Iterable, Iterator, List, Mapping, Optional, Tuple, Type +from typing import IO, Any, Generator, Iterable, Iterator, Mapping, Optional, Type, overload -_PT = Tuple[str, int, str, Optional[str]] +_PT = tuple[str, int, str, Optional[str]] def print_tb(tb: TracebackType | None, limit: int | None = ..., file: IO[str] | None = ...) -> None: ... if sys.version_info >= (3, 10): + @overload def print_exception( __exc: Type[BaseException] | None, value: BaseException | None = ..., @@ -16,6 +17,20 @@ if sys.version_info >= (3, 10): file: IO[str] | None = ..., chain: bool = ..., ) -> None: ... + @overload + def print_exception( + __exc: BaseException, *, limit: int | None = ..., file: IO[str] | None = ..., chain: bool = ... + ) -> None: ... + @overload + def format_exception( + __exc: Type[BaseException] | None, + value: BaseException | None = ..., + tb: TracebackType | None = ..., + limit: int | None = ..., + chain: bool = ..., + ) -> list[str]: ... + @overload + def format_exception(__exc: BaseException, *, limit: int | None = ..., chain: bool = ...) -> list[str]: ... else: def print_exception( @@ -26,6 +41,13 @@ else: file: IO[str] | None = ..., chain: bool = ..., ) -> None: ... + def format_exception( + etype: Type[BaseException] | None, + value: BaseException | None, + tb: TracebackType | None, + limit: int | None = ..., + chain: bool = ..., + ) -> list[str]: ... def print_exc(limit: int | None = ..., file: IO[str] | None = ..., chain: bool = ...) -> None: ... def print_last(limit: int | None = ..., file: IO[str] | None = ..., chain: bool = ...) -> None: ... @@ -43,24 +65,6 @@ if sys.version_info >= (3, 10): else: def format_exception_only(etype: Type[BaseException] | None, value: BaseException | None) -> list[str]: ... -if sys.version_info >= (3, 10): - def format_exception( - __exc: Type[BaseException] | None, - value: BaseException | None = ..., - tb: TracebackType | None = ..., - limit: int | None = ..., - chain: bool = ..., - ) -> list[str]: ... - -else: - def format_exception( - etype: Type[BaseException] | None, - value: BaseException | None, - tb: TracebackType | None, - limit: int | None = ..., - chain: bool = ..., - ) -> list[str]: ... - 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]: ... @@ -84,7 +88,7 @@ class TracebackException: self, exc_type: Type[BaseException], exc_value: BaseException, - exc_traceback: TracebackType, + exc_traceback: TracebackType | None, *, limit: int | None = ..., lookup_lines: bool = ..., @@ -107,7 +111,7 @@ class TracebackException: self, exc_type: Type[BaseException], exc_value: BaseException, - exc_traceback: TracebackType, + exc_traceback: TracebackType | None, *, limit: int | None = ..., lookup_lines: bool = ..., @@ -142,7 +146,7 @@ class FrameSummary(Iterable[Any]): def __getitem__(self, i: int) -> Any: ... def __iter__(self) -> Iterator[Any]: ... -class StackSummary(List[FrameSummary]): +class StackSummary(list[FrameSummary]): @classmethod def extract( cls, diff --git a/mypy/typeshed/stdlib/tracemalloc.pyi b/mypy/typeshed/stdlib/tracemalloc.pyi index ca4d5901b870..4d7bbb7994a6 100644 --- a/mypy/typeshed/stdlib/tracemalloc.pyi +++ b/mypy/typeshed/stdlib/tracemalloc.pyi @@ -1,6 +1,7 @@ import sys from _tracemalloc import * -from typing import Optional, Sequence, Tuple, Union, overload +from typing import Optional, Sequence, Union, overload +from typing_extensions import SupportsIndex def get_object_traceback(obj: object) -> Traceback | None: ... def take_snapshot() -> Snapshot: ... @@ -34,7 +35,7 @@ class StatisticDiff: traceback: Traceback def __init__(self, traceback: Traceback, size: int, size_diff: int, count: int, count_diff: int) -> None: ... -_FrameTupleT = Tuple[str, int] +_FrameTupleT = tuple[str, int] class Frame: filename: str @@ -42,9 +43,9 @@ class Frame: def __init__(self, frame: _FrameTupleT) -> None: ... if sys.version_info >= (3, 9): - _TraceTupleT = Union[Tuple[int, int, Sequence[_FrameTupleT], Optional[int]], Tuple[int, int, Sequence[_FrameTupleT]]] + _TraceTupleT = Union[tuple[int, int, Sequence[_FrameTupleT], Optional[int]], tuple[int, int, Sequence[_FrameTupleT]]] else: - _TraceTupleT = Tuple[int, int, Sequence[_FrameTupleT]] + _TraceTupleT = tuple[int, int, Sequence[_FrameTupleT]] class Trace: domain: int @@ -63,7 +64,7 @@ class Traceback(Sequence[Frame]): else: def format(self, limit: int | None = ...) -> list[str]: ... @overload - def __getitem__(self, i: int) -> Frame: ... + def __getitem__(self, i: SupportsIndex) -> Frame: ... @overload def __getitem__(self, s: slice) -> Sequence[Frame]: ... def __len__(self) -> int: ... diff --git a/mypy/typeshed/stdlib/tty.pyi b/mypy/typeshed/stdlib/tty.pyi index c0dc418e9933..015669a68084 100644 --- a/mypy/typeshed/stdlib/tty.pyi +++ b/mypy/typeshed/stdlib/tty.pyi @@ -1,15 +1,16 @@ +import sys from typing import IO, Union -_FD = Union[int, IO[str]] +if sys.platform != "win32": + _FD = Union[int, IO[str]] -# XXX: Undocumented integer constants -IFLAG: int -OFLAG: int -CFLAG: int -LFLAG: int -ISPEED: int -OSPEED: int -CC: int - -def setraw(fd: _FD, when: int = ...) -> None: ... -def setcbreak(fd: _FD, when: int = ...) -> None: ... + # XXX: Undocumented integer constants + IFLAG: int + OFLAG: int + CFLAG: int + LFLAG: int + ISPEED: int + OSPEED: int + CC: int + def setraw(fd: _FD, when: int = ...) -> None: ... + def setcbreak(fd: _FD, when: int = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/turtle.pyi b/mypy/typeshed/stdlib/turtle.pyi index 9371f2a7a547..e5efcb4f6ed9 100644 --- a/mypy/typeshed/stdlib/turtle.pyi +++ b/mypy/typeshed/stdlib/turtle.pyi @@ -1,24 +1,26 @@ -from tkinter import Canvas, PhotoImage -from typing import Any, Callable, Dict, Sequence, Tuple, TypeVar, Union, overload +from tkinter import Canvas, Frame, PhotoImage +from typing import Any, Callable, ClassVar, Sequence, TypeVar, Union, overload # Note: '_Color' is the alias we use for arguments and _AnyColor is the # alias we use for return types. Really, these two aliases should be the # same, but as per the "no union returns" typeshed policy, we'll return # Any instead. -_Color = Union[str, Tuple[float, float, float]] +_Color = Union[str, tuple[float, float, float]] _AnyColor = Any # TODO: Replace this with a TypedDict once it becomes standardized. -_PenState = Dict[str, Any] +_PenState = dict[str, Any] _Speed = Union[str, float] -_PolygonCoords = Sequence[Tuple[float, float]] +_PolygonCoords = Sequence[tuple[float, float]] # TODO: Type this more accurately # Vec2D is actually a custom subclass of 'tuple'. -Vec2D = Tuple[float, float] +Vec2D = tuple[float, float] -class TurtleScreenBase(object): +class ScrolledCanvas(Frame): ... + +class TurtleScreenBase: cv: Canvas canvwidth: int canvheight: int @@ -34,7 +36,7 @@ class TurtleScreenBase(object): class Terminator(Exception): ... class TurtleGraphicsError(Exception): ... -class Shape(object): +class Shape: def __init__(self, type_: str, data: _PolygonCoords | PhotoImage | None = ...) -> None: ... def addcomponent(self, poly: _PolygonCoords, fill: _Color, outline: _Color | None = ...) -> None: ... @@ -92,7 +94,7 @@ class TurtleScreen(TurtleScreenBase): def onkeypress(self, fun: Callable[[], Any], key: str | None = ...) -> None: ... onkeyrelease = onkey -class TNavigator(object): +class TNavigator: START_ORIENTATION: dict[str, Vec2D] DEFAULT_MODE: str DEFAULT_ANGLEOFFSET: int @@ -136,7 +138,7 @@ class TNavigator(object): setposition = goto seth = setheading -class TPen(object): +class TPen: def __init__(self, resizemode: str = ...) -> None: ... @overload def resizemode(self, rmode: None = ...) -> str: ... @@ -178,7 +180,7 @@ class TPen(object): def isvisible(self) -> bool: ... # Note: signatures 1 and 2 overlap unsafely when no arguments are provided @overload - def pen(self) -> _PenState: ... # type: ignore + def pen(self) -> _PenState: ... # type: ignore[misc] @overload def pen( self, @@ -206,6 +208,8 @@ class TPen(object): _T = TypeVar("_T") class RawTurtle(TPen, TNavigator): + screen: TurtleScreen + screens: ClassVar[list[TurtleScreen]] def __init__( self, canvas: Canvas | TurtleScreen | None = ..., shape: str = ..., undobuffersize: int = ..., visible: bool = ... ) -> None: ... @@ -220,7 +224,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[misc] @overload def shapesize( self, stretch_wid: float | None = ..., stretch_len: float | None = ..., outline: float | None = ... @@ -231,7 +235,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[misc] @overload def shapetransform( self, t11: float | None = ..., t12: float | None = ..., t21: float | None = ..., t22: float | None = ... @@ -247,7 +251,7 @@ class RawTurtle(TPen, TNavigator): # a compound stamp or not. So, as per the "no Union return" policy, # we return Any. def stamp(self) -> Any: ... - def clearstamp(self, stampid: int | Tuple[int, ...]) -> None: ... + def clearstamp(self, stampid: int | tuple[int, ...]) -> None: ... def clearstamps(self, n: int | None = ...) -> None: ... def filling(self) -> bool: ... def begin_fill(self) -> None: ... @@ -449,7 +453,7 @@ def isvisible() -> bool: ... # Note: signatures 1 and 2 overlap unsafely when no arguments are provided @overload -def pen() -> _PenState: ... # type: ignore +def pen() -> _PenState: ... # type: ignore[misc] @overload def pen( pen: _PenState | None = ..., @@ -485,7 +489,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[misc] @overload def shapesize(stretch_wid: float | None = ..., stretch_len: float | None = ..., outline: float | None = ...) -> None: ... @overload @@ -495,7 +499,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[misc] @overload def shapetransform( t11: float | None = ..., t12: float | None = ..., t21: float | None = ..., t22: float | None = ... @@ -512,7 +516,7 @@ def tilt(angle: float) -> None: ... # a compound stamp or not. So, as per the "no Union return" policy, # we return Any. def stamp() -> Any: ... -def clearstamp(stampid: int | Tuple[int, ...]) -> None: ... +def clearstamp(stampid: int | tuple[int, ...]) -> None: ... def clearstamps(n: int | None = ...) -> None: ... def filling() -> bool: ... def begin_fill() -> None: ... diff --git a/mypy/typeshed/stdlib/types.pyi b/mypy/typeshed/stdlib/types.pyi index 899024f2dd4d..caf745b99554 100644 --- a/mypy/typeshed/stdlib/types.pyi +++ b/mypy/typeshed/stdlib/types.pyi @@ -1,4 +1,5 @@ import sys +from _typeshed import SupportsKeysAndGetItem from importlib.abc import _LoaderProtocol from importlib.machinery import ModuleSpec from typing import ( @@ -15,7 +16,6 @@ from typing import ( KeysView, Mapping, MutableSequence, - Tuple, Type, TypeVar, ValuesView, @@ -36,14 +36,15 @@ _V_co = TypeVar("_V_co", covariant=True) @final class _Cell: - __hash__: None # type: ignore + __hash__: None # type: ignore[assignment] cell_contents: Any +# Make sure this class definition stays roughly in line with `builtins.function` @final class FunctionType: - __closure__: Tuple[_Cell, ...] | None + __closure__: tuple[_Cell, ...] | None __code__: CodeType - __defaults__: Tuple[Any, ...] | None + __defaults__: tuple[Any, ...] | None __dict__: dict[str, Any] __globals__: dict[str, Any] __name__: str @@ -55,11 +56,11 @@ class FunctionType: code: CodeType, globals: dict[str, Any], name: str | None = ..., - argdefs: Tuple[object, ...] | None = ..., - closure: Tuple[_Cell, ...] | None = ..., + argdefs: tuple[object, ...] | None = ..., + closure: tuple[_Cell, ...] | None = ..., ) -> None: ... def __call__(self, *args: Any, **kwargs: Any) -> Any: ... - def __get__(self, obj: object | None, type: type | None) -> MethodType: ... + def __get__(self, obj: object | None, type: type | None = ...) -> MethodType: ... LambdaType = FunctionType @@ -75,15 +76,15 @@ class CodeType: co_stacksize: int co_flags: int co_code: bytes - co_consts: Tuple[Any, ...] - co_names: Tuple[str, ...] - co_varnames: Tuple[str, ...] + co_consts: tuple[Any, ...] + co_names: tuple[str, ...] + co_varnames: tuple[str, ...] co_filename: str co_name: str co_firstlineno: int co_lnotab: bytes - co_freevars: Tuple[str, ...] - co_cellvars: Tuple[str, ...] + co_freevars: tuple[str, ...] + co_cellvars: tuple[str, ...] if sys.version_info >= (3, 8): def __init__( self, @@ -94,15 +95,15 @@ class CodeType: stacksize: int, flags: int, codestring: bytes, - constants: Tuple[Any, ...], - names: Tuple[str, ...], - varnames: Tuple[str, ...], + constants: tuple[Any, ...], + names: tuple[str, ...], + varnames: tuple[str, ...], filename: str, name: str, firstlineno: int, lnotab: bytes, - freevars: Tuple[str, ...] = ..., - cellvars: Tuple[str, ...] = ..., + freevars: tuple[str, ...] = ..., + cellvars: tuple[str, ...] = ..., ) -> None: ... else: def __init__( @@ -113,17 +114,40 @@ class CodeType: stacksize: int, flags: int, codestring: bytes, - constants: Tuple[Any, ...], - names: Tuple[str, ...], - varnames: Tuple[str, ...], + constants: tuple[Any, ...], + names: tuple[str, ...], + varnames: tuple[str, ...], filename: str, name: str, firstlineno: int, lnotab: bytes, - freevars: Tuple[str, ...] = ..., - cellvars: Tuple[str, ...] = ..., + freevars: tuple[str, ...] = ..., + cellvars: tuple[str, ...] = ..., ) -> None: ... - if sys.version_info >= (3, 8): + if sys.version_info >= (3, 10): + def replace( + self, + *, + co_argcount: int = ..., + co_posonlyargcount: int = ..., + co_kwonlyargcount: int = ..., + co_nlocals: int = ..., + co_stacksize: int = ..., + co_flags: int = ..., + co_firstlineno: int = ..., + co_code: bytes = ..., + co_consts: tuple[Any, ...] = ..., + co_names: tuple[str, ...] = ..., + co_varnames: tuple[str, ...] = ..., + co_freevars: tuple[str, ...] = ..., + co_cellvars: tuple[str, ...] = ..., + co_filename: str = ..., + co_name: str = ..., + co_linetable: object = ..., + ) -> CodeType: ... + def co_lines(self) -> Iterator[tuple[int, int, int | None]]: ... + co_linetable: object + elif sys.version_info >= (3, 8): def replace( self, *, @@ -135,11 +159,11 @@ class CodeType: co_flags: int = ..., co_firstlineno: int = ..., co_code: bytes = ..., - co_consts: Tuple[Any, ...] = ..., - co_names: Tuple[str, ...] = ..., - co_varnames: Tuple[str, ...] = ..., - co_freevars: Tuple[str, ...] = ..., - co_cellvars: Tuple[str, ...] = ..., + co_consts: tuple[Any, ...] = ..., + co_names: tuple[str, ...] = ..., + co_varnames: tuple[str, ...] = ..., + co_freevars: tuple[str, ...] = ..., + co_cellvars: tuple[str, ...] = ..., co_filename: str = ..., co_name: str = ..., co_lnotab: bytes = ..., @@ -149,8 +173,8 @@ class CodeType: @final class MappingProxyType(Mapping[_KT, _VT_co], Generic[_KT, _VT_co]): - __hash__: None # type: ignore - def __init__(self, mapping: Mapping[_KT, _VT_co]) -> None: ... + __hash__: None # type: ignore[assignment] + def __init__(self, mapping: SupportsKeysAndGetItem[_KT, _VT_co]) -> None: ... def __getitem__(self, k: _KT) -> _VT_co: ... def __iter__(self) -> Iterator[_KT]: ... def __len__(self) -> int: ... @@ -165,7 +189,7 @@ class MappingProxyType(Mapping[_KT, _VT_co], Generic[_KT, _VT_co]): def __ror__(self, __value: Mapping[_T1, _T2]) -> dict[_KT | _T1, _VT_co | _T2]: ... class SimpleNamespace: - __hash__: None # type: ignore + __hash__: None # type: ignore[assignment] def __init__(self, **kwargs: Any) -> None: ... def __getattribute__(self, name: str) -> Any: ... def __setattr__(self, name: str, value: Any) -> None: ... @@ -218,6 +242,8 @@ class AsyncGeneratorType(AsyncGenerator[_T_co, _T_contra]): @overload def athrow(self, __typ: BaseException, __val: None = ..., __tb: TracebackType | None = ...) -> Awaitable[_T_co]: ... def aclose(self) -> Awaitable[None]: ... + if sys.version_info >= (3, 9): + def __class_getitem__(cls, __item: Any) -> GenericAlias: ... @final class CoroutineType(Coroutine[_T_co, _T_contra, _V_co]): @@ -255,8 +281,8 @@ class _StaticFunctionType: @final class MethodType: - __closure__: Tuple[_Cell, ...] | None # inherited from the added function - __defaults__: Tuple[Any, ...] | None # inherited from the added function + __closure__: tuple[_Cell, ...] | None # inherited from the added function + __defaults__: tuple[Any, ...] | None # inherited from the added function __func__: _StaticFunctionType __self__: object __name__: str # inherited from the added function @@ -328,7 +354,10 @@ class FrameType: f_code: CodeType f_globals: dict[str, Any] f_lasti: int - f_lineno: int + # see discussion in #6769: f_lineno *can* sometimes be None, + # but you should probably file a bug report with CPython if you encounter it being None in the wild. + # An `int | None` annotation here causes too many false-positive errors. + f_lineno: int | Any f_locals: dict[str, Any] f_trace: Callable[[FrameType, str, Any], Any] | None if sys.version_info >= (3, 7): @@ -359,18 +388,18 @@ if sys.version_info >= (3, 7): kwds: dict[str, Any] | None = ..., exec_body: Callable[[dict[str, Any]], None] | None = ..., ) -> type: ... - def resolve_bases(bases: Iterable[object]) -> Tuple[Any, ...]: ... + def resolve_bases(bases: Iterable[object]) -> tuple[Any, ...]: ... else: def new_class( name: str, - bases: Tuple[type, ...] = ..., + bases: tuple[type, ...] = ..., kwds: dict[str, Any] | None = ..., exec_body: Callable[[dict[str, Any]], None] | None = ..., ) -> type: ... def prepare_class( - name: str, bases: Tuple[type, ...] = ..., kwds: dict[str, Any] | None = ... + name: str, bases: tuple[type, ...] = ..., kwds: dict[str, Any] | None = ... ) -> tuple[type, dict[str, Any], dict[str, Any]]: ... # Actually a different type, but `property` is special and we want that too. @@ -381,10 +410,11 @@ _R = TypeVar("_R") _P = ParamSpec("_P") # it's not really an Awaitable, but can be used in an await expression. Real type: Generator & Awaitable +# The type: ignore is due to overlapping overloads, not the use of ParamSpec @overload -def coroutine(func: Callable[_P, Generator[_R, Any, Any]]) -> Callable[_P, Awaitable[_R]]: ... # type: ignore +def coroutine(func: Callable[_P, Generator[_R, Any, Any]]) -> Callable[_P, Awaitable[_R]]: ... # type: ignore[misc] @overload -def coroutine(func: _Fn) -> _Fn: ... # type: ignore +def coroutine(func: _Fn) -> _Fn: ... if sys.version_info >= (3, 8): CellType = _Cell @@ -392,8 +422,8 @@ if sys.version_info >= (3, 8): if sys.version_info >= (3, 9): class GenericAlias: __origin__: type - __args__: Tuple[Any, ...] - __parameters__: Tuple[Any, ...] + __args__: tuple[Any, ...] + __parameters__: tuple[Any, ...] def __init__(self, origin: type, args: Any) -> None: ... def __getattr__(self, name: str) -> Any: ... # incomplete @@ -407,6 +437,6 @@ if sys.version_info >= (3, 10): NotImplementedType = _NotImplementedType # noqa F811 from builtins @final class UnionType: - __args__: Tuple[Any, ...] + __args__: tuple[Any, ...] def __or__(self, obj: Any) -> UnionType: ... def __ror__(self, obj: Any) -> UnionType: ... diff --git a/mypy/typeshed/stdlib/typing.pyi b/mypy/typeshed/stdlib/typing.pyi index 4656add7ec21..6e461b8aa260 100644 --- a/mypy/typeshed/stdlib/typing.pyi +++ b/mypy/typeshed/stdlib/typing.pyi @@ -1,5 +1,6 @@ import collections # Needed by aliases like DefaultDict, see mypy issue 2986 import sys +from _typeshed import SupportsKeysAndGetItem 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, final as _final @@ -10,9 +11,6 @@ if sys.version_info >= (3, 7): if sys.version_info >= (3, 9): from types import GenericAlias -# Definitions of special type checking related constructs. Their definitions -# are not used, so their value does not matter. - Any = object() class TypeVar: @@ -29,11 +27,18 @@ class TypeVar: covariant: bool = ..., contravariant: bool = ..., ) -> None: ... + if sys.version_info >= (3, 10): + def __or__(self, other: Any) -> _SpecialForm: ... + def __ror__(self, other: Any) -> _SpecialForm: ... +# Used for an undocumented mypy feature. Does not exist at runtime. _promote = object() class _SpecialForm: def __getitem__(self, typeargs: Any) -> object: ... + if sys.version_info >= (3, 10): + def __or__(self, other: Any) -> _SpecialForm: ... + def __ror__(self, other: Any) -> _SpecialForm: ... _F = TypeVar("_F", bound=Callable[..., Any]) _P = _ParamSpec("_P") @@ -80,9 +85,20 @@ if sys.version_info >= (3, 10): def args(self) -> ParamSpecArgs: ... @property def kwargs(self) -> ParamSpecKwargs: ... + def __or__(self, other: Any) -> _SpecialForm: ... + def __ror__(self, other: Any) -> _SpecialForm: ... Concatenate: _SpecialForm = ... TypeAlias: _SpecialForm = ... TypeGuard: _SpecialForm = ... + class NewType: + def __init__(self, name: str, tp: type) -> None: ... + def __call__(self, x: _T) -> _T: ... + def __or__(self, other: Any) -> _SpecialForm: ... + def __ror__(self, other: Any) -> _SpecialForm: ... + __supertype__: type + +else: + def NewType(name: str, tp: Type[_T]) -> Type[_T]: ... # These type variables are used by the container types. _S = TypeVar("_S") @@ -96,7 +112,7 @@ _T_contra = TypeVar("_T_contra", contravariant=True) # Ditto contravariant. _TC = TypeVar("_TC", bound=Type[object]) def no_type_check(arg: _F) -> _F: ... -def no_type_check_decorator(decorator: Callable[_P, _T]) -> Callable[_P, _T]: ... # type: ignore +def no_type_check_decorator(decorator: Callable[_P, _T]) -> Callable[_P, _T]: ... # type: ignore[misc] # Type aliases and type constructors @@ -122,6 +138,14 @@ if sys.version_info >= (3, 9): # Predefined type variables. AnyStr = TypeVar("AnyStr", str, bytes) +if sys.version_info >= (3, 8): + # This class did actually exist in 3.7, but had a different base. + # We'll just pretend it didn't exist though: the main external use case for _ProtocolMeta is + # to inherit from for your own custom protocol metaclasses. If you're using 3.7, at runtime + # you'd use typing_extensions.Protocol, which would be unrelated to typing._ProtocolMeta and + # so you'd run into metaclass conflicts at runtime if you used typing._ProtocolMeta. + class _ProtocolMeta(ABCMeta): ... + # Abstract base classes. def runtime_checkable(cls: _TC) -> _TC: ... @@ -246,7 +270,7 @@ class Coroutine(Awaitable[_V_co], Generic[_T_co, _T_contra, _V_co]): @abstractmethod def close(self) -> None: ... -# NOTE: This type does not exist in typing.py or PEP 484. +# NOTE: This type does not exist in typing.py or PEP 484 but mypy needs it to exist. # The parameters correspond to Generator, but the 4th is the original type. class AwaitableGenerator( Awaitable[_V_co], Generator[_T_co, _T_contra, _V_co], Generic[_T_co, _T_contra, _V_co, _S], metaclass=ABCMeta @@ -465,7 +489,7 @@ class MutableMapping(Mapping[_KT, _VT], Generic[_KT, _VT]): # known to be a Mapping with unknown type parameters, which is closer # to the behavior we want. See mypy issue #1430. @overload - def update(self, __m: Mapping[_KT, _VT], **kwargs: _VT) -> None: ... + def update(self, __m: SupportsKeysAndGetItem[_KT, _VT], **kwargs: _VT) -> None: ... @overload def update(self, __m: Iterable[tuple[_KT, _VT]], **kwargs: _VT) -> None: ... @overload @@ -550,7 +574,7 @@ class Match(Generic[AnyStr]): pos: int endpos: int lastindex: int | None - lastgroup: AnyStr | None + lastgroup: str | None string: AnyStr # The regular expression object whose match() or search() method produced @@ -598,7 +622,7 @@ class Pattern(Generic[AnyStr]): def search(self, string: AnyStr, pos: int = ..., endpos: int = ...) -> Match[AnyStr] | None: ... def match(self, string: AnyStr, pos: int = ..., endpos: int = ...) -> Match[AnyStr] | None: ... def fullmatch(self, string: AnyStr, pos: int = ..., endpos: int = ...) -> Match[AnyStr] | None: ... - def split(self, string: AnyStr, maxsplit: int = ...) -> list[AnyStr]: ... + def split(self, string: AnyStr, maxsplit: int = ...) -> list[AnyStr | Any]: ... def findall(self, string: AnyStr, pos: int = ..., endpos: int = ...) -> list[Any]: ... def finditer(self, string: AnyStr, pos: int = ..., endpos: int = ...) -> Iterator[Match[AnyStr]]: ... @overload @@ -657,9 +681,11 @@ def cast(typ: object, val: Any) -> Any: ... # Type constructors -# NamedTuple is special-cased in the type checker class NamedTuple(Tuple[Any, ...]): - _field_types: collections.OrderedDict[str, Type[Any]] + if sys.version_info < (3, 8): + _field_types: collections.OrderedDict[str, type] + elif sys.version_info < (3, 9): + _field_types: dict[str, type] _field_defaults: dict[str, Any] _fields: Tuple[str, ...] _source: str @@ -691,8 +717,6 @@ class _TypedDict(Mapping[str, object], metaclass=ABCMeta): def __or__(self: _T, __value: _T) -> _T: ... def __ior__(self: _T, __value: _T) -> _T: ... -def NewType(name: str, tp: Type[_T]) -> Type[_T]: ... - # This itself is only available during type checking def type_check_only(func_or_cls: _F) -> _F: ... @@ -704,14 +728,17 @@ if sys.version_info >= (3, 7): __forward_value__: Any | None __forward_is_argument__: bool if sys.version_info >= (3, 9): - # The module argument was added in Python 3.9.7. - def __init__(self, arg: str, is_argument: bool = ..., module: Any | None = ...) -> None: ... + # The module and is_class arguments were added in later Python 3.9 versions. + def __init__(self, arg: str, is_argument: bool = ..., module: Any | None = ..., *, is_class: bool = ...) -> None: ... else: def __init__(self, arg: str, is_argument: bool = ...) -> None: ... def _evaluate(self, globalns: dict[str, Any] | None, localns: dict[str, Any] | None) -> Any | None: ... def __eq__(self, other: Any) -> bool: ... def __hash__(self) -> int: ... def __repr__(self) -> str: ... + if sys.version_info >= (3, 11): + def __or__(self, other: Any) -> _SpecialForm: ... + def __ror__(self, other: Any) -> _SpecialForm: ... if sys.version_info >= (3, 10): - def is_typeddict(tp: Any) -> bool: ... + def is_typeddict(tp: object) -> bool: ... diff --git a/mypy/typeshed/stdlib/typing_extensions.pyi b/mypy/typeshed/stdlib/typing_extensions.pyi index ce407f996022..e7f288377b83 100644 --- a/mypy/typeshed/stdlib/typing_extensions.pyi +++ b/mypy/typeshed/stdlib/typing_extensions.pyi @@ -22,7 +22,6 @@ from typing import ( NewType as NewType, NoReturn as NoReturn, Text as Text, - Tuple, Type as Type, TypeVar, ValuesView, @@ -53,6 +52,11 @@ Literal: _SpecialForm = ... def IntVar(name: str) -> Any: ... # returns a new TypeVar +if sys.version_info < (3, 8): + # Technically in 3.6 this inherited from GenericMeta. But let's not reflect that, since + # type checkers tend to assume that Protocols all have the ABCMeta metaclass. + class _ProtocolMeta(abc.ABCMeta): ... + # 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] @@ -82,7 +86,7 @@ if sys.version_info >= (3, 7): localns: dict[str, Any] | None = ..., include_extras: bool = ..., ) -> dict[str, Any]: ... - def get_args(tp: Any) -> Tuple[Any, ...]: ... + def get_args(tp: Any) -> tuple[Any, ...]: ... def get_origin(tp: Any) -> Any | None: ... Annotated: _SpecialForm = ... diff --git a/mypy/typeshed/stdlib/unicodedata.pyi b/mypy/typeshed/stdlib/unicodedata.pyi index 66c93f7439f7..ead25ba4062c 100644 --- a/mypy/typeshed/stdlib/unicodedata.pyi +++ b/mypy/typeshed/stdlib/unicodedata.pyi @@ -24,7 +24,7 @@ def name(__chr: str, __default: _T = ...) -> str | _T: ... def normalize(__form: str, __unistr: str) -> str: ... def numeric(__chr: str, __default: _T = ...) -> float | _T: ... -class UCD(object): +class UCD: # The methods below are constructed from the same array in C # (unicodedata_functions) and hence identical to the methods above. unidata_version: str diff --git a/mypy/typeshed/stdlib/unittest/__init__.pyi b/mypy/typeshed/stdlib/unittest/__init__.pyi index 8f0ef896fa0c..d3b0efaa83ff 100644 --- a/mypy/typeshed/stdlib/unittest/__init__.pyi +++ b/mypy/typeshed/stdlib/unittest/__init__.pyi @@ -10,15 +10,25 @@ from .case import ( skipIf as skipIf, skipUnless as skipUnless, ) +from .loader import ( + TestLoader as TestLoader, + defaultTestLoader as defaultTestLoader, + findTestCases as findTestCases, + getTestCaseNames as getTestCaseNames, + makeSuite as makeSuite, +) +from .main import TestProgram as TestProgram, main as main +from .result import TestResult as TestResult +from .runner import TextTestResult as TextTestResult, TextTestRunner as TextTestRunner +from .signals import ( + installHandler as installHandler, + registerResult as registerResult, + removeHandler as removeHandler, + removeResult as removeResult, +) +from .suite import BaseTestSuite as BaseTestSuite, TestSuite as TestSuite if sys.version_info >= (3, 8): from .case import addModuleCleanup as addModuleCleanup -from unittest.loader import * -from unittest.main import * -from unittest.result import TestResult as TestResult -from unittest.runner import * -from unittest.signals import * -from unittest.suite import * - def load_tests(loader: TestLoader, tests: TestSuite, pattern: str | None) -> TestSuite: ... diff --git a/mypy/typeshed/stdlib/unittest/_log.pyi b/mypy/typeshed/stdlib/unittest/_log.pyi new file mode 100644 index 000000000000..f9e406199cd4 --- /dev/null +++ b/mypy/typeshed/stdlib/unittest/_log.pyi @@ -0,0 +1,27 @@ +import logging +import sys +from types import TracebackType +from typing import ClassVar, Generic, NamedTuple, Type, TypeVar +from unittest.case import TestCase + +_L = TypeVar("_L", None, _LoggingWatcher) + +class _LoggingWatcher(NamedTuple): + records: list[logging.LogRecord] + output: list[str] + +class _AssertLogsContext(Generic[_L]): + LOGGING_FORMAT: ClassVar[str] + test_case: TestCase + logger_name: str + level: int + msg: None + if sys.version_info >= (3, 10): + def __init__(self, test_case: TestCase, logger_name: str, level: int, no_logs: bool) -> None: ... + no_logs: bool + else: + def __init__(self, test_case: TestCase, logger_name: str, level: int) -> None: ... + def __enter__(self) -> _L: ... + def __exit__( + self, exc_type: Type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None + ) -> bool | None: ... diff --git a/mypy/typeshed/stdlib/unittest/case.pyi b/mypy/typeshed/stdlib/unittest/case.pyi index 2ae07144373c..858bf38e700d 100644 --- a/mypy/typeshed/stdlib/unittest/case.pyi +++ b/mypy/typeshed/stdlib/unittest/case.pyi @@ -3,13 +3,14 @@ import logging import sys import unittest.result from _typeshed import Self -from collections.abc import Set # equivalent to typing.AbstractSet, not builtins.set +from collections.abc import Set as AbstractSet from contextlib import AbstractContextManager from types import TracebackType from typing import ( Any, AnyStr, Callable, + ClassVar, Container, Generic, Iterable, @@ -18,7 +19,6 @@ from typing import ( NoReturn, Pattern, Sequence, - Tuple, Type, TypeVar, overload, @@ -31,6 +31,33 @@ if sys.version_info >= (3, 9): _E = TypeVar("_E", bound=BaseException) _FT = TypeVar("_FT", bound=Callable[..., Any]) +DIFF_OMITTED: str + +class _BaseTestCaseContext: + def __init__(self, test_case: TestCase) -> None: ... + +if sys.version_info >= (3, 9): + from unittest._log import _AssertLogsContext, _LoggingWatcher +else: + # Unused dummy for _AssertLogsContext. Starting with Python 3.10, + # this is generic over the logging watcher, but in lower versions + # the watcher is hard-coded. + _L = TypeVar("_L") + class _LoggingWatcher(NamedTuple): + records: list[logging.LogRecord] + output: list[str] + class _AssertLogsContext(_BaseTestCaseContext, Generic[_L]): + LOGGING_FORMAT: ClassVar[str] + test_case: TestCase + logger_name: str + level: int + msg: None + def __init__(self, test_case: TestCase, logger_name: str, level: int) -> None: ... + def __enter__(self) -> _LoggingWatcher: ... + def __exit__( + self, exc_type: Type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None + ) -> bool | None: ... + if sys.version_info >= (3, 8): def addModuleCleanup(__function: Callable[..., Any], *args: Any, **kwargs: Any) -> None: ... def doModuleCleanups() -> None: ... @@ -74,26 +101,26 @@ class TestCase: def assertIsNotNone(self, obj: Any, msg: Any = ...) -> None: ... def assertIn(self, member: Any, container: Iterable[Any] | Container[Any], msg: Any = ...) -> None: ... def assertNotIn(self, member: Any, container: Iterable[Any] | Container[Any], msg: Any = ...) -> None: ... - def assertIsInstance(self, obj: Any, cls: type | Tuple[type, ...], msg: Any = ...) -> None: ... - def assertNotIsInstance(self, obj: Any, cls: type | Tuple[type, ...], msg: Any = ...) -> None: ... + def assertIsInstance(self, obj: Any, cls: type | tuple[type, ...], msg: Any = ...) -> None: ... + def assertNotIsInstance(self, obj: Any, cls: type | tuple[type, ...], msg: Any = ...) -> None: ... def assertGreater(self, a: Any, b: Any, msg: Any = ...) -> None: ... def assertGreaterEqual(self, a: Any, b: Any, msg: Any = ...) -> None: ... def assertLess(self, a: Any, b: Any, msg: Any = ...) -> None: ... def assertLessEqual(self, a: Any, b: Any, msg: Any = ...) -> None: ... @overload - def assertRaises( # type: ignore + def assertRaises( # type: ignore[misc] self, - expected_exception: Type[BaseException] | Tuple[Type[BaseException], ...], + expected_exception: Type[BaseException] | tuple[Type[BaseException], ...], callable: Callable[..., Any], *args: Any, **kwargs: Any, ) -> None: ... @overload - def assertRaises(self, expected_exception: Type[_E] | Tuple[Type[_E], ...], msg: Any = ...) -> _AssertRaisesContext[_E]: ... + def assertRaises(self, expected_exception: Type[_E] | tuple[Type[_E], ...], msg: Any = ...) -> _AssertRaisesContext[_E]: ... @overload - def assertRaisesRegex( # type: ignore + def assertRaisesRegex( # type: ignore[misc] self, - expected_exception: Type[BaseException] | Tuple[Type[BaseException], ...], + expected_exception: Type[BaseException] | tuple[Type[BaseException], ...], expected_regex: str | bytes | Pattern[str] | Pattern[bytes], callable: Callable[..., Any], *args: Any, @@ -102,20 +129,20 @@ class TestCase: @overload def assertRaisesRegex( self, - expected_exception: Type[_E] | Tuple[Type[_E], ...], + expected_exception: Type[_E] | tuple[Type[_E], ...], expected_regex: str | bytes | Pattern[str] | Pattern[bytes], msg: Any = ..., ) -> _AssertRaisesContext[_E]: ... @overload - def assertWarns( # type: ignore - self, expected_warning: Type[Warning] | Tuple[Type[Warning], ...], callable: Callable[..., Any], *args: Any, **kwargs: Any + def assertWarns( # type: ignore[misc] + self, expected_warning: Type[Warning] | tuple[Type[Warning], ...], callable: Callable[..., Any], *args: Any, **kwargs: Any ) -> None: ... @overload - def assertWarns(self, expected_warning: Type[Warning] | Tuple[Type[Warning], ...], msg: Any = ...) -> _AssertWarnsContext: ... + def assertWarns(self, expected_warning: Type[Warning] | tuple[Type[Warning], ...], msg: Any = ...) -> _AssertWarnsContext: ... @overload - def assertWarnsRegex( # type: ignore + def assertWarnsRegex( # type: ignore[misc] self, - expected_warning: Type[Warning] | Tuple[Type[Warning], ...], + expected_warning: Type[Warning] | tuple[Type[Warning], ...], expected_regex: str | bytes | Pattern[str] | Pattern[bytes], callable: Callable[..., Any], *args: Any, @@ -124,11 +151,17 @@ class TestCase: @overload def assertWarnsRegex( self, - expected_warning: Type[Warning] | Tuple[Type[Warning], ...], + expected_warning: Type[Warning] | tuple[Type[Warning], ...], expected_regex: str | bytes | Pattern[str] | Pattern[bytes], msg: Any = ..., ) -> _AssertWarnsContext: ... - def assertLogs(self, logger: str | logging.Logger | None = ..., level: int | str | None = ...) -> _AssertLogsContext: ... + def assertLogs( + self, logger: str | logging.Logger | None = ..., level: int | str | None = ... + ) -> _AssertLogsContext[_LoggingWatcher]: ... + if sys.version_info >= (3, 10): + def assertNoLogs( + self, logger: str | logging.Logger | None = ..., level: int | str | None = ... + ) -> _AssertLogsContext[None]: ... @overload def assertAlmostEqual( self, first: float, second: float, places: int | None = ..., msg: Any = ..., delta: float | None = ... @@ -166,8 +199,8 @@ class TestCase: self, seq1: Sequence[Any], seq2: Sequence[Any], msg: Any = ..., seq_type: Type[Sequence[Any]] | None = ... ) -> None: ... def assertListEqual(self, list1: list[Any], list2: list[Any], msg: Any = ...) -> None: ... - def assertTupleEqual(self, tuple1: Tuple[Any, ...], tuple2: Tuple[Any, ...], msg: Any = ...) -> None: ... - def assertSetEqual(self, set1: Set[object], set2: Set[object], msg: Any = ...) -> None: ... + def assertTupleEqual(self, tuple1: tuple[Any, ...], tuple2: tuple[Any, ...], msg: Any = ...) -> None: ... + def assertSetEqual(self, set1: AbstractSet[object], set2: AbstractSet[object], msg: Any = ...) -> None: ... def assertDictEqual(self, d1: Mapping[Any, object], d2: Mapping[Any, object], msg: Any = ...) -> None: ... def fail(self, msg: Any = ...) -> NoReturn: ... def countTestCases(self) -> int: ... @@ -186,49 +219,53 @@ class TestCase: def doClassCleanups(cls) -> None: ... def _formatMessage(self, msg: str | None, standardMsg: str) -> str: ... # undocumented def _getAssertEqualityFunc(self, first: Any, second: Any) -> Callable[..., None]: ... # undocumented - # below is deprecated - def failUnlessEqual(self, first: Any, second: Any, msg: Any = ...) -> None: ... - def assertEquals(self, first: Any, second: Any, msg: Any = ...) -> None: ... - def failIfEqual(self, first: Any, second: Any, msg: Any = ...) -> None: ... - def assertNotEquals(self, first: Any, second: Any, msg: Any = ...) -> None: ... - def failUnless(self, expr: bool, msg: Any = ...) -> None: ... - def assert_(self, expr: bool, msg: Any = ...) -> None: ... - def failIf(self, expr: bool, msg: Any = ...) -> None: ... - @overload - def failUnlessRaises( # type: ignore - self, - exception: Type[BaseException] | Tuple[Type[BaseException], ...], - callable: Callable[..., Any] = ..., - *args: Any, - **kwargs: Any, - ) -> None: ... - @overload - def failUnlessRaises(self, exception: Type[_E] | Tuple[Type[_E], ...], msg: Any = ...) -> _AssertRaisesContext[_E]: ... - def failUnlessAlmostEqual(self, first: float, second: float, places: int = ..., msg: Any = ...) -> None: ... - def assertAlmostEquals(self, first: float, second: float, places: int = ..., msg: Any = ..., delta: float = ...) -> None: ... - def failIfAlmostEqual(self, first: float, second: float, places: int = ..., msg: Any = ...) -> None: ... - def assertNotAlmostEquals( - self, first: float, second: float, places: int = ..., msg: Any = ..., delta: float = ... - ) -> None: ... - def assertRegexpMatches(self, text: AnyStr, regex: AnyStr | Pattern[AnyStr], msg: Any = ...) -> None: ... - def assertNotRegexpMatches(self, text: AnyStr, regex: AnyStr | Pattern[AnyStr], msg: Any = ...) -> None: ... - @overload - def assertRaisesRegexp( # type: ignore - self, - exception: Type[BaseException] | Tuple[Type[BaseException], ...], - expected_regex: str | bytes | Pattern[str] | Pattern[bytes], - callable: Callable[..., Any], - *args: Any, - **kwargs: Any, - ) -> None: ... - @overload - def assertRaisesRegexp( - self, - exception: Type[_E] | Tuple[Type[_E], ...], - expected_regex: str | bytes | Pattern[str] | Pattern[bytes], - msg: Any = ..., - ) -> _AssertRaisesContext[_E]: ... - def assertDictContainsSubset(self, subset: Mapping[Any, Any], dictionary: Mapping[Any, Any], msg: object = ...) -> None: ... + if sys.version_info < (3, 11): + def failUnlessEqual(self, first: Any, second: Any, msg: Any = ...) -> None: ... + def assertEquals(self, first: Any, second: Any, msg: Any = ...) -> None: ... + def failIfEqual(self, first: Any, second: Any, msg: Any = ...) -> None: ... + def assertNotEquals(self, first: Any, second: Any, msg: Any = ...) -> None: ... + def failUnless(self, expr: bool, msg: Any = ...) -> None: ... + def assert_(self, expr: bool, msg: Any = ...) -> None: ... + def failIf(self, expr: bool, msg: Any = ...) -> None: ... + @overload + def failUnlessRaises( # type: ignore[misc] + self, + exception: Type[BaseException] | tuple[Type[BaseException], ...], + callable: Callable[..., Any] = ..., + *args: Any, + **kwargs: Any, + ) -> None: ... + @overload + def failUnlessRaises(self, exception: Type[_E] | tuple[Type[_E], ...], msg: Any = ...) -> _AssertRaisesContext[_E]: ... + def failUnlessAlmostEqual(self, first: float, second: float, places: int = ..., msg: Any = ...) -> None: ... + def assertAlmostEquals( + self, first: float, second: float, places: int = ..., msg: Any = ..., delta: float = ... + ) -> None: ... + def failIfAlmostEqual(self, first: float, second: float, places: int = ..., msg: Any = ...) -> None: ... + def assertNotAlmostEquals( + self, first: float, second: float, places: int = ..., msg: Any = ..., delta: float = ... + ) -> None: ... + def assertRegexpMatches(self, text: AnyStr, regex: AnyStr | Pattern[AnyStr], msg: Any = ...) -> None: ... + def assertNotRegexpMatches(self, text: AnyStr, regex: AnyStr | Pattern[AnyStr], msg: Any = ...) -> None: ... + @overload + def assertRaisesRegexp( # type: ignore[misc] + self, + exception: Type[BaseException] | tuple[Type[BaseException], ...], + expected_regex: str | bytes | Pattern[str] | Pattern[bytes], + callable: Callable[..., Any], + *args: Any, + **kwargs: Any, + ) -> None: ... + @overload + def assertRaisesRegexp( + self, + exception: Type[_E] | tuple[Type[_E], ...], + expected_regex: str | bytes | Pattern[str] | Pattern[bytes], + msg: Any = ..., + ) -> _AssertRaisesContext[_E]: ... + def assertDictContainsSubset( + self, subset: Mapping[Any, Any], dictionary: Mapping[Any, Any], msg: object = ... + ) -> None: ... class FunctionTestCase(TestCase): def __init__( @@ -240,10 +277,6 @@ class FunctionTestCase(TestCase): ) -> None: ... def runTest(self) -> None: ... -class _LoggingWatcher(NamedTuple): - records: list[logging.LogRecord] - output: list[str] - class _AssertRaisesContext(Generic[_E]): exception: _E def __enter__(self: Self) -> Self: ... @@ -262,16 +295,3 @@ class _AssertWarnsContext: def __exit__( self, exc_type: Type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None ) -> None: ... - -class _AssertLogsContext: - LOGGING_FORMAT: str - records: list[logging.LogRecord] - output: list[str] - def __init__(self, test_case: TestCase, logger_name: str, level: int) -> None: ... - if sys.version_info >= (3, 10): - def __enter__(self) -> _LoggingWatcher | None: ... - else: - def __enter__(self) -> _LoggingWatcher: ... - def __exit__( - self, exc_type: Type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None - ) -> bool | None: ... diff --git a/mypy/typeshed/stdlib/unittest/loader.pyi b/mypy/typeshed/stdlib/unittest/loader.pyi index d3cb4cef733b..aca7e4f9554f 100644 --- a/mypy/typeshed/stdlib/unittest/loader.pyi +++ b/mypy/typeshed/stdlib/unittest/loader.pyi @@ -3,10 +3,12 @@ import unittest.case import unittest.result import unittest.suite from types import ModuleType -from typing import Any, Callable, List, Sequence, Type +from typing import Any, Callable, Pattern, Sequence, Type _SortComparisonMethod = Callable[[str, str], int] -_SuiteClass = Callable[[List[unittest.case.TestCase]], unittest.suite.TestSuite] +_SuiteClass = Callable[[list[unittest.case.TestCase]], unittest.suite.TestSuite] + +VALID_MODULE_NAME: Pattern[str] class TestLoader: errors: list[Type[BaseException]] diff --git a/mypy/typeshed/stdlib/unittest/main.pyi b/mypy/typeshed/stdlib/unittest/main.pyi index cd887cec27d0..6d1117ecaf79 100644 --- a/mypy/typeshed/stdlib/unittest/main.pyi +++ b/mypy/typeshed/stdlib/unittest/main.pyi @@ -6,6 +6,9 @@ import unittest.suite from types import ModuleType from typing import Any, Iterable, Protocol, Type +MAIN_EXAMPLES: str +MODULE_EXAMPLES: str + class _TestRunner(Protocol): def run(self, test: unittest.suite.TestSuite | unittest.case.TestCase) -> unittest.result.TestResult: ... diff --git a/mypy/typeshed/stdlib/unittest/mock.pyi b/mypy/typeshed/stdlib/unittest/mock.pyi index 567ce346f464..72d0bab95c2e 100644 --- a/mypy/typeshed/stdlib/unittest/mock.pyi +++ b/mypy/typeshed/stdlib/unittest/mock.pyi @@ -1,27 +1,61 @@ import sys -from typing import Any, Callable, Generic, Iterable, List, Mapping, Sequence, Tuple, Type, TypeVar, overload +from typing import Any, Awaitable, Callable, Generic, Iterable, Mapping, Sequence, Type, TypeVar, overload _T = TypeVar("_T") _TT = TypeVar("_TT", bound=Type[Any]) _R = TypeVar("_R") -__all__ = [ - "Mock", - "MagicMock", - "patch", - "sentinel", - "DEFAULT", - "ANY", - "call", - "create_autospec", - "AsyncMock", - "FILTER_DIR", - "NonCallableMock", - "NonCallableMagicMock", - "mock_open", - "PropertyMock", - "seal", -] +if sys.version_info >= (3, 8): + __all__ = ( + "Mock", + "MagicMock", + "patch", + "sentinel", + "DEFAULT", + "ANY", + "call", + "create_autospec", + "AsyncMock", + "FILTER_DIR", + "NonCallableMock", + "NonCallableMagicMock", + "mock_open", + "PropertyMock", + "seal", + ) +elif sys.version_info >= (3, 7): + __all__ = ( + "Mock", + "MagicMock", + "patch", + "sentinel", + "DEFAULT", + "ANY", + "call", + "create_autospec", + "FILTER_DIR", + "NonCallableMock", + "NonCallableMagicMock", + "mock_open", + "PropertyMock", + "seal", + ) +else: + __all__ = ( + "Mock", + "MagicMock", + "patch", + "sentinel", + "DEFAULT", + "ANY", + "call", + "create_autospec", + "FILTER_DIR", + "NonCallableMock", + "NonCallableMagicMock", + "mock_open", + "PropertyMock", + ) __version__: str FILTER_DIR: Any @@ -39,7 +73,7 @@ class _Sentinel: sentinel: Any DEFAULT: Any -class _Call(Tuple[Any, ...]): +class _Call(tuple[Any, ...]): def __new__( cls, value: Any = ..., name: Any | None = ..., parent: Any | None = ..., two: bool = ..., from_kall: bool = ... ) -> Any: ... @@ -53,25 +87,22 @@ class _Call(Tuple[Any, ...]): __ne__: Any def __call__(self, *args: Any, **kwargs: Any) -> _Call: ... def __getattr__(self, attr: Any) -> Any: ... - def count(self, *args: Any, **kwargs: Any) -> Any: ... - def index(self, *args: Any, **kwargs: Any) -> Any: ... + if sys.version_info >= (3, 8): + @property + def args(self): ... + @property + def kwargs(self): ... def call_list(self) -> Any: ... call: _Call -class _CallList(List[_Call]): +class _CallList(list[_Call]): def __contains__(self, value: Any) -> bool: ... -class _MockIter: - obj: Any - def __init__(self, obj: Any) -> None: ... - def __iter__(self) -> Any: ... - def __next__(self) -> Any: ... - class Base: def __init__(self, *args: Any, **kwargs: Any) -> None: ... -class NonCallableMock(Base, Any): # type: ignore +class NonCallableMock(Base, Any): def __new__(__cls, *args: Any, **kw: Any) -> NonCallableMock: ... def __init__( self, @@ -124,7 +155,7 @@ class NonCallableMock(Base, Any): # type: ignore call_args_list: _CallList mock_calls: _CallList def _format_mock_call_signature(self, args: Any, kwargs: Any) -> str: ... - def _call_matcher(self, _call: Tuple[_Call, ...]) -> _Call: ... + def _call_matcher(self, _call: tuple[_Call, ...]) -> _Call: ... def _get_child_mock(self, **kw: Any) -> NonCallableMock: ... class CallableMixin(Base): @@ -143,7 +174,10 @@ class CallableMixin(Base): _new_parent: Any | None = ..., **kwargs: Any, ) -> None: ... - def __call__(_mock_self, *args: Any, **kwargs: Any) -> Any: ... + if sys.version_info >= (3, 8): + def __call__(self, *args: Any, **kwargs: Any) -> Any: ... + else: + def __call__(_mock_self, *args: Any, **kwargs: Any) -> Any: ... class Mock(CallableMixin, NonCallableMock): ... @@ -162,25 +196,45 @@ class _patch(Generic[_T]): additional_patchers: Any # If new==DEFAULT, self is _patch[Any]. Ideally we'd be able to add an overload for it so that self is _patch[MagicMock], # but that's impossible with the current type system. - def __init__( - self: _patch[_T], - getter: Callable[[], Any], - attribute: str, - new: _T, - spec: Any | None, - create: bool, - spec_set: Any | None, - autospec: Any | None, - new_callable: Any | None, - kwargs: Mapping[str, Any], - ) -> None: ... + if sys.version_info >= (3, 10): + def __init__( + self: _patch[_T], + getter: Callable[[], Any], + attribute: str, + new: _T, + spec: Any | None, + create: bool, + spec_set: Any | None, + autospec: Any | None, + new_callable: Any | None, + kwargs: Mapping[str, Any], + *, + unsafe: bool = ..., + ) -> None: ... + else: + def __init__( + self: _patch[_T], + getter: Callable[[], Any], + attribute: str, + new: _T, + spec: Any | None, + create: bool, + spec_set: Any | None, + autospec: Any | None, + new_callable: Any | None, + 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]: ... + if sys.version_info >= (3, 8): + def decoration_helper(self, patched, args, keywargs): ... def decorate_class(self, klass: _TT) -> _TT: ... def decorate_callable(self, func: Callable[..., _R]) -> Callable[..., _R]: ... + if sys.version_info >= (3, 8): + def decorate_async_callable(self, func: Callable[..., Awaitable[_R]]) -> Callable[..., Awaitable[_R]]: ... def get_original(self) -> tuple[Any, bool]: ... target: Any temp_original: Any @@ -210,7 +264,7 @@ class _patcher: # Ideally we'd be able to add an overload for it so that the return type is _patch[MagicMock], # but that's impossible with the current type system. @overload - def __call__( # type: ignore + def __call__( # type: ignore[misc] self, target: Any, new: _T, @@ -222,7 +276,7 @@ class _patcher: **kwargs: Any, ) -> _patch[_T]: ... @overload - def __call__( # type: ignore + def __call__( self, target: Any, *, @@ -235,7 +289,7 @@ class _patcher: ) -> _patch[MagicMock | AsyncMock]: ... else: @overload - def __call__( # type: ignore + def __call__( # type: ignore[misc] self, target: Any, new: _T, @@ -247,7 +301,7 @@ class _patcher: **kwargs: Any, ) -> _patch[_T]: ... @overload - def __call__( # type: ignore + def __call__( self, target: Any, *, @@ -260,7 +314,7 @@ class _patcher: ) -> _patch[MagicMock]: ... if sys.version_info >= (3, 8): @overload - def object( # type: ignore + def object( # type: ignore[misc] self, target: Any, attribute: str, @@ -273,7 +327,7 @@ class _patcher: **kwargs: Any, ) -> _patch[_T]: ... @overload - def object( # type: ignore + def object( self, target: Any, attribute: str, @@ -287,7 +341,7 @@ class _patcher: ) -> _patch[MagicMock | AsyncMock]: ... else: @overload - def object( # type: ignore + def object( # type: ignore[misc] self, target: Any, attribute: str, @@ -300,7 +354,7 @@ class _patcher: **kwargs: Any, ) -> _patch[_T]: ... @overload - def object( # type: ignore + def object( self, target: Any, attribute: str, @@ -357,10 +411,11 @@ if sys.version_info >= (3, 8): class MagicProxy: name: Any parent: Any - def __init__(self, name: Any, parent: Any) -> None: ... - def __call__(self, *args: Any, **kwargs: Any) -> Any: ... - def create_mock(self) -> Any: ... - def __get__(self, obj: Any, _type: Any | None = ...) -> Any: ... + def __init__(self, name, parent) -> None: ... + if sys.version_info < (3, 8): + def __call__(self, *args: Any, **kwargs: Any) -> Any: ... + def create_mock(self): ... + def __get__(self, obj, _type: Any | None = ...): ... class _ANY: def __eq__(self, other: Any) -> bool: ... diff --git a/mypy/typeshed/stdlib/unittest/result.pyi b/mypy/typeshed/stdlib/unittest/result.pyi index 20c43cf38aa4..9a19aef77d21 100644 --- a/mypy/typeshed/stdlib/unittest/result.pyi +++ b/mypy/typeshed/stdlib/unittest/result.pyi @@ -1,11 +1,14 @@ import unittest.case from types import TracebackType -from typing import Any, Callable, TextIO, Tuple, Type, TypeVar, Union +from typing import Any, Callable, TextIO, Type, TypeVar, Union -_SysExcInfoType = Union[Tuple[Type[BaseException], BaseException, TracebackType], Tuple[None, None, None]] +_SysExcInfoType = Union[tuple[Type[BaseException], BaseException, TracebackType], tuple[None, None, None]] _F = TypeVar("_F", bound=Callable[..., Any]) +STDOUT_LINE: str +STDERR_LINE: str + # undocumented def failfast(method: _F) -> _F: ... diff --git a/mypy/typeshed/stdlib/unittest/runner.pyi b/mypy/typeshed/stdlib/unittest/runner.pyi index bf8f3c05c1cd..85481880ab17 100644 --- a/mypy/typeshed/stdlib/unittest/runner.pyi +++ b/mypy/typeshed/stdlib/unittest/runner.pyi @@ -17,7 +17,7 @@ class TextTestResult(unittest.result.TestResult): def printErrors(self) -> None: ... def printErrorList(self, flavour: str, errors: tuple[unittest.case.TestCase, str]) -> None: ... -class TextTestRunner(object): +class TextTestRunner: resultclass: _ResultClassType def __init__( self, diff --git a/mypy/typeshed/stdlib/unittest/signals.pyi b/mypy/typeshed/stdlib/unittest/signals.pyi index 375b7d736a35..e6f5f95e1eb1 100644 --- a/mypy/typeshed/stdlib/unittest/signals.pyi +++ b/mypy/typeshed/stdlib/unittest/signals.pyi @@ -11,4 +11,4 @@ def removeResult(result: unittest.result.TestResult) -> bool: ... @overload def removeHandler(method: None = ...) -> None: ... @overload -def removeHandler(method: Callable[_P, _T]) -> Callable[_P, _T]: ... # type: ignore +def removeHandler(method: Callable[_P, _T]) -> Callable[_P, _T]: ... diff --git a/mypy/typeshed/stdlib/unittest/util.pyi b/mypy/typeshed/stdlib/unittest/util.pyi index ab6ed053a6ff..680ca24b7c33 100644 --- a/mypy/typeshed/stdlib/unittest/util.pyi +++ b/mypy/typeshed/stdlib/unittest/util.pyi @@ -1,7 +1,7 @@ -from typing import Any, Sequence, Tuple, TypeVar +from typing import Any, Sequence, TypeVar _T = TypeVar("_T") -_Mismatch = Tuple[_T, _T, int] +_Mismatch = tuple[_T, _T, int] _MAX_LENGTH: int _PLACEHOLDER_LEN: int diff --git a/mypy/typeshed/stdlib/urllib/parse.pyi b/mypy/typeshed/stdlib/urllib/parse.pyi index a2467e96c43c..7404b5382014 100644 --- a/mypy/typeshed/stdlib/urllib/parse.pyi +++ b/mypy/typeshed/stdlib/urllib/parse.pyi @@ -1,5 +1,5 @@ import sys -from typing import Any, AnyStr, Callable, Generic, Mapping, NamedTuple, Sequence, Tuple, Union, overload +from typing import Any, AnyStr, Callable, Generic, Mapping, NamedTuple, Sequence, Union, overload if sys.version_info >= (3, 9): from types import GenericAlias @@ -35,7 +35,7 @@ class _NetlocResultMixinBase(Generic[AnyStr]): class _NetlocResultMixinStr(_NetlocResultMixinBase[str], _ResultMixinStr): ... class _NetlocResultMixinBytes(_NetlocResultMixinBase[bytes], _ResultMixinBytes): ... -class _DefragResultBase(Tuple[Any, ...], Generic[AnyStr]): +class _DefragResultBase(tuple[Any, ...], Generic[AnyStr]): url: AnyStr fragment: AnyStr @@ -116,10 +116,10 @@ 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]]], doseq: bool = ..., - safe: AnyStr = ..., + safe: _Str = ..., encoding: str = ..., errors: str = ..., - quote_via: Callable[[str, AnyStr, str, str], str] = ..., + quote_via: Callable[[AnyStr, _Str, str, str], str] = ..., ) -> str: ... def urljoin(base: AnyStr, url: AnyStr | None, allow_fragments: bool = ...) -> AnyStr: ... @overload diff --git a/mypy/typeshed/stdlib/urllib/request.pyi b/mypy/typeshed/stdlib/urllib/request.pyi index 3c8a6facde6f..3749d7a390ea 100644 --- a/mypy/typeshed/stdlib/urllib/request.pyi +++ b/mypy/typeshed/stdlib/urllib/request.pyi @@ -4,7 +4,7 @@ from _typeshed import StrOrBytesPath from email.message import Message from http.client import HTTPMessage, HTTPResponse, _HTTPConnectionProtocol from http.cookiejar import CookieJar -from typing import IO, Any, Callable, ClassVar, Mapping, NoReturn, Pattern, Sequence, Tuple, TypeVar, overload +from typing import IO, Any, Callable, ClassVar, Mapping, NoReturn, Pattern, Sequence, TypeVar, overload from urllib.error import HTTPError from urllib.response import addclosehook, addinfourl @@ -196,9 +196,9 @@ class HTTPSHandler(AbstractHTTPHandler): def https_request(self, request: Request) -> Request: ... # undocumented class FileHandler(BaseHandler): - names: ClassVar[Tuple[str, ...] | None] # undocumented + names: ClassVar[tuple[str, ...] | None] # undocumented def file_open(self, req: Request) -> addinfourl: ... - def get_names(self) -> Tuple[str, ...]: ... # undocumented + def get_names(self) -> tuple[str, ...]: ... # undocumented def open_local_file(self, req: Request) -> addinfourl: ... # undocumented class DataHandler(BaseHandler): diff --git a/mypy/typeshed/stdlib/urllib/response.pyi b/mypy/typeshed/stdlib/urllib/response.pyi index 647ebf874432..18b498b40744 100644 --- a/mypy/typeshed/stdlib/urllib/response.pyi +++ b/mypy/typeshed/stdlib/urllib/response.pyi @@ -2,7 +2,7 @@ import sys from _typeshed import Self from email.message import Message from types import TracebackType -from typing import IO, Any, BinaryIO, Callable, Iterable, Tuple, Type, TypeVar +from typing import IO, Any, BinaryIO, Callable, Iterable, Type, TypeVar _AIUT = TypeVar("_AIUT", bound=addbase) @@ -37,7 +37,7 @@ class addbase(BinaryIO): class addclosehook(addbase): closehook: Callable[..., object] - hookargs: Tuple[Any, ...] + hookargs: tuple[Any, ...] def __init__(self, fp: IO[bytes], closehook: Callable[..., object], *hookargs: Any) -> None: ... class addinfo(addbase): diff --git a/mypy/typeshed/stdlib/uuid.pyi b/mypy/typeshed/stdlib/uuid.pyi index da13d819fbdf..782c0491ffb2 100644 --- a/mypy/typeshed/stdlib/uuid.pyi +++ b/mypy/typeshed/stdlib/uuid.pyi @@ -1,10 +1,10 @@ import sys -from typing import Any, Tuple +from typing import Any # Because UUID has properties called int and bytes we need to rename these temporarily. _Int = int _Bytes = bytes -_FieldsType = Tuple[int, int, int, int, int, int] +_FieldsType = tuple[int, int, int, int, int, int] if sys.version_info >= (3, 7): from enum import Enum diff --git a/mypy/typeshed/stdlib/venv/__init__.pyi b/mypy/typeshed/stdlib/venv/__init__.pyi index 25cf615a3243..7650e87d98b4 100644 --- a/mypy/typeshed/stdlib/venv/__init__.pyi +++ b/mypy/typeshed/stdlib/venv/__init__.pyi @@ -3,6 +3,9 @@ from _typeshed import StrOrBytesPath from types import SimpleNamespace from typing import Sequence +if sys.version_info >= (3, 9): + CORE_VENV_DEPS: tuple[str, ...] + class EnvBuilder: system_site_packages: bool clear: bool diff --git a/mypy/typeshed/stdlib/weakref.pyi b/mypy/typeshed/stdlib/weakref.pyi index dbb6b49f2f2e..fd1cad7fe840 100644 --- a/mypy/typeshed/stdlib/weakref.pyi +++ b/mypy/typeshed/stdlib/weakref.pyi @@ -1,5 +1,5 @@ from _weakrefset import WeakSet as WeakSet -from typing import Any, Callable, Generic, Iterable, Iterator, Mapping, MutableMapping, Tuple, Type, TypeVar, overload +from typing import Any, Callable, Generic, Iterable, Iterator, Mapping, MutableMapping, Type, TypeVar, overload from _weakref import ( CallableProxyType as CallableProxyType, @@ -17,7 +17,7 @@ _KT = TypeVar("_KT") _VT = TypeVar("_VT") _CallableT = TypeVar("_CallableT", bound=Callable[..., Any]) -ProxyTypes: Tuple[Type[Any], ...] +ProxyTypes: tuple[Type[Any], ...] class WeakMethod(ref[_CallableT], Generic[_CallableT]): def __new__(cls, meth: _CallableT, callback: Callable[[_CallableT], object] | None = ...) -> WeakMethod[_CallableT]: ... @@ -37,9 +37,9 @@ class WeakValueDictionary(MutableMapping[_KT, _VT]): def __str__(self) -> str: ... def copy(self) -> WeakValueDictionary[_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 keys(self) -> Iterator[_KT]: ... # type: ignore[override] + def values(self) -> Iterator[_VT]: ... # type: ignore[override] + def items(self) -> Iterator[tuple[_KT, _VT]]: ... # type: ignore[override] def itervaluerefs(self) -> Iterator[KeyedRef[_KT, _VT]]: ... def valuerefs(self) -> list[KeyedRef[_KT, _VT]]: ... def setdefault(self, key: _KT, default: _VT = ...) -> _VT: ... @@ -68,9 +68,9 @@ class WeakKeyDictionary(MutableMapping[_KT, _VT]): def __str__(self) -> str: ... def copy(self) -> WeakKeyDictionary[_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 keys(self) -> Iterator[_KT]: ... # type: ignore[override] + def values(self) -> Iterator[_VT]: ... # type: ignore[override] + def items(self) -> Iterator[tuple[_KT, _VT]]: ... # type: ignore[override] def keyrefs(self) -> list[ref[_KT]]: ... def setdefault(self, key: _KT, default: _VT = ...) -> _VT: ... @overload @@ -81,7 +81,7 @@ class WeakKeyDictionary(MutableMapping[_KT, _VT]): 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/webbrowser.pyi b/mypy/typeshed/stdlib/webbrowser.pyi index c85288cc562f..459d886ac930 100644 --- a/mypy/typeshed/stdlib/webbrowser.pyi +++ b/mypy/typeshed/stdlib/webbrowser.pyi @@ -28,14 +28,9 @@ class BaseBrowser: def open_new_tab(self, url: str) -> bool: ... class GenericBrowser(BaseBrowser): - args: list[str] - name: str - basename: str def __init__(self, name: str | Sequence[str]) -> None: ... - def open(self, url: str, new: int = ..., autoraise: bool = ...) -> bool: ... -class BackgroundBrowser(GenericBrowser): - def open(self, url: str, new: int = ..., autoraise: bool = ...) -> bool: ... +class BackgroundBrowser(GenericBrowser): ... class UnixBrowser(BaseBrowser): raise_opts: list[str] | None @@ -45,59 +40,21 @@ class UnixBrowser(BaseBrowser): remote_action: str remote_action_newwin: str remote_action_newtab: str - def open(self, url: str, new: int = ..., autoraise: bool = ...) -> bool: ... -class Mozilla(UnixBrowser): - remote_args: list[str] - remote_action: str - remote_action_newwin: str - remote_action_newtab: str - background: bool +class Mozilla(UnixBrowser): ... class Galeon(UnixBrowser): raise_opts: list[str] - remote_args: list[str] - remote_action: str - remote_action_newwin: str - background: bool -class Chrome(UnixBrowser): - remote_args: list[str] - remote_action: str - remote_action_newwin: str - remote_action_newtab: str - background: bool - -class Opera(UnixBrowser): - remote_args: list[str] - remote_action: str - remote_action_newwin: str - remote_action_newtab: str - background: bool - -class Elinks(UnixBrowser): - remote_args: list[str] - remote_action: str - remote_action_newwin: str - remote_action_newtab: str - background: bool - redirect_stdout: bool - -class Konqueror(BaseBrowser): - def open(self, url: str, new: int = ..., autoraise: bool = ...) -> bool: ... - -class Grail(BaseBrowser): - def open(self, url: str, new: int = ..., autoraise: bool = ...) -> bool: ... +class Chrome(UnixBrowser): ... +class Opera(UnixBrowser): ... +class Elinks(UnixBrowser): ... +class Konqueror(BaseBrowser): ... +class Grail(BaseBrowser): ... if sys.platform == "win32": - class WindowsDefault(BaseBrowser): - def open(self, url: str, new: int = ..., autoraise: bool = ...) -> bool: ... + class WindowsDefault(BaseBrowser): ... if sys.platform == "darwin": - class MacOSX(BaseBrowser): - name: str - def __init__(self, name: str) -> None: ... - def open(self, url: str, new: int = ..., autoraise: bool = ...) -> bool: ... - class MacOSXOSAScript(BaseBrowser): - def __init__(self, name: str) -> None: ... - def open(self, url: str, new: int = ..., autoraise: bool = ...) -> bool: ... + class MacOSX(BaseBrowser): ... + class MacOSXOSAScript(BaseBrowser): ... # In runtime this class does not have `name` and `basename` diff --git a/mypy/typeshed/stdlib/winreg.pyi b/mypy/typeshed/stdlib/winreg.pyi index 5fff1104e246..57f0c4b3ddba 100644 --- a/mypy/typeshed/stdlib/winreg.pyi +++ b/mypy/typeshed/stdlib/winreg.pyi @@ -1,101 +1,101 @@ +import sys from _typeshed import Self from types import TracebackType from typing import Any, Type, Union -from typing_extensions import final +from typing_extensions import Literal, final -_KeyType = Union[HKEYType, int] +if sys.platform == "win32": + _KeyType = Union[HKEYType, int] + def CloseKey(__hkey: _KeyType) -> None: ... + def ConnectRegistry(__computer_name: str | None, __key: _KeyType) -> HKEYType: ... + def CreateKey(__key: _KeyType, __sub_key: str | None) -> HKEYType: ... + def CreateKeyEx(key: _KeyType, sub_key: str | None, reserved: int = ..., access: int = ...) -> HKEYType: ... + 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 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 QueryValue(__key: _KeyType, __sub_key: str | None) -> str: ... + 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( + __key: _KeyType, __value_name: str | None, __reserved: Any, __type: int, __value: str | int + ) -> None: ... # reserved is ignored + def DisableReflectionKey(__key: _KeyType) -> None: ... + def EnableReflectionKey(__key: _KeyType) -> None: ... + def QueryReflectionKey(__key: _KeyType) -> bool: ... + HKEY_CLASSES_ROOT: int + HKEY_CURRENT_USER: int + HKEY_LOCAL_MACHINE: int + HKEY_USERS: int + HKEY_PERFORMANCE_DATA: int + HKEY_CURRENT_CONFIG: int + HKEY_DYN_DATA: int -def CloseKey(__hkey: _KeyType) -> None: ... -def ConnectRegistry(__computer_name: str | None, __key: _KeyType) -> HKEYType: ... -def CreateKey(__key: _KeyType, __sub_key: str | None) -> HKEYType: ... -def CreateKeyEx(key: _KeyType, sub_key: str | None, reserved: int = ..., access: int = ...) -> HKEYType: ... -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 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 QueryValue(__key: _KeyType, __sub_key: str | None) -> str: ... -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( - __key: _KeyType, __value_name: str | None, __reserved: Any, __type: int, __value: str | int -) -> None: ... # reserved is ignored -def DisableReflectionKey(__key: _KeyType) -> None: ... -def EnableReflectionKey(__key: _KeyType) -> None: ... -def QueryReflectionKey(__key: _KeyType) -> bool: ... + KEY_ALL_ACCESS: Literal[983103] + KEY_WRITE: Literal[131078] + KEY_READ: Literal[131097] + KEY_EXECUTE: Literal[131097] + KEY_QUERY_VALUE: Literal[1] + KEY_SET_VALUE: Literal[2] + KEY_CREATE_SUB_KEY: Literal[4] + KEY_ENUMERATE_SUB_KEYS: Literal[8] + KEY_NOTIFY: Literal[16] + KEY_CREATE_LINK: Literal[32] -HKEY_CLASSES_ROOT: int -HKEY_CURRENT_USER: int -HKEY_LOCAL_MACHINE: int -HKEY_USERS: int -HKEY_PERFORMANCE_DATA: int -HKEY_CURRENT_CONFIG: int -HKEY_DYN_DATA: int + KEY_WOW64_64KEY: Literal[256] + KEY_WOW64_32KEY: Literal[512] -KEY_ALL_ACCESS: int -KEY_WRITE: int -KEY_READ: int -KEY_EXECUTE: int -KEY_QUERY_VALUE: int -KEY_SET_VALUE: int -KEY_CREATE_SUB_KEY: int -KEY_ENUMERATE_SUB_KEYS: int -KEY_NOTIFY: int -KEY_CREATE_LINK: int + REG_BINARY: Literal[3] + REG_DWORD: Literal[4] + REG_DWORD_LITTLE_ENDIAN: Literal[4] + REG_DWORD_BIG_ENDIAN: Literal[5] + REG_EXPAND_SZ: Literal[2] + REG_LINK: Literal[6] + REG_MULTI_SZ: Literal[7] + REG_NONE: Literal[0] + REG_QWORD: Literal[11] + REG_QWORD_LITTLE_ENDIAN: Literal[11] + REG_RESOURCE_LIST: Literal[8] + REG_FULL_RESOURCE_DESCRIPTOR: Literal[9] + REG_RESOURCE_REQUIREMENTS_LIST: Literal[10] + REG_SZ: Literal[1] -KEY_WOW64_64KEY: int -KEY_WOW64_32KEY: int + REG_CREATED_NEW_KEY: int # undocumented + REG_LEGAL_CHANGE_FILTER: int # undocumented + REG_LEGAL_OPTION: int # undocumented + REG_NOTIFY_CHANGE_ATTRIBUTES: int # undocumented + REG_NOTIFY_CHANGE_LAST_SET: int # undocumented + REG_NOTIFY_CHANGE_NAME: int # undocumented + REG_NOTIFY_CHANGE_SECURITY: int # undocumented + REG_NO_LAZY_FLUSH: int # undocumented + REG_OPENED_EXISTING_KEY: int # undocumented + REG_OPTION_BACKUP_RESTORE: int # undocumented + REG_OPTION_CREATE_LINK: int # undocumented + REG_OPTION_NON_VOLATILE: int # undocumented + REG_OPTION_OPEN_LINK: int # undocumented + REG_OPTION_RESERVED: int # undocumented + REG_OPTION_VOLATILE: int # undocumented + REG_REFRESH_HIVE: int # undocumented + REG_WHOLE_HIVE_VOLATILE: int # undocumented -REG_BINARY: int -REG_DWORD: int -REG_DWORD_LITTLE_ENDIAN: int -REG_DWORD_BIG_ENDIAN: int -REG_EXPAND_SZ: int -REG_LINK: int -REG_MULTI_SZ: int -REG_NONE: int -REG_QWORD: int -REG_QWORD_LITTLE_ENDIAN: int -REG_RESOURCE_LIST: int -REG_FULL_RESOURCE_DESCRIPTOR: int -REG_RESOURCE_REQUIREMENTS_LIST: int -REG_SZ: int + error = OSError -REG_CREATED_NEW_KEY: int # undocumented -REG_LEGAL_CHANGE_FILTER: int # undocumented -REG_LEGAL_OPTION: int # undocumented -REG_NOTIFY_CHANGE_ATTRIBUTES: int # undocumented -REG_NOTIFY_CHANGE_LAST_SET: int # undocumented -REG_NOTIFY_CHANGE_NAME: int # undocumented -REG_NOTIFY_CHANGE_SECURITY: int # undocumented -REG_NO_LAZY_FLUSH: int # undocumented -REG_OPENED_EXISTING_KEY: int # undocumented -REG_OPTION_BACKUP_RESTORE: int # undocumented -REG_OPTION_CREATE_LINK: int # undocumented -REG_OPTION_NON_VOLATILE: int # undocumented -REG_OPTION_OPEN_LINK: int # undocumented -REG_OPTION_RESERVED: int # undocumented -REG_OPTION_VOLATILE: int # undocumented -REG_REFRESH_HIVE: int # undocumented -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: ... - def __enter__(self: Self) -> Self: ... - def __exit__( - self, exc_type: Type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None - ) -> bool | None: ... - def Close(self) -> None: ... - def Detach(self) -> int: ... + # 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: ... + def __enter__(self: Self) -> Self: ... + def __exit__( + self, exc_type: Type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None + ) -> bool | None: ... + def Close(self) -> None: ... + def Detach(self) -> int: ... diff --git a/mypy/typeshed/stdlib/wsgiref/handlers.pyi b/mypy/typeshed/stdlib/wsgiref/handlers.pyi index ac1e56b7664e..eccc0d164767 100644 --- a/mypy/typeshed/stdlib/wsgiref/handlers.pyi +++ b/mypy/typeshed/stdlib/wsgiref/handlers.pyi @@ -1,12 +1,12 @@ from abc import abstractmethod from types import TracebackType -from typing import IO, Callable, MutableMapping, Optional, Tuple, Type +from typing import IO, Callable, MutableMapping, Optional, Type from .headers import Headers from .types import ErrorStream, InputStream, StartResponse, WSGIApplication, WSGIEnvironment from .util import FileWrapper -_exc_info = Tuple[Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]] +_exc_info = tuple[Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]] def format_date_time(timestamp: float | None) -> str: ... # undocumented def read_environ() -> dict[str, str]: ... diff --git a/mypy/typeshed/stdlib/wsgiref/headers.pyi b/mypy/typeshed/stdlib/wsgiref/headers.pyi index 531a521d3824..b62124a2a936 100644 --- a/mypy/typeshed/stdlib/wsgiref/headers.pyi +++ b/mypy/typeshed/stdlib/wsgiref/headers.pyi @@ -1,6 +1,6 @@ -from typing import List, Pattern, Tuple, overload +from typing import Pattern, overload -_HeaderList = List[Tuple[str, str]] +_HeaderList = list[tuple[str, str]] tspecials: Pattern[str] # undocumented diff --git a/mypy/typeshed/stdlib/wsgiref/util.pyi b/mypy/typeshed/stdlib/wsgiref/util.pyi index a7f710e8012c..c769c77d36e9 100644 --- a/mypy/typeshed/stdlib/wsgiref/util.pyi +++ b/mypy/typeshed/stdlib/wsgiref/util.pyi @@ -1,3 +1,4 @@ +import sys from typing import IO, Any, Callable from .types import WSGIEnvironment @@ -7,7 +8,8 @@ class FileWrapper: blksize: int close: Callable[[], None] # only exists if filelike.close exists def __init__(self, filelike: IO[bytes], blksize: int = ...) -> None: ... - def __getitem__(self, key: Any) -> bytes: ... + if sys.version_info < (3, 11): + def __getitem__(self, key: Any) -> bytes: ... def __iter__(self) -> FileWrapper: ... def __next__(self) -> bytes: ... diff --git a/mypy/typeshed/stdlib/xml/dom/__init__.pyi b/mypy/typeshed/stdlib/xml/dom/__init__.pyi index c5766c326c3e..e5b91bf2a795 100644 --- a/mypy/typeshed/stdlib/xml/dom/__init__.pyi +++ b/mypy/typeshed/stdlib/xml/dom/__init__.pyi @@ -43,6 +43,7 @@ class IndexSizeErr(DOMException): ... class DomstringSizeErr(DOMException): ... class HierarchyRequestErr(DOMException): ... class WrongDocumentErr(DOMException): ... +class InvalidCharacterErr(DOMException): ... class NoDataAllowedErr(DOMException): ... class NoModificationAllowedErr(DOMException): ... class NotFoundErr(DOMException): ... diff --git a/mypy/typeshed/stdlib/xml/dom/expatbuilder.pyi b/mypy/typeshed/stdlib/xml/dom/expatbuilder.pyi index 964e6fa3f426..58914e8fabf1 100644 --- a/mypy/typeshed/stdlib/xml/dom/expatbuilder.pyi +++ b/mypy/typeshed/stdlib/xml/dom/expatbuilder.pyi @@ -1,3 +1,99 @@ -from typing import Any +from typing import Any, NoReturn +from xml.dom.minidom import Document, DOMImplementation, Node, TypeInfo +from xml.dom.xmlbuilder import DOMBuilderFilter, Options -def __getattr__(name: str) -> Any: ... # incomplete +TEXT_NODE = Node.TEXT_NODE +CDATA_SECTION_NODE = Node.CDATA_SECTION_NODE +DOCUMENT_NODE = Node.DOCUMENT_NODE +FILTER_ACCEPT = DOMBuilderFilter.FILTER_ACCEPT +FILTER_REJECT = DOMBuilderFilter.FILTER_REJECT +FILTER_SKIP = DOMBuilderFilter.FILTER_SKIP +FILTER_INTERRUPT = DOMBuilderFilter.FILTER_INTERRUPT +theDOMImplementation: DOMImplementation | None + +class ElementInfo: + tagName: Any + def __init__(self, tagName, model: Any | None = ...) -> None: ... + def getAttributeType(self, aname) -> TypeInfo: ... + def getAttributeTypeNS(self, namespaceURI, localName) -> TypeInfo: ... + def isElementContent(self) -> bool: ... + def isEmpty(self) -> bool: ... + def isId(self, aname) -> bool: ... + def isIdNS(self, euri, ename, auri, aname) -> bool: ... + +class ExpatBuilder: + document: Document # Created in self.reset() + curNode: Any # Created in self.reset() + def __init__(self, options: Options | None = ...) -> None: ... + def createParser(self): ... + def getParser(self): ... + def reset(self) -> None: ... + def install(self, parser) -> None: ... + def parseFile(self, file) -> Document: ... + def parseString(self, string: str) -> Document: ... + def start_doctype_decl_handler(self, doctypeName, systemId, publicId, has_internal_subset) -> None: ... + def end_doctype_decl_handler(self) -> None: ... + def pi_handler(self, target, data) -> None: ... + def character_data_handler_cdata(self, data) -> None: ... + def character_data_handler(self, data) -> None: ... + def start_cdata_section_handler(self) -> None: ... + def end_cdata_section_handler(self) -> None: ... + def entity_decl_handler(self, entityName, is_parameter_entity, value, base, systemId, publicId, notationName) -> None: ... + def notation_decl_handler(self, notationName, base, systemId, publicId) -> None: ... + def comment_handler(self, data) -> None: ... + def external_entity_ref_handler(self, context, base, systemId, publicId) -> int: ... + def first_element_handler(self, name, attributes) -> None: ... + def start_element_handler(self, name, attributes) -> None: ... + def end_element_handler(self, name) -> None: ... + def element_decl_handler(self, name, model) -> None: ... + def attlist_decl_handler(self, elem, name, type, default, required) -> None: ... + def xml_decl_handler(self, version, encoding, standalone) -> None: ... + +class FilterVisibilityController: + filter: DOMBuilderFilter + def __init__(self, filter: DOMBuilderFilter) -> None: ... + def startContainer(self, node: Node) -> int: ... + def acceptNode(self, node: Node) -> int: ... + +class FilterCrutch: + def __init__(self, builder) -> None: ... + +class Rejecter(FilterCrutch): + def start_element_handler(self, *args: Any) -> None: ... + def end_element_handler(self, *args: Any) -> None: ... + +class Skipper(FilterCrutch): + def start_element_handler(self, *args: Any) -> None: ... + def end_element_handler(self, *args: Any) -> None: ... + +class FragmentBuilder(ExpatBuilder): + fragment: Any | None + originalDocument: Any + context: Any + def __init__(self, context, options: Options | None = ...) -> None: ... + +class Namespaces: + def createParser(self): ... + def install(self, parser) -> None: ... + def start_namespace_decl_handler(self, prefix, uri) -> None: ... + def start_element_handler(self, name, attributes) -> None: ... + def end_element_handler(self, name) -> None: ... + +class ExpatBuilderNS(Namespaces, ExpatBuilder): ... +class FragmentBuilderNS(Namespaces, FragmentBuilder): ... +class ParseEscape(Exception): ... + +class InternalSubsetExtractor(ExpatBuilder): + subset: Any | None + def getSubset(self) -> Any | None: ... + def parseFile(self, file) -> None: ... # type: ignore[override] + def parseString(self, string: str) -> None: ... # type: ignore[override] + def start_doctype_decl_handler(self, name, publicId, systemId, has_internal_subset) -> None: ... # type: ignore[override] + def end_doctype_decl_handler(self) -> NoReturn: ... + def start_element_handler(self, name, attrs) -> NoReturn: ... + +def parse(file, namespaces: bool = ...): ... +def parseString(string: str, namespaces: bool = ...): ... +def parseFragment(file, context, namespaces: bool = ...): ... +def parseFragmentString(string: str, context, namespaces: bool = ...): ... +def makeBuilder(options: Options) -> ExpatBuilderNS | ExpatBuilder: ... diff --git a/mypy/typeshed/stdlib/xml/dom/minicompat.pyi b/mypy/typeshed/stdlib/xml/dom/minicompat.pyi index 4bc60f7ab965..38e6d05e4743 100644 --- a/mypy/typeshed/stdlib/xml/dom/minicompat.pyi +++ b/mypy/typeshed/stdlib/xml/dom/minicompat.pyi @@ -1,17 +1,17 @@ -from typing import Any, Iterable, List, Tuple, Type, TypeVar +from typing import Any, Iterable, Type, TypeVar _T = TypeVar("_T") StringTypes: tuple[Type[str]] -class NodeList(List[_T]): +class NodeList(list[_T]): length: int def item(self, index: int) -> _T | None: ... -class EmptyNodeList(Tuple[Any, ...]): +class EmptyNodeList(tuple[Any, ...]): length: int def item(self, index: int) -> None: ... - def __add__(self, other: Iterable[_T]) -> NodeList[_T]: ... # type: ignore + def __add__(self, other: Iterable[_T]) -> NodeList[_T]: ... # type: ignore[override] def __radd__(self, other: Iterable[_T]) -> NodeList[_T]: ... def defproperty(klass: Type[Any], name: str, doc: str) -> None: ... diff --git a/mypy/typeshed/stdlib/xml/dom/minidom.pyi b/mypy/typeshed/stdlib/xml/dom/minidom.pyi index 4d1d7a9d0faf..e9a26e30d721 100644 --- a/mypy/typeshed/stdlib/xml/dom/minidom.pyi +++ b/mypy/typeshed/stdlib/xml/dom/minidom.pyi @@ -70,6 +70,10 @@ class Attr(Node): self, qName: str, namespaceURI: str | None = ..., localName: Any | None = ..., prefix: Any | None = ... ) -> None: ... def unlink(self) -> None: ... + @property + def isId(self) -> bool: ... + @property + def schemaType(self) -> Any: ... class NamedNodeMap: def __init__(self, attrs, attrsNS, ownerElement) -> None: ... @@ -96,6 +100,8 @@ class NamedNodeMap: def setNamedItem(self, node): ... def setNamedItemNS(self, node): ... def __delitem__(self, attname_or_tuple) -> None: ... + @property + def length(self) -> int: ... AttributeList = NamedNodeMap @@ -110,6 +116,7 @@ class Element(Node): schemaType: Any parentNode: Any tagName: str + nodeName: str prefix: Any namespaceURI: str | None childNodes: Any @@ -139,6 +146,8 @@ class Element(Node): def setIdAttribute(self, name) -> None: ... def setIdAttributeNS(self, namespaceURI: str, localName) -> None: ... def setIdAttributeNode(self, idAttr) -> None: ... + @property + def attributes(self) -> NamedNodeMap: ... class Childless: attributes: Any @@ -173,6 +182,8 @@ class CharacterData(Childless, Node): def insertData(self, offset: int, arg: str) -> None: ... def deleteData(self, offset: int, count: int) -> None: ... def replaceData(self, offset: int, count: int, arg: str) -> None: ... + @property + def length(self) -> int: ... class Text(CharacterData): nodeType: Any @@ -182,6 +193,10 @@ class Text(CharacterData): def splitText(self, offset): ... def writexml(self, writer, indent: str = ..., addindent: str = ..., newl: str = ...) -> None: ... def replaceWholeText(self, content): ... + @property + def isWhitespaceInElementContent(self) -> bool: ... + @property + def wholeText(self) -> str: ... class Comment(CharacterData): nodeType: Any @@ -205,15 +220,17 @@ class ReadOnlySequentialNamedNodeMap: def removeNamedItemNS(self, namespaceURI: str, localName) -> None: ... def setNamedItem(self, node) -> None: ... def setNamedItemNS(self, node) -> None: ... + @property + def length(self) -> int: ... -class Identified: ... +class Identified: + publicId: Any + systemId: Any class DocumentType(Identified, Childless, Node): nodeType: Any nodeValue: Any name: Any - publicId: Any - systemId: Any internalSubset: Any entities: Any notations: Any diff --git a/mypy/typeshed/stdlib/xml/dom/pulldom.pyi b/mypy/typeshed/stdlib/xml/dom/pulldom.pyi index ce8816b4a98a..c2b7aa0772fa 100644 --- a/mypy/typeshed/stdlib/xml/dom/pulldom.pyi +++ b/mypy/typeshed/stdlib/xml/dom/pulldom.pyi @@ -1,4 +1,5 @@ -from typing import IO, Any, Sequence, Tuple, Union +import sys +from typing import IO, Any, Sequence, Union from typing_extensions import Literal from xml.dom.minidom import Document, DOMImplementation, Element, Text from xml.sax.handler import ContentHandler @@ -16,7 +17,7 @@ CHARACTERS: Literal["CHARACTERS"] _DocumentFactory = Union[DOMImplementation, None] _Node = Union[Document, Element, Text] -_Event = Tuple[ +_Event = tuple[ Literal[ Literal["START_ELEMENT"], Literal["END_ELEMENT"], @@ -66,7 +67,8 @@ class DOMEventStream: bufsize: int def __init__(self, stream: IO[bytes], parser: XMLReader, bufsize: int) -> None: ... pulldom: Any - def __getitem__(self, pos): ... + if sys.version_info < (3, 11): + def __getitem__(self, pos): ... def __next__(self): ... def __iter__(self): ... def getEvent(self) -> _Event: ... diff --git a/mypy/typeshed/stdlib/xml/dom/xmlbuilder.pyi b/mypy/typeshed/stdlib/xml/dom/xmlbuilder.pyi index d8936bdc2ab4..2738d735e73f 100644 --- a/mypy/typeshed/stdlib/xml/dom/xmlbuilder.pyi +++ b/mypy/typeshed/stdlib/xml/dom/xmlbuilder.pyi @@ -1,6 +1,107 @@ -from typing import Any +from typing import Any, NoReturn, Optional +from typing_extensions import Literal +from urllib.request import OpenerDirector +from xml.dom.expatbuilder import ExpatBuilder, ExpatBuilderNS +from xml.dom.minidom import Node -def __getattr__(name: str) -> Any: ... # incomplete +# UNKNOWN TYPES: +# - `Options.errorHandler`. +# The same as `_DOMBuilderErrorHandlerType`? +# Maybe `xml.sax.handler.ErrorHandler`? +# - Return type of DOMBuilder.getFeature(). +# We could get rid of the `Any` if we knew more +# about `Options.errorHandler`. -class DocumentLS(Any): ... # type: ignore -class DOMImplementationLS(Any): ... # type: ignore +# ALIASES REPRESENTING MORE UNKNOWN TYPES: + +# probably the same as `Options.errorHandler`? +# Maybe `xml.sax.handler.ErrorHandler`? +_DOMBuilderErrorHandlerType = Optional[Any] +# probably some kind of IO... +_DOMInputSourceCharacterStreamType = Optional[Any] +# probably a string?? +_DOMInputSourceStringDataType = Optional[Any] +# probably a string?? +_DOMInputSourceEncodingType = Optional[Any] + +class Options: + namespaces: int + namespace_declarations: bool + validation: bool + external_parameter_entities: bool + external_general_entities: bool + external_dtd_subset: bool + validate_if_schema: bool + validate: bool + datatype_normalization: bool + create_entity_ref_nodes: bool + entities: bool + whitespace_in_element_content: bool + cdata_sections: bool + comments: bool + charset_overrides_xml_encoding: bool + infoset: bool + supported_mediatypes_only: bool + errorHandler: Any | None + filter: DOMBuilderFilter | None # a guess, but seems likely + +class DOMBuilder: + entityResolver: DOMEntityResolver | None # a guess, but seems likely + errorHandler: _DOMBuilderErrorHandlerType + filter: DOMBuilderFilter | None # a guess, but seems likely + ACTION_REPLACE: Literal[1] + ACTION_APPEND_AS_CHILDREN: Literal[2] + ACTION_INSERT_AFTER: Literal[3] + ACTION_INSERT_BEFORE: Literal[4] + def __init__(self) -> None: ... + def setFeature(self, name: str, state: int) -> None: ... + def supportsFeature(self, name: str) -> bool: ... + def canSetFeature(self, name: str, state: int) -> bool: ... + # getFeature could return any attribute from an instance of `Options` + def getFeature(self, name: str) -> Any: ... + def parseURI(self, uri: str) -> ExpatBuilder | ExpatBuilderNS: ... + def parse(self, input: DOMInputSource) -> ExpatBuilder | ExpatBuilderNS: ... + # `input` and `cnode` argtypes for `parseWithContext` are unknowable + # as the function does nothing with them, and always raises an exception. + # But `input` is *probably* `DOMInputSource`? + def parseWithContext(self, input: object, cnode: object, action: Literal[1, 2, 3, 4]) -> NoReturn: ... + +class DOMEntityResolver: + def resolveEntity(self, publicId: str | None, systemId: str) -> DOMInputSource: ... + +class DOMInputSource: + byteStream: OpenerDirector | None + characterStream: _DOMInputSourceCharacterStreamType + stringData: _DOMInputSourceStringDataType + encoding: _DOMInputSourceEncodingType + publicId: str | None + systemId: str | None + baseURI: str | None + +class DOMBuilderFilter: + FILTER_ACCEPT: Literal[1] + FILTER_REJECT: Literal[2] + FILTER_SKIP: Literal[3] + FILTER_INTERRUPT: Literal[4] + whatToShow: int + # The argtypes for acceptNode and startContainer appear to be irrelevant. + def acceptNode(self, element: object) -> Literal[1]: ... + def startContainer(self, element: object) -> Literal[1]: ... + +class DocumentLS: + async_: bool + def abort(self) -> NoReturn: ... + # `load()` and `loadXML()` always raise exceptions + # so the argtypes of `uri` and `source` are unknowable. + # `source` is *probably* `DOMInputSource`? + # `uri` is *probably* a str? (see DOMBuilder.parseURI()) + def load(self, uri: object) -> NoReturn: ... + def loadXML(self, source: object) -> NoReturn: ... + def saveXML(self, snode: Node | None) -> str: ... + +class DOMImplementationLS: + MODE_SYNCHRONOUS: Literal[1] + MODE_ASYNCHRONOUS: Literal[2] + def createDOMBuilder(self, mode: Literal[1], schemaType: None) -> DOMBuilder: ... + def createDOMWriter(self) -> NoReturn: ... + def createDOMInputSource(self) -> DOMInputSource: ... diff --git a/mypy/typeshed/stdlib/xml/etree/ElementInclude.pyi b/mypy/typeshed/stdlib/xml/etree/ElementInclude.pyi index 0ccccce4f3d0..b355bef1208c 100644 --- a/mypy/typeshed/stdlib/xml/etree/ElementInclude.pyi +++ b/mypy/typeshed/stdlib/xml/etree/ElementInclude.pyi @@ -6,6 +6,9 @@ XINCLUDE: str XINCLUDE_INCLUDE: str XINCLUDE_FALLBACK: str +if sys.version_info >= (3, 9): + DEFAULT_MAX_INCLUSION_DEPTH: int + class FatalIncludeError(SyntaxError): ... def default_loader(href: str | bytes | int, parse: str, encoding: str | None = ...) -> str | Element: ... @@ -17,6 +20,7 @@ if sys.version_info >= (3, 9): def include( elem: Element, loader: Callable[..., str | Element] | None = ..., base_url: str | None = ..., max_depth: int | None = ... ) -> None: ... + class LimitedRecursiveIncludeError(FatalIncludeError): ... else: def include(elem: Element, loader: Callable[..., str | Element] | None = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/xml/etree/ElementPath.pyi b/mypy/typeshed/stdlib/xml/etree/ElementPath.pyi index db4bd6a4e958..5a2dd69c1bee 100644 --- a/mypy/typeshed/stdlib/xml/etree/ElementPath.pyi +++ b/mypy/typeshed/stdlib/xml/etree/ElementPath.pyi @@ -1,11 +1,11 @@ -from typing import Callable, Generator, List, Pattern, Tuple, TypeVar +from typing import Callable, Generator, Pattern, TypeVar from xml.etree.ElementTree import Element xpath_tokenizer_re: Pattern[str] -_token = Tuple[str, str] +_token = tuple[str, str] _next = Callable[[], _token] -_callback = Callable[[_SelectorContext, List[Element]], Generator[Element, None, None]] +_callback = Callable[[_SelectorContext, list[Element]], Generator[Element, None, None]] def xpath_tokenizer(pattern: str, namespaces: dict[str, str] | None = ...) -> Generator[_token, None, None]: ... def get_parent_map(context: _SelectorContext) -> dict[Element, Element]: ... diff --git a/mypy/typeshed/stdlib/xml/etree/ElementTree.pyi b/mypy/typeshed/stdlib/xml/etree/ElementTree.pyi index 03a20dcad4cb..c4236cf292bb 100644 --- a/mypy/typeshed/stdlib/xml/etree/ElementTree.pyi +++ b/mypy/typeshed/stdlib/xml/etree/ElementTree.pyi @@ -4,19 +4,19 @@ from typing import ( IO, Any, Callable, - Dict, Generator, ItemsView, Iterable, Iterator, KeysView, + Mapping, MutableSequence, Sequence, TypeVar, Union, overload, ) -from typing_extensions import Literal +from typing_extensions import Literal, SupportsIndex _T = TypeVar("_T") _File = Union[StrOrBytesPath, FileDescriptor, IO[Any]] @@ -87,14 +87,14 @@ class Element(MutableSequence[Element]): def makeelement(self, __tag: str, __attrib: dict[str, str]) -> Element: ... def remove(self, __subelement: Element) -> None: ... def set(self, __key: str, __value: str) -> None: ... - def __delitem__(self, i: int | slice) -> None: ... + def __delitem__(self, i: SupportsIndex | slice) -> None: ... @overload - def __getitem__(self, i: int) -> Element: ... + def __getitem__(self, i: SupportsIndex) -> Element: ... @overload def __getitem__(self, s: slice) -> MutableSequence[Element]: ... def __len__(self) -> int: ... @overload - def __setitem__(self, i: int, o: Element) -> None: ... + def __setitem__(self, i: SupportsIndex, o: Element) -> None: ... @overload def __setitem__(self, s: slice, o: Iterable[Element]) -> None: ... if sys.version_info < (3, 9): @@ -256,14 +256,32 @@ def fromstringlist(sequence: Sequence[str | bytes], parser: XMLParser | None = . # TreeBuilder is called by client code (they could pass strs, bytes or whatever); # but we don't want to use a too-broad type, or it would be too hard to write # elementfactories. -_ElementFactory = Callable[[Any, Dict[Any, Any]], Element] +_ElementFactory = Callable[[Any, dict[Any, Any]], Element] class TreeBuilder: - def __init__(self, element_factory: _ElementFactory | None = ...) -> None: ... + if sys.version_info >= (3, 8): + # comment_factory can take None because passing None to Comment is not an error + def __init__( + self, + element_factory: _ElementFactory | None = ..., + *, + comment_factory: Callable[[str | None], Element] | None = ..., + pi_factory: Callable[[str, str | None], Element] | None = ..., + insert_comments: bool = ..., + insert_pis: bool = ..., + ) -> None: ... + insert_comments: bool + insert_pis: bool + else: + def __init__(self, element_factory: _ElementFactory | None = ...) -> None: ... def close(self) -> Element: ... def data(self, __data: str | bytes) -> None: ... def start(self, __tag: str | bytes, __attrs: dict[str | bytes, str | bytes]) -> Element: ... def end(self, __tag: str | bytes) -> Element: ... + if sys.version_info >= (3, 8): + # These two methods have pos-only parameters in the C implementation + def comment(self, __text: str | None) -> Element: ... + def pi(self, __target: str, __text: str | None = ...) -> Element: ... if sys.version_info >= (3, 8): class C14NWriterTarget: @@ -279,6 +297,12 @@ if sys.version_info >= (3, 8): exclude_attrs: Iterable[str] | None = ..., exclude_tags: Iterable[str] | None = ..., ) -> None: ... + def data(self, data: str) -> None: ... + def start_ns(self, prefix: str, uri: str) -> None: ... + def start(self, tag: str, attrs: Mapping[str, str]) -> None: ... + def end(self, tag: str) -> None: ... + def comment(self, text: str) -> None: ... + def pi(self, target: str, data: str) -> None: ... class XMLParser: parser: Any diff --git a/mypy/typeshed/stdlib/xmlrpc/client.pyi b/mypy/typeshed/stdlib/xmlrpc/client.pyi index 061df849eff2..e9f9e03ae56d 100644 --- a/mypy/typeshed/stdlib/xmlrpc/client.pyi +++ b/mypy/typeshed/stdlib/xmlrpc/client.pyi @@ -6,16 +6,16 @@ from _typeshed import Self, SupportsRead, SupportsWrite from datetime import datetime from io import BytesIO from types import TracebackType -from typing import Any, Callable, Dict, Iterable, List, Mapping, Protocol, Tuple, Type, Union, overload +from typing import Any, Callable, Iterable, Mapping, Protocol, Type, Union, overload from typing_extensions import Literal class _SupportsTimeTuple(Protocol): def timetuple(self) -> time.struct_time: ... _DateTimeComparable = Union[DateTime, datetime, str, _SupportsTimeTuple] -_Marshallable = Union[None, bool, int, float, str, bytes, Tuple[Any, ...], List[Any], Dict[Any, Any], datetime, DateTime, Binary] -_XMLDate = Union[int, datetime, Tuple[int, ...], time.struct_time] -_HostType = Union[Tuple[str, Dict[str, str]], str] +_Marshallable = Union[None, bool, int, float, str, bytes, tuple[Any, ...], list[Any], dict[Any, Any], datetime, DateTime, Binary] +_XMLDate = Union[int, datetime, tuple[int, ...], time.struct_time] +_HostType = Union[tuple[str, dict[str, str]], str] def escape(s: str) -> str: ... # undocumented @@ -63,12 +63,12 @@ def _strftime(value: _XMLDate) -> str: ... # undocumented class DateTime: value: str # undocumented - def __init__(self, value: int | str | datetime | time.struct_time | Tuple[int, ...] = ...) -> None: ... + def __init__(self, value: int | str | datetime | time.struct_time | tuple[int, ...] = ...) -> None: ... def __lt__(self, other: _DateTimeComparable) -> bool: ... def __le__(self, other: _DateTimeComparable) -> bool: ... def __gt__(self, other: _DateTimeComparable) -> bool: ... def __ge__(self, other: _DateTimeComparable) -> bool: ... - def __eq__(self, other: _DateTimeComparable) -> bool: ... # type: ignore + def __eq__(self, other: _DateTimeComparable) -> bool: ... # type: ignore[override] def make_comparable(self, other: _DateTimeComparable) -> tuple[str, str]: ... # undocumented def timetuple(self) -> time.struct_time: ... # undocumented def decode(self, data: Any) -> None: ... @@ -135,7 +135,7 @@ class Unmarshaller: _use_datetime: bool _use_builtin_types: bool def __init__(self, use_datetime: bool = ..., use_builtin_types: bool = ...) -> None: ... - def close(self) -> Tuple[_Marshallable, ...]: ... + def close(self) -> tuple[_Marshallable, ...]: ... def getmethodname(self) -> str | None: ... def xml(self, encoding: str, standalone: Any) -> None: ... # Standalone is ignored def start(self, tag: str, attrs: dict[str, str]) -> None: ... @@ -159,7 +159,7 @@ 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 __getattr__(self, name: str) -> _MultiCallMethod: ... @@ -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: ... @@ -186,13 +186,13 @@ FastUnmarshaller: Unmarshaller | None def getparser(use_datetime: bool = ..., use_builtin_types: bool = ...) -> tuple[ExpatParser, Unmarshaller]: ... def dumps( - params: Fault | Tuple[_Marshallable, ...], + params: Fault | tuple[_Marshallable, ...], methodname: str | None = ..., methodresponse: bool | None = ..., 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 @@ -204,9 +204,9 @@ class GzipDecodedResponse(gzip.GzipFile): # undocumented class _Method: # undocumented - __send: Callable[[str, Tuple[_Marshallable, ...]], _Marshallable] + __send: Callable[[str, tuple[_Marshallable, ...]], _Marshallable] __name: str - def __init__(self, send: Callable[[str, Tuple[_Marshallable, ...]], _Marshallable], name: str) -> None: ... + def __init__(self, send: Callable[[str, tuple[_Marshallable, ...]], _Marshallable], name: str) -> None: ... def __getattr__(self, name: str) -> _Method: ... def __call__(self, *args: _Marshallable) -> _Marshallable: ... @@ -228,10 +228,10 @@ class Transport: ) -> None: ... else: def __init__(self, use_datetime: bool = ..., use_builtin_types: bool = ...) -> None: ... - def request(self, host: _HostType, handler: str, request_body: bytes, verbose: bool = ...) -> Tuple[_Marshallable, ...]: ... + def request(self, host: _HostType, handler: str, request_body: bytes, verbose: bool = ...) -> tuple[_Marshallable, ...]: ... def single_request( self, host: _HostType, handler: str, request_body: bytes, verbose: bool = ... - ) -> Tuple[_Marshallable, ...]: ... + ) -> 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 make_connection(self, host: _HostType) -> http.client.HTTPConnection: ... @@ -239,7 +239,7 @@ class Transport: 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_content(self, connection: http.client.HTTPConnection, request_body: bytes) -> None: ... - def parse_response(self, response: http.client.HTTPResponse) -> Tuple[_Marshallable, ...]: ... + def parse_response(self, response: http.client.HTTPResponse) -> tuple[_Marshallable, ...]: ... class SafeTransport(Transport): @@ -304,6 +304,6 @@ class ServerProxy: self, exc_type: Type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None ) -> None: ... def __close(self) -> None: ... # undocumented - def __request(self, methodname: str, params: Tuple[_Marshallable, ...]) -> Tuple[_Marshallable, ...]: ... # undocumented + def __request(self, methodname: str, params: tuple[_Marshallable, ...]) -> tuple[_Marshallable, ...]: ... # undocumented Server = ServerProxy diff --git a/mypy/typeshed/stdlib/xmlrpc/server.pyi b/mypy/typeshed/stdlib/xmlrpc/server.pyi index bf5611fbaa96..48105d1461f0 100644 --- a/mypy/typeshed/stdlib/xmlrpc/server.pyi +++ b/mypy/typeshed/stdlib/xmlrpc/server.pyi @@ -3,11 +3,11 @@ import pydoc import socketserver import sys from datetime import datetime -from typing import Any, Callable, Dict, Iterable, List, Mapping, Pattern, Protocol, Tuple, Type, Union +from typing import Any, Callable, Iterable, Mapping, Pattern, Protocol, Type, Union from xmlrpc.client import Fault # TODO: Recursive type on tuple, list, dict -_Marshallable = Union[None, bool, int, float, str, bytes, Tuple[Any, ...], List[Any], Dict[Any, Any], datetime] +_Marshallable = Union[None, bool, int, float, str, bytes, tuple[Any, ...], list[Any], dict[Any, Any], datetime] # The dispatch accepts anywhere from 0 to N arguments, no easy way to allow this in mypy class _DispatchArity0(Protocol): @@ -53,7 +53,7 @@ class SimpleXMLRPCDispatcher: # undocumented def _marshaled_dispatch( self, data: str, - dispatch_method: Callable[[str | None, Tuple[_Marshallable, ...]], Fault | Tuple[_Marshallable, ...]] | None = ..., + dispatch_method: Callable[[str | None, tuple[_Marshallable, ...]], Fault | tuple[_Marshallable, ...]] | None = ..., path: Any | None = ..., ) -> str: ... # undocumented def system_listMethods(self) -> list[str]: ... # undocumented @@ -109,7 +109,7 @@ class MultiPathXMLRPCServer(SimpleXMLRPCServer): # undocumented def _marshaled_dispatch( self, data: str, - dispatch_method: Callable[[str | None, Tuple[_Marshallable, ...]], Fault | Tuple[_Marshallable, ...]] | None = ..., + dispatch_method: Callable[[str | None, tuple[_Marshallable, ...]], Fault | tuple[_Marshallable, ...]] | None = ..., path: Any | None = ..., ) -> str: ... @@ -120,7 +120,16 @@ class CGIXMLRPCRequestHandler(SimpleXMLRPCDispatcher): def handle_request(self, request_text: str | None = ...) -> None: ... class ServerHTMLDoc(pydoc.HTMLDoc): # undocumented - def docroutine(self, object: object, name: str, mod: str | None = ..., funcs: Mapping[str, str] = ..., classes: Mapping[str, str] = ..., methods: Mapping[str, str] = ..., cl: type | None = ...) -> str: ... # type: ignore + def docroutine( # type: ignore[override] + self, + object: object, + name: str, + mod: str | None = ..., + funcs: Mapping[str, str] = ..., + classes: Mapping[str, str] = ..., + methods: Mapping[str, str] = ..., + cl: type | None = ..., + ) -> str: ... def docserver(self, server_name: str, package_documentation: str, methods: dict[str, str]) -> str: ... class XMLRPCDocGenerator: # undocumented diff --git a/mypy/typeshed/stdlib/zipfile.pyi b/mypy/typeshed/stdlib/zipfile.pyi index 2335428549dc..c64690ba8ca9 100644 --- a/mypy/typeshed/stdlib/zipfile.pyi +++ b/mypy/typeshed/stdlib/zipfile.pyi @@ -3,10 +3,10 @@ import sys from _typeshed import Self, StrPath from os import PathLike from types import TracebackType -from typing import IO, Any, Callable, Iterable, Iterator, Protocol, Sequence, Tuple, Type, overload +from typing import IO, Any, Callable, Iterable, Iterator, Protocol, Sequence, Type, overload from typing_extensions import Literal -_DateTuple = Tuple[int, int, int, int, int, int] +_DateTuple = tuple[int, int, int, int, int, int] _ReadWriteMode = Literal["r", "w"] _ReadWriteBinaryMode = Literal["r", "w", "rb", "wb"] _ZipFileMode = Literal["r", "w", "x", "a"] @@ -97,10 +97,10 @@ class ZipExtFile(io.BufferedIOBase): close_fileobj: Literal[False] = ..., ) -> None: ... def read(self, n: int | None = ...) -> bytes: ... - def readline(self, limit: int = ...) -> bytes: ... # type: ignore + def readline(self, limit: int = ...) -> bytes: ... # type: ignore[override] def __repr__(self) -> str: ... def peek(self, n: int = ...) -> bytes: ... - def read1(self, n: int | None) -> bytes: ... # type: ignore + def read1(self, n: int | None) -> bytes: ... # type: ignore[override] if sys.version_info >= (3, 7): def seek(self, offset: int, whence: int = ...) -> int: ... diff --git a/mypy/typeshed/stdlib/zipimport.pyi b/mypy/typeshed/stdlib/zipimport.pyi index 155b9742aa57..3435092a4722 100644 --- a/mypy/typeshed/stdlib/zipimport.pyi +++ b/mypy/typeshed/stdlib/zipimport.pyi @@ -1,5 +1,6 @@ import os import sys +from importlib.machinery import ModuleSpec from types import CodeType, ModuleType from typing import Any @@ -8,7 +9,7 @@ if sys.version_info >= (3, 7): class ZipImportError(ImportError): ... -class zipimporter(object): +class zipimporter: archive: str prefix: str def __init__(self, path: str | bytes | os.PathLike[Any]) -> None: ... @@ -22,3 +23,6 @@ class zipimporter(object): def get_source(self, fullname: str) -> str | None: ... def is_package(self, fullname: str) -> bool: ... def load_module(self, fullname: str) -> ModuleType: ... + if sys.version_info >= (3, 10): + def find_spec(self, fullname: str, target: ModuleType | None = ...) -> ModuleSpec | None: ... + def invalidate_caches(self) -> None: ... diff --git a/mypy/typeshed/stdlib/zlib.pyi b/mypy/typeshed/stdlib/zlib.pyi index 5acc4190f1fe..646c96bd2bef 100644 --- a/mypy/typeshed/stdlib/zlib.pyi +++ b/mypy/typeshed/stdlib/zlib.pyi @@ -1,12 +1,16 @@ from array import array from typing import Any +from typing_extensions import Literal DEFLATED: int DEF_MEM_LEVEL: int MAX_WBITS: int ZLIB_VERSION: str +Z_NO_COMPRESSION: Literal[0] +Z_PARTIAL_FLUSH: Literal[1] Z_BEST_COMPRESSION: int Z_BEST_SPEED: int +Z_BLOCK: Literal[5] Z_DEFAULT_COMPRESSION: int Z_DEFAULT_STRATEGY: int Z_FILTERED: int @@ -17,6 +21,7 @@ Z_HUFFMAN_ONLY: int Z_NO_FLUSH: int Z_RLE: int Z_SYNC_FLUSH: int +Z_TREES: Literal[6] DEF_BUF_SIZE: int ZLIB_RUNTIME_VERSION: str diff --git a/mypy/typeshed/stubs/mypy-extensions/mypy_extensions.pyi b/mypy/typeshed/stubs/mypy-extensions/mypy_extensions.pyi index fc6de37d07d1..dd182c485177 100644 --- a/mypy/typeshed/stubs/mypy-extensions/mypy_extensions.pyi +++ b/mypy/typeshed/stubs/mypy-extensions/mypy_extensions.pyi @@ -1,6 +1,6 @@ import abc import sys -from typing import Any, Callable, Generic, ItemsView, KeysView, Mapping, Type, TypeVar, Union, ValuesView +from typing import Any, Callable, Generic, ItemsView, KeysView, Mapping, Type, TypeVar, ValuesView _T = TypeVar("_T") _U = TypeVar("_U") @@ -34,9 +34,8 @@ def VarArg(type: _T = ...) -> _T: ... def KwArg(type: _T = ...) -> _T: ... # 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] # Deprecated: Use typing.NoReturn instead. +# Deprecated: Use typing.NoReturn instead. +class NoReturn: ... # This is intended as a class decorator, but mypy rejects abstract classes # when a Type[_T] is expected, so we can't give it the type we want diff --git a/mypy/util.py b/mypy/util.py index b25f069d845d..2d6888dd0a2e 100644 --- a/mypy/util.py +++ b/mypy/util.py @@ -46,6 +46,26 @@ "C:\\Python27\\python.exe", ] +SPECIAL_DUNDERS: Final = frozenset(( + "__init__", "__new__", "__call__", "__init_subclass__", "__class_getitem__", +)) + + +def is_dunder(name: str, exclude_special: bool = False) -> bool: + """Returns whether name is a dunder name. + + Args: + exclude_special: Whether to return False for a couple special dunder methods. + + """ + if exclude_special and name in SPECIAL_DUNDERS: + return False + return name.startswith("__") and name.endswith("__") + + +def is_sunder(name: str) -> bool: + return not is_dunder(name) and name.startswith('_') and name.endswith('_') + def split_module_names(mod_name: str) -> List[str]: """Return the module and all parent module names. @@ -105,6 +125,20 @@ def find_python_encoding(text: bytes, pyversion: Tuple[int, int]) -> Tuple[str, return default_encoding, -1 +def bytes_to_human_readable_repr(b: bytes) -> str: + """Converts bytes into some human-readable representation. Unprintable + bytes such as the nul byte are escaped. For example: + + >>> b = bytes([102, 111, 111, 10, 0]) + >>> s = bytes_to_human_readable_repr(b) + >>> print(s) + foo\n\x00 + >>> print(repr(s)) + 'foo\\n\\x00' + """ + return repr(b)[2:-1] + + class DecodeError(Exception): """Exception raised when a file cannot be decoded due to an unknown encoding type. @@ -483,6 +517,8 @@ def hash_digest(data: bytes) -> str: def parse_gray_color(cup: bytes) -> str: """Reproduce a gray color in ANSI escape sequence""" + if sys.platform == "win32": + assert False, "curses is not available on Windows" set_color = ''.join([cup[:-1].decode(), 'm']) gray = curses.tparm(set_color.encode('utf-8'), 1, 89).decode() return gray @@ -546,7 +582,7 @@ def initialize_win_colors(self) -> bool: def initialize_unix_colors(self) -> bool: """Return True if initialization was successful and we can use colors, False otherwise""" - if not CURSES_ENABLED: + if sys.platform == "win32" or not CURSES_ENABLED: return False try: # setupterm wants a fd to potentially write an "initialization sequence". @@ -566,11 +602,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..daa805d65395 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.942' base_version = __version__ mypy_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) diff --git a/mypy/visitor.py b/mypy/visitor.py index b98ec773bbe3..9d3ebb6818b4 100644 --- a/mypy/visitor.py +++ b/mypy/visitor.py @@ -8,6 +8,7 @@ if TYPE_CHECKING: # break import cycle only needed for mypy import mypy.nodes + import mypy.patterns T = TypeVar('T') @@ -310,10 +311,50 @@ def visit_print_stmt(self, o: 'mypy.nodes.PrintStmt') -> T: def visit_exec_stmt(self, o: 'mypy.nodes.ExecStmt') -> T: pass + @abstractmethod + def visit_match_stmt(self, o: 'mypy.nodes.MatchStmt') -> T: + pass + @trait @mypyc_attr(allow_interpreted_subclasses=True) -class NodeVisitor(Generic[T], ExpressionVisitor[T], StatementVisitor[T]): +class PatternVisitor(Generic[T]): + @abstractmethod + def visit_as_pattern(self, o: 'mypy.patterns.AsPattern') -> T: + pass + + @abstractmethod + def visit_or_pattern(self, o: 'mypy.patterns.OrPattern') -> T: + pass + + @abstractmethod + def visit_value_pattern(self, o: 'mypy.patterns.ValuePattern') -> T: + pass + + @abstractmethod + def visit_singleton_pattern(self, o: 'mypy.patterns.SingletonPattern') -> T: + pass + + @abstractmethod + def visit_sequence_pattern(self, o: 'mypy.patterns.SequencePattern') -> T: + pass + + @abstractmethod + def visit_starred_pattern(self, o: 'mypy.patterns.StarredPattern') -> T: + pass + + @abstractmethod + def visit_mapping_pattern(self, o: 'mypy.patterns.MappingPattern') -> T: + pass + + @abstractmethod + def visit_class_pattern(self, o: 'mypy.patterns.ClassPattern') -> T: + pass + + +@trait +@mypyc_attr(allow_interpreted_subclasses=True) +class NodeVisitor(Generic[T], ExpressionVisitor[T], StatementVisitor[T], PatternVisitor[T]): """Empty base class for parse tree node visitors. The T type argument specifies the return type of the visit @@ -429,6 +470,9 @@ def visit_print_stmt(self, o: 'mypy.nodes.PrintStmt') -> T: def visit_exec_stmt(self, o: 'mypy.nodes.ExecStmt') -> T: pass + def visit_match_stmt(self, o: 'mypy.nodes.MatchStmt') -> T: + pass + # Expressions (default no-op implementation) def visit_int_expr(self, o: 'mypy.nodes.IntExpr') -> T: @@ -562,3 +606,29 @@ def visit_await_expr(self, o: 'mypy.nodes.AwaitExpr') -> T: def visit_temp_node(self, o: 'mypy.nodes.TempNode') -> T: pass + + # Patterns + + def visit_as_pattern(self, o: 'mypy.patterns.AsPattern') -> T: + pass + + def visit_or_pattern(self, o: 'mypy.patterns.OrPattern') -> T: + pass + + def visit_value_pattern(self, o: 'mypy.patterns.ValuePattern') -> T: + pass + + def visit_singleton_pattern(self, o: 'mypy.patterns.SingletonPattern') -> T: + pass + + def visit_sequence_pattern(self, o: 'mypy.patterns.SequencePattern') -> T: + pass + + def visit_starred_pattern(self, o: 'mypy.patterns.StarredPattern') -> T: + pass + + def visit_mapping_pattern(self, o: 'mypy.patterns.MappingPattern') -> T: + pass + + def visit_class_pattern(self, o: 'mypy.patterns.ClassPattern') -> T: + pass diff --git a/mypyc/analysis/ircheck.py b/mypyc/analysis/ircheck.py index f15beceff8ce..6450766f404c 100644 --- a/mypyc/analysis/ircheck.py +++ b/mypyc/analysis/ircheck.py @@ -1,14 +1,20 @@ """Utilities for checking that internal ir is valid and consistent.""" -from typing import List, Union +from typing import List, Union, Set, Tuple 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 + LoadMem, SetMem, GetElementPtr, LoadAddress, KeepAlive, Register, Integer, + BaseAssign ) -from mypyc.ir.func_ir import FuncIR +from mypyc.ir.rtypes import ( + RType, RPrimitive, RUnion, is_object_rprimitive, RInstance, RArray, + int_rprimitive, list_rprimitive, dict_rprimitive, set_rprimitive, + range_rprimitive, str_rprimitive, bytes_rprimitive, tuple_rprimitive +) +from mypyc.ir.func_ir import FuncIR, FUNC_STATICMETHOD class FnError(object): @@ -17,8 +23,11 @@ def __init__(self, source: Union[Op, BasicBlock], desc: str) -> None: self.desc = desc def __eq__(self, other: object) -> bool: - return isinstance(other, FnError) and self.source == other.source and \ - self.desc == other.desc + 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})" @@ -28,19 +37,44 @@ def check_func_ir(fn: FuncIR) -> List[FnError]: """Applies validations to a given function ir and returns a list of errors found.""" errors = [] + op_set = set() + 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", - )) + errors.append( + FnError( + source=block.ops[-1] if block.ops else block, + desc="Block not terminated", + ) + ) + for op in block.ops[:-1]: + if isinstance(op, ControlOp): + errors.append( + FnError( + source=op, + desc="Block has operations after control op", + ) + ) + + if op in op_set: + errors.append( + FnError( + source=op, + desc="Func has a duplicate op", + ) + ) + op_set.add(op) + + errors.extend(check_op_sources_valid(fn)) + if errors: + return errors op_checker = OpChecker(fn) for block in fn.blocks: for op in block.ops: op.accept(op_checker) - return errors + op_checker.errors + return op_checker.errors class IrCheckException(Exception): @@ -50,11 +84,90 @@ class IrCheckException(Exception): 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])), + raise IrCheckException( + "Internal error: Generated invalid IR: \n" + + "\n".join(format_func(fn, [(e.source, e.desc) for e in errors])), ) +def check_op_sources_valid(fn: FuncIR) -> List[FnError]: + errors = [] + valid_ops: Set[Op] = set() + valid_registers: Set[Register] = set() + + for block in fn.blocks: + valid_ops.update(block.ops) + + valid_registers.update( + [op.dest for op in block.ops if isinstance(op, BaseAssign)] + ) + + valid_registers.update(fn.arg_regs) + + for block in fn.blocks: + for op in block.ops: + for source in op.sources(): + if isinstance(source, Integer): + pass + elif isinstance(source, Op): + if source not in valid_ops: + errors.append( + FnError( + source=op, + desc=f"Invalid op reference to op of type {type(source).__name__}", + ) + ) + elif isinstance(source, Register): + if source not in valid_registers: + errors.append( + FnError( + source=op, + desc=f"Invalid op reference to register {source.name}", + ) + ) + + return errors + + +disjoint_types = set( + [ + int_rprimitive.name, + bytes_rprimitive.name, + str_rprimitive.name, + dict_rprimitive.name, + list_rprimitive.name, + set_rprimitive.name, + tuple_rprimitive.name, + range_rprimitive.name, + ] +) + + +def can_coerce_to(src: RType, dest: RType) -> bool: + """Check if src can be assigned to dest_rtype. + + Currently okay to have false positives. + """ + if isinstance(dest, RUnion): + return any(can_coerce_to(src, d) for d in dest.items) + + if isinstance(dest, RPrimitive): + if isinstance(src, RPrimitive): + # If either src or dest is a disjoint type, then they must both be. + if src.name in disjoint_types and dest.name in disjoint_types: + return src.name == dest.name + return src.size == dest.size + if isinstance(src, RInstance): + return is_object_rprimitive(dest) + if isinstance(src, RUnion): + # IR doesn't have the ability to narrow unions based on + # control flow, so cannot be a strict all() here. + return any(can_coerce_to(s, dest) for s in src.items) + return False + + return True + + class OpChecker(OpVisitor[None]): def __init__(self, parent_fn: FuncIR) -> None: self.parent_fn = parent_fn @@ -66,7 +179,16 @@ def fail(self, source: Op, desc: str) -> None: 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}") + self.fail( + source=op, desc=f"Invalid control operation target: {target.label}" + ) + + def check_type_coercion(self, op: Op, src: RType, dest: RType) -> None: + if not can_coerce_to(src, dest): + self.fail( + source=op, + desc=f"Cannot coerce source type {src.name} to dest type {dest.name}", + ) def visit_goto(self, op: Goto) -> None: self.check_control_op_targets(op) @@ -75,29 +197,76 @@ def visit_branch(self, op: Branch) -> None: self.check_control_op_targets(op) def visit_return(self, op: Return) -> None: - pass + self.check_type_coercion(op, op.value.type, self.parent_fn.decl.sig.ret_type) def visit_unreachable(self, op: Unreachable) -> None: + # Unreachables are checked at a higher level since validation + # requires access to the entire basic block. pass def visit_assign(self, op: Assign) -> None: - pass + self.check_type_coercion(op, op.src.type, op.dest.type) def visit_assign_multi(self, op: AssignMulti) -> None: - pass + for src in op.src: + assert isinstance(op.dest.type, RArray) + self.check_type_coercion(op, src.type, op.dest.type.item_type) def visit_load_error_value(self, op: LoadErrorValue) -> None: + # Currently it is assumed that all types have an error value. + # Once this is fixed we can validate that the rtype here actually + # has an error value. pass + def check_tuple_items_valid_literals( + self, op: LoadLiteral, t: Tuple[object, ...] + ) -> None: + for x in t: + if x is not None and not isinstance( + x, (str, bytes, bool, int, float, complex, tuple) + ): + self.fail(op, f"Invalid type for item of tuple literal: {type(x)})") + if isinstance(x, tuple): + self.check_tuple_items_valid_literals(op, x) + def visit_load_literal(self, op: LoadLiteral) -> None: - pass + expected_type = None + if op.value is None: + expected_type = "builtins.object" + elif isinstance(op.value, int): + expected_type = "builtins.int" + elif isinstance(op.value, str): + expected_type = "builtins.str" + elif isinstance(op.value, bytes): + expected_type = "builtins.bytes" + elif isinstance(op.value, bool): + expected_type = "builtins.object" + elif isinstance(op.value, float): + expected_type = "builtins.float" + elif isinstance(op.value, complex): + expected_type = "builtins.object" + elif isinstance(op.value, tuple): + expected_type = "builtins.tuple" + self.check_tuple_items_valid_literals(op, op.value) + + assert expected_type is not None, "Missed a case for LoadLiteral check" + + if op.type.name not in [expected_type, "builtins.object"]: + self.fail( + op, + f"Invalid literal value for type: value has " + f"type {expected_type}, but op has type {op.type.name}", + ) def visit_get_attr(self, op: GetAttr) -> None: + # Nothing to do. pass def visit_set_attr(self, op: SetAttr) -> None: + # Nothing to do. pass + # Static operations cannot be checked at the function level. def visit_load_static(self, op: LoadStatic) -> None: pass @@ -105,22 +274,41 @@ def visit_init_static(self, op: InitStatic) -> None: pass def visit_tuple_get(self, op: TupleGet) -> None: + # Nothing to do. pass def visit_tuple_set(self, op: TupleSet) -> None: + # Nothing to do. pass def visit_inc_ref(self, op: IncRef) -> None: + # Nothing to do. pass def visit_dec_ref(self, op: DecRef) -> None: + # Nothing to do. pass def visit_call(self, op: Call) -> None: - pass + # Length is checked in constructor, and return type is set + # in a way that can't be incorrect + for arg_value, arg_runtime in zip(op.args, op.fn.sig.args): + self.check_type_coercion(op, arg_value.type, arg_runtime.type) def visit_method_call(self, op: MethodCall) -> None: - pass + # Similar to above, but we must look up method first. + method_decl = op.receiver_type.class_ir.method_decl(op.method) + if method_decl.kind == FUNC_STATICMETHOD: + decl_index = 0 + else: + decl_index = 1 + + if len(op.args) + decl_index != len(method_decl.sig.args): + self.fail(op, "Incorrect number of args for method call.") + + # Skip the receiver argument (self) + for arg_value, arg_runtime in zip(op.args, method_decl.sig.args[decl_index:]): + self.check_type_coercion(op, arg_value.type, arg_runtime.type) def visit_cast(self, op: Cast) -> None: pass diff --git a/mypyc/build.py b/mypyc/build.py index 571fb0dd2f5a..8528aa088ac0 100644 --- a/mypyc/build.py +++ b/mypyc/build.py @@ -308,8 +308,8 @@ def write_file(path: str, contents: str) -> None: old_contents = None if old_contents != encoded_contents: os.makedirs(os.path.dirname(path), exist_ok=True) - with open(path, 'wb') as f: - f.write(encoded_contents) + with open(path, 'wb') as g: + g.write(encoded_contents) # Fudge the mtime forward because otherwise when two builds happen close # together (like in a test) setuptools might not realize the source is newer diff --git a/mypyc/codegen/emitfunc.py b/mypyc/codegen/emitfunc.py index 3b94c5648769..6215e29b51a1 100644 --- a/mypyc/codegen/emitfunc.py +++ b/mypyc/codegen/emitfunc.py @@ -122,10 +122,12 @@ def visit_goto(self, op: Goto) -> None: def visit_branch(self, op: Branch) -> None: true, false = op.true, op.false negated = op.negated + negated_rare = False if true is self.next_block and op.traceback_entry is None: # Switch true/false since it avoids an else block. true, false = false, true negated = not negated + negated_rare = True neg = '!' if negated else '' cond = '' @@ -150,7 +152,10 @@ def visit_branch(self, op: Branch) -> None: # For error checks, tell the compiler the branch is unlikely if op.traceback_entry is not None or op.rare: - cond = 'unlikely({})'.format(cond) + if not negated_rare: + cond = 'unlikely({})'.format(cond) + else: + cond = 'likely({})'.format(cond) if false is self.next_block: if op.traceback_entry is None: @@ -287,17 +292,17 @@ def visit_get_attr(self, op: GetAttr) -> None: # Otherwise, use direct or offset struct access. attr_expr = self.get_attr_expr(obj, op, decl_cl) self.emitter.emit_line('{} = {};'.format(dest, attr_expr)) + self.emitter.emit_undefined_attr_check( + attr_rtype, attr_expr, '==', unlikely=True + ) + exc_class = 'PyExc_AttributeError' + self.emitter.emit_line( + 'PyErr_SetString({}, "attribute {} of {} undefined");'.format( + exc_class, repr(op.attr), repr(cl.name))) if attr_rtype.is_refcounted: - self.emitter.emit_undefined_attr_check( - attr_rtype, attr_expr, '==', unlikely=True - ) - exc_class = 'PyExc_AttributeError' - self.emitter.emit_lines( - 'PyErr_SetString({}, "attribute {} of {} undefined");'.format( - exc_class, repr(op.attr), repr(cl.name)), - '} else {') + self.emitter.emit_line('} else {') self.emitter.emit_inc_ref(attr_expr, attr_rtype) - self.emitter.emit_line('}') + self.emitter.emit_line('}') def visit_set_attr(self, op: SetAttr) -> None: dest = self.reg(op) diff --git a/mypyc/codegen/emitwrapper.py b/mypyc/codegen/emitwrapper.py index bbee8fea0d91..dd08bdb40bf3 100644 --- a/mypyc/codegen/emitwrapper.py +++ b/mypyc/codegen/emitwrapper.py @@ -286,21 +286,20 @@ def generate_bin_op_wrapper(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str: gen.emit_header() if fn.name not in reverse_op_methods and fn.name in reverse_op_method_names: # There's only a reverse operator method. - generate_bin_op_reverse_only_wrapper(cl, fn, emitter, gen) + generate_bin_op_reverse_only_wrapper(emitter, gen) else: rmethod = reverse_op_methods[fn.name] fn_rev = cl.get_method(rmethod) if fn_rev is None: # There's only a forward operator method. - generate_bin_op_forward_only_wrapper(cl, fn, emitter, gen) + generate_bin_op_forward_only_wrapper(fn, emitter, gen) else: # There's both a forward and a reverse operator method. generate_bin_op_both_wrappers(cl, fn, fn_rev, emitter, gen) return wrapper_name -def generate_bin_op_forward_only_wrapper(cl: ClassIR, - fn: FuncIR, +def generate_bin_op_forward_only_wrapper(fn: FuncIR, emitter: Emitter, gen: 'WrapperGenerator') -> None: gen.emit_arg_processing(error=GotoHandler('typefail'), raise_exception=False) @@ -331,9 +330,7 @@ def generate_bin_op_forward_only_wrapper(cl: ClassIR, gen.finish() -def generate_bin_op_reverse_only_wrapper(cl: ClassIR, - fn_rev: FuncIR, - emitter: Emitter, +def generate_bin_op_reverse_only_wrapper(emitter: Emitter, gen: 'WrapperGenerator') -> None: gen.arg_names = ['right', 'left'] gen.emit_arg_processing(error=GotoHandler('typefail'), raise_exception=False) @@ -650,47 +647,17 @@ def generate_wrapper_core(fn: FuncIR, It converts the PyObject *s to the necessary types, checking and unboxing if necessary, makes the call, then boxes the result if necessary and returns it. """ + gen = WrapperGenerator(None, emitter) + gen.set_target(fn) + gen.arg_names = arg_names or [arg.name for arg in fn.args] + gen.cleanups = cleanups or [] + gen.optional_args = optional_args or [] + gen.traceback_code = traceback_code or '' - optional_args = optional_args or [] - cleanups = cleanups or [] - use_goto = bool(cleanups or traceback_code) - error = ReturnHandler('NULL') if not use_goto else GotoHandler('fail') - - arg_names = arg_names or [arg.name for arg in fn.args] - for arg_name, arg in zip(arg_names, fn.args): - # Suppress the argument check for *args/**kwargs, since we know it must be right. - typ = arg.type if arg.kind not in (ARG_STAR, ARG_STAR2) else object_rprimitive - generate_arg_check(arg_name, - typ, - emitter, - error, - optional=arg in optional_args) - native_args = ', '.join('arg_{}'.format(arg) for arg in arg_names) - if fn.ret_type.is_unboxed or use_goto: - # TODO: The Py_RETURN macros return the correct PyObject * with reference count handling. - # Are they relevant? - emitter.emit_line('{}retval = {}{}({});'.format(emitter.ctype_spaced(fn.ret_type), - NATIVE_PREFIX, - fn.cname(emitter.names), - native_args)) - emitter.emit_lines(*cleanups) - if fn.ret_type.is_unboxed: - emitter.emit_error_check('retval', fn.ret_type, 'return NULL;') - emitter.emit_box('retval', 'retbox', fn.ret_type, declare_dest=True) - - emitter.emit_line('return {};'.format('retbox' if fn.ret_type.is_unboxed else 'retval')) - else: - emitter.emit_line('return {}{}({});'.format(NATIVE_PREFIX, - fn.cname(emitter.names), - native_args)) - # TODO: Tracebacks? - - if use_goto: - emitter.emit_label('fail') - emitter.emit_lines(*cleanups) - if traceback_code: - emitter.emit_lines(traceback_code) - emitter.emit_lines('return NULL;') + error = ReturnHandler('NULL') if not gen.use_goto() else GotoHandler('fail') + gen.emit_arg_processing(error=error) + gen.emit_call() + gen.emit_error_handling() def generate_arg_check(name: str, @@ -741,7 +708,7 @@ class WrapperGenerator: # TODO: Use this for more wrappers - def __init__(self, cl: ClassIR, emitter: Emitter) -> None: + def __init__(self, cl: Optional[ClassIR], emitter: Emitter) -> None: self.cl = cl self.emitter = emitter self.cleanups: List[str] = [] @@ -764,7 +731,7 @@ def wrapper_name(self) -> str: """Return the name of the wrapper function.""" return '{}{}{}'.format(DUNDER_PREFIX, self.target_name, - self.cl.name_prefix(self.emitter.names)) + self.cl.name_prefix(self.emitter.names) if self.cl else '') def use_goto(self) -> bool: """Do we use a goto for error handling (instead of straight return)?""" diff --git a/mypyc/doc/dev-intro.md b/mypyc/doc/dev-intro.md index bf0c1a836874..d11df7068e91 100644 --- a/mypyc/doc/dev-intro.md +++ b/mypyc/doc/dev-intro.md @@ -149,7 +149,7 @@ know for mypyc contributors: ([The C Programming Language](https://en.wikipedia.org/wiki/The_C_Programming_Language) is a classic book about C) * Basic familiarity with the Python C API (see - [Python C API documentation](https://docs.python.org/3/c-api/intro.html)) + [Python C API documentation](https://docs.python.org/3/c-api/intro.html)). [Extending and Embedding the Python Interpreter](https://docs.python.org/3/extending/index.html) is a good tutorial for beginners. * Basics of compilers (see the [mypy wiki](https://github.com/python/mypy/wiki/Learning-Resources) for some ideas) diff --git a/mypyc/ir/ops.py b/mypyc/ir/ops.py index 22dead2f7976..65480ebcc7c3 100644 --- a/mypyc/ir/ops.py +++ b/mypyc/ir/ops.py @@ -214,15 +214,21 @@ def accept(self, visitor: 'OpVisitor[T]') -> T: pass -class Assign(Op): +class BaseAssign(Op): + """Base class for ops that assign to a register.""" + def __init__(self, dest: Register, line: int = -1) -> None: + super().__init__(line) + self.dest = dest + + +class Assign(BaseAssign): """Assign a value to a Register (dest = src).""" error_kind = ERR_NEVER def __init__(self, dest: Register, src: Value, line: int = -1) -> None: - super().__init__(line) + super().__init__(dest, line) self.src = src - self.dest = dest def sources(self) -> List[Value]: return [self.src] @@ -234,7 +240,7 @@ def accept(self, visitor: 'OpVisitor[T]') -> T: return visitor.visit_assign(self) -class AssignMulti(Op): +class AssignMulti(BaseAssign): """Assign multiple values to a Register (dest = src1, src2, ...). This is used to initialize RArray values. It's provided to avoid @@ -248,12 +254,11 @@ class AssignMulti(Op): error_kind = ERR_NEVER def __init__(self, dest: Register, src: List[Value], line: int = -1) -> None: - super().__init__(line) + super().__init__(dest, line) assert src assert isinstance(dest.type, RArray) assert dest.type.length == len(src) self.src = src - self.dest = dest def sources(self) -> List[Value]: return self.src[:] @@ -490,6 +495,7 @@ def __init__(self, fn: 'FuncDecl', args: Sequence[Value], line: int) -> None: super().__init__(line) self.fn = fn self.args = list(args) + assert len(self.args) == len(fn.sig.args) self.type = fn.sig.ret_type def sources(self) -> List[Value]: diff --git a/mypyc/irbuild/classdef.py b/mypyc/irbuild/classdef.py index 6c2958c5b8de..80ec331cd550 100644 --- a/mypyc/irbuild/classdef.py +++ b/mypyc/irbuild/classdef.py @@ -8,7 +8,7 @@ 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 mypy.types import Instance, get_proper_type, ENUM_REMOVED_PROPS from mypyc.ir.ops import ( Value, Register, Call, LoadErrorValue, LoadStatic, InitStatic, TupleSet, SetAttr, Return, BasicBlock, Branch, MethodCall, NAMESPACE_TYPE, LoadAddress @@ -517,8 +517,8 @@ def add_non_ext_class_attr(builder: IRBuilder, if ( cdef.info.bases and cdef.info.bases[0].type.fullname == 'enum.Enum' - # Skip "_order_" and "__order__", since Enum will remove it - and lvalue.name not in ('_order_', '__order__') + # Skip these since Enum will remove it + and lvalue.name not in ENUM_REMOVED_PROPS ): # Enum values are always boxed, so use object_rprimitive. attr_to_cache.append((lvalue, object_rprimitive)) diff --git a/mypyc/irbuild/expression.py b/mypyc/irbuild/expression.py index 6a42820b9b21..71e497f9e368 100644 --- a/mypyc/irbuild/expression.py +++ b/mypyc/irbuild/expression.py @@ -326,11 +326,20 @@ def translate_super_method_call(builder: IRBuilder, expr: CallExpr, callee: Supe return translate_call(builder, expr, callee) ir = builder.mapper.type_to_ir[callee.info] - # Search for the method in the mro, skipping ourselves. + # Search for the method in the mro, skipping ourselves. We + # determine targets of super calls to native methods statically. for base in ir.mro[1:]: if callee.name in base.method_decls: break else: + if (ir.is_ext_class + and ir.builtin_base is None + and not ir.inherits_python + and callee.name == '__init__' + and len(expr.args) == 0): + # Call translates to object.__init__(self), which is a + # no-op, so omit the call. + return builder.none() return translate_call(builder, expr, callee) decl = base.method_decl(callee.name) diff --git a/mypyc/irbuild/prepare.py b/mypyc/irbuild/prepare.py index 3f028d900943..2cb3deac9700 100644 --- a/mypyc/irbuild/prepare.py +++ b/mypyc/irbuild/prepare.py @@ -142,7 +142,7 @@ def prepare_method_def(ir: ClassIR, module_name: str, cdef: ClassDef, mapper: Ma ir.method_decls[PROPSET_PREFIX + node.name] = decl if node.func.is_property: - assert node.func.type + assert node.func.type, f"Expected return type annotation for property '{node.name}'" decl.is_prop_getter = True ir.property_types[node.name] = decl.sig.ret_type diff --git a/mypyc/irbuild/visitor.py b/mypyc/irbuild/visitor.py index 1a6a84809707..43cfd457667d 100644 --- a/mypyc/irbuild/visitor.py +++ b/mypyc/irbuild/visitor.py @@ -16,7 +16,8 @@ FloatExpr, GeneratorExpr, GlobalDecl, LambdaExpr, ListComprehension, SetComprehension, NamedTupleExpr, NewTypeExpr, NonlocalDecl, OverloadedFuncDef, PrintStmt, RaiseStmt, RevealExpr, SetExpr, SliceExpr, StarExpr, SuperExpr, TryStmt, TypeAliasExpr, TypeApplication, - TypeVarExpr, TypedDictExpr, UnicodeExpr, WithStmt, YieldFromExpr, YieldExpr, ParamSpecExpr + TypeVarExpr, TypedDictExpr, UnicodeExpr, WithStmt, YieldFromExpr, YieldExpr, ParamSpecExpr, + MatchStmt ) from mypyc.ir.ops import Value @@ -179,6 +180,9 @@ def visit_nonlocal_decl(self, stmt: NonlocalDecl) -> None: # Pure declaration -- no runtime effect pass + def visit_match_stmt(self, stmt: MatchStmt) -> None: + self.bail("Match statements are not yet supported", stmt.line) + # Expressions def visit_name_expr(self, expr: NameExpr) -> Value: diff --git a/mypyc/lib-rt/dict_ops.c b/mypyc/lib-rt/dict_ops.c index 21a9035021ea..b013a8a5f0b9 100644 --- a/mypyc/lib-rt/dict_ops.c +++ b/mypyc/lib-rt/dict_ops.c @@ -139,8 +139,8 @@ int CPyDict_UpdateInDisplay(PyObject *dict, PyObject *stuff) { if (ret < 0) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Format(PyExc_TypeError, - "'%.200s' object is not a mapping", - stuff->ob_type->tp_name); + "'%.200s' object is not a mapping", + Py_TYPE(stuff)->tp_name); } } return ret; diff --git a/mypyc/lib-rt/exc_ops.c b/mypyc/lib-rt/exc_ops.c index b87d5471a411..7ef46479d2e8 100644 --- a/mypyc/lib-rt/exc_ops.c +++ b/mypyc/lib-rt/exc_ops.c @@ -140,7 +140,7 @@ static PyObject *CPy_GetTypeName(PyObject *type) { // Get the type of a value as a string, expanding tuples to include // all the element types. static PyObject *CPy_FormatTypeName(PyObject *value) { - if (value == Py_None) { + if (Py_IsNone(value)) { return PyUnicode_FromString("None"); } diff --git a/mypyc/lib-rt/generic_ops.c b/mypyc/lib-rt/generic_ops.c index 1dff949dcfcf..2f4a7941a6da 100644 --- a/mypyc/lib-rt/generic_ops.c +++ b/mypyc/lib-rt/generic_ops.c @@ -33,7 +33,7 @@ PyObject *CPyObject_GetAttr3(PyObject *v, PyObject *name, PyObject *defl) PyObject *CPyIter_Next(PyObject *iter) { - return (*iter->ob_type->tp_iternext)(iter); + return (*Py_TYPE(iter)->tp_iternext)(iter); } PyObject *CPyNumber_Power(PyObject *base, PyObject *index) diff --git a/mypyc/lib-rt/misc_ops.c b/mypyc/lib-rt/misc_ops.c index 6b5685ab1f1a..cebd1cf997f8 100644 --- a/mypyc/lib-rt/misc_ops.c +++ b/mypyc/lib-rt/misc_ops.c @@ -3,14 +3,13 @@ // These are registered in mypyc.primitives.misc_ops. #include -#include "pythoncapi_compat.h" #include "CPy.h" PyObject *CPy_GetCoro(PyObject *obj) { // If the type has an __await__ method, call it, // otherwise, fallback to calling __iter__. - PyAsyncMethods* async_struct = obj->ob_type->tp_as_async; + PyAsyncMethods* async_struct = Py_TYPE(obj)->tp_as_async; if (async_struct != NULL && async_struct->am_await != NULL) { return (async_struct->am_await)(obj); } else { @@ -25,7 +24,7 @@ PyObject *CPyIter_Send(PyObject *iter, PyObject *val) // Do a send, or a next if second arg is None. // (This behavior is to match the PEP 380 spec for yield from.) _Py_IDENTIFIER(send); - if (val == Py_None) { + if (Py_IsNone(val)) { return CPyIter_Next(iter); } else { return _PyObject_CallMethodIdOneArg(iter, &PyId_send, val); @@ -640,7 +639,7 @@ CPy_Super(PyObject *builtins, PyObject *self) { if (!super_type) return NULL; PyObject *result = PyObject_CallFunctionObjArgs( - super_type, (PyObject*)self->ob_type, self, NULL); + super_type, (PyObject*)Py_TYPE(self), self, NULL); Py_DECREF(super_type); return result; } diff --git a/mypyc/lib-rt/pythoncapi_compat.h b/mypyc/lib-rt/pythoncapi_compat.h index b4011d20a19a..c9191a1d7a57 100644 --- a/mypyc/lib-rt/pythoncapi_compat.h +++ b/mypyc/lib-rt/pythoncapi_compat.h @@ -1,7 +1,6 @@ -// Header file providing new functions of the Python C API to old Python -// versions. +// Header file providing new C API functions to old Python versions. // -// File distributed under the MIT license. +// File distributed under the Zero Clause BSD (0BSD) license. // Copyright Contributors to the pythoncapi_compat project. // // Homepage: @@ -10,7 +9,7 @@ // Latest version: // https://raw.githubusercontent.com/pythoncapi/pythoncapi_compat/master/pythoncapi_compat.h // -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: 0BSD #ifndef PYTHONCAPI_COMPAT #define PYTHONCAPI_COMPAT @@ -27,24 +26,34 @@ extern "C" { // 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 +# define PYCAPI_COMPAT_INLINE(TYPE static __inline TYPE +#else +# define PYCAPI_COMPAT_STATIC_INLINE(TYPE) static inline TYPE #endif +// C++ compatibility +#ifdef __cplusplus +# define PYCAPI_COMPAT_CAST(TYPE, EXPR) reinterpret_cast(EXPR) +# define PYCAPI_COMPAT_NULL nullptr +#else +# define PYCAPI_COMPAT_CAST(TYPE, EXPR) (TYPE)(EXPR) +# define PYCAPI_COMPAT_NULL NULL +#endif + // Cast argument to PyObject* type. #ifndef _PyObject_CAST -# define _PyObject_CAST(op) ((PyObject*)(op)) +# define _PyObject_CAST(op) PYCAPI_COMPAT_CAST(PyObject*, op) #endif #ifndef _PyObject_CAST_CONST -# define _PyObject_CAST_CONST(op) ((const PyObject*)(op)) +# define _PyObject_CAST_CONST(op) PYCAPI_COMPAT_CAST(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) +PYCAPI_COMPAT_STATIC_INLINE(PyObject*) +_Py_NewRef(PyObject *obj) { Py_INCREF(obj); return obj; @@ -55,7 +64,8 @@ static inline PyObject* _Py_NewRef(PyObject *obj) // 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) +PYCAPI_COMPAT_STATIC_INLINE(PyObject*) +_Py_XNewRef(PyObject *obj) { Py_XINCREF(obj); return obj; @@ -66,7 +76,8 @@ static inline PyObject* _Py_XNewRef(PyObject *obj) // See https://bugs.python.org/issue42522 #if !defined(_Py_StealRef) -static inline PyObject* __Py_StealRef(PyObject *obj) +PYCAPI_COMPAT_STATIC_INLINE(PyObject*) +__Py_StealRef(PyObject *obj) { Py_DECREF(obj); return obj; @@ -77,7 +88,8 @@ static inline PyObject* __Py_StealRef(PyObject *obj) // See https://bugs.python.org/issue42522 #if !defined(_Py_XStealRef) -static inline PyObject* __Py_XStealRef(PyObject *obj) +PYCAPI_COMPAT_STATIC_INLINE(PyObject*) +__Py_XStealRef(PyObject *obj) { Py_XDECREF(obj); return obj; @@ -88,7 +100,8 @@ static inline PyObject* __Py_XStealRef(PyObject *obj) // 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) +PYCAPI_COMPAT_STATIC_INLINE(void) +_Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) { ob->ob_refcnt = refcnt; } @@ -133,7 +146,7 @@ static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) // bpo-39573 added Py_SET_TYPE() to Python 3.9.0a4 #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE) -static inline void +PYCAPI_COMPAT_STATIC_INLINE(void) _Py_SET_TYPE(PyObject *ob, PyTypeObject *type) { ob->ob_type = type; @@ -144,7 +157,7 @@ _Py_SET_TYPE(PyObject *ob, PyTypeObject *type) // bpo-39573 added Py_SET_SIZE() to Python 3.9.0a4 #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE) -static inline void +PYCAPI_COMPAT_STATIC_INLINE(void) _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { ob->ob_size = size; @@ -155,47 +168,49 @@ _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) // bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1 #if PY_VERSION_HEX < 0x030900B1 -static inline PyCodeObject* +PYCAPI_COMPAT_STATIC_INLINE(PyCodeObject*) PyFrame_GetCode(PyFrameObject *frame) { - assert(frame != NULL); - assert(frame->f_code != NULL); - return (PyCodeObject*)Py_NewRef(frame->f_code); + assert(frame != PYCAPI_COMPAT_NULL); + assert(frame->f_code != PYCAPI_COMPAT_NULL); + return PYCAPI_COMPAT_CAST(PyCodeObject*, Py_NewRef(frame->f_code)); } #endif -static inline PyCodeObject* +PYCAPI_COMPAT_STATIC_INLINE(PyCodeObject*) _PyFrame_GetCodeBorrow(PyFrameObject *frame) { - return (PyCodeObject *)_Py_StealRef(PyFrame_GetCode(frame)); + return PYCAPI_COMPAT_CAST(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* +PYCAPI_COMPAT_STATIC_INLINE(PyFrameObject*) PyFrame_GetBack(PyFrameObject *frame) { - assert(frame != NULL); - return (PyFrameObject*)Py_XNewRef(frame->f_back); + assert(frame != PYCAPI_COMPAT_NULL); + return PYCAPI_COMPAT_CAST(PyFrameObject*, Py_XNewRef(frame->f_back)); } #endif #if !defined(PYPY_VERSION) -static inline PyFrameObject* +PYCAPI_COMPAT_STATIC_INLINE(PyFrameObject*) _PyFrame_GetBackBorrow(PyFrameObject *frame) { - return (PyFrameObject *)_Py_XStealRef(PyFrame_GetBack(frame)); + return PYCAPI_COMPAT_CAST(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 * +PYCAPI_COMPAT_STATIC_INLINE(PyInterpreterState *) PyThreadState_GetInterpreter(PyThreadState *tstate) { - assert(tstate != NULL); + assert(tstate != PYCAPI_COMPAT_NULL); return tstate->interp; } #endif @@ -203,37 +218,38 @@ PyThreadState_GetInterpreter(PyThreadState *tstate) // bpo-40429 added PyThreadState_GetFrame() to Python 3.9.0b1 #if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION) -static inline PyFrameObject* +PYCAPI_COMPAT_STATIC_INLINE(PyFrameObject*) PyThreadState_GetFrame(PyThreadState *tstate) { - assert(tstate != NULL); - return (PyFrameObject *)Py_XNewRef(tstate->frame); + assert(tstate != PYCAPI_COMPAT_NULL); + return PYCAPI_COMPAT_CAST(PyFrameObject *, Py_XNewRef(tstate->frame)); } #endif #if !defined(PYPY_VERSION) -static inline PyFrameObject* +PYCAPI_COMPAT_STATIC_INLINE(PyFrameObject*) _PyThreadState_GetFrameBorrow(PyThreadState *tstate) { - return (PyFrameObject *)_Py_XStealRef(PyThreadState_GetFrame(tstate)); + return PYCAPI_COMPAT_CAST(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 * +PYCAPI_COMPAT_STATIC_INLINE(PyInterpreterState*) PyInterpreterState_Get(void) { PyThreadState *tstate; PyInterpreterState *interp; tstate = PyThreadState_GET(); - if (tstate == NULL) { + if (tstate == PYCAPI_COMPAT_NULL) { Py_FatalError("GIL released (tstate is NULL)"); } interp = tstate->interp; - if (interp == NULL) { + if (interp == PYCAPI_COMPAT_NULL) { Py_FatalError("no current interpreter"); } return interp; @@ -243,17 +259,18 @@ PyInterpreterState_Get(void) // 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 +PYCAPI_COMPAT_STATIC_INLINE(uint64_t) PyThreadState_GetID(PyThreadState *tstate) { - assert(tstate != NULL); + assert(tstate != PYCAPI_COMPAT_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) +PYCAPI_COMPAT_STATIC_INLINE(void) +PyThreadState_EnterTracing(PyThreadState *tstate) { tstate->tracing++; #if PY_VERSION_HEX >= 0x030A00A1 @@ -266,11 +283,12 @@ static inline void PyThreadState_EnterTracing(PyThreadState *tstate) // 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) +PYCAPI_COMPAT_STATIC_INLINE(void) +PyThreadState_LeaveTracing(PyThreadState *tstate) { + int use_tracing = (tstate->c_tracefunc != PYCAPI_COMPAT_NULL + || tstate->c_profilefunc != PYCAPI_COMPAT_NULL); 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 @@ -282,7 +300,7 @@ static inline void PyThreadState_LeaveTracing(PyThreadState *tstate) // bpo-37194 added PyObject_CallNoArgs() to Python 3.9.0a1 #if PY_VERSION_HEX < 0x030900A1 -static inline PyObject* +PYCAPI_COMPAT_STATIC_INLINE(PyObject*) PyObject_CallNoArgs(PyObject *func) { return PyObject_CallFunctionObjArgs(func, NULL); @@ -293,7 +311,7 @@ PyObject_CallNoArgs(PyObject *func) // bpo-39245 made PyObject_CallOneArg() public (previously called // _PyObject_CallOneArg) in Python 3.9.0a4 #if PY_VERSION_HEX < 0x030900A4 -static inline PyObject* +PYCAPI_COMPAT_STATIC_INLINE(PyObject*) PyObject_CallOneArg(PyObject *func, PyObject *arg) { return PyObject_CallFunctionObjArgs(func, arg, NULL); @@ -303,12 +321,12 @@ PyObject_CallOneArg(PyObject *func, PyObject *arg) // 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) +PYCAPI_COMPAT_STATIC_INLINE(int) +PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value) { int res; Py_XINCREF(value); - res = PyModule_AddObject(module, name, value); + res = PyModule_AddObject(mod, name, value); if (res < 0) { Py_XDECREF(value); } @@ -319,8 +337,8 @@ PyModule_AddObjectRef(PyObject *module, const char *name, PyObject *value) // bpo-40024 added PyModule_AddType() to Python 3.9.0a5 #if PY_VERSION_HEX < 0x030900A5 -static inline int -PyModule_AddType(PyObject *module, PyTypeObject *type) +PYCAPI_COMPAT_STATIC_INLINE(int) +PyModule_AddType(PyObject *mod, PyTypeObject *type) { const char *name, *dot; @@ -330,13 +348,13 @@ PyModule_AddType(PyObject *module, PyTypeObject *type) // inline _PyType_Name() name = type->tp_name; - assert(name != NULL); + assert(name != PYCAPI_COMPAT_NULL); dot = strrchr(name, '.'); - if (dot != NULL) { + if (dot != PYCAPI_COMPAT_NULL) { name = dot + 1; } - return PyModule_AddObjectRef(module, name, (PyObject *)type); + return PyModule_AddObjectRef(mod, name, _PyObject_CAST(type)); } #endif @@ -344,7 +362,7 @@ PyModule_AddType(PyObject *module, PyTypeObject *type) // 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 +PYCAPI_COMPAT_STATIC_INLINE(int) PyObject_GC_IsTracked(PyObject* obj) { return (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)); @@ -354,17 +372,18 @@ PyObject_GC_IsTracked(PyObject* obj) // 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 +PYCAPI_COMPAT_STATIC_INLINE(int) PyObject_GC_IsFinalized(PyObject *obj) { - return (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED((PyGC_Head *)(obj)-1)); + PyGC_Head *gc = PYCAPI_COMPAT_CAST(PyGC_Head *, obj) - 1; + return (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(gc)); } #endif // bpo-39573 added Py_IS_TYPE() to Python 3.9.0a4 #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_IS_TYPE) -static inline int +PYCAPI_COMPAT_STATIC_INLINE(int) _Py_IS_TYPE(const PyObject *ob, const PyTypeObject *type) { return ob->ob_type == type; } @@ -382,11 +401,6 @@ _Py_IS_TYPE(const PyObject *ob, const PyTypeObject *type) { #endif -#ifdef PYTHONCAPI_COMPAT_MSC_INLINE -# undef inline -# undef PYTHONCAPI_COMPAT_MSC_INLINE -#endif - #ifdef __cplusplus } #endif diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 2032ea034e71..5aa5e25487c4 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -909,20 +909,19 @@ L0: [case testDownCastSpecialCases] from typing import cast, Optional, Tuple class A: pass -def f(o: Optional[A], n: int, t: Tuple[int, ...]) -> None: +def f(o: Optional[A], n: int, t: Tuple[int, ...], tt: Tuple[int, int]) -> None: a = cast(A, o) m = cast(bool, n) - tt: Tuple[int, int] t = tt [out] -def f(o, n, t): +def f(o, n, t, tt): o :: union[__main__.A, None] n :: int t :: tuple + tt :: tuple[int, int] r0, a :: __main__.A r1 :: object r2, m :: bool - tt :: tuple[int, int] r3 :: object L0: r0 = cast(__main__.A, o) diff --git a/mypyc/test-data/irbuild-classes.test b/mypyc/test-data/irbuild-classes.test index 8f9b768df47c..77943045ffe3 100644 --- a/mypyc/test-data/irbuild-classes.test +++ b/mypyc/test-data/irbuild-classes.test @@ -795,6 +795,53 @@ L0: r0 = T.foo(self) return 1 +[case testSuperCallToObjectInitIsOmitted] +class C: + def __init__(self) -> None: + super().__init__() +class D: pass +class E(D): + def __init__(self) -> None: + super().__init__() +class F(C): + def __init__(self) -> None: + super().__init__() +class DictSubclass(dict): + def __init__(self) -> None: + super().__init__() +[out] +def C.__init__(self): + self :: __main__.C +L0: + return 1 +def E.__init__(self): + self :: __main__.E +L0: + return 1 +def F.__init__(self): + self :: __main__.F + r0 :: None +L0: + r0 = C.__init__(self) + return 1 +def DictSubclass.__init__(self): + self :: dict + r0 :: object + r1 :: str + r2, r3, r4 :: object + r5 :: str + r6, r7 :: object +L0: + r0 = builtins :: module + r1 = 'super' + r2 = CPyObject_GetAttr(r0, r1) + r3 = __main__.DictSubclass :: type + r4 = PyObject_CallFunctionObjArgs(r2, r3, self, 0) + r5 = '__init__' + r6 = CPyObject_GetAttr(r4, r5) + r7 = PyObject_CallFunctionObjArgs(r6, 0) + return 1 + [case testClassVariable] from typing import ClassVar class A: diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index 69dd42f01dd3..089a9a02b0b0 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -458,4 +458,3 @@ L2: L3: r7 = box(None, 1) return r7 - diff --git a/mypyc/test-data/run-classes.test b/mypyc/test-data/run-classes.test index e2beca1bafc6..83838e188762 100644 --- a/mypyc/test-data/run-classes.test +++ b/mypyc/test-data/run-classes.test @@ -336,6 +336,7 @@ class C: b: bool c: C d: object + e: int def setattrs(o: C, a: List[int], b: bool, c: C) -> None: o.a = a @@ -346,6 +347,8 @@ def getattrs(o: C) -> Tuple[List[int], bool, C]: return o.a, o.b, o.c [file driver.py] from native import C, setattrs, getattrs +from testutil import assertRaises + c1 = C() c2 = C() aa = [2] @@ -359,6 +362,18 @@ o = object() c1.d = o assert c1.d is o +c3 = C() +with assertRaises(AttributeError, "attribute 'a' of 'C' undefined"): + c3.a +with assertRaises(AttributeError, "attribute 'b' of 'C' undefined"): + c3.b +with assertRaises(AttributeError, "attribute 'c' of 'C' undefined"): + c3.c +with assertRaises(AttributeError, "attribute 'd' of 'C' undefined"): + c3.d +with assertRaises(AttributeError, "attribute 'e' of 'C' undefined"): + c3.e + [case testInitMethodWithMissingNoneReturnAnnotation] class C: def __init__(self): diff --git a/mypyc/test-data/run-multimodule.test b/mypyc/test-data/run-multimodule.test index 1444254b7595..20c9002cdf1d 100644 --- a/mypyc/test-data/run-multimodule.test +++ b/mypyc/test-data/run-multimodule.test @@ -1,4 +1,14 @@ --- These test cases compile two modules at a time (native and other.py) +-- These test cases compile two or more modules at a time. +-- Any file prefixed with "other" is compiled. +-- +-- Note that these are run in three compilation modes: regular, +-- multi-file and separate. See the docstrings of +-- mypyc.test.test_run.TestRunMultiFile and +-- mypyc.test.test_run.TestRunSeparate for more information. +-- +-- Some of these files perform multiple incremental runs. See +-- test-data/unit/check-incremental.test for more information +-- about how this is specified (e.g. .2 file name suffixes). [case testMultiModulePackage] from p.other import g diff --git a/mypyc/test/config.py b/mypyc/test/config.py index 6b2c09d1ebfb..1158c5c459be 100644 --- a/mypyc/test/config.py +++ b/mypyc/test/config.py @@ -1,7 +1,11 @@ import os -this_file_dir = os.path.dirname(os.path.realpath(__file__)) -prefix = os.path.dirname(os.path.dirname(this_file_dir)) +provided_prefix = os.getenv('MYPY_TEST_PREFIX', None) +if provided_prefix: + PREFIX = provided_prefix +else: + this_file_dir = os.path.dirname(os.path.realpath(__file__)) + PREFIX = os.path.dirname(os.path.dirname(this_file_dir)) -# Locations of test data files such as test case descriptions (.test). -test_data_prefix = os.path.join(prefix, 'mypyc', 'test-data') +# Location of test data files such as test case descriptions. +test_data_prefix = os.path.join(PREFIX, 'mypyc', 'test-data') diff --git a/mypyc/test/test_emitfunc.py b/mypyc/test/test_emitfunc.py index a3f55a7facf2..c18cd37b1707 100644 --- a/mypyc/test/test_emitfunc.py +++ b/mypyc/test/test_emitfunc.py @@ -187,6 +187,29 @@ def test_branch_is_error_next_block(self) -> None: """if (cpy_r_b == 2) goto CPyL9;""", next_block=next_block) + def test_branch_rare(self) -> None: + self.assert_emit(Branch(self.b, BasicBlock(8), BasicBlock(9), Branch.BOOL, rare=True), + """if (unlikely(cpy_r_b)) { + goto CPyL8; + } else + goto CPyL9; + """) + next_block = BasicBlock(9) + self.assert_emit(Branch(self.b, BasicBlock(8), next_block, Branch.BOOL, rare=True), + """if (unlikely(cpy_r_b)) goto CPyL8;""", + next_block=next_block) + next_block = BasicBlock(8) + b = Branch(self.b, next_block, BasicBlock(9), Branch.BOOL, rare=True) + self.assert_emit(b, + """if (likely(!cpy_r_b)) goto CPyL9;""", + next_block=next_block) + next_block = BasicBlock(8) + b = Branch(self.b, next_block, BasicBlock(9), Branch.BOOL, rare=True) + b.negated = True + self.assert_emit(b, + """if (likely(cpy_r_b)) goto CPyL9;""", + next_block=next_block) + def test_call(self) -> None: decl = FuncDecl('myfn', None, 'mod', FuncSignature([RuntimeArg('m', int_rprimitive)], int_rprimitive)) @@ -265,6 +288,15 @@ def test_get_attr(self) -> None: } """) + def test_get_attr_non_refcounted(self) -> None: + self.assert_emit( + GetAttr(self.r, 'x', 1), + """cpy_r_r0 = ((mod___AObject *)cpy_r_r)->_x; + if (unlikely(((mod___AObject *)cpy_r_r)->_x == 2)) { + PyErr_SetString(PyExc_AttributeError, "attribute 'x' of 'A' undefined"); + } + """) + def test_set_attr(self) -> None: self.assert_emit( SetAttr(self.r, 'y', self.m, 1), diff --git a/mypyc/test/test_ircheck.py b/mypyc/test/test_ircheck.py index 28d3c8e8c25d..3c56ddac3e85 100644 --- a/mypyc/test/test_ircheck.py +++ b/mypyc/test/test_ircheck.py @@ -1,9 +1,15 @@ 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 typing import List, Optional + +from mypyc.analysis.ircheck import check_func_ir, FnError, can_coerce_to +from mypyc.ir.class_ir import ClassIR +from mypyc.ir.rtypes import ( + none_rprimitive, str_rprimitive, int32_rprimitive, int64_rprimitive, + RType, RUnion, bytes_rprimitive, RInstance, object_rprimitive +) +from mypyc.ir.ops import ( + BasicBlock, Op, Return, Integer, Goto, Register, LoadLiteral, Assign +) from mypyc.ir.func_ir import FuncIR, FuncDecl, FuncSignature from mypyc.ir.pprint import format_func @@ -30,19 +36,33 @@ def basic_block(self, ops: List[Op]) -> BasicBlock: 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 func_decl(self, name: str, ret_type: Optional[RType] = None) -> FuncDecl: + if ret_type is None: + ret_type = none_rprimitive + return FuncDecl( + name=name, + class_name=None, + module_name="module", + sig=FuncSignature( + args=[], + ret_type=ret_type, + ), + ) 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), - ])], - )) + 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([]) @@ -73,7 +93,108 @@ def test_invalid_goto(self) -> None: # block_1 omitted blocks=[block_2], ) - assert_has_error(fn, FnError(source=goto, desc="Invalid control operation target: 1")) + assert_has_error( + fn, FnError(source=goto, desc="Invalid control operation target: 1") + ) + + def test_invalid_register_source(self) -> None: + ret = Return( + value=Register( + type=none_rprimitive, + name="r1", + ) + ) + block = self.basic_block([ret]) + fn = FuncIR( + decl=self.func_decl(name="func_1"), + arg_regs=[], + blocks=[block], + ) + assert_has_error( + fn, FnError(source=ret, desc="Invalid op reference to register r1") + ) + + def test_invalid_op_source(self) -> None: + ret = Return( + value=LoadLiteral( + value="foo", + rtype=str_rprimitive, + ) + ) + block = self.basic_block([ret]) + fn = FuncIR( + decl=self.func_decl(name="func_1"), + arg_regs=[], + blocks=[block], + ) + assert_has_error( + fn, + FnError(source=ret, desc="Invalid op reference to op of type LoadLiteral"), + ) + + def test_invalid_return_type(self) -> None: + ret = Return(value=Integer(value=5, rtype=int32_rprimitive)) + fn = FuncIR( + decl=self.func_decl(name="func_1", ret_type=int64_rprimitive), + arg_regs=[], + blocks=[self.basic_block([ret])], + ) + assert_has_error( + fn, + FnError( + source=ret, desc="Cannot coerce source type int32 to dest type int64" + ), + ) + + def test_invalid_assign(self) -> None: + arg_reg = Register(type=int64_rprimitive, name="r1") + assign = Assign(dest=arg_reg, src=Integer(value=5, rtype=int32_rprimitive)) + ret = Return(value=NONE_VALUE) + fn = FuncIR( + decl=self.func_decl(name="func_1"), + arg_regs=[arg_reg], + blocks=[self.basic_block([assign, ret])], + ) + assert_has_error( + fn, + FnError( + source=assign, desc="Cannot coerce source type int32 to dest type int64" + ), + ) + + def test_can_coerce_to(self) -> None: + cls = ClassIR(name="Cls", module_name="cls") + valid_cases = [ + (int64_rprimitive, int64_rprimitive), + (str_rprimitive, str_rprimitive), + (str_rprimitive, object_rprimitive), + (object_rprimitive, str_rprimitive), + (RUnion([bytes_rprimitive, str_rprimitive]), str_rprimitive), + (str_rprimitive, RUnion([bytes_rprimitive, str_rprimitive])), + (RInstance(cls), object_rprimitive), + ] + + invalid_cases = [ + (int64_rprimitive, int32_rprimitive), + (RInstance(cls), str_rprimitive), + (str_rprimitive, bytes_rprimitive), + ] + + for src, dest in valid_cases: + assert can_coerce_to(src, dest) + for src, dest in invalid_cases: + assert not can_coerce_to(src, dest) + + def test_duplicate_op(self) -> None: + arg_reg = Register(type=int32_rprimitive, name="r1") + assign = Assign(dest=arg_reg, src=Integer(value=5, rtype=int32_rprimitive)) + block = self.basic_block([assign, assign, Return(value=NONE_VALUE)]) + fn = FuncIR( + decl=self.func_decl(name="func_1"), + arg_regs=[], + blocks=[block], + ) + assert_has_error(fn, FnError(source=assign, desc="Func has a duplicate op")) def test_pprint(self) -> None: block_1 = self.basic_block([Return(value=NONE_VALUE)]) diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index 306c151ef319..a5e356ea56a6 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -127,7 +127,7 @@ class TestRun(MypycDataSuite): base_path = test_temp_dir optional_out = True multi_file = False - separate = False + separate = False # If True, using separate (incremental) compilation def run_case(self, testcase: DataDrivenTestCase) -> None: # setup.py wants to be run from the root directory of the package, which we accommodate @@ -347,7 +347,11 @@ def get_separate(self, program_text: str, class TestRunMultiFile(TestRun): - """Run the main multi-module tests in multi-file compilation mode.""" + """Run the main multi-module tests in multi-file compilation mode. + + In multi-file mode each module gets compiled into a separate C file, + but all modules (C files) are compiled together. + """ multi_file = True test_name_suffix = '_multi' @@ -358,7 +362,20 @@ class TestRunMultiFile(TestRun): class TestRunSeparate(TestRun): - """Run the main multi-module tests in separate compilation mode.""" + """Run the main multi-module tests in separate compilation mode. + + In this mode there are multiple compilation groups, which are compiled + incrementally. Each group is compiled to a separate C file, and these C + files are compiled separately. + + Each compiled module is placed into a separate compilation group, unless + overridden by a special comment. Consider this example: + + # separate: [(["other.py", "other_b.py"], "stuff")] + + This puts other.py and other_b.py into a compilation group named "stuff". + Any files not mentioned in the comment will get single-file groups. + """ separate = True test_name_suffix = '_separate' diff --git a/setup.py b/setup.py index 10042279a446..233ad30294c6 100644 --- a/setup.py +++ b/setup.py @@ -107,6 +107,8 @@ def run(self): )) + ( # Don't want to grab this accidentally os.path.join('mypyc', 'lib-rt', 'setup.py'), + # Uses __file__ at top level https://github.com/mypyc/mypyc/issues/700 + os.path.join('mypyc', '__main__.py'), ) everything = ( @@ -199,7 +201,11 @@ def run(self): 'tomli>=1.1.0', ], # Same here. - extras_require={'dmypy': 'psutil >= 4.0', 'python2': 'typed_ast >= 1.4.0, < 2'}, + extras_require={ + 'dmypy': 'psutil >= 4.0', + 'python2': 'typed_ast >= 1.4.0, < 2', + 'reports': 'lxml' + }, python_requires=">=3.6", include_package_data=True, project_urls={ diff --git a/test-data/samples/bottles.py b/test-data/samples/bottles.py deleted file mode 100644 index ddf77f59eaa0..000000000000 --- a/test-data/samples/bottles.py +++ /dev/null @@ -1,13 +0,0 @@ -import typing - -REFRAIN = ''' -%d bottles of beer on the wall, -%d bottles of beer, -take one down, pass it around, -%d bottles of beer on the wall! -''' -bottles_of_beer = 99 -while bottles_of_beer > 1: - print(REFRAIN % (bottles_of_beer, bottles_of_beer, - bottles_of_beer - 1)) - bottles_of_beer -= 1 diff --git a/test-data/samples/class.py b/test-data/samples/class.py deleted file mode 100644 index d2eb4ac0516f..000000000000 --- a/test-data/samples/class.py +++ /dev/null @@ -1,18 +0,0 @@ -import typing - - -class BankAccount(object): - def __init__(self, initial_balance: int = 0) -> None: - self.balance = initial_balance - - def deposit(self, amount: int) -> None: - self.balance += amount - - def withdraw(self, amount: int) -> None: - self.balance -= amount - - def overdrawn(self) -> bool: - return self.balance < 0 -my_account = BankAccount(15) -my_account.withdraw(5) -print(my_account.balance) diff --git a/test-data/samples/cmdline.py b/test-data/samples/cmdline.py deleted file mode 100644 index 105c27a305b9..000000000000 --- a/test-data/samples/cmdline.py +++ /dev/null @@ -1,8 +0,0 @@ -# This program adds up integers in the command line -import sys -import typing -try: - total = sum(int(arg) for arg in sys.argv[1:]) - print('sum =', total) -except ValueError: - print('Please supply integer arguments') diff --git a/test-data/samples/crawl2.py b/test-data/samples/crawl2.py deleted file mode 100644 index 28b19f38c7c5..000000000000 --- a/test-data/samples/crawl2.py +++ /dev/null @@ -1,852 +0,0 @@ -#!/usr/bin/env python3.4 - -"""A simple web crawler.""" - -# This is cloned from /examples/crawl.py, -# with type annotations added (PEP 484). -# -# This version (crawl2.) has also been converted to use `async def` + -# `await` (PEP 492). - -import argparse -import asyncio -import cgi -from http.client import BadStatusLine -import logging -import re -import sys -import time -import urllib.parse -from typing import Any, Awaitable, IO, Optional, Sequence, Set, Tuple, List, Dict - - -ARGS = argparse.ArgumentParser(description="Web crawler") -ARGS.add_argument( - '--iocp', action='store_true', dest='iocp', - default=False, help='Use IOCP event loop (Windows only)') -ARGS.add_argument( - '--select', action='store_true', dest='select', - default=False, help='Use Select event loop instead of default') -ARGS.add_argument( - 'roots', nargs='*', - default=[], help='Root URL (may be repeated)') -ARGS.add_argument( - '--max_redirect', action='store', type=int, metavar='N', - default=10, help='Limit redirection chains (for 301, 302 etc.)') -ARGS.add_argument( - '--max_tries', action='store', type=int, metavar='N', - default=4, help='Limit retries on network errors') -ARGS.add_argument( - '--max_tasks', action='store', type=int, metavar='N', - default=100, help='Limit concurrent connections') -ARGS.add_argument( - '--max_pool', action='store', type=int, metavar='N', - default=100, help='Limit connection pool size') -ARGS.add_argument( - '--exclude', action='store', metavar='REGEX', - help='Exclude matching URLs') -ARGS.add_argument( - '--strict', action='store_true', - default=True, help='Strict host matching (default)') -ARGS.add_argument( - '--lenient', action='store_false', dest='strict', - default=False, help='Lenient host matching') -ARGS.add_argument( - '-v', '--verbose', action='count', dest='level', - default=1, help='Verbose logging (repeat for more verbose)') -ARGS.add_argument( - '-q', '--quiet', action='store_const', const=0, dest='level', - default=1, help='Quiet logging (opposite of --verbose)') - - -ESCAPES = [('quot', '"'), - ('gt', '>'), - ('lt', '<'), - ('amp', '&') # Must be last. - ] - - -def unescape(url: str) -> str: - """Turn & into &, and so on. - - This is the inverse of cgi.escape(). - """ - for name, char in ESCAPES: - url = url.replace('&' + name + ';', char) - return url - - -def fix_url(url: str) -> str: - """Prefix a schema-less URL with http://.""" - if '://' not in url: - url = 'http://' + url - return url - - -class Logger: - - def __init__(self, level: int) -> None: - self.level = level - - def _log(self, n: int, args: Sequence[Any]) -> None: - if self.level >= n: - print(*args, file=sys.stderr, flush=True) - - def log(self, n: int, *args: Any) -> None: - self._log(n, args) - - def __call__(self, n: int, *args: Any) -> None: - self._log(n, args) - - -KeyTuple = Tuple[str, int, bool] - - -class ConnectionPool: - """A connection pool. - - To open a connection, use reserve(). To recycle it, use unreserve(). - - The pool is mostly just a mapping from (host, port, ssl) tuples to - lists of Connections. The currently active connections are *not* - in the data structure; get_connection() takes the connection out, - and recycle_connection() puts it back in. To recycle a - connection, call conn.close(recycle=True). - - There are limits to both the overall pool and the per-key pool. - """ - - def __init__(self, log: Logger, max_pool: int = 10, max_tasks: int = 5) -> None: - self.log = log - self.max_pool = max_pool # Overall limit. - self.max_tasks = max_tasks # Per-key limit. - self.loop = asyncio.get_event_loop() - self.connections = {} # type: Dict[KeyTuple, List[Connection]] - self.queue = [] # type: List[Connection] - - def close(self) -> None: - """Close all connections available for reuse.""" - for conns in self.connections.values(): - for conn in conns: - conn.close() - self.connections.clear() - self.queue.clear() - - async def get_connection(self, host: str, port: int, ssl: bool) -> 'Connection': - """Create or reuse a connection.""" - port = port or (443 if ssl else 80) - try: - ipaddrs = await self.loop.getaddrinfo(host, port) - except Exception as exc: - self.log(0, 'Exception %r for (%r, %r)' % (exc, host, port)) - raise - self.log(1, '* %s resolves to %s' % - (host, ', '.join(ip[4][0] for ip in ipaddrs))) - - # Look for a reusable connection. - for _1, _2, _3, _4, (h, p, *_5) in ipaddrs: - key = h, p, ssl - conn = None - conns = self.connections.get(key) - while conns: - conn = conns.pop(0) - self.queue.remove(conn) - if not conns: - del self.connections[key] - if conn.stale(): - self.log(1, 'closing stale connection for', key) - conn.close() # Just in case. - else: - self.log(1, '* Reusing pooled connection', key, - 'FD =', conn.fileno()) - return conn - - # Create a new connection. - conn = Connection(self.log, self, host, port, ssl) - await conn.connect() - self.log(1, '* New connection', conn.key, 'FD =', conn.fileno()) - return conn - - def recycle_connection(self, conn: 'Connection') -> None: - """Make a connection available for reuse. - - This also prunes the pool if it exceeds the size limits. - """ - if conn.stale(): - conn.close() - return - - key = conn.key - conns = self.connections.setdefault(key, []) - conns.append(conn) - self.queue.append(conn) - - if len(conns) <= self.max_tasks and len(self.queue) <= self.max_pool: - return - - # Prune the queue. - - # Close stale connections for this key first. - stale = [conn for conn in conns if conn.stale()] - if stale: - for conn in stale: - conns.remove(conn) - self.queue.remove(conn) - self.log(1, 'closing stale connection for', key) - conn.close() - if not conns: - del self.connections[key] - - # Close oldest connection(s) for this key if limit reached. - while len(conns) > self.max_tasks: - conn = conns.pop(0) - self.queue.remove(conn) - self.log(1, 'closing oldest connection for', key) - conn.close() - - if len(self.queue) <= self.max_pool: - return - - # Close overall stale connections. - stale = [conn for conn in self.queue if conn.stale()] - if stale: - for conn in stale: - conns = self.connections.get(conn.key) - conns.remove(conn) - self.queue.remove(conn) - self.log(1, 'closing stale connection for', key) - conn.close() - - # Close oldest overall connection(s) if limit reached. - while len(self.queue) > self.max_pool: - conn = self.queue.pop(0) - conns = self.connections.get(conn.key) - c = conns.pop(0) - assert conn == c, (conn.key, conn, c, conns) - self.log(1, 'closing overall oldest connection for', conn.key) - conn.close() - - -class Connection: - - def __init__(self, log: Logger, pool: ConnectionPool, host: str, port: int, ssl: bool) -> None: - self.log = log - self.pool = pool - self.host = host - self.port = port - self.ssl = ssl - self.reader = None # type: asyncio.StreamReader - self.writer = None # type: asyncio.StreamWriter - self.key = None # type: KeyTuple - - def stale(self) -> bool: - return self.reader is None or self.reader.at_eof() - - def fileno(self) -> Optional[int]: - writer = self.writer - if writer is not None: - transport = writer.transport - if transport is not None: - sock = transport.get_extra_info('socket') - if sock is not None: - return sock.fileno() - return None - - async def connect(self) -> None: - self.reader, self.writer = await asyncio.open_connection( - self.host, self.port, ssl=self.ssl) - peername = self.writer.get_extra_info('peername') - if peername: - self.host, self.port = peername[:2] - else: - self.log(1, 'NO PEERNAME???', self.host, self.port, self.ssl) - self.key = self.host, self.port, self.ssl - - def close(self, recycle: bool = False) -> None: - if recycle and not self.stale(): - self.pool.recycle_connection(self) - else: - self.writer.close() - self.pool = self.reader = self.writer = None - - -class Request: - """HTTP request. - - Use connect() to open a connection; send_request() to send the - request; get_response() to receive the response headers. - """ - - def __init__(self, log: Logger, url: str, pool: ConnectionPool) -> None: - self.log = log - self.url = url - self.pool = pool - self.parts = urllib.parse.urlparse(self.url) - self.scheme = self.parts.scheme - assert self.scheme in ('http', 'https'), repr(url) - self.ssl = self.parts.scheme == 'https' - self.netloc = self.parts.netloc - self.hostname = self.parts.hostname - self.port = self.parts.port or (443 if self.ssl else 80) - self.path = (self.parts.path or '/') - self.query = self.parts.query - if self.query: - self.full_path = '%s?%s' % (self.path, self.query) - else: - self.full_path = self.path - self.http_version = 'HTTP/1.1' - self.method = 'GET' - self.headers = [] # type: List[Tuple[str, str]] - self.conn = None # type: Connection - - async def connect(self) -> None: - """Open a connection to the server.""" - self.log(1, '* Connecting to %s:%s using %s for %s' % - (self.hostname, self.port, - 'ssl' if self.ssl else 'tcp', - self.url)) - self.conn = await self.pool.get_connection(self.hostname, - self.port, self.ssl) - - def close(self, recycle: bool = False) -> None: - """Close the connection, recycle if requested.""" - if self.conn is not None: - if not recycle: - self.log(1, 'closing connection for', self.conn.key) - self.conn.close(recycle) - self.conn = None - - async def putline(self, line: str) -> None: - """Write a line to the connection. - - Used for the request line and headers. - """ - self.log(2, '>', line) - self.conn.writer.write(line.encode('latin-1') + b'\r\n') - - async def send_request(self) -> None: - """Send the request.""" - request_line = '%s %s %s' % (self.method, self.full_path, - self.http_version) - await self.putline(request_line) - # TODO: What if a header is already set? - self.headers.append(('User-Agent', 'asyncio-example-crawl/0.0')) - self.headers.append(('Host', self.netloc)) - self.headers.append(('Accept', '*/*')) - # self.headers.append(('Accept-Encoding', 'gzip')) - for key, value in self.headers: - line = '%s: %s' % (key, value) - await self.putline(line) - await self.putline('') - - async def get_response(self) -> 'Response': - """Receive the response.""" - response = Response(self.log, self.conn.reader) - await response.read_headers() - return response - - -class Response: - """HTTP response. - - Call read_headers() to receive the request headers. Then check - the status attribute and call get_header() to inspect the headers. - Finally call read() to receive the body. - """ - - def __init__(self, log: Logger, reader: asyncio.StreamReader) -> None: - self.log = log - self.reader = reader - self.http_version = None # type: str # 'HTTP/1.1' - self.status = None # type: int # 200 - self.reason = None # type: str # 'Ok' - self.headers = [] # type: List[Tuple[str, str]] # [('Content-Type', 'text/html')] - - async def getline(self) -> str: - """Read one line from the connection.""" - line = (await self.reader.readline()).decode('latin-1').rstrip() - self.log(2, '<', line) - return line - - async def read_headers(self) -> None: - """Read the response status and the request headers.""" - status_line = await self.getline() - status_parts = status_line.split(None, 2) - if len(status_parts) != 3: - self.log(0, 'bad status_line', repr(status_line)) - raise BadStatusLine(status_line) - self.http_version, status, self.reason = status_parts - self.status = int(status) - while True: - header_line = await self.getline() - if not header_line: - break - # TODO: Continuation lines. - key, value = header_line.split(':', 1) - self.headers.append((key, value.strip())) - - def get_redirect_url(self, default: str = '') -> str: - """Inspect the status and return the redirect url if appropriate.""" - if self.status not in (300, 301, 302, 303, 307): - return default - return self.get_header('Location', default) - - def get_header(self, key: str, default: str = '') -> str: - """Get one header value, using a case insensitive header name.""" - key = key.lower() - for k, v in self.headers: - if k.lower() == key: - return v - return default - - async def read(self) -> bytes: - """Read the response body. - - This honors Content-Length and Transfer-Encoding: chunked. - """ - nbytes = None - for key, value in self.headers: - if key.lower() == 'content-length': - nbytes = int(value) - break - if nbytes is None: - if self.get_header('transfer-encoding').lower() == 'chunked': - self.log(2, 'parsing chunked response') - blocks = [] - while True: - size_header = await self.reader.readline() - if not size_header: - self.log(0, 'premature end of chunked response') - break - self.log(3, 'size_header =', repr(size_header)) - parts = size_header.split(b';') - size = int(parts[0], 16) - if size: - self.log(3, 'reading chunk of', size, 'bytes') - block = await self.reader.readexactly(size) - assert len(block) == size, (len(block), size) - blocks.append(block) - crlf = await self.reader.readline() - assert crlf == b'\r\n', repr(crlf) - if not size: - break - body = b''.join(blocks) - self.log(1, 'chunked response had', len(body), - 'bytes in', len(blocks), 'blocks') - else: - self.log(3, 'reading until EOF') - body = await self.reader.read() - # TODO: Should make sure not to recycle the connection - # in this case. - else: - body = await self.reader.readexactly(nbytes) - return body - - -class Fetcher: - """Logic and state for one URL. - - When found in crawler.busy, this represents a URL to be fetched or - in the process of being fetched; when found in crawler.done, this - holds the results from fetching it. - - This is usually associated with a task. This references the - crawler for the connection pool and to add more URLs to its todo - list. - - Call fetch() to do the fetching, then report() to print the results. - """ - - def __init__(self, log: Logger, url: str, crawler: 'Crawler', - max_redirect: int = 10, max_tries: int = 4) -> None: - self.log = log - self.url = url - self.crawler = crawler - # We don't loop resolving redirects here -- we just use this - # to decide whether to add the redirect URL to crawler.todo. - self.max_redirect = max_redirect - # But we do loop to retry on errors a few times. - self.max_tries = max_tries - # Everything we collect from the response goes here. - self.task = None # type: asyncio.Task - self.exceptions = [] # type: List[Exception] - self.tries = 0 - self.request = None # type: Request - self.response = None # type: Response - self.body = None # type: bytes - self.next_url = None # type: str - self.ctype = None # type: str - self.pdict = None # type: Dict[str, str] - self.encoding = None # type: str - self.urls = None # type: Set[str] - self.new_urls = None # type: Set[str] - - async def fetch(self) -> None: - """Attempt to fetch the contents of the URL. - - If successful, and the data is HTML, extract further links and - add them to the crawler. Redirects are also added back there. - """ - while self.tries < self.max_tries: - self.tries += 1 - self.request = None - try: - self.request = Request(self.log, self.url, self.crawler.pool) - await self.request.connect() - await self.request.send_request() - self.response = await self.request.get_response() - self.body = await self.response.read() - h_conn = self.response.get_header('connection').lower() - if h_conn != 'close': - self.request.close(recycle=True) - self.request = None - if self.tries > 1: - self.log(1, 'try', self.tries, 'for', self.url, 'success') - break - except (BadStatusLine, OSError) as exc: - self.exceptions.append(exc) - self.log(1, 'try', self.tries, 'for', self.url, - 'raised', repr(exc)) - # import pdb; pdb.set_trace() - # Don't reuse the connection in this case. - finally: - if self.request is not None: - self.request.close() - else: - # We never broke out of the while loop, i.e. all tries failed. - self.log(0, 'no success for', self.url, - 'in', self.max_tries, 'tries') - return - next_url = self.response.get_redirect_url() - if next_url: - self.next_url = urllib.parse.urljoin(self.url, next_url) - if self.max_redirect > 0: - self.log(1, 'redirect to', self.next_url, 'from', self.url) - self.crawler.add_url(self.next_url, self.max_redirect - 1) - else: - self.log(0, 'redirect limit reached for', self.next_url, - 'from', self.url) - else: - if self.response.status == 200: - self.ctype = self.response.get_header('content-type') - self.pdict = {} - if self.ctype: - self.ctype, self.pdict = cgi.parse_header(self.ctype) - self.encoding = self.pdict.get('charset', 'utf-8') - if self.ctype == 'text/html': - body = self.body.decode(self.encoding, 'replace') - # Replace href with (?:href|src) to follow image links. - self.urls = set(re.findall(r'(?i)href=["\']?([^\s"\'<>]+)', - body)) - if self.urls: - self.log(1, 'got', len(self.urls), - 'distinct urls from', self.url) - self.new_urls = set() - for url in self.urls: - url = unescape(url) - url = urllib.parse.urljoin(self.url, url) - url, frag = urllib.parse.urldefrag(url) - if self.crawler.add_url(url): - self.new_urls.add(url) - - def report(self, stats: 'Stats', file: IO[str] = None) -> None: - """Print a report on the state for this URL. - - Also update the Stats instance. - """ - if self.task is not None: - if not self.task.done(): - stats.add('pending') - print(self.url, 'pending', file=file) - return - elif self.task.cancelled(): - stats.add('cancelled') - print(self.url, 'cancelled', file=file) - return - elif self.task.exception(): - stats.add('exception') - exc = self.task.exception() - stats.add('exception_' + exc.__class__.__name__) - print(self.url, exc, file=file) - return - if len(self.exceptions) == self.tries: - stats.add('fail') - exc = self.exceptions[-1] - stats.add('fail_' + str(exc.__class__.__name__)) - print(self.url, 'error', exc, file=file) - elif self.next_url: - stats.add('redirect') - print(self.url, self.response.status, 'redirect', self.next_url, - file=file) - elif self.ctype == 'text/html': - stats.add('html') - size = len(self.body or b'') - stats.add('html_bytes', size) - if self.log.level: - print(self.url, self.response.status, - self.ctype, self.encoding, - size, - '%d/%d' % (len(self.new_urls or ()), len(self.urls or ())), - file=file) - elif self.response is None: - print(self.url, 'no response object') - else: - size = len(self.body or b'') - if self.response.status == 200: - stats.add('other') - stats.add('other_bytes', size) - else: - stats.add('error') - stats.add('error_bytes', size) - stats.add('status_%s' % self.response.status) - print(self.url, self.response.status, - self.ctype, self.encoding, - size, - file=file) - - -class Stats: - """Record stats of various sorts.""" - - def __init__(self) -> None: - self.stats = {} # type: Dict[str, int] - - def add(self, key: str, count: int = 1) -> None: - self.stats[key] = self.stats.get(key, 0) + count - - def report(self, file: IO[str] = None) -> None: - for key, count in sorted(self.stats.items()): - print('%10d' % count, key, file=file) - - -class Crawler: - """Crawl a set of URLs. - - This manages three disjoint sets of URLs (todo, busy, done). The - data structures actually store dicts -- the values in todo give - the redirect limit, while the values in busy and done are Fetcher - instances. - """ - def __init__(self, log: Logger, - roots: Set[str], exclude: str = None, strict: bool = True, # What to crawl. - max_redirect: int = 10, max_tries: int = 4, # Per-url limits. - max_tasks: int = 10, max_pool: int = 10, # Global limits. - ) -> None: - self.log = log - self.roots = roots - self.exclude = exclude - self.strict = strict - self.max_redirect = max_redirect - self.max_tries = max_tries - self.max_tasks = max_tasks - self.max_pool = max_pool - self.todo = {} # type: Dict[str, int] - self.busy = {} # type: Dict[str, Fetcher] - self.done = {} # type: Dict[str, Fetcher] - self.pool = ConnectionPool(self.log, max_pool, max_tasks) - self.root_domains = set() # type: Set[str] - for root in roots: - host = urllib.parse.urlparse(root).hostname - if not host: - continue - if re.match(r'\A[\d\.]*\Z', host): - self.root_domains.add(host) - else: - host = host.lower() - if self.strict: - self.root_domains.add(host) - if host.startswith('www.'): - self.root_domains.add(host[4:]) - else: - self.root_domains.add('www.' + host) - else: - parts = host.split('.') - if len(parts) > 2: - host = '.'.join(parts[-2:]) - self.root_domains.add(host) - for root in roots: - self.add_url(root) - self.governor = asyncio.Semaphore(max_tasks) - self.termination = asyncio.Condition() - self.t0 = time.time() - self.t1 = None # type: Optional[float] - - def close(self) -> None: - """Close resources (currently only the pool).""" - self.pool.close() - - def host_okay(self, host: str) -> bool: - """Check if a host should be crawled. - - A literal match (after lowercasing) is always good. For hosts - that don't look like IP addresses, some approximate matches - are okay depending on the strict flag. - """ - host = host.lower() - if host in self.root_domains: - return True - if re.match(r'\A[\d\.]*\Z', host): - return False - if self.strict: - return self._host_okay_strictish(host) - else: - return self._host_okay_lenient(host) - - def _host_okay_strictish(self, host: str) -> bool: - """Check if a host should be crawled, strict-ish version. - - This checks for equality modulo an initial 'www.' component. - """ - if host.startswith('www.'): - if host[4:] in self.root_domains: - return True - else: - if 'www.' + host in self.root_domains: - return True - return False - - def _host_okay_lenient(self, host: str) -> bool: - """Check if a host should be crawled, lenient version. - - This compares the last two components of the host. - """ - parts = host.split('.') - if len(parts) > 2: - host = '.'.join(parts[-2:]) - return host in self.root_domains - - def add_url(self, url: str, max_redirect: int = None) -> bool: - """Add a URL to the todo list if not seen before.""" - if self.exclude and re.search(self.exclude, url): - return False - parsed = urllib.parse.urlparse(url) - if parsed.scheme not in ('http', 'https'): - self.log(2, 'skipping non-http scheme in', url) - return False - host = parsed.hostname - if not self.host_okay(host): - self.log(2, 'skipping non-root host in', url) - return False - if max_redirect is None: - max_redirect = self.max_redirect - if url in self.todo or url in self.busy or url in self.done: - return False - self.log(1, 'adding', url, max_redirect) - self.todo[url] = max_redirect - return True - - async def crawl(self) -> None: - """Run the crawler until all finished.""" - with (await self.termination): - while self.todo or self.busy: - if self.todo: - url, max_redirect = self.todo.popitem() - fetcher = Fetcher(self.log, url, - crawler=self, - max_redirect=max_redirect, - max_tries=self.max_tries, - ) - self.busy[url] = fetcher - fetcher.task = asyncio.Task(self.fetch(fetcher)) - else: - await self.termination.wait() - self.t1 = time.time() - - async def fetch(self, fetcher: Fetcher) -> None: - """Call the Fetcher's fetch(), with a limit on concurrency. - - Once this returns, move the fetcher from busy to done. - """ - url = fetcher.url - with (await self.governor): - try: - await fetcher.fetch() # Fetcher gonna fetch. - finally: - # Force GC of the task, so the error is logged. - fetcher.task = None - with (await self.termination): - self.done[url] = fetcher - del self.busy[url] - self.termination.notify() - - def report(self, file: IO[str] = None) -> None: - """Print a report on all completed URLs.""" - if self.t1 is None: - self.t1 = time.time() - dt = self.t1 - self.t0 - if dt and self.max_tasks: - speed = len(self.done) / dt / self.max_tasks - else: - speed = 0 - stats = Stats() - print('*** Report ***', file=file) - try: - show = [] # type: List[Tuple[str, Fetcher]] - show.extend(self.done.items()) - show.extend(self.busy.items()) - show.sort() - for url, fetcher in show: - fetcher.report(stats, file=file) - except KeyboardInterrupt: - print('\nInterrupted', file=file) - print('Finished', len(self.done), - 'urls in %.3f secs' % dt, - '(max_tasks=%d)' % self.max_tasks, - '(%.3f urls/sec/task)' % speed, - file=file) - stats.report(file=file) - print('Todo:', len(self.todo), file=file) - print('Busy:', len(self.busy), file=file) - print('Done:', len(self.done), file=file) - print('Date:', time.ctime(), 'local time', file=file) - - -def main() -> None: - """Main program. - - Parse arguments, set up event loop, run crawler, print report. - """ - args = ARGS.parse_args() - if not args.roots: - print('Use --help for command line help') - return - - log = Logger(args.level) - - if args.iocp: - if sys.platform == 'win32': - from asyncio import ProactorEventLoop - loop = ProactorEventLoop() # type: ignore - asyncio.set_event_loop(loop) - else: - assert False - elif args.select: - loop = asyncio.SelectorEventLoop() # type: ignore - asyncio.set_event_loop(loop) - else: - loop = asyncio.get_event_loop() # type: ignore - - roots = {fix_url(root) for root in args.roots} - - crawler = Crawler(log, - roots, exclude=args.exclude, - strict=args.strict, - max_redirect=args.max_redirect, - max_tries=args.max_tries, - max_tasks=args.max_tasks, - max_pool=args.max_pool, - ) - try: - loop.run_until_complete(crawler.crawl()) # Crawler gonna crawl. - except KeyboardInterrupt: - sys.stderr.flush() - print('\nInterrupted\n') - finally: - crawler.report() - crawler.close() - loop.close() - - -if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) # type: ignore - main() diff --git a/test-data/samples/dict.py b/test-data/samples/dict.py deleted file mode 100644 index d74a5b5ea01a..000000000000 --- a/test-data/samples/dict.py +++ /dev/null @@ -1,8 +0,0 @@ -import typing -prices = {'apple': 0.40, 'banana': 0.50} -my_purchase = { - 'apple': 1, - 'banana': 6} -grocery_bill = sum(prices[fruit] * my_purchase[fruit] - for fruit in my_purchase) -print('I owe the grocer $%.2f' % grocery_bill) diff --git a/test-data/samples/fib.py b/test-data/samples/fib.py deleted file mode 100644 index 26248c866b1f..000000000000 --- a/test-data/samples/fib.py +++ /dev/null @@ -1,5 +0,0 @@ -import typing -parents, babies = (1, 1) -while babies < 100: - print('This generation has {0} babies'.format(babies)) - parents, babies = (babies, parents + babies) diff --git a/test-data/samples/files.py b/test-data/samples/files.py deleted file mode 100644 index f540c7c2b665..000000000000 --- a/test-data/samples/files.py +++ /dev/null @@ -1,14 +0,0 @@ -# indent your Python code to put into an email -import glob -import typing -# glob supports Unix style pathname extensions -python_files = glob.glob('*.py') -for file_name in sorted(python_files): - print(' ------' + file_name) - - f = open(file_name) - for line in f: - print(' ' + line.rstrip()) - f.close() - - print() diff --git a/test-data/samples/for.py b/test-data/samples/for.py deleted file mode 100644 index f7eeed4efbe6..000000000000 --- a/test-data/samples/for.py +++ /dev/null @@ -1,4 +0,0 @@ -import typing -friends = ['john', 'pat', 'gary', 'michael'] -for i, name in enumerate(friends): - print("iteration {iteration} is {name}".format(iteration=i, name=name)) diff --git a/test-data/samples/generators.py b/test-data/samples/generators.py deleted file mode 100644 index 17e94c1bfb45..000000000000 --- a/test-data/samples/generators.py +++ /dev/null @@ -1,24 +0,0 @@ -# Prime number sieve with generators - -import itertools -from typing import Iterator - - -def iter_primes() -> Iterator[int]: - # an iterator of all numbers between 2 and +infinity - numbers = itertools.count(2) # type: Iterator[int] - - # generate primes forever - while True: - # get the first number from the iterator (always a prime) - prime = next(numbers) - yield prime - - # this code iteratively builds up a chain of - # filters...slightly tricky, but ponder it a bit - numbers = filter(prime.__rmod__, numbers) - -for p in iter_primes(): - if p > 1000: - break - print(p) diff --git a/test-data/samples/greet.py b/test-data/samples/greet.py deleted file mode 100644 index 47e7626410c3..000000000000 --- a/test-data/samples/greet.py +++ /dev/null @@ -1,8 +0,0 @@ -import typing - - -def greet(name: str) -> None: - print('Hello', name) -greet('Jack') -greet('Jill') -greet('Bob') diff --git a/test-data/samples/guess.py b/test-data/samples/guess.py deleted file mode 100644 index d3f1cee4edc7..000000000000 --- a/test-data/samples/guess.py +++ /dev/null @@ -1,32 +0,0 @@ -# "Guess the Number" Game (edited) from http://inventwithpython.com - -import random -import typing - -guesses_made = 0 - -name = input('Hello! What is your name?\n') - -number = random.randint(1, 20) -print('Well, {0}, I am thinking of a number between 1 and 20.'.format(name)) - -while guesses_made < 6: - - guess = int(input('Take a guess: ')) - - guesses_made += 1 - - if guess < number: - print('Your guess is too low.') - - if guess > number: - print('Your guess is too high.') - - if guess == number: - break - -if guess == number: - print('Good job, {0}! You guessed my number in {1} guesses!'.format( - name, guesses_made)) -else: - print('Nope. The number I was thinking of was {0}'.format(number)) diff --git a/test-data/samples/hello.py b/test-data/samples/hello.py deleted file mode 100644 index 6c0b2caa7a60..000000000000 --- a/test-data/samples/hello.py +++ /dev/null @@ -1,2 +0,0 @@ -import typing -print('Hello, world') diff --git a/test-data/samples/input.py b/test-data/samples/input.py deleted file mode 100644 index cca92336f06b..000000000000 --- a/test-data/samples/input.py +++ /dev/null @@ -1,3 +0,0 @@ -import typing -name = input('What is your name?\n') -print('Hi, %s.' % name) diff --git a/test-data/samples/itertool.py b/test-data/samples/itertool.py deleted file mode 100644 index 9ee2475e01fb..000000000000 --- a/test-data/samples/itertool.py +++ /dev/null @@ -1,16 +0,0 @@ -from itertools import groupby -import typing -lines = ''' -This is the -first paragraph. - -This is the second. -'''.splitlines() -# Use itertools.groupby and bool to return groups of -# consecutive lines that either have content or don't. -for has_chars, frags in groupby(lines, bool): - if has_chars: - print(' '.join(frags)) -# PRINTS: -# This is the first paragraph. -# This is the second. diff --git a/test-data/samples/readme.txt b/test-data/samples/readme.txt deleted file mode 100644 index 5889a8ee00ca..000000000000 --- a/test-data/samples/readme.txt +++ /dev/null @@ -1,25 +0,0 @@ -Mypy Sample Programs --------------------- - -The sample programs use static typing unless otherwise noted in comments. - -Original credits for sample programs: - - fib.py - Python Wiki [1] - for.py - Python Wiki [1] - greet.py - Python Wiki [1] - hello.py - Python Wiki [1] - input.py - Python Wiki [1] - regexp.py - Python Wiki [1] - dict.py - Python Wiki [1] - cmdline.py - Python Wiki [1] - files.py - Python Wiki [1] - bottles.py - Python Wiki [1] - class.py - Python Wiki [1] - guess.py - Python Wiki [1] - generators.py - Python Wiki [1] - itertool.py - Python Wiki [1] - -The sample programs were ported to mypy by Jukka Lehtosalo. - -[1] http://wiki.python.org/moin/SimplePrograms diff --git a/test-data/samples/regexp.py b/test-data/samples/regexp.py deleted file mode 100644 index 6d8d7992d0ae..000000000000 --- a/test-data/samples/regexp.py +++ /dev/null @@ -1,7 +0,0 @@ -import typing -import re -for test_string in ['555-1212', 'ILL-EGAL']: - if re.match(r'^\d{3}-\d{4}$', test_string): - print(test_string, 'is a valid US local phone number') - else: - print(test_string, 'rejected') diff --git a/test-data/stdlib-samples/3.2/base64.py b/test-data/stdlib-samples/3.2/base64.py deleted file mode 100644 index ef9196490571..000000000000 --- a/test-data/stdlib-samples/3.2/base64.py +++ /dev/null @@ -1,411 +0,0 @@ -#! /usr/bin/env python3 - -"""RFC 3548: Base16, Base32, Base64 Data Encodings""" - -# Modified 04-Oct-1995 by Jack Jansen to use binascii module -# Modified 30-Dec-2003 by Barry Warsaw to add full RFC 3548 support -# Modified 22-May-2007 by Guido van Rossum to use bytes everywhere - -import re -import struct -import binascii - -from typing import Dict, List, AnyStr, IO - - -__all__ = [ - # Legacy interface exports traditional RFC 1521 Base64 encodings - 'encode', 'decode', 'encodebytes', 'decodebytes', - # Generalized interface for other encodings - 'b64encode', 'b64decode', 'b32encode', 'b32decode', - 'b16encode', 'b16decode', - # Standard Base64 encoding - 'standard_b64encode', 'standard_b64decode', - # Some common Base64 alternatives. As referenced by RFC 3458, see thread - # starting at: - # - # http://zgp.org/pipermail/p2p-hackers/2001-September/000316.html - 'urlsafe_b64encode', 'urlsafe_b64decode', - ] - - -bytes_types = (bytes, bytearray) # Types acceptable as binary data - - -def _translate(s: bytes, altchars: Dict[AnyStr, bytes]) -> bytes: - if not isinstance(s, bytes_types): - raise TypeError("expected bytes, not %s" % s.__class__.__name__) - translation = bytearray(range(256)) - for k, v in altchars.items(): - translation[ord(k)] = v[0] - return s.translate(translation) - - - -# Base64 encoding/decoding uses binascii - -def b64encode(s: bytes, altchars: bytes = None) -> bytes: - """Encode a byte string using Base64. - - s is the byte string to encode. Optional altchars must be a byte - string of length 2 which specifies an alternative alphabet for the - '+' and '/' characters. This allows an application to - e.g. generate url or filesystem safe Base64 strings. - - The encoded byte string is returned. - """ - if not isinstance(s, bytes_types): - raise TypeError("expected bytes, not %s" % s.__class__.__name__) - # Strip off the trailing newline - encoded = binascii.b2a_base64(s)[:-1] - if altchars is not None: - if not isinstance(altchars, bytes_types): - raise TypeError("expected bytes, not %s" - % altchars.__class__.__name__) - assert len(altchars) == 2, repr(altchars) - return _translate(encoded, {'+': altchars[0:1], '/': altchars[1:2]}) - return encoded - - -def b64decode(s: bytes, altchars: bytes = None, - validate: bool = False) -> bytes: - """Decode a Base64 encoded byte string. - - s is the byte string to decode. Optional altchars must be a - string of length 2 which specifies the alternative alphabet used - instead of the '+' and '/' characters. - - The decoded string is returned. A binascii.Error is raised if s is - incorrectly padded. - - If validate is False (the default), non-base64-alphabet characters are - discarded prior to the padding check. If validate is True, - non-base64-alphabet characters in the input result in a binascii.Error. - """ - if not isinstance(s, bytes_types): - raise TypeError("expected bytes, not %s" % s.__class__.__name__) - if altchars is not None: - if not isinstance(altchars, bytes_types): - raise TypeError("expected bytes, not %s" - % altchars.__class__.__name__) - assert len(altchars) == 2, repr(altchars) - s = _translate(s, {chr(altchars[0]): b'+', chr(altchars[1]): b'/'}) - if validate and not re.match(b'^[A-Za-z0-9+/]*={0,2}$', s): - raise binascii.Error('Non-base64 digit found') - return binascii.a2b_base64(s) - - -def standard_b64encode(s: bytes) -> bytes: - """Encode a byte string using the standard Base64 alphabet. - - s is the byte string to encode. The encoded byte string is returned. - """ - return b64encode(s) - -def standard_b64decode(s: bytes) -> bytes: - """Decode a byte string encoded with the standard Base64 alphabet. - - s is the byte string to decode. The decoded byte string is - returned. binascii.Error is raised if the input is incorrectly - padded or if there are non-alphabet characters present in the - input. - """ - return b64decode(s) - -def urlsafe_b64encode(s: bytes) -> bytes: - """Encode a byte string using a url-safe Base64 alphabet. - - s is the byte string to encode. The encoded byte string is - returned. The alphabet uses '-' instead of '+' and '_' instead of - '/'. - """ - return b64encode(s, b'-_') - -def urlsafe_b64decode(s: bytes) -> bytes: - """Decode a byte string encoded with the standard Base64 alphabet. - - s is the byte string to decode. The decoded byte string is - returned. binascii.Error is raised if the input is incorrectly - padded or if there are non-alphabet characters present in the - input. - - The alphabet uses '-' instead of '+' and '_' instead of '/'. - """ - return b64decode(s, b'-_') - - - -# Base32 encoding/decoding must be done in Python -_b32alphabet = { - 0: b'A', 9: b'J', 18: b'S', 27: b'3', - 1: b'B', 10: b'K', 19: b'T', 28: b'4', - 2: b'C', 11: b'L', 20: b'U', 29: b'5', - 3: b'D', 12: b'M', 21: b'V', 30: b'6', - 4: b'E', 13: b'N', 22: b'W', 31: b'7', - 5: b'F', 14: b'O', 23: b'X', - 6: b'G', 15: b'P', 24: b'Y', - 7: b'H', 16: b'Q', 25: b'Z', - 8: b'I', 17: b'R', 26: b'2', - } - -_b32tab = [v[0] for k, v in sorted(_b32alphabet.items())] -_b32rev = dict([(v[0], k) for k, v in _b32alphabet.items()]) - - -def b32encode(s: bytes) -> bytes: - """Encode a byte string using Base32. - - s is the byte string to encode. The encoded byte string is returned. - """ - if not isinstance(s, bytes_types): - raise TypeError("expected bytes, not %s" % s.__class__.__name__) - quanta, leftover = divmod(len(s), 5) - # Pad the last quantum with zero bits if necessary - if leftover: - s = s + bytes(5 - leftover) # Don't use += ! - quanta += 1 - encoded = bytes() - for i in range(quanta): - # c1 and c2 are 16 bits wide, c3 is 8 bits wide. The intent of this - # code is to process the 40 bits in units of 5 bits. So we take the 1 - # leftover bit of c1 and tack it onto c2. Then we take the 2 leftover - # bits of c2 and tack them onto c3. The shifts and masks are intended - # to give us values of exactly 5 bits in width. - c1, c2, c3 = struct.unpack('!HHB', s[i*5:(i+1)*5]) # type: (int, int, int) - c2 += (c1 & 1) << 16 # 17 bits wide - c3 += (c2 & 3) << 8 # 10 bits wide - encoded += bytes([_b32tab[c1 >> 11], # bits 1 - 5 - _b32tab[(c1 >> 6) & 0x1f], # bits 6 - 10 - _b32tab[(c1 >> 1) & 0x1f], # bits 11 - 15 - _b32tab[c2 >> 12], # bits 16 - 20 (1 - 5) - _b32tab[(c2 >> 7) & 0x1f], # bits 21 - 25 (6 - 10) - _b32tab[(c2 >> 2) & 0x1f], # bits 26 - 30 (11 - 15) - _b32tab[c3 >> 5], # bits 31 - 35 (1 - 5) - _b32tab[c3 & 0x1f], # bits 36 - 40 (1 - 5) - ]) - # Adjust for any leftover partial quanta - if leftover == 1: - return encoded[:-6] + b'======' - elif leftover == 2: - return encoded[:-4] + b'====' - elif leftover == 3: - return encoded[:-3] + b'===' - elif leftover == 4: - return encoded[:-1] + b'=' - return encoded - - -def b32decode(s: bytes, casefold: bool = False, map01: bytes = None) -> bytes: - """Decode a Base32 encoded byte string. - - s is the byte string to decode. Optional casefold is a flag - specifying whether a lowercase alphabet is acceptable as input. - For security purposes, the default is False. - - RFC 3548 allows for optional mapping of the digit 0 (zero) to the - letter O (oh), and for optional mapping of the digit 1 (one) to - either the letter I (eye) or letter L (el). The optional argument - map01 when not None, specifies which letter the digit 1 should be - mapped to (when map01 is not None, the digit 0 is always mapped to - the letter O). For security purposes the default is None, so that - 0 and 1 are not allowed in the input. - - The decoded byte string is returned. binascii.Error is raised if - the input is incorrectly padded or if there are non-alphabet - characters present in the input. - """ - if not isinstance(s, bytes_types): - raise TypeError("expected bytes, not %s" % s.__class__.__name__) - quanta, leftover = divmod(len(s), 8) - if leftover: - raise binascii.Error('Incorrect padding') - # Handle section 2.4 zero and one mapping. The flag map01 will be either - # False, or the character to map the digit 1 (one) to. It should be - # either L (el) or I (eye). - if map01 is not None: - if not isinstance(map01, bytes_types): - raise TypeError("expected bytes, not %s" % map01.__class__.__name__) - assert len(map01) == 1, repr(map01) - s = _translate(s, {b'0': b'O', b'1': map01}) - if casefold: - s = s.upper() - # Strip off pad characters from the right. We need to count the pad - # characters because this will tell us how many null bytes to remove from - # the end of the decoded string. - padchars = 0 - mo = re.search(b'(?P[=]*)$', s) - if mo: - padchars = len(mo.group('pad')) - if padchars > 0: - s = s[:-padchars] - # Now decode the full quanta - parts = [] # type: List[bytes] - acc = 0 - shift = 35 - for c in s: - val = _b32rev.get(c) - if val is None: - raise TypeError('Non-base32 digit found') - acc += _b32rev[c] << shift - shift -= 5 - if shift < 0: - parts.append(binascii.unhexlify(bytes('%010x' % acc, "ascii"))) - acc = 0 - shift = 35 - # Process the last, partial quanta - last = binascii.unhexlify(bytes('%010x' % acc, "ascii")) - if padchars == 0: - last = b'' # No characters - elif padchars == 1: - last = last[:-1] - elif padchars == 3: - last = last[:-2] - elif padchars == 4: - last = last[:-3] - elif padchars == 6: - last = last[:-4] - else: - raise binascii.Error('Incorrect padding') - parts.append(last) - return b''.join(parts) - - - -# RFC 3548, Base 16 Alphabet specifies uppercase, but hexlify() returns -# lowercase. The RFC also recommends against accepting input case -# insensitively. -def b16encode(s: bytes) -> bytes: - """Encode a byte string using Base16. - - s is the byte string to encode. The encoded byte string is returned. - """ - if not isinstance(s, bytes_types): - raise TypeError("expected bytes, not %s" % s.__class__.__name__) - return binascii.hexlify(s).upper() - - -def b16decode(s: bytes, casefold: bool = False) -> bytes: - """Decode a Base16 encoded byte string. - - s is the byte string to decode. Optional casefold is a flag - specifying whether a lowercase alphabet is acceptable as input. - For security purposes, the default is False. - - The decoded byte string is returned. binascii.Error is raised if - s were incorrectly padded or if there are non-alphabet characters - present in the string. - """ - if not isinstance(s, bytes_types): - raise TypeError("expected bytes, not %s" % s.__class__.__name__) - if casefold: - s = s.upper() - if re.search(b'[^0-9A-F]', s): - raise binascii.Error('Non-base16 digit found') - return binascii.unhexlify(s) - - - -# Legacy interface. This code could be cleaned up since I don't believe -# binascii has any line length limitations. It just doesn't seem worth it -# though. The files should be opened in binary mode. - -MAXLINESIZE = 76 # Excluding the CRLF -MAXBINSIZE = (MAXLINESIZE//4)*3 - -def encode(input: IO[bytes], output: IO[bytes]) -> None: - """Encode a file; input and output are binary files.""" - while True: - s = input.read(MAXBINSIZE) - if not s: - break - while len(s) < MAXBINSIZE: - ns = input.read(MAXBINSIZE-len(s)) - if not ns: - break - s += ns - line = binascii.b2a_base64(s) - output.write(line) - - -def decode(input: IO[bytes], output: IO[bytes]) -> None: - """Decode a file; input and output are binary files.""" - while True: - line = input.readline() - if not line: - break - s = binascii.a2b_base64(line) - output.write(s) - - -def encodebytes(s: bytes) -> bytes: - """Encode a bytestring into a bytestring containing multiple lines - of base-64 data.""" - if not isinstance(s, bytes_types): - raise TypeError("expected bytes, not %s" % s.__class__.__name__) - pieces = [] # type: List[bytes] - for i in range(0, len(s), MAXBINSIZE): - chunk = s[i : i + MAXBINSIZE] - pieces.append(binascii.b2a_base64(chunk)) - return b"".join(pieces) - -def encodestring(s: bytes) -> bytes: - """Legacy alias of encodebytes().""" - import warnings - warnings.warn("encodestring() is a deprecated alias, use encodebytes()", - DeprecationWarning, 2) - return encodebytes(s) - - -def decodebytes(s: bytes) -> bytes: - """Decode a bytestring of base-64 data into a bytestring.""" - if not isinstance(s, bytes_types): - raise TypeError("expected bytes, not %s" % s.__class__.__name__) - return binascii.a2b_base64(s) - -def decodestring(s: bytes) -> bytes: - """Legacy alias of decodebytes().""" - import warnings - warnings.warn("decodestring() is a deprecated alias, use decodebytes()", - DeprecationWarning, 2) - return decodebytes(s) - - -# Usable as a script... -def main() -> None: - """Small main program""" - import sys, getopt - try: - opts, args = getopt.getopt(sys.argv[1:], 'deut') - except getopt.error as msg: - sys.stdout = sys.stderr - print(msg) - print("""usage: %s [-d|-e|-u|-t] [file|-] - -d, -u: decode - -e: encode (default) - -t: encode and decode string 'Aladdin:open sesame'"""%sys.argv[0]) - sys.exit(2) - func = encode - for o, a in opts: - if o == '-e': func = encode - if o == '-d': func = decode - if o == '-u': func = decode - if o == '-t': test(); return - if args and args[0] != '-': - with open(args[0], 'rb') as f: - func(f, sys.stdout.buffer) - else: - func(sys.stdin.buffer, sys.stdout.buffer) - - -def test() -> None: - s0 = b"Aladdin:open sesame" - print(repr(s0)) - s1 = encodebytes(s0) - print(repr(s1)) - s2 = decodebytes(s1) - print(repr(s2)) - assert s0 == s2 - - -if __name__ == '__main__': - main() diff --git a/test-data/stdlib-samples/3.2/fnmatch.py b/test-data/stdlib-samples/3.2/fnmatch.py deleted file mode 100644 index 3dccb0ce65fc..000000000000 --- a/test-data/stdlib-samples/3.2/fnmatch.py +++ /dev/null @@ -1,112 +0,0 @@ -"""Filename matching with shell patterns. - -fnmatch(FILENAME, PATTERN) matches according to the local convention. -fnmatchcase(FILENAME, PATTERN) always takes case in account. - -The functions operate by translating the pattern into a regular -expression. They cache the compiled regular expressions for speed. - -The function translate(PATTERN) returns a regular expression -corresponding to PATTERN. (It does not compile it.) -""" -import os -import posixpath -import re -import functools - -from typing import Iterable, List, AnyStr, Any, Callable, Match - -__all__ = ["filter", "fnmatch", "fnmatchcase", "translate"] - -def fnmatch(name: AnyStr, pat: AnyStr) -> bool: - """Test whether FILENAME matches PATTERN. - - Patterns are Unix shell style: - - * matches everything - ? matches any single character - [seq] matches any character in seq - [!seq] matches any char not in seq - - An initial period in FILENAME is not special. - Both FILENAME and PATTERN are first case-normalized - if the operating system requires it. - If you don't want this, use fnmatchcase(FILENAME, PATTERN). - """ - name = os.path.normcase(name) - pat = os.path.normcase(pat) - return fnmatchcase(name, pat) - -@functools.lru_cache(maxsize=250) -def _compile_pattern(pat: AnyStr, - is_bytes: bool = False) -> Callable[[AnyStr], - Match[AnyStr]]: - if isinstance(pat, bytes): - pat_str = str(pat, 'ISO-8859-1') - res_str = translate(pat_str) - res = bytes(res_str, 'ISO-8859-1') - else: - res = translate(pat) - return re.compile(res).match - -def filter(names: Iterable[AnyStr], pat: AnyStr) -> List[AnyStr]: - """Return the subset of the list NAMES that match PAT.""" - result = [] # type: List[AnyStr] - pat = os.path.normcase(pat) - match = _compile_pattern(pat, isinstance(pat, bytes)) - if os.path is posixpath: - # normcase on posix is NOP. Optimize it away from the loop. - for name in names: - if match(name): - result.append(name) - else: - for name in names: - if match(os.path.normcase(name)): - result.append(name) - return result - -def fnmatchcase(name: AnyStr, pat: AnyStr) -> bool: - """Test whether FILENAME matches PATTERN, including case. - - This is a version of fnmatch() which doesn't case-normalize - its arguments. - """ - match = _compile_pattern(pat, isinstance(pat, bytes)) - return match(name) is not None - -def translate(pat: str) -> str: - """Translate a shell PATTERN to a regular expression. - - There is no way to quote meta-characters. - """ - - i, n = 0, len(pat) - res = '' - while i < n: - c = pat[i] - i = i+1 - if c == '*': - res = res + '.*' - elif c == '?': - res = res + '.' - elif c == '[': - j = i - if j < n and pat[j] == '!': - j = j+1 - if j < n and pat[j] == ']': - j = j+1 - while j < n and pat[j] != ']': - j = j+1 - if j >= n: - res = res + '\\[' - else: - stuff = pat[i:j].replace('\\','\\\\') - i = j+1 - if stuff[0] == '!': - stuff = '^' + stuff[1:] - elif stuff[0] == '^': - stuff = '\\' + stuff - res = '%s[%s]' % (res, stuff) - else: - res = res + re.escape(c) - return res + r'\Z(?ms)' diff --git a/test-data/stdlib-samples/3.2/genericpath.py b/test-data/stdlib-samples/3.2/genericpath.py deleted file mode 100644 index bd1fddf750bf..000000000000 --- a/test-data/stdlib-samples/3.2/genericpath.py +++ /dev/null @@ -1,112 +0,0 @@ -""" -Path operations common to more than one OS -Do not use directly. The OS specific modules import the appropriate -functions from this module themselves. -""" -import os -import stat - -from typing import ( - Any as Any_, List as List_, AnyStr as AnyStr_, Tuple as Tuple_ -) - -__all__ = ['commonprefix', 'exists', 'getatime', 'getctime', 'getmtime', - 'getsize', 'isdir', 'isfile'] - - -# Does a path exist? -# This is false for dangling symbolic links on systems that support them. -def exists(path: AnyStr_) -> bool: - """Test whether a path exists. Returns False for broken symbolic links""" - try: - os.stat(path) - except os.error: - return False - return True - - -# This follows symbolic links, so both islink() and isdir() can be true -# for the same path ono systems that support symlinks -def isfile(path: AnyStr_) -> bool: - """Test whether a path is a regular file""" - try: - st = os.stat(path) - except os.error: - return False - return stat.S_ISREG(st.st_mode) - - -# Is a path a directory? -# This follows symbolic links, so both islink() and isdir() -# can be true for the same path on systems that support symlinks -def isdir(s: AnyStr_) -> bool: - """Return true if the pathname refers to an existing directory.""" - try: - st = os.stat(s) - except os.error: - return False - return stat.S_ISDIR(st.st_mode) - - -def getsize(filename: AnyStr_) -> int: - """Return the size of a file, reported by os.stat().""" - return os.stat(filename).st_size - - -def getmtime(filename: AnyStr_) -> float: - """Return the last modification time of a file, reported by os.stat().""" - return os.stat(filename).st_mtime - - -def getatime(filename: AnyStr_) -> float: - """Return the last access time of a file, reported by os.stat().""" - return os.stat(filename).st_atime - - -def getctime(filename: AnyStr_) -> float: - """Return the metadata change time of a file, reported by os.stat().""" - return os.stat(filename).st_ctime - - -# Return the longest prefix of all list elements. -def commonprefix(m: List_[Any_]) -> Any_: - "Given a list of pathnames, returns the longest common leading component" - if not m: return '' - s1 = min(m) - s2 = max(m) - for i, c in enumerate(s1): - if c != s2[i]: - return s1[:i] - return s1 - - -# Split a path in root and extension. -# The extension is everything starting at the last dot in the last -# pathname component; the root is everything before that. -# It is always true that root + ext == p. - -# Generic implementation of splitext, to be parametrized with -# the separators -def _splitext(p: AnyStr_, sep: AnyStr_, altsep: AnyStr_, - extsep: AnyStr_) -> Tuple_[AnyStr_, AnyStr_]: - """Split the extension from a pathname. - - Extension is everything from the last dot to the end, ignoring - leading dots. Returns "(root, ext)"; ext may be empty.""" - # NOTE: This code must work for text and bytes strings. - - sepIndex = p.rfind(sep) - if altsep: - altsepIndex = p.rfind(altsep) - sepIndex = max(sepIndex, altsepIndex) - - dotIndex = p.rfind(extsep) - if dotIndex > sepIndex: - # skip all leading dots - filenameIndex = sepIndex + 1 - while filenameIndex < dotIndex: - if p[filenameIndex:filenameIndex+1] != extsep: - return p[:dotIndex], p[dotIndex:] - filenameIndex += 1 - - return p, p[:0] diff --git a/test-data/stdlib-samples/3.2/getopt.py b/test-data/stdlib-samples/3.2/getopt.py deleted file mode 100644 index 32f5bcec7420..000000000000 --- a/test-data/stdlib-samples/3.2/getopt.py +++ /dev/null @@ -1,220 +0,0 @@ -"""Parser for command line options. - -This module helps scripts to parse the command line arguments in -sys.argv. It supports the same conventions as the Unix getopt() -function (including the special meanings of arguments of the form `-' -and `--'). Long options similar to those supported by GNU software -may be used as well via an optional third argument. This module -provides two functions and an exception: - -getopt() -- Parse command line options -gnu_getopt() -- Like getopt(), but allow option and non-option arguments -to be intermixed. -GetoptError -- exception (class) raised with 'opt' attribute, which is the -option involved with the exception. -""" - -# Long option support added by Lars Wirzenius . -# -# Gerrit Holl moved the string-based exceptions -# to class-based exceptions. -# -# Peter Åstrand added gnu_getopt(). -# -# TODO for gnu_getopt(): -# -# - GNU getopt_long_only mechanism -# - allow the caller to specify ordering -# - RETURN_IN_ORDER option -# - GNU extension with '-' as first character of option string -# - optional arguments, specified by double colons -# - a option string with a W followed by semicolon should -# treat "-W foo" as "--foo" - -__all__ = ["GetoptError","error","getopt","gnu_getopt"] - -import os - -from typing import List, Tuple, Iterable - -class GetoptError(Exception): - opt = '' - msg = '' - def __init__(self, msg: str, opt: str = '') -> None: - self.msg = msg - self.opt = opt - Exception.__init__(self, msg, opt) - - def __str__(self) -> str: - return self.msg - -error = GetoptError # backward compatibility - -def getopt(args: List[str], shortopts: str, - longopts: Iterable[str] = []) -> Tuple[List[Tuple[str, str]], - List[str]]: - """getopt(args, options[, long_options]) -> opts, args - - Parses command line options and parameter list. args is the - argument list to be parsed, without the leading reference to the - running program. Typically, this means "sys.argv[1:]". shortopts - is the string of option letters that the script wants to - recognize, with options that require an argument followed by a - colon (i.e., the same format that Unix getopt() uses). If - specified, longopts is a list of strings with the names of the - long options which should be supported. The leading '--' - characters should not be included in the option name. Options - which require an argument should be followed by an equal sign - ('='). - - The return value consists of two elements: the first is a list of - (option, value) pairs; the second is the list of program arguments - left after the option list was stripped (this is a trailing slice - of the first argument). Each option-and-value pair returned has - the option as its first element, prefixed with a hyphen (e.g., - '-x'), and the option argument as its second element, or an empty - string if the option has no argument. The options occur in the - list in the same order in which they were found, thus allowing - multiple occurrences. Long and short options may be mixed. - - """ - - opts = [] # type: List[Tuple[str, str]] - if isinstance(longopts, str): - longopts = [longopts] - else: - longopts = list(longopts) - while args and args[0].startswith('-') and args[0] != '-': - if args[0] == '--': - args = args[1:] - break - if args[0].startswith('--'): - opts, args = do_longs(opts, args[0][2:], longopts, args[1:]) - else: - opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:]) - - return opts, args - -def gnu_getopt(args: List[str], shortopts: str, - longopts: Iterable[str] = []) -> Tuple[List[Tuple[str, str]], - List[str]]: - """getopt(args, options[, long_options]) -> opts, args - - This function works like getopt(), except that GNU style scanning - mode is used by default. This means that option and non-option - arguments may be intermixed. The getopt() function stops - processing options as soon as a non-option argument is - encountered. - - If the first character of the option string is `+', or if the - environment variable POSIXLY_CORRECT is set, then option - processing stops as soon as a non-option argument is encountered. - - """ - - opts = [] # type: List[Tuple[str, str]] - prog_args = [] # type: List[str] - if isinstance(longopts, str): - longopts = [longopts] - else: - longopts = list(longopts) - - # Allow options after non-option arguments? - if shortopts.startswith('+'): - shortopts = shortopts[1:] - all_options_first = True - elif os.environ.get("POSIXLY_CORRECT"): - all_options_first = True - else: - all_options_first = False - - while args: - if args[0] == '--': - prog_args += args[1:] - break - - if args[0][:2] == '--': - opts, args = do_longs(opts, args[0][2:], longopts, args[1:]) - elif args[0][:1] == '-' and args[0] != '-': - opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:]) - else: - if all_options_first: - prog_args += args - break - else: - prog_args.append(args[0]) - args = args[1:] - - return opts, prog_args - -def do_longs(opts: List[Tuple[str, str]], opt: str, - longopts: List[str], - args: List[str]) -> Tuple[List[Tuple[str, str]], List[str]]: - try: - i = opt.index('=') - except ValueError: - optarg = None # type: str - else: - opt, optarg = opt[:i], opt[i+1:] - - has_arg, opt = long_has_args(opt, longopts) - if has_arg: - if optarg is None: - if not args: - raise GetoptError('option --%s requires argument' % opt, opt) - optarg, args = args[0], args[1:] - elif optarg is not None: - raise GetoptError('option --%s must not have an argument' % opt, opt) - opts.append(('--' + opt, optarg or '')) - return opts, args - -# Return: -# has_arg? -# full option name -def long_has_args(opt: str, longopts: List[str]) -> Tuple[bool, str]: - possibilities = [o for o in longopts if o.startswith(opt)] - if not possibilities: - raise GetoptError('option --%s not recognized' % opt, opt) - # Is there an exact match? - if opt in possibilities: - return False, opt - elif opt + '=' in possibilities: - return True, opt - # No exact match, so better be unique. - if len(possibilities) > 1: - # XXX since possibilities contains all valid continuations, might be - # nice to work them into the error msg - raise GetoptError('option --%s not a unique prefix' % opt, opt) - assert len(possibilities) == 1 - unique_match = possibilities[0] - has_arg = unique_match.endswith('=') - if has_arg: - unique_match = unique_match[:-1] - return has_arg, unique_match - -def do_shorts(opts: List[Tuple[str, str]], optstring: str, - shortopts: str, args: List[str]) -> Tuple[List[Tuple[str, str]], - List[str]]: - while optstring != '': - opt, optstring = optstring[0], optstring[1:] - if short_has_arg(opt, shortopts): - if optstring == '': - if not args: - raise GetoptError('option -%s requires argument' % opt, - opt) - optstring, args = args[0], args[1:] - optarg, optstring = optstring, '' - else: - optarg = '' - opts.append(('-' + opt, optarg)) - return opts, args - -def short_has_arg(opt: str, shortopts: str) -> bool: - for i in range(len(shortopts)): - if opt == shortopts[i] != ':': - return shortopts.startswith(':', i+1) - raise GetoptError('option -%s not recognized' % opt, opt) - -if __name__ == '__main__': - import sys - print(getopt(sys.argv[1:], "a:b", ["alpha=", "beta"])) diff --git a/test-data/stdlib-samples/3.2/glob.py b/test-data/stdlib-samples/3.2/glob.py deleted file mode 100644 index 0f3d5f5d9a09..000000000000 --- a/test-data/stdlib-samples/3.2/glob.py +++ /dev/null @@ -1,84 +0,0 @@ -"""Filename globbing utility.""" - -import os -import re -import fnmatch - -from typing import List, Iterator, Iterable, Any, AnyStr - -__all__ = ["glob", "iglob"] - -def glob(pathname: AnyStr) -> List[AnyStr]: - """Return a list of paths matching a pathname pattern. - - The pattern may contain simple shell-style wildcards a la fnmatch. - - """ - return list(iglob(pathname)) - -def iglob(pathname: AnyStr) -> Iterator[AnyStr]: - """Return an iterator which yields the paths matching a pathname pattern. - - The pattern may contain simple shell-style wildcards a la fnmatch. - - """ - if not has_magic(pathname): - if os.path.lexists(pathname): - yield pathname - return - dirname, basename = os.path.split(pathname) - if not dirname: - for name in glob1(None, basename): - yield name - return - if has_magic(dirname): - dirs = iglob(dirname) # type: Iterable[AnyStr] - else: - dirs = [dirname] - if has_magic(basename): - glob_in_dir = glob1 # type: Any - else: - glob_in_dir = glob0 - for dirname in dirs: - for name in glob_in_dir(dirname, basename): - yield os.path.join(dirname, name) - -# These 2 helper functions non-recursively glob inside a literal directory. -# They return a list of basenames. `glob1` accepts a pattern while `glob0` -# takes a literal basename (so it only has to check for its existence). - -def glob1(dirname: AnyStr, pattern: AnyStr) -> List[AnyStr]: - if not dirname: - if isinstance(pattern, bytes): - dirname = bytes(os.curdir, 'ASCII') - else: - dirname = os.curdir - try: - names = os.listdir(dirname) - except os.error: - return [] - if pattern[0] != '.': - names = [x for x in names if x[0] != '.'] - return fnmatch.filter(names, pattern) - -def glob0(dirname: AnyStr, basename: AnyStr) -> List[AnyStr]: - if basename == '': - # `os.path.split()` returns an empty basename for paths ending with a - # directory separator. 'q*x/' should match only directories. - if os.path.isdir(dirname): - return [basename] - else: - if os.path.lexists(os.path.join(dirname, basename)): - return [basename] - return [] - - -magic_check = re.compile('[*?[]') -magic_check_bytes = re.compile(b'[*?[]') - -def has_magic(s: AnyStr) -> bool: - if isinstance(s, bytes): - match = magic_check_bytes.search(s) - else: - match = magic_check.search(s) - return match is not None diff --git a/test-data/stdlib-samples/3.2/posixpath.py b/test-data/stdlib-samples/3.2/posixpath.py deleted file mode 100644 index cf5d59e6a69a..000000000000 --- a/test-data/stdlib-samples/3.2/posixpath.py +++ /dev/null @@ -1,466 +0,0 @@ -"""Common operations on Posix pathnames. - -Instead of importing this module directly, import os and refer to -this module as os.path. The "os.path" name is an alias for this -module on Posix systems; on other systems (e.g. Mac, Windows), -os.path provides the same operations in a manner specific to that -platform, and is an alias to another module (e.g. macpath, ntpath). - -Some of this can actually be useful on non-Posix systems too, e.g. -for manipulation of the pathname component of URLs. -""" - -import os -import sys -import stat -import genericpath -from genericpath import * - -from typing import ( - Tuple, BinaryIO, TextIO, Pattern, AnyStr, List, Set, Any, Union, cast -) - -__all__ = ["normcase","isabs","join","splitdrive","split","splitext", - "basename","dirname","commonprefix","getsize","getmtime", - "getatime","getctime","islink","exists","lexists","isdir","isfile", - "ismount", "expanduser","expandvars","normpath","abspath", - "samefile","sameopenfile","samestat", - "curdir","pardir","sep","pathsep","defpath","altsep","extsep", - "devnull","realpath","supports_unicode_filenames","relpath"] - -# Strings representing various path-related bits and pieces. -# These are primarily for export; internally, they are hardcoded. -curdir = '.' -pardir = '..' -extsep = '.' -sep = '/' -pathsep = ':' -defpath = ':/bin:/usr/bin' -altsep = None # type: str -devnull = '/dev/null' - -def _get_sep(path: AnyStr) -> AnyStr: - if isinstance(path, bytes): - return b'/' - else: - return '/' - -# Normalize the case of a pathname. Trivial in Posix, string.lower on Mac. -# On MS-DOS this may also turn slashes into backslashes; however, other -# normalizations (such as optimizing '../' away) are not allowed -# (another function should be defined to do that). - -def normcase(s: AnyStr) -> AnyStr: - """Normalize case of pathname. Has no effect under Posix""" - # TODO: on Mac OS X, this should really return s.lower(). - if not isinstance(s, (bytes, str)): - raise TypeError("normcase() argument must be str or bytes, " - "not '{}'".format(s.__class__.__name__)) - return cast(AnyStr, s) - - -# Return whether a path is absolute. -# Trivial in Posix, harder on the Mac or MS-DOS. - -def isabs(s: AnyStr) -> bool: - """Test whether a path is absolute""" - sep = _get_sep(s) - return s.startswith(sep) - - -# Join pathnames. -# Ignore the previous parts if a part is absolute. -# Insert a '/' unless the first part is empty or already ends in '/'. - -def join(a: AnyStr, *p: AnyStr) -> AnyStr: - """Join two or more pathname components, inserting '/' as needed. - If any component is an absolute path, all previous path components - will be discarded.""" - sep = _get_sep(a) - path = a - for b in p: - if b.startswith(sep): - path = b - elif not path or path.endswith(sep): - path += b - else: - path += sep + b - return path - - -# Split a path in head (everything up to the last '/') and tail (the -# rest). If the path ends in '/', tail will be empty. If there is no -# '/' in the path, head will be empty. -# Trailing '/'es are stripped from head unless it is the root. - -def split(p: AnyStr) -> Tuple[AnyStr, AnyStr]: - """Split a pathname. Returns tuple "(head, tail)" where "tail" is - everything after the final slash. Either part may be empty.""" - sep = _get_sep(p) - i = p.rfind(sep) + 1 - head, tail = p[:i], p[i:] - if head and head != sep*len(head): - head = head.rstrip(sep) - return head, tail - - -# Split a path in root and extension. -# The extension is everything starting at the last dot in the last -# pathname component; the root is everything before that. -# It is always true that root + ext == p. - -def splitext(p: AnyStr) -> Tuple[AnyStr, AnyStr]: - if isinstance(p, bytes): - sep = b'/' - extsep = b'.' - else: - sep = '/' - extsep = '.' - return genericpath._splitext(p, sep, None, extsep) -splitext.__doc__ = genericpath._splitext.__doc__ - -# Split a pathname into a drive specification and the rest of the -# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty. - -def splitdrive(p: AnyStr) -> Tuple[AnyStr, AnyStr]: - """Split a pathname into drive and path. On Posix, drive is always - empty.""" - return p[:0], p - - -# Return the tail (basename) part of a path, same as split(path)[1]. - -def basename(p: AnyStr) -> AnyStr: - """Returns the final component of a pathname""" - sep = _get_sep(p) - i = p.rfind(sep) + 1 - return p[i:] - - -# Return the head (dirname) part of a path, same as split(path)[0]. - -def dirname(p: AnyStr) -> AnyStr: - """Returns the directory component of a pathname""" - sep = _get_sep(p) - i = p.rfind(sep) + 1 - head = p[:i] - if head and head != sep*len(head): - head = head.rstrip(sep) - return head - - -# Is a path a symbolic link? -# This will always return false on systems where os.lstat doesn't exist. - -def islink(path: AnyStr) -> bool: - """Test whether a path is a symbolic link""" - try: - st = os.lstat(path) - except (os.error, AttributeError): - return False - return stat.S_ISLNK(st.st_mode) - -# Being true for dangling symbolic links is also useful. - -def lexists(path: AnyStr) -> bool: - """Test whether a path exists. Returns True for broken symbolic links""" - try: - os.lstat(path) - except os.error: - return False - return True - - -# Are two filenames really pointing to the same file? - -def samefile(f1: AnyStr, f2: AnyStr) -> bool: - """Test whether two pathnames reference the same actual file""" - s1 = os.stat(f1) - s2 = os.stat(f2) - return samestat(s1, s2) - - -# Are two open files really referencing the same file? -# (Not necessarily the same file descriptor!) - -def sameopenfile(fp1: int, fp2: int) -> bool: - """Test whether two open file objects reference the same file""" - s1 = os.fstat(fp1) - s2 = os.fstat(fp2) - return samestat(s1, s2) - - -# Are two stat buffers (obtained from stat, fstat or lstat) -# describing the same file? - -def samestat(s1: os.stat_result, s2: os.stat_result) -> bool: - """Test whether two stat buffers reference the same file""" - return s1.st_ino == s2.st_ino and \ - s1.st_dev == s2.st_dev - - -# Is a path a mount point? -# (Does this work for all UNIXes? Is it even guaranteed to work by Posix?) - -def ismount(path: AnyStr) -> bool: - """Test whether a path is a mount point""" - if islink(path): - # A symlink can never be a mount point - return False - try: - s1 = os.lstat(path) - if isinstance(path, bytes): - parent = join(path, b'..') - else: - parent = join(path, '..') - s2 = os.lstat(parent) - except os.error: - return False # It doesn't exist -- so not a mount point :-) - dev1 = s1.st_dev - dev2 = s2.st_dev - if dev1 != dev2: - return True # path/.. on a different device as path - ino1 = s1.st_ino - ino2 = s2.st_ino - if ino1 == ino2: - return True # path/.. is the same i-node as path - return False - - -# Expand paths beginning with '~' or '~user'. -# '~' means $HOME; '~user' means that user's home directory. -# If the path doesn't begin with '~', or if the user or $HOME is unknown, -# the path is returned unchanged (leaving error reporting to whatever -# function is called with the expanded path as argument). -# See also module 'glob' for expansion of *, ? and [...] in pathnames. -# (A function should also be defined to do full *sh-style environment -# variable expansion.) - -def expanduser(path: AnyStr) -> AnyStr: - """Expand ~ and ~user constructions. If user or $HOME is unknown, - do nothing.""" - if isinstance(path, bytes): - tilde = b'~' - else: - tilde = '~' - if not path.startswith(tilde): - return path - sep = _get_sep(path) - i = path.find(sep, 1) - if i < 0: - i = len(path) - if i == 1: - userhome = None # type: Union[str, bytes] - if 'HOME' not in os.environ: - import pwd - userhome = pwd.getpwuid(os.getuid()).pw_dir - else: - userhome = os.environ['HOME'] - else: - import pwd - name = path[1:i] # type: Union[str, bytes] - if isinstance(name, bytes): - name = str(name, 'ASCII') - try: - pwent = pwd.getpwnam(name) - except KeyError: - return path - userhome = pwent.pw_dir - if isinstance(path, bytes): - userhome = os.fsencode(userhome) - root = b'/' - else: - root = '/' - userhome = userhome.rstrip(root) - return (userhome + path[i:]) or root - - -# Expand paths containing shell variable substitutions. -# This expands the forms $variable and ${variable} only. -# Non-existent variables are left unchanged. - -_varprog = None # type: Pattern[str] -_varprogb = None # type: Pattern[bytes] - -def expandvars(path: AnyStr) -> AnyStr: - """Expand shell variables of form $var and ${var}. Unknown variables - are left unchanged.""" - global _varprog, _varprogb - if isinstance(path, bytes): - if b'$' not in path: - return path - if not _varprogb: - import re - _varprogb = re.compile(br'\$(\w+|\{[^}]*\})', re.ASCII) - search = _varprogb.search - start = b'{' - end = b'}' - else: - if '$' not in path: - return path - if not _varprog: - import re - _varprog = re.compile(r'\$(\w+|\{[^}]*\})', re.ASCII) - search = _varprog.search - start = '{' - end = '}' - i = 0 - while True: - m = search(path, i) - if not m: - break - i, j = m.span(0) - name = None # type: Union[str, bytes] - name = m.group(1) - if name.startswith(start) and name.endswith(end): - name = name[1:-1] - if isinstance(name, bytes): - name = str(name, 'ASCII') - if name in os.environ: - tail = path[j:] - value = None # type: Union[str, bytes] - value = os.environ[name] - if isinstance(path, bytes): - value = value.encode('ASCII') - path = path[:i] + value - i = len(path) - path += tail - else: - i = j - return path - - -# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B. -# It should be understood that this may change the meaning of the path -# if it contains symbolic links! - -def normpath(path: AnyStr) -> AnyStr: - """Normalize path, eliminating double slashes, etc.""" - if isinstance(path, bytes): - sep = b'/' - empty = b'' - dot = b'.' - dotdot = b'..' - else: - sep = '/' - empty = '' - dot = '.' - dotdot = '..' - if path == empty: - return dot - initial_slashes = path.startswith(sep) # type: int - # POSIX allows one or two initial slashes, but treats three or more - # as single slash. - if (initial_slashes and - path.startswith(sep*2) and not path.startswith(sep*3)): - initial_slashes = 2 - comps = path.split(sep) - new_comps = [] # type: List[AnyStr] - for comp in comps: - if comp in (empty, dot): - continue - if (comp != dotdot or (not initial_slashes and not new_comps) or - (new_comps and new_comps[-1] == dotdot)): - new_comps.append(comp) - elif new_comps: - new_comps.pop() - comps = new_comps - path = sep.join(comps) - if initial_slashes: - path = sep*initial_slashes + path - return path or dot - - -def abspath(path: AnyStr) -> AnyStr: - """Return an absolute path.""" - if not isabs(path): - if isinstance(path, bytes): - cwd = os.getcwdb() - else: - cwd = os.getcwd() - path = join(cwd, path) - return normpath(path) - - -# Return a canonical path (i.e. the absolute location of a file on the -# filesystem). - -def realpath(filename: AnyStr) -> AnyStr: - """Return the canonical path of the specified filename, eliminating any -symbolic links encountered in the path.""" - if isinstance(filename, bytes): - sep = b'/' - empty = b'' - else: - sep = '/' - empty = '' - if isabs(filename): - bits = [sep] + filename.split(sep)[1:] - else: - bits = [empty] + filename.split(sep) - - for i in range(2, len(bits)+1): - component = join(*bits[0:i]) - # Resolve symbolic links. - if islink(component): - resolved = _resolve_link(component) - if resolved is None: - # Infinite loop -- return original component + rest of the path - return abspath(join(*([component] + bits[i:]))) - else: - newpath = join(*([resolved] + bits[i:])) - return realpath(newpath) - - return abspath(filename) - - -def _resolve_link(path: AnyStr) -> AnyStr: - """Internal helper function. Takes a path and follows symlinks - until we either arrive at something that isn't a symlink, or - encounter a path we've seen before (meaning that there's a loop). - """ - paths_seen = set() # type: Set[AnyStr] - while islink(path): - if path in paths_seen: - # Already seen this path, so we must have a symlink loop - return None - paths_seen.add(path) - # Resolve where the link points to - resolved = os.readlink(path) - if not isabs(resolved): - dir = dirname(path) - path = normpath(join(dir, resolved)) - else: - path = normpath(resolved) - return path - -supports_unicode_filenames = (sys.platform == 'darwin') - -def relpath(path: AnyStr, start: AnyStr = None) -> AnyStr: - """Return a relative version of a path""" - - if not path: - raise ValueError("no path specified") - - if isinstance(path, bytes): - curdir = b'.' - sep = b'/' - pardir = b'..' - else: - curdir = '.' - sep = '/' - pardir = '..' - - if start is None: - start = curdir - - start_list = [x for x in abspath(start).split(sep) if x] - path_list = [x for x in abspath(path).split(sep) if x] - - # Work out how much of the filepath is shared by start and path. - i = len(commonprefix([start_list, path_list])) - - rel_list = [pardir] * (len(start_list)-i) + path_list[i:] - if not rel_list: - return curdir - return join(*rel_list) diff --git a/test-data/stdlib-samples/3.2/pprint.py b/test-data/stdlib-samples/3.2/pprint.py deleted file mode 100644 index 650c1a3b5afe..000000000000 --- a/test-data/stdlib-samples/3.2/pprint.py +++ /dev/null @@ -1,380 +0,0 @@ -# Author: Fred L. Drake, Jr. -# fdrake@acm.org -# -# This is a simple little module I wrote to make life easier. I didn't -# see anything quite like it in the library, though I may have overlooked -# something. I wrote this when I was trying to read some heavily nested -# tuples with fairly non-descriptive content. This is modeled very much -# after Lisp/Scheme - style pretty-printing of lists. If you find it -# useful, thank small children who sleep at night. - -"""Support to pretty-print lists, tuples, & dictionaries recursively. - -Very simple, but useful, especially in debugging data structures. - -Classes -------- - -PrettyPrinter() - Handle pretty-printing operations onto a stream using a configured - set of formatting parameters. - -Functions ---------- - -pformat() - Format a Python object into a pretty-printed representation. - -pprint() - Pretty-print a Python object to a stream [default is sys.stdout]. - -saferepr() - Generate a 'standard' repr()-like value, but protect against recursive - data structures. - -""" - -import sys as _sys -from collections import OrderedDict as _OrderedDict -from io import StringIO as _StringIO - -from typing import Any, Tuple, Dict, TextIO, cast, List - -__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr", - "PrettyPrinter"] - -# cache these for faster access: -_commajoin = ", ".join -_id = id -_len = len -_type = type - - -def pprint(object: object, stream: TextIO = None, indent: int = 1, - width: int = 80, depth: int = None) -> None: - """Pretty-print a Python object to a stream [default is sys.stdout].""" - printer = PrettyPrinter( - stream=stream, indent=indent, width=width, depth=depth) - printer.pprint(object) - -def pformat(object: object, indent: int = 1, width: int = 80, - depth: int = None) -> str: - """Format a Python object into a pretty-printed representation.""" - return PrettyPrinter(indent=indent, width=width, depth=depth).pformat(object) - -def saferepr(object: object) -> str: - """Version of repr() which can handle recursive data structures.""" - return _safe_repr(object, {}, None, 0)[0] - -def isreadable(object: object) -> bool: - """Determine if saferepr(object) is readable by eval().""" - return _safe_repr(object, {}, None, 0)[1] - -def isrecursive(object: object) -> bool: - """Determine if object requires a recursive representation.""" - return _safe_repr(object, {}, None, 0)[2] - -class _safe_key: - """Helper function for key functions when sorting unorderable objects. - - The wrapped-object will fallback to an Py2.x style comparison for - unorderable types (sorting first comparing the type name and then by - the obj ids). Does not work recursively, so dict.items() must have - _safe_key applied to both the key and the value. - - """ - - __slots__ = ['obj'] - - def __init__(self, obj: Any) -> None: - self.obj = obj - - def __lt__(self, other: Any) -> Any: - rv = self.obj.__lt__(other.obj) # type: Any - if rv is NotImplemented: - rv = (str(type(self.obj)), id(self.obj)) < \ - (str(type(other.obj)), id(other.obj)) - return rv - -def _safe_tuple(t: Tuple[Any, Any]) -> Tuple[_safe_key, _safe_key]: - "Helper function for comparing 2-tuples" - return _safe_key(t[0]), _safe_key(t[1]) - -class PrettyPrinter: - def __init__(self, indent: int = 1, width: int = 80, depth: int = None, - stream: TextIO = None) -> None: - """Handle pretty printing operations onto a stream using a set of - configured parameters. - - indent - Number of spaces to indent for each level of nesting. - - width - Attempted maximum number of columns in the output. - - depth - The maximum depth to print out nested structures. - - stream - The desired output stream. If omitted (or false), the standard - output stream available at construction will be used. - - """ - indent = int(indent) - width = int(width) - assert indent >= 0, "indent must be >= 0" - assert depth is None or depth > 0, "depth must be > 0" - assert width, "width must be != 0" - self._depth = depth - self._indent_per_level = indent - self._width = width - if stream is not None: - self._stream = stream - else: - self._stream = _sys.stdout - - def pprint(self, object: object) -> None: - self._format(object, self._stream, 0, 0, {}, 0) - self._stream.write("\n") - - def pformat(self, object: object) -> str: - sio = _StringIO() - self._format(object, sio, 0, 0, {}, 0) - return sio.getvalue() - - def isrecursive(self, object: object) -> int: - return self.format(object, {}, 0, 0)[2] - - def isreadable(self, object: object) -> int: - s, readable, recursive = self.format(object, {}, 0, 0) - return readable and not recursive - - def _format(self, object: object, stream: TextIO, indent: int, - allowance: int, context: Dict[int, int], level: int) -> None: - level = level + 1 - objid = _id(object) - if objid in context: - stream.write(_recursion(object)) - self._recursive = True - self._readable = False - return - rep = self._repr(object, context, level - 1) - typ = _type(object) - sepLines = _len(rep) > (self._width - 1 - indent - allowance) - write = stream.write - - if self._depth and level > self._depth: - write(rep) - return - - if sepLines: - r = getattr(typ, "__repr__", None) - if isinstance(object, dict): - write('{') - if self._indent_per_level > 1: - write((self._indent_per_level - 1) * ' ') - length = _len(object) - if length: - context[objid] = 1 - indent = indent + self._indent_per_level - if issubclass(typ, _OrderedDict): - items = list(object.items()) - else: - items = sorted(object.items(), key=_safe_tuple) - key, ent = items[0] - rep = self._repr(key, context, level) - write(rep) - write(': ') - self._format(ent, stream, indent + _len(rep) + 2, - allowance + 1, context, level) - if length > 1: - for key, ent in items[1:]: - rep = self._repr(key, context, level) - write(',\n%s%s: ' % (' '*indent, rep)) - self._format(ent, stream, indent + _len(rep) + 2, - allowance + 1, context, level) - indent = indent - self._indent_per_level - del context[objid] - write('}') - return - - if ((issubclass(typ, list) and r is list.__repr__) or - (issubclass(typ, tuple) and r is tuple.__repr__) or - (issubclass(typ, set) and r is set.__repr__) or - (issubclass(typ, frozenset) and r is frozenset.__repr__) - ): - anyobj = cast(Any, object) # TODO Collection? - length = _len(anyobj) - if issubclass(typ, list): - write('[') - endchar = ']' - lst = anyobj - elif issubclass(typ, set): - if not length: - write('set()') - return - write('{') - endchar = '}' - lst = sorted(anyobj, key=_safe_key) - elif issubclass(typ, frozenset): - if not length: - write('frozenset()') - return - write('frozenset({') - endchar = '})' - lst = sorted(anyobj, key=_safe_key) - indent += 10 - else: - write('(') - endchar = ')' - lst = list(anyobj) - if self._indent_per_level > 1: - write((self._indent_per_level - 1) * ' ') - if length: - context[objid] = 1 - indent = indent + self._indent_per_level - self._format(lst[0], stream, indent, allowance + 1, - context, level) - if length > 1: - for ent in lst[1:]: - write(',\n' + ' '*indent) - self._format(ent, stream, indent, - allowance + 1, context, level) - indent = indent - self._indent_per_level - del context[objid] - if issubclass(typ, tuple) and length == 1: - write(',') - write(endchar) - return - - write(rep) - - def _repr(self, object: object, context: Dict[int, int], - level: int) -> str: - repr, readable, recursive = self.format(object, context.copy(), - self._depth, level) - if not readable: - self._readable = False - if recursive: - self._recursive = True - return repr - - def format(self, object: object, context: Dict[int, int], - maxlevels: int, level: int) -> Tuple[str, int, int]: - """Format object for a specific context, returning a string - and flags indicating whether the representation is 'readable' - and whether the object represents a recursive construct. - """ - return _safe_repr(object, context, maxlevels, level) - - -# Return triple (repr_string, isreadable, isrecursive). - -def _safe_repr(object: object, context: Dict[int, int], - maxlevels: int, level: int) -> Tuple[str, bool, bool]: - typ = _type(object) - if typ is str: - s = cast(str, object) - if 'locale' not in _sys.modules: - return repr(object), True, False - if "'" in s and '"' not in s: - closure = '"' - quotes = {'"': '\\"'} - else: - closure = "'" - quotes = {"'": "\\'"} - qget = quotes.get - sio = _StringIO() - write = sio.write - for char in s: - if char.isalpha(): - write(char) - else: - write(qget(char, repr(char)[1:-1])) - return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False - - r = getattr(typ, "__repr__", None) - if issubclass(typ, dict) and r is dict.__repr__: - if not object: - return "{}", True, False - objid = _id(object) - if maxlevels and level >= maxlevels: - return "{...}", False, objid in context - if objid in context: - return _recursion(object), False, True - context[objid] = 1 - readable = True - recursive = False - components = [] # type: List[str] - append = components.append - level += 1 - saferepr = _safe_repr - items = sorted((cast(dict, object)).items(), key=_safe_tuple) - for k, v in items: - krepr, kreadable, krecur = saferepr(k, context, maxlevels, level) - vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level) - append("%s: %s" % (krepr, vrepr)) - readable = readable and kreadable and vreadable - if krecur or vrecur: - recursive = True - del context[objid] - return "{%s}" % _commajoin(components), readable, recursive - - if (issubclass(typ, list) and r is list.__repr__) or \ - (issubclass(typ, tuple) and r is tuple.__repr__): - anyobj = cast(Any, object) # TODO Sequence? - if issubclass(typ, list): - if not object: - return "[]", True, False - format = "[%s]" - elif _len(anyobj) == 1: - format = "(%s,)" - else: - if not object: - return "()", True, False - format = "(%s)" - objid = _id(object) - if maxlevels and level >= maxlevels: - return format % "...", False, objid in context - if objid in context: - return _recursion(object), False, True - context[objid] = 1 - readable = True - recursive = False - components = [] - append = components.append - level += 1 - for o in anyobj: - orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level) - append(orepr) - if not oreadable: - readable = False - if orecur: - recursive = True - del context[objid] - return format % _commajoin(components), readable, recursive - - rep = repr(object) - return rep, bool(rep and not rep.startswith('<')), False - - -def _recursion(object: object) -> str: - return ("" - % (_type(object).__name__, _id(object))) - - -def _perfcheck(object: object = None) -> None: - import time - if object is None: - object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000 - p = PrettyPrinter() - t1 = time.time() - _safe_repr(object, {}, None, 0) - t2 = time.time() - p.pformat(object) - t3 = time.time() - print("_safe_repr:", t2 - t1) - print("pformat:", t3 - t2) - -if __name__ == "__main__": - _perfcheck() diff --git a/test-data/stdlib-samples/3.2/random.py b/test-data/stdlib-samples/3.2/random.py deleted file mode 100644 index 82bda03f7e53..000000000000 --- a/test-data/stdlib-samples/3.2/random.py +++ /dev/null @@ -1,743 +0,0 @@ -"""Random variable generators. - - integers - -------- - uniform within range - - sequences - --------- - pick random element - pick random sample - generate random permutation - - distributions on the real line: - ------------------------------ - uniform - triangular - normal (Gaussian) - lognormal - negative exponential - gamma - beta - pareto - Weibull - - distributions on the circle (angles 0 to 2pi) - --------------------------------------------- - circular uniform - von Mises - -General notes on the underlying Mersenne Twister core generator: - -* The period is 2**19937-1. -* It is one of the most extensively tested generators in existence. -* The random() method is implemented in C, executes in a single Python step, - and is, therefore, threadsafe. - -""" - -from warnings import warn as _warn -from types import MethodType as _MethodType, BuiltinMethodType as _BuiltinMethodType -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.abc import Set as _Set, Sequence as _Sequence -from hashlib import sha512 as _sha512 - -from typing import ( - Any, TypeVar, Iterable, Sequence, List, Callable, Set, cast, SupportsInt, Union -) - -__all__ = ["Random","seed","random","uniform","randint","choice","sample", - "randrange","shuffle","normalvariate","lognormvariate", - "expovariate","vonmisesvariate","gammavariate","triangular", - "gauss","betavariate","paretovariate","weibullvariate", - "getstate","setstate", "getrandbits", - "SystemRandom"] - -NV_MAGICCONST = 4 * _exp(-0.5)/_sqrt(2.0) -TWOPI = 2.0*_pi -LOG4 = _log(4.0) -SG_MAGICCONST = 1.0 + _log(4.5) -BPF = 53 # Number of bits in a float -RECIP_BPF = 2**-BPF # type: float - - -# Translated by Guido van Rossum from C source provided by -# Adrian Baddeley. Adapted by Raymond Hettinger for use with -# the Mersenne Twister and os.urandom() core generators. - -import _random - -T = TypeVar('T') - -class Random(_random.Random): - """Random number generator base class used by bound module functions. - - Used to instantiate instances of Random to get generators that don't - share state. - - Class Random can also be subclassed if you want to use a different basic - generator of your own devising: in that case, override the following - methods: random(), seed(), getstate(), and setstate(). - Optionally, implement a getrandbits() method so that randrange() - can cover arbitrarily large ranges. - - """ - - VERSION = 3 # used by getstate/setstate - gauss_next = 0.0 - - def __init__(self, x: object = None) -> None: - """Initialize an instance. - - Optional argument x controls seeding, as for Random.seed(). - """ - - self.seed(x) - self.gauss_next = None - - def seed(self, a: Any = None, version: int = 2) -> None: - """Initialize internal state from hashable object. - - None or no argument seeds from current time or from an operating - system specific randomness source if available. - - For version 2 (the default), all of the bits are used if *a *is a str, - bytes, or bytearray. For version 1, the hash() of *a* is used instead. - - If *a* is an int, all bits are used. - - """ - - if a is None: - try: - a = int.from_bytes(_urandom(32), 'big') - except NotImplementedError: - import time - a = int(time.time() * 256) # use fractional seconds - - if version == 2: - if isinstance(a, (str, bytes, bytearray)): - if isinstance(a, str): - a = a.encode() - a += _sha512(a).digest() - a = int.from_bytes(a, 'big') - - super().seed(a) - self.gauss_next = None - - def getstate(self) -> tuple: - """Return internal state; can be passed to setstate() later.""" - return self.VERSION, super().getstate(), self.gauss_next - - def setstate(self, state: tuple) -> None: - """Restore internal state from object returned by getstate().""" - version = state[0] - if version == 3: - version, internalstate, self.gauss_next = state - super().setstate(internalstate) - elif version == 2: - version, internalstate, self.gauss_next = state - # In version 2, the state was saved as signed ints, which causes - # inconsistencies between 32/64-bit systems. The state is - # really unsigned 32-bit ints, so we convert negative ints from - # version 2 to positive longs for version 3. - try: - internalstate = tuple(x % (2**32) for x in internalstate) - except ValueError as e: - raise TypeError() - super().setstate(internalstate) - else: - raise ValueError("state with version %s passed to " - "Random.setstate() of version %s" % - (version, self.VERSION)) - -## ---- Methods below this point do not need to be overridden when -## ---- subclassing for the purpose of using a different core generator. - -## -------------------- pickle support ------------------- - - def __getstate__(self) -> object: # for pickle - return self.getstate() - - def __setstate__(self, state: Any) -> None: # for pickle - self.setstate(state) - - def __reduce__(self) -> tuple: - return self.__class__, (), self.getstate() - -## -------------------- integer methods ------------------- - - def randrange(self, start: SupportsInt, stop: SupportsInt = None, - step: int = 1, int: Callable[[SupportsInt], - int] = int) -> int: - """Choose a random item from range(start, stop[, step]). - - This fixes the problem with randint() which includes the - endpoint; in Python this is usually not what you want. - - Do not supply the 'int' argument. - """ - - # This code is a bit messy to make it fast for the - # common case while still doing adequate error checking. - istart = int(start) - if istart != start: - raise ValueError("non-integer arg 1 for randrange()") - if stop is None: - if istart > 0: - return self._randbelow(istart) - raise ValueError("empty range for randrange()") - - # stop argument supplied. - istop = int(stop) - if istop != stop: - raise ValueError("non-integer stop for randrange()") - width = istop - istart - if step == 1 and width > 0: - return istart + self._randbelow(width) - if step == 1: - raise ValueError("empty range for randrange() (%d,%d, %d)" % (istart, istop, width)) - - # Non-unit step argument supplied. - istep = int(step) - if istep != step: - raise ValueError("non-integer step for randrange()") - if istep > 0: - n = (width + istep - 1) // istep - elif istep < 0: - n = (width + istep + 1) // istep - else: - raise ValueError("zero step for randrange()") - - if n <= 0: - raise ValueError("empty range for randrange()") - - return istart + istep*self._randbelow(n) - - def randint(self, a: int, b: int) -> int: - """Return random integer in range [a, b], including both end points. - """ - - return self.randrange(a, b+1) - - def _randbelow(self, n: int, int: Callable[[float], int] = int, - maxsize: int = 1< int: - "Return a random int in the range [0,n). Raises ValueError if n==0." - - getrandbits = self.getrandbits - # Only call self.getrandbits if the original random() builtin method - # has not been overridden or if a new getrandbits() was supplied. - if type(self.random) is BuiltinMethod or type(getrandbits) is Method: - k = n.bit_length() # don't use (n-1) here because n can be 1 - r = getrandbits(k) # 0 <= r < 2**k - while r >= n: - r = getrandbits(k) - return r - # There's an overridden random() method but no new getrandbits() method, - # so we can only use random() from here. - random = self.random - if n >= maxsize: - _warn("Underlying random() generator does not supply \n" - "enough bits to choose from a population range this large.\n" - "To remove the range limitation, add a getrandbits() method.") - return int(random() * n) - rem = maxsize % n - limit = (maxsize - rem) / maxsize # int(limit * maxsize) % n == 0 - s = random() - while s >= limit: - s = random() - return int(s*maxsize) % n - -## -------------------- sequence methods ------------------- - - def choice(self, seq: Sequence[T]) -> T: - """Choose a random element from a non-empty sequence.""" - try: - i = self._randbelow(len(seq)) - except ValueError: - raise IndexError('Cannot choose from an empty sequence') - return seq[i] - - def shuffle(self, x: List[T], - random: Callable[[], float] = None, - int: Callable[[float], int] = int) -> None: - """x, random=random.random -> shuffle list x in place; return None. - - Optional arg random is a 0-argument function returning a random - float in [0.0, 1.0); by default, the standard random.random. - """ - - randbelow = self._randbelow - for i in reversed(range(1, len(x))): - # pick an element in x[:i+1] with which to exchange x[i] - j = randbelow(i+1) if random is None else int(random() * (i+1)) - x[i], x[j] = x[j], x[i] - - def sample(self, population: Union[_Set[T], _Sequence[T]], k: int) -> List[T]: - """Chooses k unique random elements from a population sequence or set. - - Returns a new list containing elements from the population while - leaving the original population unchanged. The resulting list is - in selection order so that all sub-slices will also be valid random - samples. This allows raffle winners (the sample) to be partitioned - into grand prize and second place winners (the subslices). - - Members of the population need not be hashable or unique. If the - population contains repeats, then each occurrence is a possible - selection in the sample. - - To choose a sample in a range of integers, use range as an argument. - This is especially fast and space efficient for sampling from a - large population: sample(range(10000000), 60) - """ - - # Sampling without replacement entails tracking either potential - # selections (the pool) in a list or previous selections in a set. - - # When the number of selections is small compared to the - # population, then tracking selections is efficient, requiring - # only a small set and an occasional reselection. For - # a larger number of selections, the pool tracking method is - # preferred since the list takes less space than the - # set and it doesn't suffer from frequent reselections. - - if isinstance(population, _Set): - population = list(population) - if not isinstance(population, _Sequence): - raise TypeError("Population must be a sequence or set. For dicts, use list(d).") - randbelow = self._randbelow - n = len(population) - if not (0 <= k and k <= n): - raise ValueError("Sample larger than population") - result = [cast(T, None)] * k - setsize = 21 # size of a small set minus size of an empty list - if k > 5: - setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big sets - if n <= setsize: - # An n-length list is smaller than a k-length set - pool = list(population) - for i in range(k): # invariant: non-selected at [0,n-i) - j = randbelow(n-i) - result[i] = pool[j] - pool[j] = pool[n-i-1] # move non-selected item into vacancy - else: - selected = set() # type: Set[int] - selected_add = selected.add - for i in range(k): - j = randbelow(n) - while j in selected: - j = randbelow(n) - selected_add(j) - result[i] = population[j] - return result - -## -------------------- real-valued distributions ------------------- - -## -------------------- uniform distribution ------------------- - - def uniform(self, a: float, b: float) -> float: - "Get a random number in the range [a, b) or [a, b] depending on rounding." - return a + (b-a) * self.random() - -## -------------------- triangular -------------------- - - def triangular(self, low: float = 0.0, high: float = 1.0, - mode: float = None) -> float: - """Triangular distribution. - - Continuous distribution bounded by given lower and upper limits, - and having a given mode value in-between. - - http://en.wikipedia.org/wiki/Triangular_distribution - - """ - u = self.random() - c = 0.5 if mode is None else (mode - low) / (high - low) - if u > c: - u = 1.0 - u - c = 1.0 - c - low, high = high, low - return low + (high - low) * (u * c) ** 0.5 - -## -------------------- normal distribution -------------------- - - def normalvariate(self, mu: float, sigma: float) -> float: - """Normal distribution. - - mu is the mean, and sigma is the standard deviation. - - """ - # mu = mean, sigma = standard deviation - - # Uses Kinderman and Monahan method. Reference: Kinderman, - # A.J. and Monahan, J.F., "Computer generation of random - # variables using the ratio of uniform deviates", ACM Trans - # Math Software, 3, (1977), pp257-260. - - random = self.random - while 1: - u1 = random() - u2 = 1.0 - random() - z = NV_MAGICCONST*(u1-0.5)/u2 - zz = z*z/4.0 - if zz <= -_log(u2): - break - return mu + z*sigma - -## -------------------- lognormal distribution -------------------- - - def lognormvariate(self, mu: float, sigma: float) -> float: - """Log normal distribution. - - If you take the natural logarithm of this distribution, you'll get a - normal distribution with mean mu and standard deviation sigma. - mu can have any value, and sigma must be greater than zero. - - """ - return _exp(self.normalvariate(mu, sigma)) - -## -------------------- exponential distribution -------------------- - - def expovariate(self, lambd: float) -> float: - """Exponential distribution. - - lambd is 1.0 divided by the desired mean. It should be - nonzero. (The parameter would be called "lambda", but that is - a reserved word in Python.) Returned values range from 0 to - positive infinity if lambd is positive, and from negative - infinity to 0 if lambd is negative. - - """ - # lambd: rate lambd = 1/mean - # ('lambda' is a Python reserved word) - - # we use 1-random() instead of random() to preclude the - # possibility of taking the log of zero. - return -_log(1.0 - self.random())/lambd - -## -------------------- von Mises distribution -------------------- - - def vonmisesvariate(self, mu: float, kappa: float) -> float: - """Circular data distribution. - - mu is the mean angle, expressed in radians between 0 and 2*pi, and - kappa is the concentration parameter, which must be greater than or - equal to zero. If kappa is equal to zero, this distribution reduces - to a uniform random angle over the range 0 to 2*pi. - - """ - # mu: mean angle (in radians between 0 and 2*pi) - # kappa: concentration parameter kappa (>= 0) - # if kappa = 0 generate uniform random angle - - # Based upon an algorithm published in: Fisher, N.I., - # "Statistical Analysis of Circular Data", Cambridge - # University Press, 1993. - - # Thanks to Magnus Kessler for a correction to the - # implementation of step 4. - - random = self.random - if kappa <= 1e-6: - return TWOPI * random() - - a = 1.0 + _sqrt(1.0 + 4.0 * kappa * kappa) - b = (a - _sqrt(2.0 * a))/(2.0 * kappa) - r = (1.0 + b * b)/(2.0 * b) - - while 1: - u1 = random() - - z = _cos(_pi * u1) - f = (1.0 + r * z)/(r + z) - c = kappa * (r - f) - - u2 = random() - - if u2 < c * (2.0 - c) or u2 <= c * _exp(1.0 - c): - break - - u3 = random() - if u3 > 0.5: - theta = (mu % TWOPI) + _acos(f) - else: - theta = (mu % TWOPI) - _acos(f) - - return theta - -## -------------------- gamma distribution -------------------- - - def gammavariate(self, alpha: float, beta: float) -> float: - """Gamma distribution. Not the gamma function! - - Conditions on the parameters are alpha > 0 and beta > 0. - - The probability distribution function is: - - x ** (alpha - 1) * math.exp(-x / beta) - pdf(x) = -------------------------------------- - math.gamma(alpha) * beta ** alpha - - """ - - # alpha > 0, beta > 0, mean is alpha*beta, variance is alpha*beta**2 - - # Warning: a few older sources define the gamma distribution in terms - # of alpha > -1.0 - if alpha <= 0.0 or beta <= 0.0: - raise ValueError('gammavariate: alpha and beta must be > 0.0') - - random = self.random - if alpha > 1.0: - - # Uses R.C.H. Cheng, "The generation of Gamma - # variables with non-integral shape parameters", - # Applied Statistics, (1977), 26, No. 1, p71-74 - - ainv = _sqrt(2.0 * alpha - 1.0) - bbb = alpha - LOG4 - ccc = alpha + ainv - - while 1: - u1 = random() - if not (1e-7 < u1 and u1 < .9999999): - continue - u2 = 1.0 - random() - v = _log(u1/(1.0-u1))/ainv - x = alpha*_exp(v) - z = u1*u1*u2 - r = bbb+ccc*v-x - if r + SG_MAGICCONST - 4.5*z >= 0.0 or r >= _log(z): - return x * beta - - elif alpha == 1.0: - # expovariate(1) - u = random() - while u <= 1e-7: - u = random() - return -_log(u) * beta - - else: # alpha is between 0 and 1 (exclusive) - - # Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle - - while 1: - u = random() - b = (_e + alpha)/_e - p = b*u - if p <= 1.0: - x = p ** (1.0/alpha) - else: - x = -_log((b-p)/alpha) - u1 = random() - if p > 1.0: - if u1 <= x ** (alpha - 1.0): - break - elif u1 <= _exp(-x): - break - return x * beta - -## -------------------- Gauss (faster alternative) -------------------- - - def gauss(self, mu: float, sigma: float) -> float: - """Gaussian distribution. - - mu is the mean, and sigma is the standard deviation. This is - slightly faster than the normalvariate() function. - - Not thread-safe without a lock around calls. - - """ - - # When x and y are two variables from [0, 1), uniformly - # distributed, then - # - # cos(2*pi*x)*sqrt(-2*log(1-y)) - # sin(2*pi*x)*sqrt(-2*log(1-y)) - # - # are two *independent* variables with normal distribution - # (mu = 0, sigma = 1). - # (Lambert Meertens) - # (corrected version; bug discovered by Mike Miller, fixed by LM) - - # Multithreading note: When two threads call this function - # simultaneously, it is possible that they will receive the - # same return value. The window is very small though. To - # avoid this, you have to use a lock around all calls. (I - # didn't want to slow this down in the serial case by using a - # lock here.) - - random = self.random - z = self.gauss_next - self.gauss_next = None - if z is None: - x2pi = random() * TWOPI - g2rad = _sqrt(-2.0 * _log(1.0 - random())) - z = _cos(x2pi) * g2rad - self.gauss_next = _sin(x2pi) * g2rad - - return mu + z*sigma - -## -------------------- beta -------------------- -## See -## http://mail.python.org/pipermail/python-bugs-list/2001-January/003752.html -## for Ivan Frohne's insightful analysis of why the original implementation: -## -## def betavariate(self, alpha, beta): -## # Discrete Event Simulation in C, pp 87-88. -## -## y = self.expovariate(alpha) -## z = self.expovariate(1.0/beta) -## return z/(y+z) -## -## was dead wrong, and how it probably got that way. - - def betavariate(self, alpha: float, beta: float) -> 'float': - """Beta distribution. - - Conditions on the parameters are alpha > 0 and beta > 0. - Returned values range between 0 and 1. - - """ - - # This version due to Janne Sinkkonen, and matches all the std - # texts (e.g., Knuth Vol 2 Ed 3 pg 134 "the beta distribution"). - y = self.gammavariate(alpha, 1.) - if y == 0: - return 0.0 - else: - return y / (y + self.gammavariate(beta, 1.)) - -## -------------------- Pareto -------------------- - - def paretovariate(self, alpha: float) -> float: - """Pareto distribution. alpha is the shape parameter.""" - # Jain, pg. 495 - - u = 1.0 - self.random() - return 1.0 / u ** (1.0/alpha) - -## -------------------- Weibull -------------------- - - def weibullvariate(self, alpha: float, beta: float) -> float: - """Weibull distribution. - - alpha is the scale parameter and beta is the shape parameter. - - """ - # Jain, pg. 499; bug fix courtesy Bill Arms - - u = 1.0 - self.random() - return alpha * (-_log(u)) ** (1.0/beta) - -## --------------- Operating System Random Source ------------------ - -class SystemRandom(Random): - """Alternate random number generator using sources provided - by the operating system (such as /dev/urandom on Unix or - CryptGenRandom on Windows). - - Not available on all systems (see os.urandom() for details). - """ - - def random(self) -> float: - """Get the next random number in the range [0.0, 1.0).""" - return (int.from_bytes(_urandom(7), 'big') >> 3) * RECIP_BPF - - def getrandbits(self, k: int) -> int: - """getrandbits(k) -> x. Generates a long int with k random bits.""" - if k <= 0: - raise ValueError('number of bits must be greater than zero') - if k != int(k): - raise TypeError('number of bits should be an integer') - numbytes = (k + 7) // 8 # bits / 8 and rounded up - x = int.from_bytes(_urandom(numbytes), 'big') - return x >> (numbytes * 8 - k) # trim excess bits - - def seed(self, a: object = None, version: int = None) -> None: - "Stub method. Not used for a system random number generator." - return - - def _notimplemented(self, *args: Any, **kwds: Any) -> Any: - "Method should not be called for a system random number generator." - raise NotImplementedError('System entropy source does not have state.') - getstate = setstate = _notimplemented - -# Create one instance, seeded from current time, and export its methods -# as module-level functions. The functions share state across all uses -#(both in the user's code and in the Python libraries), but that's fine -# for most programs and is easier for the casual user than making them -# instantiate their own Random() instance. - -_inst = Random() -seed = _inst.seed -random = _inst.random -uniform = _inst.uniform -triangular = _inst.triangular -randint = _inst.randint -choice = _inst.choice -randrange = _inst.randrange -sample = _inst.sample -shuffle = _inst.shuffle -normalvariate = _inst.normalvariate -lognormvariate = _inst.lognormvariate -expovariate = _inst.expovariate -vonmisesvariate = _inst.vonmisesvariate -gammavariate = _inst.gammavariate -gauss = _inst.gauss -betavariate = _inst.betavariate -paretovariate = _inst.paretovariate -weibullvariate = _inst.weibullvariate -getstate = _inst.getstate -setstate = _inst.setstate -getrandbits = _inst.getrandbits - -## -------------------- test program -------------------- - -def _test_generator(n: int, func: Any, args: tuple) -> None: - import time - print(n, 'times', func.__name__) - total = 0.0 - sqsum = 0.0 - smallest = 1e10 - largest = -1e10 - t0 = time.time() - for i in range(n): - x = func(*args) # type: float - total += x - sqsum = sqsum + x*x - smallest = min(x, smallest) - largest = max(x, largest) - t1 = time.time() - print(round(t1-t0, 3), 'sec,', end=' ') - avg = total/n - stddev = _sqrt(sqsum/n - avg*avg) - print('avg %g, stddev %g, min %g, max %g' % \ - (avg, stddev, smallest, largest)) - - -def _test(N: int = 2000) -> None: - _test_generator(N, random, ()) - _test_generator(N, normalvariate, (0.0, 1.0)) - _test_generator(N, lognormvariate, (0.0, 1.0)) - _test_generator(N, vonmisesvariate, (0.0, 1.0)) - _test_generator(N, gammavariate, (0.01, 1.0)) - _test_generator(N, gammavariate, (0.1, 1.0)) - _test_generator(N, gammavariate, (0.1, 2.0)) - _test_generator(N, gammavariate, (0.5, 1.0)) - _test_generator(N, gammavariate, (0.9, 1.0)) - _test_generator(N, gammavariate, (1.0, 1.0)) - _test_generator(N, gammavariate, (2.0, 1.0)) - _test_generator(N, gammavariate, (20.0, 1.0)) - _test_generator(N, gammavariate, (200.0, 1.0)) - _test_generator(N, gauss, (0.0, 1.0)) - _test_generator(N, betavariate, (3.0, 3.0)) - _test_generator(N, triangular, (0.0, 1.0, 1.0/3.0)) - -if __name__ == '__main__': - _test() diff --git a/test-data/stdlib-samples/3.2/shutil.py b/test-data/stdlib-samples/3.2/shutil.py deleted file mode 100644 index bcefb7787952..000000000000 --- a/test-data/stdlib-samples/3.2/shutil.py +++ /dev/null @@ -1,790 +0,0 @@ -"""Utility functions for copying and archiving files and directory trees. - -XXX The functions here don't copy the resource fork or other metadata on Mac. - -""" - -import os -import sys -import stat -from os.path import abspath -import fnmatch -import collections -import errno -import tarfile -import builtins - -from typing import ( - Any, AnyStr, IO, List, Iterable, Callable, Tuple, Dict, Sequence, cast -) -from types import TracebackType - -try: - import bz2 - _BZ2_SUPPORTED = True -except ImportError: - _BZ2_SUPPORTED = False - -try: - from pwd import getpwnam as _getpwnam - getpwnam = _getpwnam -except ImportError: - getpwnam = None - -try: - from grp import getgrnam as _getgrnam - getgrnam = _getgrnam -except ImportError: - getgrnam = None - -__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2", - "copytree", "move", "rmtree", "Error", "SpecialFileError", - "ExecError", "make_archive", "get_archive_formats", - "register_archive_format", "unregister_archive_format", - "get_unpack_formats", "register_unpack_format", - "unregister_unpack_format", "unpack_archive", "ignore_patterns"] - -class Error(EnvironmentError): - pass - -class SpecialFileError(EnvironmentError): - """Raised when trying to do a kind of operation (e.g. copying) which is - not supported on a special file (e.g. a named pipe)""" - -class ExecError(EnvironmentError): - """Raised when a command could not be executed""" - -class ReadError(EnvironmentError): - """Raised when an archive cannot be read""" - -class RegistryError(Exception): - """Raised when a registry operation with the archiving - and unpacking registeries fails""" - - -if sys.platform == "win32": - _WindowsError = WindowsError -else: - _WindowsError = None - - -# Function aliases to be patched in test cases -rename = os.rename -open = builtins.open - - -def copyfileobj(fsrc: IO[AnyStr], fdst: IO[AnyStr], - length: int = 16*1024) -> None: - """copy data from file-like object fsrc to file-like object fdst""" - while 1: - buf = fsrc.read(length) - if not buf: - break - fdst.write(buf) - -def _samefile(src: str, dst: str) -> bool: - # Macintosh, Unix. - if hasattr(os.path, 'samefile'): - try: - return os.path.samefile(src, dst) - except OSError: - return False - - # All other platforms: check for same pathname. - return (os.path.normcase(os.path.abspath(src)) == - os.path.normcase(os.path.abspath(dst))) - -def copyfile(src: str, dst: str) -> None: - """Copy data from src to dst""" - if _samefile(src, dst): - raise Error("`%s` and `%s` are the same file" % (src, dst)) - - for fn in [src, dst]: - try: - st = os.stat(fn) - except OSError: - # File most likely does not exist - pass - else: - # XXX What about other special files? (sockets, devices...) - if stat.S_ISFIFO(st.st_mode): - raise SpecialFileError("`%s` is a named pipe" % fn) - - with open(src, 'rb') as fsrc: - with open(dst, 'wb') as fdst: - copyfileobj(fsrc, fdst) - -def copymode(src: str, dst: str) -> None: - """Copy mode bits from src to dst""" - if hasattr(os, 'chmod'): - st = os.stat(src) - mode = stat.S_IMODE(st.st_mode) - os.chmod(dst, mode) - -def copystat(src: str, dst: str) -> None: - """Copy all stat info (mode bits, atime, mtime, flags) from src to dst""" - st = os.stat(src) - mode = stat.S_IMODE(st.st_mode) - if hasattr(os, 'utime'): - os.utime(dst, (st.st_atime, st.st_mtime)) - if hasattr(os, 'chmod'): - os.chmod(dst, mode) - if hasattr(os, 'chflags') and hasattr(st, 'st_flags'): - try: - os.chflags(dst, st.st_flags) - except OSError as why: - if (not hasattr(errno, 'EOPNOTSUPP') or - why.errno != errno.EOPNOTSUPP): - raise - -def copy(src: str, dst: str) -> None: - """Copy data and mode bits ("cp src dst"). - - The destination may be a directory. - - """ - if os.path.isdir(dst): - dst = os.path.join(dst, os.path.basename(src)) - copyfile(src, dst) - copymode(src, dst) - -def copy2(src: str, dst: str) -> None: - """Copy data and all stat info ("cp -p src dst"). - - The destination may be a directory. - - """ - if os.path.isdir(dst): - dst = os.path.join(dst, os.path.basename(src)) - copyfile(src, dst) - copystat(src, dst) - -def ignore_patterns(*patterns: str) -> Callable[[str, List[str]], - Iterable[str]]: - """Function that can be used as copytree() ignore parameter. - - Patterns is a sequence of glob-style patterns - that are used to exclude files""" - def _ignore_patterns(path: str, names: List[str]) -> Iterable[str]: - ignored_names = [] # type: List[str] - for pattern in patterns: - ignored_names.extend(fnmatch.filter(names, pattern)) - return set(ignored_names) - return _ignore_patterns - -def copytree(src: str, dst: str, symlinks: bool = False, - ignore: Callable[[str, List[str]], Iterable[str]] = None, - copy_function: Callable[[str, str], None] = copy2, - ignore_dangling_symlinks: bool = False) -> None: - """Recursively copy a directory tree. - - The destination directory must not already exist. - If exception(s) occur, an Error is raised with a list of reasons. - - If the optional symlinks flag is true, symbolic links in the - source tree result in symbolic links in the destination tree; if - it is false, the contents of the files pointed to by symbolic - links are copied. If the file pointed by the symlink doesn't - exist, an exception will be added in the list of errors raised in - an Error exception at the end of the copy process. - - You can set the optional ignore_dangling_symlinks flag to true if you - want to silence this exception. Notice that this has no effect on - platforms that don't support os.symlink. - - The optional ignore argument is a callable. If given, it - is called with the `src` parameter, which is the directory - being visited by copytree(), and `names` which is the list of - `src` contents, as returned by os.listdir(): - - callable(src, names) -> ignored_names - - Since copytree() is called recursively, the callable will be - called once for each directory that is copied. It returns a - list of names relative to the `src` directory that should - not be copied. - - The optional copy_function argument is a callable that will be used - to copy each file. It will be called with the source path and the - destination path as arguments. By default, copy2() is used, but any - function that supports the same signature (like copy()) can be used. - - """ - names = os.listdir(src) - if ignore is not None: - ignored_names = ignore(src, names) - else: - ignored_names = set() - - os.makedirs(dst) - errors = [] # type: List[Tuple[str, str, str]] - for name in names: - if name in ignored_names: - continue - srcname = os.path.join(src, name) - dstname = os.path.join(dst, name) - try: - if os.path.islink(srcname): - linkto = os.readlink(srcname) - if symlinks: - os.symlink(linkto, dstname) - else: - # ignore dangling symlink if the flag is on - if not os.path.exists(linkto) and ignore_dangling_symlinks: - continue - # otherwise let the copy occurs. copy2 will raise an error - copy_function(srcname, dstname) - elif os.path.isdir(srcname): - copytree(srcname, dstname, symlinks, ignore, copy_function) - else: - # Will raise a SpecialFileError for unsupported file types - copy_function(srcname, dstname) - # catch the Error from the recursive copytree so that we can - # continue with other files - except Error as err: - errors.extend(err.args[0]) - except EnvironmentError as why: - errors.append((srcname, dstname, str(why))) - try: - copystat(src, dst) - except OSError as why: - if _WindowsError is not None and isinstance(why, _WindowsError): - # Copying file access times may fail on Windows - pass - else: - errors.append((src, dst, str(why))) - if errors: - raise Error(errors) - -def rmtree(path: str, ignore_errors: bool = False, - onerror: Callable[[Any, str, Tuple[type, BaseException, TracebackType]], - None] = None) -> None: - """Recursively delete a directory tree. - - If ignore_errors is set, errors are ignored; otherwise, if onerror - is set, it is called to handle the error with arguments (func, - path, exc_info) where func is os.listdir, os.remove, or os.rmdir; - path is the argument to that function that caused it to fail; and - exc_info is a tuple returned by sys.exc_info(). If ignore_errors - is false and onerror is None, an exception is raised. - - """ - if ignore_errors: - def _onerror(x: Any, y: str, - z: Tuple[type, BaseException, TracebackType]) -> None: - pass - onerror = _onerror - elif onerror is None: - def __onerror(x: Any, y: str, - z: Tuple[type, BaseException, TracebackType]) -> None: - raise - onerror = __onerror - try: - if os.path.islink(path): - # symlinks to directories are forbidden, see bug #1669 - raise OSError("Cannot call rmtree on a symbolic link") - except OSError: - onerror(os.path.islink, path, sys.exc_info()) - # can't continue even if onerror hook returns - return - names = [] # type: List[str] - try: - names = os.listdir(path) - except os.error as err: - onerror(os.listdir, path, sys.exc_info()) - for name in names: - fullname = os.path.join(path, name) - try: - mode = os.lstat(fullname).st_mode - except os.error: - mode = 0 - if stat.S_ISDIR(mode): - rmtree(fullname, ignore_errors, onerror) - else: - try: - os.remove(fullname) - except os.error as err: - onerror(os.remove, fullname, sys.exc_info()) - try: - os.rmdir(path) - except os.error: - onerror(os.rmdir, path, sys.exc_info()) - - -def _basename(path: str) -> str: - # A basename() variant which first strips the trailing slash, if present. - # Thus we always get the last component of the path, even for directories. - return os.path.basename(path.rstrip(os.path.sep)) - -def move(src: str, dst: str) -> None: - """Recursively move a file or directory to another location. This is - similar to the Unix "mv" command. - - If the destination is a directory or a symlink to a directory, the source - is moved inside the directory. The destination path must not already - exist. - - If the destination already exists but is not a directory, it may be - overwritten depending on os.rename() semantics. - - If the destination is on our current filesystem, then rename() is used. - Otherwise, src is copied to the destination and then removed. - A lot more could be done here... A look at a mv.c shows a lot of - the issues this implementation glosses over. - - """ - real_dst = dst - if os.path.isdir(dst): - if _samefile(src, dst): - # We might be on a case insensitive filesystem, - # perform the rename anyway. - os.rename(src, dst) - return - - real_dst = os.path.join(dst, _basename(src)) - if os.path.exists(real_dst): - raise Error("Destination path '%s' already exists" % real_dst) - try: - os.rename(src, real_dst) - except OSError as exc: - if os.path.isdir(src): - if _destinsrc(src, dst): - raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) - copytree(src, real_dst, symlinks=True) - rmtree(src) - else: - copy2(src, real_dst) - os.unlink(src) - -def _destinsrc(src: str, dst: str) -> bool: - src = abspath(src) - dst = abspath(dst) - if not src.endswith(os.path.sep): - src += os.path.sep - if not dst.endswith(os.path.sep): - dst += os.path.sep - return dst.startswith(src) - -def _get_gid(name: str) -> int: - """Returns a gid, given a group name.""" - if getgrnam is None or name is None: - return None - try: - result = getgrnam(name) - except KeyError: - result = None - if result is not None: - return result.gr_gid - return None - -def _get_uid(name: str) -> int: - """Returns an uid, given a user name.""" - if getpwnam is None or name is None: - return None - try: - result = getpwnam(name) - except KeyError: - result = None - if result is not None: - return result.pw_uid - return None - -def _make_tarball(base_name: str, base_dir: str, compress: str = "gzip", - verbose: bool = False, dry_run: bool = False, - owner: str = None, group: str = None, - logger: Any = None) -> str: - """Create a (possibly compressed) tar file from all the files under - 'base_dir'. - - 'compress' must be "gzip" (the default), "bzip2", or None. - - 'owner' and 'group' can be used to define an owner and a group for the - archive that is being built. If not provided, the current owner and group - will be used. - - The output tar file will be named 'base_name' + ".tar", possibly plus - the appropriate compression extension (".gz", or ".bz2"). - - Returns the output filename. - """ - tar_compression = {'gzip': 'gz', None: ''} - compress_ext = {'gzip': '.gz'} - - if _BZ2_SUPPORTED: - tar_compression['bzip2'] = 'bz2' - compress_ext['bzip2'] = '.bz2' - - # flags for compression program, each element of list will be an argument - if compress is not None and compress not in compress_ext.keys(): - raise ValueError("bad value for 'compress', or compression format not " - "supported : {0}".format(compress)) - - archive_name = base_name + '.tar' + compress_ext.get(compress, '') - archive_dir = os.path.dirname(archive_name) - - if not os.path.exists(archive_dir): - if logger is not None: - logger.info("creating %s", archive_dir) - if not dry_run: - os.makedirs(archive_dir) - - # creating the tarball - if logger is not None: - logger.info('Creating tar archive') - - uid = _get_uid(owner) - gid = _get_gid(group) - - def _set_uid_gid(tarinfo): - if gid is not None: - tarinfo.gid = gid - tarinfo.gname = group - if uid is not None: - tarinfo.uid = uid - tarinfo.uname = owner - return tarinfo - - if not dry_run: - tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress]) - try: - tar.add(base_dir, filter=_set_uid_gid) - finally: - tar.close() - - return archive_name - -def _call_external_zip(base_dir: str, zip_filename: str, verbose: bool = False, - dry_run: bool = False) -> None: - # XXX see if we want to keep an external call here - if verbose: - zipoptions = "-r" - else: - zipoptions = "-rq" - from distutils.errors import DistutilsExecError - from distutils.spawn import spawn - try: - spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run) - except DistutilsExecError: - # XXX really should distinguish between "couldn't find - # external 'zip' command" and "zip failed". - raise ExecError(("unable to create zip file '%s': " - "could neither import the 'zipfile' module nor " - "find a standalone zip utility") % zip_filename) - -def _make_zipfile(base_name: str, base_dir: str, verbose: bool = False, - dry_run: bool = False, logger: Any = None) -> str: - """Create a zip file from all the files under 'base_dir'. - - The output zip file will be named 'base_name' + ".zip". Uses either the - "zipfile" Python module (if available) or the InfoZIP "zip" utility - (if installed and found on the default search path). If neither tool is - available, raises ExecError. Returns the name of the output zip - file. - """ - zip_filename = base_name + ".zip" - archive_dir = os.path.dirname(base_name) - - if not os.path.exists(archive_dir): - if logger is not None: - logger.info("creating %s", archive_dir) - if not dry_run: - os.makedirs(archive_dir) - - # If zipfile module is not available, try spawning an external 'zip' - # command. - try: - import zipfile - except ImportError: - zipfile = None - - if zipfile is None: - _call_external_zip(base_dir, zip_filename, verbose, dry_run) - else: - if logger is not None: - logger.info("creating '%s' and adding '%s' to it", - zip_filename, base_dir) - - if not dry_run: - zip = zipfile.ZipFile(zip_filename, "w", - compression=zipfile.ZIP_DEFLATED) - - for dirpath, dirnames, filenames in os.walk(base_dir): - for name in filenames: - path = os.path.normpath(os.path.join(dirpath, name)) - if os.path.isfile(path): - zip.write(path, path) - if logger is not None: - logger.info("adding '%s'", path) - zip.close() - - return zip_filename - -_ARCHIVE_FORMATS = { - 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), - 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"), - 'zip': (_make_zipfile, [],"ZIP file") - } # type: Dict[str, Tuple[Any, Sequence[Tuple[str, str]], str]] - -if _BZ2_SUPPORTED: - _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')], - "bzip2'ed tar-file") - -def get_archive_formats() -> List[Tuple[str, str]]: - """Returns a list of supported formats for archiving and unarchiving. - - Each element of the returned sequence is a tuple (name, description) - """ - formats = [(name, registry[2]) for name, registry in - _ARCHIVE_FORMATS.items()] - formats.sort() - return formats - -def register_archive_format(name: str, function: Any, - extra_args: Sequence[Tuple[str, Any]] = None, - description: str = '') -> None: - """Registers an archive format. - - name is the name of the format. function is the callable that will be - used to create archives. If provided, extra_args is a sequence of - (name, value) tuples that will be passed as arguments to the callable. - description can be provided to describe the format, and will be returned - by the get_archive_formats() function. - """ - if extra_args is None: - extra_args = [] - if not callable(function): - raise TypeError('The %s object is not callable' % function) - if not isinstance(extra_args, (tuple, list)): - raise TypeError('extra_args needs to be a sequence') - for element in extra_args: - if not isinstance(element, (tuple, list)) or len(cast(tuple, element)) !=2 : - raise TypeError('extra_args elements are : (arg_name, value)') - - _ARCHIVE_FORMATS[name] = (function, extra_args, description) - -def unregister_archive_format(name: str) -> None: - del _ARCHIVE_FORMATS[name] - -def make_archive(base_name: str, format: str, root_dir: str = None, - base_dir: str = None, verbose: bool = False, - dry_run: bool = False, owner: str = None, - group: str = None, logger: Any = None) -> str: - """Create an archive file (eg. zip or tar). - - 'base_name' is the name of the file to create, minus any format-specific - extension; 'format' is the archive format: one of "zip", "tar", "bztar" - or "gztar". - - 'root_dir' is a directory that will be the root directory of the - archive; ie. we typically chdir into 'root_dir' before creating the - archive. 'base_dir' is the directory where we start archiving from; - ie. 'base_dir' will be the common prefix of all files and - directories in the archive. 'root_dir' and 'base_dir' both default - to the current directory. Returns the name of the archive file. - - 'owner' and 'group' are used when creating a tar archive. By default, - uses the current owner and group. - """ - save_cwd = os.getcwd() - if root_dir is not None: - if logger is not None: - logger.debug("changing into '%s'", root_dir) - base_name = os.path.abspath(base_name) - if not dry_run: - os.chdir(root_dir) - - if base_dir is None: - base_dir = os.curdir - - kwargs = {'dry_run': dry_run, 'logger': logger} - - try: - format_info = _ARCHIVE_FORMATS[format] - except KeyError: - raise ValueError("unknown archive format '%s'" % format) - - func = format_info[0] - for arg, val in format_info[1]: - kwargs[arg] = val - - if format != 'zip': - kwargs['owner'] = owner - kwargs['group'] = group - - try: - filename = func(base_name, base_dir, **kwargs) - finally: - if root_dir is not None: - if logger is not None: - logger.debug("changing back to '%s'", save_cwd) - os.chdir(save_cwd) - - return filename - - -def get_unpack_formats() -> List[Tuple[str, List[str], str]]: - """Returns a list of supported formats for unpacking. - - Each element of the returned sequence is a tuple - (name, extensions, description) - """ - formats = [(name, info[0], info[3]) for name, info in - _UNPACK_FORMATS.items()] - formats.sort() - return formats - -def _check_unpack_options(extensions: List[str], function: Any, - extra_args: Sequence[Tuple[str, Any]]) -> None: - """Checks what gets registered as an unpacker.""" - # first make sure no other unpacker is registered for this extension - existing_extensions = {} # type: Dict[str, str] - for name, info in _UNPACK_FORMATS.items(): - for ext in info[0]: - existing_extensions[ext] = name - - for extension in extensions: - if extension in existing_extensions: - msg = '%s is already registered for "%s"' - raise RegistryError(msg % (extension, - existing_extensions[extension])) - - if not callable(function): - raise TypeError('The registered function must be a callable') - - -def register_unpack_format(name: str, extensions: List[str], function: Any, - extra_args: Sequence[Tuple[str, Any]] = None, - description: str = '') -> None: - """Registers an unpack format. - - `name` is the name of the format. `extensions` is a list of extensions - corresponding to the format. - - `function` is the callable that will be - used to unpack archives. The callable will receive archives to unpack. - If it's unable to handle an archive, it needs to raise a ReadError - exception. - - If provided, `extra_args` is a sequence of - (name, value) tuples that will be passed as arguments to the callable. - description can be provided to describe the format, and will be returned - by the get_unpack_formats() function. - """ - if extra_args is None: - extra_args = [] - _check_unpack_options(extensions, function, extra_args) - _UNPACK_FORMATS[name] = extensions, function, extra_args, description - -def unregister_unpack_format(name: str) -> None: - """Removes the pack format from the registry.""" - del _UNPACK_FORMATS[name] - -def _ensure_directory(path: str) -> None: - """Ensure that the parent directory of `path` exists""" - dirname = os.path.dirname(path) - if not os.path.isdir(dirname): - os.makedirs(dirname) - -def _unpack_zipfile(filename: str, extract_dir: str) -> None: - """Unpack zip `filename` to `extract_dir` - """ - try: - import zipfile - except ImportError: - raise ReadError('zlib not supported, cannot unpack this archive.') - - if not zipfile.is_zipfile(filename): - raise ReadError("%s is not a zip file" % filename) - - zip = zipfile.ZipFile(filename) - try: - for info in zip.infolist(): - name = info.filename - - # don't extract absolute paths or ones with .. in them - if name.startswith('/') or '..' in name: - continue - - target = os.path.join(extract_dir, *name.split('/')) - if not target: - continue - - _ensure_directory(target) - if not name.endswith('/'): - # file - data = zip.read(info.filename) - f = open(target,'wb') - try: - f.write(data) - finally: - f.close() - del data - finally: - zip.close() - -def _unpack_tarfile(filename: str, extract_dir: str) -> None: - """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` - """ - try: - tarobj = tarfile.open(filename) - except tarfile.TarError: - raise ReadError( - "%s is not a compressed or uncompressed tar file" % filename) - try: - tarobj.extractall(extract_dir) - finally: - tarobj.close() - -_UNPACK_FORMATS = { - 'gztar': (['.tar.gz', '.tgz'], _unpack_tarfile, [], "gzip'ed tar-file"), - 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"), - 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file") - } # type: Dict[str, Tuple[List[str], Any, Sequence[Tuple[str, Any]], str]] - -if _BZ2_SUPPORTED: - _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [], - "bzip2'ed tar-file") - -def _find_unpack_format(filename: str) -> str: - for name, info in _UNPACK_FORMATS.items(): - for extension in info[0]: - if filename.endswith(extension): - return name - return None - -def unpack_archive(filename: str, extract_dir: str = None, - format: str = None) -> None: - """Unpack an archive. - - `filename` is the name of the archive. - - `extract_dir` is the name of the target directory, where the archive - is unpacked. If not provided, the current working directory is used. - - `format` is the archive format: one of "zip", "tar", or "gztar". Or any - other registered format. If not provided, unpack_archive will use the - filename extension and see if an unpacker was registered for that - extension. - - In case none is found, a ValueError is raised. - """ - if extract_dir is None: - extract_dir = os.getcwd() - - if format is not None: - try: - format_info = _UNPACK_FORMATS[format] - except KeyError: - raise ValueError("Unknown unpack format '{0}'".format(format)) - - func = format_info[1] - func(filename, extract_dir, **dict(format_info[2])) - else: - # we need to look at the registered unpackers supported extensions - format = _find_unpack_format(filename) - if format is None: - raise ReadError("Unknown archive format '{0}'".format(filename)) - - func = _UNPACK_FORMATS[format][1] - kwargs = dict(_UNPACK_FORMATS[format][2]) - func(filename, extract_dir, **kwargs) diff --git a/test-data/stdlib-samples/3.2/tempfile.py b/test-data/stdlib-samples/3.2/tempfile.py deleted file mode 100644 index fa4059276fcb..000000000000 --- a/test-data/stdlib-samples/3.2/tempfile.py +++ /dev/null @@ -1,724 +0,0 @@ -"""Temporary files. - -This module provides generic, low- and high-level interfaces for -creating temporary files and directories. The interfaces listed -as "safe" just below can be used without fear of race conditions. -Those listed as "unsafe" cannot, and are provided for backward -compatibility only. - -This module also provides some data items to the user: - - TMP_MAX - maximum number of names that will be tried before - giving up. - template - the default prefix for all temporary names. - You may change this to control the default prefix. - tempdir - If this is set to a string before the first use of - any routine from this module, it will be considered as - another candidate location to store temporary files. -""" - -__all__ = [ - "NamedTemporaryFile", "TemporaryFile", # high level safe interfaces - "SpooledTemporaryFile", "TemporaryDirectory", - "mkstemp", "mkdtemp", # low level safe interfaces - "mktemp", # deprecated unsafe interface - "TMP_MAX", "gettempprefix", # constants - "tempdir", "gettempdir" - ] - - -# Imports. - -import warnings as _warnings -import sys as _sys -import io as _io -import os as _os -import errno as _errno -from random import Random as _Random - -from typing import ( - Any as _Any, Callable as _Callable, Iterator as _Iterator, - List as _List, Tuple as _Tuple, Dict as _Dict, Iterable as _Iterable, - IO as _IO, cast as _cast, Optional as _Optional, Type as _Type, -) -from typing_extensions import Literal -from types import TracebackType as _TracebackType - -try: - import fcntl as _fcntl -except ImportError: - def _set_cloexec(fd: int) -> None: - pass -else: - def _set_cloexec(fd: int) -> None: - try: - flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0) - except IOError: - pass - else: - # flags read successfully, modify - flags |= _fcntl.FD_CLOEXEC - _fcntl.fcntl(fd, _fcntl.F_SETFD, flags) - - -try: - import _thread - _allocate_lock = _thread.allocate_lock # type: _Callable[[], _Any] -except ImportError: - import _dummy_thread - _allocate_lock = _dummy_thread.allocate_lock - -_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL -if hasattr(_os, 'O_NOINHERIT'): - _text_openflags |= _os.O_NOINHERIT -if hasattr(_os, 'O_NOFOLLOW'): - _text_openflags |= _os.O_NOFOLLOW - -_bin_openflags = _text_openflags -if hasattr(_os, 'O_BINARY'): - _bin_openflags |= _os.O_BINARY - -if hasattr(_os, 'TMP_MAX'): - TMP_MAX = _os.TMP_MAX -else: - TMP_MAX = 10000 - -template = "tmp" - -# Internal routines. - -_once_lock = _allocate_lock() - -if hasattr(_os, "lstat"): - _stat = _os.lstat # type: _Callable[[str], object] -elif hasattr(_os, "stat"): - _stat = _os.stat -else: - # Fallback. All we need is something that raises os.error if the - # file doesn't exist. - def __stat(fn: str) -> object: - try: - f = open(fn) - except IOError: - raise _os.error() - f.close() - return None - _stat = __stat - -def _exists(fn: str) -> bool: - try: - _stat(fn) - except _os.error: - return False - else: - return True - -class _RandomNameSequence(_Iterator[str]): - """An instance of _RandomNameSequence generates an endless - sequence of unpredictable strings which can safely be incorporated - into file names. Each string is six characters long. Multiple - threads can safely use the same instance at the same time. - - _RandomNameSequence is an iterator.""" - - characters = "abcdefghijklmnopqrstuvwxyz0123456789_" - - @property - def rng(self) -> _Random: - cur_pid = _os.getpid() - if cur_pid != getattr(self, '_rng_pid', None): - self._rng = _Random() - self._rng_pid = cur_pid - return self._rng - - def __iter__(self) -> _Iterator[str]: - return self - - def __next__(self) -> str: - c = self.characters - choose = self.rng.choice - letters = [choose(c) for dummy in "123456"] - return ''.join(letters) - -def _candidate_tempdir_list() -> _List[str]: - """Generate a list of candidate temporary directories which - _get_default_tempdir will try.""" - - dirlist = [] # type: _List[str] - - # First, try the environment. - for envname in 'TMPDIR', 'TEMP', 'TMP': - dirname = _os.getenv(envname) - if dirname: dirlist.append(dirname) - - # Failing that, try OS-specific locations. - if _os.name == 'nt': - dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ]) - else: - dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ]) - - # As a last resort, the current directory. - try: - dirlist.append(_os.getcwd()) - except (AttributeError, _os.error): - dirlist.append(_os.curdir) - - return dirlist - -def _get_default_tempdir() -> str: - """Calculate the default directory to use for temporary files. - This routine should be called exactly once. - - We determine whether or not a candidate temp dir is usable by - trying to create and write to a file in that directory. If this - is successful, the test file is deleted. To prevent denial of - service, the name of the test file must be randomized.""" - - namer = _RandomNameSequence() - dirlist = _candidate_tempdir_list() - - for dir in dirlist: - if dir != _os.curdir: - dir = _os.path.normcase(_os.path.abspath(dir)) - # Try only a few names per directory. - for seq in range(100): - name = next(namer) - filename = _os.path.join(dir, name) - try: - fd = _os.open(filename, _bin_openflags, 0o600) - fp = _io.open(fd, 'wb') - fp.write(b'blat') - fp.close() - _os.unlink(filename) - fp = fd = None - return dir - except (OSError, IOError) as e: - if e.args[0] != _errno.EEXIST: - break # no point trying more names in this directory - pass - raise IOError(_errno.ENOENT, - "No usable temporary directory found in %s" % dirlist) - -_name_sequence = None # type: _RandomNameSequence - -def _get_candidate_names() -> _RandomNameSequence: - """Common setup sequence for all user-callable interfaces.""" - - global _name_sequence - if _name_sequence is None: - _once_lock.acquire() - try: - if _name_sequence is None: - _name_sequence = _RandomNameSequence() - finally: - _once_lock.release() - return _name_sequence - - -def _mkstemp_inner(dir: str, pre: str, suf: str, - flags: int) -> _Tuple[int, str]: - """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile.""" - - names = _get_candidate_names() - - for seq in range(TMP_MAX): - name = next(names) - file = _os.path.join(dir, pre + name + suf) - try: - fd = _os.open(file, flags, 0o600) - _set_cloexec(fd) - return (fd, _os.path.abspath(file)) - except OSError as e: - if e.errno == _errno.EEXIST: - continue # try again - raise - - raise IOError(_errno.EEXIST, "No usable temporary file name found") - - -# User visible interfaces. - -def gettempprefix() -> str: - """Accessor for tempdir.template.""" - return template - -tempdir = None # type: str - -def gettempdir() -> str: - """Accessor for tempfile.tempdir.""" - global tempdir - if tempdir is None: - _once_lock.acquire() - try: - if tempdir is None: - tempdir = _get_default_tempdir() - finally: - _once_lock.release() - return tempdir - -def mkstemp(suffix: str = "", prefix: str = template, dir: str = None, - text: bool = False) -> _Tuple[int, str]: - """User-callable function to create and return a unique temporary - file. The return value is a pair (fd, name) where fd is the - file descriptor returned by os.open, and name is the filename. - - If 'suffix' is specified, the file name will end with that suffix, - otherwise there will be no suffix. - - If 'prefix' is specified, the file name will begin with that prefix, - otherwise a default prefix is used. - - If 'dir' is specified, the file will be created in that directory, - otherwise a default directory is used. - - If 'text' is specified and true, the file is opened in text - mode. Else (the default) the file is opened in binary mode. On - some operating systems, this makes no difference. - - The file is readable and writable only by the creating user ID. - If the operating system uses permission bits to indicate whether a - file is executable, the file is executable by no one. The file - descriptor is not inherited by children of this process. - - Caller is responsible for deleting the file when done with it. - """ - - if dir is None: - dir = gettempdir() - - if text: - flags = _text_openflags - else: - flags = _bin_openflags - - return _mkstemp_inner(dir, prefix, suffix, flags) - - -def mkdtemp(suffix: str = "", prefix: str = template, dir: str = None) -> str: - """User-callable function to create and return a unique temporary - directory. The return value is the pathname of the directory. - - Arguments are as for mkstemp, except that the 'text' argument is - not accepted. - - The directory is readable, writable, and searchable only by the - creating user. - - Caller is responsible for deleting the directory when done with it. - """ - - if dir is None: - dir = gettempdir() - - names = _get_candidate_names() - - for seq in range(TMP_MAX): - name = next(names) - file = _os.path.join(dir, prefix + name + suffix) - try: - _os.mkdir(file, 0o700) - return file - except OSError as e: - if e.errno == _errno.EEXIST: - continue # try again - raise - - raise IOError(_errno.EEXIST, "No usable temporary directory name found") - -def mktemp(suffix: str = "", prefix: str = template, dir: str = None) -> str: - """User-callable function to return a unique temporary file name. The - file is not created. - - Arguments are as for mkstemp, except that the 'text' argument is - not accepted. - - This function is unsafe and should not be used. The file name - refers to a file that did not exist at some point, but by the time - you get around to creating it, someone else may have beaten you to - the punch. - """ - -## from warnings import warn as _warn -## _warn("mktemp is a potential security risk to your program", -## RuntimeWarning, stacklevel=2) - - if dir is None: - dir = gettempdir() - - names = _get_candidate_names() - for seq in range(TMP_MAX): - name = next(names) - file = _os.path.join(dir, prefix + name + suffix) - if not _exists(file): - return file - - raise IOError(_errno.EEXIST, "No usable temporary filename found") - - -class _TemporaryFileWrapper: - """Temporary file wrapper - - This class provides a wrapper around files opened for - temporary use. In particular, it seeks to automatically - remove the file when it is no longer needed. - """ - - def __init__(self, file: _IO[_Any], name: str, - delete: bool = True) -> None: - self.file = file - self.name = name - self.close_called = False - self.delete = delete - - if _os.name != 'nt': - # Cache the unlinker so we don't get spurious errors at - # shutdown when the module-level "os" is None'd out. Note - # that this must be referenced as self.unlink, because the - # name TemporaryFileWrapper may also get None'd out before - # __del__ is called. - self.unlink = _os.unlink - - def __getattr__(self, name: str) -> _Any: - # Attribute lookups are delegated to the underlying file - # and cached for non-numeric results - # (i.e. methods are cached, closed and friends are not) - file = _cast(_Any, self).__dict__['file'] # type: _IO[_Any] - a = getattr(file, name) - if not isinstance(a, int): - setattr(self, name, a) - return a - - # The underlying __enter__ method returns the wrong object - # (self.file) so override it to return the wrapper - def __enter__(self) -> '_TemporaryFileWrapper': - self.file.__enter__() - return self - - # iter() doesn't use __getattr__ to find the __iter__ method - def __iter__(self) -> _Iterator[_Any]: - return iter(self.file) - - # NT provides delete-on-close as a primitive, so we don't need - # the wrapper to do anything special. We still use it so that - # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile. - if _os.name != 'nt': - def close(self) -> None: - if not self.close_called: - self.close_called = True - self.file.close() - if self.delete: - self.unlink(self.name) - - def __del__(self) -> None: - self.close() - - # Need to trap __exit__ as well to ensure the file gets - # deleted when used in a with statement - def __exit__(self, exc: _Type[BaseException], value: BaseException, - tb: _Optional[_TracebackType]) -> bool: - result = self.file.__exit__(exc, value, tb) - self.close() - return result - else: - def __exit__(self, # type: ignore[misc] - exc: _Type[BaseException], - value: BaseException, - tb: _Optional[_TracebackType]) -> Literal[False]: - self.file.__exit__(exc, value, tb) - return False - - -def NamedTemporaryFile(mode: str = 'w+b', buffering: int = -1, - encoding: str = None, newline: str = None, - suffix: str = "", prefix: str = template, - dir: str = None, delete: bool = True) -> _IO[_Any]: - """Create and return a temporary file. - Arguments: - 'prefix', 'suffix', 'dir' -- as for mkstemp. - 'mode' -- the mode argument to io.open (default "w+b"). - 'buffering' -- the buffer size argument to io.open (default -1). - 'encoding' -- the encoding argument to io.open (default None) - 'newline' -- the newline argument to io.open (default None) - 'delete' -- whether the file is deleted on close (default True). - The file is created as mkstemp() would do it. - - Returns an object with a file-like interface; the name of the file - is accessible as file.name. The file will be automatically deleted - when it is closed unless the 'delete' argument is set to False. - """ - - if dir is None: - dir = gettempdir() - - flags = _bin_openflags - - # Setting O_TEMPORARY in the flags causes the OS to delete - # the file when it is closed. This is only supported by Windows. - if _os.name == 'nt' and delete: - flags |= _os.O_TEMPORARY - - (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags) - file = _io.open(fd, mode, buffering=buffering, - newline=newline, encoding=encoding) - - return _cast(_IO[_Any], _TemporaryFileWrapper(file, name, delete)) - -if _os.name != 'posix' or _sys.platform == 'cygwin': - # On non-POSIX and Cygwin systems, assume that we cannot unlink a file - # while it is open. - TemporaryFile = NamedTemporaryFile - -else: - def _TemporaryFile(mode: str = 'w+b', buffering: int = -1, - encoding: str = None, newline: str = None, - suffix: str = "", prefix: str = template, - dir: str = None, delete: bool = True) -> _IO[_Any]: - """Create and return a temporary file. - Arguments: - 'prefix', 'suffix', 'dir' -- as for mkstemp. - 'mode' -- the mode argument to io.open (default "w+b"). - 'buffering' -- the buffer size argument to io.open (default -1). - 'encoding' -- the encoding argument to io.open (default None) - 'newline' -- the newline argument to io.open (default None) - The file is created as mkstemp() would do it. - - Returns an object with a file-like interface. The file has no - name, and will cease to exist when it is closed. - """ - - if dir is None: - dir = gettempdir() - - flags = _bin_openflags - - (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags) - try: - _os.unlink(name) - return _io.open(fd, mode, buffering=buffering, - newline=newline, encoding=encoding) - except: - _os.close(fd) - raise - TemporaryFile = _TemporaryFile - -class SpooledTemporaryFile: - """Temporary file wrapper, specialized to switch from - StringIO to a real file when it exceeds a certain size or - when a fileno is needed. - """ - _rolled = False - _file = None # type: _Any # BytesIO, StringIO or TemporaryFile - - def __init__(self, max_size: int = 0, mode: str = 'w+b', - buffering: int = -1, encoding: str = None, - newline: str = None, suffix: str = "", - prefix: str = template, dir: str = None) -> None: - if 'b' in mode: - self._file = _io.BytesIO() - else: - # Setting newline="\n" avoids newline translation; - # this is important because otherwise on Windows we'd - # hget double newline translation upon rollover(). - self._file = _io.StringIO(newline="\n") - self._max_size = max_size - self._rolled = False - self._TemporaryFileArgs = { - 'mode': mode, 'buffering': buffering, - 'suffix': suffix, 'prefix': prefix, - 'encoding': encoding, 'newline': newline, - 'dir': dir} # type: _Dict[str, _Any] - - def _check(self, file: _IO[_Any]) -> None: - if self._rolled: return - max_size = self._max_size - if max_size and file.tell() > max_size: - self.rollover() - - def rollover(self) -> None: - if self._rolled: return - file = self._file - newfile = self._file = TemporaryFile(**self._TemporaryFileArgs) - self._TemporaryFileArgs = None - - newfile.write(file.getvalue()) - newfile.seek(file.tell(), 0) - - self._rolled = True - - # The method caching trick from NamedTemporaryFile - # won't work here, because _file may change from a - # _StringIO instance to a real file. So we list - # all the methods directly. - - # Context management protocol - def __enter__(self) -> 'SpooledTemporaryFile': - if self._file.closed: - raise ValueError("Cannot enter context with closed file") - return self - - def __exit__(self, exc: type, value: BaseException, - tb: _TracebackType) -> Literal[False]: - self._file.close() - return False - - # file protocol - def __iter__(self) -> _Iterable[_Any]: - return self._file.__iter__() - - def close(self) -> None: - self._file.close() - - @property - def closed(self) -> bool: - return self._file.closed - - @property - def encoding(self) -> str: - return self._file.encoding - - def fileno(self) -> int: - self.rollover() - return self._file.fileno() - - def flush(self) -> None: - self._file.flush() - - def isatty(self) -> bool: - return self._file.isatty() - - @property - def mode(self) -> str: - return self._file.mode - - @property - def name(self) -> str: - return self._file.name - - @property - def newlines(self) -> _Any: - return self._file.newlines - - #def next(self): - # return self._file.next - - def read(self, n: int = -1) -> _Any: - return self._file.read(n) - - def readline(self, limit: int = -1) -> _Any: - return self._file.readline(limit) - - def readlines(self, *args) -> _List[_Any]: - return self._file.readlines(*args) - - def seek(self, offset: int, whence: int = 0) -> None: - self._file.seek(offset, whence) - - @property - def softspace(self) -> bool: - return self._file.softspace - - def tell(self) -> int: - return self._file.tell() - - def truncate(self) -> None: - self._file.truncate() - - def write(self, s: _Any) -> int: - file = self._file # type: _IO[_Any] - rv = file.write(s) - self._check(file) - return rv - - def writelines(self, iterable: _Iterable[_Any]) -> None: - file = self._file # type: _IO[_Any] - file.writelines(iterable) - self._check(file) - - #def xreadlines(self, *args) -> _Any: - # return self._file.xreadlines(*args) - - -class TemporaryDirectory(object): - """Create and return a temporary directory. This has the same - behavior as mkdtemp but can be used as a context manager. For - example: - - with TemporaryDirectory() as tmpdir: - ... - - Upon exiting the context, the directory and everything contained - in it are removed. - """ - - def __init__(self, suffix: str = "", prefix: str = template, - dir: str = None) -> None: - self._closed = False - self.name = None # type: str # Handle mkdtemp throwing an exception - self.name = mkdtemp(suffix, prefix, dir) - - # XXX (ncoghlan): The following code attempts to make - # this class tolerant of the module nulling out process - # that happens during CPython interpreter shutdown - # Alas, it doesn't actually manage it. See issue #10188 - self._listdir = _os.listdir - self._path_join = _os.path.join - self._isdir = _os.path.isdir - self._islink = _os.path.islink - self._remove = _os.remove - self._rmdir = _os.rmdir - self._os_error = _os.error - self._warn = _warnings.warn - - def __repr__(self) -> str: - return "<{} {!r}>".format(self.__class__.__name__, self.name) - - def __enter__(self) -> str: - return self.name - - def cleanup(self, _warn: bool = False) -> None: - if self.name and not self._closed: - try: - self._rmtree(self.name) - except (TypeError, AttributeError) as ex: - # Issue #10188: Emit a warning on stderr - # if the directory could not be cleaned - # up due to missing globals - if "None" not in str(ex): - raise - print("ERROR: {!r} while cleaning up {!r}".format(ex, self,), - file=_sys.stderr) - return - self._closed = True - if _warn: - self._warn("Implicitly cleaning up {!r}".format(self), - ResourceWarning) - - def __exit__(self, exc: type, value: BaseException, - tb: _TracebackType) -> Literal[False]: - self.cleanup() - return False - - def __del__(self) -> None: - # Issue a ResourceWarning if implicit cleanup needed - self.cleanup(_warn=True) - - def _rmtree(self, path: str) -> None: - # Essentially a stripped down version of shutil.rmtree. We can't - # use globals because they may be None'ed out at shutdown. - for name in self._listdir(path): - fullname = self._path_join(path, name) - try: - isdir = self._isdir(fullname) and not self._islink(fullname) - except self._os_error: - isdir = False - if isdir: - self._rmtree(fullname) - else: - try: - self._remove(fullname) - except self._os_error: - pass - try: - self._rmdir(path) - except self._os_error: - pass diff --git a/test-data/stdlib-samples/3.2/test/__init__.py b/test-data/stdlib-samples/3.2/test/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/test-data/stdlib-samples/3.2/test/mypy.ini b/test-data/stdlib-samples/3.2/test/mypy.ini deleted file mode 100644 index 90a0e394b258..000000000000 --- a/test-data/stdlib-samples/3.2/test/mypy.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mypy] -mypy_path = .. diff --git a/test-data/stdlib-samples/3.2/test/randv2_32.pck b/test-data/stdlib-samples/3.2/test/randv2_32.pck deleted file mode 100644 index 587ab241091e..000000000000 --- a/test-data/stdlib-samples/3.2/test/randv2_32.pck +++ /dev/null @@ -1,633 +0,0 @@ -crandom -Random -p0 -(tRp1 -(I2 -(I-2147483648 -I-845974985 -I-1294090086 -I1193659239 -I-1849481736 -I-946579732 -I-34406770 -I1749049471 -I1997774682 -I1432026457 -I1288127073 -I-943175655 -I-1718073964 -I339993548 -I-1045260575 -I582505037 -I-1555108250 -I-1114765620 -I1578648750 -I-350384412 -I-20845848 -I-288255314 -I738790953 -I1901249641 -I1999324672 -I-277361068 -I-1515885839 -I2061761596 -I-809068089 -I1287981136 -I258129492 -I-6303745 -I-765148337 -I1090344911 -I1653434703 -I-1242923628 -I1639171313 -I-1870042660 -I-1655014050 -I345609048 -I2093410138 -I1963263374 -I-2122098342 -I1336859961 -I-810942729 -I945857753 -I2103049942 -I623922684 -I1418349549 -I690877342 -I754973107 -I-1605111847 -I1607137813 -I-1704917131 -I1317536428 -I1714882872 -I-1665385120 -I1823694397 -I-1790836866 -I-1696724812 -I-603979847 -I-498599394 -I-341265291 -I927388804 -I1778562135 -I1716895781 -I1023198122 -I1726145967 -I941955525 -I1240148950 -I-1929634545 -I-1288147083 -I-519318335 -I754559777 -I-707571958 -I374604022 -I420424061 -I-1095443486 -I1621934944 -I-1220502522 -I-140049608 -I-918917122 -I304341024 -I-1637446057 -I-353934485 -I1973436235 -I433380241 -I-686759465 -I-2111563154 -I-573422032 -I804304541 -I1513063483 -I1417381689 -I-804778729 -I211756408 -I544537322 -I890881641 -I150378374 -I1765739392 -I1011604116 -I584889095 -I1400520554 -I413747808 -I-1741992587 -I-1882421574 -I-1373001903 -I-1885348538 -I903819480 -I1083220038 -I-1318105424 -I1740421404 -I1693089625 -I775965557 -I1319608037 -I-2127475785 -I-367562895 -I-1416273451 -I1693000327 -I-1217438421 -I834405522 -I-128287275 -I864057548 -I-973917356 -I7304111 -I1712253182 -I1353897741 -I672982288 -I1778575559 -I-403058377 -I-38540378 -I-1393713496 -I13193171 -I1127196200 -I205176472 -I-2104790506 -I299985416 -I1403541685 -I-1018270667 -I-1980677490 -I-1182625797 -I1637015181 -I-1795357414 -I1514413405 -I-924516237 -I-1841873650 -I-1014591269 -I1576616065 -I-1319103135 -I-120847840 -I2062259778 -I-9285070 -I1160890300 -I-575137313 -I-1509108275 -I46701926 -I-287560914 -I-256824960 -I577558250 -I900598310 -I944607867 -I2121154920 -I-1170505192 -I-1347170575 -I77247778 -I-1899015765 -I1234103327 -I1027053658 -I1934632322 -I-792031234 -I1147322536 -I1290655117 -I1002059715 -I1325898538 -I896029793 -I-790940694 -I-980470721 -I-1922648255 -I-951672814 -I291543943 -I1158740218 -I-1959023736 -I-1977185236 -I1527900076 -I514104195 -I-814154113 -I-593157883 -I-1023704660 -I1285688377 -I-2117525386 -I768954360 -I-38676846 -I-799848659 -I-1305517259 -I-1938213641 -I-462146758 -I-1663302892 -I1899591069 -I-22935388 -I-275856976 -I-443736893 -I-739441156 -I93862068 -I-838105669 -I1735629845 -I-817484206 -I280814555 -I1753547179 -I1811123479 -I1974543632 -I-48447465 -I-642694345 -I-531149613 -I518698953 -I-221642627 -I-686519187 -I776644303 -I257774400 -I-1499134857 -I-1055273455 -I-237023943 -I1981752330 -I-917671662 -I-372905983 -I1588058420 -I1171936660 -I-1730977121 -I1360028989 -I1769469287 -I1910709542 -I-852692959 -I1396944667 -I-1723999155 -I-310975435 -I-1965453954 -I-1636858570 -I2005650794 -I680293715 -I1355629386 -I844514684 -I-1909152807 -I-808646074 -I1936510018 -I1134413810 -I-143411047 -I-1478436304 -I1394969244 -I-1170110660 -I1963112086 -I-1518351049 -I-1506287443 -I-455023090 -I-855366028 -I-1746785568 -I933990882 -I-703625141 -I-285036872 -I188277905 -I1471578620 -I-981382835 -I-586974220 -I945619758 -I1608778444 -I-1708548066 -I-1897629320 -I-42617810 -I-836840790 -I539154487 -I-235706962 -I332074418 -I-575700589 -I1534608003 -I632116560 -I-1819760653 -I642052958 -I-722391771 -I-1104719475 -I-1196847084 -I582413973 -I1563394876 -I642007944 -I108989456 -I361625014 -I677308625 -I-1806529496 -I-959050708 -I-1858251070 -I-216069832 -I701624579 -I501238033 -I12287030 -I1895107107 -I2089098638 -I-874806230 -I1236279203 -I563718890 -I-544352489 -I-1879707498 -I1767583393 -I-1776604656 -I-693294301 -I-88882831 -I169303357 -I1299196152 -I-1122791089 -I-379157172 -I1934671851 -I1575736961 -I-19573174 -I-1401511009 -I9305167 -I-1115174467 -I1670735537 -I1226436501 -I-2004524535 -I1767463878 -I-1722855079 -I-559413926 -I1529810851 -I1201272087 -I-1297130971 -I-1188149982 -I1396557188 -I-370358342 -I-1006619702 -I1600942463 -I906087130 -I-76991909 -I2069580179 -I-1674195181 -I-2098404729 -I-940972459 -I-573399187 -I-1930386277 -I-721311199 -I-647834744 -I1452181671 -I688681916 -I1812793731 -I1704380620 -I-1389615179 -I866287837 -I-1435265007 -I388400782 -I-147986600 -I-1613598851 -I-1040347408 -I782063323 -I-239282031 -I-575966722 -I-1865208174 -I-481365146 -I579572803 -I-1239481494 -I335361280 -I-429722947 -I1881772789 -I1908103808 -I1653690013 -I-1668588344 -I1933787953 -I-2033480609 -I22162797 -I-1516527040 -I-461232482 -I-16201372 -I-2043092030 -I114990337 -I-1524090084 -I1456374020 -I458606440 -I-1928083218 -I227773125 -I-1129028159 -I1678689 -I1575896907 -I-1792935220 -I-151387575 -I64084088 -I-95737215 -I1337335688 -I-1963466345 -I1243315130 -I-1798518411 -I-546013212 -I-607065396 -I1219824160 -I1715218469 -I-1368163783 -I1701552913 -I-381114888 -I1068821717 -I266062971 -I-2066513172 -I1767407229 -I-780936414 -I-705413443 -I-1256268847 -I1646874149 -I1107690353 -I839133072 -I67001749 -I860763503 -I884880613 -I91977084 -I755371933 -I420745153 -I-578480690 -I-1520193551 -I1011369331 -I-99754575 -I-733141064 -I-500598588 -I1081124271 -I-1341266575 -I921002612 -I-848852487 -I-1904467341 -I-1294256973 -I-94074714 -I-1778758498 -I-1401188547 -I2101830578 -I2058864877 -I-272875991 -I-1375854779 -I-1332937870 -I619425525 -I-1034529639 -I-36454393 -I-2030499985 -I-1637127500 -I-1408110287 -I-2108625749 -I-961007436 -I1475654951 -I-791946251 -I1667792115 -I1818978830 -I1897980514 -I1959546477 -I-74478911 -I-508643347 -I461594399 -I538802715 -I-2094970071 -I-2076660253 -I1091358944 -I1944029246 -I-343957436 -I-1915845022 -I1237620188 -I1144125174 -I1522190520 -I-670252952 -I-19469226 -I675626510 -I758750096 -I909724354 -I-1846259652 -I544669343 -I445182495 -I-821519930 -I-1124279685 -I-1668995122 -I1653284793 -I-678555151 -I-687513207 -I1558259445 -I-1978866839 -I1558835601 -I1732138472 -I-1904793363 -I620020296 -I1562597874 -I1942617227 -I-549632552 -I721603795 -I417978456 -I-1355281522 -I-538065208 -I-1079523196 -I187375699 -I449064972 -I1018083947 -I1632388882 -I-493269866 -I92769041 -I1477146750 -I1782708404 -I444873376 -I1085851104 -I-6823272 -I-1302251853 -I1602050688 -I-1042187824 -I287161745 -I-1972094479 -I103271491 -I2131619773 -I-2064115870 -I766815498 -I990861458 -I-1664407378 -I1083746756 -I-1018331904 -I-677315687 -I-951670647 -I-952356874 -I451460609 -I-818615564 -I851439508 -I656362634 -I-1351240485 -I823378078 -I1985597385 -I597757740 -I-1512303057 -I1590872798 -I1108424213 -I818850898 -I-1368594306 -I-201107761 -I1793370378 -I1247597611 -I-1594326264 -I-601653890 -I427642759 -I248322113 -I-292545338 -I1708985870 -I1917042771 -I429354503 -I-478470329 -I793960014 -I369939133 -I1728189157 -I-518963626 -I-278523974 -I-1877289696 -I-2088617658 -I-1367940049 -I-62295925 -I197975119 -I-252900777 -I803430539 -I485759441 -I-528283480 -I-1287443963 -I-478617444 -I-861906946 -I-649095555 -I-893184337 -I2050571322 -I803433133 -I1629574571 -I1649720417 -I-2050225209 -I1208598977 -I720314344 -I-615166251 -I-835077127 -I-1405372429 -I995698064 -I148123240 -I-943016676 -I-594609622 -I-1381596711 -I1017195301 -I-1268893013 -I-1815985179 -I-1393570351 -I-870027364 -I-476064472 -I185582645 -I569863326 -I1098584267 -I-1599147006 -I-485054391 -I-852098365 -I1477320135 -I222316762 -I-1515583064 -I-935051367 -I393383063 -I819617226 -I722921837 -I-1241806499 -I-1358566385 -I1666813591 -I1333875114 -I-1663688317 -I-47254623 -I-885800726 -I307388991 -I-1219459496 -I1374870300 -I2132047877 -I-1385624198 -I-245139206 -I1015139214 -I-926198559 -I1969798868 -I-1950480619 -I-559193432 -I-1256446518 -I-1983476981 -I790179655 -I1004289659 -I1541827617 -I1555805575 -I501127333 -I-1123446797 -I-453230915 -I2035104883 -I1296122398 -I-1843698604 -I-715464588 -I337143971 -I-1972119192 -I606777909 -I726977302 -I-1149501872 -I-1963733522 -I-1797504644 -I624 -tp2 -Ntp3 -b. \ No newline at end of file diff --git a/test-data/stdlib-samples/3.2/test/randv2_64.pck b/test-data/stdlib-samples/3.2/test/randv2_64.pck deleted file mode 100644 index 090dd6fd1968..000000000000 --- a/test-data/stdlib-samples/3.2/test/randv2_64.pck +++ /dev/null @@ -1,633 +0,0 @@ -crandom -Random -p0 -(tRp1 -(I2 -(I2147483648 -I1812115682 -I2741755497 -I1028055730 -I809166036 -I2773628650 -I62321950 -I535290043 -I349877800 -I976167039 -I2490696940 -I3631326955 -I2107991114 -I2941205793 -I3199611605 -I1871971556 -I1456108540 -I2984591044 -I140836801 -I4203227310 -I3652722980 -I4031971234 -I555769760 -I697301296 -I2347638880 -I3302335858 -I320255162 -I2553586608 -I1570224361 -I2838780912 -I2315834918 -I2351348158 -I3545433015 -I2292018579 -I1177569331 -I758497559 -I2913311175 -I1014948880 -I1793619243 -I3982451053 -I3850988342 -I2393984324 -I1583100093 -I3144742543 -I3655047493 -I3507532385 -I3094515442 -I350042434 -I2455294844 -I1038739312 -I313809152 -I189433072 -I1653165452 -I4186650593 -I19281455 -I2589680619 -I4145931590 -I4283266118 -I636283172 -I943618337 -I3170184633 -I2308766231 -I634615159 -I538152647 -I2079576891 -I1029442616 -I3410689412 -I1370292761 -I1071718978 -I2139496322 -I1876699543 -I3485866187 -I3157490130 -I1633105386 -I1453253160 -I3841322080 -I3789608924 -I4110770792 -I95083673 -I931354627 -I2065389591 -I3448339827 -I3348204577 -I3263528560 -I2411324590 -I4003055026 -I1869670093 -I2737231843 -I4150701155 -I2689667621 -I2993263224 -I3239890140 -I1191430483 -I1214399779 -I3623428533 -I1817058866 -I3052274451 -I326030082 -I1505129312 -I2306812262 -I1349150363 -I1099127895 -I2543465574 -I2396380193 -I503926466 -I1607109730 -I3451716817 -I58037114 -I4290081119 -I947517597 -I3083440186 -I520522630 -I2948962496 -I4184319574 -I2957636335 -I668374201 -I2325446473 -I472785314 -I3791932366 -I573017189 -I2185725379 -I1262251492 -I3525089379 -I2951262653 -I1305347305 -I940958122 -I3343754566 -I359371744 -I3874044973 -I396897232 -I147188248 -I716683703 -I4013880315 -I1133359586 -I1794612249 -I3480815192 -I3988787804 -I1729355809 -I573408542 -I1419310934 -I1770030447 -I3552845567 -I1693976502 -I1271189893 -I2298236738 -I2049219027 -I3464198070 -I1233574082 -I1007451781 -I1838253750 -I687096593 -I1131375603 -I1223013895 -I1490478435 -I339265439 -I4232792659 -I491538536 -I2816256769 -I1044097522 -I2566227049 -I748762793 -I1511830494 -I3593259822 -I4121279213 -I3735541309 -I3609794797 -I1939942331 -I377570434 -I1437957554 -I1831285696 -I55062811 -I2046783110 -I1303902283 -I1838349877 -I420993556 -I1256392560 -I2795216506 -I2783687924 -I3322303169 -I512794749 -I308405826 -I517164429 -I3320436022 -I1328403632 -I2269184746 -I3729522810 -I3304314450 -I2238756124 -I1690581361 -I3813277532 -I4119706879 -I2659447875 -I388818978 -I2064580814 -I1586227676 -I2627522685 -I2017792269 -I547928109 -I859107450 -I1062238929 -I858886237 -I3795783146 -I4173914756 -I3835915965 -I3329504821 -I3494579904 -I838863205 -I3399734724 -I4247387481 -I3618414834 -I2984433798 -I2165205561 -I4260685684 -I3045904244 -I3450093836 -I3597307595 -I3215851166 -I3162801328 -I2558283799 -I950068105 -I1829664117 -I3108542987 -I2378860527 -I790023460 -I280087750 -I1171478018 -I2333653728 -I3976932140 -I896746152 -I1802494195 -I1232873794 -I2749440836 -I2032037296 -I2012091682 -I1296131034 -I3892133385 -I908161334 -I2296791795 -I548169794 -I696265 -I893156828 -I426904709 -I3565374535 -I2655906825 -I2792178515 -I2406814632 -I4038847579 -I3123934642 -I2197503004 -I3535032597 -I2266216689 -I2117613462 -I1787448518 -I1875089416 -I2037165384 -I1140676321 -I3606296464 -I3229138231 -I2458267132 -I1874651171 -I3331900867 -I1000557654 -I1432861701 -I473636323 -I2691783927 -I1871437447 -I1328016401 -I4118690062 -I449467602 -I681789035 -I864889442 -I1200888928 -I75769445 -I4008690037 -I2464577667 -I4167795823 -I3070097648 -I2579174882 -I1216886568 -I3810116343 -I2249507485 -I3266903480 -I3671233480 -I100191658 -I3087121334 -I365063087 -I3821275176 -I2165052848 -I1282465245 -I3601570637 -I3132413236 -I2780570459 -I3222142917 -I3129794692 -I2611590811 -I947031677 -I2991908938 -I750997949 -I3632575131 -I1632014461 -I2846484755 -I2347261779 -I2903959448 -I1397316686 -I1904578392 -I774649578 -I3164598558 -I2429587609 -I738244516 -I1563304975 -I1399317414 -I1021316297 -I3187933234 -I2126780757 -I4011907847 -I4095169219 -I3358010054 -I2729978247 -I3736811646 -I3009656410 -I2893043637 -I4027447385 -I1239610110 -I1488806900 -I2674866844 -I442876374 -I2853687260 -I2785921005 -I3151378528 -I1180567 -I2803146964 -I982221759 -I2192919417 -I3087026181 -I2480838002 -I738452921 -I687986185 -I3049371676 -I3636492954 -I3468311299 -I2379621102 -I788988633 -I1643210601 -I2983998168 -I2492730801 -I2586048705 -I604073029 -I4121082815 -I1496476928 -I2972357110 -I2663116968 -I2642628592 -I2116052039 -I487186279 -I2577680328 -I3974766614 -I730776636 -I3842528855 -I1929093695 -I44626622 -I3989908833 -I1695426222 -I3675479382 -I3051784964 -I1514876613 -I1254036595 -I2420450649 -I3034377361 -I2332990590 -I1535175126 -I185834384 -I1107372900 -I1707278185 -I1286285295 -I3332574225 -I2785672437 -I883170645 -I2005666473 -I3403131327 -I4122021352 -I1464032858 -I3702576112 -I260554598 -I1837731650 -I2594435345 -I75771049 -I2012484289 -I3058649775 -I29979703 -I3861335335 -I2506495152 -I3786448704 -I442947790 -I2582724774 -I4291336243 -I2568189843 -I1923072690 -I1121589611 -I837696302 -I3284631720 -I3865021324 -I3576453165 -I2559531629 -I1459231762 -I3506550036 -I3754420159 -I2622000757 -I124228596 -I1084328605 -I1692830753 -I547273558 -I674282621 -I655259103 -I3188629610 -I490502174 -I2081001293 -I3191330704 -I4109943593 -I1859948504 -I3163806460 -I508833168 -I1256371033 -I2709253790 -I2068956572 -I3092842814 -I3913926529 -I2039638759 -I981982529 -I536094190 -I368855295 -I51993975 -I1597480732 -I4058175522 -I2155896702 -I3196251991 -I1081913893 -I3952353788 -I3545548108 -I2370669647 -I2206572308 -I2576392991 -I1732303374 -I1153136290 -I537641955 -I1738691747 -I3232854186 -I2539632206 -I2829760278 -I3058187853 -I1202425792 -I3762361970 -I2863949342 -I2640635867 -I376638744 -I1857679757 -I330798087 -I1457400505 -I1135610046 -I606400715 -I1859536026 -I509811335 -I529772308 -I2579273244 -I1890382004 -I3959908876 -I2612335971 -I2834052227 -I1434475986 -I3684202717 -I4015011345 -I582567852 -I3689969571 -I3934753460 -I3034960691 -I208573292 -I4004113742 -I3992904842 -I2587153719 -I3529179079 -I1565424987 -I779130678 -I1048582935 -I3213591622 -I3607793434 -I3951254937 -I2047811901 -I7508850 -I248544605 -I4210090324 -I2331490884 -I70057213 -I776474945 -I1345528889 -I3290403612 -I1664955269 -I1533143116 -I545003424 -I4141564478 -I1257326139 -I868843601 -I2337603029 -I1918131449 -I1843439523 -I1125519035 -I673340118 -I421408852 -I1520454906 -I1804722630 -I3621254196 -I2329968000 -I39464672 -I430583134 -I294026512 -I53978525 -I2892276105 -I1418863764 -I3419054451 -I1391595797 -I3544981798 -I4191780858 -I825672357 -I2972000844 -I1571305069 -I4231982845 -I3611916419 -I3045163168 -I2982349733 -I278572141 -I4215338078 -I839860504 -I1819151779 -I1412347479 -I1386770353 -I3914589491 -I3783104977 -I4124296733 -I830546258 -I89825624 -I4110601328 -I2545483429 -I300600527 -I516641158 -I3693021034 -I2852912854 -I3240039868 -I4167407959 -I1479557946 -I3621188804 -I1391590944 -I3578441128 -I1227055556 -I406898396 -I3064054983 -I25835338 -I402664165 -I4097682779 -I2106728012 -I203613622 -I3045467686 -I1381726438 -I3798670110 -I1342314961 -I3552497361 -I535913619 -I2625787583 -I1606574307 -I1101269630 -I1950513752 -I1121355862 -I3586816903 -I438529984 -I2473182121 -I1229997203 -I405445940 -I1695535315 -I427014336 -I3916768430 -I392298359 -I1884642868 -I1244730821 -I741058080 -I567479957 -I3527621168 -I3191971011 -I3267069104 -I4108668146 -I1520795587 -I166581006 -I473794477 -I1562126550 -I929843010 -I889533294 -I1266556608 -I874518650 -I3520162092 -I3013765049 -I4220231414 -I547246449 -I3998093769 -I3737193746 -I3872944207 -I793651876 -I2606384318 -I875991012 -I1394836334 -I4102011644 -I854380426 -I2618666767 -I2568302000 -I1995512132 -I229491093 -I2673500286 -I3364550739 -I3836923416 -I243656987 -I3944388983 -I4064949677 -I1416956378 -I1703244487 -I3990798829 -I2023425781 -I3926702214 -I1229015501 -I3174247824 -I624 -tp2 -Ntp3 -b. \ No newline at end of file diff --git a/test-data/stdlib-samples/3.2/test/randv3.pck b/test-data/stdlib-samples/3.2/test/randv3.pck deleted file mode 100644 index 09fc38b1a876..000000000000 --- a/test-data/stdlib-samples/3.2/test/randv3.pck +++ /dev/null @@ -1,633 +0,0 @@ -crandom -Random -p0 -(tRp1 -(I3 -(L2147483648L -L994081831L -L2806287265L -L2228999830L -L3396498069L -L2956805457L -L3273927761L -L920726507L -L1862624492L -L2921292485L -L1779526843L -L2469105503L -L251696293L -L1254390717L -L779197080L -L3165356830L -L2007365218L -L1870028812L -L2896519363L -L1855578438L -L979518416L -L3481710246L -L3191861507L -L3993006593L -L2967971479L -L3353342753L -L3576782572L -L339685558L -L2367675732L -L116208555L -L1220054437L -L486597056L -L1912115141L -L1037044792L -L4096904723L -L3409146175L -L3701651227L -L315824610L -L4138604583L -L1385764892L -L191878900L -L2320582219L -L3420677494L -L2776503169L -L1148247403L -L829555069L -L902064012L -L2934642741L -L2477108577L -L2583928217L -L1658612579L -L2865447913L -L129147346L -L3691171887L -L1569328110L -L1372860143L -L1054139183L -L1617707080L -L69020592L -L3810271603L -L1853953416L -L3499803073L -L1027545027L -L3229043605L -L250848720L -L3324932626L -L3537002962L -L2494323345L -L3238103962L -L4147541579L -L3636348186L -L3025455083L -L2678771977L -L584700256L -L3461826909L -L854511420L -L943463552L -L3609239025L -L3977577989L -L253070090L -L777394544L -L2144086567L -L1092947992L -L854327284L -L2222750082L -L360183510L -L1312466483L -L3227531091L -L2235022500L -L3013060530L -L2541091298L -L3480126342L -L1839762775L -L2632608190L -L1108889403L -L3045050923L -L731513126L -L3505436788L -L3062762017L -L1667392680L -L1354126500L -L1143573930L -L2816645702L -L2100356873L -L2817679106L -L1210746010L -L2409915248L -L2910119964L -L2309001420L -L220351824L -L3667352871L -L3993148590L -L2886160232L -L4239393701L -L1189270581L -L3067985541L -L147374573L -L2355164869L -L3696013550L -L4227037846L -L1905112743L -L3312843689L -L2930678266L -L1828795355L -L76933594L -L3987100796L -L1288361435L -L3464529151L -L965498079L -L1444623093L -L1372893415L -L1536235597L -L1341994850L -L963594758L -L2115295754L -L982098685L -L1053433904L -L2078469844L -L3059765792L -L1753606181L -L2130171254L -L567588194L -L529629426L -L3621523534L -L3027576564L -L1176438083L -L4096287858L -L1168574683L -L1425058962L -L1429631655L -L2902106759L -L761900641L -L1329183956L -L1947050932L -L447490289L -L3282516276L -L200037389L -L921868197L -L3331403999L -L4088760249L -L2188326318L -L288401961L -L1360802675L -L314302808L -L3314639210L -L3749821203L -L2286081570L -L2768939062L -L3200541016L -L2133495482L -L385029880L -L4217232202L -L3171617231L -L1660846653L -L2459987621L -L2691776124L -L4225030408L -L3595396773L -L1103680661L -L539064057L -L1492841101L -L166195394L -L757973658L -L533893054L -L2784879594L -L1021821883L -L2350548162L -L176852116L -L3503166025L -L148079914L -L1633466236L -L2773090165L -L1162846701L -L3575737795L -L1624178239L -L2454894710L -L3014691938L -L526355679L -L1870824081L -L3362425857L -L3907566665L -L3462563184L -L2229112004L -L4203735748L -L1557442481L -L924133999L -L1906634214L -L880459727L -L4065895870L -L141426254L -L1258450159L -L3243115027L -L1574958840L -L313939294L -L3055664260L -L3459714255L -L531778790L -L509505506L -L1620227491L -L2675554942L -L2516509560L -L3797299887L -L237135890L -L3203142213L -L1087745310L -L1897151854L -L3936590041L -L132765167L -L2385908063L -L1360600289L -L3574567769L -L2752788114L -L2644228966L -L2377705183L -L601277909L -L4046480498L -L324401408L -L3279931760L -L2227059377L -L1538827493L -L4220532064L -L478044564L -L2917117761L -L635492832L -L2319763261L -L795944206L -L1820473234L -L1673151409L -L1404095402L -L1661067505L -L3217106938L -L2406310683L -L1931309248L -L2458622868L -L3323670524L -L3266852755L -L240083943L -L3168387397L -L607722198L -L1256837690L -L3608124913L -L4244969357L -L1289959293L -L519750328L -L3229482463L -L1105196988L -L1832684479L -L3761037224L -L2363631822L -L3297957711L -L572766355L -L1195822137L -L2239207981L -L2034241203L -L163540514L -L288160255L -L716403680L -L4019439143L -L1536281935L -L2345100458L -L2786059178L -L2822232109L -L987025395L -L3061166559L -L490422513L -L2551030115L -L2638707620L -L1344728502L -L714108911L -L2831719700L -L2188615369L -L373509061L -L1351077504L -L3136217056L -L783521095L -L2554949468L -L2662499550L -L1203826951L -L1379632388L -L1918858985L -L607465976L -L1980450237L -L3540079211L -L3397813410L -L2913309266L -L2289572621L -L4133935327L -L4166227663L -L3371801704L -L3065474909L -L3580562343L -L3832172378L -L2556130719L -L310473705L -L3734014346L -L2490413810L -L347233056L -L526668037L -L1158393656L -L544329703L -L2150085419L -L3914038146L -L1060237586L -L4159394837L -L113205121L -L309966775L -L4098784465L -L3635222960L -L2417516569L -L2089579233L -L1725807541L -L2728122526L -L2365836523L -L2504078522L -L1443946869L -L2384171411L -L997046534L -L3249131657L -L1699875986L -L3618097146L -L1716038224L -L2629818607L -L2929217876L -L1367250314L -L1726434951L -L1388496325L -L2107602181L -L2822366842L -L3052979190L -L3796798633L -L1543813381L -L959000121L -L1363845999L -L2952528150L -L874184932L -L1888387194L -L2328695295L -L3442959855L -L841805947L -L1087739275L -L3230005434L -L3045399265L -L1161817318L -L2898673139L -L860011094L -L940539782L -L1297818080L -L4243941623L -L1577613033L -L4204131887L -L3819057225L -L1969439558L -L3297963932L -L241874069L -L3517033453L -L2295345664L -L1098911422L -L886955008L -L1477397621L -L4279347332L -L3616558791L -L2384411957L -L742537731L -L764221540L -L2871698900L -L3530636393L -L691256644L -L758730966L -L1717773090L -L2751856377L -L3188484000L -L3767469670L -L1623863053L -L3533236793L -L4099284176L -L723921107L -L310594036L -L223978745L -L2266565776L -L201843303L -L2969968546L -L3351170888L -L3465113624L -L2712246712L -L1521383057L -L2384461798L -L216357551L -L2167301975L -L3144653194L -L2781220155L -L3620747666L -L95971265L -L4255400243L -L59999757L -L4174273472L -L3974511524L -L1007123950L -L3112477628L -L806461512L -L3148074008L -L528352882L -L2545979588L -L2562281969L -L3010249477L -L1886331611L -L3210656433L -L1034099976L -L2906893579L -L1197048779L -L1870004401L -L3898300490L -L2686856402L -L3975723478L -L613043532L -L2565674353L -L3760045310L -L3468984376L -L4126258L -L303855424L -L3988963552L -L276256796L -L544071807L -L1023872062L -L1747461519L -L1975571260L -L4033766958L -L2946555557L -L1492957796L -L958271685L -L46480515L -L907760635L -L1306626357L -L819652378L -L1172300279L -L1116851319L -L495601075L -L1157715330L -L534220108L -L377320028L -L1672286106L -L2066219284L -L1842386355L -L2546059464L -L1839457336L -L3476194446L -L3050550028L -L594705582L -L1905813535L -L1813033412L -L2700858157L -L169067972L -L4252889045L -L1921944555L -L497671474L -L210143935L -L2688398489L -L325158375L -L3450846447L -L891760597L -L712802536L -L1132557436L -L1417044075L -L1639889660L -L1746379970L -L1478741647L -L2817563486L -L2573612532L -L4266444457L -L2911601615L -L804745411L -L2207254652L -L1189140646L -L3829725111L -L3637367348L -L1944731747L -L2193440343L -L1430195413L -L1173515229L -L1582618217L -L2070767037L -L247908936L -L1460675439L -L556001596L -L327629335L -L1036133876L -L4228129605L -L999174048L -L3635804039L -L1416550481L -L1270540269L -L4280743815L -L39607659L -L1552540623L -L2762294062L -L504137289L -L4117044239L -L1417130225L -L1342970056L -L1755716449L -L1169447322L -L2731401356L -L2319976745L -L2869221479L -L23972655L -L2251495389L -L1429860878L -L3728135992L -L4241432973L -L3698275076L -L216416432L -L4040046960L -L246077176L -L894675685L -L3932282259L -L3097205100L -L2128818650L -L1319010656L -L1601974009L -L2552960957L -L3554016055L -L4209395641L -L2013340102L -L3370447801L -L2307272002L -L1795091354L -L202109401L -L988345070L -L2514870758L -L1132726850L -L582746224L -L3112305421L -L1843020683L -L3600189223L -L1101349165L -L4211905855L -L2866677581L -L2881621130L -L4165324109L -L4238773191L -L3635649550L -L2670481044L -L2996248219L -L1676992480L -L3473067050L -L4205793699L -L4019490897L -L1579990481L -L1899617990L -L1136347713L -L1802842268L -L3591752960L -L1197308739L -L433629786L -L4032142790L -L3148041979L -L3312138845L -L3896860449L -L3298182567L -L907605170L -L1658664067L -L2682980313L -L2523523173L -L1208722103L -L3808530363L -L1079003946L -L4282402864L -L2041010073L -L2667555071L -L688018180L -L1405121012L -L4167994076L -L3504695336L -L1923944749L -L1143598790L -L3936268898L -L3606243846L -L1017420080L -L4026211169L -L596529763L -L1844259624L -L2840216282L -L2673807759L -L3407202575L -L2737971083L -L4075423068L -L3684057432L -L3146627241L -L599650513L -L69773114L -L1257035919L -L807485291L -L2376230687L -L3036593147L -L2642411658L -L106080044L -L2199622729L -L291834511L -L2697611361L -L11689733L -L625123952L -L3226023062L -L3229663265L -L753059444L -L2843610189L -L624L -tp2 -Ntp3 -b. \ No newline at end of file diff --git a/test-data/stdlib-samples/3.2/test/subprocessdata/fd_status.py b/test-data/stdlib-samples/3.2/test/subprocessdata/fd_status.py deleted file mode 100644 index 1f61e13a3456..000000000000 --- a/test-data/stdlib-samples/3.2/test/subprocessdata/fd_status.py +++ /dev/null @@ -1,24 +0,0 @@ -"""When called as a script, print a comma-separated list of the open -file descriptors on stdout.""" - -import errno -import os - -try: - _MAXFD = os.sysconf("SC_OPEN_MAX") -except: - _MAXFD = 256 - -if __name__ == "__main__": - fds = [] - for fd in range(0, _MAXFD): - try: - st = os.fstat(fd) - except OSError as e: - if e.errno == errno.EBADF: - continue - raise - # Ignore Solaris door files - if st.st_mode & 0xF000 != 0xd000: - fds.append(fd) - print(','.join(map(str, fds))) diff --git a/test-data/stdlib-samples/3.2/test/subprocessdata/input_reader.py b/test-data/stdlib-samples/3.2/test/subprocessdata/input_reader.py deleted file mode 100644 index 1dc3191ad183..000000000000 --- a/test-data/stdlib-samples/3.2/test/subprocessdata/input_reader.py +++ /dev/null @@ -1,7 +0,0 @@ -"""When called as a script, consumes the input""" - -import sys - -if __name__ == "__main__": - for line in sys.stdin: - pass diff --git a/test-data/stdlib-samples/3.2/test/subprocessdata/qcat.py b/test-data/stdlib-samples/3.2/test/subprocessdata/qcat.py deleted file mode 100644 index fe6f9db25c97..000000000000 --- a/test-data/stdlib-samples/3.2/test/subprocessdata/qcat.py +++ /dev/null @@ -1,7 +0,0 @@ -"""When ran as a script, simulates cat with no arguments.""" - -import sys - -if __name__ == "__main__": - for line in sys.stdin: - sys.stdout.write(line) diff --git a/test-data/stdlib-samples/3.2/test/subprocessdata/qgrep.py b/test-data/stdlib-samples/3.2/test/subprocessdata/qgrep.py deleted file mode 100644 index 69906379a9b3..000000000000 --- a/test-data/stdlib-samples/3.2/test/subprocessdata/qgrep.py +++ /dev/null @@ -1,10 +0,0 @@ -"""When called with a single argument, simulated fgrep with a single -argument and no options.""" - -import sys - -if __name__ == "__main__": - pattern = sys.argv[1] - for line in sys.stdin: - if pattern in line: - sys.stdout.write(line) diff --git a/test-data/stdlib-samples/3.2/test/subprocessdata/sigchild_ignore.py b/test-data/stdlib-samples/3.2/test/subprocessdata/sigchild_ignore.py deleted file mode 100644 index 6072aece28a8..000000000000 --- a/test-data/stdlib-samples/3.2/test/subprocessdata/sigchild_ignore.py +++ /dev/null @@ -1,6 +0,0 @@ -import signal, subprocess, sys -# On Linux this causes os.waitpid to fail with OSError as the OS has already -# reaped our child process. The wait() passing the OSError on to the caller -# and causing us to exit with an error is what we are testing against. -signal.signal(signal.SIGCHLD, signal.SIG_IGN) -subprocess.Popen([sys.executable, '-c', 'print("albatross")']).wait() diff --git a/test-data/stdlib-samples/3.2/test/support.py b/test-data/stdlib-samples/3.2/test/support.py deleted file mode 100644 index 88ce10cd74a9..000000000000 --- a/test-data/stdlib-samples/3.2/test/support.py +++ /dev/null @@ -1,1602 +0,0 @@ -"""Supporting definitions for the Python regression tests.""" - -if __name__ != 'test.support': - raise ImportError('support must be imported from the test package') - -import contextlib -import errno -import functools -import gc -import socket -import sys -import os -import platform -import shutil -import warnings -import unittest -import importlib -import collections -import re -import subprocess -import imp -import time -import sysconfig -import fnmatch -import logging.handlers - -import _thread, threading -from typing import Any, Dict, cast -#try: -# import multiprocessing.process -#except ImportError: -# multiprocessing = None - - -__all__ = [ - "Error", "TestFailed", "ResourceDenied", "import_module", - "verbose", "use_resources", "max_memuse", "record_original_stdout", - "get_original_stdout", "unload", "unlink", "rmtree", "forget", - "is_resource_enabled", "requires", "requires_mac_ver", - "find_unused_port", "bind_port", - "fcmp", "is_jython", "TESTFN", "HOST", "FUZZ", "SAVEDCWD", "temp_cwd", - "findfile", "sortdict", "check_syntax_error", "open_urlresource", - "check_warnings", "CleanImport", "EnvironmentVarGuard", - "TransientResource", "captured_output", "captured_stdout", - "captured_stdin", "captured_stderr", - "time_out", "socket_peer_reset", "ioerror_peer_reset", - "run_with_locale", 'temp_umask', "transient_internet", - "set_memlimit", "bigmemtest", "bigaddrspacetest", "BasicTestRunner", - "run_unittest", "run_doctest", "threading_setup", "threading_cleanup", - "reap_children", "cpython_only", "check_impl_detail", "get_attribute", - "swap_item", "swap_attr", "requires_IEEE_754", - "TestHandler", "Matcher", "can_symlink", "skip_unless_symlink", - "import_fresh_module", "failfast", - ] - -class Error(Exception): - """Base class for regression test exceptions.""" - -class TestFailed(Error): - """Test failed.""" - -class ResourceDenied(unittest.SkipTest): - """Test skipped because it requested a disallowed resource. - - This is raised when a test calls requires() for a resource that - has not be enabled. It is used to distinguish between expected - and unexpected skips. - """ - -@contextlib.contextmanager -def _ignore_deprecated_imports(ignore=True): - """Context manager to suppress package and module deprecation - warnings when importing them. - - If ignore is False, this context manager has no effect.""" - if ignore: - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", ".+ (module|package)", - DeprecationWarning) - yield None - else: - yield None - - -def import_module(name, deprecated=False): - """Import and return the module to be tested, raising SkipTest if - it is not available. - - If deprecated is True, any module or package deprecation messages - will be suppressed.""" - with _ignore_deprecated_imports(deprecated): - try: - return importlib.import_module(name) - except ImportError as msg: - raise unittest.SkipTest(str(msg)) - - -def _save_and_remove_module(name, orig_modules): - """Helper function to save and remove a module from sys.modules - - Raise ImportError if the module can't be imported.""" - # try to import the module and raise an error if it can't be imported - if name not in sys.modules: - __import__(name) - del sys.modules[name] - for modname in list(sys.modules): - if modname == name or modname.startswith(name + '.'): - orig_modules[modname] = sys.modules[modname] - del sys.modules[modname] - -def _save_and_block_module(name, orig_modules): - """Helper function to save and block a module in sys.modules - - Return True if the module was in sys.modules, False otherwise.""" - saved = True - try: - orig_modules[name] = sys.modules[name] - except KeyError: - saved = False - sys.modules[name] = None - return saved - - -def import_fresh_module(name, fresh=(), blocked=(), deprecated=False): - """Imports and returns a module, deliberately bypassing the sys.modules cache - and importing a fresh copy of the module. Once the import is complete, - the sys.modules cache is restored to its original state. - - Modules named in fresh are also imported anew if needed by the import. - If one of these modules can't be imported, None is returned. - - Importing of modules named in blocked is prevented while the fresh import - takes place. - - If deprecated is True, any module or package deprecation messages - will be suppressed.""" - # NOTE: test_heapq, test_json and test_warnings include extra sanity checks - # to make sure that this utility function is working as expected - with _ignore_deprecated_imports(deprecated): - # Keep track of modules saved for later restoration as well - # as those which just need a blocking entry removed - orig_modules = {} - names_to_remove = [] - _save_and_remove_module(name, orig_modules) - try: - for fresh_name in fresh: - _save_and_remove_module(fresh_name, orig_modules) - for blocked_name in blocked: - if not _save_and_block_module(blocked_name, orig_modules): - names_to_remove.append(blocked_name) - fresh_module = importlib.import_module(name) - except ImportError: - fresh_module = None - finally: - for orig_name, module in orig_modules.items(): - sys.modules[orig_name] = module - for name_to_remove in names_to_remove: - del sys.modules[name_to_remove] - return fresh_module - - -def get_attribute(obj, name): - """Get an attribute, raising SkipTest if AttributeError is raised.""" - try: - attribute = getattr(obj, name) - except AttributeError: - raise unittest.SkipTest("module %s has no attribute %s" % ( - obj.__name__, name)) - else: - return attribute - -verbose = 1 # Flag set to 0 by regrtest.py -use_resources = None # type: Any # Flag set to [] by regrtest.py -max_memuse = 0 # Disable bigmem tests (they will still be run with - # small sizes, to make sure they work.) -real_max_memuse = 0 -failfast = False -match_tests = None # type: Any - -# _original_stdout is meant to hold stdout at the time regrtest began. -# This may be "the real" stdout, or IDLE's emulation of stdout, or whatever. -# The point is to have some flavor of stdout the user can actually see. -_original_stdout = None # type: 'Any' -def record_original_stdout(stdout): - global _original_stdout - _original_stdout = stdout - -def get_original_stdout(): - return _original_stdout or sys.stdout - -def unload(name): - try: - del sys.modules[name] - except KeyError: - pass - -def unlink(filename): - try: - os.unlink(filename) - except OSError as error: - # The filename need not exist. - if error.errno not in (errno.ENOENT, errno.ENOTDIR): - raise - -def rmtree(path): - try: - shutil.rmtree(path) - except OSError as error: - # Unix returns ENOENT, Windows returns ESRCH. - if error.errno not in (errno.ENOENT, errno.ESRCH): - raise - -def make_legacy_pyc(source): - """Move a PEP 3147 pyc/pyo file to its legacy pyc/pyo location. - - The choice of .pyc or .pyo extension is done based on the __debug__ flag - value. - - :param source: The file system path to the source file. The source file - does not need to exist, however the PEP 3147 pyc file must exist. - :return: The file system path to the legacy pyc file. - """ - pyc_file = imp.cache_from_source(source) - up_one = os.path.dirname(os.path.abspath(source)) - if __debug__: - ch = 'c' - else: - ch = 'o' - legacy_pyc = os.path.join(up_one, source + ch) - os.rename(pyc_file, legacy_pyc) - return legacy_pyc - -def forget(modname): - """'Forget' a module was ever imported. - - This removes the module from sys.modules and deletes any PEP 3147 or - legacy .pyc and .pyo files. - """ - unload(modname) - for dirname in sys.path: - source = os.path.join(dirname, modname + '.py') - # It doesn't matter if they exist or not, unlink all possible - # combinations of PEP 3147 and legacy pyc and pyo files. - unlink(source + 'c') - unlink(source + 'o') - unlink(imp.cache_from_source(source, debug_override=True)) - unlink(imp.cache_from_source(source, debug_override=False)) - -# On some platforms, should not run gui test even if it is allowed -# in `use_resources'. -#if sys.platform.startswith('win'): - #import ctypes - #import ctypes.wintypes - #def _is_gui_available(): - # UOI_FLAGS = 1 - # WSF_VISIBLE = 0x0001 - # class USEROBJECTFLAGS(ctypes.Structure): - # _fields_ = [("fInherit", ctypes.wintypes.BOOL), - # ("fReserved", ctypes.wintypes.BOOL), - # ("dwFlags", ctypes.wintypes.DWORD)] - # dll = ctypes.windll.user32 - # h = dll.GetProcessWindowStation() - # if not h: - # raise ctypes.WinError() - # uof = USEROBJECTFLAGS() - # needed = ctypes.wintypes.DWORD() - # res = dll.GetUserObjectInformationW(h, - # UOI_FLAGS, - # ctypes.byref(uof), - # ctypes.sizeof(uof), - # ctypes.byref(needed)) - # if not res: - # raise ctypes.WinError() - # return bool(uof.dwFlags & WSF_VISIBLE) -#else: -def _is_gui_available(): - return True - -def is_resource_enabled(resource): - """Test whether a resource is enabled. Known resources are set by - regrtest.py.""" - return use_resources is not None and resource in use_resources - -def requires(resource, msg=None): - """Raise ResourceDenied if the specified resource is not available. - - If the caller's module is __main__ then automatically return True. The - possibility of False being returned occurs when regrtest.py is - executing. - """ - if resource == 'gui' and not _is_gui_available(): - raise unittest.SkipTest("Cannot use the 'gui' resource") - # see if the caller's module is __main__ - if so, treat as if - # the resource was set - if sys._getframe(1).f_globals.get("__name__") == "__main__": - return - if not is_resource_enabled(resource): - if msg is None: - msg = "Use of the `%s' resource not enabled" % resource - raise ResourceDenied(msg) - -def requires_mac_ver(*min_version): - """Decorator raising SkipTest if the OS is Mac OS X and the OS X - version if less than min_version. - - For example, @requires_mac_ver(10, 5) raises SkipTest if the OS X version - is lesser than 10.5. - """ - def decorator(func): - @functools.wraps(func) - def wrapper(*args, **kw): - if sys.platform == 'darwin': - version_txt = platform.mac_ver()[0] - try: - version = tuple(map(int, version_txt.split('.'))) - except ValueError: - pass - else: - if version < min_version: - min_version_txt = '.'.join(map(str, min_version)) - raise unittest.SkipTest( - "Mac OS X %s or higher required, not %s" - % (min_version_txt, version_txt)) - return func(*args, **kw) - wrapper.min_version = min_version - return wrapper - return decorator - -HOST = 'localhost' - -def find_unused_port(family=socket.AF_INET, socktype=socket.SOCK_STREAM): - """Returns an unused port that should be suitable for binding. This is - achieved by creating a temporary socket with the same family and type as - the 'sock' parameter (default is AF_INET, SOCK_STREAM), and binding it to - the specified host address (defaults to 0.0.0.0) with the port set to 0, - eliciting an unused ephemeral port from the OS. The temporary socket is - then closed and deleted, and the ephemeral port is returned. - - Either this method or bind_port() should be used for any tests where a - server socket needs to be bound to a particular port for the duration of - the test. Which one to use depends on whether the calling code is creating - a python socket, or if an unused port needs to be provided in a constructor - or passed to an external program (i.e. the -accept argument to openssl's - s_server mode). Always prefer bind_port() over find_unused_port() where - possible. Hard coded ports should *NEVER* be used. As soon as a server - socket is bound to a hard coded port, the ability to run multiple instances - of the test simultaneously on the same host is compromised, which makes the - test a ticking time bomb in a buildbot environment. On Unix buildbots, this - may simply manifest as a failed test, which can be recovered from without - intervention in most cases, but on Windows, the entire python process can - completely and utterly wedge, requiring someone to log in to the buildbot - and manually kill the affected process. - - (This is easy to reproduce on Windows, unfortunately, and can be traced to - the SO_REUSEADDR socket option having different semantics on Windows versus - Unix/Linux. On Unix, you can't have two AF_INET SOCK_STREAM sockets bind, - listen and then accept connections on identical host/ports. An EADDRINUSE - socket.error will be raised at some point (depending on the platform and - the order bind and listen were called on each socket). - - However, on Windows, if SO_REUSEADDR is set on the sockets, no EADDRINUSE - will ever be raised when attempting to bind two identical host/ports. When - accept() is called on each socket, the second caller's process will steal - the port from the first caller, leaving them both in an awkwardly wedged - state where they'll no longer respond to any signals or graceful kills, and - must be forcibly killed via OpenProcess()/TerminateProcess(). - - The solution on Windows is to use the SO_EXCLUSIVEADDRUSE socket option - instead of SO_REUSEADDR, which effectively affords the same semantics as - SO_REUSEADDR on Unix. Given the propensity of Unix developers in the Open - Source world compared to Windows ones, this is a common mistake. A quick - look over OpenSSL's 0.9.8g source shows that they use SO_REUSEADDR when - openssl.exe is called with the 's_server' option, for example. See - http://bugs.python.org/issue2550 for more info. The following site also - has a very thorough description about the implications of both REUSEADDR - and EXCLUSIVEADDRUSE on Windows: - http://msdn2.microsoft.com/en-us/library/ms740621(VS.85).aspx) - - XXX: although this approach is a vast improvement on previous attempts to - elicit unused ports, it rests heavily on the assumption that the ephemeral - port returned to us by the OS won't immediately be dished back out to some - other process when we close and delete our temporary socket but before our - calling code has a chance to bind the returned port. We can deal with this - issue if/when we come across it. - """ - - tempsock = socket.socket(family, socktype) - port = bind_port(tempsock) - tempsock.close() - #del tempsock - return port - -def bind_port(sock, host=HOST): - """Bind the socket to a free port and return the port number. Relies on - ephemeral ports in order to ensure we are using an unbound port. This is - important as many tests may be running simultaneously, especially in a - buildbot environment. This method raises an exception if the sock.family - is AF_INET and sock.type is SOCK_STREAM, *and* the socket has SO_REUSEADDR - or SO_REUSEPORT set on it. Tests should *never* set these socket options - for TCP/IP sockets. The only case for setting these options is testing - multicasting via multiple UDP sockets. - - Additionally, if the SO_EXCLUSIVEADDRUSE socket option is available (i.e. - on Windows), it will be set on the socket. This will prevent anyone else - from bind()'ing to our host/port for the duration of the test. - """ - - if sock.family == socket.AF_INET and sock.type == socket.SOCK_STREAM: - if hasattr(socket, 'SO_REUSEADDR'): - if sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) == 1: - raise TestFailed("tests should never set the SO_REUSEADDR " \ - "socket option on TCP/IP sockets!") - if hasattr(socket, 'SO_REUSEPORT'): - if sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT) == 1: - raise TestFailed("tests should never set the SO_REUSEPORT " \ - "socket option on TCP/IP sockets!") - if hasattr(socket, 'SO_EXCLUSIVEADDRUSE'): - sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1) - - sock.bind((host, 0)) - port = sock.getsockname()[1] - return port - -FUZZ = 1e-6 - -def fcmp(x, y): # fuzzy comparison function - if isinstance(x, float) or isinstance(y, float): - try: - fuzz = (abs(x) + abs(y)) * FUZZ - if abs(x-y) <= fuzz: - return 0 - except: - pass - elif type(x) == type(y) and isinstance(x, (tuple, list)): - for i in range(min(len(x), len(y))): - outcome = fcmp(x[i], y[i]) - if outcome != 0: - return outcome - return (len(x) > len(y)) - (len(x) < len(y)) - return (x > y) - (x < y) - -# decorator for skipping tests on non-IEEE 754 platforms -requires_IEEE_754 = unittest.skipUnless( - cast(Any, float).__getformat__("double").startswith("IEEE"), - "test requires IEEE 754 doubles") - -is_jython = sys.platform.startswith('java') - -TESTFN = '' -# Filename used for testing -if os.name == 'java': - # Jython disallows @ in module names - TESTFN = '$test' -else: - TESTFN = '@test' - -# Disambiguate TESTFN for parallel testing, while letting it remain a valid -# module name. -TESTFN = "{}_{}_tmp".format(TESTFN, os.getpid()) - - -# TESTFN_UNICODE is a non-ascii filename -TESTFN_UNICODE = TESTFN + "-\xe0\xf2\u0258\u0141\u011f" -if sys.platform == 'darwin': - # In Mac OS X's VFS API file names are, by definition, canonically - # decomposed Unicode, encoded using UTF-8. See QA1173: - # http://developer.apple.com/mac/library/qa/qa2001/qa1173.html - import unicodedata - TESTFN_UNICODE = unicodedata.normalize('NFD', TESTFN_UNICODE) -TESTFN_ENCODING = sys.getfilesystemencoding() - -# TESTFN_UNENCODABLE is a filename (str type) that should *not* be able to be -# encoded by the filesystem encoding (in strict mode). It can be None if we -# cannot generate such filename. -TESTFN_UNENCODABLE = None # type: Any -if sys.platform == "win32": - # skip win32s (0) or Windows 9x/ME (1) - if sys.getwindowsversion().platform >= 2: - # Different kinds of characters from various languages to minimize the - # probability that the whole name is encodable to MBCS (issue #9819) - TESTFN_UNENCODABLE = TESTFN + "-\u5171\u0141\u2661\u0363\uDC80" - try: - TESTFN_UNENCODABLE.encode(TESTFN_ENCODING) - except UnicodeEncodeError: - pass - else: - print('WARNING: The filename %r CAN be encoded by the filesystem encoding (%s). ' - 'Unicode filename tests may not be effective' - % (TESTFN_UNENCODABLE, TESTFN_ENCODING)) - TESTFN_UNENCODABLE = None -# Mac OS X denies unencodable filenames (invalid utf-8) -elif sys.platform != 'darwin': - try: - # ascii and utf-8 cannot encode the byte 0xff - b'\xff'.decode(TESTFN_ENCODING) - except UnicodeDecodeError: - # 0xff will be encoded using the surrogate character u+DCFF - TESTFN_UNENCODABLE = TESTFN \ - + b'-\xff'.decode(TESTFN_ENCODING, 'surrogateescape') - else: - # File system encoding (eg. ISO-8859-* encodings) can encode - # the byte 0xff. Skip some unicode filename tests. - pass - -# Save the initial cwd -SAVEDCWD = os.getcwd() - -@contextlib.contextmanager -def temp_cwd(name='tempcwd', quiet=False, path=None): - """ - Context manager that temporarily changes the CWD. - - An existing path may be provided as *path*, in which case this - function makes no changes to the file system. - - Otherwise, the new CWD is created in the current directory and it's - named *name*. If *quiet* is False (default) and it's not possible to - create or change the CWD, an error is raised. If it's True, only a - warning is raised and the original CWD is used. - """ - saved_dir = os.getcwd() - is_temporary = False - if path is None: - path = name - try: - os.mkdir(name) - is_temporary = True - except OSError: - if not quiet: - raise - warnings.warn('tests may fail, unable to create temp CWD ' + name, - RuntimeWarning, stacklevel=3) - try: - os.chdir(path) - except OSError: - if not quiet: - raise - warnings.warn('tests may fail, unable to change the CWD to ' + name, - RuntimeWarning, stacklevel=3) - try: - yield os.getcwd() - finally: - os.chdir(saved_dir) - if is_temporary: - rmtree(name) - - -@contextlib.contextmanager -def temp_umask(umask): - """Context manager that temporarily sets the process umask.""" - oldmask = os.umask(umask) - try: - yield None - finally: - os.umask(oldmask) - - -def findfile(file, here=__file__, subdir=None): - """Try to find a file on sys.path and the working directory. If it is not - found the argument passed to the function is returned (this does not - necessarily signal failure; could still be the legitimate path).""" - if os.path.isabs(file): - return file - if subdir is not None: - file = os.path.join(subdir, file) - path = sys.path - path = [os.path.dirname(here)] + path - for dn in path: - fn = os.path.join(dn, file) - if os.path.exists(fn): return fn - return file - -def sortdict(dict): - "Like repr(dict), but in sorted order." - items = sorted(dict.items()) - reprpairs = ["%r: %r" % pair for pair in items] - withcommas = ", ".join(reprpairs) - return "{%s}" % withcommas - -def make_bad_fd(): - """ - Create an invalid file descriptor by opening and closing a file and return - its fd. - """ - file = open(TESTFN, "wb") - try: - return file.fileno() - finally: - file.close() - unlink(TESTFN) - -def check_syntax_error(testcase, statement): - raise NotImplementedError('no compile built-in') - #testcase.assertRaises(SyntaxError, compile, statement, - # '', 'exec') - -def open_urlresource(url, *args, **kw): - from urllib import request, parse - - check = kw.pop('check', None) - - filename = parse.urlparse(url)[2].split('/')[-1] # '/': it's URL! - - fn = os.path.join(os.path.dirname(__file__), "data", filename) - - def check_valid_file(fn): - f = open(fn, *args, **kw) - if check is None: - return f - elif check(f): - f.seek(0) - return f - f.close() - - if os.path.exists(fn): - f = check_valid_file(fn) - if f is not None: - return f - unlink(fn) - - # Verify the requirement before downloading the file - requires('urlfetch') - - print('\tfetching %s ...' % url, file=get_original_stdout()) - f = request.urlopen(url, timeout=15) - try: - with open(fn, "wb") as out: - s = f.read() - while s: - out.write(s) - s = f.read() - finally: - f.close() - - f = check_valid_file(fn) - if f is not None: - return f - raise TestFailed('invalid resource "%s"' % fn) - - -class WarningsRecorder(object): - """Convenience wrapper for the warnings list returned on - entry to the warnings.catch_warnings() context manager. - """ - def __init__(self, warnings_list): - self._warnings = warnings_list - self._last = 0 - - def __getattr__(self, attr): - if len(self._warnings) > self._last: - return getattr(self._warnings[-1], attr) - elif attr in warnings.WarningMessage._WARNING_DETAILS: - return None - raise AttributeError("%r has no attribute %r" % (self, attr)) - - #@property - #def warnings(self): - # return self._warnings[self._last:] - - def reset(self): - self._last = len(self._warnings) - - -def _filterwarnings(filters, quiet=False): - """Catch the warnings, then check if all the expected - warnings have been raised and re-raise unexpected warnings. - If 'quiet' is True, only re-raise the unexpected warnings. - """ - # Clear the warning registry of the calling module - # in order to re-raise the warnings. - frame = sys._getframe(2) - registry = frame.f_globals.get('__warningregistry__') - if registry: - registry.clear() - with warnings.catch_warnings(record=True) as w: - # Set filter "always" to record all warnings. Because - # test_warnings swap the module, we need to look up in - # the sys.modules dictionary. - sys.modules['warnings'].simplefilter("always") - yield WarningsRecorder(w) - # Filter the recorded warnings - reraise = list(w) - missing = [] - for msg, cat in filters: - seen = False - for w in reraise[:]: - warning = w.message - # Filter out the matching messages - if (re.match(msg, str(warning), re.I) and - issubclass(warning.__class__, cat)): - seen = True - reraise.remove(w) - if not seen and not quiet: - # This filter caught nothing - missing.append((msg, cat.__name__)) - if reraise: - raise AssertionError("unhandled warning %s" % reraise[0]) - if missing: - raise AssertionError("filter (%r, %s) did not catch any warning" % - missing[0]) - - -@contextlib.contextmanager -def check_warnings(*filters, **kwargs): - """Context manager to silence warnings. - - Accept 2-tuples as positional arguments: - ("message regexp", WarningCategory) - - Optional argument: - - if 'quiet' is True, it does not fail if a filter catches nothing - (default True without argument, - default False if some filters are defined) - - Without argument, it defaults to: - check_warnings(("", Warning), quiet=True) - """ - quiet = kwargs.get('quiet') - if not filters: - filters = (("", Warning),) - # Preserve backward compatibility - if quiet is None: - quiet = True - return _filterwarnings(filters, quiet) - - -class CleanImport(object): - """Context manager to force import to return a new module reference. - - This is useful for testing module-level behaviours, such as - the emission of a DeprecationWarning on import. - - Use like this: - - with CleanImport("foo"): - importlib.import_module("foo") # new reference - """ - - def __init__(self, *module_names): - self.original_modules = sys.modules.copy() - for module_name in module_names: - if module_name in sys.modules: - module = sys.modules[module_name] - # It is possible that module_name is just an alias for - # another module (e.g. stub for modules renamed in 3.x). - # In that case, we also need delete the real module to clear - # the import cache. - if module.__name__ != module_name: - del sys.modules[module.__name__] - del sys.modules[module_name] - - def __enter__(self): - return self - - def __exit__(self, *ignore_exc): - sys.modules.update(self.original_modules) - - -class EnvironmentVarGuard(dict): - - """Class to help protect the environment variable properly. Can be used as - a context manager.""" - - def __init__(self): - self._environ = os.environ - self._changed = {} - - def __getitem__(self, envvar): - return self._environ[envvar] - - def __setitem__(self, envvar, value): - # Remember the initial value on the first access - if envvar not in self._changed: - self._changed[envvar] = self._environ.get(envvar) - self._environ[envvar] = value - - def __delitem__(self, envvar): - # Remember the initial value on the first access - if envvar not in self._changed: - self._changed[envvar] = self._environ.get(envvar) - if envvar in self._environ: - del self._environ[envvar] - - def keys(self): - return self._environ.keys() - - def __iter__(self): - return iter(self._environ) - - def __len__(self): - return len(self._environ) - - def set(self, envvar, value): - self[envvar] = value - - def unset(self, envvar): - del self[envvar] - - def __enter__(self): - return self - - def __exit__(self, *ignore_exc): - for k, v in self._changed.items(): - if v is None: - if k in self._environ: - del self._environ[k] - else: - self._environ[k] = v - os.environ = self._environ - - -class DirsOnSysPath(object): - """Context manager to temporarily add directories to sys.path. - - This makes a copy of sys.path, appends any directories given - as positional arguments, then reverts sys.path to the copied - settings when the context ends. - - Note that *all* sys.path modifications in the body of the - context manager, including replacement of the object, - will be reverted at the end of the block. - """ - - def __init__(self, *paths): - self.original_value = sys.path[:] - self.original_object = sys.path - sys.path.extend(paths) - - def __enter__(self): - return self - - def __exit__(self, *ignore_exc): - sys.path = self.original_object - sys.path[:] = self.original_value - - -class TransientResource(object): - - """Raise ResourceDenied if an exception is raised while the context manager - is in effect that matches the specified exception and attributes.""" - - def __init__(self, exc, **kwargs): - self.exc = exc - self.attrs = kwargs - - def __enter__(self): - return self - - def __exit__(self, type_=None, value=None, traceback=None): - """If type_ is a subclass of self.exc and value has attributes matching - self.attrs, raise ResourceDenied. Otherwise let the exception - propagate (if any).""" - if type_ is not None and issubclass(self.exc, type_): - for attr, attr_value in self.attrs.items(): - if not hasattr(value, attr): - break - if getattr(value, attr) != attr_value: - break - else: - raise ResourceDenied("an optional resource is not available") - -# Context managers that raise ResourceDenied when various issues -# with the Internet connection manifest themselves as exceptions. -# XXX deprecate these and use transient_internet() instead -time_out = TransientResource(IOError, errno=errno.ETIMEDOUT) -socket_peer_reset = TransientResource(socket.error, errno=errno.ECONNRESET) -ioerror_peer_reset = TransientResource(IOError, errno=errno.ECONNRESET) - - -@contextlib.contextmanager -def transient_internet(resource_name, *, timeout=30.0, errnos=()): - """Return a context manager that raises ResourceDenied when various issues - with the Internet connection manifest themselves as exceptions.""" - default_errnos = [ - ('ECONNREFUSED', 111), - ('ECONNRESET', 104), - ('EHOSTUNREACH', 113), - ('ENETUNREACH', 101), - ('ETIMEDOUT', 110), - ] - default_gai_errnos = [ - ('EAI_AGAIN', -3), - ('EAI_FAIL', -4), - ('EAI_NONAME', -2), - ('EAI_NODATA', -5), - # Encountered when trying to resolve IPv6-only hostnames - ('WSANO_DATA', 11004), - ] - - denied = ResourceDenied("Resource '%s' is not available" % resource_name) - captured_errnos = errnos - gai_errnos = [] - if not captured_errnos: - captured_errnos = [getattr(errno, name, num) - for name, num in default_errnos] - gai_errnos = [getattr(socket, name, num) - for name, num in default_gai_errnos] - - def filter_error(err): - n = getattr(err, 'errno', None) - if (isinstance(err, socket.timeout) or - (isinstance(err, socket.gaierror) and n in gai_errnos) or - n in captured_errnos): - if not verbose: - sys.stderr.write(denied.args[0] + "\n") - raise denied from err - - old_timeout = socket.getdefaulttimeout() - try: - if timeout is not None: - socket.setdefaulttimeout(timeout) - yield None - except IOError as err: - # urllib can wrap original socket errors multiple times (!), we must - # unwrap to get at the original error. - while True: - a = err.args - if len(a) >= 1 and isinstance(a[0], IOError): - err = a[0] - # The error can also be wrapped as args[1]: - # except socket.error as msg: - # raise IOError('socket error', msg).with_traceback(sys.exc_info()[2]) - elif len(a) >= 2 and isinstance(a[1], IOError): - err = a[1] - else: - break - filter_error(err) - raise - # XXX should we catch generic exceptions and look for their - # __cause__ or __context__? - finally: - socket.setdefaulttimeout(old_timeout) - - -@contextlib.contextmanager -def captured_output(stream_name): - """Return a context manager used by captured_stdout/stdin/stderr - that temporarily replaces the sys stream *stream_name* with a StringIO.""" - import io - orig_stdout = getattr(sys, stream_name) - setattr(sys, stream_name, io.StringIO()) - try: - yield getattr(sys, stream_name) - finally: - setattr(sys, stream_name, orig_stdout) - -def captured_stdout(): - """Capture the output of sys.stdout: - - with captured_stdout() as s: - print("hello") - self.assertEqual(s.getvalue(), "hello") - """ - return captured_output("stdout") - -def captured_stderr(): - return captured_output("stderr") - -def captured_stdin(): - return captured_output("stdin") - - -def gc_collect(): - """Force as many objects as possible to be collected. - - In non-CPython implementations of Python, this is needed because timely - deallocation is not guaranteed by the garbage collector. (Even in CPython - this can be the case in case of reference cycles.) This means that __del__ - methods may be called later than expected and weakrefs may remain alive for - longer than expected. This function tries its best to force all garbage - objects to disappear. - """ - gc.collect() - if is_jython: - time.sleep(0.1) - gc.collect() - gc.collect() - - -def python_is_optimized(): - """Find if Python was built with optimizations.""" - cflags = sysconfig.get_config_var('PY_CFLAGS') or '' - final_opt = "" - for opt in cflags.split(): - if opt.startswith('-O'): - final_opt = opt - return final_opt and final_opt != '-O0' - - -#======================================================================= -# Decorator for running a function in a different locale, correctly resetting -# it afterwards. - -def run_with_locale(catstr, *locales): - def decorator(func): - def inner(*args, **kwds): - try: - import locale - category = getattr(locale, catstr) - orig_locale = locale.setlocale(category) - except AttributeError: - # if the test author gives us an invalid category string - raise - except: - # cannot retrieve original locale, so do nothing - locale = orig_locale = None - else: - for loc in locales: - try: - locale.setlocale(category, loc) - break - except: - pass - - # now run the function, resetting the locale on exceptions - try: - return func(*args, **kwds) - finally: - if locale and orig_locale: - locale.setlocale(category, orig_locale) - inner.__name__ = func.__name__ - inner.__doc__ = func.__doc__ - return inner - return decorator - -#======================================================================= -# Big-memory-test support. Separate from 'resources' because memory use -# should be configurable. - -# Some handy shorthands. Note that these are used for byte-limits as well -# as size-limits, in the various bigmem tests -_1M = 1024*1024 -_1G = 1024 * _1M -_2G = 2 * _1G -_4G = 4 * _1G - -MAX_Py_ssize_t = sys.maxsize - -def set_memlimit(limit): - global max_memuse - global real_max_memuse - sizes = { - 'k': 1024, - 'm': _1M, - 'g': _1G, - 't': 1024*_1G, - } - m = re.match(r'(\d+(\.\d+)?) (K|M|G|T)b?$', limit, - re.IGNORECASE | re.VERBOSE) - if m is None: - raise ValueError('Invalid memory limit %r' % (limit,)) - memlimit = int(float(m.group(1)) * sizes[m.group(3).lower()]) - real_max_memuse = memlimit - if memlimit > MAX_Py_ssize_t: - memlimit = MAX_Py_ssize_t - if memlimit < _2G - 1: - raise ValueError('Memory limit %r too low to be useful' % (limit,)) - max_memuse = memlimit - -def _memory_watchdog(start_evt, finish_evt, period=10.0): - """A function which periodically watches the process' memory consumption - and prints it out. - """ - # XXX: because of the GIL, and because the very long operations tested - # in most bigmem tests are uninterruptible, the loop below gets woken up - # much less often than expected. - # The polling code should be rewritten in raw C, without holding the GIL, - # and push results onto an anonymous pipe. - try: - page_size = os.sysconf('SC_PAGESIZE') - except (ValueError, AttributeError): - try: - page_size = os.sysconf('SC_PAGE_SIZE') - except (ValueError, AttributeError): - page_size = 4096 - procfile = '/proc/{pid}/statm'.format(pid=os.getpid()) - try: - f = open(procfile, 'rb') - except IOError as e: - warnings.warn('/proc not available for stats: {}'.format(e), - RuntimeWarning) - sys.stderr.flush() - return - with f: - start_evt.set() - old_data = -1 - while not finish_evt.wait(period): - f.seek(0) - statm = f.read().decode('ascii') - data = int(statm.split()[5]) - if data != old_data: - old_data = data - print(" ... process data size: {data:.1f}G" - .format(data=data * page_size / (1024 ** 3))) - -def bigmemtest(size, memuse, dry_run=True): - """Decorator for bigmem tests. - - 'minsize' is the minimum useful size for the test (in arbitrary, - test-interpreted units.) 'memuse' is the number of 'bytes per size' for - the test, or a good estimate of it. - - if 'dry_run' is False, it means the test doesn't support dummy runs - when -M is not specified. - """ - def decorator(f): - def wrapper(self): - size = wrapper.size - memuse = wrapper.memuse - if not real_max_memuse: - maxsize = 5147 - else: - maxsize = size - - if ((real_max_memuse or not dry_run) - and real_max_memuse < maxsize * memuse): - raise unittest.SkipTest( - "not enough memory: %.1fG minimum needed" - % (size * memuse / (1024 ** 3))) - - if real_max_memuse and verbose and threading: - print() - print(" ... expected peak memory use: {peak:.1f}G" - .format(peak=size * memuse / (1024 ** 3))) - sys.stdout.flush() - start_evt = threading.Event() - finish_evt = threading.Event() - t = threading.Thread(target=_memory_watchdog, - args=(start_evt, finish_evt, 0.5)) - t.daemon = True - t.start() - start_evt.set() - else: - t = None - - try: - return f(self, maxsize) - finally: - if t: - finish_evt.set() - t.join() - - wrapper.size = size - wrapper.memuse = memuse - return wrapper - return decorator - -def bigaddrspacetest(f): - """Decorator for tests that fill the address space.""" - def wrapper(self): - if max_memuse < MAX_Py_ssize_t: - if MAX_Py_ssize_t >= 2**63 - 1 and max_memuse >= 2**31: - raise unittest.SkipTest( - "not enough memory: try a 32-bit build instead") - else: - raise unittest.SkipTest( - "not enough memory: %.1fG minimum needed" - % (MAX_Py_ssize_t / (1024 ** 3))) - else: - return f(self) - return wrapper - -#======================================================================= -# unittest integration. - -class BasicTestRunner: - def run(self, test): - result = unittest.TestResult() - test(result) - return result - -def _id(obj): - return obj - -def requires_resource(resource): - if resource == 'gui' and not _is_gui_available(): - return unittest.skip("resource 'gui' is not available") - if is_resource_enabled(resource): - return _id - else: - return unittest.skip("resource {0!r} is not enabled".format(resource)) - -def cpython_only(test): - """ - Decorator for tests only applicable on CPython. - """ - return impl_detail(cpython=True)(test) - -def impl_detail(msg=None, **guards): - if check_impl_detail(**guards): - return _id - if msg is None: - guardnames, default = _parse_guards(guards) - if default: - msg = "implementation detail not available on {0}" - else: - msg = "implementation detail specific to {0}" - guardnames = sorted(guardnames.keys()) - msg = msg.format(' or '.join(guardnames)) - return unittest.skip(msg) - -def _parse_guards(guards): - # Returns a tuple ({platform_name: run_me}, default_value) - if not guards: - return ({'cpython': True}, False) - is_true = list(guards.values())[0] - assert list(guards.values()) == [is_true] * len(guards) # all True or all False - return (guards, not is_true) - -# Use the following check to guard CPython's implementation-specific tests -- -# or to run them only on the implementation(s) guarded by the arguments. -def check_impl_detail(**guards): - """This function returns True or False depending on the host platform. - Examples: - if check_impl_detail(): # only on CPython (default) - if check_impl_detail(jython=True): # only on Jython - if check_impl_detail(cpython=False): # everywhere except on CPython - """ - guards, default = _parse_guards(guards) - return guards.get(platform.python_implementation().lower(), default) - - -def _filter_suite(suite, pred): - """Recursively filter test cases in a suite based on a predicate.""" - newtests = [] - for test in suite._tests: - if isinstance(test, unittest.TestSuite): - _filter_suite(test, pred) - newtests.append(test) - else: - if pred(test): - newtests.append(test) - suite._tests = newtests - - -def _run_suite(suite): - """Run tests from a unittest.TestSuite-derived class.""" - if verbose: - runner = unittest.TextTestRunner(sys.stdout, verbosity=2, - failfast=failfast) - else: - runner = BasicTestRunner() - - result = runner.run(suite) - if not result.wasSuccessful(): - if len(result.errors) == 1 and not result.failures: - err = result.errors[0][1] - elif len(result.failures) == 1 and not result.errors: - err = result.failures[0][1] - else: - err = "multiple errors occurred" - if not verbose: err += "; run in verbose mode for details" - raise TestFailed(err) - - -def run_unittest(*classes): - """Run tests from unittest.TestCase-derived classes.""" - valid_types = (unittest.TestSuite, unittest.TestCase) - suite = unittest.TestSuite() - for cls in classes: - if isinstance(cls, str): - if cls in sys.modules: - suite.addTest(unittest.findTestCases(sys.modules[cls])) - else: - raise ValueError("str arguments must be keys in sys.modules") - elif isinstance(cls, valid_types): - suite.addTest(cls) - else: - suite.addTest(unittest.makeSuite(cls)) - def case_pred(test): - if match_tests is None: - return True - for name in test.id().split("."): - if fnmatch.fnmatchcase(name, match_tests): - return True - return False - _filter_suite(suite, case_pred) - _run_suite(suite) - - -#======================================================================= -# doctest driver. - -def run_doctest(module, verbosity=None): - """Run doctest on the given module. Return (#failures, #tests). - - If optional argument verbosity is not specified (or is None), pass - support's belief about verbosity on to doctest. Else doctest's - usual behavior is used (it searches sys.argv for -v). - """ - - import doctest - - if verbosity is None: - verbosity = verbose - else: - verbosity = None - - f, t = doctest.testmod(module, verbose=verbosity) - if f: - raise TestFailed("%d of %d doctests failed" % (f, t)) - if verbose: - print('doctest (%s) ... %d tests with zero failures' % - (module.__name__, t)) - return f, t - - -#======================================================================= -# Support for saving and restoring the imported modules. - -def modules_setup(): - return sys.modules.copy(), - -def modules_cleanup(oldmodules): - # Encoders/decoders are registered permanently within the internal - # codec cache. If we destroy the corresponding modules their - # globals will be set to None which will trip up the cached functions. - encodings = [(k, v) for k, v in sys.modules.items() - if k.startswith('encodings.')] - sys.modules.clear() - sys.modules.update(encodings) - # XXX: This kind of problem can affect more than just encodings. In particular - # extension modules (such as _ssl) don't cope with reloading properly. - # Really, test modules should be cleaning out the test specific modules they - # know they added (ala test_runpy) rather than relying on this function (as - # test_importhooks and test_pkg do currently). - # Implicitly imported *real* modules should be left alone (see issue 10556). - sys.modules.update(oldmodules) - -#======================================================================= -# Threading support to prevent reporting refleaks when running regrtest.py -R - -# NOTE: we use thread._count() rather than threading.enumerate() (or the -# moral equivalent thereof) because a threading.Thread object is still alive -# until its __bootstrap() method has returned, even after it has been -# unregistered from the threading module. -# thread._count(), on the other hand, only gets decremented *after* the -# __bootstrap() method has returned, which gives us reliable reference counts -# at the end of a test run. - -def threading_setup(): - if _thread: - return _thread._count(), threading._dangling.copy() - else: - return 1, () - -def threading_cleanup(*original_values): - if not _thread: - return - _MAX_COUNT = 10 - for count in range(_MAX_COUNT): - values = _thread._count(), threading._dangling - if values == original_values: - break - time.sleep(0.1) - gc_collect() - # XXX print a warning in case of failure? - -def reap_threads(func): - """Use this function when threads are being used. This will - ensure that the threads are cleaned up even when the test fails. - If threading is unavailable this function does nothing. - """ - if not _thread: - return func - - @functools.wraps(func) - def decorator(*args): - key = threading_setup() - try: - return func(*args) - finally: - threading_cleanup(*key) - return decorator - -def reap_children(): - """Use this function at the end of test_main() whenever sub-processes - are started. This will help ensure that no extra children (zombies) - stick around to hog resources and create problems when looking - for refleaks. - """ - - # Reap all our dead child processes so we don't leave zombies around. - # These hog resources and might be causing some of the buildbots to die. - if hasattr(os, 'waitpid'): - any_process = -1 - while True: - try: - # This will raise an exception on Windows. That's ok. - pid, status = os.waitpid(any_process, os.WNOHANG) - if pid == 0: - break - except: - break - -@contextlib.contextmanager -def swap_attr(obj, attr, new_val): - """Temporary swap out an attribute with a new object. - - Usage: - with swap_attr(obj, "attr", 5): - ... - - This will set obj.attr to 5 for the duration of the with: block, - restoring the old value at the end of the block. If `attr` doesn't - exist on `obj`, it will be created and then deleted at the end of the - block. - """ - if hasattr(obj, attr): - real_val = getattr(obj, attr) - setattr(obj, attr, new_val) - try: - yield None - finally: - setattr(obj, attr, real_val) - else: - setattr(obj, attr, new_val) - try: - yield None - finally: - delattr(obj, attr) - -@contextlib.contextmanager -def swap_item(obj, item, new_val): - """Temporary swap out an item with a new object. - - Usage: - with swap_item(obj, "item", 5): - ... - - This will set obj["item"] to 5 for the duration of the with: block, - restoring the old value at the end of the block. If `item` doesn't - exist on `obj`, it will be created and then deleted at the end of the - block. - """ - if item in obj: - real_val = obj[item] - obj[item] = new_val - try: - yield None - finally: - obj[item] = real_val - else: - obj[item] = new_val - try: - yield None - finally: - del obj[item] - -def strip_python_stderr(stderr): - """Strip the stderr of a Python process from potential debug output - emitted by the interpreter. - - This will typically be run on the result of the communicate() method - of a subprocess.Popen object. - """ - stderr = re.sub(br"\[\d+ refs\]\r?\n?$", b"", stderr).strip() - return stderr - -def args_from_interpreter_flags(): - """Return a list of command-line arguments reproducing the current - settings in sys.flags.""" - flag_opt_map = { - 'bytes_warning': 'b', - 'dont_write_bytecode': 'B', - 'hash_randomization': 'R', - 'ignore_environment': 'E', - 'no_user_site': 's', - 'no_site': 'S', - 'optimize': 'O', - 'verbose': 'v', - } - args = [] - for flag, opt in flag_opt_map.items(): - v = getattr(sys.flags, flag) - if v > 0: - args.append('-' + opt * v) - return args - -#============================================================ -# Support for assertions about logging. -#============================================================ - -class TestHandler(logging.handlers.BufferingHandler): - def __init__(self, matcher): - # BufferingHandler takes a "capacity" argument - # so as to know when to flush. As we're overriding - # shouldFlush anyway, we can set a capacity of zero. - # You can call flush() manually to clear out the - # buffer. - logging.handlers.BufferingHandler.__init__(self, 0) - self.matcher = matcher - - def shouldFlush(self, record): - return False - - def emit(self, record): - self.format(record) - self.buffer.append(record.__dict__) - - def matches(self, **kwargs): - """ - Look for a saved dict whose keys/values match the supplied arguments. - """ - result = False - for d in self.buffer: - if self.matcher.matches(d, **kwargs): - result = True - break - return result - -class Matcher(object): - - _partial_matches = ('msg', 'message') - - def matches(self, d, **kwargs): - """ - Try to match a single dict with the supplied arguments. - - Keys whose values are strings and which are in self._partial_matches - will be checked for partial (i.e. substring) matches. You can extend - this scheme to (for example) do regular expression matching, etc. - """ - result = True - for k in kwargs: - v = kwargs[k] - dv = d.get(k) - if not self.match_value(k, dv, v): - result = False - break - return result - - def match_value(self, k, dv, v): - """ - Try to match a single stored value (dv) with a supplied value (v). - """ - if type(v) != type(dv): - result = False - elif type(dv) is not str or k not in self._partial_matches: - result = (v == dv) - else: - result = dv.find(v) >= 0 - return result - - -_can_symlink = None # type: Any -def can_symlink(): - global _can_symlink - if _can_symlink is not None: - return _can_symlink - symlink_path = TESTFN + "can_symlink" - try: - os.symlink(TESTFN, symlink_path) - can = True - except (OSError, NotImplementedError, AttributeError): - can = False - else: - os.remove(symlink_path) - _can_symlink = can - return can - -def skip_unless_symlink(test): - """Skip decorator for tests that require functional symlink""" - ok = can_symlink() - msg = "Requires functional symlink implementation" - if ok: - return test - else: - return unittest.skip(msg)(test) - -def patch(test_instance, object_to_patch, attr_name, new_value): - """Override 'object_to_patch'.'attr_name' with 'new_value'. - - Also, add a cleanup procedure to 'test_instance' to restore - 'object_to_patch' value for 'attr_name'. - The 'attr_name' should be a valid attribute for 'object_to_patch'. - - """ - # check that 'attr_name' is a real attribute for 'object_to_patch' - # will raise AttributeError if it does not exist - getattr(object_to_patch, attr_name) - - # keep a copy of the old value - attr_is_local = False - try: - old_value = object_to_patch.__dict__[attr_name] - except (AttributeError, KeyError): - old_value = getattr(object_to_patch, attr_name, None) - else: - attr_is_local = True - - # restore the value when the test is done - def cleanup(): - if attr_is_local: - setattr(object_to_patch, attr_name, old_value) - else: - delattr(object_to_patch, attr_name) - - test_instance.addCleanup(cleanup) - - # actually override the attribute - setattr(object_to_patch, attr_name, new_value) diff --git a/test-data/stdlib-samples/3.2/test/test_base64.py b/test-data/stdlib-samples/3.2/test/test_base64.py deleted file mode 100644 index 9e4dcf5544ed..000000000000 --- a/test-data/stdlib-samples/3.2/test/test_base64.py +++ /dev/null @@ -1,267 +0,0 @@ -import unittest -from test import support -import base64 -import binascii -import sys -import subprocess - -from typing import Any - - - -class LegacyBase64TestCase(unittest.TestCase): - def test_encodebytes(self) -> None: - eq = self.assertEqual - eq(base64.encodebytes(b"www.python.org"), b"d3d3LnB5dGhvbi5vcmc=\n") - eq(base64.encodebytes(b"a"), b"YQ==\n") - eq(base64.encodebytes(b"ab"), b"YWI=\n") - eq(base64.encodebytes(b"abc"), b"YWJj\n") - eq(base64.encodebytes(b""), b"") - eq(base64.encodebytes(b"abcdefghijklmnopqrstuvwxyz" - b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" - b"0123456789!@#0^&*();:<>,. []{}"), - b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" - b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT" - b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n") - self.assertRaises(TypeError, base64.encodebytes, "") - - def test_decodebytes(self) -> None: - eq = self.assertEqual - eq(base64.decodebytes(b"d3d3LnB5dGhvbi5vcmc=\n"), b"www.python.org") - eq(base64.decodebytes(b"YQ==\n"), b"a") - eq(base64.decodebytes(b"YWI=\n"), b"ab") - eq(base64.decodebytes(b"YWJj\n"), b"abc") - eq(base64.decodebytes(b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" - b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT" - b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n"), - b"abcdefghijklmnopqrstuvwxyz" - b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" - b"0123456789!@#0^&*();:<>,. []{}") - eq(base64.decodebytes(b''), b'') - self.assertRaises(TypeError, base64.decodebytes, "") - - def test_encode(self) -> None: - eq = self.assertEqual - from io import BytesIO - infp = BytesIO(b'abcdefghijklmnopqrstuvwxyz' - b'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - b'0123456789!@#0^&*();:<>,. []{}') - outfp = BytesIO() - base64.encode(infp, outfp) - eq(outfp.getvalue(), - b'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE' - b'RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT' - b'Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n') - - def test_decode(self) -> None: - from io import BytesIO - infp = BytesIO(b'd3d3LnB5dGhvbi5vcmc=') - outfp = BytesIO() - base64.decode(infp, outfp) - self.assertEqual(outfp.getvalue(), b'www.python.org') - - -class BaseXYTestCase(unittest.TestCase): - def test_b64encode(self) -> None: - eq = self.assertEqual - # Test default alphabet - eq(base64.b64encode(b"www.python.org"), b"d3d3LnB5dGhvbi5vcmc=") - eq(base64.b64encode(b'\x00'), b'AA==') - eq(base64.b64encode(b"a"), b"YQ==") - eq(base64.b64encode(b"ab"), b"YWI=") - eq(base64.b64encode(b"abc"), b"YWJj") - eq(base64.b64encode(b""), b"") - eq(base64.b64encode(b"abcdefghijklmnopqrstuvwxyz" - b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" - b"0123456789!@#0^&*();:<>,. []{}"), - b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" - b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NT" - b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==") - # Test with arbitrary alternative characters - eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars=b'*$'), b'01a*b$cd') - # Check if passing a str object raises an error - self.assertRaises(TypeError, base64.b64encode, "") - self.assertRaises(TypeError, base64.b64encode, b"", altchars="") - # Test standard alphabet - eq(base64.standard_b64encode(b"www.python.org"), b"d3d3LnB5dGhvbi5vcmc=") - eq(base64.standard_b64encode(b"a"), b"YQ==") - eq(base64.standard_b64encode(b"ab"), b"YWI=") - eq(base64.standard_b64encode(b"abc"), b"YWJj") - eq(base64.standard_b64encode(b""), b"") - eq(base64.standard_b64encode(b"abcdefghijklmnopqrstuvwxyz" - b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" - b"0123456789!@#0^&*();:<>,. []{}"), - b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" - b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NT" - b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==") - # Check if passing a str object raises an error - self.assertRaises(TypeError, base64.standard_b64encode, "") - self.assertRaises(TypeError, base64.standard_b64encode, b"", altchars="") - # Test with 'URL safe' alternative characters - eq(base64.urlsafe_b64encode(b'\xd3V\xbeo\xf7\x1d'), b'01a-b_cd') - # Check if passing a str object raises an error - self.assertRaises(TypeError, base64.urlsafe_b64encode, "") - - def test_b64decode(self) -> None: - eq = self.assertEqual - eq(base64.b64decode(b"d3d3LnB5dGhvbi5vcmc="), b"www.python.org") - eq(base64.b64decode(b'AA=='), b'\x00') - eq(base64.b64decode(b"YQ=="), b"a") - eq(base64.b64decode(b"YWI="), b"ab") - eq(base64.b64decode(b"YWJj"), b"abc") - eq(base64.b64decode(b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" - b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT" - b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ=="), - b"abcdefghijklmnopqrstuvwxyz" - b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" - b"0123456789!@#0^&*();:<>,. []{}") - eq(base64.b64decode(b''), b'') - # Test with arbitrary alternative characters - eq(base64.b64decode(b'01a*b$cd', altchars=b'*$'), b'\xd3V\xbeo\xf7\x1d') - # Check if passing a str object raises an error - self.assertRaises(TypeError, base64.b64decode, "") - self.assertRaises(TypeError, base64.b64decode, b"", altchars="") - # Test standard alphabet - eq(base64.standard_b64decode(b"d3d3LnB5dGhvbi5vcmc="), b"www.python.org") - eq(base64.standard_b64decode(b"YQ=="), b"a") - eq(base64.standard_b64decode(b"YWI="), b"ab") - eq(base64.standard_b64decode(b"YWJj"), b"abc") - eq(base64.standard_b64decode(b""), b"") - eq(base64.standard_b64decode(b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" - b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NT" - b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ=="), - b"abcdefghijklmnopqrstuvwxyz" - b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" - b"0123456789!@#0^&*();:<>,. []{}") - # Check if passing a str object raises an error - self.assertRaises(TypeError, base64.standard_b64decode, "") - self.assertRaises(TypeError, base64.standard_b64decode, b"", altchars="") - # Test with 'URL safe' alternative characters - eq(base64.urlsafe_b64decode(b'01a-b_cd'), b'\xd3V\xbeo\xf7\x1d') - self.assertRaises(TypeError, base64.urlsafe_b64decode, "") - - def test_b64decode_padding_error(self) -> None: - self.assertRaises(binascii.Error, base64.b64decode, b'abc') - - def test_b64decode_invalid_chars(self) -> None: - # issue 1466065: Test some invalid characters. - tests = ((b'%3d==', b'\xdd'), - (b'$3d==', b'\xdd'), - (b'[==', b''), - (b'YW]3=', b'am'), - (b'3{d==', b'\xdd'), - (b'3d}==', b'\xdd'), - (b'@@', b''), - (b'!', b''), - (b'YWJj\nYWI=', b'abcab')) - for bstr, res in tests: - self.assertEqual(base64.b64decode(bstr), res) - with self.assertRaises(binascii.Error): - base64.b64decode(bstr, validate=True) - - def test_b32encode(self) -> None: - eq = self.assertEqual - eq(base64.b32encode(b''), b'') - eq(base64.b32encode(b'\x00'), b'AA======') - eq(base64.b32encode(b'a'), b'ME======') - eq(base64.b32encode(b'ab'), b'MFRA====') - eq(base64.b32encode(b'abc'), b'MFRGG===') - eq(base64.b32encode(b'abcd'), b'MFRGGZA=') - eq(base64.b32encode(b'abcde'), b'MFRGGZDF') - self.assertRaises(TypeError, base64.b32encode, "") - - def test_b32decode(self) -> None: - eq = self.assertEqual - eq(base64.b32decode(b''), b'') - eq(base64.b32decode(b'AA======'), b'\x00') - eq(base64.b32decode(b'ME======'), b'a') - eq(base64.b32decode(b'MFRA===='), b'ab') - eq(base64.b32decode(b'MFRGG==='), b'abc') - eq(base64.b32decode(b'MFRGGZA='), b'abcd') - eq(base64.b32decode(b'MFRGGZDF'), b'abcde') - self.assertRaises(TypeError, base64.b32decode, "") - - def test_b32decode_casefold(self) -> None: - eq = self.assertEqual - eq(base64.b32decode(b'', True), b'') - eq(base64.b32decode(b'ME======', True), b'a') - eq(base64.b32decode(b'MFRA====', True), b'ab') - eq(base64.b32decode(b'MFRGG===', True), b'abc') - eq(base64.b32decode(b'MFRGGZA=', True), b'abcd') - eq(base64.b32decode(b'MFRGGZDF', True), b'abcde') - # Lower cases - eq(base64.b32decode(b'me======', True), b'a') - eq(base64.b32decode(b'mfra====', True), b'ab') - eq(base64.b32decode(b'mfrgg===', True), b'abc') - eq(base64.b32decode(b'mfrggza=', True), b'abcd') - eq(base64.b32decode(b'mfrggzdf', True), b'abcde') - # Expected exceptions - self.assertRaises(TypeError, base64.b32decode, b'me======') - # Mapping zero and one - eq(base64.b32decode(b'MLO23456'), b'b\xdd\xad\xf3\xbe') - eq(base64.b32decode(b'M1023456', map01=b'L'), b'b\xdd\xad\xf3\xbe') - eq(base64.b32decode(b'M1023456', map01=b'I'), b'b\x1d\xad\xf3\xbe') - self.assertRaises(TypeError, base64.b32decode, b"", map01="") - - def test_b32decode_error(self) -> None: - self.assertRaises(binascii.Error, base64.b32decode, b'abc') - self.assertRaises(binascii.Error, base64.b32decode, b'ABCDEF==') - - def test_b16encode(self) -> None: - eq = self.assertEqual - eq(base64.b16encode(b'\x01\x02\xab\xcd\xef'), b'0102ABCDEF') - eq(base64.b16encode(b'\x00'), b'00') - self.assertRaises(TypeError, base64.b16encode, "") - - def test_b16decode(self) -> None: - eq = self.assertEqual - eq(base64.b16decode(b'0102ABCDEF'), b'\x01\x02\xab\xcd\xef') - eq(base64.b16decode(b'00'), b'\x00') - # Lower case is not allowed without a flag - self.assertRaises(binascii.Error, base64.b16decode, b'0102abcdef') - # Case fold - eq(base64.b16decode(b'0102abcdef', True), b'\x01\x02\xab\xcd\xef') - self.assertRaises(TypeError, base64.b16decode, "") - - def test_ErrorHeritage(self) -> None: - self.assertTrue(issubclass(binascii.Error, ValueError)) - - - -class TestMain(unittest.TestCase): - def get_output(self, *args_tuple: str, **options: Any) -> Any: - args = [sys.executable, '-m', 'base64'] + list(args_tuple) - return subprocess.check_output(args, **options) - - def test_encode_decode(self) -> None: - output = self.get_output('-t') - self.assertSequenceEqual(output.splitlines(), [ - b"b'Aladdin:open sesame'", - br"b'QWxhZGRpbjpvcGVuIHNlc2FtZQ==\n'", - b"b'Aladdin:open sesame'", - ]) - - def test_encode_file(self) -> None: - with open(support.TESTFN, 'wb') as fp: - fp.write(b'a\xffb\n') - - output = self.get_output('-e', support.TESTFN) - self.assertEqual(output.rstrip(), b'Yf9iCg==') - - with open(support.TESTFN, 'rb') as fp: - output = self.get_output('-e', stdin=fp) - self.assertEqual(output.rstrip(), b'Yf9iCg==') - - def test_decode(self) -> None: - with open(support.TESTFN, 'wb') as fp: - fp.write(b'Yf9iCg==') - output = self.get_output('-d', support.TESTFN) - self.assertEqual(output.rstrip(), b'a\xffb') - - - -def test_main() -> None: - support.run_unittest(__name__) - -if __name__ == '__main__': - test_main() diff --git a/test-data/stdlib-samples/3.2/test/test_fnmatch.py b/test-data/stdlib-samples/3.2/test/test_fnmatch.py deleted file mode 100644 index b5309c118be0..000000000000 --- a/test-data/stdlib-samples/3.2/test/test_fnmatch.py +++ /dev/null @@ -1,93 +0,0 @@ -"""Test cases for the fnmatch module.""" - -from test import support -import unittest - -from fnmatch import fnmatch, fnmatchcase, translate, filter - -from typing import Any, AnyStr, Callable - -class FnmatchTestCase(unittest.TestCase): - - def check_match(self, filename: AnyStr, pattern: AnyStr, - should_match: int = 1, - fn: Any = fnmatch) -> None: # see #270 - if should_match: - self.assertTrue(fn(filename, pattern), - "expected %r to match pattern %r" - % (filename, pattern)) - else: - self.assertTrue(not fn(filename, pattern), - "expected %r not to match pattern %r" - % (filename, pattern)) - - def test_fnmatch(self) -> None: - check = self.check_match - check('abc', 'abc') - check('abc', '?*?') - check('abc', '???*') - check('abc', '*???') - check('abc', '???') - check('abc', '*') - check('abc', 'ab[cd]') - check('abc', 'ab[!de]') - check('abc', 'ab[de]', 0) - check('a', '??', 0) - check('a', 'b', 0) - - # these test that '\' is handled correctly in character sets; - # see SF bug #409651 - check('\\', r'[\]') - check('a', r'[!\]') - check('\\', r'[!\]', 0) - - # test that filenames with newlines in them are handled correctly. - # http://bugs.python.org/issue6665 - check('foo\nbar', 'foo*') - check('foo\nbar\n', 'foo*') - check('\nfoo', 'foo*', False) - check('\n', '*') - - def test_mix_bytes_str(self) -> None: - self.assertRaises(TypeError, fnmatch, 'test', b'*') - self.assertRaises(TypeError, fnmatch, b'test', '*') - self.assertRaises(TypeError, fnmatchcase, 'test', b'*') - self.assertRaises(TypeError, fnmatchcase, b'test', '*') - - def test_fnmatchcase(self) -> None: - check = self.check_match - check('AbC', 'abc', 0, fnmatchcase) - check('abc', 'AbC', 0, fnmatchcase) - - def test_bytes(self) -> None: - self.check_match(b'test', b'te*') - self.check_match(b'test\xff', b'te*\xff') - self.check_match(b'foo\nbar', b'foo*') - -class TranslateTestCase(unittest.TestCase): - - def test_translate(self) -> None: - self.assertEqual(translate('*'), r'.*\Z(?ms)') - self.assertEqual(translate('?'), r'.\Z(?ms)') - self.assertEqual(translate('a?b*'), r'a.b.*\Z(?ms)') - self.assertEqual(translate('[abc]'), r'[abc]\Z(?ms)') - self.assertEqual(translate('[]]'), r'[]]\Z(?ms)') - self.assertEqual(translate('[!x]'), r'[^x]\Z(?ms)') - self.assertEqual(translate('[^x]'), r'[\\^x]\Z(?ms)') - self.assertEqual(translate('[x'), r'\\[x\Z(?ms)') - - -class FilterTestCase(unittest.TestCase): - - def test_filter(self) -> None: - self.assertEqual(filter(['a', 'b'], 'a'), ['a']) - - -def test_main() -> None: - support.run_unittest(FnmatchTestCase, - TranslateTestCase, - FilterTestCase) - - -if __name__ == "__main__": - test_main() diff --git a/test-data/stdlib-samples/3.2/test/test_genericpath.py b/test-data/stdlib-samples/3.2/test/test_genericpath.py deleted file mode 100644 index df0e10701d39..000000000000 --- a/test-data/stdlib-samples/3.2/test/test_genericpath.py +++ /dev/null @@ -1,313 +0,0 @@ -""" -Tests common to genericpath, macpath, ntpath and posixpath -""" - -import unittest -from test import support -import os - -import genericpath -import imp -imp.reload(genericpath) # Make sure we are using the local copy - -import sys -from typing import Any, List - - -def safe_rmdir(dirname: str) -> None: - try: - os.rmdir(dirname) - except OSError: - pass - - -class GenericTest(unittest.TestCase): - # The path module to be tested - pathmodule = genericpath # type: Any - common_attributes = ['commonprefix', 'getsize', 'getatime', 'getctime', - 'getmtime', 'exists', 'isdir', 'isfile'] - attributes = [] # type: List[str] - - def test_no_argument(self) -> None: - for attr in self.common_attributes + self.attributes: - with self.assertRaises(TypeError): - getattr(self.pathmodule, attr)() - self.fail("{}.{}() did not raise a TypeError" - .format(self.pathmodule.__name__, attr)) - - def test_commonprefix(self) -> None: - commonprefix = self.pathmodule.commonprefix - self.assertEqual( - commonprefix([]), - "" - ) - self.assertEqual( - commonprefix(["/home/swenson/spam", "/home/swen/spam"]), - "/home/swen" - ) - self.assertEqual( - commonprefix(["/home/swen/spam", "/home/swen/eggs"]), - "/home/swen/" - ) - self.assertEqual( - commonprefix(["/home/swen/spam", "/home/swen/spam"]), - "/home/swen/spam" - ) - self.assertEqual( - commonprefix(["home:swenson:spam", "home:swen:spam"]), - "home:swen" - ) - self.assertEqual( - commonprefix([":home:swen:spam", ":home:swen:eggs"]), - ":home:swen:" - ) - self.assertEqual( - commonprefix([":home:swen:spam", ":home:swen:spam"]), - ":home:swen:spam" - ) - - self.assertEqual( - commonprefix([b"/home/swenson/spam", b"/home/swen/spam"]), - b"/home/swen" - ) - self.assertEqual( - commonprefix([b"/home/swen/spam", b"/home/swen/eggs"]), - b"/home/swen/" - ) - self.assertEqual( - commonprefix([b"/home/swen/spam", b"/home/swen/spam"]), - b"/home/swen/spam" - ) - self.assertEqual( - commonprefix([b"home:swenson:spam", b"home:swen:spam"]), - b"home:swen" - ) - self.assertEqual( - commonprefix([b":home:swen:spam", b":home:swen:eggs"]), - b":home:swen:" - ) - self.assertEqual( - commonprefix([b":home:swen:spam", b":home:swen:spam"]), - b":home:swen:spam" - ) - - testlist = ['', 'abc', 'Xbcd', 'Xb', 'XY', 'abcd', - 'aXc', 'abd', 'ab', 'aX', 'abcX'] - for s1 in testlist: - for s2 in testlist: - p = commonprefix([s1, s2]) - self.assertTrue(s1.startswith(p)) - self.assertTrue(s2.startswith(p)) - if s1 != s2: - n = len(p) - self.assertNotEqual(s1[n:n+1], s2[n:n+1]) - - def test_getsize(self) -> None: - f = open(support.TESTFN, "wb") - try: - f.write(b"foo") - f.close() - self.assertEqual(self.pathmodule.getsize(support.TESTFN), 3) - finally: - if not f.closed: - f.close() - support.unlink(support.TESTFN) - - def test_time(self) -> None: - f = open(support.TESTFN, "wb") - try: - f.write(b"foo") - f.close() - f = open(support.TESTFN, "ab") - f.write(b"bar") - f.close() - f = open(support.TESTFN, "rb") - d = f.read() - f.close() - self.assertEqual(d, b"foobar") - - self.assertLessEqual( - self.pathmodule.getctime(support.TESTFN), - self.pathmodule.getmtime(support.TESTFN) - ) - finally: - if not f.closed: - f.close() - support.unlink(support.TESTFN) - - def test_exists(self) -> None: - self.assertIs(self.pathmodule.exists(support.TESTFN), False) - f = open(support.TESTFN, "wb") - try: - f.write(b"foo") - f.close() - self.assertIs(self.pathmodule.exists(support.TESTFN), True) - if not self.pathmodule == genericpath: - self.assertIs(self.pathmodule.lexists(support.TESTFN), - True) - finally: - if not f.closed: - f.close() - support.unlink(support.TESTFN) - - def test_isdir(self) -> None: - self.assertIs(self.pathmodule.isdir(support.TESTFN), False) - f = open(support.TESTFN, "wb") - try: - f.write(b"foo") - f.close() - self.assertIs(self.pathmodule.isdir(support.TESTFN), False) - os.remove(support.TESTFN) - os.mkdir(support.TESTFN) - self.assertIs(self.pathmodule.isdir(support.TESTFN), True) - os.rmdir(support.TESTFN) - finally: - if not f.closed: - f.close() - support.unlink(support.TESTFN) - safe_rmdir(support.TESTFN) - - def test_isfile(self) -> None: - self.assertIs(self.pathmodule.isfile(support.TESTFN), False) - f = open(support.TESTFN, "wb") - try: - f.write(b"foo") - f.close() - self.assertIs(self.pathmodule.isfile(support.TESTFN), True) - os.remove(support.TESTFN) - os.mkdir(support.TESTFN) - self.assertIs(self.pathmodule.isfile(support.TESTFN), False) - os.rmdir(support.TESTFN) - finally: - if not f.closed: - f.close() - support.unlink(support.TESTFN) - safe_rmdir(support.TESTFN) - - -# Following TestCase is not supposed to be run from test_genericpath. -# It is inherited by other test modules (macpath, ntpath, posixpath). - -class CommonTest(GenericTest): - # The path module to be tested - pathmodule = None # type: Any - common_attributes = GenericTest.common_attributes + [ - # Properties - 'curdir', 'pardir', 'extsep', 'sep', - 'pathsep', 'defpath', 'altsep', 'devnull', - # Methods - 'normcase', 'splitdrive', 'expandvars', 'normpath', 'abspath', - 'join', 'split', 'splitext', 'isabs', 'basename', 'dirname', - 'lexists', 'islink', 'ismount', 'expanduser', 'normpath', 'realpath', - ] - - def test_normcase(self) -> None: - normcase = self.pathmodule.normcase - # check that normcase() is idempotent - for p in ["FoO/./BaR", b"FoO/./BaR"]: - p = normcase(p) - self.assertEqual(p, normcase(p)) - - self.assertEqual(normcase(''), '') - self.assertEqual(normcase(b''), b'') - - # check that normcase raises a TypeError for invalid types - for path in (None, True, 0, 2.5, [], bytearray(b''), {'o','o'}): - self.assertRaises(TypeError, normcase, path) - - def test_splitdrive(self) -> None: - # splitdrive for non-NT paths - splitdrive = self.pathmodule.splitdrive - self.assertEqual(splitdrive("/foo/bar"), ("", "/foo/bar")) - self.assertEqual(splitdrive("foo:bar"), ("", "foo:bar")) - self.assertEqual(splitdrive(":foo:bar"), ("", ":foo:bar")) - - self.assertEqual(splitdrive(b"/foo/bar"), (b"", b"/foo/bar")) - self.assertEqual(splitdrive(b"foo:bar"), (b"", b"foo:bar")) - self.assertEqual(splitdrive(b":foo:bar"), (b"", b":foo:bar")) - - def test_expandvars(self) -> None: - if self.pathmodule.__name__ == 'macpath': - self.skipTest('macpath.expandvars is a stub') - expandvars = self.pathmodule.expandvars - with support.EnvironmentVarGuard() as env: - env.clear() - env["foo"] = "bar" - env["{foo"] = "baz1" - env["{foo}"] = "baz2" - self.assertEqual(expandvars("foo"), "foo") - self.assertEqual(expandvars("$foo bar"), "bar bar") - self.assertEqual(expandvars("${foo}bar"), "barbar") - self.assertEqual(expandvars("$[foo]bar"), "$[foo]bar") - self.assertEqual(expandvars("$bar bar"), "$bar bar") - self.assertEqual(expandvars("$?bar"), "$?bar") - self.assertEqual(expandvars("${foo}bar"), "barbar") - self.assertEqual(expandvars("$foo}bar"), "bar}bar") - self.assertEqual(expandvars("${foo"), "${foo") - self.assertEqual(expandvars("${{foo}}"), "baz1}") - self.assertEqual(expandvars("$foo$foo"), "barbar") - self.assertEqual(expandvars("$bar$bar"), "$bar$bar") - - self.assertEqual(expandvars(b"foo"), b"foo") - self.assertEqual(expandvars(b"$foo bar"), b"bar bar") - self.assertEqual(expandvars(b"${foo}bar"), b"barbar") - self.assertEqual(expandvars(b"$[foo]bar"), b"$[foo]bar") - self.assertEqual(expandvars(b"$bar bar"), b"$bar bar") - self.assertEqual(expandvars(b"$?bar"), b"$?bar") - self.assertEqual(expandvars(b"${foo}bar"), b"barbar") - self.assertEqual(expandvars(b"$foo}bar"), b"bar}bar") - self.assertEqual(expandvars(b"${foo"), b"${foo") - self.assertEqual(expandvars(b"${{foo}}"), b"baz1}") - self.assertEqual(expandvars(b"$foo$foo"), b"barbar") - self.assertEqual(expandvars(b"$bar$bar"), b"$bar$bar") - - def test_abspath(self) -> None: - self.assertIn("foo", self.pathmodule.abspath("foo")) - self.assertIn(b"foo", self.pathmodule.abspath(b"foo")) - - # Abspath returns bytes when the arg is bytes - for path in (b'', b'foo', b'f\xf2\xf2', b'/foo', b'C:\\'): - self.assertIsInstance(self.pathmodule.abspath(path), bytes) - - def test_realpath(self) -> None: - self.assertIn("foo", self.pathmodule.realpath("foo")) - self.assertIn(b"foo", self.pathmodule.realpath(b"foo")) - - def test_normpath_issue5827(self) -> None: - # Make sure normpath preserves unicode - for path in ('', '.', '/', '\\', '///foo/.//bar//'): - self.assertIsInstance(self.pathmodule.normpath(path), str) - - def test_abspath_issue3426(self) -> None: - # Check that abspath returns unicode when the arg is unicode - # with both ASCII and non-ASCII cwds. - abspath = self.pathmodule.abspath - for path in ('', 'fuu', 'f\xf9\xf9', '/fuu', 'U:\\'): - self.assertIsInstance(abspath(path), str) - - unicwd = '\xe7w\xf0' - try: - fsencoding = support.TESTFN_ENCODING or "ascii" - unicwd.encode(fsencoding) - except (AttributeError, UnicodeEncodeError): - # FS encoding is probably ASCII - pass - else: - with support.temp_cwd(unicwd): - for path in ('', 'fuu', 'f\xf9\xf9', '/fuu', 'U:\\'): - self.assertIsInstance(abspath(path), str) - - @unittest.skipIf(sys.platform == 'darwin', - "Mac OS X denies the creation of a directory with an invalid utf8 name") - def test_nonascii_abspath(self) -> None: - # Test non-ASCII, non-UTF8 bytes in the path. - with support.temp_cwd(b'\xe7w\xf0'): - self.test_abspath() - - -def test_main() -> None: - support.run_unittest(GenericTest) - - -if __name__=="__main__": - test_main() diff --git a/test-data/stdlib-samples/3.2/test/test_getopt.py b/test-data/stdlib-samples/3.2/test/test_getopt.py deleted file mode 100644 index 33205521ebd2..000000000000 --- a/test-data/stdlib-samples/3.2/test/test_getopt.py +++ /dev/null @@ -1,190 +0,0 @@ -# test_getopt.py -# David Goodger 2000-08-19 - -from test.support import verbose, run_doctest, run_unittest, EnvironmentVarGuard -import unittest - -import getopt - -from typing import cast, Any - -sentinel = object() - -class GetoptTests(unittest.TestCase): - def setUp(self) -> None: - self.env = EnvironmentVarGuard() - if "POSIXLY_CORRECT" in self.env: - del self.env["POSIXLY_CORRECT"] - - def tearDown(self) -> None: - self.env.__exit__() - del self.env - - def assertError(self, *args: Any, **kwargs: Any) -> None: - # JLe: work around mypy bug #229 - cast(Any, self.assertRaises)(getopt.GetoptError, *args, **kwargs) - - def test_short_has_arg(self) -> None: - self.assertTrue(getopt.short_has_arg('a', 'a:')) - self.assertFalse(getopt.short_has_arg('a', 'a')) - self.assertError(getopt.short_has_arg, 'a', 'b') - - def test_long_has_args(self) -> None: - has_arg, option = getopt.long_has_args('abc', ['abc=']) - self.assertTrue(has_arg) - self.assertEqual(option, 'abc') - - has_arg, option = getopt.long_has_args('abc', ['abc']) - self.assertFalse(has_arg) - self.assertEqual(option, 'abc') - - has_arg, option = getopt.long_has_args('abc', ['abcd']) - self.assertFalse(has_arg) - self.assertEqual(option, 'abcd') - - self.assertError(getopt.long_has_args, 'abc', ['def']) - self.assertError(getopt.long_has_args, 'abc', []) - self.assertError(getopt.long_has_args, 'abc', ['abcd','abcde']) - - def test_do_shorts(self) -> None: - opts, args = getopt.do_shorts([], 'a', 'a', []) - self.assertEqual(opts, [('-a', '')]) - self.assertEqual(args, []) - - opts, args = getopt.do_shorts([], 'a1', 'a:', []) - self.assertEqual(opts, [('-a', '1')]) - self.assertEqual(args, []) - - #opts, args = getopt.do_shorts([], 'a=1', 'a:', []) - #self.assertEqual(opts, [('-a', '1')]) - #self.assertEqual(args, []) - - opts, args = getopt.do_shorts([], 'a', 'a:', ['1']) - self.assertEqual(opts, [('-a', '1')]) - self.assertEqual(args, []) - - opts, args = getopt.do_shorts([], 'a', 'a:', ['1', '2']) - self.assertEqual(opts, [('-a', '1')]) - self.assertEqual(args, ['2']) - - self.assertError(getopt.do_shorts, [], 'a1', 'a', []) - self.assertError(getopt.do_shorts, [], 'a', 'a:', []) - - def test_do_longs(self) -> None: - opts, args = getopt.do_longs([], 'abc', ['abc'], []) - self.assertEqual(opts, [('--abc', '')]) - self.assertEqual(args, []) - - opts, args = getopt.do_longs([], 'abc=1', ['abc='], []) - self.assertEqual(opts, [('--abc', '1')]) - self.assertEqual(args, []) - - opts, args = getopt.do_longs([], 'abc=1', ['abcd='], []) - self.assertEqual(opts, [('--abcd', '1')]) - self.assertEqual(args, []) - - opts, args = getopt.do_longs([], 'abc', ['ab', 'abc', 'abcd'], []) - self.assertEqual(opts, [('--abc', '')]) - self.assertEqual(args, []) - - # Much like the preceding, except with a non-alpha character ("-") in - # option name that precedes "="; failed in - # http://python.org/sf/126863 - opts, args = getopt.do_longs([], 'foo=42', ['foo-bar', 'foo=',], []) - self.assertEqual(opts, [('--foo', '42')]) - self.assertEqual(args, []) - - self.assertError(getopt.do_longs, [], 'abc=1', ['abc'], []) - self.assertError(getopt.do_longs, [], 'abc', ['abc='], []) - - def test_getopt(self) -> None: - # note: the empty string between '-a' and '--beta' is significant: - # it simulates an empty string option argument ('-a ""') on the - # command line. - cmdline = ['-a', '1', '-b', '--alpha=2', '--beta', '-a', '3', '-a', - '', '--beta', 'arg1', 'arg2'] - - opts, args = getopt.getopt(cmdline, 'a:b', ['alpha=', 'beta']) - self.assertEqual(opts, [('-a', '1'), ('-b', ''), - ('--alpha', '2'), ('--beta', ''), - ('-a', '3'), ('-a', ''), ('--beta', '')]) - # Note ambiguity of ('-b', '') and ('-a', '') above. This must be - # accounted for in the code that calls getopt(). - self.assertEqual(args, ['arg1', 'arg2']) - - self.assertError(getopt.getopt, cmdline, 'a:b', ['alpha', 'beta']) - - def test_gnu_getopt(self) -> None: - # Test handling of GNU style scanning mode. - cmdline = ['-a', 'arg1', '-b', '1', '--alpha', '--beta=2'] - - # GNU style - opts, args = getopt.gnu_getopt(cmdline, 'ab:', ['alpha', 'beta=']) - self.assertEqual(args, ['arg1']) - self.assertEqual(opts, [('-a', ''), ('-b', '1'), - ('--alpha', ''), ('--beta', '2')]) - - # recognize "-" as an argument - opts, args = getopt.gnu_getopt(['-a', '-', '-b', '-'], 'ab:', []) - self.assertEqual(args, ['-']) - self.assertEqual(opts, [('-a', ''), ('-b', '-')]) - - # Posix style via + - opts, args = getopt.gnu_getopt(cmdline, '+ab:', ['alpha', 'beta=']) - self.assertEqual(opts, [('-a', '')]) - self.assertEqual(args, ['arg1', '-b', '1', '--alpha', '--beta=2']) - - # Posix style via POSIXLY_CORRECT - self.env["POSIXLY_CORRECT"] = "1" - opts, args = getopt.gnu_getopt(cmdline, 'ab:', ['alpha', 'beta=']) - self.assertEqual(opts, [('-a', '')]) - self.assertEqual(args, ['arg1', '-b', '1', '--alpha', '--beta=2']) - - def test_libref_examples(self) -> None: - s = """ - Examples from the Library Reference: Doc/lib/libgetopt.tex - - An example using only Unix style options: - - - >>> import getopt - >>> args = '-a -b -cfoo -d bar a1 a2'.split() - >>> args - ['-a', '-b', '-cfoo', '-d', 'bar', 'a1', 'a2'] - >>> optlist, args = getopt.getopt(args, 'abc:d:') - >>> optlist - [('-a', ''), ('-b', ''), ('-c', 'foo'), ('-d', 'bar')] - >>> args - ['a1', 'a2'] - - Using long option names is equally easy: - - - >>> s = '--condition=foo --testing --output-file abc.def -x a1 a2' - >>> args = s.split() - >>> args - ['--condition=foo', '--testing', '--output-file', 'abc.def', '-x', 'a1', 'a2'] - >>> optlist, args = getopt.getopt(args, 'x', [ - ... 'condition=', 'output-file=', 'testing']) - >>> optlist - [('--condition', 'foo'), ('--testing', ''), ('--output-file', 'abc.def'), ('-x', '')] - >>> args - ['a1', 'a2'] - """ - - import types - m = types.ModuleType("libreftest", s) - run_doctest(m, verbose) - - def test_issue4629(self) -> None: - longopts, shortopts = getopt.getopt(['--help='], '', ['help=']) - self.assertEqual(longopts, [('--help', '')]) - longopts, shortopts = getopt.getopt(['--help=x'], '', ['help=']) - self.assertEqual(longopts, [('--help', 'x')]) - self.assertRaises(getopt.GetoptError, getopt.getopt, ['--help='], '', ['help']) - -def test_main() -> None: - run_unittest(GetoptTests) - -if __name__ == "__main__": - test_main() diff --git a/test-data/stdlib-samples/3.2/test/test_glob.py b/test-data/stdlib-samples/3.2/test/test_glob.py deleted file mode 100644 index 08c8932c5759..000000000000 --- a/test-data/stdlib-samples/3.2/test/test_glob.py +++ /dev/null @@ -1,122 +0,0 @@ -import unittest -from test.support import run_unittest, TESTFN, skip_unless_symlink, can_symlink -import glob -import os -import shutil - -from typing import TypeVar, Iterable, List, cast - -T = TypeVar('T') - -class GlobTests(unittest.TestCase): - - tempdir = '' - - # JLe: work around mypy issue #231 - def norm(self, first: str, *parts: str) -> str: - return os.path.normpath(os.path.join(self.tempdir, first, *parts)) - - def mktemp(self, *parts: str) -> None: - filename = self.norm(*parts) - base, file = os.path.split(filename) - if not os.path.exists(base): - os.makedirs(base) - f = open(filename, 'w') - f.close() - - def setUp(self) -> None: - self.tempdir = TESTFN+"_dir" - self.mktemp('a', 'D') - self.mktemp('aab', 'F') - self.mktemp('aaa', 'zzzF') - self.mktemp('ZZZ') - self.mktemp('a', 'bcd', 'EF') - self.mktemp('a', 'bcd', 'efg', 'ha') - if can_symlink(): - os.symlink(self.norm('broken'), self.norm('sym1')) - os.symlink(self.norm('broken'), self.norm('sym2')) - - def tearDown(self) -> None: - shutil.rmtree(self.tempdir) - - def glob(self, *parts: str) -> List[str]: - if len(parts) == 1: - pattern = parts[0] - else: - pattern = os.path.join(*parts) - p = os.path.join(self.tempdir, pattern) - res = glob.glob(p) - self.assertEqual(list(glob.iglob(p)), res) - return res - - def assertSequencesEqual_noorder(self, l1: Iterable[T], - l2: Iterable[T]) -> None: - self.assertEqual(set(l1), set(l2)) - - def test_glob_literal(self) -> None: - eq = self.assertSequencesEqual_noorder - eq(self.glob('a'), [self.norm('a')]) - eq(self.glob('a', 'D'), [self.norm('a', 'D')]) - eq(self.glob('aab'), [self.norm('aab')]) - eq(self.glob('zymurgy'), cast(List[str], [])) # JLe: work around #230 - - # test return types are unicode, but only if os.listdir - # returns unicode filenames - uniset = set([str]) - tmp = os.listdir('.') - if set(type(x) for x in tmp) == uniset: - u1 = glob.glob('*') - u2 = glob.glob('./*') - self.assertEqual(set(type(r) for r in u1), uniset) - self.assertEqual(set(type(r) for r in u2), uniset) - - def test_glob_one_directory(self) -> None: - eq = self.assertSequencesEqual_noorder - eq(self.glob('a*'), map(self.norm, ['a', 'aab', 'aaa'])) - eq(self.glob('*a'), map(self.norm, ['a', 'aaa'])) - eq(self.glob('aa?'), map(self.norm, ['aaa', 'aab'])) - eq(self.glob('aa[ab]'), map(self.norm, ['aaa', 'aab'])) - eq(self.glob('*q'), cast(List[str], [])) # JLe: work around #230 - - def test_glob_nested_directory(self) -> None: - eq = self.assertSequencesEqual_noorder - if os.path.normcase("abCD") == "abCD": - # case-sensitive filesystem - eq(self.glob('a', 'bcd', 'E*'), [self.norm('a', 'bcd', 'EF')]) - else: - # case insensitive filesystem - eq(self.glob('a', 'bcd', 'E*'), [self.norm('a', 'bcd', 'EF'), - self.norm('a', 'bcd', 'efg')]) - eq(self.glob('a', 'bcd', '*g'), [self.norm('a', 'bcd', 'efg')]) - - def test_glob_directory_names(self) -> None: - eq = self.assertSequencesEqual_noorder - eq(self.glob('*', 'D'), [self.norm('a', 'D')]) - eq(self.glob('*', '*a'), cast(List[str], [])) # JLe: work around #230 - eq(self.glob('a', '*', '*', '*a'), - [self.norm('a', 'bcd', 'efg', 'ha')]) - eq(self.glob('?a?', '*F'), map(self.norm, [os.path.join('aaa', 'zzzF'), - os.path.join('aab', 'F')])) - - def test_glob_directory_with_trailing_slash(self) -> None: - # We are verifying that when there is wildcard pattern which - # ends with os.sep doesn't blow up. - res = glob.glob(self.tempdir + '*' + os.sep) - self.assertEqual(len(res), 1) - # either of these results are reasonable - self.assertIn(res[0], [self.tempdir, self.tempdir + os.sep]) - - @skip_unless_symlink - def test_glob_broken_symlinks(self) -> None: - eq = self.assertSequencesEqual_noorder - eq(self.glob('sym*'), [self.norm('sym1'), self.norm('sym2')]) - eq(self.glob('sym1'), [self.norm('sym1')]) - eq(self.glob('sym2'), [self.norm('sym2')]) - - -def test_main() -> None: - run_unittest(GlobTests) - - -if __name__ == "__main__": - test_main() diff --git a/test-data/stdlib-samples/3.2/test/test_posixpath.py b/test-data/stdlib-samples/3.2/test/test_posixpath.py deleted file mode 100644 index de98975ad92e..000000000000 --- a/test-data/stdlib-samples/3.2/test/test_posixpath.py +++ /dev/null @@ -1,531 +0,0 @@ -import unittest -from test import support, test_genericpath - -import posixpath -import genericpath - -import imp -imp.reload(posixpath) # Make sure we are using the local copy -imp.reload(genericpath) - -import os -import sys -from posixpath import realpath, abspath, dirname, basename - -import posix -from typing import cast, Any, TypeVar, Callable - -T = TypeVar('T') - -# An absolute path to a temporary filename for testing. We can't rely on TESTFN -# being an absolute path, so we need this. - -ABSTFN = abspath(support.TESTFN) - -def skip_if_ABSTFN_contains_backslash( - test: Callable[[T], None]) -> Callable[[T], None]: - """ - On Windows, posixpath.abspath still returns paths with backslashes - instead of posix forward slashes. If this is the case, several tests - fail, so skip them. - """ - found_backslash = '\\' in ABSTFN - msg = "ABSTFN is not a posix path - tests fail" - return [test, unittest.skip(msg)(test)][found_backslash] - -def safe_rmdir(dirname: str) -> None: - try: - os.rmdir(dirname) - except OSError: - pass - -class PosixPathTest(unittest.TestCase): - - def setUp(self) -> None: - self.tearDown() - - def tearDown(self) -> None: - for suffix in ["", "1", "2"]: - support.unlink(support.TESTFN + suffix) - safe_rmdir(support.TESTFN + suffix) - - def test_join(self) -> None: - self.assertEqual(posixpath.join("/foo", "bar", "/bar", "baz"), - "/bar/baz") - self.assertEqual(posixpath.join("/foo", "bar", "baz"), "/foo/bar/baz") - self.assertEqual(posixpath.join("/foo/", "bar/", "baz/"), - "/foo/bar/baz/") - - self.assertEqual(posixpath.join(b"/foo", b"bar", b"/bar", b"baz"), - b"/bar/baz") - self.assertEqual(posixpath.join(b"/foo", b"bar", b"baz"), - b"/foo/bar/baz") - self.assertEqual(posixpath.join(b"/foo/", b"bar/", b"baz/"), - b"/foo/bar/baz/") - - self.assertRaises(TypeError, posixpath.join, b"bytes", "str") - self.assertRaises(TypeError, posixpath.join, "str", b"bytes") - - def test_split(self) -> None: - self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar")) - self.assertEqual(posixpath.split("/"), ("/", "")) - self.assertEqual(posixpath.split("foo"), ("", "foo")) - self.assertEqual(posixpath.split("////foo"), ("////", "foo")) - self.assertEqual(posixpath.split("//foo//bar"), ("//foo", "bar")) - - self.assertEqual(posixpath.split(b"/foo/bar"), (b"/foo", b"bar")) - self.assertEqual(posixpath.split(b"/"), (b"/", b"")) - self.assertEqual(posixpath.split(b"foo"), (b"", b"foo")) - self.assertEqual(posixpath.split(b"////foo"), (b"////", b"foo")) - self.assertEqual(posixpath.split(b"//foo//bar"), (b"//foo", b"bar")) - - def splitextTest(self, path: str, filename: str, ext: str) -> None: - self.assertEqual(posixpath.splitext(path), (filename, ext)) - self.assertEqual(posixpath.splitext("/" + path), ("/" + filename, ext)) - self.assertEqual(posixpath.splitext("abc/" + path), - ("abc/" + filename, ext)) - self.assertEqual(posixpath.splitext("abc.def/" + path), - ("abc.def/" + filename, ext)) - self.assertEqual(posixpath.splitext("/abc.def/" + path), - ("/abc.def/" + filename, ext)) - self.assertEqual(posixpath.splitext(path + "/"), - (filename + ext + "/", "")) - - pathb = bytes(path, "ASCII") - filenameb = bytes(filename, "ASCII") - extb = bytes(ext, "ASCII") - - self.assertEqual(posixpath.splitext(pathb), (filenameb, extb)) - self.assertEqual(posixpath.splitext(b"/" + pathb), - (b"/" + filenameb, extb)) - self.assertEqual(posixpath.splitext(b"abc/" + pathb), - (b"abc/" + filenameb, extb)) - self.assertEqual(posixpath.splitext(b"abc.def/" + pathb), - (b"abc.def/" + filenameb, extb)) - self.assertEqual(posixpath.splitext(b"/abc.def/" + pathb), - (b"/abc.def/" + filenameb, extb)) - self.assertEqual(posixpath.splitext(pathb + b"/"), - (filenameb + extb + b"/", b"")) - - def test_splitext(self) -> None: - self.splitextTest("foo.bar", "foo", ".bar") - self.splitextTest("foo.boo.bar", "foo.boo", ".bar") - self.splitextTest("foo.boo.biff.bar", "foo.boo.biff", ".bar") - self.splitextTest(".csh.rc", ".csh", ".rc") - self.splitextTest("nodots", "nodots", "") - self.splitextTest(".cshrc", ".cshrc", "") - self.splitextTest("...manydots", "...manydots", "") - self.splitextTest("...manydots.ext", "...manydots", ".ext") - self.splitextTest(".", ".", "") - self.splitextTest("..", "..", "") - self.splitextTest("........", "........", "") - self.splitextTest("", "", "") - - def test_isabs(self) -> None: - self.assertIs(posixpath.isabs(""), False) - self.assertIs(posixpath.isabs("/"), True) - self.assertIs(posixpath.isabs("/foo"), True) - self.assertIs(posixpath.isabs("/foo/bar"), True) - self.assertIs(posixpath.isabs("foo/bar"), False) - - self.assertIs(posixpath.isabs(b""), False) - self.assertIs(posixpath.isabs(b"/"), True) - self.assertIs(posixpath.isabs(b"/foo"), True) - self.assertIs(posixpath.isabs(b"/foo/bar"), True) - self.assertIs(posixpath.isabs(b"foo/bar"), False) - - def test_basename(self) -> None: - self.assertEqual(posixpath.basename("/foo/bar"), "bar") - self.assertEqual(posixpath.basename("/"), "") - self.assertEqual(posixpath.basename("foo"), "foo") - self.assertEqual(posixpath.basename("////foo"), "foo") - self.assertEqual(posixpath.basename("//foo//bar"), "bar") - - self.assertEqual(posixpath.basename(b"/foo/bar"), b"bar") - self.assertEqual(posixpath.basename(b"/"), b"") - self.assertEqual(posixpath.basename(b"foo"), b"foo") - self.assertEqual(posixpath.basename(b"////foo"), b"foo") - self.assertEqual(posixpath.basename(b"//foo//bar"), b"bar") - - def test_dirname(self) -> None: - self.assertEqual(posixpath.dirname("/foo/bar"), "/foo") - self.assertEqual(posixpath.dirname("/"), "/") - self.assertEqual(posixpath.dirname("foo"), "") - self.assertEqual(posixpath.dirname("////foo"), "////") - self.assertEqual(posixpath.dirname("//foo//bar"), "//foo") - - self.assertEqual(posixpath.dirname(b"/foo/bar"), b"/foo") - self.assertEqual(posixpath.dirname(b"/"), b"/") - self.assertEqual(posixpath.dirname(b"foo"), b"") - self.assertEqual(posixpath.dirname(b"////foo"), b"////") - self.assertEqual(posixpath.dirname(b"//foo//bar"), b"//foo") - - def test_islink(self) -> None: - self.assertIs(posixpath.islink(support.TESTFN + "1"), False) - self.assertIs(posixpath.lexists(support.TESTFN + "2"), False) - f = open(support.TESTFN + "1", "wb") - try: - f.write(b"foo") - f.close() - self.assertIs(posixpath.islink(support.TESTFN + "1"), False) - if support.can_symlink(): - os.symlink(support.TESTFN + "1", support.TESTFN + "2") - self.assertIs(posixpath.islink(support.TESTFN + "2"), True) - os.remove(support.TESTFN + "1") - self.assertIs(posixpath.islink(support.TESTFN + "2"), True) - self.assertIs(posixpath.exists(support.TESTFN + "2"), False) - self.assertIs(posixpath.lexists(support.TESTFN + "2"), True) - finally: - if not f.closed: - f.close() - - @staticmethod - def _create_file(filename: str) -> None: - with open(filename, 'wb') as f: - f.write(b'foo') - - def test_samefile(self) -> None: - test_fn = support.TESTFN + "1" - self._create_file(test_fn) - self.assertTrue(posixpath.samefile(test_fn, test_fn)) - self.assertRaises(TypeError, posixpath.samefile) - - @unittest.skipIf( - sys.platform.startswith('win'), - "posixpath.samefile does not work on links in Windows") - @unittest.skipUnless(hasattr(os, "symlink"), - "Missing symlink implementation") - def test_samefile_on_links(self) -> None: - test_fn1 = support.TESTFN + "1" - test_fn2 = support.TESTFN + "2" - self._create_file(test_fn1) - - os.symlink(test_fn1, test_fn2) - self.assertTrue(posixpath.samefile(test_fn1, test_fn2)) - os.remove(test_fn2) - - self._create_file(test_fn2) - self.assertFalse(posixpath.samefile(test_fn1, test_fn2)) - - - def test_samestat(self) -> None: - test_fn = support.TESTFN + "1" - self._create_file(test_fn) - test_fns = [test_fn]*2 - stats = map(os.stat, test_fns) - self.assertTrue(posixpath.samestat(*stats)) - - @unittest.skipIf( - sys.platform.startswith('win'), - "posixpath.samestat does not work on links in Windows") - @unittest.skipUnless(hasattr(os, "symlink"), - "Missing symlink implementation") - def test_samestat_on_links(self) -> None: - test_fn1 = support.TESTFN + "1" - test_fn2 = support.TESTFN + "2" - self._create_file(test_fn1) - test_fns = [test_fn1, test_fn2] - cast(Any, os.symlink)(*test_fns) - stats = map(os.stat, test_fns) - self.assertTrue(posixpath.samestat(*stats)) - os.remove(test_fn2) - - self._create_file(test_fn2) - stats = map(os.stat, test_fns) - self.assertFalse(posixpath.samestat(*stats)) - - self.assertRaises(TypeError, posixpath.samestat) - - def test_ismount(self) -> None: - self.assertIs(posixpath.ismount("/"), True) - self.assertIs(posixpath.ismount(b"/"), True) - - def test_ismount_non_existent(self) -> None: - # Non-existent mountpoint. - self.assertIs(posixpath.ismount(ABSTFN), False) - try: - os.mkdir(ABSTFN) - self.assertIs(posixpath.ismount(ABSTFN), False) - finally: - safe_rmdir(ABSTFN) - - @unittest.skipUnless(support.can_symlink(), - "Test requires symlink support") - def test_ismount_symlinks(self) -> None: - # Symlinks are never mountpoints. - try: - os.symlink("/", ABSTFN) - self.assertIs(posixpath.ismount(ABSTFN), False) - finally: - os.unlink(ABSTFN) - - @unittest.skipIf(posix is None, "Test requires posix module") - def test_ismount_different_device(self) -> None: - # Simulate the path being on a different device from its parent by - # mocking out st_dev. - save_lstat = os.lstat - def fake_lstat(path): - st_ino = 0 - st_dev = 0 - if path == ABSTFN: - st_dev = 1 - st_ino = 1 - return posix.stat_result((0, st_ino, st_dev, 0, 0, 0, 0, 0, 0, 0)) - try: - setattr(os, 'lstat', fake_lstat) # mypy: can't modify os directly - self.assertIs(posixpath.ismount(ABSTFN), True) - finally: - setattr(os, 'lstat', save_lstat) - - def test_expanduser(self) -> None: - self.assertEqual(posixpath.expanduser("foo"), "foo") - self.assertEqual(posixpath.expanduser(b"foo"), b"foo") - try: - import pwd - except ImportError: - pass - else: - self.assertIsInstance(posixpath.expanduser("~/"), str) - self.assertIsInstance(posixpath.expanduser(b"~/"), bytes) - # if home directory == root directory, this test makes no sense - if posixpath.expanduser("~") != '/': - self.assertEqual( - posixpath.expanduser("~") + "/", - posixpath.expanduser("~/") - ) - self.assertEqual( - posixpath.expanduser(b"~") + b"/", - posixpath.expanduser(b"~/") - ) - self.assertIsInstance(posixpath.expanduser("~root/"), str) - self.assertIsInstance(posixpath.expanduser("~foo/"), str) - self.assertIsInstance(posixpath.expanduser(b"~root/"), bytes) - self.assertIsInstance(posixpath.expanduser(b"~foo/"), bytes) - - with support.EnvironmentVarGuard() as env: - env['HOME'] = '/' - self.assertEqual(posixpath.expanduser("~"), "/") - # expanduser should fall back to using the password database - del env['HOME'] - home = pwd.getpwuid(os.getuid()).pw_dir - self.assertEqual(posixpath.expanduser("~"), home) - - def test_normpath(self) -> None: - self.assertEqual(posixpath.normpath(""), ".") - self.assertEqual(posixpath.normpath("/"), "/") - self.assertEqual(posixpath.normpath("//"), "//") - self.assertEqual(posixpath.normpath("///"), "/") - self.assertEqual(posixpath.normpath("///foo/.//bar//"), "/foo/bar") - self.assertEqual(posixpath.normpath("///foo/.//bar//.//..//.//baz"), - "/foo/baz") - self.assertEqual(posixpath.normpath("///..//./foo/.//bar"), "/foo/bar") - - self.assertEqual(posixpath.normpath(b""), b".") - self.assertEqual(posixpath.normpath(b"/"), b"/") - self.assertEqual(posixpath.normpath(b"//"), b"//") - self.assertEqual(posixpath.normpath(b"///"), b"/") - self.assertEqual(posixpath.normpath(b"///foo/.//bar//"), b"/foo/bar") - self.assertEqual(posixpath.normpath(b"///foo/.//bar//.//..//.//baz"), - b"/foo/baz") - self.assertEqual(posixpath.normpath(b"///..//./foo/.//bar"), - b"/foo/bar") - - @unittest.skipUnless(hasattr(os, "symlink"), - "Missing symlink implementation") - @skip_if_ABSTFN_contains_backslash - def test_realpath_basic(self) -> None: - # Basic operation. - try: - os.symlink(ABSTFN+"1", ABSTFN) - self.assertEqual(realpath(ABSTFN), ABSTFN+"1") - finally: - support.unlink(ABSTFN) - - @unittest.skipUnless(hasattr(os, "symlink"), - "Missing symlink implementation") - @skip_if_ABSTFN_contains_backslash - def test_realpath_relative(self) -> None: - try: - os.symlink(posixpath.relpath(ABSTFN+"1"), ABSTFN) - self.assertEqual(realpath(ABSTFN), ABSTFN+"1") - finally: - support.unlink(ABSTFN) - - @unittest.skipUnless(hasattr(os, "symlink"), - "Missing symlink implementation") - @skip_if_ABSTFN_contains_backslash - def test_realpath_symlink_loops(self) -> None: - # Bug #930024, return the path unchanged if we get into an infinite - # symlink loop. - try: - old_path = abspath('.') - os.symlink(ABSTFN, ABSTFN) - self.assertEqual(realpath(ABSTFN), ABSTFN) - - os.symlink(ABSTFN+"1", ABSTFN+"2") - os.symlink(ABSTFN+"2", ABSTFN+"1") - self.assertEqual(realpath(ABSTFN+"1"), ABSTFN+"1") - self.assertEqual(realpath(ABSTFN+"2"), ABSTFN+"2") - - # Test using relative path as well. - os.chdir(dirname(ABSTFN)) - self.assertEqual(realpath(basename(ABSTFN)), ABSTFN) - finally: - os.chdir(old_path) - support.unlink(ABSTFN) - support.unlink(ABSTFN+"1") - support.unlink(ABSTFN+"2") - - @unittest.skipUnless(hasattr(os, "symlink"), - "Missing symlink implementation") - @skip_if_ABSTFN_contains_backslash - def test_realpath_resolve_parents(self) -> None: - # We also need to resolve any symlinks in the parents of a relative - # path passed to realpath. E.g.: current working directory is - # /usr/doc with 'doc' being a symlink to /usr/share/doc. We call - # realpath("a"). This should return /usr/share/doc/a/. - try: - old_path = abspath('.') - os.mkdir(ABSTFN) - os.mkdir(ABSTFN + "/y") - os.symlink(ABSTFN + "/y", ABSTFN + "/k") - - os.chdir(ABSTFN + "/k") - self.assertEqual(realpath("a"), ABSTFN + "/y/a") - finally: - os.chdir(old_path) - support.unlink(ABSTFN + "/k") - safe_rmdir(ABSTFN + "/y") - safe_rmdir(ABSTFN) - - @unittest.skipUnless(hasattr(os, "symlink"), - "Missing symlink implementation") - @skip_if_ABSTFN_contains_backslash - def test_realpath_resolve_before_normalizing(self) -> None: - # Bug #990669: Symbolic links should be resolved before we - # normalize the path. E.g.: if we have directories 'a', 'k' and 'y' - # in the following hierarchy: - # a/k/y - # - # and a symbolic link 'link-y' pointing to 'y' in directory 'a', - # then realpath("link-y/..") should return 'k', not 'a'. - try: - old_path = abspath('.') - os.mkdir(ABSTFN) - os.mkdir(ABSTFN + "/k") - os.mkdir(ABSTFN + "/k/y") - os.symlink(ABSTFN + "/k/y", ABSTFN + "/link-y") - - # Absolute path. - self.assertEqual(realpath(ABSTFN + "/link-y/.."), ABSTFN + "/k") - # Relative path. - os.chdir(dirname(ABSTFN)) - self.assertEqual(realpath(basename(ABSTFN) + "/link-y/.."), - ABSTFN + "/k") - finally: - os.chdir(old_path) - support.unlink(ABSTFN + "/link-y") - safe_rmdir(ABSTFN + "/k/y") - safe_rmdir(ABSTFN + "/k") - safe_rmdir(ABSTFN) - - @unittest.skipUnless(hasattr(os, "symlink"), - "Missing symlink implementation") - @skip_if_ABSTFN_contains_backslash - def test_realpath_resolve_first(self) -> None: - # Bug #1213894: The first component of the path, if not absolute, - # must be resolved too. - - try: - old_path = abspath('.') - os.mkdir(ABSTFN) - os.mkdir(ABSTFN + "/k") - os.symlink(ABSTFN, ABSTFN + "link") - os.chdir(dirname(ABSTFN)) - - base = basename(ABSTFN) - self.assertEqual(realpath(base + "link"), ABSTFN) - self.assertEqual(realpath(base + "link/k"), ABSTFN + "/k") - finally: - os.chdir(old_path) - support.unlink(ABSTFN + "link") - safe_rmdir(ABSTFN + "/k") - safe_rmdir(ABSTFN) - - def test_relpath(self) -> None: - real_getcwd = os.getcwd - # mypy: can't modify os directly - setattr(os, 'getcwd', lambda: r"/home/user/bar") - try: - curdir = os.path.split(os.getcwd())[-1] - self.assertRaises(ValueError, posixpath.relpath, "") - self.assertEqual(posixpath.relpath("a"), "a") - self.assertEqual(posixpath.relpath(posixpath.abspath("a")), "a") - self.assertEqual(posixpath.relpath("a/b"), "a/b") - self.assertEqual(posixpath.relpath("../a/b"), "../a/b") - self.assertEqual(posixpath.relpath("a", "../b"), "../"+curdir+"/a") - self.assertEqual(posixpath.relpath("a/b", "../c"), - "../"+curdir+"/a/b") - self.assertEqual(posixpath.relpath("a", "b/c"), "../../a") - self.assertEqual(posixpath.relpath("a", "a"), ".") - self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x/y/z"), '../../../foo/bar/bat') - self.assertEqual(posixpath.relpath("/foo/bar/bat", "/foo/bar"), 'bat') - self.assertEqual(posixpath.relpath("/foo/bar/bat", "/"), 'foo/bar/bat') - self.assertEqual(posixpath.relpath("/", "/foo/bar/bat"), '../../..') - self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x"), '../foo/bar/bat') - self.assertEqual(posixpath.relpath("/x", "/foo/bar/bat"), '../../../x') - self.assertEqual(posixpath.relpath("/", "/"), '.') - self.assertEqual(posixpath.relpath("/a", "/a"), '.') - self.assertEqual(posixpath.relpath("/a/b", "/a/b"), '.') - finally: - setattr(os, 'getcwd', real_getcwd) - - def test_relpath_bytes(self) -> None: - real_getcwdb = os.getcwdb - # mypy: can't modify os directly - setattr(os, 'getcwdb', lambda: br"/home/user/bar") - try: - curdir = os.path.split(os.getcwdb())[-1] - self.assertRaises(ValueError, posixpath.relpath, b"") - self.assertEqual(posixpath.relpath(b"a"), b"a") - self.assertEqual(posixpath.relpath(posixpath.abspath(b"a")), b"a") - self.assertEqual(posixpath.relpath(b"a/b"), b"a/b") - self.assertEqual(posixpath.relpath(b"../a/b"), b"../a/b") - self.assertEqual(posixpath.relpath(b"a", b"../b"), - b"../"+curdir+b"/a") - self.assertEqual(posixpath.relpath(b"a/b", b"../c"), - b"../"+curdir+b"/a/b") - self.assertEqual(posixpath.relpath(b"a", b"b/c"), b"../../a") - self.assertEqual(posixpath.relpath(b"a", b"a"), b".") - self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/x/y/z"), b'../../../foo/bar/bat') - self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/foo/bar"), b'bat') - self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/"), b'foo/bar/bat') - self.assertEqual(posixpath.relpath(b"/", b"/foo/bar/bat"), b'../../..') - self.assertEqual(posixpath.relpath(b"/foo/bar/bat", b"/x"), b'../foo/bar/bat') - self.assertEqual(posixpath.relpath(b"/x", b"/foo/bar/bat"), b'../../../x') - self.assertEqual(posixpath.relpath(b"/", b"/"), b'.') - self.assertEqual(posixpath.relpath(b"/a", b"/a"), b'.') - self.assertEqual(posixpath.relpath(b"/a/b", b"/a/b"), b'.') - - self.assertRaises(TypeError, posixpath.relpath, b"bytes", "str") - self.assertRaises(TypeError, posixpath.relpath, "str", b"bytes") - finally: - setattr(os, 'getcwdb', real_getcwdb) - - def test_sameopenfile(self) -> None: - fname = support.TESTFN + "1" - with open(fname, "wb") as a, open(fname, "wb") as b: - self.assertTrue(posixpath.sameopenfile(a.fileno(), b.fileno())) - - -class PosixCommonTest(test_genericpath.CommonTest): - pathmodule = posixpath - attributes = ['relpath', 'samefile', 'sameopenfile', 'samestat'] - - -def test_main() -> None: - support.run_unittest(PosixPathTest, PosixCommonTest) - - -if __name__=="__main__": - test_main() diff --git a/test-data/stdlib-samples/3.2/test/test_pprint.py b/test-data/stdlib-samples/3.2/test/test_pprint.py deleted file mode 100644 index cf54ebde6adc..000000000000 --- a/test-data/stdlib-samples/3.2/test/test_pprint.py +++ /dev/null @@ -1,488 +0,0 @@ -import pprint -import test.support -import unittest -import test.test_set -import random -import collections -import itertools - -from typing import List, Any, Dict, Tuple, cast, Callable - -# list, tuple and dict subclasses that do or don't overwrite __repr__ -class list2(list): - pass - -class list3(list): - def __repr__(self) -> str: - return list.__repr__(self) - -class tuple2(tuple): - pass - -class tuple3(tuple): - def __repr__(self) -> str: - return tuple.__repr__(self) - -class dict2(dict): - pass - -class dict3(dict): - def __repr__(self) -> str: - return dict.__repr__(self) - -class Unorderable: - def __repr__(self) -> str: - return str(id(self)) - -class QueryTestCase(unittest.TestCase): - - def setUp(self) -> None: - self.a = list(range(100)) # type: List[Any] - self.b = list(range(200)) # type: List[Any] - self.a[-12] = self.b - - def test_basic(self) -> None: - # Verify .isrecursive() and .isreadable() w/o recursion - pp = pprint.PrettyPrinter() - for safe in (2, 2.0, complex(0.0, 2.0), "abc", [3], (2,2), {3: 3}, "yaddayadda", - self.a, self.b): - # module-level convenience functions - self.assertFalse(pprint.isrecursive(safe), - "expected not isrecursive for %r" % (safe,)) - self.assertTrue(pprint.isreadable(safe), - "expected isreadable for %r" % (safe,)) - # PrettyPrinter methods - self.assertFalse(pp.isrecursive(safe), - "expected not isrecursive for %r" % (safe,)) - self.assertTrue(pp.isreadable(safe), - "expected isreadable for %r" % (safe,)) - - def test_knotted(self) -> None: - # Verify .isrecursive() and .isreadable() w/ recursion - # Tie a knot. - self.b[67] = self.a - # Messy dict. - self.d = {} # type: Dict[int, dict] - self.d[0] = self.d[1] = self.d[2] = self.d - - pp = pprint.PrettyPrinter() - - for icky in self.a, self.b, self.d, (self.d, self.d): - self.assertTrue(pprint.isrecursive(icky), "expected isrecursive") - self.assertFalse(pprint.isreadable(icky), "expected not isreadable") - self.assertTrue(pp.isrecursive(icky), "expected isrecursive") - self.assertFalse(pp.isreadable(icky), "expected not isreadable") - - # Break the cycles. - self.d.clear() - del self.a[:] - del self.b[:] - - for safe in self.a, self.b, self.d, (self.d, self.d): - # module-level convenience functions - self.assertFalse(pprint.isrecursive(safe), - "expected not isrecursive for %r" % (safe,)) - self.assertTrue(pprint.isreadable(safe), - "expected isreadable for %r" % (safe,)) - # PrettyPrinter methods - self.assertFalse(pp.isrecursive(safe), - "expected not isrecursive for %r" % (safe,)) - self.assertTrue(pp.isreadable(safe), - "expected isreadable for %r" % (safe,)) - - def test_unreadable(self) -> None: - # Not recursive but not readable anyway - pp = pprint.PrettyPrinter() - for unreadable in type(3), pprint, pprint.isrecursive: - # module-level convenience functions - self.assertFalse(pprint.isrecursive(unreadable), - "expected not isrecursive for %r" % (unreadable,)) - self.assertFalse(pprint.isreadable(unreadable), - "expected not isreadable for %r" % (unreadable,)) - # PrettyPrinter methods - self.assertFalse(pp.isrecursive(unreadable), - "expected not isrecursive for %r" % (unreadable,)) - self.assertFalse(pp.isreadable(unreadable), - "expected not isreadable for %r" % (unreadable,)) - - def test_same_as_repr(self) -> None: - # Simple objects, small containers and classes that overwrite __repr__ - # For those the result should be the same as repr(). - # Ahem. The docs don't say anything about that -- this appears to - # be testing an implementation quirk. Starting in Python 2.5, it's - # not true for dicts: pprint always sorts dicts by key now; before, - # it sorted a dict display if and only if the display required - # multiple lines. For that reason, dicts with more than one element - # aren't tested here. - for simple in (0, 0, complex(0.0), 0.0, "", b"", - (), tuple2(), tuple3(), - [], list2(), list3(), - {}, dict2(), dict3(), - self.assertTrue, pprint, - -6, -6, complex(-6.,-6.), -1.5, "x", b"x", (3,), [3], {3: 6}, - (1,2), [3,4], {5: 6}, - tuple2((1,2)), tuple3((1,2)), tuple3(range(100)), # type: ignore - [3,4], list2(cast(Any, [3,4])), list3(cast(Any, [3,4])), - list3(cast(Any, range(100))), dict2(cast(Any, {5: 6})), - dict3(cast(Any, {5: 6})), # JLe: work around mypy issue #233 - range(10, -11, -1) - ): - native = repr(simple) - for function in "pformat", "saferepr": - f = getattr(pprint, function) - got = f(simple) - self.assertEqual(native, got, - "expected %s got %s from pprint.%s" % - (native, got, function)) - - def test_basic_line_wrap(self) -> None: - # verify basic line-wrapping operation - o = {'RPM_cal': 0, - 'RPM_cal2': 48059, - 'Speed_cal': 0, - 'controldesk_runtime_us': 0, - 'main_code_runtime_us': 0, - 'read_io_runtime_us': 0, - 'write_io_runtime_us': 43690} - exp = """\ -{'RPM_cal': 0, - 'RPM_cal2': 48059, - 'Speed_cal': 0, - 'controldesk_runtime_us': 0, - 'main_code_runtime_us': 0, - 'read_io_runtime_us': 0, - 'write_io_runtime_us': 43690}""" - # JLe: work around mypy issue #232 - for type in cast(List[Any], [dict, dict2]): - self.assertEqual(pprint.pformat(type(o)), exp) - - o2 = range(100) - exp = '[%s]' % ',\n '.join(map(str, o2)) - for type in cast(List[Any], [list, list2]): - self.assertEqual(pprint.pformat(type(o2)), exp) - - o3 = tuple(range(100)) - exp = '(%s)' % ',\n '.join(map(str, o3)) - for type in cast(List[Any], [tuple, tuple2]): - self.assertEqual(pprint.pformat(type(o3)), exp) - - # indent parameter - o4 = range(100) - exp = '[ %s]' % ',\n '.join(map(str, o4)) - for type in cast(List[Any], [list, list2]): - self.assertEqual(pprint.pformat(type(o4), indent=4), exp) - - def test_nested_indentations(self) -> None: - o1 = list(range(10)) - o2 = {'first':1, 'second':2, 'third':3} - o = [o1, o2] - expected = """\ -[ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - { 'first': 1, - 'second': 2, - 'third': 3}]""" - self.assertEqual(pprint.pformat(o, indent=4, width=42), expected) - - def test_sorted_dict(self) -> None: - # Starting in Python 2.5, pprint sorts dict displays by key regardless - # of how small the dictionary may be. - # Before the change, on 32-bit Windows pformat() gave order - # 'a', 'c', 'b' here, so this test failed. - d = {'a': 1, 'b': 1, 'c': 1} - self.assertEqual(pprint.pformat(d), "{'a': 1, 'b': 1, 'c': 1}") - self.assertEqual(pprint.pformat([d, d]), - "[{'a': 1, 'b': 1, 'c': 1}, {'a': 1, 'b': 1, 'c': 1}]") - - # The next one is kind of goofy. The sorted order depends on the - # alphabetic order of type names: "int" < "str" < "tuple". Before - # Python 2.5, this was in the test_same_as_repr() test. It's worth - # keeping around for now because it's one of few tests of pprint - # against a crazy mix of types. - self.assertEqual(pprint.pformat({"xy\tab\n": (3,), 5: [[]], (): {}}), - r"{5: [[]], 'xy\tab\n': (3,), (): {}}") - - def test_ordered_dict(self) -> None: - words = 'the quick brown fox jumped over a lazy dog'.split() - d = collections.OrderedDict(zip(words, itertools.count())) - self.assertEqual(pprint.pformat(d), -"""\ -{'the': 0, - 'quick': 1, - 'brown': 2, - 'fox': 3, - 'jumped': 4, - 'over': 5, - 'a': 6, - 'lazy': 7, - 'dog': 8}""") - def test_subclassing(self) -> None: - o = {'names with spaces': 'should be presented using repr()', - 'others.should.not.be': 'like.this'} - exp = """\ -{'names with spaces': 'should be presented using repr()', - others.should.not.be: like.this}""" - self.assertEqual(DottedPrettyPrinter().pformat(o), exp) - - @test.support.cpython_only - def test_set_reprs(self) -> None: - # This test creates a complex arrangement of frozensets and - # compares the pretty-printed repr against a string hard-coded in - # the test. The hard-coded repr depends on the sort order of - # frozensets. - # - # However, as the docs point out: "Since sets only define - # partial ordering (subset relationships), the output of the - # list.sort() method is undefined for lists of sets." - # - # In a nutshell, the test assumes frozenset({0}) will always - # sort before frozenset({1}), but: - # - # >>> frozenset({0}) < frozenset({1}) - # False - # >>> frozenset({1}) < frozenset({0}) - # False - # - # Consequently, this test is fragile and - # implementation-dependent. Small changes to Python's sort - # algorithm cause the test to fail when it should pass. - - self.assertEqual(pprint.pformat(set()), 'set()') - self.assertEqual(pprint.pformat(set(range(3))), '{0, 1, 2}') - self.assertEqual(pprint.pformat(frozenset()), 'frozenset()') - self.assertEqual(pprint.pformat(frozenset(range(3))), 'frozenset({0, 1, 2})') - cube_repr_tgt = """\ -{frozenset(): frozenset({frozenset({2}), frozenset({0}), frozenset({1})}), - frozenset({0}): frozenset({frozenset(), - frozenset({0, 2}), - frozenset({0, 1})}), - frozenset({1}): frozenset({frozenset(), - frozenset({1, 2}), - frozenset({0, 1})}), - frozenset({2}): frozenset({frozenset(), - frozenset({1, 2}), - frozenset({0, 2})}), - frozenset({1, 2}): frozenset({frozenset({2}), - frozenset({1}), - frozenset({0, 1, 2})}), - frozenset({0, 2}): frozenset({frozenset({2}), - frozenset({0}), - frozenset({0, 1, 2})}), - frozenset({0, 1}): frozenset({frozenset({0}), - frozenset({1}), - frozenset({0, 1, 2})}), - frozenset({0, 1, 2}): frozenset({frozenset({1, 2}), - frozenset({0, 2}), - frozenset({0, 1})})}""" - cube = test.test_set.cube(3) - self.assertEqual(pprint.pformat(cube), cube_repr_tgt) - cubo_repr_tgt = """\ -{frozenset({frozenset({0, 2}), frozenset({0})}): frozenset({frozenset({frozenset({0, - 2}), - frozenset({0, - 1, - 2})}), - frozenset({frozenset({0}), - frozenset({0, - 1})}), - frozenset({frozenset(), - frozenset({0})}), - frozenset({frozenset({2}), - frozenset({0, - 2})})}), - frozenset({frozenset({0, 1}), frozenset({1})}): frozenset({frozenset({frozenset({0, - 1}), - frozenset({0, - 1, - 2})}), - frozenset({frozenset({0}), - frozenset({0, - 1})}), - frozenset({frozenset({1}), - frozenset({1, - 2})}), - frozenset({frozenset(), - frozenset({1})})}), - frozenset({frozenset({1, 2}), frozenset({1})}): frozenset({frozenset({frozenset({1, - 2}), - frozenset({0, - 1, - 2})}), - frozenset({frozenset({2}), - frozenset({1, - 2})}), - frozenset({frozenset(), - frozenset({1})}), - frozenset({frozenset({1}), - frozenset({0, - 1})})}), - frozenset({frozenset({1, 2}), frozenset({2})}): frozenset({frozenset({frozenset({1, - 2}), - frozenset({0, - 1, - 2})}), - frozenset({frozenset({1}), - frozenset({1, - 2})}), - frozenset({frozenset({2}), - frozenset({0, - 2})}), - frozenset({frozenset(), - frozenset({2})})}), - frozenset({frozenset(), frozenset({0})}): frozenset({frozenset({frozenset({0}), - frozenset({0, - 1})}), - frozenset({frozenset({0}), - frozenset({0, - 2})}), - frozenset({frozenset(), - frozenset({1})}), - frozenset({frozenset(), - frozenset({2})})}), - frozenset({frozenset(), frozenset({1})}): frozenset({frozenset({frozenset(), - frozenset({0})}), - frozenset({frozenset({1}), - frozenset({1, - 2})}), - frozenset({frozenset(), - frozenset({2})}), - frozenset({frozenset({1}), - frozenset({0, - 1})})}), - frozenset({frozenset({2}), frozenset()}): frozenset({frozenset({frozenset({2}), - frozenset({1, - 2})}), - frozenset({frozenset(), - frozenset({0})}), - frozenset({frozenset(), - frozenset({1})}), - frozenset({frozenset({2}), - frozenset({0, - 2})})}), - frozenset({frozenset({0, 1, 2}), frozenset({0, 1})}): frozenset({frozenset({frozenset({1, - 2}), - frozenset({0, - 1, - 2})}), - frozenset({frozenset({0, - 2}), - frozenset({0, - 1, - 2})}), - frozenset({frozenset({0}), - frozenset({0, - 1})}), - frozenset({frozenset({1}), - frozenset({0, - 1})})}), - frozenset({frozenset({0}), frozenset({0, 1})}): frozenset({frozenset({frozenset(), - frozenset({0})}), - frozenset({frozenset({0, - 1}), - frozenset({0, - 1, - 2})}), - frozenset({frozenset({0}), - frozenset({0, - 2})}), - frozenset({frozenset({1}), - frozenset({0, - 1})})}), - frozenset({frozenset({2}), frozenset({0, 2})}): frozenset({frozenset({frozenset({0, - 2}), - frozenset({0, - 1, - 2})}), - frozenset({frozenset({2}), - frozenset({1, - 2})}), - frozenset({frozenset({0}), - frozenset({0, - 2})}), - frozenset({frozenset(), - frozenset({2})})}), - frozenset({frozenset({0, 1, 2}), frozenset({0, 2})}): frozenset({frozenset({frozenset({1, - 2}), - frozenset({0, - 1, - 2})}), - frozenset({frozenset({0, - 1}), - frozenset({0, - 1, - 2})}), - frozenset({frozenset({0}), - frozenset({0, - 2})}), - frozenset({frozenset({2}), - frozenset({0, - 2})})}), - frozenset({frozenset({1, 2}), frozenset({0, 1, 2})}): frozenset({frozenset({frozenset({0, - 2}), - frozenset({0, - 1, - 2})}), - frozenset({frozenset({0, - 1}), - frozenset({0, - 1, - 2})}), - frozenset({frozenset({2}), - frozenset({1, - 2})}), - frozenset({frozenset({1}), - frozenset({1, - 2})})})}""" - - cubo = test.test_set.linegraph(cube) - self.assertEqual(pprint.pformat(cubo), cubo_repr_tgt) - - def test_depth(self) -> None: - nested_tuple = (1, (2, (3, (4, (5, 6))))) - nested_dict = {1: {2: {3: {4: {5: {6: 6}}}}}} - nested_list = [1, [2, [3, [4, [5, [6, []]]]]]] - self.assertEqual(pprint.pformat(nested_tuple), repr(nested_tuple)) - self.assertEqual(pprint.pformat(nested_dict), repr(nested_dict)) - self.assertEqual(pprint.pformat(nested_list), repr(nested_list)) - - lv1_tuple = '(1, (...))' - lv1_dict = '{1: {...}}' - lv1_list = '[1, [...]]' - self.assertEqual(pprint.pformat(nested_tuple, depth=1), lv1_tuple) - self.assertEqual(pprint.pformat(nested_dict, depth=1), lv1_dict) - self.assertEqual(pprint.pformat(nested_list, depth=1), lv1_list) - - def test_sort_unorderable_values(self) -> None: - # Issue 3976: sorted pprints fail for unorderable values. - n = 20 - keys = [Unorderable() for i in range(n)] - random.shuffle(keys) - skeys = sorted(keys, key=id) - clean = lambda s: s.replace(' ', '').replace('\n','') # type: Callable[[str], str] - - self.assertEqual(clean(pprint.pformat(set(keys))), - '{' + ','.join(map(repr, skeys)) + '}') - self.assertEqual(clean(pprint.pformat(frozenset(keys))), - 'frozenset({' + ','.join(map(repr, skeys)) + '})') - self.assertEqual(clean(pprint.pformat(dict.fromkeys(keys))), - '{' + ','.join('%r:None' % k for k in skeys) + '}') - -class DottedPrettyPrinter(pprint.PrettyPrinter): - - def format(self, object: object, context: Dict[int, Any], maxlevels: int, - level: int) -> Tuple[str, int, int]: - if isinstance(object, str): - if ' ' in object: - return repr(object), 1, 0 - else: - return object, 0, 0 - else: - return pprint.PrettyPrinter.format( - self, object, context, maxlevels, level) - - -def test_main() -> None: - test.support.run_unittest(QueryTestCase) - - -if __name__ == "__main__": - test_main() diff --git a/test-data/stdlib-samples/3.2/test/test_random.py b/test-data/stdlib-samples/3.2/test/test_random.py deleted file mode 100644 index 5989ceeee2bb..000000000000 --- a/test-data/stdlib-samples/3.2/test/test_random.py +++ /dev/null @@ -1,533 +0,0 @@ -#!/usr/bin/env python3 - -import unittest -import random -import time -import pickle -import warnings -from math import log, exp, pi, fsum, sin -from test import support - -from typing import Any, Dict, List, Callable, Generic, TypeVar, cast - -RT = TypeVar('RT', random.Random, random.SystemRandom) - -class TestBasicOps(unittest.TestCase, Generic[RT]): - # Superclass with tests common to all generators. - # Subclasses must arrange for self.gen to retrieve the Random instance - # to be tested. - - gen = None # type: RT # Either Random or SystemRandom - - def randomlist(self, n: int) -> List[float]: - """Helper function to make a list of random numbers""" - return [self.gen.random() for i in range(n)] - - def test_autoseed(self) -> None: - self.gen.seed() - state1 = self.gen.getstate() - time.sleep(0.1) - self.gen.seed() # diffent seeds at different times - state2 = self.gen.getstate() - self.assertNotEqual(state1, state2) - - def test_saverestore(self) -> None: - N = 1000 - self.gen.seed() - state = self.gen.getstate() - randseq = self.randomlist(N) - self.gen.setstate(state) # should regenerate the same sequence - self.assertEqual(randseq, self.randomlist(N)) - - def test_seedargs(self) -> None: - for arg in [None, 0, 0, 1, 1, -1, -1, 10**20, -(10**20), - 3.14, complex(1., 2.), 'a', tuple('abc')]: - self.gen.seed(arg) - for arg in [list(range(3)), {'one': 1}]: - self.assertRaises(TypeError, self.gen.seed, arg) - self.assertRaises(TypeError, self.gen.seed, 1, 2, 3, 4) - self.assertRaises(TypeError, type(self.gen), []) # type: ignore # mypy issue 1846 - - def test_choice(self) -> None: - choice = self.gen.choice - with self.assertRaises(IndexError): - choice([]) - self.assertEqual(choice([50]), 50) - self.assertIn(choice([25, 75]), [25, 75]) - - def test_sample(self) -> None: - # For the entire allowable range of 0 <= k <= N, validate that - # the sample is of the correct length and contains only unique items - N = 100 - population = range(N) - for k in range(N+1): - s = self.gen.sample(population, k) - self.assertEqual(len(s), k) - uniq = set(s) - self.assertEqual(len(uniq), k) - self.assertTrue(uniq <= set(population)) - self.assertEqual(self.gen.sample([], 0), []) # test edge case N==k==0 - - def test_sample_distribution(self) -> None: - # For the entire allowable range of 0 <= k <= N, validate that - # sample generates all possible permutations - n = 5 - pop = range(n) - trials = 10000 # large num prevents false negatives without slowing normal case - def factorial(n: int) -> int: - if n == 0: - return 1 - return n * factorial(n - 1) - for k in range(n): - expected = factorial(n) // factorial(n-k) - perms = {} # type: Dict[tuple, object] - for i in range(trials): - perms[tuple(self.gen.sample(pop, k))] = None - if len(perms) == expected: - break - else: - self.fail() - - def test_sample_inputs(self) -> None: - # SF bug #801342 -- population can be any iterable defining __len__() - self.gen.sample(set(range(20)), 2) - self.gen.sample(range(20), 2) - self.gen.sample(range(20), 2) - self.gen.sample(str('abcdefghijklmnopqrst'), 2) - self.gen.sample(tuple('abcdefghijklmnopqrst'), 2) - - def test_sample_on_dicts(self) -> None: - self.assertRaises(TypeError, self.gen.sample, dict.fromkeys('abcdef'), 2) - - def test_gauss(self) -> None: - # Ensure that the seed() method initializes all the hidden state. In - # particular, through 2.2.1 it failed to reset a piece of state used - # by (and only by) the .gauss() method. - - for seed in 1, 12, 123, 1234, 12345, 123456, 654321: - self.gen.seed(seed) - x1 = self.gen.random() - y1 = self.gen.gauss(0, 1) - - self.gen.seed(seed) - x2 = self.gen.random() - y2 = self.gen.gauss(0, 1) - - self.assertEqual(x1, x2) - self.assertEqual(y1, y2) - - def test_pickling(self) -> None: - state = pickle.dumps(self.gen) - origseq = [self.gen.random() for i in range(10)] - newgen = pickle.loads(state) - restoredseq = [newgen.random() for i in range(10)] - self.assertEqual(origseq, restoredseq) - - def test_bug_1727780(self) -> None: - # verify that version-2-pickles can be loaded - # fine, whether they are created on 32-bit or 64-bit - # platforms, and that version-3-pickles load fine. - files = [("randv2_32.pck", 780), - ("randv2_64.pck", 866), - ("randv3.pck", 343)] - for file, value in files: - f = open(support.findfile(file),"rb") - r = pickle.load(f) - f.close() - self.assertEqual(int(r.random()*1000), value) - - def test_bug_9025(self) -> None: - # Had problem with an uneven distribution in int(n*random()) - # Verify the fix by checking that distributions fall within expectations. - n = 100000 - randrange = self.gen.randrange - k = sum(randrange(6755399441055744) % 3 == 2 for i in range(n)) - self.assertTrue(0.30 < k/n and k/n < .37, (k/n)) - -class SystemRandom_TestBasicOps(TestBasicOps[random.SystemRandom]): - gen = random.SystemRandom() - - def test_autoseed(self) -> None: - # Doesn't need to do anything except not fail - self.gen.seed() - - def test_saverestore(self) -> None: - self.assertRaises(NotImplementedError, self.gen.getstate) - self.assertRaises(NotImplementedError, self.gen.setstate, None) - - def test_seedargs(self) -> None: - # Doesn't need to do anything except not fail - self.gen.seed(100) - - def test_gauss(self) -> None: - self.gen.gauss_next = None - self.gen.seed(100) - self.assertEqual(self.gen.gauss_next, None) - - def test_pickling(self) -> None: - self.assertRaises(NotImplementedError, pickle.dumps, self.gen) - - def test_53_bits_per_float(self) -> None: - # This should pass whenever a C double has 53 bit precision. - span = 2 ** 53 # type: int - cum = 0 - for i in range(100): - cum |= int(self.gen.random() * span) - self.assertEqual(cum, span-1) - - def test_bigrand(self) -> None: - # The randrange routine should build-up the required number of bits - # in stages so that all bit positions are active. - span = 2 ** 500 # type: int - cum = 0 - for i in range(100): - r = self.gen.randrange(span) - self.assertTrue(0 <= r < span) - cum |= r - self.assertEqual(cum, span-1) - - def test_bigrand_ranges(self) -> None: - for i in [40,80, 160, 200, 211, 250, 375, 512, 550]: - start = self.gen.randrange(2 ** i) - stop = self.gen.randrange(2 ** (i-2)) - if stop <= start: - return - self.assertTrue(start <= self.gen.randrange(start, stop) < stop) - - def test_rangelimits(self) -> None: - for start, stop in [(-2,0), (-(2**60)-2,-(2**60)), (2**60,2**60+2)]: - self.assertEqual(set(range(start,stop)), - set([self.gen.randrange(start,stop) for i in range(100)])) - - def test_genrandbits(self) -> None: - # Verify ranges - for k in range(1, 1000): - self.assertTrue(0 <= self.gen.getrandbits(k) < 2**k) - - # Verify all bits active - getbits = self.gen.getrandbits - for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]: - cum = 0 - for i in range(100): - cum |= getbits(span) - self.assertEqual(cum, 2**span-1) - - # Verify argument checking - self.assertRaises(TypeError, self.gen.getrandbits) - self.assertRaises(TypeError, self.gen.getrandbits, 1, 2) - self.assertRaises(ValueError, self.gen.getrandbits, 0) - self.assertRaises(ValueError, self.gen.getrandbits, -1) - self.assertRaises(TypeError, self.gen.getrandbits, 10.1) - - def test_randbelow_logic(self, _log: Callable[[float, float], float] = log, - int: Callable[[float], int] = int) -> None: - # check bitcount transition points: 2**i and 2**(i+1)-1 - # show that: k = int(1.001 + _log(n, 2)) - # is equal to or one greater than the number of bits in n - for i in range(1, 1000): - n = 1 << i # check an exact power of two - numbits = i+1 - k = int(1.00001 + _log(n, 2)) - self.assertEqual(k, numbits) - self.assertEqual(n, 2**(k-1)) - - n += n - 1 # check 1 below the next power of two - k = int(1.00001 + _log(n, 2)) - self.assertIn(k, [numbits, numbits+1]) - self.assertTrue(2**k > n > 2**(k-2)) - - n -= n >> 15 # check a little farther below the next power of two - k = int(1.00001 + _log(n, 2)) - self.assertEqual(k, numbits) # note the stronger assertion - self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion - - -class MersenneTwister_TestBasicOps(TestBasicOps[random.Random]): - gen = random.Random() - - def test_guaranteed_stable(self) -> None: - # These sequences are guaranteed to stay the same across versions of python - self.gen.seed(3456147, version=1) - self.assertEqual([self.gen.random().hex() for i in range(4)], - ['0x1.ac362300d90d2p-1', '0x1.9d16f74365005p-1', - '0x1.1ebb4352e4c4dp-1', '0x1.1a7422abf9c11p-1']) - self.gen.seed("the quick brown fox", version=2) - self.assertEqual([self.gen.random().hex() for i in range(4)], - ['0x1.1239ddfb11b7cp-3', '0x1.b3cbb5c51b120p-4', - '0x1.8c4f55116b60fp-1', '0x1.63eb525174a27p-1']) - - def test_setstate_first_arg(self) -> None: - self.assertRaises(ValueError, self.gen.setstate, (1, None, None)) - - def test_setstate_middle_arg(self) -> None: - # Wrong type, s/b tuple - self.assertRaises(TypeError, self.gen.setstate, (2, None, None)) - # Wrong length, s/b 625 - self.assertRaises(ValueError, self.gen.setstate, (2, (1,2,3), None)) - # Wrong type, s/b tuple of 625 ints - self.assertRaises(TypeError, self.gen.setstate, (2, tuple(['a',]*625), None)) - # Last element s/b an int also - self.assertRaises(TypeError, self.gen.setstate, (2, cast(Any, (0,))*624+('a',), None)) - - def test_referenceImplementation(self) -> None: - # Compare the python implementation with results from the original - # code. Create 2000 53-bit precision random floats. Compare only - # the last ten entries to show that the independent implementations - # are tracking. Here is the main() function needed to create the - # list of expected random numbers: - # void main(void){ - # int i; - # unsigned long init[4]={61731, 24903, 614, 42143}, length=4; - # init_by_array(init, length); - # for (i=0; i<2000; i++) { - # printf("%.15f ", genrand_res53()); - # if (i%5==4) printf("\n"); - # } - # } - expected = [0.45839803073713259, - 0.86057815201978782, - 0.92848331726782152, - 0.35932681119782461, - 0.081823493762449573, - 0.14332226470169329, - 0.084297823823520024, - 0.53814864671831453, - 0.089215024911993401, - 0.78486196105372907] - - self.gen.seed(61731 + (24903<<32) + (614<<64) + (42143<<96)) - actual = self.randomlist(2000)[-10:] - for a, e in zip(actual, expected): - self.assertAlmostEqual(a,e,places=14) - - def test_strong_reference_implementation(self) -> None: - # Like test_referenceImplementation, but checks for exact bit-level - # equality. This should pass on any box where C double contains - # at least 53 bits of precision (the underlying algorithm suffers - # no rounding errors -- all results are exact). - from math import ldexp - - expected = [0x0eab3258d2231f, - 0x1b89db315277a5, - 0x1db622a5518016, - 0x0b7f9af0d575bf, - 0x029e4c4db82240, - 0x04961892f5d673, - 0x02b291598e4589, - 0x11388382c15694, - 0x02dad977c9e1fe, - 0x191d96d4d334c6] - self.gen.seed(61731 + (24903<<32) + (614<<64) + (42143<<96)) - actual = self.randomlist(2000)[-10:] - for a, e in zip(actual, expected): - self.assertEqual(int(ldexp(a, 53)), e) - - def test_long_seed(self) -> None: - # This is most interesting to run in debug mode, just to make sure - # nothing blows up. Under the covers, a dynamically resized array - # is allocated, consuming space proportional to the number of bits - # in the seed. Unfortunately, that's a quadratic-time algorithm, - # so don't make this horribly big. - seed = (1 << (10000 * 8)) - 1 # about 10K bytes - self.gen.seed(seed) - - def test_53_bits_per_float(self) -> None: - # This should pass whenever a C double has 53 bit precision. - span = 2 ** 53 # type: int - cum = 0 - for i in range(100): - cum |= int(self.gen.random() * span) - self.assertEqual(cum, span-1) - - def test_bigrand(self) -> None: - # The randrange routine should build-up the required number of bits - # in stages so that all bit positions are active. - span = 2 ** 500 # type: int - cum = 0 - for i in range(100): - r = self.gen.randrange(span) - self.assertTrue(0 <= r < span) - cum |= r - self.assertEqual(cum, span-1) - - def test_bigrand_ranges(self) -> None: - for i in [40,80, 160, 200, 211, 250, 375, 512, 550]: - start = self.gen.randrange(2 ** i) - stop = self.gen.randrange(2 ** (i-2)) - if stop <= start: - return - self.assertTrue(start <= self.gen.randrange(start, stop) < stop) - - def test_rangelimits(self) -> None: - for start, stop in [(-2,0), (-(2**60)-2,-(2**60)), (2**60,2**60+2)]: - self.assertEqual(set(range(start,stop)), - set([self.gen.randrange(start,stop) for i in range(100)])) - - def test_genrandbits(self) -> None: - # Verify cross-platform repeatability - self.gen.seed(1234567) - self.assertEqual(self.gen.getrandbits(100), - 97904845777343510404718956115) - # Verify ranges - for k in range(1, 1000): - self.assertTrue(0 <= self.gen.getrandbits(k) < 2**k) - - # Verify all bits active - getbits = self.gen.getrandbits - for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]: - cum = 0 - for i in range(100): - cum |= getbits(span) - self.assertEqual(cum, 2**span-1) - - # Verify argument checking - self.assertRaises(TypeError, self.gen.getrandbits) - self.assertRaises(TypeError, self.gen.getrandbits, 'a') - self.assertRaises(TypeError, self.gen.getrandbits, 1, 2) - self.assertRaises(ValueError, self.gen.getrandbits, 0) - self.assertRaises(ValueError, self.gen.getrandbits, -1) - - def test_randbelow_logic(self, - _log: Callable[[int, float], float] = log, - int: Callable[[float], int] = int) -> None: - # check bitcount transition points: 2**i and 2**(i+1)-1 - # show that: k = int(1.001 + _log(n, 2)) - # is equal to or one greater than the number of bits in n - for i in range(1, 1000): - n = 1 << i # check an exact power of two - numbits = i+1 - k = int(1.00001 + _log(n, 2)) - self.assertEqual(k, numbits) - self.assertEqual(n, 2**(k-1)) - - n += n - 1 # check 1 below the next power of two - k = int(1.00001 + _log(n, 2)) - self.assertIn(k, [numbits, numbits+1]) - self.assertTrue(2**k > n > 2**(k-2)) - - n -= n >> 15 # check a little farther below the next power of two - k = int(1.00001 + _log(n, 2)) - self.assertEqual(k, numbits) # note the stronger assertion - self.assertTrue(2**k > n > 2**(k-1)) # note the stronger assertion - - def test_randrange_bug_1590891(self) -> None: - start = 1000000000000 - stop = -100000000000000000000 - step = -200 - x = self.gen.randrange(start, stop, step) - self.assertTrue(stop < x <= start) - self.assertEqual((x+stop)%step, 0) - -def gamma(z: float, sqrt2pi: float = (2.0*pi)**0.5) -> float: - # Reflection to right half of complex plane - if z < 0.5: - return pi / sin(pi*z) / gamma(1.0-z) - # Lanczos approximation with g=7 - az = z + (7.0 - 0.5) - return az ** (z-0.5) / exp(az) * sqrt2pi * fsum([ - 0.9999999999995183, - 676.5203681218835 / z, - -1259.139216722289 / (z+1.0), - 771.3234287757674 / (z+2.0), - -176.6150291498386 / (z+3.0), - 12.50734324009056 / (z+4.0), - -0.1385710331296526 / (z+5.0), - 0.9934937113930748e-05 / (z+6.0), - 0.1659470187408462e-06 / (z+7.0), - ]) - -class TestDistributions(unittest.TestCase): - def test_zeroinputs(self) -> None: - # Verify that distributions can handle a series of zero inputs' - g = random.Random() - x = [g.random() for i in range(50)] + [0.0]*5 - def patch() -> None: - setattr(g, 'random', x[:].pop) - patch(); g.uniform(1.0,10.0) - patch(); g.paretovariate(1.0) - patch(); g.expovariate(1.0) - patch(); g.weibullvariate(1.0, 1.0) - patch(); g.normalvariate(0.0, 1.0) - patch(); g.gauss(0.0, 1.0) - patch(); g.lognormvariate(0.0, 1.0) - patch(); g.vonmisesvariate(0.0, 1.0) - patch(); g.gammavariate(0.01, 1.0) - patch(); g.gammavariate(1.0, 1.0) - patch(); g.gammavariate(200.0, 1.0) - patch(); g.betavariate(3.0, 3.0) - patch(); g.triangular(0.0, 1.0, 1.0/3.0) - - def test_avg_std(self) -> None: - # Use integration to test distribution average and standard deviation. - # Only works for distributions which do not consume variates in pairs - g = random.Random() - N = 5000 - x = [i/float(N) for i in range(1,N)] - variate = None # type: Any - for variate, args, mu, sigmasqrd in [ - (g.uniform, (1.0,10.0), (10.0+1.0)/2, (10.0-1.0)**2/12), - (g.triangular, (0.0, 1.0, 1.0/3.0), 4.0/9.0, 7.0/9.0/18.0), - (g.expovariate, (1.5,), 1/1.5, 1/1.5**2), - (g.paretovariate, (5.0,), 5.0/(5.0-1), - 5.0/((5.0-1)**2*(5.0-2))), - (g.weibullvariate, (1.0, 3.0), gamma(1+1/3.0), - gamma(1+2/3.0)-gamma(1+1/3.0)**2) ]: - setattr(g, 'random', x[:].pop) - y = [] # type: List[float] - for i in range(len(x)): - try: - y.append(variate(*args)) - except IndexError: - pass - s1 = s2 = 0.0 - for e in y: - s1 += e - s2 += (e - mu) ** 2 - N = len(y) - self.assertAlmostEqual(s1/N, mu, places=2) - self.assertAlmostEqual(s2/(N-1), sigmasqrd, places=2) - -class TestModule(unittest.TestCase): - def testMagicConstants(self) -> None: - self.assertAlmostEqual(random.NV_MAGICCONST, 1.71552776992141) - self.assertAlmostEqual(random.TWOPI, 6.28318530718) - self.assertAlmostEqual(random.LOG4, 1.38629436111989) - self.assertAlmostEqual(random.SG_MAGICCONST, 2.50407739677627) - - def test__all__(self) -> None: - # tests validity but not completeness of the __all__ list - self.assertTrue(set(random.__all__) <= set(dir(random))) - - def test_random_subclass_with_kwargs(self) -> None: - # SF bug #1486663 -- this used to erroneously raise a TypeError - class Subclass(random.Random): - def __init__(self, newarg: object = None) -> None: - random.Random.__init__(self) - Subclass(newarg=1) - - -def test_main(verbose: bool = None) -> None: - testclasses = [MersenneTwister_TestBasicOps, - TestDistributions, - TestModule] - - try: - random.SystemRandom().random() - except NotImplementedError: - pass - else: - testclasses.append(SystemRandom_TestBasicOps) - - support.run_unittest(*testclasses) - - # verify reference counting - import sys - if verbose and hasattr(sys, "gettotalrefcount"): - counts = [None] * 5 # type: List[int] - for i in range(len(counts)): - support.run_unittest(*testclasses) - counts[i] = sys.gettotalrefcount() - print(counts) - -if __name__ == "__main__": - test_main(verbose=True) diff --git a/test-data/stdlib-samples/3.2/test/test_set.py b/test-data/stdlib-samples/3.2/test/test_set.py deleted file mode 100644 index 16f86198cc0f..000000000000 --- a/test-data/stdlib-samples/3.2/test/test_set.py +++ /dev/null @@ -1,1884 +0,0 @@ -import unittest -from test import support -import gc -import weakref -import operator -import copy -import pickle -from random import randrange, shuffle -import sys -import warnings -import collections -from typing import Set, Any - -class PassThru(Exception): - pass - -def check_pass_thru(): - raise PassThru - yield 1 - -class BadCmp: - def __hash__(self): - return 1 - def __eq__(self, other): - raise RuntimeError - -class ReprWrapper: - 'Used to test self-referential repr() calls' - def __repr__(self): - return repr(self.value) - -#class HashCountingInt(int): -# 'int-like object that counts the number of times __hash__ is called' -# def __init__(self, *args): -# self.hash_count = 0 -# def __hash__(self): -# self.hash_count += 1 -# return int.__hash__(self) - -class TestJointOps(unittest.TestCase): - # Tests common to both set and frozenset - - def setUp(self): - self.word = word = 'simsalabim' - self.otherword = 'madagascar' - self.letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' - self.s = self.thetype(word) - self.d = dict.fromkeys(word) - - def test_new_or_init(self): - self.assertRaises(TypeError, self.thetype, [], 2) - self.assertRaises(TypeError, set().__init__, a=1) - - def test_uniquification(self): - actual = sorted(self.s) - expected = sorted(self.d) - self.assertEqual(actual, expected) - self.assertRaises(PassThru, self.thetype, check_pass_thru()) - self.assertRaises(TypeError, self.thetype, [[]]) - - def test_len(self): - self.assertEqual(len(self.s), len(self.d)) - - def test_contains(self): - for c in self.letters: - self.assertEqual(c in self.s, c in self.d) - self.assertRaises(TypeError, self.s.__contains__, [[]]) - s = self.thetype([frozenset(self.letters)]) - self.assertIn(self.thetype(self.letters), s) - - def test_union(self): - u = self.s.union(self.otherword) - for c in self.letters: - self.assertEqual(c in u, c in self.d or c in self.otherword) - self.assertEqual(self.s, self.thetype(self.word)) - self.assertEqual(type(u), self.basetype) - self.assertRaises(PassThru, self.s.union, check_pass_thru()) - self.assertRaises(TypeError, self.s.union, [[]]) - for C in set, frozenset, dict.fromkeys, str, list, tuple: - self.assertEqual(self.thetype('abcba').union(C('cdc')), set('abcd')) - self.assertEqual(self.thetype('abcba').union(C('efgfe')), set('abcefg')) - self.assertEqual(self.thetype('abcba').union(C('ccb')), set('abc')) - self.assertEqual(self.thetype('abcba').union(C('ef')), set('abcef')) - self.assertEqual(self.thetype('abcba').union(C('ef'), C('fg')), set('abcefg')) - - # Issue #6573 - x = self.thetype() - self.assertEqual(x.union(set([1]), x, set([2])), self.thetype([1, 2])) - - def test_or(self): - i = self.s.union(self.otherword) - self.assertEqual(self.s | set(self.otherword), i) - self.assertEqual(self.s | frozenset(self.otherword), i) - try: - self.s | self.otherword - except TypeError: - pass - else: - self.fail("s|t did not screen-out general iterables") - - def test_intersection(self): - i = self.s.intersection(self.otherword) - for c in self.letters: - self.assertEqual(c in i, c in self.d and c in self.otherword) - self.assertEqual(self.s, self.thetype(self.word)) - self.assertEqual(type(i), self.basetype) - self.assertRaises(PassThru, self.s.intersection, check_pass_thru()) - for C in set, frozenset, dict.fromkeys, str, list, tuple: - self.assertEqual(self.thetype('abcba').intersection(C('cdc')), set('cc')) - self.assertEqual(self.thetype('abcba').intersection(C('efgfe')), set('')) - self.assertEqual(self.thetype('abcba').intersection(C('ccb')), set('bc')) - self.assertEqual(self.thetype('abcba').intersection(C('ef')), set('')) - self.assertEqual(self.thetype('abcba').intersection(C('cbcf'), C('bag')), set('b')) - s = self.thetype('abcba') - z = s.intersection() - if self.thetype == frozenset(): - self.assertEqual(id(s), id(z)) - else: - self.assertNotEqual(id(s), id(z)) - - def test_isdisjoint(self): - def f(s1, s2): - 'Pure python equivalent of isdisjoint()' - return not set(s1).intersection(s2) - for larg in '', 'a', 'ab', 'abc', 'ababac', 'cdc', 'cc', 'efgfe', 'ccb', 'ef': - s1 = self.thetype(larg) - for rarg in '', 'a', 'ab', 'abc', 'ababac', 'cdc', 'cc', 'efgfe', 'ccb', 'ef': - for C in set, frozenset, dict.fromkeys, str, list, tuple: - s2 = C(rarg) - actual = s1.isdisjoint(s2) - expected = f(s1, s2) - self.assertEqual(actual, expected) - self.assertTrue(actual is True or actual is False) - - def test_and(self): - i = self.s.intersection(self.otherword) - self.assertEqual(self.s & set(self.otherword), i) - self.assertEqual(self.s & frozenset(self.otherword), i) - try: - self.s & self.otherword - except TypeError: - pass - else: - self.fail("s&t did not screen-out general iterables") - - def test_difference(self): - i = self.s.difference(self.otherword) - for c in self.letters: - self.assertEqual(c in i, c in self.d and c not in self.otherword) - self.assertEqual(self.s, self.thetype(self.word)) - self.assertEqual(type(i), self.basetype) - self.assertRaises(PassThru, self.s.difference, check_pass_thru()) - self.assertRaises(TypeError, self.s.difference, [[]]) - for C in set, frozenset, dict.fromkeys, str, list, tuple: - self.assertEqual(self.thetype('abcba').difference(C('cdc')), set('ab')) - self.assertEqual(self.thetype('abcba').difference(C('efgfe')), set('abc')) - self.assertEqual(self.thetype('abcba').difference(C('ccb')), set('a')) - self.assertEqual(self.thetype('abcba').difference(C('ef')), set('abc')) - self.assertEqual(self.thetype('abcba').difference(), set('abc')) - self.assertEqual(self.thetype('abcba').difference(C('a'), C('b')), set('c')) - - def test_sub(self): - i = self.s.difference(self.otherword) - self.assertEqual(self.s - set(self.otherword), i) - self.assertEqual(self.s - frozenset(self.otherword), i) - try: - self.s - self.otherword - except TypeError: - pass - else: - self.fail("s-t did not screen-out general iterables") - - def test_symmetric_difference(self): - i = self.s.symmetric_difference(self.otherword) - for c in self.letters: - self.assertEqual(c in i, (c in self.d) ^ (c in self.otherword)) - self.assertEqual(self.s, self.thetype(self.word)) - self.assertEqual(type(i), self.basetype) - self.assertRaises(PassThru, self.s.symmetric_difference, check_pass_thru()) - self.assertRaises(TypeError, self.s.symmetric_difference, [[]]) - for C in set, frozenset, dict.fromkeys, str, list, tuple: - self.assertEqual(self.thetype('abcba').symmetric_difference(C('cdc')), set('abd')) - self.assertEqual(self.thetype('abcba').symmetric_difference(C('efgfe')), set('abcefg')) - self.assertEqual(self.thetype('abcba').symmetric_difference(C('ccb')), set('a')) - self.assertEqual(self.thetype('abcba').symmetric_difference(C('ef')), set('abcef')) - - def test_xor(self): - i = self.s.symmetric_difference(self.otherword) - self.assertEqual(self.s ^ set(self.otherword), i) - self.assertEqual(self.s ^ frozenset(self.otherword), i) - try: - self.s ^ self.otherword - except TypeError: - pass - else: - self.fail("s^t did not screen-out general iterables") - - def test_equality(self): - self.assertEqual(self.s, set(self.word)) - self.assertEqual(self.s, frozenset(self.word)) - self.assertEqual(self.s == self.word, False) - self.assertNotEqual(self.s, set(self.otherword)) - self.assertNotEqual(self.s, frozenset(self.otherword)) - self.assertEqual(self.s != self.word, True) - - def test_setOfFrozensets(self): - t = map(frozenset, ['abcdef', 'bcd', 'bdcb', 'fed', 'fedccba']) - s = self.thetype(t) - self.assertEqual(len(s), 3) - - def test_sub_and_super(self): - p, q, r = map(self.thetype, ['ab', 'abcde', 'def']) - self.assertTrue(p < q) - self.assertTrue(p <= q) - self.assertTrue(q <= q) - self.assertTrue(q > p) - self.assertTrue(q >= p) - self.assertFalse(q < r) - self.assertFalse(q <= r) - self.assertFalse(q > r) - self.assertFalse(q >= r) - self.assertTrue(set('a').issubset('abc')) - self.assertTrue(set('abc').issuperset('a')) - self.assertFalse(set('a').issubset('cbs')) - self.assertFalse(set('cbs').issuperset('a')) - - def test_pickling(self): - for i in range(pickle.HIGHEST_PROTOCOL + 1): - p = pickle.dumps(self.s, i) - dup = pickle.loads(p) - self.assertEqual(self.s, dup, "%s != %s" % (self.s, dup)) - if type(self.s) not in (set, frozenset): - self.s.x = 10 - p = pickle.dumps(self.s) - dup = pickle.loads(p) - self.assertEqual(self.s.x, dup.x) - - def test_deepcopy(self): - class Tracer: - def __init__(self, value): - self.value = value - def __hash__(self): - return self.value - def __deepcopy__(self, memo=None): - return Tracer(self.value + 1) - t = Tracer(10) - s = self.thetype([t]) - dup = copy.deepcopy(s) - self.assertNotEqual(id(s), id(dup)) - for elem in dup: - newt = elem - self.assertNotEqual(id(t), id(newt)) - self.assertEqual(t.value + 1, newt.value) - - def test_gc(self): - # Create a nest of cycles to exercise overall ref count check - class A: - pass - s = set(A() for i in range(1000)) - for elem in s: - elem.cycle = s - elem.sub = elem - elem.set = set([elem]) - - def test_subclass_with_custom_hash(self): - raise NotImplementedError() # runtime computed base class below - # Bug #1257731 - class H: # (self.thetype): - def __hash__(self): - return int(id(self) & 0x7fffffff) - s=H() - f=set() - f.add(s) - self.assertIn(s, f) - f.remove(s) - f.add(s) - f.discard(s) - - def test_badcmp(self): - s = self.thetype([BadCmp()]) - # Detect comparison errors during insertion and lookup - self.assertRaises(RuntimeError, self.thetype, [BadCmp(), BadCmp()]) - self.assertRaises(RuntimeError, s.__contains__, BadCmp()) - # Detect errors during mutating operations - if hasattr(s, 'add'): - self.assertRaises(RuntimeError, s.add, BadCmp()) - self.assertRaises(RuntimeError, s.discard, BadCmp()) - self.assertRaises(RuntimeError, s.remove, BadCmp()) - - def test_cyclical_repr(self): - w = ReprWrapper() - s = self.thetype([w]) - w.value = s - if self.thetype == set: - self.assertEqual(repr(s), '{set(...)}') - else: - name = repr(s).partition('(')[0] # strip class name - self.assertEqual(repr(s), '%s({%s(...)})' % (name, name)) - - def test_cyclical_print(self): - w = ReprWrapper() - s = self.thetype([w]) - w.value = s - fo = open(support.TESTFN, "w") - try: - fo.write(str(s)) - fo.close() - fo = open(support.TESTFN, "r") - self.assertEqual(fo.read(), repr(s)) - finally: - fo.close() - support.unlink(support.TESTFN) - - def test_do_not_rehash_dict_keys(self): - raise NotImplementedError() # cannot subclass int - n = 10 - d = None # dict.fromkeys(map(HashCountingInt, range(n))) - self.assertEqual(sum(elem.hash_count for elem in d), n) - s = self.thetype(d) - self.assertEqual(sum(elem.hash_count for elem in d), n) - s.difference(d) - self.assertEqual(sum(elem.hash_count for elem in d), n) - if hasattr(s, 'symmetric_difference_update'): - s.symmetric_difference_update(d) - self.assertEqual(sum(elem.hash_count for elem in d), n) - d2 = dict.fromkeys(set(d)) - self.assertEqual(sum(elem.hash_count for elem in d), n) - d3 = dict.fromkeys(frozenset(d)) - self.assertEqual(sum(elem.hash_count for elem in d), n) - d3 = dict.fromkeys(frozenset(d), 123) - self.assertEqual(sum(elem.hash_count for elem in d), n) - self.assertEqual(d3, dict.fromkeys(d, 123)) - - def test_container_iterator(self): - # Bug #3680: tp_traverse was not implemented for set iterator object - class C(object): - pass - obj = C() - ref = weakref.ref(obj) - container = set([obj, 1]) - obj.x = iter(container) - obj = None - container = None - gc.collect() - self.assertTrue(ref() is None, "Cycle was not collected") - -class TestSet(TestJointOps): - thetype = set - basetype = set - - def test_init(self): - s = self.thetype() - s.__init__(self.word) - self.assertEqual(s, set(self.word)) - s.__init__(self.otherword) - self.assertEqual(s, set(self.otherword)) - self.assertRaises(TypeError, s.__init__, s, 2); - self.assertRaises(TypeError, s.__init__, 1) - - def test_constructor_identity(self): - s = self.thetype(range(3)) - t = self.thetype(s) - self.assertNotEqual(id(s), id(t)) - - def test_set_literal(self): - raise NotImplementedError() - #s = set([1,2,3]) - #t = {1,2,3} - #self.assertEqual(s, t) - - def test_hash(self): - self.assertRaises(TypeError, hash, self.s) - - def test_clear(self): - self.s.clear() - self.assertEqual(self.s, set()) - self.assertEqual(len(self.s), 0) - - def test_copy(self): - dup = self.s.copy() - self.assertEqual(self.s, dup) - self.assertNotEqual(id(self.s), id(dup)) - self.assertEqual(type(dup), self.basetype) - - def test_add(self): - self.s.add('Q') - self.assertIn('Q', self.s) - dup = self.s.copy() - self.s.add('Q') - self.assertEqual(self.s, dup) - self.assertRaises(TypeError, self.s.add, []) - - def test_remove(self): - self.s.remove('a') - self.assertNotIn('a', self.s) - self.assertRaises(KeyError, self.s.remove, 'Q') - self.assertRaises(TypeError, self.s.remove, []) - s = self.thetype([frozenset(self.word)]) - self.assertIn(self.thetype(self.word), s) - s.remove(self.thetype(self.word)) - self.assertNotIn(self.thetype(self.word), s) - self.assertRaises(KeyError, self.s.remove, self.thetype(self.word)) - - def test_remove_keyerror_unpacking(self): - # bug: www.python.org/sf/1576657 - for v1 in ['Q', (1,)]: - try: - self.s.remove(v1) - except KeyError as e: - v2 = e.args[0] - self.assertEqual(v1, v2) - else: - self.fail() - - def test_remove_keyerror_set(self): - key = self.thetype([3, 4]) - try: - self.s.remove(key) - except KeyError as e: - self.assertTrue(e.args[0] is key, - "KeyError should be {0}, not {1}".format(key, - e.args[0])) - else: - self.fail() - - def test_discard(self): - self.s.discard('a') - self.assertNotIn('a', self.s) - self.s.discard('Q') - self.assertRaises(TypeError, self.s.discard, []) - s = self.thetype([frozenset(self.word)]) - self.assertIn(self.thetype(self.word), s) - s.discard(self.thetype(self.word)) - self.assertNotIn(self.thetype(self.word), s) - s.discard(self.thetype(self.word)) - - def test_pop(self): - for i in range(len(self.s)): - elem = self.s.pop() - self.assertNotIn(elem, self.s) - self.assertRaises(KeyError, self.s.pop) - - def test_update(self): - retval = self.s.update(self.otherword) - self.assertEqual(retval, None) - for c in (self.word + self.otherword): - self.assertIn(c, self.s) - self.assertRaises(PassThru, self.s.update, check_pass_thru()) - self.assertRaises(TypeError, self.s.update, [[]]) - for p, q in (('cdc', 'abcd'), ('efgfe', 'abcefg'), ('ccb', 'abc'), ('ef', 'abcef')): - for C in set, frozenset, dict.fromkeys, str, list, tuple: - s = self.thetype('abcba') - self.assertEqual(s.update(C(p)), None) - self.assertEqual(s, set(q)) - for p in ('cdc', 'efgfe', 'ccb', 'ef', 'abcda'): - q = 'ahi' - for C in set, frozenset, dict.fromkeys, str, list, tuple: - s = self.thetype('abcba') - self.assertEqual(s.update(C(p), C(q)), None) - self.assertEqual(s, set(s) | set(p) | set(q)) - - def test_ior(self): - self.s |= set(self.otherword) - for c in (self.word + self.otherword): - self.assertIn(c, self.s) - - def test_intersection_update(self): - retval = self.s.intersection_update(self.otherword) - self.assertEqual(retval, None) - for c in (self.word + self.otherword): - if c in self.otherword and c in self.word: - self.assertIn(c, self.s) - else: - self.assertNotIn(c, self.s) - self.assertRaises(PassThru, self.s.intersection_update, check_pass_thru()) - self.assertRaises(TypeError, self.s.intersection_update, [[]]) - for p, q in (('cdc', 'c'), ('efgfe', ''), ('ccb', 'bc'), ('ef', '')): - for C in set, frozenset, dict.fromkeys, str, list, tuple: - s = self.thetype('abcba') - self.assertEqual(s.intersection_update(C(p)), None) - self.assertEqual(s, set(q)) - ss = 'abcba' - s = self.thetype(ss) - t = 'cbc' - self.assertEqual(s.intersection_update(C(p), C(t)), None) - self.assertEqual(s, set('abcba')&set(p)&set(t)) - - def test_iand(self): - self.s &= set(self.otherword) - for c in (self.word + self.otherword): - if c in self.otherword and c in self.word: - self.assertIn(c, self.s) - else: - self.assertNotIn(c, self.s) - - def test_difference_update(self): - retval = self.s.difference_update(self.otherword) - self.assertEqual(retval, None) - for c in (self.word + self.otherword): - if c in self.word and c not in self.otherword: - self.assertIn(c, self.s) - else: - self.assertNotIn(c, self.s) - self.assertRaises(PassThru, self.s.difference_update, check_pass_thru()) - self.assertRaises(TypeError, self.s.difference_update, [[]]) - self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]]) - for p, q in (('cdc', 'ab'), ('efgfe', 'abc'), ('ccb', 'a'), ('ef', 'abc')): - for C in set, frozenset, dict.fromkeys, str, list, tuple: - s = self.thetype('abcba') - self.assertEqual(s.difference_update(C(p)), None) - self.assertEqual(s, set(q)) - - s = self.thetype('abcdefghih') - s.difference_update() - self.assertEqual(s, self.thetype('abcdefghih')) - - s = self.thetype('abcdefghih') - s.difference_update(C('aba')) - self.assertEqual(s, self.thetype('cdefghih')) - - s = self.thetype('abcdefghih') - s.difference_update(C('cdc'), C('aba')) - self.assertEqual(s, self.thetype('efghih')) - - def test_isub(self): - self.s -= set(self.otherword) - for c in (self.word + self.otherword): - if c in self.word and c not in self.otherword: - self.assertIn(c, self.s) - else: - self.assertNotIn(c, self.s) - - def test_symmetric_difference_update(self): - retval = self.s.symmetric_difference_update(self.otherword) - self.assertEqual(retval, None) - for c in (self.word + self.otherword): - if (c in self.word) ^ (c in self.otherword): - self.assertIn(c, self.s) - else: - self.assertNotIn(c, self.s) - self.assertRaises(PassThru, self.s.symmetric_difference_update, check_pass_thru()) - self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]]) - for p, q in (('cdc', 'abd'), ('efgfe', 'abcefg'), ('ccb', 'a'), ('ef', 'abcef')): - for C in set, frozenset, dict.fromkeys, str, list, tuple: - s = self.thetype('abcba') - self.assertEqual(s.symmetric_difference_update(C(p)), None) - self.assertEqual(s, set(q)) - - def test_ixor(self): - self.s ^= set(self.otherword) - for c in (self.word + self.otherword): - if (c in self.word) ^ (c in self.otherword): - self.assertIn(c, self.s) - else: - self.assertNotIn(c, self.s) - - def test_inplace_on_self(self): - t = self.s.copy() - t |= t - self.assertEqual(t, self.s) - t &= t - self.assertEqual(t, self.s) - t -= t - self.assertEqual(t, self.thetype()) - t = self.s.copy() - t ^= t - self.assertEqual(t, self.thetype()) - - def test_weakref(self): - s = self.thetype('gallahad') - p = weakref.proxy(s) - self.assertEqual(str(p), str(s)) - s = None - self.assertRaises(ReferenceError, str, p) - - def test_rich_compare(self): - class TestRichSetCompare: - def __gt__(self, some_set): - self.gt_called = True - return False - def __lt__(self, some_set): - self.lt_called = True - return False - def __ge__(self, some_set): - self.ge_called = True - return False - def __le__(self, some_set): - self.le_called = True - return False - - # This first tries the builtin rich set comparison, which doesn't know - # how to handle the custom object. Upon returning NotImplemented, the - # corresponding comparison on the right object is invoked. - myset = {1, 2, 3} - - myobj = TestRichSetCompare() - myset < myobj - self.assertTrue(myobj.gt_called) - - myobj = TestRichSetCompare() - myset > myobj - self.assertTrue(myobj.lt_called) - - myobj = TestRichSetCompare() - myset <= myobj - self.assertTrue(myobj.ge_called) - - myobj = TestRichSetCompare() - myset >= myobj - self.assertTrue(myobj.le_called) - - # C API test only available in a debug build - if hasattr(set, "test_c_api"): - def test_c_api(self): - self.assertEqual(set().test_c_api(), True) - -class SetSubclass(set): - pass - -class TestSetSubclass(TestSet): - thetype = SetSubclass - basetype = set - -class SetSubclassWithKeywordArgs(set): - def __init__(self, iterable=[], newarg=None): - set.__init__(self, iterable) - -class TestSetSubclassWithKeywordArgs(TestSet): - - def test_keywords_in_subclass(self): - 'SF bug #1486663 -- this used to erroneously raise a TypeError' - SetSubclassWithKeywordArgs(newarg=1) - -class TestFrozenSet(TestJointOps): - thetype = frozenset - basetype = frozenset - - def test_init(self): - s = self.thetype(self.word) - s.__init__(self.otherword) - self.assertEqual(s, set(self.word)) - - def test_singleton_empty_frozenset(self): - f = frozenset() - efs = [frozenset(), frozenset([]), frozenset(()), frozenset(''), - frozenset(), frozenset([]), frozenset(()), frozenset(''), - frozenset(range(0)), frozenset(frozenset()), - frozenset(f), f] - # All of the empty frozensets should have just one id() - self.assertEqual(len(set(map(id, efs))), 1) - - def test_constructor_identity(self): - s = self.thetype(range(3)) - t = self.thetype(s) - self.assertEqual(id(s), id(t)) - - def test_hash(self): - self.assertEqual(hash(self.thetype('abcdeb')), - hash(self.thetype('ebecda'))) - - # make sure that all permutations give the same hash value - n = 100 - seq = [randrange(n) for i in range(n)] - results = set() - for i in range(200): - shuffle(seq) - results.add(hash(self.thetype(seq))) - self.assertEqual(len(results), 1) - - def test_copy(self): - dup = self.s.copy() - self.assertEqual(id(self.s), id(dup)) - - def test_frozen_as_dictkey(self): - seq = list(range(10)) + list('abcdefg') + ['apple'] - key1 = self.thetype(seq) - key2 = self.thetype(reversed(seq)) - self.assertEqual(key1, key2) - self.assertNotEqual(id(key1), id(key2)) - d = {} - d[key1] = 42 - self.assertEqual(d[key2], 42) - - def test_hash_caching(self): - f = self.thetype('abcdcda') - self.assertEqual(hash(f), hash(f)) - - def test_hash_effectiveness(self): - n = 13 - hashvalues = set() - addhashvalue = hashvalues.add - elemmasks = [(i+1, 1<=": "issuperset", - } - - reverse = {"==": "==", - "!=": "!=", - "<": ">", - ">": "<", - "<=": ">=", - ">=": "<=", - } - - def test_issubset(self): - raise NotImplementedError() # eval not supported below - x = self.left - y = self.right - for case in "!=", "==", "<", "<=", ">", ">=": - expected = case in self.cases - # Test the binary infix spelling. - result = None ## eval("x" + case + "y", locals()) - self.assertEqual(result, expected) - # Test the "friendly" method-name spelling, if one exists. - if case in TestSubsets.case2method: - method = getattr(x, TestSubsets.case2method[case]) - result = method(y) - self.assertEqual(result, expected) - - # Now do the same for the operands reversed. - rcase = TestSubsets.reverse[case] - result = None ## eval("y" + rcase + "x", locals()) - self.assertEqual(result, expected) - if rcase in TestSubsets.case2method: - method = getattr(y, TestSubsets.case2method[rcase]) - result = method(x) - self.assertEqual(result, expected) -#------------------------------------------------------------------------------ - -class TestSubsetEqualEmpty(TestSubsets): - left = set() # type: Any - right = set() # type: Any - name = "both empty" - cases = "==", "<=", ">=" - -#------------------------------------------------------------------------------ - -class TestSubsetEqualNonEmpty(TestSubsets): - left = set([1, 2]) - right = set([1, 2]) - name = "equal pair" - cases = "==", "<=", ">=" - -#------------------------------------------------------------------------------ - -class TestSubsetEmptyNonEmpty(TestSubsets): - left = set() # type: Any - right = set([1, 2]) - name = "one empty, one non-empty" - cases = "!=", "<", "<=" - -#------------------------------------------------------------------------------ - -class TestSubsetPartial(TestSubsets): - left = set([1]) - right = set([1, 2]) - name = "one a non-empty proper subset of other" - cases = "!=", "<", "<=" - -#------------------------------------------------------------------------------ - -class TestSubsetNonOverlap(TestSubsets): - left = set([1]) - right = set([2]) - name = "neither empty, neither contains" - cases = "!=" - -#============================================================================== - -class TestOnlySetsInBinaryOps(unittest.TestCase): - - def test_eq_ne(self): - # Unlike the others, this is testing that == and != *are* allowed. - self.assertEqual(self.other == self.set, False) - self.assertEqual(self.set == self.other, False) - self.assertEqual(self.other != self.set, True) - self.assertEqual(self.set != self.other, True) - - def test_ge_gt_le_lt(self): - self.assertRaises(TypeError, lambda: self.set < self.other) - self.assertRaises(TypeError, lambda: self.set <= self.other) - self.assertRaises(TypeError, lambda: self.set > self.other) - self.assertRaises(TypeError, lambda: self.set >= self.other) - - self.assertRaises(TypeError, lambda: self.other < self.set) - self.assertRaises(TypeError, lambda: self.other <= self.set) - self.assertRaises(TypeError, lambda: self.other > self.set) - self.assertRaises(TypeError, lambda: self.other >= self.set) - - def test_update_operator(self): - try: - self.set |= self.other - except TypeError: - pass - else: - self.fail("expected TypeError") - - def test_update(self): - if self.otherIsIterable: - self.set.update(self.other) - else: - self.assertRaises(TypeError, self.set.update, self.other) - - def test_union(self): - self.assertRaises(TypeError, lambda: self.set | self.other) - self.assertRaises(TypeError, lambda: self.other | self.set) - if self.otherIsIterable: - self.set.union(self.other) - else: - self.assertRaises(TypeError, self.set.union, self.other) - - def test_intersection_update_operator(self): - try: - self.set &= self.other - except TypeError: - pass - else: - self.fail("expected TypeError") - - def test_intersection_update(self): - if self.otherIsIterable: - self.set.intersection_update(self.other) - else: - self.assertRaises(TypeError, - self.set.intersection_update, - self.other) - - def test_intersection(self): - self.assertRaises(TypeError, lambda: self.set & self.other) - self.assertRaises(TypeError, lambda: self.other & self.set) - if self.otherIsIterable: - self.set.intersection(self.other) - else: - self.assertRaises(TypeError, self.set.intersection, self.other) - - def test_sym_difference_update_operator(self): - try: - self.set ^= self.other - except TypeError: - pass - else: - self.fail("expected TypeError") - - def test_sym_difference_update(self): - if self.otherIsIterable: - self.set.symmetric_difference_update(self.other) - else: - self.assertRaises(TypeError, - self.set.symmetric_difference_update, - self.other) - - def test_sym_difference(self): - self.assertRaises(TypeError, lambda: self.set ^ self.other) - self.assertRaises(TypeError, lambda: self.other ^ self.set) - if self.otherIsIterable: - self.set.symmetric_difference(self.other) - else: - self.assertRaises(TypeError, self.set.symmetric_difference, self.other) - - def test_difference_update_operator(self): - try: - self.set -= self.other - except TypeError: - pass - else: - self.fail("expected TypeError") - - def test_difference_update(self): - if self.otherIsIterable: - self.set.difference_update(self.other) - else: - self.assertRaises(TypeError, - self.set.difference_update, - self.other) - - def test_difference(self): - self.assertRaises(TypeError, lambda: self.set - self.other) - self.assertRaises(TypeError, lambda: self.other - self.set) - if self.otherIsIterable: - self.set.difference(self.other) - else: - self.assertRaises(TypeError, self.set.difference, self.other) - -#------------------------------------------------------------------------------ - -class TestOnlySetsNumeric(TestOnlySetsInBinaryOps): - def setUp(self): - self.set = set((1, 2, 3)) - self.other = 19 - self.otherIsIterable = False - -#------------------------------------------------------------------------------ - -class TestOnlySetsDict(TestOnlySetsInBinaryOps): - def setUp(self): - self.set = set((1, 2, 3)) - self.other = {1:2, 3:4} - self.otherIsIterable = True - -#------------------------------------------------------------------------------ - -class TestOnlySetsOperator(TestOnlySetsInBinaryOps): - def setUp(self): - self.set = set((1, 2, 3)) - self.other = operator.add - self.otherIsIterable = False - -#------------------------------------------------------------------------------ - -class TestOnlySetsTuple(TestOnlySetsInBinaryOps): - def setUp(self): - self.set = set((1, 2, 3)) - self.other = (2, 4, 6) - self.otherIsIterable = True - -#------------------------------------------------------------------------------ - -class TestOnlySetsString(TestOnlySetsInBinaryOps): - def setUp(self): - self.set = set((1, 2, 3)) - self.other = 'abc' - self.otherIsIterable = True - -#------------------------------------------------------------------------------ - -class TestOnlySetsGenerator(TestOnlySetsInBinaryOps): - def setUp(self): - def gen(): - for i in range(0, 10, 2): - yield i - self.set = set((1, 2, 3)) - self.other = gen() - self.otherIsIterable = True - -#============================================================================== - -class TestCopying(unittest.TestCase): - - def test_copy(self): - dup = self.set.copy() - dup_list = sorted(dup, key=repr) - set_list = sorted(self.set, key=repr) - self.assertEqual(len(dup_list), len(set_list)) - for i in range(len(dup_list)): - self.assertTrue(dup_list[i] is set_list[i]) - - def test_deep_copy(self): - dup = copy.deepcopy(self.set) - ##print type(dup), repr(dup) - dup_list = sorted(dup, key=repr) - set_list = sorted(self.set, key=repr) - self.assertEqual(len(dup_list), len(set_list)) - for i in range(len(dup_list)): - self.assertEqual(dup_list[i], set_list[i]) - -#------------------------------------------------------------------------------ - -class TestCopyingEmpty(TestCopying): - def setUp(self): - self.set = set() - -#------------------------------------------------------------------------------ - -class TestCopyingSingleton(TestCopying): - def setUp(self): - self.set = set(["hello"]) - -#------------------------------------------------------------------------------ - -class TestCopyingTriple(TestCopying): - def setUp(self): - self.set = set(["zero", 0, None]) - -#------------------------------------------------------------------------------ - -class TestCopyingTuple(TestCopying): - def setUp(self): - self.set = set([(1, 2)]) - -#------------------------------------------------------------------------------ - -class TestCopyingNested(TestCopying): - def setUp(self): - self.set = set([((1, 2), (3, 4))]) - -#============================================================================== - -class TestIdentities(unittest.TestCase): - def setUp(self): - self.a = set('abracadabra') - self.b = set('alacazam') - - def test_binopsVsSubsets(self): - a, b = self.a, self.b - self.assertTrue(a - b < a) - self.assertTrue(b - a < b) - self.assertTrue(a & b < a) - self.assertTrue(a & b < b) - self.assertTrue(a | b > a) - self.assertTrue(a | b > b) - self.assertTrue(a ^ b < a | b) - - def test_commutativity(self): - a, b = self.a, self.b - self.assertEqual(a&b, b&a) - self.assertEqual(a|b, b|a) - self.assertEqual(a^b, b^a) - if a != b: - self.assertNotEqual(a-b, b-a) - - def test_summations(self): - # check that sums of parts equal the whole - a, b = self.a, self.b - self.assertEqual((a-b)|(a&b)|(b-a), a|b) - self.assertEqual((a&b)|(a^b), a|b) - self.assertEqual(a|(b-a), a|b) - self.assertEqual((a-b)|b, a|b) - self.assertEqual((a-b)|(a&b), a) - self.assertEqual((b-a)|(a&b), b) - self.assertEqual((a-b)|(b-a), a^b) - - def test_exclusion(self): - # check that inverse operations show non-overlap - a, b, zero = self.a, self.b, set() - self.assertEqual((a-b)&b, zero) - self.assertEqual((b-a)&a, zero) - self.assertEqual((a&b)&(a^b), zero) - -# Tests derived from test_itertools.py ======================================= - -def R(seqn): - 'Regular generator' - for i in seqn: - yield i - -class G: - 'Sequence using __getitem__' - def __init__(self, seqn): - self.seqn = seqn - def __getitem__(self, i): - return self.seqn[i] - -class I: - 'Sequence using iterator protocol' - def __init__(self, seqn): - self.seqn = seqn - self.i = 0 - def __iter__(self): - return self - def __next__(self): - if self.i >= len(self.seqn): raise StopIteration - v = self.seqn[self.i] - self.i += 1 - return v - -class Ig: - 'Sequence using iterator protocol defined with a generator' - def __init__(self, seqn): - self.seqn = seqn - self.i = 0 - def __iter__(self): - for val in self.seqn: - yield val - -class X: - 'Missing __getitem__ and __iter__' - def __init__(self, seqn): - self.seqn = seqn - self.i = 0 - def __next__(self): - if self.i >= len(self.seqn): raise StopIteration - v = self.seqn[self.i] - self.i += 1 - return v - -class N: - 'Iterator missing __next__()' - def __init__(self, seqn): - self.seqn = seqn - self.i = 0 - def __iter__(self): - return self - -class E: - 'Test propagation of exceptions' - def __init__(self, seqn): - self.seqn = seqn - self.i = 0 - def __iter__(self): - return self - def __next__(self): - 3 // 0 - -class S: - 'Test immediate stop' - def __init__(self, seqn): - pass - def __iter__(self): - return self - def __next__(self): - raise StopIteration - -from itertools import chain -def L(seqn): - 'Test multiple tiers of iterators' - return chain(map(lambda x:x, R(Ig(G(seqn))))) - -class TestVariousIteratorArgs(unittest.TestCase): - - def test_constructor(self): - for cons in (set, frozenset): - for s in ("123", "", range(1000), ('do', 1.2), range(2000,2200,5)): - for g in (G, I, Ig, S, L, R): - self.assertEqual(sorted(cons(g(s)), key=repr), sorted(g(s), key=repr)) - self.assertRaises(TypeError, cons , X(s)) - self.assertRaises(TypeError, cons , N(s)) - self.assertRaises(ZeroDivisionError, cons , E(s)) - - def test_inline_methods(self): - s = set('november') - for data in ("123", "", range(1000), ('do', 1.2), range(2000,2200,5), 'december'): - for meth in (s.union, s.intersection, s.difference, s.symmetric_difference, s.isdisjoint): - for g in (G, I, Ig, L, R): - expected = meth(data) - actual = meth(G(data)) - if isinstance(expected, bool): - self.assertEqual(actual, expected) - else: - self.assertEqual(sorted(actual, key=repr), sorted(expected, key=repr)) - self.assertRaises(TypeError, meth, X(s)) - self.assertRaises(TypeError, meth, N(s)) - self.assertRaises(ZeroDivisionError, meth, E(s)) - - def test_inplace_methods(self): - for data in ("123", "", range(1000), ('do', 1.2), range(2000,2200,5), 'december'): - for methname in ('update', 'intersection_update', - 'difference_update', 'symmetric_difference_update'): - for g in (G, I, Ig, S, L, R): - s = set('january') - t = s.copy() - getattr(s, methname)(list(g(data))) - getattr(t, methname)(g(data)) - self.assertEqual(sorted(s, key=repr), sorted(t, key=repr)) - - self.assertRaises(TypeError, getattr(set('january'), methname), X(data)) - self.assertRaises(TypeError, getattr(set('january'), methname), N(data)) - self.assertRaises(ZeroDivisionError, getattr(set('january'), methname), E(data)) - -be_bad = set2 = dict2 = None # type: Any - -class bad_eq: - def __eq__(self, other): - if be_bad: - set2.clear() - raise ZeroDivisionError - return self is other - def __hash__(self): - return 0 - -class bad_dict_clear: - def __eq__(self, other): - if be_bad: - dict2.clear() - return self is other - def __hash__(self): - return 0 - -class TestWeirdBugs(unittest.TestCase): - def test_8420_set_merge(self): - # This used to segfault - global be_bad, set2, dict2 - be_bad = False - set1 = {bad_eq()} - set2 = {bad_eq() for i in range(75)} - be_bad = True - self.assertRaises(ZeroDivisionError, set1.update, set2) - - be_bad = False - set1 = {bad_dict_clear()} - dict2 = {bad_dict_clear(): None} - be_bad = True - set1.symmetric_difference_update(dict2) - -# Application tests (based on David Eppstein's graph recipes ==================================== - -def powerset(U): - """Generates all subsets of a set or sequence U.""" - U = iter(U) - try: - x = frozenset([next(U)]) - for S in powerset(U): - yield S - yield S | x - except StopIteration: - yield frozenset() - -def cube(n): - """Graph of n-dimensional hypercube.""" - singletons = [frozenset([x]) for x in range(n)] - return dict([(x, frozenset([x^s for s in singletons])) - for x in powerset(range(n))]) - -def linegraph(G): - """Graph, the vertices of which are edges of G, - with two vertices being adjacent iff the corresponding - edges share a vertex.""" - L = {} - for x in G: - for y in G[x]: - nx = [frozenset([x,z]) for z in G[x] if z != y] - ny = [frozenset([y,z]) for z in G[y] if z != x] - L[frozenset([x,y])] = frozenset(nx+ny) - return L - -def faces(G): - 'Return a set of faces in G. Where a face is a set of vertices on that face' - # currently limited to triangles,squares, and pentagons - f = set() - for v1, edges in G.items(): - for v2 in edges: - for v3 in G[v2]: - if v1 == v3: - continue - if v1 in G[v3]: - f.add(frozenset([v1, v2, v3])) - else: - for v4 in G[v3]: - if v4 == v2: - continue - if v1 in G[v4]: - f.add(frozenset([v1, v2, v3, v4])) - else: - for v5 in G[v4]: - if v5 == v3 or v5 == v2: - continue - if v1 in G[v5]: - f.add(frozenset([v1, v2, v3, v4, v5])) - return f - - -class TestGraphs(unittest.TestCase): - - def test_cube(self): - - g = cube(3) # vert --> {v1, v2, v3} - vertices1 = set(g) - self.assertEqual(len(vertices1), 8) # eight vertices - for edge in g.values(): - self.assertEqual(len(edge), 3) # each vertex connects to three edges - vertices2 = set() - for edges in g.values(): - for v in edges: - vertices2.add(v) - self.assertEqual(vertices1, vertices2) # edge vertices in original set - - cubefaces = faces(g) - self.assertEqual(len(cubefaces), 6) # six faces - for face in cubefaces: - self.assertEqual(len(face), 4) # each face is a square - - def test_cuboctahedron(self): - - # http://en.wikipedia.org/wiki/Cuboctahedron - # 8 triangular faces and 6 square faces - # 12 identical vertices each connecting a triangle and square - - g = cube(3) - cuboctahedron = linegraph(g) # V( --> {V1, V2, V3, V4} - self.assertEqual(len(cuboctahedron), 12)# twelve vertices - - vertices = set(cuboctahedron) - for edges in cuboctahedron.values(): - self.assertEqual(len(edges), 4) # each vertex connects to four other vertices - othervertices = set(edge for edges in cuboctahedron.values() for edge in edges) - self.assertEqual(vertices, othervertices) # edge vertices in original set - - cubofaces = faces(cuboctahedron) - facesizes = collections.defaultdict(int) - for face in cubofaces: - facesizes[len(face)] += 1 - self.assertEqual(facesizes[3], 8) # eight triangular faces - self.assertEqual(facesizes[4], 6) # six square faces - - for vertex in cuboctahedron: - edge = vertex # Cuboctahedron vertices are edges in Cube - self.assertEqual(len(edge), 2) # Two cube vertices define an edge - for cubevert in edge: - self.assertIn(cubevert, g) - - -#============================================================================== - -def test_main(verbose=None): - test_classes = ( - TestSet, - TestSetSubclass, - TestSetSubclassWithKeywordArgs, - TestFrozenSet, - TestFrozenSetSubclass, - TestSetOfSets, - TestExceptionPropagation, - TestBasicOpsEmpty, - TestBasicOpsSingleton, - TestBasicOpsTuple, - TestBasicOpsTriple, - TestBasicOpsString, - TestBasicOpsBytes, - TestBasicOpsMixedStringBytes, - TestBinaryOps, - TestUpdateOps, - TestMutate, - TestSubsetEqualEmpty, - TestSubsetEqualNonEmpty, - TestSubsetEmptyNonEmpty, - TestSubsetPartial, - TestSubsetNonOverlap, - TestOnlySetsNumeric, - TestOnlySetsDict, - TestOnlySetsOperator, - TestOnlySetsTuple, - TestOnlySetsString, - TestOnlySetsGenerator, - TestCopyingEmpty, - TestCopyingSingleton, - TestCopyingTriple, - TestCopyingTuple, - TestCopyingNested, - TestIdentities, - TestVariousIteratorArgs, - TestGraphs, - TestWeirdBugs, - ) - - support.run_unittest(*test_classes) - - # verify reference counting - if verbose and hasattr(sys, "gettotalrefcount"): - import gc - counts = [None] * 5 - for i in range(len(counts)): - support.run_unittest(*test_classes) - gc.collect() - counts[i] = sys.gettotalrefcount() - print(counts) - -if __name__ == "__main__": - test_main(verbose=True) diff --git a/test-data/stdlib-samples/3.2/test/test_shutil.py b/test-data/stdlib-samples/3.2/test/test_shutil.py deleted file mode 100644 index 32e0fd153bcf..000000000000 --- a/test-data/stdlib-samples/3.2/test/test_shutil.py +++ /dev/null @@ -1,978 +0,0 @@ -# Copyright (C) 2003 Python Software Foundation - -import unittest -import shutil -import tempfile -import sys -import stat -import os -import os.path -import functools -from test import support -from test.support import TESTFN -from os.path import splitdrive -from distutils.spawn import find_executable, spawn -from shutil import (_make_tarball, _make_zipfile, make_archive, - register_archive_format, unregister_archive_format, - get_archive_formats, Error, unpack_archive, - register_unpack_format, RegistryError, - unregister_unpack_format, get_unpack_formats) -import tarfile -import warnings - -from test import support -from test.support import check_warnings, captured_stdout - -from typing import ( - Any, Callable, Tuple, List, Sequence, BinaryIO, IO, Union, cast -) -from types import TracebackType - -import bz2 -BZ2_SUPPORTED = True - -TESTFN2 = TESTFN + "2" - -import grp -import pwd -UID_GID_SUPPORT = True - -import zlib - -import zipfile -ZIP_SUPPORT = True - -def _fake_rename(*args: Any, **kwargs: Any) -> None: - # Pretend the destination path is on a different filesystem. - raise OSError() - -def mock_rename(func: Any) -> Any: - @functools.wraps(func) - def wrap(*args: Any, **kwargs: Any) -> Any: - try: - builtin_rename = shutil.rename - shutil.rename = cast(Any, _fake_rename) - return func(*args, **kwargs) - finally: - shutil.rename = cast(Any, builtin_rename) - return wrap - -class TestShutil(unittest.TestCase): - - def setUp(self) -> None: - super().setUp() - self.tempdirs = [] # type: List[str] - - def tearDown(self) -> None: - super().tearDown() - while self.tempdirs: - d = self.tempdirs.pop() - shutil.rmtree(d, os.name in ('nt', 'cygwin')) - - def write_file(self, path: Union[str, List[str], tuple], content: str = 'xxx') -> None: - """Writes a file in the given path. - - - path can be a string or a sequence. - """ - if isinstance(path, list): - path = os.path.join(*path) - elif isinstance(path, tuple): - path = cast(str, os.path.join(*path)) - f = open(path, 'w') - try: - f.write(content) - finally: - f.close() - - def mkdtemp(self) -> str: - """Create a temporary directory that will be cleaned up. - - Returns the path of the directory. - """ - d = tempfile.mkdtemp() - self.tempdirs.append(d) - return d - - def test_rmtree_errors(self) -> None: - # filename is guaranteed not to exist - filename = tempfile.mktemp() - self.assertRaises(OSError, shutil.rmtree, filename) - - # See bug #1071513 for why we don't run this on cygwin - # and bug #1076467 for why we don't run this as root. - if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin' - and not (hasattr(os, 'geteuid') and os.geteuid() == 0)): - def test_on_error(self) -> None: - self.errorState = 0 - os.mkdir(TESTFN) - self.childpath = os.path.join(TESTFN, 'a') - f = open(self.childpath, 'w') - f.close() - old_dir_mode = os.stat(TESTFN).st_mode - old_child_mode = os.stat(self.childpath).st_mode - # Make unwritable. - os.chmod(self.childpath, stat.S_IREAD) - os.chmod(TESTFN, stat.S_IREAD) - - shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) - # Test whether onerror has actually been called. - self.assertEqual(self.errorState, 2, - "Expected call to onerror function did not happen.") - - # Make writable again. - os.chmod(TESTFN, old_dir_mode) - os.chmod(self.childpath, old_child_mode) - - # Clean up. - shutil.rmtree(TESTFN) - - def check_args_to_onerror(self, func: Callable[[str], Any], arg: str, - exc: Tuple[type, BaseException, - TracebackType]) -> None: - # test_rmtree_errors deliberately runs rmtree - # on a directory that is chmod 400, which will fail. - # This function is run when shutil.rmtree fails. - # 99.9% of the time it initially fails to remove - # a file in the directory, so the first time through - # func is os.remove. - # However, some Linux machines running ZFS on - # FUSE experienced a failure earlier in the process - # at os.listdir. The first failure may legally - # be either. - if self.errorState == 0: - if func is os.remove: - self.assertEqual(arg, self.childpath) - else: - self.assertIs(func, os.listdir, - "func must be either os.remove or os.listdir") - self.assertEqual(arg, TESTFN) - self.assertTrue(issubclass(exc[0], OSError)) - self.errorState = 1 - else: - self.assertEqual(func, os.rmdir) - self.assertEqual(arg, TESTFN) - self.assertTrue(issubclass(exc[0], OSError)) - self.errorState = 2 - - def test_rmtree_dont_delete_file(self) -> None: - # When called on a file instead of a directory, don't delete it. - handle, path = tempfile.mkstemp() - os.fdopen(handle).close() - self.assertRaises(OSError, shutil.rmtree, path) - os.remove(path) - - def _write_data(self, path: str, data: str) -> None: - f = open(path, "w") - f.write(data) - f.close() - - def test_copytree_simple(self) -> None: - - def read_data(path: str) -> str: - f = open(path) - data = f.read() - f.close() - return data - - src_dir = tempfile.mkdtemp() - dst_dir = os.path.join(tempfile.mkdtemp(), 'destination') - self._write_data(os.path.join(src_dir, 'test.txt'), '123') - os.mkdir(os.path.join(src_dir, 'test_dir')) - self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') - - try: - shutil.copytree(src_dir, dst_dir) - self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt'))) - self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir'))) - self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir', - 'test.txt'))) - actual = read_data(os.path.join(dst_dir, 'test.txt')) - self.assertEqual(actual, '123') - actual = read_data(os.path.join(dst_dir, 'test_dir', 'test.txt')) - self.assertEqual(actual, '456') - finally: - for path in ( - os.path.join(src_dir, 'test.txt'), - os.path.join(dst_dir, 'test.txt'), - os.path.join(src_dir, 'test_dir', 'test.txt'), - os.path.join(dst_dir, 'test_dir', 'test.txt'), - ): - if os.path.exists(path): - os.remove(path) - for path in (src_dir, - os.path.dirname(dst_dir) - ): - if os.path.exists(path): - shutil.rmtree(path) - - def test_copytree_with_exclude(self) -> None: - - def read_data(path: str) -> str: - f = open(path) - data = f.read() - f.close() - return data - - # creating data - join = os.path.join - exists = os.path.exists - src_dir = tempfile.mkdtemp() - try: - dst_dir = join(tempfile.mkdtemp(), 'destination') - self._write_data(join(src_dir, 'test.txt'), '123') - self._write_data(join(src_dir, 'test.tmp'), '123') - os.mkdir(join(src_dir, 'test_dir')) - self._write_data(join(src_dir, 'test_dir', 'test.txt'), '456') - os.mkdir(join(src_dir, 'test_dir2')) - self._write_data(join(src_dir, 'test_dir2', 'test.txt'), '456') - os.mkdir(join(src_dir, 'test_dir2', 'subdir')) - os.mkdir(join(src_dir, 'test_dir2', 'subdir2')) - self._write_data(join(src_dir, 'test_dir2', 'subdir', 'test.txt'), - '456') - self._write_data(join(src_dir, 'test_dir2', 'subdir2', 'test.py'), - '456') - - - # testing glob-like patterns - try: - patterns = shutil.ignore_patterns('*.tmp', 'test_dir2') - shutil.copytree(src_dir, dst_dir, ignore=patterns) - # checking the result: some elements should not be copied - self.assertTrue(exists(join(dst_dir, 'test.txt'))) - self.assertTrue(not exists(join(dst_dir, 'test.tmp'))) - self.assertTrue(not exists(join(dst_dir, 'test_dir2'))) - finally: - if os.path.exists(dst_dir): - shutil.rmtree(dst_dir) - try: - patterns = shutil.ignore_patterns('*.tmp', 'subdir*') - shutil.copytree(src_dir, dst_dir, ignore=patterns) - # checking the result: some elements should not be copied - self.assertTrue(not exists(join(dst_dir, 'test.tmp'))) - self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir2'))) - self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir'))) - finally: - if os.path.exists(dst_dir): - shutil.rmtree(dst_dir) - - # testing callable-style - try: - def _filter(src: str, names: Sequence[str]) -> List[str]: - res = [] # type: List[str] - for name in names: - path = os.path.join(src, name) - - if (os.path.isdir(path) and - path.split()[-1] == 'subdir'): - res.append(name) - elif os.path.splitext(path)[-1] in ('.py'): - res.append(name) - return res - - shutil.copytree(src_dir, dst_dir, ignore=_filter) - - # checking the result: some elements should not be copied - self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir2', - 'test.py'))) - self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir'))) - - finally: - if os.path.exists(dst_dir): - shutil.rmtree(dst_dir) - finally: - shutil.rmtree(src_dir) - shutil.rmtree(os.path.dirname(dst_dir)) - - @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link') - def test_dont_copy_file_onto_link_to_itself(self) -> None: - # Temporarily disable test on Windows. - if os.name == 'nt': - return - # bug 851123. - os.mkdir(TESTFN) - src = os.path.join(TESTFN, 'cheese') - dst = os.path.join(TESTFN, 'shop') - try: - with open(src, 'w') as f: - f.write('cheddar') - os.link(src, dst) - self.assertRaises(shutil.Error, shutil.copyfile, src, dst) - with open(src, 'r') as f: - self.assertEqual(f.read(), 'cheddar') - os.remove(dst) - finally: - shutil.rmtree(TESTFN, ignore_errors=True) - - @support.skip_unless_symlink - def test_dont_copy_file_onto_symlink_to_itself(self) -> None: - # bug 851123. - os.mkdir(TESTFN) - src = os.path.join(TESTFN, 'cheese') - dst = os.path.join(TESTFN, 'shop') - try: - with open(src, 'w') as f: - f.write('cheddar') - # Using `src` here would mean we end up with a symlink pointing - # to TESTFN/TESTFN/cheese, while it should point at - # TESTFN/cheese. - os.symlink('cheese', dst) - self.assertRaises(shutil.Error, shutil.copyfile, src, dst) - with open(src, 'r') as f: - self.assertEqual(f.read(), 'cheddar') - os.remove(dst) - finally: - shutil.rmtree(TESTFN, ignore_errors=True) - - @support.skip_unless_symlink - def test_rmtree_on_symlink(self) -> None: - # bug 1669. - os.mkdir(TESTFN) - try: - src = os.path.join(TESTFN, 'cheese') - dst = os.path.join(TESTFN, 'shop') - os.mkdir(src) - os.symlink(src, dst) - self.assertRaises(OSError, shutil.rmtree, dst) - finally: - shutil.rmtree(TESTFN, ignore_errors=True) - - if hasattr(os, "mkfifo"): - # Issue #3002: copyfile and copytree block indefinitely on named pipes - def test_copyfile_named_pipe(self) -> None: - os.mkfifo(TESTFN) - try: - self.assertRaises(shutil.SpecialFileError, - shutil.copyfile, TESTFN, TESTFN2) - self.assertRaises(shutil.SpecialFileError, - shutil.copyfile, __file__, TESTFN) - finally: - os.remove(TESTFN) - - @support.skip_unless_symlink - def test_copytree_named_pipe(self) -> None: - os.mkdir(TESTFN) - try: - subdir = os.path.join(TESTFN, "subdir") - os.mkdir(subdir) - pipe = os.path.join(subdir, "mypipe") - os.mkfifo(pipe) - try: - shutil.copytree(TESTFN, TESTFN2) - except shutil.Error as e: - errors = e.args[0] - self.assertEqual(len(errors), 1) - src, dst, error_msg = errors[0] - self.assertEqual("`%s` is a named pipe" % pipe, error_msg) - else: - self.fail("shutil.Error should have been raised") - finally: - shutil.rmtree(TESTFN, ignore_errors=True) - shutil.rmtree(TESTFN2, ignore_errors=True) - - def test_copytree_special_func(self) -> None: - - src_dir = self.mkdtemp() - dst_dir = os.path.join(self.mkdtemp(), 'destination') - self._write_data(os.path.join(src_dir, 'test.txt'), '123') - os.mkdir(os.path.join(src_dir, 'test_dir')) - self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') - - copied = [] # type: List[Tuple[str, str]] - def _copy(src: str, dst: str) -> None: - copied.append((src, dst)) - - shutil.copytree(src_dir, dst_dir, copy_function=_copy) - self.assertEqual(len(copied), 2) - - @support.skip_unless_symlink - def test_copytree_dangling_symlinks(self) -> None: - - # a dangling symlink raises an error at the end - src_dir = self.mkdtemp() - dst_dir = os.path.join(self.mkdtemp(), 'destination') - os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt')) - os.mkdir(os.path.join(src_dir, 'test_dir')) - self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') - self.assertRaises(Error, shutil.copytree, src_dir, dst_dir) - - # a dangling symlink is ignored with the proper flag - dst_dir = os.path.join(self.mkdtemp(), 'destination2') - shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True) - self.assertNotIn('test.txt', os.listdir(dst_dir)) - - # a dangling symlink is copied if symlinks=True - dst_dir = os.path.join(self.mkdtemp(), 'destination3') - shutil.copytree(src_dir, dst_dir, symlinks=True) - self.assertIn('test.txt', os.listdir(dst_dir)) - - def _copy_file(self, - method: Callable[[str, str], None]) -> Tuple[str, str]: - fname = 'test.txt' - tmpdir = self.mkdtemp() - self.write_file([tmpdir, fname]) - file1 = os.path.join(tmpdir, fname) - tmpdir2 = self.mkdtemp() - method(file1, tmpdir2) - file2 = os.path.join(tmpdir2, fname) - return (file1, file2) - - @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod') - def test_copy(self) -> None: - # Ensure that the copied file exists and has the same mode bits. - file1, file2 = self._copy_file(shutil.copy) - self.assertTrue(os.path.exists(file2)) - self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode) - - @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod') - @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime') - def test_copy2(self) -> None: - # Ensure that the copied file exists and has the same mode and - # modification time bits. - file1, file2 = self._copy_file(shutil.copy2) - self.assertTrue(os.path.exists(file2)) - file1_stat = os.stat(file1) - file2_stat = os.stat(file2) - self.assertEqual(file1_stat.st_mode, file2_stat.st_mode) - for attr in 'st_atime', 'st_mtime': - # The modification times may be truncated in the new file. - self.assertLessEqual(getattr(file1_stat, attr), - getattr(file2_stat, attr) + 1) - if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'): - self.assertEqual(getattr(file1_stat, 'st_flags'), - getattr(file2_stat, 'st_flags')) - - @unittest.skipUnless(zlib, "requires zlib") - def test_make_tarball(self) -> None: - # creating something to tar - tmpdir = self.mkdtemp() - self.write_file([tmpdir, 'file1'], 'xxx') - self.write_file([tmpdir, 'file2'], 'xxx') - os.mkdir(os.path.join(tmpdir, 'sub')) - self.write_file([tmpdir, 'sub', 'file3'], 'xxx') - - tmpdir2 = self.mkdtemp() - # force shutil to create the directory - os.rmdir(tmpdir2) - unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0], - "source and target should be on same drive") - - base_name = os.path.join(tmpdir2, 'archive') - - # working with relative paths to avoid tar warnings - old_dir = os.getcwd() - os.chdir(tmpdir) - try: - _make_tarball(splitdrive(base_name)[1], '.') - finally: - os.chdir(old_dir) - - # check if the compressed tarball was created - tarball = base_name + '.tar.gz' - self.assertTrue(os.path.exists(tarball)) - - # trying an uncompressed one - base_name = os.path.join(tmpdir2, 'archive') - old_dir = os.getcwd() - os.chdir(tmpdir) - try: - _make_tarball(splitdrive(base_name)[1], '.', compress=None) - finally: - os.chdir(old_dir) - tarball = base_name + '.tar' - self.assertTrue(os.path.exists(tarball)) - - def _tarinfo(self, path: str) -> tuple: - tar = tarfile.open(path) - try: - names = tar.getnames() - names.sort() - return tuple(names) - finally: - tar.close() - - def _create_files(self) -> Tuple[str, str, str]: - # creating something to tar - tmpdir = self.mkdtemp() - dist = os.path.join(tmpdir, 'dist') - os.mkdir(dist) - self.write_file([dist, 'file1'], 'xxx') - self.write_file([dist, 'file2'], 'xxx') - os.mkdir(os.path.join(dist, 'sub')) - self.write_file([dist, 'sub', 'file3'], 'xxx') - os.mkdir(os.path.join(dist, 'sub2')) - tmpdir2 = self.mkdtemp() - base_name = os.path.join(tmpdir2, 'archive') - return tmpdir, tmpdir2, base_name - - @unittest.skipUnless(zlib, "Requires zlib") - @unittest.skipUnless(find_executable('tar') and find_executable('gzip'), - 'Need the tar command to run') - def test_tarfile_vs_tar(self) -> None: - tmpdir, tmpdir2, base_name = self._create_files() - old_dir = os.getcwd() - os.chdir(tmpdir) - try: - _make_tarball(base_name, 'dist') - finally: - os.chdir(old_dir) - - # check if the compressed tarball was created - tarball = base_name + '.tar.gz' - self.assertTrue(os.path.exists(tarball)) - - # now create another tarball using `tar` - tarball2 = os.path.join(tmpdir, 'archive2.tar.gz') - tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist'] - gzip_cmd = ['gzip', '-f9', 'archive2.tar'] - old_dir = os.getcwd() - os.chdir(tmpdir) - try: - with captured_stdout() as s: - spawn(tar_cmd) - spawn(gzip_cmd) - finally: - os.chdir(old_dir) - - self.assertTrue(os.path.exists(tarball2)) - # let's compare both tarballs - self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2)) - - # trying an uncompressed one - base_name = os.path.join(tmpdir2, 'archive') - old_dir = os.getcwd() - os.chdir(tmpdir) - try: - _make_tarball(base_name, 'dist', compress=None) - finally: - os.chdir(old_dir) - tarball = base_name + '.tar' - self.assertTrue(os.path.exists(tarball)) - - # now for a dry_run - base_name = os.path.join(tmpdir2, 'archive') - old_dir = os.getcwd() - os.chdir(tmpdir) - try: - _make_tarball(base_name, 'dist', compress=None, dry_run=True) - finally: - os.chdir(old_dir) - tarball = base_name + '.tar' - self.assertTrue(os.path.exists(tarball)) - - @unittest.skipUnless(zlib, "Requires zlib") - @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run') - def test_make_zipfile(self) -> None: - # creating something to tar - tmpdir = self.mkdtemp() - self.write_file([tmpdir, 'file1'], 'xxx') - self.write_file([tmpdir, 'file2'], 'xxx') - - tmpdir2 = self.mkdtemp() - # force shutil to create the directory - os.rmdir(tmpdir2) - base_name = os.path.join(tmpdir2, 'archive') - _make_zipfile(base_name, tmpdir) - - # check if the compressed tarball was created - tarball = base_name + '.zip' - self.assertTrue(os.path.exists(tarball)) - - - def test_make_archive(self) -> None: - tmpdir = self.mkdtemp() - base_name = os.path.join(tmpdir, 'archive') - self.assertRaises(ValueError, make_archive, base_name, 'xxx') - - @unittest.skipUnless(zlib, "Requires zlib") - def test_make_archive_owner_group(self) -> None: - # testing make_archive with owner and group, with various combinations - # this works even if there's not gid/uid support - if UID_GID_SUPPORT: - group = grp.getgrgid(0).gr_name - owner = pwd.getpwuid(0).pw_name - else: - group = owner = 'root' - - base_dir, root_dir, base_name = self._create_files() - base_name = os.path.join(self.mkdtemp() , 'archive') - res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner, - group=group) - self.assertTrue(os.path.exists(res)) - - res = make_archive(base_name, 'zip', root_dir, base_dir) - self.assertTrue(os.path.exists(res)) - - res = make_archive(base_name, 'tar', root_dir, base_dir, - owner=owner, group=group) - self.assertTrue(os.path.exists(res)) - - res = make_archive(base_name, 'tar', root_dir, base_dir, - owner='kjhkjhkjg', group='oihohoh') - self.assertTrue(os.path.exists(res)) - - - @unittest.skipUnless(zlib, "Requires zlib") - @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support") - def test_tarfile_root_owner(self) -> None: - tmpdir, tmpdir2, base_name = self._create_files() - old_dir = os.getcwd() - os.chdir(tmpdir) - group = grp.getgrgid(0).gr_name - owner = pwd.getpwuid(0).pw_name - try: - archive_name = _make_tarball(base_name, 'dist', compress=None, - owner=owner, group=group) - finally: - os.chdir(old_dir) - - # check if the compressed tarball was created - self.assertTrue(os.path.exists(archive_name)) - - # now checks the rights - archive = tarfile.open(archive_name) - try: - for member in archive.getmembers(): - self.assertEqual(member.uid, 0) - self.assertEqual(member.gid, 0) - finally: - archive.close() - - def test_make_archive_cwd(self) -> None: - current_dir = os.getcwd() - def _breaks(*args: Any, **kw: Any) -> None: - raise RuntimeError() - - register_archive_format('xxx', _breaks, [], 'xxx file') - try: - try: - make_archive('xxx', 'xxx', root_dir=self.mkdtemp()) - except Exception: - pass - self.assertEqual(os.getcwd(), current_dir) - finally: - unregister_archive_format('xxx') - - def test_register_archive_format(self) -> None: - - self.assertRaises(TypeError, register_archive_format, 'xxx', 1) - self.assertRaises(TypeError, register_archive_format, 'xxx', - lambda: 1/0, - 1) - self.assertRaises(TypeError, register_archive_format, 'xxx', - lambda: 1/0, - [(1, 2), (1, 2, 3)]) - - register_archive_format('xxx', lambda: 1/0, [('x', 2)], 'xxx file') - formats = [name for name, params in get_archive_formats()] - self.assertIn('xxx', formats) - - unregister_archive_format('xxx') - formats = [name for name, params in get_archive_formats()] - self.assertNotIn('xxx', formats) - - def _compare_dirs(self, dir1: str, dir2: str) -> List[str]: - # check that dir1 and dir2 are equivalent, - # return the diff - diff = [] # type: List[str] - for root, dirs, files in os.walk(dir1): - for file_ in files: - path = os.path.join(root, file_) - target_path = os.path.join(dir2, os.path.split(path)[-1]) - if not os.path.exists(target_path): - diff.append(file_) - return diff - - @unittest.skipUnless(zlib, "Requires zlib") - def test_unpack_archive(self) -> None: - formats = ['tar', 'gztar', 'zip'] - if BZ2_SUPPORTED: - formats.append('bztar') - - for format in formats: - tmpdir = self.mkdtemp() - base_dir, root_dir, base_name = self._create_files() - tmpdir2 = self.mkdtemp() - filename = make_archive(base_name, format, root_dir, base_dir) - - # let's try to unpack it now - unpack_archive(filename, tmpdir2) - diff = self._compare_dirs(tmpdir, tmpdir2) - self.assertEqual(diff, []) - - # and again, this time with the format specified - tmpdir3 = self.mkdtemp() - unpack_archive(filename, tmpdir3, format=format) - diff = self._compare_dirs(tmpdir, tmpdir3) - self.assertEqual(diff, []) - self.assertRaises(shutil.ReadError, unpack_archive, TESTFN) - self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx') - - def test_unpack_registery(self) -> None: - - formats = get_unpack_formats() - - def _boo(filename: str, extract_dir: str, extra: int) -> None: - self.assertEqual(extra, 1) - self.assertEqual(filename, 'stuff.boo') - self.assertEqual(extract_dir, 'xx') - - register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)]) - unpack_archive('stuff.boo', 'xx') - - # trying to register a .boo unpacker again - self.assertRaises(RegistryError, register_unpack_format, 'Boo2', - ['.boo'], _boo) - - # should work now - unregister_unpack_format('Boo') - register_unpack_format('Boo2', ['.boo'], _boo) - self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats()) - self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats()) - - # let's leave a clean state - unregister_unpack_format('Boo2') - self.assertEqual(get_unpack_formats(), formats) - - -class TestMove(unittest.TestCase): - - def setUp(self) -> None: - filename = "foo" - self.src_dir = tempfile.mkdtemp() - self.dst_dir = tempfile.mkdtemp() - self.src_file = os.path.join(self.src_dir, filename) - self.dst_file = os.path.join(self.dst_dir, filename) - with open(self.src_file, "wb") as f: - f.write(b"spam") - - def tearDown(self) -> None: - for d in (self.src_dir, self.dst_dir): - try: - if d: - shutil.rmtree(d) - except: - pass - - def _check_move_file(self, src: str, dst: str, real_dst: str) -> None: - with open(src, "rb") as f: - contents = f.read() - shutil.move(src, dst) - with open(real_dst, "rb") as f: - self.assertEqual(contents, f.read()) - self.assertFalse(os.path.exists(src)) - - def _check_move_dir(self, src: str, dst: str, real_dst: str) -> None: - contents = sorted(os.listdir(src)) - shutil.move(src, dst) - self.assertEqual(contents, sorted(os.listdir(real_dst))) - self.assertFalse(os.path.exists(src)) - - def test_move_file(self) -> None: - # Move a file to another location on the same filesystem. - self._check_move_file(self.src_file, self.dst_file, self.dst_file) - - def test_move_file_to_dir(self) -> None: - # Move a file inside an existing dir on the same filesystem. - self._check_move_file(self.src_file, self.dst_dir, self.dst_file) - - @mock_rename - def test_move_file_other_fs(self) -> None: - # Move a file to an existing dir on another filesystem. - self.test_move_file() - - @mock_rename - def test_move_file_to_dir_other_fs(self) -> None: - # Move a file to another location on another filesystem. - self.test_move_file_to_dir() - - def test_move_dir(self) -> None: - # Move a dir to another location on the same filesystem. - dst_dir = tempfile.mktemp() - try: - self._check_move_dir(self.src_dir, dst_dir, dst_dir) - finally: - try: - shutil.rmtree(dst_dir) - except: - pass - - @mock_rename - def test_move_dir_other_fs(self) -> None: - # Move a dir to another location on another filesystem. - self.test_move_dir() - - def test_move_dir_to_dir(self) -> None: - # Move a dir inside an existing dir on the same filesystem. - self._check_move_dir(self.src_dir, self.dst_dir, - os.path.join(self.dst_dir, os.path.basename(self.src_dir))) - - @mock_rename - def test_move_dir_to_dir_other_fs(self) -> None: - # Move a dir inside an existing dir on another filesystem. - self.test_move_dir_to_dir() - - def test_existing_file_inside_dest_dir(self) -> None: - # A file with the same name inside the destination dir already exists. - with open(self.dst_file, "wb"): - pass - self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir) - - def test_dont_move_dir_in_itself(self) -> None: - # Moving a dir inside itself raises an Error. - dst = os.path.join(self.src_dir, "bar") - self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst) - - def test_destinsrc_false_negative(self) -> None: - os.mkdir(TESTFN) - try: - for src, dst in [('srcdir', 'srcdir/dest')]: - src = os.path.join(TESTFN, src) - dst = os.path.join(TESTFN, dst) - self.assertTrue(shutil._destinsrc(src, dst), - msg='_destinsrc() wrongly concluded that ' - 'dst (%s) is not in src (%s)' % (dst, src)) - finally: - shutil.rmtree(TESTFN, ignore_errors=True) - - def test_destinsrc_false_positive(self) -> None: - os.mkdir(TESTFN) - try: - for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]: - src = os.path.join(TESTFN, src) - dst = os.path.join(TESTFN, dst) - self.assertFalse(shutil._destinsrc(src, dst), - msg='_destinsrc() wrongly concluded that ' - 'dst (%s) is in src (%s)' % (dst, src)) - finally: - shutil.rmtree(TESTFN, ignore_errors=True) - - -class TestCopyFile(unittest.TestCase): - - _delete = False - - class Faux(object): - _entered = False - _exited_with = None # type: tuple - _raised = False - def __init__(self, raise_in_exit: bool = False, - suppress_at_exit: bool = True) -> None: - self._raise_in_exit = raise_in_exit - self._suppress_at_exit = suppress_at_exit - def read(self, *args: Any) -> str: - return '' - def __enter__(self) -> None: - self._entered = True - def __exit__(self, exc_type: type, exc_val: BaseException, - exc_tb: TracebackType) -> bool: - self._exited_with = exc_type, exc_val, exc_tb - if self._raise_in_exit: - self._raised = True - raise IOError("Cannot close") - return self._suppress_at_exit - - def tearDown(self) -> None: - shutil.open = open - - def _set_shutil_open(self, func: Any) -> None: - shutil.open = func - self._delete = True - - def test_w_source_open_fails(self) -> None: - def _open(filename: str, mode: str= 'r') -> BinaryIO: - if filename == 'srcfile': - raise IOError('Cannot open "srcfile"') - assert 0 # shouldn't reach here. - - self._set_shutil_open(_open) - - self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile') - - def test_w_dest_open_fails(self) -> None: - - srcfile = TestCopyFile.Faux() - - def _open(filename: str, mode: str = 'r') -> TestCopyFile.Faux: - if filename == 'srcfile': - return srcfile - if filename == 'destfile': - raise IOError('Cannot open "destfile"') - assert 0 # shouldn't reach here. - - self._set_shutil_open(_open) - - shutil.copyfile('srcfile', 'destfile') - self.assertTrue(srcfile._entered) - self.assertTrue(srcfile._exited_with[0] is IOError) - self.assertEqual(srcfile._exited_with[1].args, - ('Cannot open "destfile"',)) - - def test_w_dest_close_fails(self) -> None: - - srcfile = TestCopyFile.Faux() - destfile = TestCopyFile.Faux(True) - - def _open(filename: str, mode: str = 'r') -> TestCopyFile.Faux: - if filename == 'srcfile': - return srcfile - if filename == 'destfile': - return destfile - assert 0 # shouldn't reach here. - - self._set_shutil_open(_open) - - shutil.copyfile('srcfile', 'destfile') - self.assertTrue(srcfile._entered) - self.assertTrue(destfile._entered) - self.assertTrue(destfile._raised) - self.assertTrue(srcfile._exited_with[0] is IOError) - self.assertEqual(srcfile._exited_with[1].args, - ('Cannot close',)) - - def test_w_source_close_fails(self) -> None: - - srcfile = TestCopyFile.Faux(True) - destfile = TestCopyFile.Faux() - - def _open(filename: str, mode: str= 'r') -> TestCopyFile.Faux: - if filename == 'srcfile': - return srcfile - if filename == 'destfile': - return destfile - assert 0 # shouldn't reach here. - - self._set_shutil_open(_open) - - self.assertRaises(IOError, - shutil.copyfile, 'srcfile', 'destfile') - self.assertTrue(srcfile._entered) - self.assertTrue(destfile._entered) - self.assertFalse(destfile._raised) - self.assertTrue(srcfile._exited_with[0] is None) - self.assertTrue(srcfile._raised) - - def test_move_dir_caseinsensitive(self) -> None: - # Renames a folder to the same name - # but a different case. - - self.src_dir = tempfile.mkdtemp() - dst_dir = os.path.join( - os.path.dirname(self.src_dir), - os.path.basename(self.src_dir).upper()) - self.assertNotEqual(self.src_dir, dst_dir) - - try: - shutil.move(self.src_dir, dst_dir) - self.assertTrue(os.path.isdir(dst_dir)) - finally: - if os.path.exists(dst_dir): - os.rmdir(dst_dir) - - - -def test_main() -> None: - support.run_unittest(TestShutil, TestMove, TestCopyFile) - -if __name__ == '__main__': - test_main() diff --git a/test-data/stdlib-samples/3.2/test/test_tempfile.py b/test-data/stdlib-samples/3.2/test/test_tempfile.py deleted file mode 100644 index 31b0fecbf677..000000000000 --- a/test-data/stdlib-samples/3.2/test/test_tempfile.py +++ /dev/null @@ -1,1122 +0,0 @@ -# tempfile.py unit tests. -import tempfile -import os -import signal -import sys -import re -import warnings - -import unittest -from test import support - -from typing import Any, AnyStr, List, Dict, IO - - -if hasattr(os, 'stat'): - import stat - has_stat = 1 -else: - has_stat = 0 - -has_textmode = (tempfile._text_openflags != tempfile._bin_openflags) -has_spawnl = hasattr(os, 'spawnl') - -# TEST_FILES may need to be tweaked for systems depending on the maximum -# number of files that can be opened at one time (see ulimit -n) -if sys.platform in ('openbsd3', 'openbsd4'): - TEST_FILES = 48 -else: - TEST_FILES = 100 - -# This is organized as one test for each chunk of code in tempfile.py, -# in order of their appearance in the file. Testing which requires -# threads is not done here. - -# Common functionality. -class TC(unittest.TestCase): - - str_check = re.compile(r"[a-zA-Z0-9_-]{6}$") - - def setUp(self) -> None: - self._warnings_manager = support.check_warnings() - self._warnings_manager.__enter__() - warnings.filterwarnings("ignore", category=RuntimeWarning, - message="mktemp", module=__name__) - - def tearDown(self) -> None: - self._warnings_manager.__exit__(None, None, None) - - - def failOnException(self, what: str, ei: tuple = None) -> None: - if ei is None: - ei = sys.exc_info() - self.fail("%s raised %s: %s" % (what, ei[0], ei[1])) - - def nameCheck(self, name: str, dir: str, pre: str, suf: str) -> None: - (ndir, nbase) = os.path.split(name) - npre = nbase[:len(pre)] - nsuf = nbase[len(nbase)-len(suf):] - - # check for equality of the absolute paths! - self.assertEqual(os.path.abspath(ndir), os.path.abspath(dir), - "file '%s' not in directory '%s'" % (name, dir)) - self.assertEqual(npre, pre, - "file '%s' does not begin with '%s'" % (nbase, pre)) - self.assertEqual(nsuf, suf, - "file '%s' does not end with '%s'" % (nbase, suf)) - - nbase = nbase[len(pre):len(nbase)-len(suf)] - self.assertTrue(self.str_check.match(nbase), - "random string '%s' does not match /^[a-zA-Z0-9_-]{6}$/" - % nbase) - -test_classes = [] # type: List[type] - -class test_exports(TC): - def test_exports(self) -> None: - # There are no surprising symbols in the tempfile module - dict = tempfile.__dict__ - - expected = { - "NamedTemporaryFile" : 1, - "TemporaryFile" : 1, - "mkstemp" : 1, - "mkdtemp" : 1, - "mktemp" : 1, - "TMP_MAX" : 1, - "gettempprefix" : 1, - "gettempdir" : 1, - "tempdir" : 1, - "template" : 1, - "SpooledTemporaryFile" : 1, - "TemporaryDirectory" : 1, - } - - unexp = [] # type: List[str] - for key in dict: - if key[0] != '_' and key not in expected: - unexp.append(key) - self.assertTrue(len(unexp) == 0, - "unexpected keys: %s" % unexp) - -test_classes.append(test_exports) - - -class test__RandomNameSequence(TC): - """Test the internal iterator object _RandomNameSequence.""" - - def setUp(self) -> None: - self.r = tempfile._RandomNameSequence() - super().setUp() - - def test_get_six_char_str(self) -> None: - # _RandomNameSequence returns a six-character string - s = next(self.r) - self.nameCheck(s, '', '', '') - - def test_many(self) -> None: - # _RandomNameSequence returns no duplicate strings (stochastic) - - dict = {} # type: Dict[str, int] - r = self.r - for i in range(TEST_FILES): - s = next(r) - self.nameCheck(s, '', '', '') - self.assertNotIn(s, dict) - dict[s] = 1 - - def supports_iter(self) -> None: - # _RandomNameSequence supports the iterator protocol - - i = 0 - r = self.r - try: - for s in r: - i += 1 - if i == 20: - break - except: - self.failOnException("iteration") - - @unittest.skipUnless(hasattr(os, 'fork'), - "os.fork is required for this test") - def test_process_awareness(self) -> None: - # ensure that the random source differs between - # child and parent. - read_fd, write_fd = os.pipe() - pid = None # type: int - try: - pid = os.fork() - if not pid: - os.close(read_fd) - os.write(write_fd, next(self.r).encode("ascii")) - os.close(write_fd) - # bypass the normal exit handlers- leave those to - # the parent. - os._exit(0) - parent_value = next(self.r) - child_value = os.read(read_fd, len(parent_value)).decode("ascii") - finally: - if pid: - # best effort to ensure the process can't bleed out - # via any bugs above - try: - os.kill(pid, signal.SIGKILL) - except EnvironmentError: - pass - os.close(read_fd) - os.close(write_fd) - self.assertNotEqual(child_value, parent_value) - - -test_classes.append(test__RandomNameSequence) - - -class test__candidate_tempdir_list(TC): - """Test the internal function _candidate_tempdir_list.""" - - def test_nonempty_list(self) -> None: - # _candidate_tempdir_list returns a nonempty list of strings - - cand = tempfile._candidate_tempdir_list() - - self.assertFalse(len(cand) == 0) - for c in cand: - self.assertIsInstance(c, str) - - def test_wanted_dirs(self) -> None: - # _candidate_tempdir_list contains the expected directories - - # Make sure the interesting environment variables are all set. - with support.EnvironmentVarGuard() as env: - for envname in 'TMPDIR', 'TEMP', 'TMP': - dirname = os.getenv(envname) - if not dirname: - env[envname] = os.path.abspath(envname) - - cand = tempfile._candidate_tempdir_list() - - for envname in 'TMPDIR', 'TEMP', 'TMP': - dirname = os.getenv(envname) - if not dirname: raise ValueError - self.assertIn(dirname, cand) - - try: - dirname = os.getcwd() - except (AttributeError, os.error): - dirname = os.curdir - - self.assertIn(dirname, cand) - - # Not practical to try to verify the presence of OS-specific - # paths in this list. - -test_classes.append(test__candidate_tempdir_list) - - -# We test _get_default_tempdir by testing gettempdir. - - -class test__get_candidate_names(TC): - """Test the internal function _get_candidate_names.""" - - def test_retval(self) -> None: - # _get_candidate_names returns a _RandomNameSequence object - obj = tempfile._get_candidate_names() - self.assertIsInstance(obj, tempfile._RandomNameSequence) - - def test_same_thing(self) -> None: - # _get_candidate_names always returns the same object - a = tempfile._get_candidate_names() - b = tempfile._get_candidate_names() - - self.assertTrue(a is b) - -test_classes.append(test__get_candidate_names) - - -class test__mkstemp_inner(TC): - """Test the internal function _mkstemp_inner.""" - - class mkstemped: - _bflags = tempfile._bin_openflags - _tflags = tempfile._text_openflags - - def __init__(self, dir: str, pre: str, suf: str, bin: int) -> None: - if bin: flags = self._bflags - else: flags = self._tflags - - (self.fd, self.name) = tempfile._mkstemp_inner(dir, pre, suf, flags) - - self._close = os.close - self._unlink = os.unlink - - def write(self, str: bytes) -> None: - os.write(self.fd, str) - - def __del__(self) -> None: - self._close(self.fd) - self._unlink(self.name) - - def do_create(self, dir: str = None, pre: str = "", suf: str= "", - bin: int = 1) -> mkstemped: - if dir is None: - dir = tempfile.gettempdir() - try: - file = test__mkstemp_inner.mkstemped(dir, pre, suf, bin) # see #259 - except: - self.failOnException("_mkstemp_inner") - - self.nameCheck(file.name, dir, pre, suf) - return file - - def test_basic(self) -> None: - # _mkstemp_inner can create files - self.do_create().write(b"blat") - self.do_create(pre="a").write(b"blat") - self.do_create(suf="b").write(b"blat") - self.do_create(pre="a", suf="b").write(b"blat") - self.do_create(pre="aa", suf=".txt").write(b"blat") - - def test_basic_many(self) -> None: - # _mkstemp_inner can create many files (stochastic) - extant = list(range(TEST_FILES)) # type: List[Any] - for i in extant: - extant[i] = self.do_create(pre="aa") - - def test_choose_directory(self) -> None: - # _mkstemp_inner can create files in a user-selected directory - dir = tempfile.mkdtemp() - try: - self.do_create(dir=dir).write(b"blat") - finally: - os.rmdir(dir) - - def test_file_mode(self) -> None: - # _mkstemp_inner creates files with the proper mode - if not has_stat: - return # ugh, can't use SkipTest. - - file = self.do_create() - mode = stat.S_IMODE(os.stat(file.name).st_mode) - expected = 0o600 - if sys.platform in ('win32', 'os2emx'): - # There's no distinction among 'user', 'group' and 'world'; - # replicate the 'user' bits. - user = expected >> 6 - expected = user * (1 + 8 + 64) - self.assertEqual(mode, expected) - - def test_noinherit(self) -> None: - # _mkstemp_inner file handles are not inherited by child processes - if not has_spawnl: - return # ugh, can't use SkipTest. - - if support.verbose: - v="v" - else: - v="q" - - file = self.do_create() - fd = "%d" % file.fd - - try: - me = __file__ # type: str - except NameError: - me = sys.argv[0] - - # We have to exec something, so that FD_CLOEXEC will take - # effect. The core of this test is therefore in - # tf_inherit_check.py, which see. - tester = os.path.join(os.path.dirname(os.path.abspath(me)), - "tf_inherit_check.py") - - # On Windows a spawn* /path/ with embedded spaces shouldn't be quoted, - # but an arg with embedded spaces should be decorated with double - # quotes on each end - if sys.platform in ('win32',): - decorated = '"%s"' % sys.executable - tester = '"%s"' % tester - else: - decorated = sys.executable - - retval = os.spawnl(os.P_WAIT, sys.executable, decorated, tester, v, fd) - self.assertFalse(retval < 0, - "child process caught fatal signal %d" % -retval) - self.assertFalse(retval > 0, "child process reports failure %d"%retval) - - def test_textmode(self) -> None: - # _mkstemp_inner can create files in text mode - if not has_textmode: - return # ugh, can't use SkipTest. - - # A text file is truncated at the first Ctrl+Z byte - f = self.do_create(bin=0) - f.write(b"blat\x1a") - f.write(b"extra\n") - os.lseek(f.fd, 0, os.SEEK_SET) - self.assertEqual(os.read(f.fd, 20), b"blat") - -test_classes.append(test__mkstemp_inner) - - -class test_gettempprefix(TC): - """Test gettempprefix().""" - - def test_sane_template(self) -> None: - # gettempprefix returns a nonempty prefix string - p = tempfile.gettempprefix() - - self.assertIsInstance(p, str) - self.assertTrue(len(p) > 0) - - def test_usable_template(self) -> None: - # gettempprefix returns a usable prefix string - - # Create a temp directory, avoiding use of the prefix. - # Then attempt to create a file whose name is - # prefix + 'xxxxxx.xxx' in that directory. - p = tempfile.gettempprefix() + "xxxxxx.xxx" - d = tempfile.mkdtemp(prefix="") - try: - p = os.path.join(d, p) - try: - fd = os.open(p, os.O_RDWR | os.O_CREAT) - except: - self.failOnException("os.open") - os.close(fd) - os.unlink(p) - finally: - os.rmdir(d) - -test_classes.append(test_gettempprefix) - - -class test_gettempdir(TC): - """Test gettempdir().""" - - def test_directory_exists(self) -> None: - # gettempdir returns a directory which exists - - dir = tempfile.gettempdir() - self.assertTrue(os.path.isabs(dir) or dir == os.curdir, - "%s is not an absolute path" % dir) - self.assertTrue(os.path.isdir(dir), - "%s is not a directory" % dir) - - def test_directory_writable(self) -> None: - # gettempdir returns a directory writable by the user - - # sneaky: just instantiate a NamedTemporaryFile, which - # defaults to writing into the directory returned by - # gettempdir. - try: - file = tempfile.NamedTemporaryFile() - file.write(b"blat") - file.close() - except: - self.failOnException("create file in %s" % tempfile.gettempdir()) - - def test_same_thing(self) -> None: - # gettempdir always returns the same object - a = tempfile.gettempdir() - b = tempfile.gettempdir() - - self.assertTrue(a is b) - -test_classes.append(test_gettempdir) - - -class test_mkstemp(TC): - """Test mkstemp().""" - - def do_create(self, dir: str = None, pre: str = "", suf: str = "") -> None: - if dir is None: - dir = tempfile.gettempdir() - try: - (fd, name) = tempfile.mkstemp(dir=dir, prefix=pre, suffix=suf) - (ndir, nbase) = os.path.split(name) - adir = os.path.abspath(dir) - self.assertEqual(adir, ndir, - "Directory '%s' incorrectly returned as '%s'" % (adir, ndir)) - except: - self.failOnException("mkstemp") - - try: - self.nameCheck(name, dir, pre, suf) - finally: - os.close(fd) - os.unlink(name) - - def test_basic(self) -> None: - # mkstemp can create files - self.do_create() - self.do_create(pre="a") - self.do_create(suf="b") - self.do_create(pre="a", suf="b") - self.do_create(pre="aa", suf=".txt") - self.do_create(dir=".") - - def test_choose_directory(self) -> None: - # mkstemp can create directories in a user-selected directory - dir = tempfile.mkdtemp() - try: - self.do_create(dir=dir) - finally: - os.rmdir(dir) - -test_classes.append(test_mkstemp) - - -class test_mkdtemp(TC): - """Test mkdtemp().""" - - def do_create(self, dir: str = None, pre: str = "", suf: str = "") -> str: - if dir is None: - dir = tempfile.gettempdir() - try: - name = tempfile.mkdtemp(dir=dir, prefix=pre, suffix=suf) - except: - self.failOnException("mkdtemp") - - try: - self.nameCheck(name, dir, pre, suf) - return name - except: - os.rmdir(name) - raise - - def test_basic(self) -> None: - # mkdtemp can create directories - os.rmdir(self.do_create()) - os.rmdir(self.do_create(pre="a")) - os.rmdir(self.do_create(suf="b")) - os.rmdir(self.do_create(pre="a", suf="b")) - os.rmdir(self.do_create(pre="aa", suf=".txt")) - - def test_basic_many(self) -> None: - # mkdtemp can create many directories (stochastic) - extant = list(range(TEST_FILES)) # type: List[Any] - try: - for i in extant: - extant[i] = self.do_create(pre="aa") - finally: - for i in extant: - if(isinstance(i, str)): - os.rmdir(i) - - def test_choose_directory(self) -> None: - # mkdtemp can create directories in a user-selected directory - dir = tempfile.mkdtemp() - try: - os.rmdir(self.do_create(dir=dir)) - finally: - os.rmdir(dir) - - def test_mode(self) -> None: - # mkdtemp creates directories with the proper mode - if not has_stat: - return # ugh, can't use SkipTest. - - dir = self.do_create() - try: - mode = stat.S_IMODE(os.stat(dir).st_mode) - mode &= 0o777 # Mask off sticky bits inherited from /tmp - expected = 0o700 - if sys.platform in ('win32', 'os2emx'): - # There's no distinction among 'user', 'group' and 'world'; - # replicate the 'user' bits. - user = expected >> 6 - expected = user * (1 + 8 + 64) - self.assertEqual(mode, expected) - finally: - os.rmdir(dir) - -test_classes.append(test_mkdtemp) - - -class test_mktemp(TC): - """Test mktemp().""" - - # For safety, all use of mktemp must occur in a private directory. - # We must also suppress the RuntimeWarning it generates. - def setUp(self) -> None: - self.dir = tempfile.mkdtemp() - super().setUp() - - def tearDown(self) -> None: - if self.dir: - os.rmdir(self.dir) - self.dir = None - super().tearDown() - - class mktemped: - def _unlink(self, path: str) -> None: - os.unlink(path) - - _bflags = tempfile._bin_openflags - - def __init__(self, dir: str, pre: str, suf: str) -> None: - self.name = tempfile.mktemp(dir=dir, prefix=pre, suffix=suf) - # Create the file. This will raise an exception if it's - # mysteriously appeared in the meanwhile. - os.close(os.open(self.name, self._bflags, 0o600)) - - def __del__(self) -> None: - self._unlink(self.name) - - def do_create(self, pre: str = "", suf: str = "") -> mktemped: - try: - file = test_mktemp.mktemped(self.dir, pre, suf) # see #259 - except: - self.failOnException("mktemp") - - self.nameCheck(file.name, self.dir, pre, suf) - return file - - def test_basic(self) -> None: - # mktemp can choose usable file names - self.do_create() - self.do_create(pre="a") - self.do_create(suf="b") - self.do_create(pre="a", suf="b") - self.do_create(pre="aa", suf=".txt") - - def test_many(self) -> None: - # mktemp can choose many usable file names (stochastic) - extant = list(range(TEST_FILES)) # type: List[Any] - for i in extant: - extant[i] = self.do_create(pre="aa") - -## def test_warning(self): -## # mktemp issues a warning when used -## warnings.filterwarnings("error", -## category=RuntimeWarning, -## message="mktemp") -## self.assertRaises(RuntimeWarning, -## tempfile.mktemp, dir=self.dir) - -test_classes.append(test_mktemp) - - -# We test _TemporaryFileWrapper by testing NamedTemporaryFile. - - -class test_NamedTemporaryFile(TC): - """Test NamedTemporaryFile().""" - - def do_create(self, dir: str = None, pre: str = "", suf: str = "", - delete: bool = True) -> IO[Any]: - if dir is None: - dir = tempfile.gettempdir() - try: - file = tempfile.NamedTemporaryFile(dir=dir, prefix=pre, suffix=suf, - delete=delete) - except: - self.failOnException("NamedTemporaryFile") - - self.nameCheck(file.name, dir, pre, suf) - return file - - - def test_basic(self) -> None: - # NamedTemporaryFile can create files - self.do_create() - self.do_create(pre="a") - self.do_create(suf="b") - self.do_create(pre="a", suf="b") - self.do_create(pre="aa", suf=".txt") - - def test_creates_named(self) -> None: - # NamedTemporaryFile creates files with names - f = tempfile.NamedTemporaryFile() - self.assertTrue(os.path.exists(f.name), - "NamedTemporaryFile %s does not exist" % f.name) - - def test_del_on_close(self) -> None: - # A NamedTemporaryFile is deleted when closed - dir = tempfile.mkdtemp() - try: - f = tempfile.NamedTemporaryFile(dir=dir) - f.write(b'blat') - f.close() - self.assertFalse(os.path.exists(f.name), - "NamedTemporaryFile %s exists after close" % f.name) - finally: - os.rmdir(dir) - - def test_dis_del_on_close(self) -> None: - # Tests that delete-on-close can be disabled - dir = tempfile.mkdtemp() - tmp = None # type: str - try: - f = tempfile.NamedTemporaryFile(dir=dir, delete=False) - tmp = f.name - f.write(b'blat') - f.close() - self.assertTrue(os.path.exists(f.name), - "NamedTemporaryFile %s missing after close" % f.name) - finally: - if tmp is not None: - os.unlink(tmp) - os.rmdir(dir) - - def test_multiple_close(self) -> None: - # A NamedTemporaryFile can be closed many times without error - f = tempfile.NamedTemporaryFile() - f.write(b'abc\n') - f.close() - try: - f.close() - f.close() - except: - self.failOnException("close") - - def test_context_manager(self) -> None: - # A NamedTemporaryFile can be used as a context manager - with tempfile.NamedTemporaryFile() as f: - self.assertTrue(os.path.exists(f.name)) - self.assertFalse(os.path.exists(f.name)) - def use_closed(): - with f: - pass - self.assertRaises(ValueError, use_closed) - - # How to test the mode and bufsize parameters? - -test_classes.append(test_NamedTemporaryFile) - -class test_SpooledTemporaryFile(TC): - """Test SpooledTemporaryFile().""" - - def do_create(self, max_size: int = 0, dir: str = None, pre: str = "", - suf: str = "") -> tempfile.SpooledTemporaryFile: - if dir is None: - dir = tempfile.gettempdir() - try: - file = tempfile.SpooledTemporaryFile(max_size=max_size, dir=dir, prefix=pre, suffix=suf) - except: - self.failOnException("SpooledTemporaryFile") - - return file - - - def test_basic(self) -> None: - # SpooledTemporaryFile can create files - f = self.do_create() - self.assertFalse(f._rolled) - f = self.do_create(max_size=100, pre="a", suf=".txt") - self.assertFalse(f._rolled) - - def test_del_on_close(self) -> None: - # A SpooledTemporaryFile is deleted when closed - dir = tempfile.mkdtemp() - try: - f = tempfile.SpooledTemporaryFile(max_size=10, dir=dir) - self.assertFalse(f._rolled) - f.write(b'blat ' * 5) - self.assertTrue(f._rolled) - filename = f.name - f.close() - self.assertFalse(isinstance(filename, str) and os.path.exists(filename), - "SpooledTemporaryFile %s exists after close" % filename) - finally: - os.rmdir(dir) - - def test_rewrite_small(self) -> None: - # A SpooledTemporaryFile can be written to multiple within the max_size - f = self.do_create(max_size=30) - self.assertFalse(f._rolled) - for i in range(5): - f.seek(0, 0) - f.write(b'x' * 20) - self.assertFalse(f._rolled) - - def test_write_sequential(self) -> None: - # A SpooledTemporaryFile should hold exactly max_size bytes, and roll - # over afterward - f = self.do_create(max_size=30) - self.assertFalse(f._rolled) - f.write(b'x' * 20) - self.assertFalse(f._rolled) - f.write(b'x' * 10) - self.assertFalse(f._rolled) - f.write(b'x') - self.assertTrue(f._rolled) - - def test_writelines(self) -> None: - # Verify writelines with a SpooledTemporaryFile - f = self.do_create() - f.writelines([b'x', b'y', b'z']) - f.seek(0) - buf = f.read() - self.assertEqual(buf, b'xyz') - - def test_writelines_sequential(self) -> None: - # A SpooledTemporaryFile should hold exactly max_size bytes, and roll - # over afterward - f = self.do_create(max_size=35) - f.writelines([b'x' * 20, b'x' * 10, b'x' * 5]) - self.assertFalse(f._rolled) - f.write(b'x') - self.assertTrue(f._rolled) - - def test_sparse(self) -> None: - # A SpooledTemporaryFile that is written late in the file will extend - # when that occurs - f = self.do_create(max_size=30) - self.assertFalse(f._rolled) - f.seek(100, 0) - self.assertFalse(f._rolled) - f.write(b'x') - self.assertTrue(f._rolled) - - def test_fileno(self) -> None: - # A SpooledTemporaryFile should roll over to a real file on fileno() - f = self.do_create(max_size=30) - self.assertFalse(f._rolled) - self.assertTrue(f.fileno() > 0) - self.assertTrue(f._rolled) - - def test_multiple_close_before_rollover(self) -> None: - # A SpooledTemporaryFile can be closed many times without error - f = tempfile.SpooledTemporaryFile() - f.write(b'abc\n') - self.assertFalse(f._rolled) - f.close() - try: - f.close() - f.close() - except: - self.failOnException("close") - - def test_multiple_close_after_rollover(self) -> None: - # A SpooledTemporaryFile can be closed many times without error - f = tempfile.SpooledTemporaryFile(max_size=1) - f.write(b'abc\n') - self.assertTrue(f._rolled) - f.close() - try: - f.close() - f.close() - except: - self.failOnException("close") - - def test_bound_methods(self) -> None: - # It should be OK to steal a bound method from a SpooledTemporaryFile - # and use it independently; when the file rolls over, those bound - # methods should continue to function - f = self.do_create(max_size=30) - read = f.read - write = f.write - seek = f.seek - - write(b"a" * 35) - write(b"b" * 35) - seek(0, 0) - self.assertEqual(read(70), b'a'*35 + b'b'*35) - - def test_text_mode(self) -> None: - # Creating a SpooledTemporaryFile with a text mode should produce - # a file object reading and writing (Unicode) text strings. - f = tempfile.SpooledTemporaryFile(mode='w+', max_size=10) - f.write("abc\n") - f.seek(0) - self.assertEqual(f.read(), "abc\n") - f.write("def\n") - f.seek(0) - self.assertEqual(f.read(), "abc\ndef\n") - f.write("xyzzy\n") - f.seek(0) - self.assertEqual(f.read(), "abc\ndef\nxyzzy\n") - # Check that Ctrl+Z doesn't truncate the file - f.write("foo\x1abar\n") - f.seek(0) - self.assertEqual(f.read(), "abc\ndef\nxyzzy\nfoo\x1abar\n") - - def test_text_newline_and_encoding(self) -> None: - f = tempfile.SpooledTemporaryFile(mode='w+', max_size=10, - newline='', encoding='utf-8') - f.write("\u039B\r\n") - f.seek(0) - self.assertEqual(f.read(), "\u039B\r\n") - self.assertFalse(f._rolled) - - f.write("\u039B" * 20 + "\r\n") - f.seek(0) - self.assertEqual(f.read(), "\u039B\r\n" + ("\u039B" * 20) + "\r\n") - self.assertTrue(f._rolled) - - def test_context_manager_before_rollover(self) -> None: - # A SpooledTemporaryFile can be used as a context manager - with tempfile.SpooledTemporaryFile(max_size=1) as f: - self.assertFalse(f._rolled) - self.assertFalse(f.closed) - self.assertTrue(f.closed) - def use_closed(): - with f: - pass - self.assertRaises(ValueError, use_closed) - - def test_context_manager_during_rollover(self) -> None: - # A SpooledTemporaryFile can be used as a context manager - with tempfile.SpooledTemporaryFile(max_size=1) as f: - self.assertFalse(f._rolled) - f.write(b'abc\n') - f.flush() - self.assertTrue(f._rolled) - self.assertFalse(f.closed) - self.assertTrue(f.closed) - def use_closed(): - with f: - pass - self.assertRaises(ValueError, use_closed) - - def test_context_manager_after_rollover(self) -> None: - # A SpooledTemporaryFile can be used as a context manager - f = tempfile.SpooledTemporaryFile(max_size=1) - f.write(b'abc\n') - f.flush() - self.assertTrue(f._rolled) - with f: - self.assertFalse(f.closed) - self.assertTrue(f.closed) - def use_closed(): - with f: - pass - self.assertRaises(ValueError, use_closed) - - -test_classes.append(test_SpooledTemporaryFile) - - -class test_TemporaryFile(TC): - """Test TemporaryFile().""" - - def test_basic(self) -> None: - # TemporaryFile can create files - # No point in testing the name params - the file has no name. - try: - tempfile.TemporaryFile() - except: - self.failOnException("TemporaryFile") - - def test_has_no_name(self) -> None: - # TemporaryFile creates files with no names (on this system) - dir = tempfile.mkdtemp() - f = tempfile.TemporaryFile(dir=dir) - f.write(b'blat') - - # Sneaky: because this file has no name, it should not prevent - # us from removing the directory it was created in. - try: - os.rmdir(dir) - except: - ei = sys.exc_info() - # cleanup - f.close() - os.rmdir(dir) - self.failOnException("rmdir", ei) - - def test_multiple_close(self) -> None: - # A TemporaryFile can be closed many times without error - f = tempfile.TemporaryFile() - f.write(b'abc\n') - f.close() - try: - f.close() - f.close() - except: - self.failOnException("close") - - # How to test the mode and bufsize parameters? - def test_mode_and_encoding(self) -> None: - - def roundtrip(input: AnyStr, *args: Any, **kwargs: Any) -> None: - with tempfile.TemporaryFile(*args, **kwargs) as fileobj: - fileobj.write(input) - fileobj.seek(0) - self.assertEqual(input, fileobj.read()) - - roundtrip(b"1234", "w+b") - roundtrip("abdc\n", "w+") - roundtrip("\u039B", "w+", encoding="utf-16") - roundtrip("foo\r\n", "w+", newline="") - - -if tempfile.NamedTemporaryFile is not tempfile.TemporaryFile: - test_classes.append(test_TemporaryFile) - - -# Helper for test_del_on_shutdown -class NulledModules: - def __init__(self, *modules: Any) -> None: - self.refs = [mod.__dict__ for mod in modules] - self.contents = [ref.copy() for ref in self.refs] - - def __enter__(self) -> None: - for d in self.refs: - for key in d: - d[key] = None - - def __exit__(self, *exc_info: Any) -> None: - for d, c in zip(self.refs, self.contents): - d.clear() - d.update(c) - -class test_TemporaryDirectory(TC): - """Test TemporaryDirectory().""" - - def do_create(self, dir: str = None, pre: str = "", suf: str = "", - recurse: int = 1) -> tempfile.TemporaryDirectory: - if dir is None: - dir = tempfile.gettempdir() - try: - tmp = tempfile.TemporaryDirectory(dir=dir, prefix=pre, suffix=suf) - except: - self.failOnException("TemporaryDirectory") - self.nameCheck(tmp.name, dir, pre, suf) - # Create a subdirectory and some files - if recurse: - self.do_create(tmp.name, pre, suf, recurse-1) - with open(os.path.join(tmp.name, "test.txt"), "wb") as f: - f.write(b"Hello world!") - return tmp - - def test_mkdtemp_failure(self) -> None: - # Check no additional exception if mkdtemp fails - # Previously would raise AttributeError instead - # (noted as part of Issue #10188) - with tempfile.TemporaryDirectory() as nonexistent: - pass - with self.assertRaises(os.error): - tempfile.TemporaryDirectory(dir=nonexistent) - - def test_explicit_cleanup(self) -> None: - # A TemporaryDirectory is deleted when cleaned up - dir = tempfile.mkdtemp() - try: - d = self.do_create(dir=dir) - self.assertTrue(os.path.exists(d.name), - "TemporaryDirectory %s does not exist" % d.name) - d.cleanup() - self.assertFalse(os.path.exists(d.name), - "TemporaryDirectory %s exists after cleanup" % d.name) - finally: - os.rmdir(dir) - - @support.skip_unless_symlink - def test_cleanup_with_symlink_to_a_directory(self) -> None: - # cleanup() should not follow symlinks to directories (issue #12464) - d1 = self.do_create() - d2 = self.do_create() - - # Symlink d1/foo -> d2 - os.symlink(d2.name, os.path.join(d1.name, "foo")) - - # This call to cleanup() should not follow the "foo" symlink - d1.cleanup() - - self.assertFalse(os.path.exists(d1.name), - "TemporaryDirectory %s exists after cleanup" % d1.name) - self.assertTrue(os.path.exists(d2.name), - "Directory pointed to by a symlink was deleted") - self.assertEqual(os.listdir(d2.name), ['test.txt'], - "Contents of the directory pointed to by a symlink " - "were deleted") - d2.cleanup() - - @support.cpython_only - def test_del_on_collection(self) -> None: - # A TemporaryDirectory is deleted when garbage collected - dir = tempfile.mkdtemp() - try: - d = self.do_create(dir=dir) - name = d.name - del d # Rely on refcounting to invoke __del__ - self.assertFalse(os.path.exists(name), - "TemporaryDirectory %s exists after __del__" % name) - finally: - os.rmdir(dir) - - @unittest.expectedFailure # See issue #10188 - def test_del_on_shutdown(self) -> None: - # A TemporaryDirectory may be cleaned up during shutdown - # Make sure it works with the relevant modules nulled out - with self.do_create() as dir: - d = self.do_create(dir=dir) - # Mimic the nulling out of modules that - # occurs during system shutdown - modules = [os, os.path] - if has_stat: - modules.append(stat) - # Currently broken, so suppress the warning - # that is otherwise emitted on stdout - with support.captured_stderr() as err: - with NulledModules(*modules): - d.cleanup() - # Currently broken, so stop spurious exception by - # indicating the object has already been closed - d._closed = True - # And this assert will fail, as expected by the - # unittest decorator... - self.assertFalse(os.path.exists(d.name), - "TemporaryDirectory %s exists after cleanup" % d.name) - - def test_warnings_on_cleanup(self) -> None: - # Two kinds of warning on shutdown - # Issue 10888: may write to stderr if modules are nulled out - # ResourceWarning will be triggered by __del__ - with self.do_create() as dir: - if os.sep != '\\': - # Embed a backslash in order to make sure string escaping - # in the displayed error message is dealt with correctly - suffix = '\\check_backslash_handling' - else: - suffix = '' - d = self.do_create(dir=dir, suf=suffix) - - #Check for the Issue 10888 message - modules = [os, os.path] - if has_stat: - modules.append(stat) - with support.captured_stderr() as err: - with NulledModules(*modules): - d.cleanup() - message = err.getvalue().replace('\\\\', '\\') - self.assertIn("while cleaning up", message) - self.assertIn(d.name, message) - - # Check for the resource warning - with support.check_warnings(('Implicitly', ResourceWarning), quiet=False): - warnings.filterwarnings("always", category=ResourceWarning) - d.__del__() - self.assertFalse(os.path.exists(d.name), - "TemporaryDirectory %s exists after __del__" % d.name) - - def test_multiple_close(self) -> None: - # Can be cleaned-up many times without error - d = self.do_create() - d.cleanup() - try: - d.cleanup() - d.cleanup() - except: - self.failOnException("cleanup") - - def test_context_manager(self) -> None: - # Can be used as a context manager - d = self.do_create() - with d as name: - self.assertTrue(os.path.exists(name)) - self.assertEqual(name, d.name) - self.assertFalse(os.path.exists(name)) - - -test_classes.append(test_TemporaryDirectory) - -def test_main() -> None: - support.run_unittest(*test_classes) - -if __name__ == "__main__": - test_main() diff --git a/test-data/stdlib-samples/3.2/test/test_textwrap.py b/test-data/stdlib-samples/3.2/test/test_textwrap.py deleted file mode 100644 index 79d921a583e6..000000000000 --- a/test-data/stdlib-samples/3.2/test/test_textwrap.py +++ /dev/null @@ -1,601 +0,0 @@ -# -# Test suite for the textwrap module. -# -# Original tests written by Greg Ward . -# Converted to PyUnit by Peter Hansen . -# Currently maintained by Greg Ward. -# -# $Id$ -# - -import unittest -from test import support - -from typing import Any, List, Sequence - -from textwrap import TextWrapper, wrap, fill, dedent - - -class BaseTestCase(unittest.TestCase): - '''Parent class with utility methods for textwrap tests.''' - - wrapper = None # type: TextWrapper - - def show(self, textin: Sequence[str]) -> str: - if isinstance(textin, list): - results = [] # type: List[str] - for i in range(len(textin)): - results.append(" %d: %r" % (i, textin[i])) - result = '\n'.join(results) - elif isinstance(textin, str): - result = " %s\n" % repr(textin) - return result - - - def check(self, result: Sequence[str], expect: Sequence[str]) -> None: - self.assertEqual(result, expect, - 'expected:\n%s\nbut got:\n%s' % ( - self.show(expect), self.show(result))) - - def check_wrap(self, text: str, width: int, expect: Sequence[str], - **kwargs: Any) -> None: - result = wrap(text, width, **kwargs) - self.check(result, expect) - - def check_split(self, text: str, expect: Sequence[str]) -> None: - result = self.wrapper._split(text) - self.assertEqual(result, expect, - "\nexpected %r\n" - "but got %r" % (expect, result)) - - -class WrapTestCase(BaseTestCase): - - def setUp(self) -> None: - self.wrapper = TextWrapper(width=45) - - def test_simple(self) -> None: - # Simple case: just words, spaces, and a bit of punctuation - - text = "Hello there, how are you this fine day? I'm glad to hear it!" - - self.check_wrap(text, 12, - ["Hello there,", - "how are you", - "this fine", - "day? I'm", - "glad to hear", - "it!"]) - self.check_wrap(text, 42, - ["Hello there, how are you this fine day?", - "I'm glad to hear it!"]) - self.check_wrap(text, 80, [text]) - - - def test_whitespace(self) -> None: - # Whitespace munging and end-of-sentence detection - - text = """\ -This is a paragraph that already has -line breaks. But some of its lines are much longer than the others, -so it needs to be wrapped. -Some lines are \ttabbed too. -What a mess! -""" - - expect = ["This is a paragraph that already has line", - "breaks. But some of its lines are much", - "longer than the others, so it needs to be", - "wrapped. Some lines are tabbed too. What a", - "mess!"] - - wrapper = TextWrapper(45, fix_sentence_endings=True) - result = wrapper.wrap(text) - self.check(result, expect) - - results = wrapper.fill(text) - self.check(results, '\n'.join(expect)) - - def test_fix_sentence_endings(self) -> None: - wrapper = TextWrapper(60, fix_sentence_endings=True) - - # SF #847346: ensure that fix_sentence_endings=True does the - # right thing even on input short enough that it doesn't need to - # be wrapped. - text = "A short line. Note the single space." - expect = ["A short line. Note the single space."] - self.check(wrapper.wrap(text), expect) - - # Test some of the hairy end cases that _fix_sentence_endings() - # is supposed to handle (the easy stuff is tested in - # test_whitespace() above). - text = "Well, Doctor? What do you think?" - expect = ["Well, Doctor? What do you think?"] - self.check(wrapper.wrap(text), expect) - - text = "Well, Doctor?\nWhat do you think?" - self.check(wrapper.wrap(text), expect) - - text = 'I say, chaps! Anyone for "tennis?"\nHmmph!' - expect = ['I say, chaps! Anyone for "tennis?" Hmmph!'] - self.check(wrapper.wrap(text), expect) - - wrapper.width = 20 - expect = ['I say, chaps!', 'Anyone for "tennis?"', 'Hmmph!'] - self.check(wrapper.wrap(text), expect) - - text = 'And she said, "Go to hell!"\nCan you believe that?' - expect = ['And she said, "Go to', - 'hell!" Can you', - 'believe that?'] - self.check(wrapper.wrap(text), expect) - - wrapper.width = 60 - expect = ['And she said, "Go to hell!" Can you believe that?'] - self.check(wrapper.wrap(text), expect) - - text = 'File stdio.h is nice.' - expect = ['File stdio.h is nice.'] - self.check(wrapper.wrap(text), expect) - - def test_wrap_short(self) -> None: - # Wrapping to make short lines longer - - text = "This is a\nshort paragraph." - - self.check_wrap(text, 20, ["This is a short", - "paragraph."]) - self.check_wrap(text, 40, ["This is a short paragraph."]) - - - def test_wrap_short_1line(self) -> None: - # Test endcases - - text = "This is a short line." - - self.check_wrap(text, 30, ["This is a short line."]) - self.check_wrap(text, 30, ["(1) This is a short line."], - initial_indent="(1) ") - - - def test_hyphenated(self) -> None: - # Test breaking hyphenated words - - text = ("this-is-a-useful-feature-for-" - "reformatting-posts-from-tim-peters'ly") - - self.check_wrap(text, 40, - ["this-is-a-useful-feature-for-", - "reformatting-posts-from-tim-peters'ly"]) - self.check_wrap(text, 41, - ["this-is-a-useful-feature-for-", - "reformatting-posts-from-tim-peters'ly"]) - self.check_wrap(text, 42, - ["this-is-a-useful-feature-for-reformatting-", - "posts-from-tim-peters'ly"]) - - def test_hyphenated_numbers(self) -> None: - # Test that hyphenated numbers (eg. dates) are not broken like words. - text = ("Python 1.0.0 was released on 1994-01-26. Python 1.0.1 was\n" - "released on 1994-02-15.") - - self.check_wrap(text, 30, ['Python 1.0.0 was released on', - '1994-01-26. Python 1.0.1 was', - 'released on 1994-02-15.']) - self.check_wrap(text, 40, ['Python 1.0.0 was released on 1994-01-26.', - 'Python 1.0.1 was released on 1994-02-15.']) - - text = "I do all my shopping at 7-11." - self.check_wrap(text, 25, ["I do all my shopping at", - "7-11."]) - self.check_wrap(text, 27, ["I do all my shopping at", - "7-11."]) - self.check_wrap(text, 29, ["I do all my shopping at 7-11."]) - - def test_em_dash(self) -> None: - # Test text with em-dashes - text = "Em-dashes should be written -- thus." - self.check_wrap(text, 25, - ["Em-dashes should be", - "written -- thus."]) - - # Probe the boundaries of the properly written em-dash, - # ie. " -- ". - self.check_wrap(text, 29, - ["Em-dashes should be written", - "-- thus."]) - expect = ["Em-dashes should be written --", - "thus."] - self.check_wrap(text, 30, expect) - self.check_wrap(text, 35, expect) - self.check_wrap(text, 36, - ["Em-dashes should be written -- thus."]) - - # The improperly written em-dash is handled too, because - # it's adjacent to non-whitespace on both sides. - text = "You can also do--this or even---this." - expect = ["You can also do", - "--this or even", - "---this."] - self.check_wrap(text, 15, expect) - self.check_wrap(text, 16, expect) - expect = ["You can also do--", - "this or even---", - "this."] - self.check_wrap(text, 17, expect) - self.check_wrap(text, 19, expect) - expect = ["You can also do--this or even", - "---this."] - self.check_wrap(text, 29, expect) - self.check_wrap(text, 31, expect) - expect = ["You can also do--this or even---", - "this."] - self.check_wrap(text, 32, expect) - self.check_wrap(text, 35, expect) - - # All of the above behaviour could be deduced by probing the - # _split() method. - text = "Here's an -- em-dash and--here's another---and another!" - expect = ["Here's", " ", "an", " ", "--", " ", "em-", "dash", " ", - "and", "--", "here's", " ", "another", "---", - "and", " ", "another!"] - self.check_split(text, expect) - - text = "and then--bam!--he was gone" - expect = ["and", " ", "then", "--", "bam!", "--", - "he", " ", "was", " ", "gone"] - self.check_split(text, expect) - - - def test_unix_options (self) -> None: - # Test that Unix-style command-line options are wrapped correctly. - # Both Optik (OptionParser) and Docutils rely on this behaviour! - - text = "You should use the -n option, or --dry-run in its long form." - self.check_wrap(text, 20, - ["You should use the", - "-n option, or --dry-", - "run in its long", - "form."]) - self.check_wrap(text, 21, - ["You should use the -n", - "option, or --dry-run", - "in its long form."]) - expect = ["You should use the -n option, or", - "--dry-run in its long form."] - self.check_wrap(text, 32, expect) - self.check_wrap(text, 34, expect) - self.check_wrap(text, 35, expect) - self.check_wrap(text, 38, expect) - expect = ["You should use the -n option, or --dry-", - "run in its long form."] - self.check_wrap(text, 39, expect) - self.check_wrap(text, 41, expect) - expect = ["You should use the -n option, or --dry-run", - "in its long form."] - self.check_wrap(text, 42, expect) - - # Again, all of the above can be deduced from _split(). - text = "the -n option, or --dry-run or --dryrun" - expect = ["the", " ", "-n", " ", "option,", " ", "or", " ", - "--dry-", "run", " ", "or", " ", "--dryrun"] - self.check_split(text, expect) - - def test_funky_hyphens (self) -> None: - # Screwy edge cases cooked up by David Goodger. All reported - # in SF bug #596434. - self.check_split("what the--hey!", ["what", " ", "the", "--", "hey!"]) - self.check_split("what the--", ["what", " ", "the--"]) - self.check_split("what the--.", ["what", " ", "the--."]) - self.check_split("--text--.", ["--text--."]) - - # When I first read bug #596434, this is what I thought David - # was talking about. I was wrong; these have always worked - # fine. The real problem is tested in test_funky_parens() - # below... - self.check_split("--option", ["--option"]) - self.check_split("--option-opt", ["--option-", "opt"]) - self.check_split("foo --option-opt bar", - ["foo", " ", "--option-", "opt", " ", "bar"]) - - def test_punct_hyphens(self) -> None: - # Oh bother, SF #965425 found another problem with hyphens -- - # hyphenated words in single quotes weren't handled correctly. - # In fact, the bug is that *any* punctuation around a hyphenated - # word was handled incorrectly, except for a leading "--", which - # was special-cased for Optik and Docutils. So test a variety - # of styles of punctuation around a hyphenated word. - # (Actually this is based on an Optik bug report, #813077). - self.check_split("the 'wibble-wobble' widget", - ['the', ' ', "'wibble-", "wobble'", ' ', 'widget']) - self.check_split('the "wibble-wobble" widget', - ['the', ' ', '"wibble-', 'wobble"', ' ', 'widget']) - self.check_split("the (wibble-wobble) widget", - ['the', ' ', "(wibble-", "wobble)", ' ', 'widget']) - self.check_split("the ['wibble-wobble'] widget", - ['the', ' ', "['wibble-", "wobble']", ' ', 'widget']) - - def test_funky_parens (self) -> None: - # Second part of SF bug #596434: long option strings inside - # parentheses. - self.check_split("foo (--option) bar", - ["foo", " ", "(--option)", " ", "bar"]) - - # Related stuff -- make sure parens work in simpler contexts. - self.check_split("foo (bar) baz", - ["foo", " ", "(bar)", " ", "baz"]) - self.check_split("blah (ding dong), wubba", - ["blah", " ", "(ding", " ", "dong),", - " ", "wubba"]) - - def test_initial_whitespace(self) -> None: - # SF bug #622849 reported inconsistent handling of leading - # whitespace; let's test that a bit, shall we? - text = " This is a sentence with leading whitespace." - self.check_wrap(text, 50, - [" This is a sentence with leading whitespace."]) - self.check_wrap(text, 30, - [" This is a sentence with", "leading whitespace."]) - - def test_no_drop_whitespace(self) -> None: - # SF patch #1581073 - text = " This is a sentence with much whitespace." - self.check_wrap(text, 10, - [" This is a", " ", "sentence ", - "with ", "much white", "space."], - drop_whitespace=False) - - def test_split(self) -> None: - # Ensure that the standard _split() method works as advertised - # in the comments - - text = "Hello there -- you goof-ball, use the -b option!" - - result = self.wrapper._split(text) - self.check(result, - ["Hello", " ", "there", " ", "--", " ", "you", " ", "goof-", - "ball,", " ", "use", " ", "the", " ", "-b", " ", "option!"]) - - def test_break_on_hyphens(self) -> None: - # Ensure that the break_on_hyphens attributes work - text = "yaba daba-doo" - self.check_wrap(text, 10, ["yaba daba-", "doo"], - break_on_hyphens=True) - self.check_wrap(text, 10, ["yaba", "daba-doo"], - break_on_hyphens=False) - - def test_bad_width(self) -> None: - # Ensure that width <= 0 is caught. - text = "Whatever, it doesn't matter." - self.assertRaises(ValueError, wrap, text, 0) - self.assertRaises(ValueError, wrap, text, -1) - - def test_no_split_at_umlaut(self) -> None: - text = "Die Empf\xe4nger-Auswahl" - self.check_wrap(text, 13, ["Die", "Empf\xe4nger-", "Auswahl"]) - - def test_umlaut_followed_by_dash(self) -> None: - text = "aa \xe4\xe4-\xe4\xe4" - self.check_wrap(text, 7, ["aa \xe4\xe4-", "\xe4\xe4"]) - - -class LongWordTestCase (BaseTestCase): - def setUp(self) -> None: - self.wrapper = TextWrapper() - self.text = '''\ -Did you say "supercalifragilisticexpialidocious?" -How *do* you spell that odd word, anyways? -''' - - def test_break_long(self) -> None: - # Wrap text with long words and lots of punctuation - - self.check_wrap(self.text, 30, - ['Did you say "supercalifragilis', - 'ticexpialidocious?" How *do*', - 'you spell that odd word,', - 'anyways?']) - self.check_wrap(self.text, 50, - ['Did you say "supercalifragilisticexpialidocious?"', - 'How *do* you spell that odd word, anyways?']) - - # SF bug 797650. Prevent an infinite loop by making sure that at - # least one character gets split off on every pass. - self.check_wrap('-'*10+'hello', 10, - ['----------', - ' h', - ' e', - ' l', - ' l', - ' o'], - subsequent_indent = ' '*15) - - # bug 1146. Prevent a long word to be wrongly wrapped when the - # preceding word is exactly one character shorter than the width - self.check_wrap(self.text, 12, - ['Did you say ', - '"supercalifr', - 'agilisticexp', - 'ialidocious?', - '" How *do*', - 'you spell', - 'that odd', - 'word,', - 'anyways?']) - - def test_nobreak_long(self) -> None: - # Test with break_long_words disabled - self.wrapper.break_long_words = False - self.wrapper.width = 30 - expect = ['Did you say', - '"supercalifragilisticexpialidocious?"', - 'How *do* you spell that odd', - 'word, anyways?' - ] - result = self.wrapper.wrap(self.text) - self.check(result, expect) - - # Same thing with kwargs passed to standalone wrap() function. - result = wrap(self.text, width=30, break_long_words=0) - self.check(result, expect) - - -class IndentTestCases(BaseTestCase): - - # called before each test method - def setUp(self) -> None: - self.text = '''\ -This paragraph will be filled, first without any indentation, -and then with some (including a hanging indent).''' - - - def test_fill(self) -> None: - # Test the fill() method - - expect = '''\ -This paragraph will be filled, first -without any indentation, and then with -some (including a hanging indent).''' - - result = fill(self.text, 40) - self.check(result, expect) - - - def test_initial_indent(self) -> None: - # Test initial_indent parameter - - expect = [" This paragraph will be filled,", - "first without any indentation, and then", - "with some (including a hanging indent)."] - result = wrap(self.text, 40, initial_indent=" ") - self.check(result, expect) - - expects = "\n".join(expect) - results = fill(self.text, 40, initial_indent=" ") - self.check(results, expects) - - - def test_subsequent_indent(self) -> None: - # Test subsequent_indent parameter - - expect = '''\ - * This paragraph will be filled, first - without any indentation, and then - with some (including a hanging - indent).''' - - result = fill(self.text, 40, - initial_indent=" * ", subsequent_indent=" ") - self.check(result, expect) - - -# Despite the similar names, DedentTestCase is *not* the inverse -# of IndentTestCase! -class DedentTestCase(unittest.TestCase): - - def assertUnchanged(self, text: str) -> None: - """assert that dedent() has no effect on 'text'""" - self.assertEqual(text, dedent(text)) - - def test_dedent_nomargin(self) -> None: - # No lines indented. - text = "Hello there.\nHow are you?\nOh good, I'm glad." - self.assertUnchanged(text) - - # Similar, with a blank line. - text = "Hello there.\n\nBoo!" - self.assertUnchanged(text) - - # Some lines indented, but overall margin is still zero. - text = "Hello there.\n This is indented." - self.assertUnchanged(text) - - # Again, add a blank line. - text = "Hello there.\n\n Boo!\n" - self.assertUnchanged(text) - - def test_dedent_even(self) -> None: - # All lines indented by two spaces. - text = " Hello there.\n How are ya?\n Oh good." - expect = "Hello there.\nHow are ya?\nOh good." - self.assertEqual(expect, dedent(text)) - - # Same, with blank lines. - text = " Hello there.\n\n How are ya?\n Oh good.\n" - expect = "Hello there.\n\nHow are ya?\nOh good.\n" - self.assertEqual(expect, dedent(text)) - - # Now indent one of the blank lines. - text = " Hello there.\n \n How are ya?\n Oh good.\n" - expect = "Hello there.\n\nHow are ya?\nOh good.\n" - self.assertEqual(expect, dedent(text)) - - def test_dedent_uneven(self) -> None: - # Lines indented unevenly. - text = '''\ - def foo(): - while 1: - return foo - ''' - expect = '''\ -def foo(): - while 1: - return foo -''' - self.assertEqual(expect, dedent(text)) - - # Uneven indentation with a blank line. - text = " Foo\n Bar\n\n Baz\n" - expect = "Foo\n Bar\n\n Baz\n" - self.assertEqual(expect, dedent(text)) - - # Uneven indentation with a whitespace-only line. - text = " Foo\n Bar\n \n Baz\n" - expect = "Foo\n Bar\n\n Baz\n" - self.assertEqual(expect, dedent(text)) - - # dedent() should not mangle internal tabs - def test_dedent_preserve_internal_tabs(self) -> None: - text = " hello\tthere\n how are\tyou?" - expect = "hello\tthere\nhow are\tyou?" - self.assertEqual(expect, dedent(text)) - - # make sure that it preserves tabs when it's not making any - # changes at all - self.assertEqual(expect, dedent(expect)) - - # dedent() should not mangle tabs in the margin (i.e. - # tabs and spaces both count as margin, but are *not* - # considered equivalent) - def test_dedent_preserve_margin_tabs(self) -> None: - text = " hello there\n\thow are you?" - self.assertUnchanged(text) - - # same effect even if we have 8 spaces - text = " hello there\n\thow are you?" - self.assertUnchanged(text) - - # dedent() only removes whitespace that can be uniformly removed! - text = "\thello there\n\thow are you?" - expect = "hello there\nhow are you?" - self.assertEqual(expect, dedent(text)) - - text = " \thello there\n \thow are you?" - self.assertEqual(expect, dedent(text)) - - text = " \t hello there\n \t how are you?" - self.assertEqual(expect, dedent(text)) - - text = " \thello there\n \t how are you?" - expect = "hello there\n how are you?" - self.assertEqual(expect, dedent(text)) - - -def test_main() -> None: - support.run_unittest(WrapTestCase, - LongWordTestCase, - IndentTestCases, - DedentTestCase) - -if __name__ == '__main__': - test_main() diff --git a/test-data/stdlib-samples/3.2/test/tf_inherit_check.py b/test-data/stdlib-samples/3.2/test/tf_inherit_check.py deleted file mode 100644 index 92ebd95e5236..000000000000 --- a/test-data/stdlib-samples/3.2/test/tf_inherit_check.py +++ /dev/null @@ -1,25 +0,0 @@ -# Helper script for test_tempfile.py. argv[2] is the number of a file -# descriptor which should _not_ be open. Check this by attempting to -# write to it -- if we succeed, something is wrong. - -import sys -import os - -verbose = (sys.argv[1] == 'v') -try: - fd = int(sys.argv[2]) - - try: - os.write(fd, b"blat") - except os.error: - # Success -- could not write to fd. - sys.exit(0) - else: - if verbose: - sys.stderr.write("fd %d is open in child" % fd) - sys.exit(1) - -except Exception: - if verbose: - raise - sys.exit(1) diff --git a/test-data/stdlib-samples/3.2/textwrap.py b/test-data/stdlib-samples/3.2/textwrap.py deleted file mode 100644 index a6d026699704..000000000000 --- a/test-data/stdlib-samples/3.2/textwrap.py +++ /dev/null @@ -1,391 +0,0 @@ -"""Text wrapping and filling. -""" - -# Copyright (C) 1999-2001 Gregory P. Ward. -# Copyright (C) 2002, 2003 Python Software Foundation. -# Written by Greg Ward - -import string, re - -from typing import Dict, List, Any - -__all__ = ['TextWrapper', 'wrap', 'fill', 'dedent'] - -# Hardcode the recognized whitespace characters to the US-ASCII -# whitespace characters. The main reason for doing this is that in -# ISO-8859-1, 0xa0 is non-breaking whitespace, so in certain locales -# that character winds up in string.whitespace. Respecting -# string.whitespace in those cases would 1) make textwrap treat 0xa0 the -# same as any other whitespace char, which is clearly wrong (it's a -# *non-breaking* space), 2) possibly cause problems with Unicode, -# since 0xa0 is not in range(128). -_whitespace = '\t\n\x0b\x0c\r ' - -class TextWrapper: - """ - Object for wrapping/filling text. The public interface consists of - the wrap() and fill() methods; the other methods are just there for - subclasses to override in order to tweak the default behaviour. - If you want to completely replace the main wrapping algorithm, - you'll probably have to override _wrap_chunks(). - - Several instance attributes control various aspects of wrapping: - width (default: 70) - the maximum width of wrapped lines (unless break_long_words - is false) - initial_indent (default: "") - string that will be prepended to the first line of wrapped - output. Counts towards the line's width. - subsequent_indent (default: "") - string that will be prepended to all lines save the first - of wrapped output; also counts towards each line's width. - expand_tabs (default: true) - Expand tabs in input text to spaces before further processing. - Each tab will become 1 .. 8 spaces, depending on its position in - its line. If false, each tab is treated as a single character. - replace_whitespace (default: true) - Replace all whitespace characters in the input text by spaces - after tab expansion. Note that if expand_tabs is false and - replace_whitespace is true, every tab will be converted to a - single space! - fix_sentence_endings (default: false) - Ensure that sentence-ending punctuation is always followed - by two spaces. Off by default because the algorithm is - (unavoidably) imperfect. - break_long_words (default: true) - Break words longer than 'width'. If false, those words will not - be broken, and some lines might be longer than 'width'. - break_on_hyphens (default: true) - Allow breaking hyphenated words. If true, wrapping will occur - preferably on whitespaces and right after hyphens part of - compound words. - drop_whitespace (default: true) - Drop leading and trailing whitespace from lines. - """ - - unicode_whitespace_trans = {} # type: Dict[int, int] - uspace = ord(' ') - for x in _whitespace: - unicode_whitespace_trans[ord(x)] = uspace - - # This funky little regex is just the trick for splitting - # text up into word-wrappable chunks. E.g. - # "Hello there -- you goof-ball, use the -b option!" - # splits into - # Hello/ /there/ /--/ /you/ /goof-/ball,/ /use/ /the/ /-b/ /option! - # (after stripping out empty strings). - wordsep_re = re.compile( - r'(\s+|' # any whitespace - r'[^\s\w]*\w+[^0-9\W]-(?=\w+[^0-9\W])|' # hyphenated words - r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash - - # This less funky little regex just split on recognized spaces. E.g. - # "Hello there -- you goof-ball, use the -b option!" - # splits into - # Hello/ /there/ /--/ /you/ /goof-ball,/ /use/ /the/ /-b/ /option!/ - wordsep_simple_re = re.compile(r'(\s+)') - - # XXX this is not locale- or charset-aware -- string.lowercase - # is US-ASCII only (and therefore English-only) - sentence_end_re = re.compile(r'[a-z]' # lowercase letter - r'[\.\!\?]' # sentence-ending punct. - r'[\"\']?' # optional end-of-quote - r'\Z') # end of chunk - - - def __init__(self, - width: int = 70, - initial_indent: str = "", - subsequent_indent: str = "", - expand_tabs: bool = True, - replace_whitespace: bool = True, - fix_sentence_endings: bool = False, - break_long_words: bool = True, - drop_whitespace: bool = True, - break_on_hyphens: bool = True) -> None: - self.width = width - self.initial_indent = initial_indent - self.subsequent_indent = subsequent_indent - self.expand_tabs = expand_tabs - self.replace_whitespace = replace_whitespace - self.fix_sentence_endings = fix_sentence_endings - self.break_long_words = break_long_words - self.drop_whitespace = drop_whitespace - self.break_on_hyphens = break_on_hyphens - - - # -- Private methods ----------------------------------------------- - # (possibly useful for subclasses to override) - - def _munge_whitespace(self, text: str) -> str: - """_munge_whitespace(text : string) -> string - - Munge whitespace in text: expand tabs and convert all other - whitespace characters to spaces. Eg. " foo\tbar\n\nbaz" - becomes " foo bar baz". - """ - if self.expand_tabs: - text = text.expandtabs() - if self.replace_whitespace: - text = text.translate(self.unicode_whitespace_trans) - return text - - - def _split(self, text: str) -> List[str]: - """_split(text : string) -> [string] - - Split the text to wrap into indivisible chunks. Chunks are - not quite the same as words; see _wrap_chunks() for full - details. As an example, the text - Look, goof-ball -- use the -b option! - breaks into the following chunks: - 'Look,', ' ', 'goof-', 'ball', ' ', '--', ' ', - 'use', ' ', 'the', ' ', '-b', ' ', 'option!' - if break_on_hyphens is True, or in: - 'Look,', ' ', 'goof-ball', ' ', '--', ' ', - 'use', ' ', 'the', ' ', '-b', ' ', option!' - otherwise. - """ - if self.break_on_hyphens is True: - chunks = self.wordsep_re.split(text) - else: - chunks = self.wordsep_simple_re.split(text) - chunks = [c for c in chunks if c] - return chunks - - def _fix_sentence_endings(self, chunks: List[str]) -> None: - """_fix_sentence_endings(chunks : [string]) - - Correct for sentence endings buried in 'chunks'. Eg. when the - original text contains "... foo.\nBar ...", munge_whitespace() - and split() will convert that to [..., "foo.", " ", "Bar", ...] - which has one too few spaces; this method simply changes the one - space to two. - """ - i = 0 - patsearch = self.sentence_end_re.search - while i < len(chunks)-1: - if chunks[i+1] == " " and patsearch(chunks[i]): - chunks[i+1] = " " - i += 2 - else: - i += 1 - - def _handle_long_word(self, reversed_chunks: List[str], - cur_line: List[str], cur_len: int, - width: int) -> None: - """_handle_long_word(chunks : [string], - cur_line : [string], - cur_len : int, width : int) - - Handle a chunk of text (most likely a word, not whitespace) that - is too long to fit in any line. - """ - # Figure out when indent is larger than the specified width, and make - # sure at least one character is stripped off on every pass - if width < 1: - space_left = 1 - else: - space_left = width - cur_len - - # If we're allowed to break long words, then do so: put as much - # of the next chunk onto the current line as will fit. - if self.break_long_words: - cur_line.append(reversed_chunks[-1][:space_left]) - reversed_chunks[-1] = reversed_chunks[-1][space_left:] - - # Otherwise, we have to preserve the long word intact. Only add - # it to the current line if there's nothing already there -- - # that minimizes how much we violate the width constraint. - elif not cur_line: - cur_line.append(reversed_chunks.pop()) - - # If we're not allowed to break long words, and there's already - # text on the current line, do nothing. Next time through the - # main loop of _wrap_chunks(), we'll wind up here again, but - # cur_len will be zero, so the next line will be entirely - # devoted to the long word that we can't handle right now. - - def _wrap_chunks(self, chunks: List[str]) -> List[str]: - """_wrap_chunks(chunks : [string]) -> [string] - - Wrap a sequence of text chunks and return a list of lines of - length 'self.width' or less. (If 'break_long_words' is false, - some lines may be longer than this.) Chunks correspond roughly - to words and the whitespace between them: each chunk is - indivisible (modulo 'break_long_words'), but a line break can - come between any two chunks. Chunks should not have internal - whitespace; ie. a chunk is either all whitespace or a "word". - Whitespace chunks will be removed from the beginning and end of - lines, but apart from that whitespace is preserved. - """ - lines = [] # type: List[str] - if self.width <= 0: - raise ValueError("invalid width %r (must be > 0)" % self.width) - - # Arrange in reverse order so items can be efficiently popped - # from a stack of chucks. - chunks.reverse() - - while chunks: - - # Start the list of chunks that will make up the current line. - # cur_len is just the length of all the chunks in cur_line. - cur_line = [] # type: List[str] - cur_len = 0 - - # Figure out which static string will prefix this line. - if lines: - indent = self.subsequent_indent - else: - indent = self.initial_indent - - # Maximum width for this line. - width = self.width - len(indent) - - # First chunk on line is whitespace -- drop it, unless this - # is the very beginning of the text (ie. no lines started yet). - if self.drop_whitespace and chunks[-1].strip() == '' and lines: - del chunks[-1] - - while chunks: - l = len(chunks[-1]) - - # Can at least squeeze this chunk onto the current line. - if cur_len + l <= width: - cur_line.append(chunks.pop()) - cur_len += l - - # Nope, this line is full. - else: - break - - # The current line is full, and the next chunk is too big to - # fit on *any* line (not just this one). - if chunks and len(chunks[-1]) > width: - self._handle_long_word(chunks, cur_line, cur_len, width) - - # If the last chunk on this line is all whitespace, drop it. - if self.drop_whitespace and cur_line and cur_line[-1].strip() == '': - del cur_line[-1] - - # Convert current line back to a string and store it in list - # of all lines (return value). - if cur_line: - lines.append(indent + ''.join(cur_line)) - - return lines - - - # -- Public interface ---------------------------------------------- - - def wrap(self, text: str) -> List[str]: - """wrap(text : string) -> [string] - - Reformat the single paragraph in 'text' so it fits in lines of - no more than 'self.width' columns, and return a list of wrapped - lines. Tabs in 'text' are expanded with string.expandtabs(), - and all other whitespace characters (including newline) are - converted to space. - """ - text = self._munge_whitespace(text) - chunks = self._split(text) - if self.fix_sentence_endings: - self._fix_sentence_endings(chunks) - return self._wrap_chunks(chunks) - - def fill(self, text: str) -> str: - """fill(text : string) -> string - - Reformat the single paragraph in 'text' to fit in lines of no - more than 'self.width' columns, and return a new string - containing the entire wrapped paragraph. - """ - return "\n".join(self.wrap(text)) - - -# -- Convenience interface --------------------------------------------- - -def wrap(text: str, width: int = 70, **kwargs: Any) -> List[str]: - """Wrap a single paragraph of text, returning a list of wrapped lines. - - Reformat the single paragraph in 'text' so it fits in lines of no - more than 'width' columns, and return a list of wrapped lines. By - default, tabs in 'text' are expanded with string.expandtabs(), and - all other whitespace characters (including newline) are converted to - space. See TextWrapper class for available keyword args to customize - wrapping behaviour. - """ - w = TextWrapper(width=width, **kwargs) - return w.wrap(text) - -def fill(text: str, width: int = 70, **kwargs: Any) -> str: - """Fill a single paragraph of text, returning a new string. - - Reformat the single paragraph in 'text' to fit in lines of no more - than 'width' columns, and return a new string containing the entire - wrapped paragraph. As with wrap(), tabs are expanded and other - whitespace characters converted to space. See TextWrapper class for - available keyword args to customize wrapping behaviour. - """ - w = TextWrapper(width=width, **kwargs) - return w.fill(text) - - -# -- Loosely related functionality ------------------------------------- - -_whitespace_only_re = re.compile('^[ \t]+$', re.MULTILINE) -_leading_whitespace_re = re.compile('(^[ \t]*)(?:[^ \t\n])', re.MULTILINE) - -def dedent(text: str) -> str: - """Remove any common leading whitespace from every line in `text`. - - This can be used to make triple-quoted strings line up with the left - edge of the display, while still presenting them in the source code - in indented form. - - Note that tabs and spaces are both treated as whitespace, but they - are not equal: the lines " hello" and "\thello" are - considered to have no common leading whitespace. (This behaviour is - new in Python 2.5; older versions of this module incorrectly - expanded tabs before searching for common leading whitespace.) - """ - # Look for the longest leading string of spaces and tabs common to - # all lines. - margin = None # type: str - text = _whitespace_only_re.sub('', text) - indents = _leading_whitespace_re.findall(text) - for indent in indents: - if margin is None: - margin = indent - - # Current line more deeply indented than previous winner: - # no change (previous winner is still on top). - elif indent.startswith(margin): - pass - - # Current line consistent with and no deeper than previous winner: - # it's the new winner. - elif margin.startswith(indent): - margin = indent - - # Current line and previous winner have no common whitespace: - # there is no margin. - else: - margin = "" - break - - # sanity check (testing/debugging only) - if 0 and margin: - for line in text.split("\n"): - assert not line or line.startswith(margin), \ - "line = %r, margin = %r" % (line, margin) - - if margin: - text = re.sub(r'(?m)^' + margin, '', text) - return text - -if __name__ == "__main__": - #print dedent("\tfoo\n\tbar") - #print dedent(" \thello there\n \t how are you?") - print(dedent("Hello there.\n This is indented.")) diff --git a/test-data/unit/check-annotated.test b/test-data/unit/check-annotated.test index 68862087d13d..d4309b8ad213 100644 --- a/test-data/unit/check-annotated.test +++ b/test-data/unit/check-annotated.test @@ -87,7 +87,7 @@ from typing import Tuple from typing_extensions import Annotated Alias = Annotated[Tuple[int, ...], ...] x: Alias -reveal_type(x) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(x) # N: Revealed type is "builtins.tuple[builtins.int, ...]" [builtins fixtures/tuple.pyi] [case testAnnotatedAliasTypeVar] diff --git a/test-data/unit/check-attr.test b/test-data/unit/check-attr.test index e7cea6c27b99..7905f1add6ca 100644 --- a/test-data/unit/check-attr.test +++ b/test-data/unit/check-attr.test @@ -1399,7 +1399,40 @@ class A: b: int = attr.ib() c: str = attr.ib() -reveal_type(A.__attrs_attrs__) # N: Revealed type is "Tuple[attr.Attribute[builtins.int], attr.Attribute[builtins.str]]" +reveal_type(A.__attrs_attrs__) # N: Revealed type is "Tuple[attr.Attribute[builtins.int], attr.Attribute[builtins.str], fallback=__main__.A._AttrsAttributes]" +reveal_type(A.__attrs_attrs__[0]) # N: Revealed type is "attr.Attribute[builtins.int]" +reveal_type(A.__attrs_attrs__.b) # N: Revealed type is "attr.Attribute[builtins.int]" +A.__attrs_attrs__.x # E: "_AttrsAttributes" has no attribute "x" + +[builtins fixtures/attr.pyi] + +[case testAttrsBareClassHasAttributeWithAttributes] +import attr + +@attr.s +class A: + b = attr.ib() + c = attr.ib() + +reveal_type(A.__attrs_attrs__) # N: Revealed type is "Tuple[attr.Attribute[Any], attr.Attribute[Any], fallback=__main__.A._AttrsAttributes]" +reveal_type(A.__attrs_attrs__[0]) # N: Revealed type is "attr.Attribute[Any]" +reveal_type(A.__attrs_attrs__.b) # N: Revealed type is "attr.Attribute[Any]" +A.__attrs_attrs__.x # E: "_AttrsAttributes" has no attribute "x" + +[builtins fixtures/attr.pyi] + +[case testAttrsNGClassHasAttributeWithAttributes] +import attr + +@attr.define +class A: + b: int + c: str + +reveal_type(A.__attrs_attrs__) # N: Revealed type is "Tuple[attr.Attribute[builtins.int], attr.Attribute[builtins.str], fallback=__main__.A._AttrsAttributes]" +reveal_type(A.__attrs_attrs__[0]) # N: Revealed type is "attr.Attribute[builtins.int]" +reveal_type(A.__attrs_attrs__.b) # N: Revealed type is "attr.Attribute[builtins.int]" +A.__attrs_attrs__.x # E: "_AttrsAttributes" has no attribute "x" [builtins fixtures/attr.pyi] @@ -1432,3 +1465,93 @@ class C: 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] + +[case testAttrsWithMatchArgs] +# flags: --python-version 3.10 +import attr + +@attr.s(match_args=True, auto_attribs=True) +class ToMatch: + x: int + y: int + # Not included: + z: int = attr.field(kw_only=True) + i: int = attr.field(init=False) + +reveal_type(ToMatch(x=1, y=2, z=3).__match_args__) # N: Revealed type is "Tuple[Literal['x']?, Literal['y']?]" +reveal_type(ToMatch(1, 2, z=3).__match_args__) # N: Revealed type is "Tuple[Literal['x']?, Literal['y']?]" +[builtins fixtures/attr.pyi] + +[case testAttrsWithMatchArgsDefaultCase] +# flags: --python-version 3.10 +import attr + +@attr.s(auto_attribs=True) +class ToMatch1: + x: int + y: int + +t1: ToMatch1 +reveal_type(t1.__match_args__) # N: Revealed type is "Tuple[Literal['x']?, Literal['y']?]" + +@attr.define +class ToMatch2: + x: int + y: int + +t2: ToMatch2 +reveal_type(t2.__match_args__) # N: Revealed type is "Tuple[Literal['x']?, Literal['y']?]" +[builtins fixtures/attr.pyi] + +[case testAttrsWithMatchArgsOverrideExisting] +# flags: --python-version 3.10 +import attr +from typing import Final + +@attr.s(match_args=True, auto_attribs=True) +class ToMatch: + __match_args__: Final = ('a', 'b') + x: int + y: int + +# It works the same way runtime does: +reveal_type(ToMatch(x=1, y=2).__match_args__) # N: Revealed type is "Tuple[Literal['a']?, Literal['b']?]" + +@attr.s(auto_attribs=True) +class WithoutMatch: + __match_args__: Final = ('a', 'b') + x: int + y: int + +reveal_type(WithoutMatch(x=1, y=2).__match_args__) # N: Revealed type is "Tuple[Literal['a']?, Literal['b']?]" +[builtins fixtures/attr.pyi] + +[case testAttrsWithMatchArgsOldVersion] +# flags: --python-version 3.9 +import attr + +@attr.s(match_args=True) +class NoMatchArgs: + ... + +n: NoMatchArgs + +reveal_type(n.__match_args__) # E: "NoMatchArgs" has no attribute "__match_args__" \ + # N: Revealed type is "Any" +[builtins fixtures/attr.pyi] + +[case testAttrsMultipleInheritance] +# flags: --python-version 3.10 +import attr + +@attr.s +class A: + x = attr.ib(type=int) + +@attr.s +class B: + y = attr.ib(type=int) + +class AB(A, B): + pass +[builtins fixtures/attr.pyi] diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index a2bcdade3287..65b0e8d69cb5 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -7134,3 +7134,153 @@ class B(A): # E: Final class __main__.B has abstract attributes "foo" [case testUndefinedBaseclassInNestedClass] class C: class C1(XX): pass # E: Name "XX" is not defined + +[case testClassScopeImports] +class Foo: + from mod import plain_function # E: Unsupported class scoped import + from mod import plain_var + +reveal_type(Foo.plain_function) # N: Revealed type is "Any" +reveal_type(Foo().plain_function) # N: Revealed type is "Any" + +reveal_type(Foo.plain_var) # N: Revealed type is "builtins.int" +reveal_type(Foo().plain_var) # N: Revealed type is "builtins.int" + +[file mod.py] +def plain_function(x: int, y: int) -> int: ... +plain_var: int + +[case testClassScopeImportModule] +class Foo: + import mod + +reveal_type(Foo.mod) # N: Revealed type is "builtins.object" +reveal_type(Foo.mod.foo) # N: Revealed type is "builtins.int" +[file mod.py] +foo: int + +[case testClassScopeImportAlias] +class Foo: + from mod import function # E: Unsupported class scoped import + foo = function + + from mod import var1 + bar = var1 + + from mod import var2 + baz = var2 + + from mod import var3 + qux = var3 + +reveal_type(Foo.foo) # N: Revealed type is "Any" +reveal_type(Foo.function) # N: Revealed type is "Any" + +reveal_type(Foo.bar) # N: Revealed type is "builtins.int" +reveal_type(Foo.var1) # N: Revealed type is "builtins.int" + +reveal_type(Foo.baz) # N: Revealed type is "mod.C" +reveal_type(Foo.var2) # N: Revealed type is "mod.C" + +reveal_type(Foo.qux) # N: Revealed type is "builtins.int" +reveal_type(Foo.var3) # N: Revealed type is "builtins.int" + +[file mod.py] +def function(x: int, y: int) -> int: ... +var1: int + +class C: ... +var2: C + +A = int +var3: A + + +[case testClassScopeImportModuleStar] +class Foo: + from mod import * # E: Unsupported class scoped import + +reveal_type(Foo.foo) # N: Revealed type is "builtins.int" +reveal_type(Foo.bar) # N: Revealed type is "Any" +reveal_type(Foo.baz) # E: "Type[Foo]" has no attribute "baz" \ + # N: Revealed type is "Any" + +[file mod.py] +foo: int +def bar(x: int) -> int: ... + +[case testClassScopeImportFunctionNested] +class Foo: + class Bar: + from mod import baz # E: Unsupported class scoped import + +reveal_type(Foo.Bar.baz) # N: Revealed type is "Any" +reveal_type(Foo.Bar().baz) # N: Revealed type is "Any" + +[file mod.py] +def baz(x: int) -> int: ... + +[case testClassScopeImportUndefined] +class Foo: + from unknown import foo # E: Cannot find implementation or library stub for module named "unknown" \ + # N: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports + +reveal_type(Foo.foo) # N: Revealed type is "Any" +reveal_type(Foo().foo) # N: Revealed type is "Any" + +[case testClassScopeImportWithFollowImports] +# flags: --follow-imports=skip +class Foo: + from mod import foo + +reveal_type(Foo().foo) # N: Revealed type is "Any" +[file mod.py] +def foo(x: int, y: int) -> int: ... + +[case testClassScopeImportVarious] +class Foo: + from mod1 import foo # E: Unsupported class scoped import + from mod2 import foo + + from mod1 import meth1 # E: Unsupported class scoped import + def meth1(self, a: str) -> str: ... # E: Name "meth1" already defined on line 5 + + def meth2(self, a: str) -> str: ... + from mod1 import meth2 # E: Unsupported class scoped import \ + # E: Name "meth2" already defined on line 8 + +class Bar: + from mod1 import foo # E: Unsupported class scoped import + +import mod1 +reveal_type(Foo.foo) # N: Revealed type is "Any" +reveal_type(Bar.foo) # N: Revealed type is "Any" +reveal_type(mod1.foo) # N: Revealed type is "def (x: builtins.int, y: builtins.int) -> builtins.int" + +[file mod1.py] +def foo(x: int, y: int) -> int: ... +def meth1(x: int) -> int: ... +def meth2(x: int) -> int: ... +[file mod2.py] +def foo(z: str) -> int: ... + + +[case testClassScopeImportWithError] +class Foo: + from mod import meth1 # E: Unsupported class scoped import + from mod import meth2 # E: Unsupported class scoped import + from mod import T + +reveal_type(Foo.T) # E: Type variable "Foo.T" cannot be used as an expression \ + # N: Revealed type is "Any" + +[file mod.pyi] +from typing import Any, TypeVar, overload + +@overload +def meth1(self: Any, y: int) -> int: ... +@overload +def meth1(self: Any, y: str) -> str: ... + +T = TypeVar("T") +def meth2(self: Any, y: T) -> T: ... diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 73476a646c99..1773ac0eac8d 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -1456,3 +1456,99 @@ class Other: __slots__ = ('x',) x: int [builtins fixtures/dataclasses.pyi] + + +[case testSlotsDefinitionWithTwoPasses1] +# flags: --python-version 3.10 +# https://github.com/python/mypy/issues/11821 +from typing import TypeVar, Protocol, Generic +from dataclasses import dataclass + +C = TypeVar("C", bound="Comparable") + +class Comparable(Protocol): + pass + +V = TypeVar("V", bound=Comparable) + +@dataclass(slots=True) +class Node(Generic[V]): # Error was here + data: V +[builtins fixtures/dataclasses.pyi] + +[case testSlotsDefinitionWithTwoPasses2] +# flags: --python-version 3.10 +from typing import TypeVar, Protocol, Generic +from dataclasses import dataclass + +C = TypeVar("C", bound="Comparable") + +class Comparable(Protocol): + pass + +V = TypeVar("V", bound=Comparable) + +@dataclass(slots=True) # Explicit slots are still not ok: +class Node(Generic[V]): # E: "Node" both defines "__slots__" and is used with "slots=True" + __slots__ = ('data',) + data: V +[builtins fixtures/dataclasses.pyi] + +[case testSlotsDefinitionWithTwoPasses3] +# flags: --python-version 3.10 +from typing import TypeVar, Protocol, Generic +from dataclasses import dataclass + +C = TypeVar("C", bound="Comparable") + +class Comparable(Protocol): + pass + +V = TypeVar("V", bound=Comparable) + +@dataclass(slots=True) # Explicit slots are still not ok, even empty ones: +class Node(Generic[V]): # E: "Node" both defines "__slots__" and is used with "slots=True" + __slots__ = () + data: V +[builtins fixtures/dataclasses.pyi] + +[case testSlotsDefinitionWithTwoPasses4] +# flags: --python-version 3.10 +import dataclasses as dtc + +PublishedMessagesVar = dict[int, 'PublishedMessages'] + +@dtc.dataclass(frozen=True, slots=True) +class PublishedMessages: + left: int +[builtins fixtures/dataclasses.pyi] + +[case testDataclassesAnyInherit] +# flags: --python-version 3.7 +from dataclasses import dataclass +from typing import Any +B: Any +@dataclass +class A(B): + a: int + +A(a=1, b=2) +A(1) +A(a="foo") # E: Argument "a" to "A" has incompatible type "str"; expected "int" +[builtins fixtures/dataclasses.pyi] + +[case testDataclassesMultipleInheritanceWithNonDataclass] +# flags: --python-version 3.10 +from dataclasses import dataclass + +@dataclass +class A: + prop_a: str + +@dataclass +class B: + prop_b: bool + +class Derived(A, B): + pass +[builtins fixtures/dataclasses.pyi] diff --git a/test-data/unit/check-default-plugin.test b/test-data/unit/check-default-plugin.test index fc9f132abb62..aef6d6a71497 100644 --- a/test-data/unit/check-default-plugin.test +++ b/test-data/unit/check-default-plugin.test @@ -24,56 +24,15 @@ 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]: +async def yield_id(item: T) -> AsyncGenerator[T, None]: yield item reveal_type(yield_id) # N: Revealed type is "def [T] (item: T`-1) -> typing.AsyncContextManager[T`-1]" @@ -83,6 +42,36 @@ async with yield_id(1) as x: [typing fixtures/typing-async.pyi] [builtins fixtures/tuple.pyi] +[case testContextManagerReturnsGenericFunction] +import contextlib +from typing import Callable +from typing import Generator +from typing import Iterable +from typing import TypeVar + +TArg = TypeVar('TArg') +TRet = TypeVar('TRet') + +@contextlib.contextmanager +def _thread_mapper(maxsize: int) -> Generator[ + Callable[[Callable[[TArg], TRet], Iterable[TArg]], Iterable[TRet]], + None, None, +]: + # defined inline as there isn't a builtins.map fixture + def my_map(f: Callable[[TArg], TRet], it: Iterable[TArg]) -> Iterable[TRet]: + for x in it: + yield f(x) + + yield my_map + +def identity(x: int) -> int: return x + +with _thread_mapper(1) as m: + lst = list(m(identity, [2, 3])) + reveal_type(lst) # N: Revealed type is "builtins.list[builtins.int*]" +[typing fixtures/typing-medium.pyi] +[builtins fixtures/list.pyi] + [case testContextManagerWithUnspecifiedArguments] from contextlib import contextmanager from typing import Callable, Iterator diff --git a/test-data/unit/check-enum.test b/test-data/unit/check-enum.test index dd94bb6f82ef..9e2b38bd9c8d 100644 --- a/test-data/unit/check-enum.test +++ b/test-data/unit/check-enum.test @@ -11,6 +11,38 @@ m = Medal.gold if int(): m = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "Medal") +-- Creation from Enum call +-- ----------------------- + +[case testEnumCreatedFromStringLiteral] +from enum import Enum +from typing_extensions import Literal + +x: Literal['ANT BEE CAT DOG'] = 'ANT BEE CAT DOG' +Animal = Enum('Animal', x) +reveal_type(Animal.ANT) # N: Revealed type is "Literal[__main__.Animal.ANT]?" +reveal_type(Animal.BEE) # N: Revealed type is "Literal[__main__.Animal.BEE]?" +reveal_type(Animal.CAT) # N: Revealed type is "Literal[__main__.Animal.CAT]?" +reveal_type(Animal.DOG) # N: Revealed type is "Literal[__main__.Animal.DOG]?" + +[builtins fixtures/tuple.pyi] + +[case testEnumCreatedFromFinalValue] +from enum import Enum +from typing_extensions import Final + +x: Final['str'] = 'ANT BEE CAT DOG' +Animal = Enum('Animal', x) +reveal_type(Animal.ANT) # N: Revealed type is "Literal[__main__.Animal.ANT]?" +reveal_type(Animal.BEE) # N: Revealed type is "Literal[__main__.Animal.BEE]?" +reveal_type(Animal.CAT) # N: Revealed type is "Literal[__main__.Animal.CAT]?" +reveal_type(Animal.DOG) # N: Revealed type is "Literal[__main__.Animal.DOG]?" + +[builtins fixtures/tuple.pyi] + +-- Creation from EnumMeta +-- ---------------------- + [case testEnumFromEnumMetaBasics] from enum import EnumMeta class Medal(metaclass=EnumMeta): @@ -200,6 +232,20 @@ an_enum = SomeIntEnum.x an_enum = returns_some_int_enum() [out] +[case testStrEnumCreation] +# flags: --python-version 3.11 +from enum import StrEnum + +class MyStrEnum(StrEnum): + x = 'x' + y = 'y' + +reveal_type(MyStrEnum.x) # N: Revealed type is "Literal[__main__.MyStrEnum.x]?" +reveal_type(MyStrEnum.x.value) # N: Revealed type is "Literal['x']?" +reveal_type(MyStrEnum.y) # N: Revealed type is "Literal[__main__.MyStrEnum.y]?" +reveal_type(MyStrEnum.y.value) # N: Revealed type is "Literal['y']?" +[out] + [case testEnumMethods] from enum import Enum @@ -586,8 +632,8 @@ reveal_type(A2.x.value) # N: Revealed type is "builtins.int" reveal_type(A2.x._value_) # N: Revealed type is "builtins.int" is_x(reveal_type(A3.x.name)) # N: Revealed type is "Literal['x']" is_x(reveal_type(A3.x._name_)) # N: Revealed type is "Literal['x']" -reveal_type(A3.x.value) # N: Revealed type is "builtins.int" -reveal_type(A3.x._value_) # N: Revealed type is "builtins.int" +reveal_type(A3.x.value) # N: Revealed type is "Literal[1]?" +reveal_type(A3.x._value_) # N: Revealed type is "Literal[1]?" B1 = IntEnum('B1', 'x') class B2(IntEnum): @@ -607,8 +653,8 @@ reveal_type(B2.x.value) # N: Revealed type is "builtins.int" reveal_type(B2.x._value_) # N: Revealed type is "builtins.int" is_x(reveal_type(B3.x.name)) # N: Revealed type is "Literal['x']" is_x(reveal_type(B3.x._name_)) # N: Revealed type is "Literal['x']" -reveal_type(B3.x.value) # N: Revealed type is "builtins.int" -reveal_type(B3.x._value_) # N: Revealed type is "builtins.int" +reveal_type(B3.x.value) # N: Revealed type is "Literal[1]?" +reveal_type(B3.x._value_) # N: Revealed type is "Literal[1]?" # TODO: C1.x.value and C2.x.value should also be of type 'int' # This requires either a typeshed change or a plugin refinement @@ -629,8 +675,8 @@ reveal_type(C2.x.value) # N: Revealed type is "builtins.int" reveal_type(C2.x._value_) # N: Revealed type is "builtins.int" is_x(reveal_type(C3.x.name)) # N: Revealed type is "Literal['x']" is_x(reveal_type(C3.x._name_)) # N: Revealed type is "Literal['x']" -reveal_type(C3.x.value) # N: Revealed type is "builtins.int" -reveal_type(C3.x._value_) # N: Revealed type is "builtins.int" +reveal_type(C3.x.value) # N: Revealed type is "Literal[1]?" +reveal_type(C3.x._value_) # N: Revealed type is "Literal[1]?" D1 = Flag('D1', 'x') class D2(Flag): @@ -648,8 +694,8 @@ reveal_type(D2.x.value) # N: Revealed type is "builtins.int" reveal_type(D2.x._value_) # N: Revealed type is "builtins.int" is_x(reveal_type(D3.x.name)) # N: Revealed type is "Literal['x']" is_x(reveal_type(D3.x._name_)) # N: Revealed type is "Literal['x']" -reveal_type(D3.x.value) # N: Revealed type is "builtins.int" -reveal_type(D3.x._value_) # N: Revealed type is "builtins.int" +reveal_type(D3.x.value) # N: Revealed type is "Literal[1]?" +reveal_type(D3.x._value_) # N: Revealed type is "Literal[1]?" # TODO: Generalize our enum functional API logic to work with subclasses of Enum # See https://github.com/python/mypy/issues/6037 @@ -667,8 +713,8 @@ reveal_type(E2.x.value) # N: Revealed type is "builtins.int" reveal_type(E2.x._value_) # N: Revealed type is "builtins.int" is_x(reveal_type(E3.x.name)) # N: Revealed type is "Literal['x']" is_x(reveal_type(E3.x._name_)) # N: Revealed type is "Literal['x']" -reveal_type(E3.x.value) # N: Revealed type is "builtins.int" -reveal_type(E3.x._value_) # N: Revealed type is "builtins.int" +reveal_type(E3.x.value) # N: Revealed type is "Literal[1]?" +reveal_type(E3.x._value_) # N: Revealed type is "Literal[1]?" # TODO: Figure out if we can construct enums using EnumMetas using the functional API. @@ -705,9 +751,9 @@ from enum import Enum class SomeEnum(Enum): a = "foo" [out] -main:2: note: Revealed type is "builtins.int" +main:2: note: Revealed type is "Literal[1]?" [out2] -main:2: note: Revealed type is "builtins.str" +main:2: note: Revealed type is "Literal['foo']?" [case testEnumReachabilityChecksBasic] from enum import Enum @@ -1279,8 +1325,8 @@ class Foo(Enum): B = 2 a = Foo.A -reveal_type(a.value) # N: Revealed type is "builtins.int" -reveal_type(a._value_) # N: Revealed type is "builtins.int" +reveal_type(a.value) # N: Revealed type is "Union[Literal[1]?, Literal[2]?]" +reveal_type(a._value_) # N: Revealed type is "Union[Literal[1]?, Literal[2]?]" [case testNewSetsUnexpectedValueType] from enum import Enum @@ -1359,9 +1405,9 @@ class E(Enum): e: E a: Literal[E.A, E.B, E.C] = e -b: Literal[E.A, E.B] = e # E: Incompatible types in assignment (expression has type "E", variable has type "Union[Literal[E.A], Literal[E.B]]") -c: Literal[E.A, E.C] = e # E: Incompatible types in assignment (expression has type "E", variable has type "Union[Literal[E.A], Literal[E.C]]") -b = a # E: Incompatible types in assignment (expression has type "Union[Literal[E.A], Literal[E.B], Literal[E.C]]", variable has type "Union[Literal[E.A], Literal[E.B]]") +b: Literal[E.A, E.B] = e # E: Incompatible types in assignment (expression has type "E", variable has type "Literal[E.A, E.B]") +c: Literal[E.A, E.C] = e # E: Incompatible types in assignment (expression has type "E", variable has type "Literal[E.A, E.C]") +b = a # E: Incompatible types in assignment (expression has type "Literal[E.A, E.B, E.C]", variable has type "Literal[E.A, E.B]") [builtins fixtures/bool.pyi] [case testIntEnumWithNewTypeValue] @@ -1405,7 +1451,7 @@ 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" +reveal_type(Foo.A.value) # N: Revealed type is "Literal[1]?" class Bar(Enum): A = 1 @@ -1437,22 +1483,22 @@ class NonEmptyFlag(Flag): class NonEmptyIntFlag(IntFlag): x = 1 -class ErrorEnumWithValue(NonEmptyEnum): # E: Cannot inherit from final class "NonEmptyEnum" +class ErrorEnumWithValue(NonEmptyEnum): # E: Cannot extend enum with existing members: "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" +class ErrorIntEnumWithValue(NonEmptyIntEnum): # E: Cannot extend enum with existing members: "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" +class ErrorFlagWithValue(NonEmptyFlag): # E: Cannot extend enum with existing members: "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" +class ErrorIntFlagWithValue(NonEmptyIntFlag): # E: Cannot extend enum with existing members: "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" +class ErrorEnumWithoutValue(NonEmptyEnum): # E: Cannot extend enum with existing members: "NonEmptyEnum" pass -class ErrorIntEnumWithoutValue(NonEmptyIntEnum): # E: Cannot inherit from final class "NonEmptyIntEnum" +class ErrorIntEnumWithoutValue(NonEmptyIntEnum): # E: Cannot extend enum with existing members: "NonEmptyIntEnum" pass -class ErrorFlagWithoutValue(NonEmptyFlag): # E: Cannot inherit from final class "NonEmptyFlag" +class ErrorFlagWithoutValue(NonEmptyFlag): # E: Cannot extend enum with existing members: "NonEmptyFlag" pass -class ErrorIntFlagWithoutValue(NonEmptyIntFlag): # E: Cannot inherit from final class "NonEmptyIntFlag" +class ErrorIntFlagWithoutValue(NonEmptyIntFlag): # E: Cannot extend enum with existing members: "NonEmptyIntFlag" pass [builtins fixtures/bool.pyi] @@ -1556,13 +1602,17 @@ class NonEmptyIntFlag(IntFlag): class NonEmptyEnumMeta(EnumMeta): x = 1 -class ErrorEnumWithoutValue(NonEmptyEnum): # E: Cannot inherit from final class "NonEmptyEnum" +class ErrorEnumWithoutValue(NonEmptyEnum): # E: Cannot inherit from final class "NonEmptyEnum" \ + # E: Cannot extend enum with existing members: "NonEmptyEnum" pass -class ErrorIntEnumWithoutValue(NonEmptyIntEnum): # E: Cannot inherit from final class "NonEmptyIntEnum" +class ErrorIntEnumWithoutValue(NonEmptyIntEnum): # E: Cannot inherit from final class "NonEmptyIntEnum" \ + # E: Cannot extend enum with existing members: "NonEmptyIntEnum" pass -class ErrorFlagWithoutValue(NonEmptyFlag): # E: Cannot inherit from final class "NonEmptyFlag" +class ErrorFlagWithoutValue(NonEmptyFlag): # E: Cannot inherit from final class "NonEmptyFlag" \ + # E: Cannot extend enum with existing members: "NonEmptyFlag" pass -class ErrorIntFlagWithoutValue(NonEmptyIntFlag): # E: Cannot inherit from final class "NonEmptyIntFlag" +class ErrorIntFlagWithoutValue(NonEmptyIntFlag): # E: Cannot inherit from final class "NonEmptyIntFlag" \ + # E: Cannot extend enum with existing members: "NonEmptyIntFlag" pass class ErrorEnumMetaWithoutValue(NonEmptyEnumMeta): # E: Cannot inherit from final class "NonEmptyEnumMeta" pass @@ -1660,13 +1710,13 @@ class NonEmptyIntFlag(IntFlag): x = 1 def method(self) -> None: pass -class ErrorEnumWithoutValue(NonEmptyEnum): # E: Cannot inherit from final class "NonEmptyEnum" +class ErrorEnumWithoutValue(NonEmptyEnum): # E: Cannot extend enum with existing members: "NonEmptyEnum" pass -class ErrorIntEnumWithoutValue(NonEmptyIntEnum): # E: Cannot inherit from final class "NonEmptyIntEnum" +class ErrorIntEnumWithoutValue(NonEmptyIntEnum): # E: Cannot extend enum with existing members: "NonEmptyIntEnum" pass -class ErrorFlagWithoutValue(NonEmptyFlag): # E: Cannot inherit from final class "NonEmptyFlag" +class ErrorFlagWithoutValue(NonEmptyFlag): # E: Cannot extend enum with existing members: "NonEmptyFlag" pass -class ErrorIntFlagWithoutValue(NonEmptyIntFlag): # E: Cannot inherit from final class "NonEmptyIntFlag" +class ErrorIntFlagWithoutValue(NonEmptyIntFlag): # E: Cannot extend enum with existing members: "NonEmptyIntFlag" pass [builtins fixtures/bool.pyi] @@ -1675,21 +1725,33 @@ from enum import Enum class A(Enum): class Inner: pass -class B(A): pass # E: Cannot inherit from final class "A" +class B(A): pass # E: Cannot extend enum with existing members: "A" [builtins fixtures/bool.pyi] - [case testEnumFinalSpecialProps] # https://github.com/python/mypy/issues/11699 +# https://github.com/python/mypy/issues/11820 from enum import Enum, IntEnum -class E(Enum): +class BaseWithSpecials: + __slots__ = () + __doc__ = 'doc' + __module__ = 'module' + __annotations__ = {'a': int} + __dict__ = {'a': 1} + +class E(BaseWithSpecials, Enum): name = 'a' value = 'b' _name_ = 'a1' _value_ = 'b2' _order_ = 'X Y' __order__ = 'X Y' + __slots__ = () + __doc__ = 'doc' + __module__ = 'module' + __annotations__ = {'a': int} + __dict__ = {'a': 1} class EI(IntEnum): name = 'a' @@ -1698,7 +1760,323 @@ class EI(IntEnum): _value_ = 2 _order_ = 'X Y' __order__ = 'X Y' + __slots__ = () + __doc__ = 'doc' + __module__ = 'module' + __annotations__ = {'a': int} + __dict__ = {'a': 1} E._order_ = 'a' # E: Cannot assign to final attribute "_order_" EI.value = 2 # E: Cannot assign to final attribute "value" +[builtins fixtures/dict.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 extend enum with existing members: "A1" + pass + +class A2(Enum): + x = 2 +class B2(A2): # E: Cannot extend enum with existing members: "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 extend enum with existing members: "A" + x = 1 # E: Cannot override writable attribute "x" with a final one + +class C(Enum): + x = 1 +class D(C): # E: Cannot extend enum with existing members: "C" + x: int # E: Cannot assign to final name "x" [builtins fixtures/bool.pyi] + +[case testEnumLiteralValues] +from enum import Enum + +class A(Enum): + str = "foo" + int = 1 + bool = False + tuple = (1,) + +reveal_type(A.str.value) # N: Revealed type is "Literal['foo']?" +reveal_type(A.int.value) # N: Revealed type is "Literal[1]?" +reveal_type(A.bool.value) # N: Revealed type is "Literal[False]?" +reveal_type(A.tuple.value) # N: Revealed type is "Tuple[Literal[1]?]" +[builtins fixtures/tuple.pyi] + +[case testFinalWithPrivateAssignment] +import enum +class Some(enum.Enum): + __priv = 1 + +class Other(Some): # Should pass + pass +[builtins fixtures/tuple.pyi] + +[case testFinalWithDunderAssignment] +import enum +class Some(enum.Enum): + __some__ = 1 + +class Other(Some): # Should pass + pass +[builtins fixtures/tuple.pyi] + +[case testFinalWithSunderAssignment] +import enum +class Some(enum.Enum): + _some_ = 1 + +class Other(Some): # Should pass + pass +[builtins fixtures/tuple.pyi] + +[case testFinalWithMethodAssignment] +import enum +from typing import overload +class Some(enum.Enum): + def lor(self, other) -> bool: + pass + + ror = lor + +class Other(Some): # Should pass + pass + + +class WithOverload(enum.IntEnum): + @overload + def meth(self, arg: int) -> int: pass + @overload + def meth(self, arg: str) -> str: pass + def meth(self, arg): pass + + alias = meth + +class SubWithOverload(WithOverload): # Should pass + pass +[builtins fixtures/tuple.pyi] + +[case testEnumBaseClassesOrder] +import enum + +# Base types: + +class First: + def __new__(cls, val): + pass + +class Second: + def __new__(cls, val): + pass + +class Third: + def __new__(cls, val): + pass + +class Mixin: + pass + +# Correct Enums: + +class Correct0(enum.Enum): + pass + +class Correct1(Mixin, First, enum.Enum): + pass + +class Correct2(First, enum.Enum): + pass + +class Correct3(Mixin, enum.Enum): + pass + +class RegularClass(Mixin, First, Second): + pass + +# Correct inheritance: + +class _InheritingDataAndMixin(Correct1): + pass + +class _CorrectWithData(First, Correct0): + pass + +class _CorrectWithDataAndMixin(Mixin, First, Correct0): + pass + +class _CorrectWithMixin(Mixin, Correct2): + pass + +# Wrong Enums: + +class TwoDataTypesViaInheritance(Second, Correct2): # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Correct2" + pass + +class TwoDataTypesViaInheritanceAndMixin(Second, Correct2, Mixin): # E: No base classes are allowed after "__main__.Correct2" \ + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Correct2" + pass + +class MixinAfterEnum1(enum.Enum, Mixin): # E: No base classes are allowed after "enum.Enum" + pass + +class MixinAfterEnum2(First, enum.Enum, Mixin): # E: No base classes are allowed after "enum.Enum" + pass + +class TwoDataTypes(First, Second, enum.Enum): # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" + pass + +class TwoDataTypesAndIntEnumMixin(First, Second, enum.IntEnum, Mixin): # E: No base classes are allowed after "enum.IntEnum" \ + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" + pass + +class ThreeDataTypes(First, Second, Third, enum.Enum): # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" \ + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Third" + pass + +class ThreeDataTypesAndMixin(First, Second, Third, enum.Enum, Mixin): # E: No base classes are allowed after "enum.Enum" \ + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" \ + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Third" + pass + +class FromEnumAndOther1(Correct2, Second, enum.Enum): # E: No base classes are allowed after "__main__.Correct2" \ + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" + pass + +class FromEnumAndOther2(Correct2, Second): # E: No base classes are allowed after "__main__.Correct2" \ + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" + pass +[builtins fixtures/tuple.pyi] + +[case testRegression12258] +from enum import Enum + +class MyEnum(Enum): ... + +class BytesEnum(bytes, MyEnum): ... # Should be ok +[builtins fixtures/tuple.pyi] + +[case testEnumWithNewHierarchy] +import enum + +class A: + def __new__(cls, val): ... +class B(A): + def __new__(cls, val): ... +class C: + def __new__(cls, val): ... + +class E1(A, enum.Enum): ... +class E2(B, enum.Enum): ... + +# Errors: + +class W1(C, E1): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E1" +class W2(C, E2): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E2" +[builtins fixtures/tuple.pyi] + +[case testEnumValueUnionSimplification] +from enum import IntEnum +from typing import Any + +class C(IntEnum): + X = 0 + Y = 1 + Z = 2 + +def f1(c: C) -> None: + x = {'x': c.value} + reveal_type(x) # N: Revealed type is "builtins.dict[builtins.str*, builtins.int]" + +def f2(c: C, a: Any) -> None: + x = {'x': c.value, 'y': a} + reveal_type(x) # N: Revealed type is "builtins.dict[builtins.str*, Any]" + y = {'y': a, 'x': c.value} + reveal_type(y) # N: Revealed type is "builtins.dict[builtins.str*, Any]" +[builtins fixtures/dict.pyi] + +[case testEnumIgnoreIsDeleted] +from enum import Enum + +class C(Enum): + _ignore_ = 'X' + +C._ignore_ # E: "Type[C]" has no attribute "_ignore_" +[typing fixtures/typing-medium.pyi] + +[case testCanOverrideDunderAttributes] +import typing +from enum import Enum, Flag + +class BaseEnum(Enum): + __dunder__ = 1 + __labels__: typing.Dict[int, str] + +class Override(BaseEnum): + __dunder__ = 2 + __labels__ = {1: "1"} + +Override.__dunder__ = 3 +BaseEnum.__dunder__ = 3 +Override.__labels__ = {2: "2"} + +class FlagBase(Flag): + __dunder__ = 1 + __labels__: typing.Dict[int, str] + +class FlagOverride(FlagBase): + __dunder__ = 2 + __labels = {1: "1"} + +FlagOverride.__dunder__ = 3 +FlagBase.__dunder__ = 3 +FlagOverride.__labels__ = {2: "2"} +[builtins fixtures/dict.pyi] + +[case testCanNotInitialize__members__] +import typing +from enum import Enum + +class WritingMembers(Enum): + __members__: typing.Dict[Enum, Enum] = {} # E: Assigned "__members__" will be overriden by "Enum" internally + +class OnlyAnnotatedMembers(Enum): + __members__: typing.Dict[Enum, Enum] +[builtins fixtures/dict.pyi] + +[case testCanOverrideDunderOnNonFirstBaseEnum] +import typing +from enum import Enum + +class Some: + __labels__: typing.Dict[int, str] + +class A(Some, Enum): + __labels__ = {1: "1"} +[builtins fixtures/dict.pyi] diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 1ceafaed8dff..a74771108ca2 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -34,10 +34,8 @@ 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] -[out version>=3.10.1] -main:1: error: invalid syntax [syntax] [case testErrorCodeSyntaxError2] def f(): # E: Type signature has too many arguments [syntax] @@ -77,41 +75,51 @@ for v in f(): # type: int, int # E: Syntax error in type annotation [syntax] [case testErrorCodeIgnore1] 'x'.foobar # type: ignore[attr-defined] -'x'.foobar # type: ignore[xyz] # E: "str" has no attribute "foobar" [attr-defined] +'x'.foobar # type: ignore[xyz] # E: "str" has no attribute "foobar" [attr-defined] \ + # N: Error code "attr-defined" not covered by "type: ignore" comment 'x'.foobar # type: ignore [case testErrorCodeIgnore2] a = 'x'.foobar # type: int # type: ignore[attr-defined] -b = 'x'.foobar # type: int # type: ignore[xyz] # E: "str" has no attribute "foobar" [attr-defined] +b = 'x'.foobar # type: int # type: ignore[xyz] # E: "str" has no attribute "foobar" [attr-defined] \ + # N: Error code "attr-defined" not covered by "type: ignore" comment c = 'x'.foobar # type: int # type: ignore [case testErrorCodeIgnore1_python2] 'x'.foobar # type: ignore[attr-defined] -'x'.foobar # type: ignore[xyz] # E: "str" has no attribute "foobar" [attr-defined] +'x'.foobar # type: ignore[xyz] # E: "str" has no attribute "foobar" [attr-defined] \ + # N: Error code "attr-defined" not covered by "type: ignore" comment 'x'.foobar # type: ignore [case testErrorCodeIgnore2_python2] a = 'x'.foobar # type: int # type: ignore[attr-defined] -b = 'x'.foobar # type: int # type: ignore[xyz] # E: "str" has no attribute "foobar" [attr-defined] +b = 'x'.foobar # type: int # type: ignore[xyz] # E: "str" has no attribute "foobar" [attr-defined] \ + # N: Error code "attr-defined" not covered by "type: ignore" comment c = 'x'.foobar # type: int # type: ignore [case testErrorCodeIgnoreMultiple1] a = 'x'.foobar(b) # type: ignore[name-defined, attr-defined] -a = 'x'.foobar(b) # type: ignore[name-defined, xyz] # E: "str" has no attribute "foobar" [attr-defined] -a = 'x'.foobar(b) # type: ignore[xyz, w, attr-defined] # E: Name "b" is not defined [name-defined] +a = 'x'.foobar(b) # type: ignore[name-defined, xyz] # E: "str" has no attribute "foobar" [attr-defined] \ + # N: Error code "attr-defined" not covered by "type: ignore" comment +a = 'x'.foobar(b) # type: ignore[xyz, w, attr-defined] # E: Name "b" is not defined [name-defined] \ + # N: Error code "name-defined" not covered by "type: ignore" comment [case testErrorCodeIgnoreMultiple2] 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] +b = 'x'.foobar(b) # type: int # type: ignore[name-defined, xyz] # E: "str" has no attribute "foobar" [attr-defined] \ + # N: Error code "attr-defined" not covered by "type: ignore" comment [case testErrorCodeIgnoreMultiple1_python2] a = 'x'.foobar(b) # type: ignore[name-defined, attr-defined] -a = 'x'.foobar(b) # type: ignore[name-defined, xyz] # E: "str" has no attribute "foobar" [attr-defined] -a = 'x'.foobar(b) # type: ignore[xyz, w, attr-defined] # E: Name "b" is not defined [name-defined] +a = 'x'.foobar(b) # type: ignore[name-defined, xyz] # E: "str" has no attribute "foobar" [attr-defined] \ + # N: Error code "attr-defined" not covered by "type: ignore" comment +a = 'x'.foobar(b) # type: ignore[xyz, w, attr-defined] # E: Name "b" is not defined [name-defined] \ + # N: Error code "name-defined" not covered by "type: ignore" comment [case testErrorCodeIgnoreMultiple2_python2] 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] +b = 'x'.foobar(b) # type: int # type: ignore[name-defined, xyz] # E: "str" has no attribute "foobar" [attr-defined] \ + # N: Error code "attr-defined" not covered by "type: ignore" comment [case testErrorCodeWarnUnusedIgnores1] # flags: --warn-unused-ignores @@ -137,21 +145,58 @@ x # type: ignore[name-defined, attr-defined] # E: Unused "type: ignore[attr-defi # flags: --warn-unused-ignores "x" # type: ignore[name-defined] # E: Unused "type: ignore" comment +[case testErrorCodeMissingWhenRequired] +# flags: --enable-error-code ignore-without-code +"x" # type: ignore # E: "type: ignore" comment without error code [ignore-without-code] +y # type: ignore # E: "type: ignore" comment without error code (consider "type: ignore[name-defined]" instead) [ignore-without-code] +z # type: ignore[name-defined] +"a" # type: ignore[ignore-without-code] + +[case testErrorCodeMissingDoesntTrampleUnusedIgnoresWarning] +# flags: --enable-error-code ignore-without-code --warn-unused-ignores +"x" # type: ignore # E: Unused "type: ignore" comment +"y" # type: ignore[ignore-without-code] # E: Unused "type: ignore" comment +z # type: ignore[ignore-without-code] # E: Unused "type: ignore" comment # E: Name "z" is not defined [name-defined] # N: Error code "name-defined" not covered by "type: ignore" comment + +[case testErrorCodeMissingWholeFileIgnores] +# flags: --enable-error-code ignore-without-code +# type: ignore # whole file ignore +x +y # type: ignore # ignore the lack of error code since we're ignore the whole file + +[case testErrorCodeMissingMultiple] +# flags: --enable-error-code ignore-without-code --python-version 3.7 +from __future__ import annotations +class A: + attr: int + def func(self, var: int) -> A | None: ... + +a: A | None +# 'union-attr' should only be listed once (instead of twice) and list should be sorted +a.func("invalid string").attr # type: ignore # E: "type: ignore" comment without error code (consider "type: ignore[arg-type, union-attr]" instead) [ignore-without-code] +[builtins fixtures/tuple.pyi] + [case testErrorCodeIgnoreWithExtraSpace] x # type: ignore [name-defined] x2 # type: ignore [ name-defined ] x3 # type: ignore [ xyz , name-defined ] x4 # type: ignore[xyz,name-defined] -y # type: ignore [xyz] # E: Name "y" is not defined [name-defined] -y # type: ignore[ xyz ] # E: Name "y" is not defined [name-defined] -y # type: ignore[ xyz , foo ] # E: Name "y" is not defined [name-defined] +y # type: ignore [xyz] # E: Name "y" is not defined [name-defined] \ + # N: Error code "name-defined" not covered by "type: ignore" comment +y # type: ignore[ xyz ] # E: Name "y" is not defined [name-defined] \ + # N: Error code "name-defined" not covered by "type: ignore" comment +y # type: ignore[ xyz , foo ] # E: Name "y" is not defined [name-defined] \ + # N: Error code "name-defined" not covered by "type: ignore" comment a = z # type: int # type: ignore [name-defined] b = z2 # type: int # type: ignore [ name-defined ] c = z2 # type: int # type: ignore [ name-defined , xyz ] -d = zz # type: int # type: ignore [xyz] # E: Name "zz" is not defined [name-defined] -e = zz # type: int # type: ignore [ xyz ] # E: Name "zz" is not defined [name-defined] -f = zz # type: int # type: ignore [ xyz,foo ] # E: Name "zz" is not defined [name-defined] +d = zz # type: int # type: ignore [xyz] # E: Name "zz" is not defined [name-defined] \ + # N: Error code "name-defined" not covered by "type: ignore" comment +e = zz # type: int # type: ignore [ xyz ] # E: Name "zz" is not defined [name-defined] \ + # N: Error code "name-defined" not covered by "type: ignore" comment +f = zz # type: int # type: ignore [ xyz,foo ] # E: Name "zz" is not defined [name-defined] \ + # N: Error code "name-defined" not covered by "type: ignore" comment [case testErrorCodeIgnoreAfterArgComment] def f(x # type: xyz # type: ignore[name-defined] # Comment @@ -164,7 +209,8 @@ def g(x # type: xyz # type: ignore # Comment # type () -> None pass -def h(x # type: xyz # type: ignore[foo] # E: Name "xyz" is not defined [name-defined] +def h(x # type: xyz # type: ignore[foo] # E: Name "xyz" is not defined [name-defined] \ + # N: Error code "name-defined" not covered by "type: ignore" comment ): # type () -> None pass @@ -180,7 +226,8 @@ def g(x # type: xyz # type: ignore # Comment # type () -> None pass -def h(x # type: xyz # type: ignore[foo] # E: Name "xyz" is not defined [name-defined] +def h(x # type: xyz # type: ignore[foo] # E: Name "xyz" is not defined [name-defined] \ + # N: Error code "name-defined" not covered by "type: ignore" comment ): # type () -> None pass @@ -900,6 +947,17 @@ if lst: pass [builtins fixtures/list.pyi] +[case testNoOverloadImplementation] +from typing import overload + +@overload # E: An overloaded function outside a stub file must have an implementation [no-overload-impl] +def f(arg: int) -> int: + ... + +@overload +def f(arg: str) -> str: + ... + [case testSliceInDict39] # flags: --python-version 3.9 --show-column-numbers from typing import Dict @@ -935,3 +993,20 @@ class TensorType: ... t: TensorType["batch":..., float] # type: ignore reveal_type(t) # N: Revealed type is "__main__.TensorType" [builtins fixtures/tuple.pyi] + +[case testNoteAboutChangedTypedDictErrorCode] +from typing_extensions import TypedDict +class D(TypedDict): + x: int + +def f(d: D, s: str) -> None: + d[s] # type: ignore[xyz] \ + # E: TypedDict key must be a string literal; expected one of ("x") [literal-required] \ + # N: Error code "literal-required" not covered by "type: ignore" comment + d[s] # E: TypedDict key must be a string literal; expected one of ("x") [literal-required] + d[s] # type: ignore[misc] \ + # E: TypedDict key must be a string literal; expected one of ("x") [literal-required] \ + # N: Error code changed to literal-required; "type: ignore" comment may be out of date + d[s] # type: ignore[literal-required] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-typeddict.pyi] diff --git a/test-data/unit/check-expressions.test b/test-data/unit/check-expressions.test index a275de94c9be..46f0cf02a125 100644 --- a/test-data/unit/check-expressions.test +++ b/test-data/unit/check-expressions.test @@ -202,6 +202,70 @@ class C: pass [builtins fixtures/tuple.pyi] +[case testDivPython2] +# flags: --python-version 2.7 +class A(object): + def __div__(self, other): + # type: (A, str) -> str + return 'a' + +a = A() +reveal_type(a / 'b') # N: Revealed type is "builtins.str" +a / 1 # E: Unsupported operand types for / ("A" and "int") +[builtins fixtures/bool.pyi] + +[case testDivPython2FutureImport] +# flags: --python-version 2.7 +from __future__ import division + +class A(object): + def __truediv__(self, other): + # type: (A, str) -> str + return 'a' + +a = A() +reveal_type(a / 'b') # N: Revealed type is "builtins.str" +a / 1 # E: Unsupported operand types for / ("A" and "int") +[builtins fixtures/bool.pyi] + +[case testDivPython2FutureImportNotLeaking] +# flags: --python-version 2.7 +import m1 + +[file m1.py] +import m2 + +class A(object): + def __div__(self, other): + # type: (A, str) -> str + return 'a' + +a = A() +reveal_type(a / 'b') # N: Revealed type is "builtins.str" +a / 1 # E: Unsupported operand types for / ("A" and "int") +[file m2.py] +from __future__ import division +[builtins fixtures/bool.pyi] + +[case testDivPython2FutureImportNotLeaking2] +# flags: --python-version 2.7 +import m1 + +[file m1.py] +import m2 + +class A(object): + def __div__(self, other): + # type: (A, str) -> str + return 'a' + +a = A() +reveal_type(a / 'b') # N: Revealed type is "builtins.str" +a / 1 # E: Unsupported operand types for / ("A" and "int") +[file m2.py] +# empty +[builtins fixtures/bool.pyi] + [case testIntDiv] a, b, c = None, None, None # type: (A, B, C) if int(): @@ -1688,6 +1752,22 @@ main:1: note: Revealed type is "Any" def reveal_type(x: int) -> None: pass reveal_type("foo") # E: Argument 1 to "reveal_type" has incompatible type "str"; expected "int" +[case testTypingRevealType] +from typing import reveal_type +from typing import reveal_type as show_me_the_type + +reveal_type(1) # N: Revealed type is "Literal[1]?" +show_me_the_type(1) # N: Revealed type is "Literal[1]?" + +[case testTypingExtensionsRevealType] +from typing_extensions import reveal_type +from typing_extensions import reveal_type as show_me_the_type + +reveal_type(1) # N: Revealed type is "Literal[1]?" +show_me_the_type(1) # N: Revealed type is "Literal[1]?" + +[builtins fixtures/tuple.pyi] + [case testRevealTypeVar] reveal_type = 1 1 + "foo" # E: Unsupported operand types for + ("int" and "str") @@ -2137,9 +2217,9 @@ def returns_1_or_2() -> Literal[1, 2]: ... THREE: Final = 3 -if returns_a_or_b() == 'c': # E: Non-overlapping equality check (left operand type: "Union[Literal['a'], Literal['b']]", right operand type: "Literal['c']") +if returns_a_or_b() == 'c': # E: Non-overlapping equality check (left operand type: "Literal['a', 'b']", right operand type: "Literal['c']") ... -if returns_1_or_2() is THREE: # E: Non-overlapping identity check (left operand type: "Union[Literal[1], Literal[2]]", right operand type: "Literal[3]") +if returns_1_or_2() is THREE: # E: Non-overlapping identity check (left operand type: "Literal[1, 2]", right operand type: "Literal[3]") ... [builtins fixtures/bool.pyi] diff --git a/test-data/unit/check-fastparse.test b/test-data/unit/check-fastparse.test index e2dc4f203855..b30581f0cfd3 100644 --- a/test-data/unit/check-fastparse.test +++ b/test-data/unit/check-fastparse.test @@ -154,7 +154,7 @@ def f(a, # type: A ): reveal_type(a) # N: Revealed type is "__main__.A" reveal_type(b) # N: Revealed type is "Union[__main__.B, None]" - reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C]" + reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C, ...]" reveal_type(d) # N: Revealed type is "Union[__main__.D, None]" reveal_type(e) # N: Revealed type is "__main__.E" reveal_type(kwargs) # N: Revealed type is "builtins.dict[builtins.str, __main__.F]" @@ -179,7 +179,7 @@ def f(a, # type: A # type: (...) -> int reveal_type(a) # N: Revealed type is "__main__.A" reveal_type(b) # N: Revealed type is "Union[__main__.B, None]" - reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C]" + reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C, ...]" reveal_type(d) # N: Revealed type is "Union[__main__.D, None]" reveal_type(e) # N: Revealed type is "__main__.E" reveal_type(kwargs) # N: Revealed type is "builtins.dict[builtins.str, __main__.F]" @@ -221,7 +221,7 @@ def f(a, # type: A ): reveal_type(a) # N: Revealed type is "__main__.A" reveal_type(b) # N: Revealed type is "Union[__main__.B, None]" - reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C]" + reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C, ...]" [builtins fixtures/dict.pyi] [out] @@ -239,7 +239,7 @@ def f(a, # type: A # type: (...) -> int reveal_type(a) # N: Revealed type is "__main__.A" reveal_type(b) # N: Revealed type is "Union[__main__.B, None]" - reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C]" + reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C, ...]" return "not an int" # E: Incompatible return value type (got "str", expected "int") [builtins fixtures/dict.pyi] [out] diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 02f6b034c512..8f72a82b0760 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -1562,17 +1562,7 @@ __all__ = ('b',) [out] main:2: error: Module "other_module_2" does not explicitly export attribute "a"; implicit reexport disabled -[case testNoImplicitReexportStarConsideredImplicit] -# flags: --no-implicit-reexport -from other_module_2 import a -[file other_module_1.py] -a = 5 -[file other_module_2.py] -from other_module_1 import * -[out] -main:2: error: Module "other_module_2" does not explicitly export attribute "a"; implicit reexport disabled - -[case testNoImplicitReexportStarCanBeReexportedWithAll] +[case testNoImplicitReexportStarConsideredExplicit] # flags: --no-implicit-reexport from other_module_2 import a from other_module_2 import b @@ -1583,8 +1573,6 @@ b = 6 from other_module_1 import * __all__ = ('b',) [builtins fixtures/tuple.pyi] -[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 diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test index 6f69a1fe25bc..30150ca436e8 100644 --- a/test-data/unit/check-functions.test +++ b/test-data/unit/check-functions.test @@ -2230,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 -- ------------------------- @@ -2599,3 +2605,13 @@ def foo() -> None: pass reveal_type(foo()) # N: Revealed type is "None" + +[case testAnyArgument] +def a(b: any): pass # E: Function "builtins.any" is not valid as a type \ + # N: Perhaps you meant "typing.Any" instead of "any"? +[builtins fixtures/any.pyi] + +[case testCallableArgument] +def a(b: callable): pass # E: Function "builtins.callable" is not valid as a type \ + # N: Perhaps you meant "typing.Callable" instead of "callable"? +[builtins fixtures/callable.pyi] diff --git a/test-data/unit/check-generic-alias.test b/test-data/unit/check-generic-alias.test index b6060f3922fe..73efbd223c6c 100644 --- a/test-data/unit/check-generic-alias.test +++ b/test-data/unit/check-generic-alias.test @@ -101,12 +101,12 @@ t11: type[int] reveal_type(t1) # N: Revealed type is "builtins.list[Any]" reveal_type(t2) # N: Revealed type is "builtins.list[builtins.int]" reveal_type(t3) # N: Revealed type is "builtins.list[builtins.str]" -reveal_type(t4) # N: Revealed type is "builtins.tuple[Any]" +reveal_type(t4) # N: Revealed type is "builtins.tuple[Any, ...]" # TODO: ideally these would reveal builtins.tuple reveal_type(t5) # N: Revealed type is "Tuple[builtins.int]" reveal_type(t6) # N: Revealed type is "Tuple[builtins.int, builtins.str]" # TODO: this is incorrect, see #9522 -reveal_type(t7) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(t7) # N: Revealed type is "builtins.tuple[builtins.int, ...]" reveal_type(t8) # N: Revealed type is "builtins.dict[Any, Any]" reveal_type(t9) # N: Revealed type is "builtins.dict[builtins.int, builtins.str]" reveal_type(t10) # N: Revealed type is "builtins.type" @@ -252,13 +252,13 @@ B = tuple[int, str] x: B = (1, 'x') y: B = ('x', 1) # E: Incompatible types in assignment (expression has type "Tuple[str, int]", variable has type "Tuple[int, str]") -reveal_type(tuple[int, ...]()) # N: Revealed type is "builtins.tuple[builtins.int*]" +reveal_type(tuple[int, ...]()) # N: Revealed type is "builtins.tuple[builtins.int*, ...]" [builtins fixtures/tuple.pyi] [case testTypeAliasWithBuiltinTupleInStub] # flags: --python-version 3.6 import m -reveal_type(m.a) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(m.a) # N: Revealed type is "builtins.tuple[builtins.int, ...]" reveal_type(m.b) # N: Revealed type is "Tuple[builtins.int, builtins.str]" [file m.pyi] @@ -273,6 +273,8 @@ b: B import m reveal_type(m.a) # N: Revealed type is "builtins.list[builtins.int]" reveal_type(m.b) # N: Revealed type is "builtins.list[builtins.list[builtins.int]]" +m.C # has complex representation, ignored +reveal_type(m.d) # N: Revealed type is "Type[builtins.str]" [file m.pyi] A = list[int] @@ -281,4 +283,16 @@ B = list[list[int]] b: B class C(list[int]): pass +d: type[str] +[builtins fixtures/list.pyi] + + +[case testTypeAliasWithBuiltinListAliasInStub] +# flags: --python-version 3.6 +import m +reveal_type(m.a()[0]) # N: Revealed type is "builtins.int*" + +[file m.pyi] +List = list +a = List[int] [builtins fixtures/list.pyi] diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index ed0b680e21aa..61f6f6a7836b 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -2073,9 +2073,9 @@ class Base(Generic[T]): return (cls(item),) return cls(item) -reveal_type(Base.make_some) # N: Revealed type is "Overload(def [T] (item: T`1) -> __main__.Base[T`1], def [T] (item: T`1, n: builtins.int) -> builtins.tuple[__main__.Base[T`1]])" +reveal_type(Base.make_some) # N: Revealed type is "Overload(def [T] (item: T`1) -> __main__.Base[T`1], def [T] (item: T`1, n: builtins.int) -> builtins.tuple[__main__.Base[T`1], ...])" reveal_type(Base.make_some(1)) # N: Revealed type is "__main__.Base[builtins.int*]" -reveal_type(Base.make_some(1, 1)) # N: Revealed type is "builtins.tuple[__main__.Base[builtins.int*]]" +reveal_type(Base.make_some(1, 1)) # N: Revealed type is "builtins.tuple[__main__.Base[builtins.int*], ...]" class Sub(Base[str]): ... Sub.make_some(1) # E: No overload variant of "make_some" of "Base" matches argument type "int" \ @@ -2183,7 +2183,7 @@ class C(Generic[T]): class D(C[str]): ... reveal_type(D.get()) # N: Revealed type is "builtins.str*" -reveal_type(D.get(42)) # N: Revealed type is "builtins.tuple[builtins.str*]" +reveal_type(D.get(42)) # N: Revealed type is "builtins.tuple[builtins.str*, ...]" [builtins fixtures/classmethod.pyi] [case testGenericClassMethodAnnotation] diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 1d2262ab303d..1a73f9f33274 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -5610,3 +5610,26 @@ 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 extend enum with existing members: "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 extend enum with existing members: "FinalEnum" +main:5: error: Cannot override final attribute "x" (previously declared in base class "FinalEnum") diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index adf4a7b60420..4de6e4a76f92 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -3210,3 +3210,48 @@ def test(seq: List[Union[Iterable, Any]]) -> None: k = [k] reveal_type(k) # N: Revealed type is "builtins.list[Any]" [builtins fixtures/list.pyi] + +[case testErasedTypeRuntimeCoverage] +# https://github.com/python/mypy/issues/11913 +from typing import TypeVar, Type, Generic, Callable, Iterable + +class DataType: ... + +T1 = TypeVar('T1') +T2 = TypeVar("T2", bound=DataType) + +def map(__func: T1) -> None: ... + +def collection_from_dict_value(model: Type[T2]) -> None: + map(lambda i: i if isinstance(i, model) else i) +[builtins fixtures/isinstancelist.pyi] + +[case testRegression11705_Strict] +# flags: --strict-optional +# See: https://github.com/python/mypy/issues/11705 +from typing import Dict, Optional, NamedTuple +class C(NamedTuple): + x: int + +t: Optional[C] +d: Dict[C, bytes] +x = t and d[t] +reveal_type(x) # N: Revealed type is "Union[None, builtins.bytes*]" +if x: + reveal_type(x) # N: Revealed type is "builtins.bytes*" +[builtins fixtures/dict.pyi] + +[case testRegression11705_NoStrict] +# flags: --no-strict-optional +# See: https://github.com/python/mypy/issues/11705 +from typing import Dict, Optional, NamedTuple +class C(NamedTuple): + x: int + +t: Optional[C] +d: Dict[C, bytes] +x = t and d[t] +reveal_type(x) # N: Revealed type is "builtins.bytes*" +if x: + reveal_type(x) # N: Revealed type is "builtins.bytes*" +[builtins fixtures/dict.pyi] diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test index f531947d1faf..64c1a2aad3cb 100644 --- a/test-data/unit/check-isinstance.test +++ b/test-data/unit/check-isinstance.test @@ -2390,8 +2390,8 @@ class B: def t3(self) -> None: if isinstance(self, (A1, A2)): reveal_type(self) # N: Revealed type is "Union[__main__.2, __main__.]" - x0: Literal[0] = self.f() # E: Incompatible types in assignment (expression has type "Union[Literal[1], Literal[2]]", variable has type "Literal[0]") - x1: Literal[1] = self.f() # E: Incompatible types in assignment (expression has type "Union[Literal[1], Literal[2]]", variable has type "Literal[1]") + x0: Literal[0] = self.f() # E: Incompatible types in assignment (expression has type "Literal[1, 2]", variable has type "Literal[0]") + x1: Literal[1] = self.f() # E: Incompatible types in assignment (expression has type "Literal[1, 2]", variable has type "Literal[1]") [builtins fixtures/isinstance.pyi] diff --git a/test-data/unit/check-kwargs.test b/test-data/unit/check-kwargs.test index 7f0b8af3ba0e..9f8de1265ee7 100644 --- a/test-data/unit/check-kwargs.test +++ b/test-data/unit/check-kwargs.test @@ -350,12 +350,15 @@ class A: pass [builtins fixtures/dict.pyi] [case testInvalidTypeForKeywordVarArg] -from typing import Dict +# flags: --strict-optional +from typing import Dict, Any, Optional def f(**kwargs: 'A') -> None: pass -d = None # type: Dict[A, A] +d = {} # type: Dict[A, A] f(**d) # E: Keywords must be strings f(**A()) # E: Argument after ** must be a mapping, not "A" class A: pass +kwargs: Optional[Any] +f(**kwargs) # E: Argument after ** must be a mapping, not "Optional[Any]" [builtins fixtures/dict.pyi] [case testPassingKeywordVarArgsToNonVarArgsFunction] diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index 37ae12419151..3886d3c39edd 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -846,7 +846,7 @@ def func(x: Literal['foo', 'bar', ' foo ']) -> None: ... func('foo') func('bar') func(' foo ') -func('baz') # E: Argument 1 to "func" has incompatible type "Literal['baz']"; expected "Union[Literal['foo'], Literal['bar'], Literal[' foo ']]" +func('baz') # E: Argument 1 to "func" has incompatible type "Literal['baz']"; expected "Literal['foo', 'bar', ' foo ']" a: Literal['foo'] b: Literal['bar'] @@ -860,7 +860,7 @@ func(b) func(c) func(d) func(e) -func(f) # E: Argument 1 to "func" has incompatible type "Union[Literal['foo'], Literal['bar'], Literal['baz']]"; expected "Union[Literal['foo'], Literal['bar'], Literal[' foo ']]" +func(f) # E: Argument 1 to "func" has incompatible type "Literal['foo', 'bar', 'baz']"; expected "Literal['foo', 'bar', ' foo ']" [builtins fixtures/tuple.pyi] [out] @@ -1129,8 +1129,8 @@ d: int foo(a) foo(b) -foo(c) # E: Argument 1 to "foo" has incompatible type "Union[Literal[4], Literal[5]]"; expected "Union[Literal[1], Literal[2], Literal[3]]" -foo(d) # E: Argument 1 to "foo" has incompatible type "int"; expected "Union[Literal[1], Literal[2], Literal[3]]" +foo(c) # E: Argument 1 to "foo" has incompatible type "Literal[4, 5]"; expected "Literal[1, 2, 3]" +foo(d) # E: Argument 1 to "foo" has incompatible type "int"; expected "Literal[1, 2, 3]" [builtins fixtures/tuple.pyi] [out] @@ -1144,7 +1144,7 @@ c: Literal[4, 'foo'] foo(a) foo(b) -foo(c) # E: Argument 1 to "foo" has incompatible type "Union[Literal[4], Literal['foo']]"; expected "int" +foo(c) # E: Argument 1 to "foo" has incompatible type "Literal[4, 'foo']"; expected "int" [builtins fixtures/tuple.pyi] [out] @@ -1248,19 +1248,19 @@ class Contravariant(Generic[T_contra]): pass a1: Invariant[Literal[1]] a2: Invariant[Literal[1, 2]] a3: Invariant[Literal[1, 2, 3]] -a2 = a1 # E: Incompatible types in assignment (expression has type "Invariant[Literal[1]]", variable has type "Invariant[Union[Literal[1], Literal[2]]]") -a2 = a3 # E: Incompatible types in assignment (expression has type "Invariant[Union[Literal[1], Literal[2], Literal[3]]]", variable has type "Invariant[Union[Literal[1], Literal[2]]]") +a2 = a1 # E: Incompatible types in assignment (expression has type "Invariant[Literal[1]]", variable has type "Invariant[Literal[1, 2]]") +a2 = a3 # E: Incompatible types in assignment (expression has type "Invariant[Literal[1, 2, 3]]", variable has type "Invariant[Literal[1, 2]]") b1: Covariant[Literal[1]] b2: Covariant[Literal[1, 2]] b3: Covariant[Literal[1, 2, 3]] b2 = b1 -b2 = b3 # E: Incompatible types in assignment (expression has type "Covariant[Union[Literal[1], Literal[2], Literal[3]]]", variable has type "Covariant[Union[Literal[1], Literal[2]]]") +b2 = b3 # E: Incompatible types in assignment (expression has type "Covariant[Literal[1, 2, 3]]", variable has type "Covariant[Literal[1, 2]]") c1: Contravariant[Literal[1]] c2: Contravariant[Literal[1, 2]] c3: Contravariant[Literal[1, 2, 3]] -c2 = c1 # E: Incompatible types in assignment (expression has type "Contravariant[Literal[1]]", variable has type "Contravariant[Union[Literal[1], Literal[2]]]") +c2 = c1 # E: Incompatible types in assignment (expression has type "Contravariant[Literal[1]]", variable has type "Contravariant[Literal[1, 2]]") c2 = c3 [builtins fixtures/tuple.pyi] [out] @@ -1275,12 +1275,12 @@ def bar(x: Sequence[Literal[1, 2]]) -> None: pass a: List[Literal[1]] b: List[Literal[1, 2, 3]] -foo(a) # E: Argument 1 to "foo" has incompatible type "List[Literal[1]]"; expected "List[Union[Literal[1], Literal[2]]]" \ +foo(a) # E: Argument 1 to "foo" has incompatible type "List[Literal[1]]"; expected "List[Literal[1, 2]]" \ # N: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance \ # N: Consider using "Sequence" instead, which is covariant -foo(b) # E: Argument 1 to "foo" has incompatible type "List[Union[Literal[1], Literal[2], Literal[3]]]"; expected "List[Union[Literal[1], Literal[2]]]" +foo(b) # E: Argument 1 to "foo" has incompatible type "List[Literal[1, 2, 3]]"; expected "List[Literal[1, 2]]" bar(a) -bar(b) # E: Argument 1 to "bar" has incompatible type "List[Union[Literal[1], Literal[2], Literal[3]]]"; expected "Sequence[Union[Literal[1], Literal[2]]]" +bar(b) # E: Argument 1 to "bar" has incompatible type "List[Literal[1, 2, 3]]"; expected "Sequence[Literal[1, 2]]" [builtins fixtures/list.pyi] [out] @@ -1363,9 +1363,9 @@ x = b # E: Incompatible types in assignment (expression has type "str", variabl y = c # E: Incompatible types in assignment (expression has type "bool", variable has type "Literal[True]") z = d # This is ok: Literal[None] and None are equivalent. -combined = a # E: Incompatible types in assignment (expression has type "int", variable has type "Union[Literal[1], Literal['foo'], Literal[True], None]") -combined = b # E: Incompatible types in assignment (expression has type "str", variable has type "Union[Literal[1], Literal['foo'], Literal[True], None]") -combined = c # E: Incompatible types in assignment (expression has type "bool", variable has type "Union[Literal[1], Literal['foo'], Literal[True], None]") +combined = a # E: Incompatible types in assignment (expression has type "int", variable has type "Optional[Literal[1, 'foo', True]]") +combined = b # E: Incompatible types in assignment (expression has type "str", variable has type "Optional[Literal[1, 'foo', True]]") +combined = c # E: Incompatible types in assignment (expression has type "bool", variable has type "Optional[Literal[1, 'foo', True]]") combined = d # Also ok, for similar reasons. e: Literal[1] = 1 @@ -1392,9 +1392,9 @@ a: Literal[1] = 2 # E: Incompatible types in assignment (expression ha b: Literal["foo"] = "bar" # E: Incompatible types in assignment (expression has type "Literal['bar']", variable has type "Literal['foo']") c: Literal[True] = False # E: Incompatible types in assignment (expression has type "Literal[False]", variable has type "Literal[True]") -d: Literal[1, 2] = 3 # E: Incompatible types in assignment (expression has type "Literal[3]", variable has type "Union[Literal[1], Literal[2]]") -e: Literal["foo", "bar"] = "baz" # E: Incompatible types in assignment (expression has type "Literal['baz']", variable has type "Union[Literal['foo'], Literal['bar']]") -f: Literal[True, 4] = False # E: Incompatible types in assignment (expression has type "Literal[False]", variable has type "Union[Literal[True], Literal[4]]") +d: Literal[1, 2] = 3 # E: Incompatible types in assignment (expression has type "Literal[3]", variable has type "Literal[1, 2]") +e: Literal["foo", "bar"] = "baz" # E: Incompatible types in assignment (expression has type "Literal['baz']", variable has type "Literal['foo', 'bar']") +f: Literal[True, 4] = False # E: Incompatible types in assignment (expression has type "Literal[False]", variable has type "Literal[True, 4]") [builtins fixtures/primitives.pyi] [out] @@ -1504,7 +1504,7 @@ reveal_type(arr3) # N: Revealed type is "builtins.list[builtins.int*]" reveal_type(arr4) # N: Revealed type is "builtins.list[builtins.object*]" reveal_type(arr5) # N: Revealed type is "builtins.list[builtins.object*]" -bad: List[Literal[1, 2]] = [1, 2, 3] # E: List item 2 has incompatible type "Literal[3]"; expected "Union[Literal[1], Literal[2]]" +bad: List[Literal[1, 2]] = [1, 2, 3] # E: List item 2 has incompatible type "Literal[3]"; expected "Literal[1, 2]" [builtins fixtures/list.pyi] [out] @@ -1619,19 +1619,19 @@ reveal_type(func(a)) # N: Revealed type is "Union[__main__.A, __main__.C]" reveal_type(func(b)) # N: Revealed type is "__main__.B" reveal_type(func(c)) # N: Revealed type is "Union[__main__.B, __main__.A]" reveal_type(func(d)) # N: Revealed type is "__main__.B" \ - # E: Argument 1 to "func" has incompatible type "Union[Literal[6], Literal[7]]"; expected "Union[Literal[3], Literal[4], Literal[5], Literal[6]]" + # E: Argument 1 to "func" has incompatible type "Literal[6, 7]"; expected "Literal[3, 4, 5, 6]" reveal_type(func(e)) # E: No overload variant of "func" matches argument type "int" \ # N: Possible overload variants: \ # N: def func(x: Literal[-40]) -> A \ - # N: def func(x: Union[Literal[3], Literal[4], Literal[5], Literal[6]]) -> B \ + # N: def func(x: Literal[3, 4, 5, 6]) -> B \ # N: def func(x: Literal['foo']) -> C \ # N: Revealed type is "Any" -reveal_type(func(f)) # E: No overload variant of "func" matches argument type "Union[Literal[7], Literal['bar']]" \ +reveal_type(func(f)) # E: No overload variant of "func" matches argument type "Literal[7, 'bar']" \ # N: Possible overload variants: \ # N: def func(x: Literal[-40]) -> A \ - # N: def func(x: Union[Literal[3], Literal[4], Literal[5], Literal[6]]) -> B \ + # N: def func(x: Literal[3, 4, 5, 6]) -> B \ # N: def func(x: Literal['foo']) -> C \ # N: Revealed type is "Any" [builtins fixtures/tuple.pyi] @@ -1657,7 +1657,7 @@ reveal_type(f(1)) # N: Revealed type is "builtins.int" reveal_type(f(2)) # N: Revealed type is "builtins.int" reveal_type(f(y)) # N: Revealed type is "builtins.object" reveal_type(f(z)) # N: Revealed type is "builtins.int" \ - # E: Argument 1 to "f" has incompatible type "Union[Literal[1], Literal[2], Literal['three']]"; expected "Union[Literal[1], Literal[2]]" + # E: Argument 1 to "f" has incompatible type "Literal[1, 2, 'three']"; expected "Literal[1, 2]" [builtins fixtures/tuple.pyi] [out] @@ -1726,8 +1726,8 @@ def f(x): x: Literal['a', 'b'] y: Literal['a', 'b'] -f(x, y) # E: Argument 1 to "f" has incompatible type "Union[Literal['a'], Literal['b']]"; expected "Literal['a']" \ - # E: Argument 2 to "f" has incompatible type "Union[Literal['a'], Literal['b']]"; expected "Literal['a']" \ +f(x, y) # E: Argument 1 to "f" has incompatible type "Literal['a', 'b']"; expected "Literal['a']" \ + # E: Argument 2 to "f" has incompatible type "Literal['a', 'b']"; expected "Literal['a']" \ [builtins fixtures/tuple.pyi] [out] diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 071fcf54f2b6..6c32c088255d 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -131,9 +131,10 @@ def f() -> None: pass [case testImportWithinClassBody2] import typing class C: - from m import f + from m import f # E: Unsupported class scoped import f() - f(C) # E: Too many arguments for "f" + # ideally, the following should error: + f(C) [file m.py] def f() -> None: pass [out] @@ -1910,6 +1911,24 @@ class C: [builtins fixtures/module.pyi] +[case testReExportChildStubs3] +from util import mod +reveal_type(mod) # N: Revealed type is "def () -> package.mod.mod" + +from util import internal_detail # E: Module "util" has no attribute "internal_detail" + +[file package/__init__.pyi] +from .mod import mod as mod + +[file package/mod.pyi] +class mod: ... + +[file util.pyi] +from package import mod as mod +# stubs require explicit re-export +from package import mod as internal_detail +[builtins fixtures/module.pyi] + [case testNoReExportChildStubs] import mod from mod import C, D # E: Module "mod" has no attribute "C" diff --git a/test-data/unit/check-namedtuple.test b/test-data/unit/check-namedtuple.test index 440884333c69..b95cc96f8115 100644 --- a/test-data/unit/check-namedtuple.test +++ b/test-data/unit/check-namedtuple.test @@ -673,7 +673,7 @@ Node = NamedTuple('Node', [ ('children', Tuple['Node', ...]), # E: Cannot resolve name "Node" (possible cyclic definition) ]) n: Node -reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.tuple[Any], fallback=__main__.Node]" +reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.tuple[Any, ...], fallback=__main__.Node]" [builtins fixtures/tuple.pyi] [case testSelfRefNT2] @@ -689,7 +689,7 @@ class B(NamedTuple): y: int n: A -reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.tuple[Any], fallback=__main__.A]" +reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.tuple[Any, ...], fallback=__main__.A]" [builtins fixtures/tuple.pyi] [case testSelfRefNT3] @@ -1081,3 +1081,42 @@ t: T y: List[T] = [t] [builtins fixtures/tuple.pyi] [typing fixtures/typing-namedtuple.pyi] + +[case testNamedTupleWithBoolNarrowsToBool] +# flags: --warn-unreachable +from typing import NamedTuple + +class C(NamedTuple): + x: int + + def __bool__(self) -> bool: + pass + +def foo(c: C) -> None: + if c: + reveal_type(c) # N: Revealed type is "Tuple[builtins.int, fallback=__main__.C]" + else: + reveal_type(c) # N: Revealed type is "Tuple[builtins.int, fallback=__main__.C]" + +def bar(c: C) -> None: + if not c: + reveal_type(c) # N: Revealed type is "Tuple[builtins.int, fallback=__main__.C]" + else: + reveal_type(c) # N: Revealed type is "Tuple[builtins.int, fallback=__main__.C]" + +class C1(NamedTuple): + x: int + +def foo1(c: C1) -> None: + if c: + reveal_type(c) # N: Revealed type is "Tuple[builtins.int, fallback=__main__.C1]" + else: + c # E: Statement is unreachable + +def bar1(c: C1) -> None: + if not c: + c # E: Statement is unreachable + else: + reveal_type(c) # N: Revealed type is "Tuple[builtins.int, fallback=__main__.C1]" +[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 d6b25ef456d9..23715b24d43e 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test @@ -894,7 +894,7 @@ else: reveal_type(y) # N: Revealed type is "__main__.Custom" # No contamination here -if 1 == x == z: # E: Non-overlapping equality check (left operand type: "Union[Literal[1], Literal[2], None]", right operand type: "Default") +if 1 == x == z: # E: Non-overlapping equality check (left operand type: "Optional[Literal[1, 2]]", right operand type: "Default") reveal_type(x) # E: Statement is unreachable reveal_type(z) else: @@ -1227,7 +1227,7 @@ def unreachable(x: Union[str, List[str]]) -> None: elif isinstance(x, list): reveal_type(x) # N: Revealed type is "builtins.list[builtins.str]" else: - reveal_type(x) # N: Revealed type is "" + reveal_type(x) # No output: this branch is unreachable def all_parts_covered(x: Union[str, List[str], List[int], int]) -> None: if isinstance(x, str): diff --git a/test-data/unit/check-newsemanal.test b/test-data/unit/check-newsemanal.test index 8a039ad278f3..3b4b0303691a 100644 --- a/test-data/unit/check-newsemanal.test +++ b/test-data/unit/check-newsemanal.test @@ -2722,7 +2722,7 @@ import m [file m.py] class C: - from mm import f + from mm import f # E: Unsupported class scoped import @dec(f) def m(self): pass @@ -2742,7 +2742,7 @@ import m [file m/__init__.py] class C: - from m.m import f + from m.m import f # E: Unsupported class scoped import @dec(f) def m(self): pass diff --git a/test-data/unit/check-overloading.test b/test-data/unit/check-overloading.test index d903c895c45c..591741f3e4e8 100644 --- a/test-data/unit/check-overloading.test +++ b/test-data/unit/check-overloading.test @@ -2589,12 +2589,12 @@ def f(*args): pass i: int reveal_type(f(i)) # N: Revealed type is "Tuple[builtins.int]" reveal_type(f(i, i)) # N: Revealed type is "Tuple[builtins.int, builtins.int]" -reveal_type(f(i, i, i)) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(f(i, i, i)) # N: Revealed type is "builtins.tuple[builtins.int, ...]" -reveal_type(f(*[])) # N: Revealed type is "builtins.tuple[builtins.int]" -reveal_type(f(*[i])) # N: Revealed type is "builtins.tuple[builtins.int]" -reveal_type(f(*[i, i])) # N: Revealed type is "builtins.tuple[builtins.int]" -reveal_type(f(*[i, i, i])) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(f(*[])) # N: Revealed type is "builtins.tuple[builtins.int, ...]" +reveal_type(f(*[i])) # N: Revealed type is "builtins.tuple[builtins.int, ...]" +reveal_type(f(*[i, i])) # N: Revealed type is "builtins.tuple[builtins.int, ...]" +reveal_type(f(*[i, i, i])) # N: Revealed type is "builtins.tuple[builtins.int, ...]" [builtins fixtures/list.pyi] [case testOverloadVarargsSelectionWithTuples] @@ -2608,10 +2608,10 @@ def f(*xs: int) -> Tuple[int, ...]: ... def f(*args): pass i: int -reveal_type(f(*())) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(f(*())) # N: Revealed type is "builtins.tuple[builtins.int, ...]" reveal_type(f(*(i,))) # N: Revealed type is "Tuple[builtins.int]" reveal_type(f(*(i, i))) # N: Revealed type is "Tuple[builtins.int, builtins.int]" -reveal_type(f(*(i, i, i))) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(f(*(i, i, i))) # N: Revealed type is "builtins.tuple[builtins.int, ...]" [builtins fixtures/tuple.pyi] [case testOverloadVarargsSelectionWithNamedTuples] @@ -2631,7 +2631,7 @@ b: B c: C reveal_type(f(*a)) # N: Revealed type is "Tuple[builtins.int, builtins.int]" reveal_type(f(*b)) # N: Revealed type is "Tuple[builtins.int, builtins.int]" -reveal_type(f(*c)) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(f(*c)) # N: Revealed type is "builtins.tuple[builtins.int, ...]" [builtins fixtures/tuple.pyi] [case testOverloadKwargsSelectionWithDict] @@ -2645,10 +2645,10 @@ def f(**xs: int) -> Tuple[int, ...]: ... def f(**kwargs): pass empty: Dict[str, int] -reveal_type(f(**empty)) # N: Revealed type is "builtins.tuple[builtins.int]" -reveal_type(f(**{'x': 4})) # N: Revealed type is "builtins.tuple[builtins.int]" -reveal_type(f(**{'x': 4, 'y': 4})) # N: Revealed type is "builtins.tuple[builtins.int]" -reveal_type(f(**{'a': 4, 'b': 4, 'c': 4})) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(f(**empty)) # N: Revealed type is "builtins.tuple[builtins.int, ...]" +reveal_type(f(**{'x': 4})) # N: Revealed type is "builtins.tuple[builtins.int, ...]" +reveal_type(f(**{'x': 4, 'y': 4})) # N: Revealed type is "builtins.tuple[builtins.int, ...]" +reveal_type(f(**{'a': 4, 'b': 4, 'c': 4})) # N: Revealed type is "builtins.tuple[builtins.int, ...]" [builtins fixtures/dict.pyi] [case testOverloadKwargsSelectionWithTypedDict] @@ -2672,7 +2672,7 @@ c: C reveal_type(f(**a)) # N: Revealed type is "Tuple[builtins.int]" reveal_type(f(**b)) # N: Revealed type is "Tuple[builtins.int, builtins.int]" -reveal_type(f(**c)) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(f(**c)) # N: Revealed type is "builtins.tuple[builtins.int, ...]" [builtins fixtures/dict.pyi] [case testOverloadVarargsAndKwargsSelection] @@ -5421,3 +5421,931 @@ def f_f(arg: str) -> None: ... @Bad2() # E: "Bad2" not callable def f_f(arg): ... [builtins fixtures/dict.pyi] + + +[case testOverloadIfBasic] +# flags: --always-true True --always-false False +from typing import overload + +class A: ... +class B: ... +class C: ... +class D: ... + +# ----- +# Test basic overload merging +# ----- + +@overload +def f1(g: A) -> A: ... +if True: + @overload + def f1(g: B) -> B: ... +def f1(g): ... +reveal_type(f1(A())) # N: Revealed type is "__main__.A" +reveal_type(f1(B())) # N: Revealed type is "__main__.B" + +@overload +def f2(g: A) -> A: ... +@overload +def f2(g: B) -> B: ... +if False: + @overload + def f2(g: C) -> C: ... +def f2(g): ... +reveal_type(f2(A())) # N: Revealed type is "__main__.A" +reveal_type(f2(C())) # E: No overload variant of "f2" matches argument type "C" \ + # N: Possible overload variants: \ + # N: def f2(g: A) -> A \ + # N: def f2(g: B) -> B \ + # N: Revealed type is "Any" + +@overload +def f3(g: A) -> A: ... +@overload +def f3(g: B) -> B: ... +if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \ + # E: Name "maybe_true" is not defined + @overload + def f3(g: C) -> C: ... +def f3(g): ... +reveal_type(f3(A())) # N: Revealed type is "__main__.A" +reveal_type(f3(C())) # E: No overload variant of "f3" matches argument type "C" \ + # N: Possible overload variants: \ + # N: def f3(g: A) -> A \ + # N: def f3(g: B) -> B \ + # N: Revealed type is "Any" + +if True: + @overload + def f4(g: A) -> A: ... +if True: + @overload + def f4(g: B) -> B: ... +@overload +def f4(g: C) -> C: ... +def f4(g): ... +reveal_type(f4(A())) # N: Revealed type is "__main__.A" +reveal_type(f4(B())) # N: Revealed type is "__main__.B" +reveal_type(f4(C())) # N: Revealed type is "__main__.C" + +if True: + @overload + def f5(g: A) -> A: ... +@overload +def f5(g: B) -> B: ... +if True: + @overload + def f5(g: C) -> C: ... +@overload +def f5(g: D) -> D: ... +def f5(g): ... +reveal_type(f5(A())) # N: Revealed type is "__main__.A" +reveal_type(f5(B())) # N: Revealed type is "__main__.B" +reveal_type(f5(C())) # N: Revealed type is "__main__.C" +reveal_type(f5(D())) # N: Revealed type is "__main__.D" + +[case testOverloadIfSysVersion] +# flags: --python-version 3.9 +from typing import overload +import sys + +class A: ... +class B: ... +class C: ... + +# ----- +# "Real" world example +# Test overload merging for sys.version_info +# ----- + +@overload +def f1(g: A) -> A: ... +if sys.version_info >= (3, 9): + @overload + def f1(g: B) -> B: ... +def f1(g): ... +reveal_type(f1(A())) # N: Revealed type is "__main__.A" +reveal_type(f1(B())) # N: Revealed type is "__main__.B" + +@overload +def f2(g: A) -> A: ... +@overload +def f2(g: B) -> B: ... +if sys.version_info >= (3, 10): + @overload + def f2(g: C) -> C: ... +def f2(g): ... +reveal_type(f2(A())) # N: Revealed type is "__main__.A" +reveal_type(f2(C())) # E: No overload variant of "f2" matches argument type "C" \ + # N: Possible overload variants: \ + # N: def f2(g: A) -> A \ + # N: def f2(g: B) -> B \ + # N: Revealed type is "Any" +[builtins fixtures/ops.pyi] + +[case testOverloadIfMerging] +# flags: --always-true True +from typing import overload + +class A: ... +class B: ... +class C: ... + +# ----- +# Test overload merging +# ----- + +@overload +def f1(g: A) -> A: ... +if True: + # Some comment + @overload + def f1(g: B) -> B: ... +def f1(g): ... +reveal_type(f1(A())) # N: Revealed type is "__main__.A" +reveal_type(f1(B())) # N: Revealed type is "__main__.B" + +@overload +def f2(g: A) -> A: ... +if True: + @overload + def f2(g: bytes) -> B: ... + @overload + def f2(g: B) -> C: ... +def f2(g): ... +reveal_type(f2(A())) # N: Revealed type is "__main__.A" +reveal_type(f2(B())) # N: Revealed type is "__main__.C" + +@overload +def f3(g: A) -> A: ... +@overload +def f3(g: B) -> B: ... +if True: + def f3(g): ... +reveal_type(f3(A())) # N: Revealed type is "__main__.A" +reveal_type(f3(B())) # N: Revealed type is "__main__.B" + +if True: + @overload + def f4(g: A) -> A: ... +@overload +def f4(g: B) -> B: ... +def f4(g): ... +reveal_type(f4(A())) # N: Revealed type is "__main__.A" +reveal_type(f4(B())) # N: Revealed type is "__main__.B" + +if True: + # Some comment + @overload + def f5(g: A) -> A: ... + @overload + def f5(g: B) -> B: ... +def f5(g): ... +reveal_type(f5(A())) # N: Revealed type is "__main__.A" +reveal_type(f5(B())) # N: Revealed type is "__main__.B" + +[case testOverloadIfNotMerging] +# flags: --always-true True +from typing import overload + +class A: ... +class B: ... +class C: ... + +# ----- +# Don't merge if IfStmt contains nodes other than overloads +# ----- + +@overload # E: An overloaded function outside a stub file must have an implementation +def f1(g: A) -> A: ... +@overload +def f1(g: B) -> B: ... +if True: + @overload # E: Name "f1" already defined on line 12 \ + # E: Single overload definition, multiple required + def f1(g: C) -> C: ... + pass # Some other action +def f1(g): ... # E: Name "f1" already defined on line 12 +reveal_type(f1(A())) # N: Revealed type is "__main__.A" +reveal_type(f1(C())) # E: No overload variant of "f1" matches argument type "C" \ + # N: Possible overload variants: \ + # N: def f1(g: A) -> A \ + # N: def f1(g: B) -> B \ + # N: Revealed type is "Any" + +if True: + pass # Some other action + @overload # E: Single overload definition, multiple required + def f2(g: A) -> A: ... +@overload # E: Name "f2" already defined on line 26 +def f2(g: B) -> B: ... +@overload +def f2(g: C) -> C: ... +def f2(g): ... +reveal_type(f2(A())) # N: Revealed type is "__main__.A" +reveal_type(f2(C())) # N: Revealed type is "__main__.A" \ + # E: Argument 1 to "f2" has incompatible type "C"; expected "A" + +[case testOverloadIfOldStyle] +# flags: --always-false var_false --always-true var_true +from typing import overload + +class A: ... +class B: ... + +# ----- +# Test old style to make sure it still works +# ----- + +var_true = True +var_false = False + +if var_false: + @overload + def f1(g: A) -> A: ... + @overload + def f1(g: B) -> B: ... + def f1(g): ... +elif var_true: + @overload + def f1(g: A) -> A: ... + @overload + def f1(g: B) -> B: ... + def f1(g): ... +else: + @overload + def f1(g: A) -> A: ... + @overload + def f1(g: B) -> B: ... + def f1(g): ... +reveal_type(f1(A())) # N: Revealed type is "__main__.A" +reveal_type(f1(B())) # N: Revealed type is "__main__.B" + +[case testOverloadIfElse] +# flags: --always-true True --always-false False +from typing import overload + +class A: ... +class B: ... +class C: ... +class D: ... + +# ----- +# Match the first always-true block +# ----- + +@overload +def f1(x: A) -> A: ... +if True: + @overload + def f1(x: B) -> B: ... +elif False: + @overload + def f1(x: C) -> C: ... +else: + @overload + def f1(x: D) -> D: ... +def f1(x): ... +reveal_type(f1(A())) # N: Revealed type is "__main__.A" +reveal_type(f1(B())) # N: Revealed type is "__main__.B" +reveal_type(f1(C())) # E: No overload variant of "f1" matches argument type "C" \ + # N: Possible overload variants: \ + # N: def f1(x: A) -> A \ + # N: def f1(x: B) -> B \ + # N: Revealed type is "Any" + +@overload +def f2(x: A) -> A: ... +if False: + @overload + def f2(x: B) -> B: ... +elif True: + @overload + def f2(x: C) -> C: ... +else: + @overload + def f2(x: D) -> D: ... +def f2(x): ... +reveal_type(f2(A())) # N: Revealed type is "__main__.A" +reveal_type(f2(B())) # E: No overload variant of "f2" matches argument type "B" \ + # N: Possible overload variants: \ + # N: def f2(x: A) -> A \ + # N: def f2(x: C) -> C \ + # N: Revealed type is "Any" +reveal_type(f2(C())) # N: Revealed type is "__main__.C" + +@overload +def f3(x: A) -> A: ... +if False: + @overload + def f3(x: B) -> B: ... +elif False: + @overload + def f3(x: C) -> C: ... +else: + @overload + def f3(x: D) -> D: ... +def f3(x): ... +reveal_type(f3(A())) # N: Revealed type is "__main__.A" +reveal_type(f3(C())) # E: No overload variant of "f3" matches argument type "C" \ + # N: Possible overload variants: \ + # N: def f3(x: A) -> A \ + # N: def f3(x: D) -> D \ + # N: Revealed type is "Any" +reveal_type(f3(D())) # N: Revealed type is "__main__.D" + +[case testOverloadIfElse2] +# flags: --always-true True +from typing import overload + +class A: ... +class B: ... +class C: ... +class D: ... + +# ----- +# Match the first always-true block +# Don't merge overloads if can't be certain about execution of block +# ----- + +@overload +def f1(x: A) -> A: ... +if True: + @overload + def f1(x: B) -> B: ... +else: + @overload + def f1(x: D) -> D: ... +def f1(x): ... +reveal_type(f1(A())) # N: Revealed type is "__main__.A" +reveal_type(f1(B())) # N: Revealed type is "__main__.B" +reveal_type(f1(D())) # E: No overload variant of "f1" matches argument type "D" \ + # N: Possible overload variants: \ + # N: def f1(x: A) -> A \ + # N: def f1(x: B) -> B \ + # N: Revealed type is "Any" + +@overload +def f2(x: A) -> A: ... +if True: + @overload + def f2(x: B) -> B: ... +elif maybe_true: + @overload + def f2(x: C) -> C: ... +else: + @overload + def f2(x: D) -> D: ... +def f2(x): ... +reveal_type(f2(A())) # N: Revealed type is "__main__.A" +reveal_type(f2(B())) # N: Revealed type is "__main__.B" +reveal_type(f2(C())) # E: No overload variant of "f2" matches argument type "C" \ + # N: Possible overload variants: \ + # N: def f2(x: A) -> A \ + # N: def f2(x: B) -> B \ + # N: Revealed type is "Any" + +@overload # E: Single overload definition, multiple required +def f3(x: A) -> A: ... +if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \ + # E: Name "maybe_true" is not defined + @overload + def f3(x: B) -> B: ... +elif True: + @overload + def f3(x: C) -> C: ... +else: + @overload + def f3(x: D) -> D: ... +def f3(x): ... +reveal_type(f3(A())) # N: Revealed type is "__main__.A" +reveal_type(f3(B())) # E: No overload variant of "f3" matches argument type "B" \ + # N: Possible overload variant: \ + # N: def f3(x: A) -> A \ + # N: Revealed type is "Any" + +@overload # E: Single overload definition, multiple required +def f4(x: A) -> A: ... +if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \ + # E: Name "maybe_true" is not defined + @overload + def f4(x: B) -> B: ... +else: + @overload + def f4(x: D) -> D: ... +def f4(x): ... +reveal_type(f4(A())) # N: Revealed type is "__main__.A" +reveal_type(f4(B())) # E: No overload variant of "f4" matches argument type "B" \ + # N: Possible overload variant: \ + # N: def f4(x: A) -> A \ + # N: Revealed type is "Any" + +[case testOverloadIfElse3] +# flags: --always-false False +from typing import overload + +class A: ... +class B: ... +class C: ... +class D: ... +class E: ... + +# ----- +# Match the first always-true block +# Don't merge overloads if can't be certain about execution of block +# ----- + +@overload +def f1(x: A) -> A: ... +if False: + @overload + def f1(x: B) -> B: ... +else: + @overload + def f1(x: D) -> D: ... +def f1(x): ... +reveal_type(f1(A())) # N: Revealed type is "__main__.A" +reveal_type(f1(B())) # E: No overload variant of "f1" matches argument type "B" \ + # N: Possible overload variants: \ + # N: def f1(x: A) -> A \ + # N: def f1(x: D) -> D \ + # N: Revealed type is "Any" +reveal_type(f1(D())) # N: Revealed type is "__main__.D" + +@overload # E: Single overload definition, multiple required +def f2(x: A) -> A: ... +if False: + @overload + def f2(x: B) -> B: ... +elif maybe_true: # E: Condition cannot be inferred, unable to merge overloads \ + # E: Name "maybe_true" is not defined + @overload + def f2(x: C) -> C: ... +else: + @overload + def f2(x: D) -> D: ... +def f2(x): ... +reveal_type(f2(A())) # N: Revealed type is "__main__.A" +reveal_type(f2(C())) # E: No overload variant of "f2" matches argument type "C" \ + # N: Possible overload variant: \ + # N: def f2(x: A) -> A \ + # N: Revealed type is "Any" + +@overload # E: Single overload definition, multiple required +def f3(x: A) -> A: ... +if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \ + # E: Name "maybe_true" is not defined + @overload + def f3(x: B) -> B: ... +elif False: + @overload + def f3(x: C) -> C: ... +else: + @overload + def f3(x: D) -> D: ... +def f3(x): ... +reveal_type(f3(A())) # N: Revealed type is "__main__.A" +reveal_type(f3(B())) # E: No overload variant of "f3" matches argument type "B" \ + # N: Possible overload variant: \ + # N: def f3(x: A) -> A \ + # N: Revealed type is "Any" + +def g(bool_var: bool) -> None: + @overload + def f4(x: A) -> A: ... + if bool_var: # E: Condition cannot be inferred, unable to merge overloads + @overload + def f4(x: B) -> B: ... + elif maybe_true: # E: Name "maybe_true" is not defined + # No 'Condition cannot be inferred' error here since it's already + # emitted on the first condition, 'bool_var', above. + @overload + def f4(x: C) -> C: ... + else: + @overload + def f4(x: D) -> D: ... + @overload + def f4(x: E) -> E: ... + def f4(x): ... + reveal_type(f4(E())) # N: Revealed type is "__main__.E" + reveal_type(f4(B())) # E: No overload variant of "f4" matches argument type "B" \ + # N: Possible overload variants: \ + # N: def f4(x: A) -> A \ + # N: def f4(x: E) -> E \ + # N: Revealed type is "Any" + +[case testOverloadIfSkipUnknownExecution] +# flags: --always-true True +from typing import overload + +class A: ... +class B: ... +class C: ... +class D: ... + +# ----- +# If blocks should be skipped if execution can't be certain +# Overload name must match outer name +# ----- + +@overload # E: Single overload definition, multiple required +def f1(x: A) -> A: ... +if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \ + # E: Name "maybe_true" is not defined + @overload + def f1(x: B) -> B: ... +def f1(x): ... +reveal_type(f1(A())) # N: Revealed type is "__main__.A" + +if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \ + # E: Name "maybe_true" is not defined + @overload + def f2(x: A) -> A: ... +@overload +def f2(x: B) -> B: ... +@overload +def f2(x: C) -> C: ... +def f2(x): ... +reveal_type(f2(A())) # E: No overload variant of "f2" matches argument type "A" \ + # N: Possible overload variants: \ + # N: def f2(x: B) -> B \ + # N: def f2(x: C) -> C \ + # N: Revealed type is "Any" + +if True: + @overload # E: Single overload definition, multiple required + def f3(x: A) -> A: ... + if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \ + # E: Name "maybe_true" is not defined + @overload + def f3(x: B) -> B: ... + def f3(x): ... +reveal_type(f3(A())) # N: Revealed type is "__main__.A" + +if True: + if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \ + # E: Name "maybe_true" is not defined + @overload + def f4(x: A) -> A: ... + @overload + def f4(x: B) -> B: ... + @overload + def f4(x: C) -> C: ... + def f4(x): ... +reveal_type(f4(A())) # E: No overload variant of "f4" matches argument type "A" \ + # N: Possible overload variants: \ + # N: def f4(x: B) -> B \ + # N: def f4(x: C) -> C \ + # N: Revealed type is "Any" + +[case testOverloadIfDontSkipUnrelatedOverload] +# flags: --always-true True +from typing import overload + +class A: ... +class B: ... +class C: ... +class D: ... + +# ----- +# Don't skip if block if overload name doesn't match outer name +# ----- + +@overload # E: Single overload definition, multiple required +def f1(x: A) -> A: ... +if maybe_true: # E: Name "maybe_true" is not defined + @overload # E: Single overload definition, multiple required + def g1(x: B) -> B: ... +def f1(x): ... # E: Name "f1" already defined on line 13 +reveal_type(f1(A())) # N: Revealed type is "__main__.A" + +if maybe_true: # E: Name "maybe_true" is not defined + @overload # E: Single overload definition, multiple required + def g2(x: A) -> A: ... +@overload +def f2(x: B) -> B: ... +@overload +def f2(x: C) -> C: ... +def f2(x): ... +reveal_type(f2(A())) # E: No overload variant of "f2" matches argument type "A" \ + # N: Possible overload variants: \ + # N: def f2(x: B) -> B \ + # N: def f2(x: C) -> C \ + # N: Revealed type is "Any" + +if True: + @overload # E: Single overload definition, multiple required + def f3(x: A) -> A: ... + if maybe_true: # E: Name "maybe_true" is not defined + @overload # E: Single overload definition, multiple required + def g3(x: B) -> B: ... + def f3(x): ... +reveal_type(f3(A())) # N: Revealed type is "__main__.A" + +if True: + if maybe_true: # E: Name "maybe_true" is not defined + @overload # E: Single overload definition, multiple required + def g4(x: A) -> A: ... + @overload + def f4(x: B) -> B: ... + @overload + def f4(x: C) -> C: ... + def f4(x): ... +reveal_type(f4(A())) # E: No overload variant of "f4" matches argument type "A" \ + # N: Possible overload variants: \ + # N: def f4(x: B) -> B \ + # N: def f4(x: C) -> C \ + # N: Revealed type is "Any" + +[case testOverloadIfNotMergingDifferentNames] +# flags: --always-true True +from typing import overload + +class A: ... +class B: ... +class C: ... +class D: ... + +# ----- +# Don't merge overloads if IfStmts contains overload with different name +# ----- + +@overload # E: An overloaded function outside a stub file must have an implementation +def f1(x: A) -> A: ... +@overload +def f1(x: B) -> B: ... +if True: + @overload # E: Single overload definition, multiple required + def g1(x: C) -> C: ... +def f1(x): ... # E: Name "f1" already defined on line 13 +reveal_type(f1(A())) # N: Revealed type is "__main__.A" +reveal_type(f1(C())) # E: No overload variant of "f1" matches argument type "C" \ + # N: Possible overload variants: \ + # N: def f1(x: A) -> A \ + # N: def f1(x: B) -> B \ + # N: Revealed type is "Any" + +if True: + @overload # E: Single overload definition, multiple required + def g2(x: A) -> A: ... +@overload +def f2(x: B) -> B: ... +@overload +def f2(x: C) -> C: ... +def f2(x): ... +reveal_type(f2(A())) # E: No overload variant of "f2" matches argument type "A" \ + # N: Possible overload variants: \ + # N: def f2(x: B) -> B \ + # N: def f2(x: C) -> C \ + # N: Revealed type is "Any" +reveal_type(f2(B())) # N: Revealed type is "__main__.B" + +if True: + if True: + @overload # E: Single overload definition, multiple required + def g3(x: A) -> A: ... + @overload + def f3(x: B) -> B: ... + @overload + def f3(x: C) -> C: ... + def f3(x): ... +reveal_type(f3(A())) # E: No overload variant of "f3" matches argument type "A" \ + # N: Possible overload variants: \ + # N: def f3(x: B) -> B \ + # N: def f3(x: C) -> C \ + # N: Revealed type is "Any" +reveal_type(f3(B())) # N: Revealed type is "__main__.B" + +[case testOverloadIfSplitFunctionDef] +# flags: --always-true True --always-false False +from typing import overload + +class A: ... +class B: ... +class C: ... +class D: ... + +# ----- +# Test split FuncDefs +# ----- + +@overload +def f1(x: A) -> A: ... +@overload +def f1(x: B) -> B: ... +if True: + def f1(x): ... +reveal_type(f1(A())) # N: Revealed type is "__main__.A" + +@overload +def f2(x: A) -> A: ... +@overload +def f2(x: B) -> B: ... +if False: + def f2(x): ... +else: + def f2(x): ... +reveal_type(f2(A())) # N: Revealed type is "__main__.A" + +@overload # E: An overloaded function outside a stub file must have an implementation +def f3(x: A) -> A: ... +@overload +def f3(x: B) -> B: ... +if True: + def f3(x): ... # E: Name "f3" already defined on line 31 +else: + pass # some other node + def f3(x): ... +reveal_type(f3(A())) # N: Revealed type is "__main__.A" + +[case testOverloadIfMixed] +# flags: --always-true True --always-false False +from typing import overload, TYPE_CHECKING + +class A: ... +class B: ... +class C: ... +class D: ... + +if maybe_var: # E: Name "maybe_var" is not defined + pass +if True: + @overload + def f1(x: A) -> A: ... +@overload +def f1(x: B) -> B: ... +def f1(x): ... +reveal_type(f1(A())) # N: Revealed type is "__main__.A" +reveal_type(f1(B())) # N: Revealed type is "__main__.B" + +if True: + @overload + def f2(x: A) -> A: ... + @overload + def f2(x: B) -> B: ... +def f2(x): ... +reveal_type(f2(A())) # N: Revealed type is "__main__.A" +reveal_type(f2(B())) # N: Revealed type is "__main__.B" + +if True: + @overload + def f3(x: A) -> A: ... + @overload + def f3(x: B) -> B: ... + def f3(x): ... +reveal_type(f3(A())) # N: Revealed type is "__main__.A" +reveal_type(f3(B())) # N: Revealed type is "__main__.B" + +# Don't crash with AssignmentStmt if elif +@overload # E: Single overload definition, multiple required +def f4(x: A) -> A: ... +if False: + @overload + def f4(x: B) -> B: ... +elif True: + var = 1 +def f4(x): ... # E: Name "f4" already defined on line 39 + +if TYPE_CHECKING: + @overload + def f5(x: A) -> A: ... + @overload + def f5(x: B) -> B: ... +def f5(x): ... +reveal_type(f5(A())) # N: Revealed type is "__main__.A" +reveal_type(f5(B())) # N: Revealed type is "__main__.B" + +# Test from check-functions - testUnconditionalRedefinitionOfConditionalFunction +# Don't merge If blocks if they appear before any overloads +# and don't contain any overloads themselves. +if maybe_true: # E: Name "maybe_true" is not defined + def f6(x): ... +def f6(x): ... # E: Name "f6" already defined on line 61 + +if maybe_true: # E: Name "maybe_true" is not defined + pass # Some other node + def f7(x): ... +def f7(x): ... # E: Name "f7" already defined on line 66 + +@overload +def f8(x: A) -> A: ... +@overload +def f8(x: B) -> B: ... +if False: + def f8(x: C) -> C: ... +def f8(x): ... +reveal_type(f8(A())) # N: Revealed type is "__main__.A" +reveal_type(f8(C())) # E: No overload variant of "f8" matches argument type "C" \ + # N: Possible overload variants: \ + # N: def f8(x: A) -> A \ + # N: def f8(x: B) -> B \ + # N: Revealed type is "Any" + +if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \ + # E: Name "maybe_true" is not defined + @overload + def f9(x: A) -> A: ... +if another_maybe_true: # E: Condition cannot be inferred, unable to merge overloads \ + # E: Name "another_maybe_true" is not defined + @overload + def f9(x: B) -> B: ... +@overload +def f9(x: C) -> C: ... +@overload +def f9(x: D) -> D: ... +def f9(x): ... +reveal_type(f9(A())) # E: No overload variant of "f9" matches argument type "A" \ + # N: Possible overload variants: \ + # N: def f9(x: C) -> C \ + # N: def f9(x: D) -> D \ + # N: Revealed type is "Any" +reveal_type(f9(C())) # N: Revealed type is "__main__.C" + +if True: + if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \ + # E: Name "maybe_true" is not defined + @overload + def f10(x: A) -> A: ... + if another_maybe_true: # E: Condition cannot be inferred, unable to merge overloads \ + # E: Name "another_maybe_true" is not defined + @overload + def f10(x: B) -> B: ... + @overload + def f10(x: C) -> C: ... + @overload + def f10(x: D) -> D: ... + def f10(x): ... +reveal_type(f10(A())) # E: No overload variant of "f10" matches argument type "A" \ + # N: Possible overload variants: \ + # N: def f10(x: C) -> C \ + # N: def f10(x: D) -> D \ + # N: Revealed type is "Any" +reveal_type(f10(C())) # N: Revealed type is "__main__.C" + +if some_var: # E: Name "some_var" is not defined + pass +@overload +def f11(x: A) -> A: ... +@overload +def f11(x: B) -> B: ... +def f11(x): ... +reveal_type(f11(A())) # N: Revealed type is "__main__.A" + +if True: + if some_var: # E: Name "some_var" is not defined + pass + @overload + def f12(x: A) -> A: ... + @overload + def f12(x: B) -> B: ... + def f12(x): ... +reveal_type(f12(A())) # N: Revealed type is "__main__.A" +[typing fixtures/typing-medium.pyi] + +[case testOverloadIfUnconditionalFuncDef] +# flags: --always-true True --always-false False +from typing import overload + +class A: ... +class B: ... + +# ----- +# Don't merge conditional FuncDef after unconditional one +# ----- + +@overload +def f1(x: A) -> A: ... +@overload +def f1(x: B) -> B: ... +def f1(x): ... + +@overload +def f2(x: A) -> A: ... +if True: + @overload + def f2(x: B) -> B: ... +def f2(x): ... +if True: + def f2(x): ... # E: Name "f2" already defined on line 17 + +[case testOverloadItemHasMoreGeneralReturnType] +from typing import overload + +@overload +def f() -> object: ... + +@overload +def f(x: int) -> object: ... + +def f(x: int = 0) -> int: + return x + +@overload +def g() -> object: ... + +@overload +def g(x: int) -> str: ... + +def g(x: int = 0) -> int: # E: Overloaded function implementation cannot produce return type of signature 2 + return x diff --git a/test-data/unit/check-parameter-specification.test b/test-data/unit/check-parameter-specification.test index f6123915aada..f2281babb193 100644 --- a/test-data/unit/check-parameter-specification.test +++ b/test-data/unit/check-parameter-specification.test @@ -3,6 +3,16 @@ from typing_extensions import ParamSpec P = ParamSpec('P') [builtins fixtures/tuple.pyi] +[case testInvalidParamSpecDefinitions] +from typing import ParamSpec + +P1 = ParamSpec("P1", covariant=True) # E: Only the first argument to ParamSpec has defined semantics +P2 = ParamSpec("P2", contravariant=True) # E: Only the first argument to ParamSpec has defined semantics +P3 = ParamSpec("P3", bound=int) # E: Only the first argument to ParamSpec has defined semantics +P4 = ParamSpec("P4", int, str) # E: Only the first argument to ParamSpec has defined semantics +P5 = ParamSpec("P5", covariant=True, bound=int) # E: Only the first argument to ParamSpec has defined semantics +[builtins fixtures/tuple.pyi] + [case testParamSpecLocations] from typing import Callable, List from typing_extensions import ParamSpec, Concatenate diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index 6768263e9832..65fb30a3547f 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -2382,7 +2382,7 @@ y: PBad = None # E: Incompatible types in assignment (expression has type "None [out] [case testOnlyMethodProtocolUsableWithIsSubclass] -from typing import Protocol, runtime_checkable, Union, Type +from typing import Protocol, runtime_checkable, Union, Type, Sequence, overload @runtime_checkable class P(Protocol): def meth(self) -> int: @@ -2404,6 +2404,17 @@ if issubclass(cls, P): reveal_type(cls) # N: Revealed type is "Type[__main__.C]" else: reveal_type(cls) # N: Revealed type is "Type[__main__.E]" + +@runtime_checkable +class POverload(Protocol): + @overload + def meth(self, a: int) -> float: ... + @overload + def meth(self, a: str) -> Sequence[float]: ... + def meth(self, a): + pass + +reveal_type(issubclass(int, POverload)) # N: Revealed type is "builtins.bool" [builtins fixtures/isinstance.pyi] [typing fixtures/typing-full.pyi] [out] @@ -2795,3 +2806,107 @@ class MyClass: assert isinstance(self, MyProtocol) [builtins fixtures/isinstance.pyi] [typing fixtures/typing-full.pyi] + +[case testProtocolAndTypeVariableSpecialCase] +from typing import TypeVar, Iterable, Optional, Callable, Protocol + +T_co = TypeVar('T_co', covariant=True) + +class SupportsNext(Protocol[T_co]): + def __next__(self) -> T_co: ... + +N = TypeVar("N", bound=SupportsNext, covariant=True) + +class SupportsIter(Protocol[T_co]): + def __iter__(self) -> T_co: ... + +def f(i: SupportsIter[N]) -> N: ... + +I = TypeVar('I', bound=Iterable) + +def g(x: I, y: Iterable) -> None: + f(x) + f(y) + +[case testMatchProtocolAgainstOverloadWithAmbiguity] +from typing import TypeVar, Protocol, Union, Generic, overload + +T = TypeVar("T", covariant=True) + +class slice: pass + +class GetItem(Protocol[T]): + def __getitem__(self, k: int) -> T: ... + +class Str: # Resembles 'str' + def __getitem__(self, k: Union[int, slice]) -> Str: ... + +class Lst(Generic[T]): # Resembles 'list' + def __init__(self, x: T): ... + @overload + def __getitem__(self, k: int) -> T: ... + @overload + def __getitem__(self, k: slice) -> Lst[T]: ... + def __getitem__(self, k): pass + +def f(x: GetItem[GetItem[Str]]) -> None: ... + +a: Lst[Str] +f(Lst(a)) + +class Lst2(Generic[T]): + def __init__(self, x: T): ... + # The overload items are tweaked but still compatible + @overload + def __getitem__(self, k: Str) -> None: ... + @overload + def __getitem__(self, k: slice) -> Lst2[T]: ... + @overload + def __getitem__(self, k: Union[int, str]) -> T: ... + def __getitem__(self, k): pass + +b: Lst2[Str] +f(Lst2(b)) + +class Lst3(Generic[T]): # Resembles 'list' + def __init__(self, x: T): ... + # The overload items are no longer compatible (too narrow argument type) + @overload + def __getitem__(self, k: slice) -> Lst3[T]: ... + @overload + def __getitem__(self, k: bool) -> T: ... + def __getitem__(self, k): pass + +c: Lst3[Str] +f(Lst3(c)) # E: Argument 1 to "f" has incompatible type "Lst3[Lst3[Str]]"; expected "GetItem[GetItem[Str]]" \ +# N: Following member(s) of "Lst3[Lst3[Str]]" have conflicts: \ +# N: Expected: \ +# N: def __getitem__(self, int) -> GetItem[Str] \ +# N: Got: \ +# N: @overload \ +# N: def __getitem__(self, slice) -> Lst3[Lst3[Str]] \ +# N: @overload \ +# N: def __getitem__(self, bool) -> Lst3[Str] + +[builtins fixtures/list.pyi] +[typing fixtures/typing-full.pyi] + +[case testMatchProtocolAgainstOverloadWithMultipleMatchingItems] +from typing import Protocol, overload, TypeVar, Any + +_T_co = TypeVar("_T_co", covariant=True) +_T = TypeVar("_T") + +class SupportsRound(Protocol[_T_co]): + @overload + def __round__(self) -> int: ... + @overload + def __round__(self, __ndigits: int) -> _T_co: ... + +class C: + # This matches both overload items of SupportsRound + def __round__(self, __ndigits: int = ...) -> int: ... + +def round(number: SupportsRound[_T], ndigits: int) -> _T: ... + +round(C(), 1) diff --git a/test-data/unit/check-python2.test b/test-data/unit/check-python2.test index d658fe013401..0481767abd63 100644 --- a/test-data/unit/check-python2.test +++ b/test-data/unit/check-python2.test @@ -68,18 +68,89 @@ A.f(1) A.f('') # E: Argument 1 to "f" of "A" has incompatible type "str"; expected "int" [builtins_py2 fixtures/staticmethod.pyi] -[case testRaiseTuple] -import typing -raise BaseException, "a" -raise BaseException, "a", None -[builtins_py2 fixtures/exception.pyi] - [case testRaiseTupleTypeFail] import typing x = None # type: typing.Type[typing.Tuple[typing.Any, typing.Any, typing.Any]] raise x # E: Exception must be derived from BaseException [builtins_py2 fixtures/exception.pyi] +[case testRaiseTupleOfThreeOnPython2] +from types import TracebackType +from typing import Optional, Tuple, Type + +e = None # type: Optional[TracebackType] + +# Correct raising several items: + +raise BaseException +raise BaseException(1) +raise (BaseException,) +raise (BaseException(1),) +raise BaseException, 1 +raise BaseException, 1, e +raise BaseException, 1, None + +raise Exception +raise Exception(1) +raise Exception() +raise Exception(1), None +raise Exception(), None +raise Exception(1), None, None +raise Exception(1), None, e +raise (Exception,) +raise (Exception(1),) +raise Exception, 1 +raise Exception, 1, e +raise Exception, 1, None + +# Errors: + +raise int, 1 # E: Argument 1 must be "Type[builtins.BaseException]" subtype +raise int, None # E: Argument 1 must be "Union[builtins.BaseException, Type[builtins.BaseException]]" subtype +raise Exception(1), 1 # E: Argument 1 must be "Type[builtins.BaseException]" subtype +raise Exception(1), 1, None # E: Argument 1 must be "Type[builtins.BaseException]" subtype +raise Exception, 1, 1 # E: Argument 3 must be "Union[types.TracebackType, None]" subtype +raise int, 1, 1 # E: Argument 1 must be "Type[builtins.BaseException]" subtype \ + # E: Argument 3 must be "Union[types.TracebackType, None]" subtype + +# Correct raising tuple: + +t1 = (BaseException,) +t2 = (Exception(1), 2, 3, 4) # type: Tuple[Exception, int, int, int] +t3 = (Exception,) # type: Tuple[Type[Exception], ...] +t4 = (Exception(1),) # type: Tuple[Exception, ...] + +raise t1 +raise t2 +raise t3 +raise t4 + +# Errors: + +raise t1, 1, None # E: Argument 1 must be "Type[builtins.BaseException]" subtype +raise t2, 1 # E: Argument 1 must be "Type[builtins.BaseException]" subtype +raise t3, 1, e # E: Argument 1 must be "Type[builtins.BaseException]" subtype +raise t4, 1, 1 # E: Argument 1 must be "Type[builtins.BaseException]" subtype \ + # E: Argument 3 must be "Union[types.TracebackType, None]" subtype + +w1 = () +w2 = (1, Exception) +w3 = (1,) # type: Tuple[int, ...] + +raise w1 # E: Exception must be derived from BaseException +raise w2 # E: When raising a tuple, first element must by derived from BaseException +raise w3 # E: When raising a tuple, first element must by derived from BaseException + +# Bare raise: + +try: + pass +except Exception: + raise # ok +[builtins_py2 fixtures/exception.pyi] +[file types.pyi] +class TracebackType: pass + [case testTryExceptWithTuple] try: None diff --git a/test-data/unit/check-python310.test b/test-data/unit/check-python310.test index 3bcac61855b4..6046b7ec7333 100644 --- a/test-data/unit/check-python310.test +++ b/test-data/unit/check-python310.test @@ -1,7 +1,1578 @@ -[case testMatchStatementNotSupported] -# flags: --python-version 3.10 -match str(): # E: Match statement is not supported - case 'x': - 1 + '' +-- Capture Pattern -- + +[case testMatchCapturePatternType] +class A: ... +m: A + +match m: + case a: + reveal_type(a) # N: Revealed type is "__main__.A" + +-- Literal Pattern -- + +[case testMatchLiteralPatternNarrows] +m: object + +match m: + case 1: + reveal_type(m) # N: Revealed type is "Literal[1]" + +[case testMatchLiteralPatternAlreadyNarrower-skip] +m: bool + +match m: + case 1: + reveal_type(m) # This should probably be unreachable, but isn't detected as such. +[builtins fixtures/primitives.pyi] + +[case testMatchLiteralPatternUnreachable] +# primitives are needed because otherwise mypy doesn't see that int and str are incompatible +m: int + +match m: + case "str": + reveal_type(m) +[builtins fixtures/primitives.pyi] + +-- Value Pattern -- + +[case testMatchValuePatternNarrows] +import b +m: object + +match m: + case b.b: + reveal_type(m) # N: Revealed type is "builtins.int" +[file b.py] +b: int + +[case testMatchValuePatternAlreadyNarrower] +import b +m: bool + +match m: + case b.b: + reveal_type(m) # N: Revealed type is "builtins.bool" +[file b.py] +b: int + +[case testMatchValuePatternIntersect] +import b + +class A: ... +m: A + +match m: + case b.b: + reveal_type(m) # N: Revealed type is "__main__.1" +[file b.py] +class B: ... +b: B + +[case testMatchValuePatternUnreachable] +# primitives are needed because otherwise mypy doesn't see that int and str are incompatible +import b + +m: int + +match m: + case b.b: + reveal_type(m) +[file b.py] +b: str +[builtins fixtures/primitives.pyi] + +-- Sequence Pattern -- + +[case testMatchSequencePatternCaptures] +from typing import List +m: List[int] + +match m: + case [a]: + reveal_type(a) # N: Revealed type is "builtins.int*" +[builtins fixtures/list.pyi] + +[case testMatchSequencePatternCapturesStarred] +from typing import Sequence +m: Sequence[int] + +match m: + case [a, *b]: + reveal_type(a) # N: Revealed type is "builtins.int*" + reveal_type(b) # N: Revealed type is "builtins.list[builtins.int*]" +[builtins fixtures/list.pyi] + +[case testMatchSequencePatternNarrowsInner] +from typing import Sequence +m: Sequence[object] + +match m: + case [1, True]: + reveal_type(m) # N: Revealed type is "typing.Sequence[builtins.int]" + +[case testMatchSequencePatternNarrowsOuter] +from typing import Sequence +m: object + +match m: + case [1, True]: + reveal_type(m) # N: Revealed type is "typing.Sequence[builtins.int]" + +[case testMatchSequencePatternAlreadyNarrowerInner] +from typing import Sequence +m: Sequence[bool] + +match m: + case [1, True]: + reveal_type(m) # N: Revealed type is "typing.Sequence[builtins.bool]" + +[case testMatchSequencePatternAlreadyNarrowerOuter] +from typing import Sequence +m: Sequence[object] + +match m: + case [1, True]: + reveal_type(m) # N: Revealed type is "typing.Sequence[builtins.int]" + +[case testMatchSequencePatternAlreadyNarrowerBoth] +from typing import Sequence +m: Sequence[bool] + +match m: + case [1, True]: + reveal_type(m) # N: Revealed type is "typing.Sequence[builtins.bool]" + +[case testMatchNestedSequencePatternNarrowsInner] +from typing import Sequence +m: Sequence[Sequence[object]] + +match m: + case [[1], [True]]: + reveal_type(m) # N: Revealed type is "typing.Sequence[typing.Sequence[builtins.int]]" + +[case testMatchNestedSequencePatternNarrowsOuter] +from typing import Sequence +m: object + +match m: + case [[1], [True]]: + reveal_type(m) # N: Revealed type is "typing.Sequence[typing.Sequence[builtins.int]]" + +[case testMatchSequencePatternDoesntNarrowInvariant] +from typing import List +m: List[object] + +match m: + case [1]: + reveal_type(m) # N: Revealed type is "builtins.list[builtins.object]" +[builtins fixtures/list.pyi] + +[case testMatchSequencePatternMatches] +import array, collections +from typing import Sequence, Iterable + +m1: object +m2: Sequence[int] +m3: array.array[int] +m4: collections.deque[int] +m5: list[int] +m6: memoryview +m7: range +m8: tuple[int] + +m9: str +m10: bytes +m11: bytearray + +match m1: + case [a]: + reveal_type(a) # N: Revealed type is "builtins.object" + +match m2: + case [b]: + reveal_type(b) # N: Revealed type is "builtins.int*" + +match m3: + case [c]: + reveal_type(c) # N: Revealed type is "builtins.int*" + +match m4: + case [d]: + reveal_type(d) # N: Revealed type is "builtins.int*" + +match m5: + case [e]: + reveal_type(e) # N: Revealed type is "builtins.int*" + +match m6: + case [f]: + reveal_type(f) # N: Revealed type is "builtins.int*" + +match m7: + case [g]: + reveal_type(g) # N: Revealed type is "builtins.int*" + +match m8: + case [h]: + reveal_type(h) # N: Revealed type is "builtins.int" + +match m9: + case [i]: + reveal_type(i) + +match m10: + case [j]: + reveal_type(j) + +match m11: + case [k]: + reveal_type(k) +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-full.pyi] + +[case testMatchSequencePatternCapturesTuple] +from typing import Tuple +m: Tuple[int, str, bool] + +match m: + case [a, b, c]: + reveal_type(a) # N: Revealed type is "builtins.int" + reveal_type(b) # N: Revealed type is "builtins.str" + reveal_type(c) # N: Revealed type is "builtins.bool" + reveal_type(m) # N: Revealed type is "Tuple[builtins.int, builtins.str, builtins.bool]" +[builtins fixtures/list.pyi] + +[case testMatchSequencePatternTupleTooLong] +from typing import Tuple +m: Tuple[int, str] + +match m: + case [a, b, c]: + reveal_type(a) + reveal_type(b) + reveal_type(c) +[builtins fixtures/list.pyi] + +[case testMatchSequencePatternTupleTooShort] +from typing import Tuple +m: Tuple[int, str, bool] + +match m: + case [a, b]: + reveal_type(a) + reveal_type(b) +[builtins fixtures/list.pyi] + +[case testMatchSequencePatternTupleNarrows] +from typing import Tuple +m: Tuple[object, object] + +match m: + case [1, "str"]: + reveal_type(m) # N: Revealed type is "Tuple[Literal[1], Literal['str']]" +[builtins fixtures/list.pyi] + +[case testMatchSequencePatternTupleStarred] +from typing import Tuple +m: Tuple[int, str, bool] + +match m: + case [a, *b, c]: + reveal_type(a) # N: Revealed type is "builtins.int" + reveal_type(b) # N: Revealed type is "builtins.list[builtins.str]" + reveal_type(c) # N: Revealed type is "builtins.bool" + reveal_type(m) # N: Revealed type is "Tuple[builtins.int, builtins.str, builtins.bool]" +[builtins fixtures/list.pyi] + +[case testMatchSequencePatternTupleStarredUnion] +from typing import Tuple +m: Tuple[int, str, float, bool] + +match m: + case [a, *b, c]: + reveal_type(a) # N: Revealed type is "builtins.int" + reveal_type(b) # N: Revealed type is "builtins.list[Union[builtins.str, builtins.float]]" + reveal_type(c) # N: Revealed type is "builtins.bool" + reveal_type(m) # N: Revealed type is "Tuple[builtins.int, builtins.str, builtins.float, builtins.bool]" +[builtins fixtures/list.pyi] + +[case testMatchSequencePatternTupleStarredTooShort] +from typing import Tuple +m: Tuple[int] +reveal_type(m) # N: Revealed type is "Tuple[builtins.int]" + +match m: + case [a, *b, c]: + reveal_type(a) + reveal_type(b) + reveal_type(c) +[builtins fixtures/list.pyi] + +[case testMatchNonMatchingSequencePattern] +from typing import List + +x: List[int] +match x: + case [str()]: + pass + +[case testMatchSequenceUnion-skip] +from typing import List, Union +m: Union[List[List[str]], str] + +match m: + case [list(['str'])]: + reveal_type(m) # N: Revealed type is "builtins.list[builtins.list[builtins.str]]" +[builtins fixtures/list.pyi] + +-- Mapping Pattern -- + +[case testMatchMappingPatternCaptures] +from typing import Dict +import b +m: Dict[str, int] + +match m: + case {"key": v}: + reveal_type(v) # N: Revealed type is "builtins.int*" + case {b.b: v2}: + reveal_type(v2) # N: Revealed type is "builtins.int*" +[file b.py] +b: str +[builtins fixtures/dict.pyi] + +[case testMatchMappingPatternCapturesWrongKeyType] +# This is not actually unreachable, as a subclass of dict could accept keys with different types +from typing import Dict +import b +m: Dict[str, int] + +match m: + case {1: v}: + reveal_type(v) # N: Revealed type is "builtins.int*" + case {b.b: v2}: + reveal_type(v2) # N: Revealed type is "builtins.int*" +[file b.py] +b: int +[builtins fixtures/dict.pyi] + +[case testMatchMappingPatternCapturesTypedDict] +from typing import TypedDict + +class A(TypedDict): + a: str + b: int + +m: A + +match m: + case {"a": v}: + reveal_type(v) # N: Revealed type is "builtins.str" + case {"b": v2}: + reveal_type(v2) # N: Revealed type is "builtins.int" + case {"a": v3, "b": v4}: + reveal_type(v3) # N: Revealed type is "builtins.str" + reveal_type(v4) # N: Revealed type is "builtins.int" + case {"o": v5}: + reveal_type(v5) # N: Revealed type is "builtins.object*" +[typing fixtures/typing-typeddict.pyi] + +[case testMatchMappingPatternCapturesTypedDictWithLiteral] +from typing import TypedDict +import b + +class A(TypedDict): + a: str + b: int + +m: A + +match m: + case {b.a: v}: + reveal_type(v) # N: Revealed type is "builtins.str" + case {b.b: v2}: + reveal_type(v2) # N: Revealed type is "builtins.int" + case {b.a: v3, b.b: v4}: + reveal_type(v3) # N: Revealed type is "builtins.str" + reveal_type(v4) # N: Revealed type is "builtins.int" + case {b.o: v5}: + reveal_type(v5) # N: Revealed type is "builtins.object*" +[file b.py] +from typing import Final, Literal +a: Final = "a" +b: Literal["b"] = "b" +o: Final[str] = "o" +[typing fixtures/typing-typeddict.pyi] + +[case testMatchMappingPatternCapturesTypedDictWithNonLiteral] +from typing import TypedDict +import b + +class A(TypedDict): + a: str + b: int + +m: A + +match m: + case {b.a: v}: + reveal_type(v) # N: Revealed type is "builtins.object*" +[file b.py] +from typing import Final, Literal +a: str +[typing fixtures/typing-typeddict.pyi] + +[case testMatchMappingPatternCapturesTypedDictUnreachable] +# TypedDict keys are always str, so this is actually unreachable +from typing import TypedDict +import b + +class A(TypedDict): + a: str + b: int + +m: A + +match m: + case {1: v}: + reveal_type(v) + case {b.b: v2}: + reveal_type(v2) +[file b.py] +b: int +[typing fixtures/typing-typeddict.pyi] + +[case testMatchMappingPatternCaptureRest] +m: object + +match m: + case {'k': 1, **r}: + reveal_type(r) # N: Revealed type is "builtins.dict[builtins.object, builtins.object]" +[builtins fixtures/dict.pyi] + +[case testMatchMappingPatternCaptureRestFromMapping] +from typing import Mapping + +m: Mapping[str, int] + +match m: + case {'k': 1, **r}: + reveal_type(r) # N: Revealed type is "builtins.dict[builtins.str*, builtins.int*]" +[builtins fixtures/dict.pyi] + +-- Mapping patterns currently do not narrow -- + +-- Class Pattern -- + +[case testMatchClassPatternCapturePositional] +from typing import Final + +class A: + __match_args__: Final = ("a", "b") + a: str + b: int + +m: A + +match m: + case A(i, j): + reveal_type(i) # N: Revealed type is "builtins.str" + reveal_type(j) # N: Revealed type is "builtins.int" +[builtins fixtures/tuple.pyi] + +[case testMatchClassPatternMemberClassCapturePositional] +import b + +m: b.A + +match m: + case b.A(i, j): + reveal_type(i) # N: Revealed type is "builtins.str" + reveal_type(j) # N: Revealed type is "builtins.int" +[file b.py] +from typing import Final + +class A: + __match_args__: Final = ("a", "b") + a: str + b: int +[builtins fixtures/tuple.pyi] + +[case testMatchClassPatternCaptureKeyword] +class A: + a: str + b: int + +m: A + +match m: + case A(a=i, b=j): + reveal_type(i) # N: Revealed type is "builtins.str" + reveal_type(j) # N: Revealed type is "builtins.int" + +[case testMatchClassPatternCaptureSelf] +m: object + +match m: + case bool(a): + reveal_type(a) # N: Revealed type is "builtins.bool" + case bytearray(b): + reveal_type(b) # N: Revealed type is "builtins.bytearray" + case bytes(c): + reveal_type(c) # N: Revealed type is "builtins.bytes" + case dict(d): + reveal_type(d) # N: Revealed type is "builtins.dict[Any, Any]" + case float(e): + reveal_type(e) # N: Revealed type is "builtins.float" + case frozenset(f): + reveal_type(f) # N: Revealed type is "builtins.frozenset[Any]" + case int(g): + reveal_type(g) # N: Revealed type is "builtins.int" + case list(h): + reveal_type(h) # N: Revealed type is "builtins.list[Any]" + case set(i): + reveal_type(i) # N: Revealed type is "builtins.set[Any]" + case str(j): + reveal_type(j) # N: Revealed type is "builtins.str" + case tuple(k): + reveal_type(k) # N: Revealed type is "builtins.tuple[Any, ...]" +[builtins fixtures/primitives.pyi] + +[case testMatchClassPatternNarrowSelfCapture] +m: object + +match m: + case bool(): + reveal_type(m) # N: Revealed type is "builtins.bool" + case bytearray(): + reveal_type(m) # N: Revealed type is "builtins.bytearray" + case bytes(): + reveal_type(m) # N: Revealed type is "builtins.bytes" + case dict(): + reveal_type(m) # N: Revealed type is "builtins.dict[Any, Any]" + case float(): + reveal_type(m) # N: Revealed type is "builtins.float" + case frozenset(): + reveal_type(m) # N: Revealed type is "builtins.frozenset[Any]" + case int(): + reveal_type(m) # N: Revealed type is "builtins.int" + case list(): + reveal_type(m) # N: Revealed type is "builtins.list[Any]" + case set(): + reveal_type(m) # N: Revealed type is "builtins.set[Any]" + case str(): + reveal_type(m) # N: Revealed type is "builtins.str" + case tuple(): + reveal_type(m) # N: Revealed type is "builtins.tuple[Any, ...]" +[builtins fixtures/primitives.pyi] + +[case testMatchInvalidClassPattern] +m: object + +match m: + case xyz(y): # E: Name "xyz" is not defined + reveal_type(m) # N: Revealed type is "Any" + reveal_type(y) # E: Cannot determine type of "y" \ + # N: Revealed type is "Any" + +match m: + case xyz(z=x): # E: Name "xyz" is not defined + reveal_type(x) # E: Cannot determine type of "x" \ + # N: Revealed type is "Any" + +[case testMatchClassPatternCaptureDataclass] +from dataclasses import dataclass + +@dataclass +class A: + a: str + b: int + +m: A + +match m: + case A(i, j): + reveal_type(i) # N: Revealed type is "builtins.str" + reveal_type(j) # N: Revealed type is "builtins.int" +[builtins fixtures/dataclasses.pyi] + +[case testMatchClassPatternCaptureDataclassNoMatchArgs] +from dataclasses import dataclass + +@dataclass(match_args=False) +class A: + a: str + b: int + +m: A + +match m: + case A(i, j): # E: Class "__main__.A" doesn't define "__match_args__" + pass +[builtins fixtures/dataclasses.pyi] + +[case testMatchClassPatternCaptureDataclassPartialMatchArgs] +from dataclasses import dataclass, field + +@dataclass +class A: + a: str + b: int = field(init=False) + +m: A + +match m: + case A(i, j): # E: Too many positional patterns for class pattern + pass + case A(k): + reveal_type(k) # N: Revealed type is "builtins.str" +[builtins fixtures/dataclasses.pyi] + +[case testMatchClassPatternCaptureNamedTupleInline] +from collections import namedtuple + +A = namedtuple("A", ["a", "b"]) + +m: A + +match m: + case A(i, j): + reveal_type(i) # N: Revealed type is "Any" + reveal_type(j) # N: Revealed type is "Any" +[builtins fixtures/list.pyi] + +[case testMatchClassPatternCaptureNamedTupleInlineTyped] +from typing import NamedTuple + +A = NamedTuple("A", [("a", str), ("b", int)]) + +m: A + +match m: + case A(i, j): + reveal_type(i) # N: Revealed type is "builtins.str" + reveal_type(j) # N: Revealed type is "builtins.int" +[builtins fixtures/list.pyi] + +[case testMatchClassPatternCaptureNamedTupleClass] +from typing import NamedTuple + +class A(NamedTuple): + a: str + b: int + +m: A + +match m: + case A(i, j): + reveal_type(i) # N: Revealed type is "builtins.str" + reveal_type(j) # N: Revealed type is "builtins.int" +[builtins fixtures/tuple.pyi] + +[case testMatchClassPatternCaptureGeneric] +from typing import Generic, TypeVar + +T = TypeVar('T') + +class A(Generic[T]): + a: T + +m: object + +match m: + case A(a=i): + reveal_type(m) # N: Revealed type is "__main__.A[Any]" + reveal_type(i) # N: Revealed type is "Any" + +[case testMatchClassPatternCaptureGenericAlreadyKnown] +from typing import Generic, TypeVar + +T = TypeVar('T') + +class A(Generic[T]): + a: T + +m: A[int] + +match m: + case A(a=i): + reveal_type(m) # N: Revealed type is "__main__.A[builtins.int]" + reveal_type(i) # N: Revealed type is "builtins.int*" + +[case testMatchClassPatternCaptureFilledGenericTypeAlias] +from typing import Generic, TypeVar + +T = TypeVar('T') + +class A(Generic[T]): + a: T + +B = A[int] + +m: object + +match m: + case B(a=i): # E: Class pattern class must not be a type alias with type parameters + reveal_type(i) + +[case testMatchClassPatternCaptureGenericTypeAlias] +from typing import Generic, TypeVar + +T = TypeVar('T') + +class A(Generic[T]): + a: T + +B = A + +m: object + +match m: + case B(a=i): + pass + +[case testMatchClassPatternNarrows] +from typing import Final + +class A: + __match_args__: Final = ("a", "b") + a: str + b: int + +m: object + +match m: + case A(): + reveal_type(m) # N: Revealed type is "__main__.A" + case A(i, j): + reveal_type(m) # N: Revealed type is "__main__.A" +[builtins fixtures/tuple.pyi] + +[case testMatchClassPatternNarrowsUnion] +from typing import Final, Union + +class A: + __match_args__: Final = ("a", "b") + a: str + b: int + +class B: + __match_args__: Final = ("a", "b") + a: int + b: str + +m: Union[A, B] + +match m: + case A(): + reveal_type(m) # N: Revealed type is "__main__.A" + +match m: + case A(i, j): + reveal_type(m) # N: Revealed type is "__main__.A" + reveal_type(i) # N: Revealed type is "builtins.str" + reveal_type(j) # N: Revealed type is "builtins.int" + +match m: + case B(): + reveal_type(m) # N: Revealed type is "__main__.B" + +match m: + case B(k, l): + reveal_type(m) # N: Revealed type is "__main__.B" + reveal_type(k) # N: Revealed type is "builtins.int" + reveal_type(l) # N: Revealed type is "builtins.str" +[builtins fixtures/tuple.pyi] + +[case testMatchClassPatternAlreadyNarrower] +from typing import Final + +class A: + __match_args__: Final = ("a", "b") + a: str + b: int +class B(A): ... + +m: B + +match m: + case A(): + reveal_type(m) # N: Revealed type is "__main__.B" + +match m: + case A(i, j): + reveal_type(m) # N: Revealed type is "__main__.B" +[builtins fixtures/tuple.pyi] + +[case testMatchClassPatternIntersection] +from typing import Final + +class A: + __match_args__: Final = ("a", "b") + a: str + b: int +class B: ... + +m: B + +match m: + case A(): + reveal_type(m) # N: Revealed type is "__main__.2" + case A(i, j): + reveal_type(m) # N: Revealed type is "__main__.3" +[builtins fixtures/tuple.pyi] + +[case testMatchClassPatternNonexistentKeyword] +class A: ... + +m: object + +match m: + case A(a=j): # E: Class "__main__.A" has no attribute "a" + reveal_type(m) # N: Revealed type is "__main__.A" + reveal_type(j) # N: Revealed type is "Any" + +[case testMatchClassPatternDuplicateKeyword] +class A: + a: str + +m: object + +match m: + case A(a=i, a=j): # E: Duplicate keyword pattern "a" + pass + +[case testMatchClassPatternDuplicateImplicitKeyword] +from typing import Final + +class A: + __match_args__: Final = ("a",) + a: str + +m: object + +match m: + case A(i, a=j): # E: Keyword "a" already matches a positional pattern + pass +[builtins fixtures/tuple.pyi] + +[case testMatchClassPatternTooManyPositionals] +from typing import Final + +class A: + __match_args__: Final = ("a", "b") + a: str + b: int + +m: object + +match m: + case A(i, j, k): # E: Too many positional patterns for class pattern + pass +[builtins fixtures/tuple.pyi] + +[case testMatchClassPatternIsNotType] +a = 1 +m: object + +match m: + case a(i, j): # E: Expected type in class pattern; found "builtins.int" + reveal_type(i) + reveal_type(j) + +[case testMatchClassPatternNestedGenerics] +# From cpython test_patma.py +x = [[{0: 0}]] +match x: + case list([({-0-0j: int(real=0+0j, imag=0-0j) | (1) as z},)]): + y = 0 + +reveal_type(x) # N: Revealed type is "builtins.list[builtins.list*[builtins.dict*[builtins.int*, builtins.int*]]]" +reveal_type(y) # N: Revealed type is "builtins.int" +reveal_type(z) # N: Revealed type is "builtins.int*" +[builtins fixtures/dict.pyi] + +[case testMatchNonFinalMatchArgs] +class A: + __match_args__ = ("a", "b") + a: str + b: int + +m: object + +match m: + case A(i, j): + reveal_type(i) # N: Revealed type is "builtins.str" + reveal_type(j) # N: Revealed type is "builtins.int" +[builtins fixtures/tuple.pyi] + +[case testMatchAnyTupleMatchArgs] +from typing import Tuple, Any + +class A: + __match_args__: Tuple[Any, ...] + a: str + b: int + +m: object + +match m: + case A(i, j, k): + reveal_type(i) # N: Revealed type is "Any" + reveal_type(j) # N: Revealed type is "Any" + reveal_type(k) # N: Revealed type is "Any" +[builtins fixtures/tuple.pyi] + +[case testMatchNonLiteralMatchArgs] +from typing import Final + +b: str = "b" +class A: + __match_args__: Final = ("a", b) # N: __match_args__ must be a tuple containing string literals for checking of match statements to work + a: str + b: int + +m: object + +match m: + case A(i, j, k): # E: Too many positional patterns for class pattern + pass + case A(i, j): + reveal_type(i) # N: Revealed type is "builtins.str" + reveal_type(j) # N: Revealed type is "Any" +[builtins fixtures/tuple.pyi] + +[case testMatchExternalMatchArgs] +from typing import Final, Literal + +args: Final = ("a", "b") +class A: + __match_args__: Final = args + a: str + b: int + +arg: Final = "a" +arg2: Literal["b"] = "b" +class B: + __match_args__: Final = (arg, arg2) + a: str + b: int + +[builtins fixtures/tuple.pyi] +[typing fixtures/typing-medium.pyi] + +-- As Pattern -- + +[case testMatchAsPattern] +m: int + +match m: + case x as l: + reveal_type(x) # N: Revealed type is "builtins.int" + reveal_type(l) # N: Revealed type is "builtins.int" + +[case testMatchAsPatternNarrows] +m: object + +match m: + case int() as l: + reveal_type(l) # N: Revealed type is "builtins.int" + +[case testMatchAsPatternCapturesOr] +m: object + +match m: + case 1 | 2 as n: + reveal_type(n) # N: Revealed type is "Union[Literal[1], Literal[2]]" + +[case testMatchAsPatternAlreadyNarrower] +m: bool + +match m: + case int() as l: + reveal_type(l) # N: Revealed type is "builtins.bool" + +-- Or Pattern -- + +[case testMatchOrPatternNarrows] +m: object + +match m: + case 1 | 2: + reveal_type(m) # N: Revealed type is "Union[Literal[1], Literal[2]]" + +[case testMatchOrPatternNarrowsStr] +m: object + +match m: + case "foo" | "bar": + reveal_type(m) # N: Revealed type is "Union[Literal['foo'], Literal['bar']]" + +[case testMatchOrPatternNarrowsUnion] +m: object + +match m: + case 1 | "foo": + reveal_type(m) # N: Revealed type is "Union[Literal[1], Literal['foo']]" + +[case testMatchOrPatterCapturesMissing] +from typing import List +m: List[int] + +match m: + case [x, y] | list(x): # E: Alternative patterns bind different names + reveal_type(x) # N: Revealed type is "builtins.object" + reveal_type(y) # N: Revealed type is "builtins.int*" +[builtins fixtures/list.pyi] + +[case testMatchOrPatternCapturesJoin] +m: object + +match m: + case list(x) | dict(x): + reveal_type(x) # N: Revealed type is "typing.Iterable[Any]" +[builtins fixtures/dict.pyi] + +-- Interactions -- + +[case testMatchCapturePatternMultipleCases] +m: object + +match m: + case int(x): + reveal_type(x) # N: Revealed type is "builtins.int" + case str(x): + reveal_type(x) # N: Revealed type is "builtins.str" + +reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str]" + +[case testMatchCapturePatternMultipleCaptures] +from typing import Iterable + +m: Iterable[int] + +match m: + case [x, x]: # E: Multiple assignments to name "x" in pattern + reveal_type(x) # N: Revealed type is "builtins.int" +[builtins fixtures/list.pyi] + +[case testMatchCapturePatternPreexistingSame] +a: int +m: int + +match m: + case a: + reveal_type(a) # N: Revealed type is "builtins.int" + +[case testMatchCapturePatternPreexistingNarrows] +a: int +m: bool + +match m: + case a: + reveal_type(a) # N: Revealed type is "builtins.bool" + +reveal_type(a) # N: Revealed type is "builtins.bool" +a = 3 +reveal_type(a) # N: Revealed type is "builtins.int" + +[case testMatchCapturePatternPreexistingIncompatible] +a: str +m: int + +match m: + case a: # E: Incompatible types in capture pattern (pattern captures type "int", variable has type "str") + reveal_type(a) # N: Revealed type is "builtins.str" + +reveal_type(a) # N: Revealed type is "builtins.str" + +[case testMatchCapturePatternPreexistingIncompatibleLater] +a: str +m: object + +match m: + case str(a): + reveal_type(a) # N: Revealed type is "builtins.str" + case int(a): # E: Incompatible types in capture pattern (pattern captures type "int", variable has type "str") + reveal_type(a) # N: Revealed type is "builtins.str" + +reveal_type(a) # N: Revealed type is "builtins.str" + +-- Guards -- + +[case testMatchSimplePatternGuard] +m: str + +def guard() -> bool: ... + +match m: + case a if guard(): + reveal_type(a) # N: Revealed type is "builtins.str" + +[case testMatchAlwaysTruePatternGuard] +m: str + +match m: + case a if True: + reveal_type(a) # N: Revealed type is "builtins.str" + +[case testMatchAlwaysFalsePatternGuard] +m: str + +match m: + case a if False: + reveal_type(a) + +[case testMatchRedefiningPatternGuard] +# flags: --strict-optional +m: str + +match m: + case a if a := 1: # E: Incompatible types in assignment (expression has type "int", variable has type "str") + reveal_type(a) # N: Revealed type is "" + +[case testMatchAssigningPatternGuard] +m: str + +match m: + case a if a := "test": + reveal_type(a) # N: Revealed type is "builtins.str" + +[case testMatchNarrowingPatternGuard] +m: object + +match m: + case a if isinstance(a, str): + reveal_type(a) # N: Revealed type is "builtins.str" +[builtins fixtures/isinstancelist.pyi] + +[case testMatchIncompatiblePatternGuard] +class A: ... +class B: ... + +m: A + +match m: + case a if isinstance(a, B): + reveal_type(a) # N: Revealed type is "__main__." +[builtins fixtures/isinstancelist.pyi] + +[case testMatchUnreachablePatternGuard] +m: str + +match m: + case a if isinstance(a, int): + reveal_type(a) +[builtins fixtures/isinstancelist.pyi] + +-- Exhaustiveness -- + +[case testMatchUnionNegativeNarrowing] +from typing import Union + +m: Union[str, int] + +match m: + case str(a): + reveal_type(a) # N: Revealed type is "builtins.str" + reveal_type(m) # N: Revealed type is "builtins.str" + case b: + reveal_type(b) # N: Revealed type is "builtins.int" + reveal_type(m) # N: Revealed type is "builtins.int" + +[case testMatchOrPatternNegativeNarrowing] +from typing import Union + +m: Union[str, bytes, int] + +match m: + case str(a) | bytes(a): + reveal_type(a) # N: Revealed type is "builtins.object" + reveal_type(m) # N: Revealed type is "Union[builtins.str, builtins.bytes]" + case b: + reveal_type(b) # N: Revealed type is "builtins.int" + +[case testMatchExhaustiveReturn] +def foo(value) -> int: + match value: + case "bar": + return 1 case _: - 1 + b'' + return 2 + +[case testMatchNonExhaustiveReturn] +def foo(value) -> int: # E: Missing return statement + match value: + case "bar": + return 1 + case 2: + return 2 + +[case testMatchMoreExhaustiveReturnCases] +def g(value: int | None) -> int: + match value: + case int(): + return 0 + case None: + return 1 + +def b(value: bool) -> int: + match value: + case True: + return 2 + case False: + return 3 + +[case testMatchMiscNonExhaustiveReturn] +class C: + a: int | str + +def f1(value: int | str | None) -> int: # E: Missing return statement + match value: + case int(): + return 0 + case None: + return 1 + +def f2(c: C) -> int: # E: Missing return statement + match c: + case C(a=int()): + return 0 + case C(a=str()): + return 1 + +def f3(x: list[str]) -> int: # E: Missing return statement + match x: + case [a]: + return 0 + case [a, b]: + return 1 + +def f4(x: dict[str, int]) -> int: # E: Missing return statement + match x: + case {'x': a}: + return 0 + +def f5(x: bool) -> int: # E: Missing return statement + match x: + case True: + return 0 +[builtins fixtures/dict.pyi] + +[case testMatchNonExhaustiveError] +from typing import NoReturn +def assert_never(x: NoReturn) -> None: ... + +def f(value: int) -> int: # E: Missing return statement + match value: + case 1: + return 0 + case 2: + return 1 + case o: + assert_never(o) # E: Argument 1 to "assert_never" has incompatible type "int"; expected "NoReturn" + +[case testMatchExhaustiveNoError] +from typing import NoReturn, Union, Literal +def assert_never(x: NoReturn) -> None: ... + +def f(value: Literal[1] | Literal[2]) -> int: + match value: + case 1: + return 0 + case 2: + return 1 + case o: + assert_never(o) +[typing fixtures/typing-medium.pyi] + +[case testMatchSequencePatternNegativeNarrowing] +from typing import Union, Sequence, Tuple + +m1: Sequence[int | str] + +match m1: + case [int()]: + reveal_type(m1) # N: Revealed type is "typing.Sequence[builtins.int]" + case r: + reveal_type(m1) # N: Revealed type is "typing.Sequence[Union[builtins.int, builtins.str]]" + +m2: Tuple[int | str] + +match m2: + case (int(),): + reveal_type(m2) # N: Revealed type is "Tuple[builtins.int]" + case r2: + reveal_type(m2) # N: Revealed type is "Tuple[builtins.str]" + +m3: Tuple[Union[int, str]] + +match m3: + case (1,): + reveal_type(m3) # N: Revealed type is "Tuple[Literal[1]]" + case r2: + reveal_type(m3) # N: Revealed type is "Tuple[Union[builtins.int, builtins.str]]" +[builtins fixtures/tuple.pyi] + +[case testMatchLiteralPatternEnumNegativeNarrowing] +from enum import Enum +class Medal(Enum): + gold = 1 + silver = 2 + bronze = 3 + +def f(m: Medal) -> int: + match m: + case Medal.gold: + reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.gold]" + return 0 + case _: + reveal_type(m) # N: Revealed type is "Union[Literal[__main__.Medal.silver], Literal[__main__.Medal.bronze]]" + return 1 + +def g(m: Medal) -> int: + match m: + case Medal.gold: + return 0 + case Medal.silver: + return 1 + case Medal.bronze: + return 2 + +[case testMatchLiteralPatternEnumCustomEquals-skip] +from enum import Enum +class Medal(Enum): + gold = 1 + silver = 2 + bronze = 3 + + def __eq__(self, other) -> bool: ... + +m: Medal + +match m: + case Medal.gold: + reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.gold]" + case _: + reveal_type(m) # N: Revealed type is "__main__.Medal" + +[case testMatchNarrowUsingPatternGuardSpecialCase] +def f(x: int | str) -> int: # E: Missing return statement + match x: + case x if isinstance(x, str): + return 0 + case int(): + return 1 +[builtins fixtures/isinstance.pyi] + +[case testMatchNarrowDownUnionPartially] +# flags: --strict-optional + +def f(x: int | str) -> None: + match x: + case int(): + return + reveal_type(x) # N: Revealed type is "builtins.str" + +def g(x: int | str | None) -> None: + match x: + case int() | None: + return + reveal_type(x) # N: Revealed type is "builtins.str" + +def h(x: int | str | None) -> None: + match x: + case int() | str(): + return + reveal_type(x) # N: Revealed type is "None" + +[case testMatchNarrowDownUsingLiteralMatch] +from enum import Enum +class Medal(Enum): + gold = 1 + silver = 2 + +def b1(x: bool) -> None: + match x: + case True: + return + reveal_type(x) # N: Revealed type is "Literal[False]" + +def b2(x: bool) -> None: + match x: + case False: + return + reveal_type(x) # N: Revealed type is "Literal[True]" + +def e1(x: Medal) -> None: + match x: + case Medal.gold: + return + reveal_type(x) # N: Revealed type is "Literal[__main__.Medal.silver]" + +def e2(x: Medal) -> None: + match x: + case Medal.silver: + return + reveal_type(x) # N: Revealed type is "Literal[__main__.Medal.gold]" + +def i(x: int) -> None: + match x: + case 1: + return + reveal_type(x) # N: Revealed type is "builtins.int" + +def s(x: str) -> None: + match x: + case 'x': + return + reveal_type(x) # N: Revealed type is "builtins.str" + +def union(x: str | bool) -> None: + match x: + case True: + return + reveal_type(x) # N: Revealed type is "Union[builtins.str, Literal[False]]" + +[case testMatchAssertFalseToSilenceFalsePositives] +class C: + a: int | str + +def f(c: C) -> int: + match c: + case C(a=int()): + return 0 + case C(a=str()): + return 1 + case _: + assert False + +def g(c: C) -> int: + match c: + case C(a=int()): + return 0 + case C(a=str()): + return 1 + assert False + +[case testMatchAsPatternExhaustiveness] +def f(x: int | str) -> int: + match x: + case int() as n: + return n + case str() as s: + return 1 + +[case testMatchAsPatternIntersection-skip] +class A: pass +class B: pass +class C: pass + +def f(x: A) -> None: + match x: + case B() as y: + reveal_type(y) # N: Revealed type is "__main__." + case C() as y: + reveal_type(y) # N: Revealed type is "__main__." + reveal_type(y) # N: Revealed type is "Union[__main__., __main__.]" + +[case testMatchWithBreakAndContinue] +# flags: --strict-optional +def f(x: int | str | None) -> None: + i = int() + while i: + match x: + case int(): + continue + case str(): + break + reveal_type(x) # N: Revealed type is "None" + reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str, None]" + +[case testMatchNarrowDownWithStarred-skip] +from typing import List +def f(x: List[int] | int) -> None: + match x: + case [*y]: + reveal_type(y) # N: Revealed type is "builtins.list[builtins.int*]" + return + reveal_type(x) # N: Revealed type is "builtins.int" +[builtins fixtures/list.pyi] + +-- Misc + +[case testMatchAndWithStatementScope] +from m import A, B + +with A() as x: + pass +with B() as x: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + pass + +with A() as y: + pass +with B() as y: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + pass + +with A() as z: + pass +with B() as z: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + pass + +with A() as zz: + pass +with B() as zz: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + pass + +match x: + case str(y) as z: + zz = y + +[file m.pyi] +from typing import Any + +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testOverrideMatchArgs] +class AST: + __match_args__ = () + +class stmt(AST): ... + +class AnnAssign(stmt): + __match_args__ = ('target', 'annotation', 'value', 'simple') + target: str + annotation: int + value: str + simple: int + +reveal_type(AST.__match_args__) # N: Revealed type is "Tuple[]" +reveal_type(stmt.__match_args__) # N: Revealed type is "Tuple[]" +reveal_type(AnnAssign.__match_args__) # N: Revealed type is "Tuple[Literal['target']?, Literal['annotation']?, Literal['value']?, Literal['simple']?]" + +AnnAssign.__match_args__ = ('a', 'b', 'c', 'd') # E: Cannot assign to "__match_args__" +__match_args__ = 0 + +def f(x: AST) -> None: + match x: + case AST(): + reveal_type(x) # N: Revealed type is "__main__.AST" + match x: + case stmt(): + reveal_type(x) # N: Revealed type is "__main__.stmt" + match x: + case AnnAssign(a, b, c, d): + reveal_type(a) # N: Revealed type is "builtins.str" + reveal_type(b) # N: Revealed type is "builtins.int" + reveal_type(c) # N: Revealed type is "builtins.str" +[builtins fixtures/tuple.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 afd75111743d..3948d215b192 100644 --- a/test-data/unit/check-selftype.test +++ b/test-data/unit/check-selftype.test @@ -555,9 +555,9 @@ reveal_type(P) # N: Revealed type is "Overload(def [T] (use_str: Literal[True]) reveal_type(P(use_str=True)) # N: Revealed type is "lib.P[builtins.str]" reveal_type(P(use_str=False)) # N: Revealed type is "lib.P[builtins.int]" -reveal_type(C) # N: Revealed type is "Overload(def [T] (item: T`1, use_tuple: Literal[False]) -> lib.C[T`1], def [T] (item: T`1, use_tuple: Literal[True]) -> lib.C[builtins.tuple[T`1]])" +reveal_type(C) # N: Revealed type is "Overload(def [T] (item: T`1, use_tuple: Literal[False]) -> lib.C[T`1], def [T] (item: T`1, use_tuple: Literal[True]) -> lib.C[builtins.tuple[T`1, ...]])" reveal_type(C(0, use_tuple=False)) # N: Revealed type is "lib.C[builtins.int*]" -reveal_type(C(0, use_tuple=True)) # N: Revealed type is "lib.C[builtins.tuple[builtins.int*]]" +reveal_type(C(0, use_tuple=True)) # N: Revealed type is "lib.C[builtins.tuple[builtins.int*, ...]]" T = TypeVar('T') class SubP(P[T]): @@ -949,9 +949,9 @@ class Other(Base): ... class Double(Sub): ... reveal_type(Other.make()) # N: Revealed type is "__main__.Other*" -reveal_type(Other.make(3)) # N: Revealed type is "builtins.tuple[__main__.Other*]" +reveal_type(Other.make(3)) # N: Revealed type is "builtins.tuple[__main__.Other*, ...]" reveal_type(Double.make()) # N: Revealed type is "__main__.Sub" -reveal_type(Double.make(3)) # N: Revealed type is "builtins.tuple[__main__.Sub]" +reveal_type(Double.make(3)) # N: Revealed type is "builtins.tuple[__main__.Sub, ...]" [file lib.pyi] from typing import overload, TypeVar, Type, Tuple diff --git a/test-data/unit/check-semanal-error.test b/test-data/unit/check-semanal-error.test index f91e3b1360c7..c6cf45d96691 100644 --- a/test-data/unit/check-semanal-error.test +++ b/test-data/unit/check-semanal-error.test @@ -77,10 +77,47 @@ continue # E: "continue" outside loop [case testYieldOutsideFunction] yield # E: "yield" outside function - -[case testYieldFromOutsideFunction] x = 1 yield from x # E: "yield from" outside function +[(yield 1) for _ in x] # E: "yield" inside comprehension or generator expression +{(yield 1) for _ in x} # E: "yield" inside comprehension or generator expression +{i: (yield 1) for i in x} # E: "yield" inside comprehension or generator expression +((yield 1) for _ in x) # E: "yield" inside comprehension or generator expression +y = 1 +[(yield from x) for _ in y] # E: "yield from" inside comprehension or generator expression +{(yield from x) for _ in y} # E: "yield from" inside comprehension or generator expression +{i: (yield from x) for i in y} # E: "yield from" inside comprehension or generator expression +((yield from x) for _ in y) # E: "yield from" inside comprehension or generator expression +def f(y): + [x for x in (yield y)] + {x for x in (yield y)} + {x: x for x in (yield y)} + (x for x in (yield y)) + [x for x in (yield from y)] + {x for x in (yield from y)} + {x: x for x in (yield from y)} + (x for x in (yield from y)) +def g(y): + [(yield 1) for _ in y] # E: "yield" inside comprehension or generator expression + {(yield 1) for _ in y} # E: "yield" inside comprehension or generator expression + {i: (yield 1) for i in y} # E: "yield" inside comprehension or generator expression + ((yield 1) for _ in y) # E: "yield" inside comprehension or generator expression + lst = 1 + [(yield from lst) for _ in y] # E: "yield from" inside comprehension or generator expression + {(yield from lst) for _ in y} # E: "yield from" inside comprehension or generator expression + {i: (yield from lst) for i in y} # E: "yield from" inside comprehension or generator expression + ((yield from lst) for _ in y) # E: "yield from" inside comprehension or generator expression +def h(y): + lst = 1 + [x for x in lst if (yield y)] # E: "yield" inside comprehension or generator expression + {x for x in lst if (yield y)} # E: "yield" inside comprehension or generator expression + {x: x for x in lst if (yield y)} # E: "yield" inside comprehension or generator expression + (x for x in lst if (yield y)) # E: "yield" inside comprehension or generator expression + lst = 1 + [x for x in lst if (yield from y)] # E: "yield from" inside comprehension or generator expression + {x for x in lst if (yield from y)} # E: "yield from" inside comprehension or generator expression + {x: x for x in lst if (yield from y)} # E: "yield from" inside comprehension or generator expression + (x for x in lst if (yield from y)) # E: "yield from" inside comprehension or generator expression [case testImportFuncDup] diff --git a/test-data/unit/check-serialize.test b/test-data/unit/check-serialize.test index b34a6c704a27..3a9d2266dd55 100644 --- a/test-data/unit/check-serialize.test +++ b/test-data/unit/check-serialize.test @@ -1030,8 +1030,8 @@ x: Tuple[int, ...] y: tuple [builtins fixtures/tuple.pyi] [out2] -tmp/a.py:2: note: Revealed type is "builtins.tuple[builtins.int]" -tmp/a.py:3: note: Revealed type is "builtins.tuple[Any]" +tmp/a.py:2: note: Revealed type is "builtins.tuple[builtins.int, ...]" +tmp/a.py:3: note: Revealed type is "builtins.tuple[Any, ...]" [case testSerializeNone] import a diff --git a/test-data/unit/check-statements.test b/test-data/unit/check-statements.test index 62d82f94a6c1..5819ace83603 100644 --- a/test-data/unit/check-statements.test +++ b/test-data/unit/check-statements.test @@ -1555,7 +1555,6 @@ class LiteralReturn: return False [builtins fixtures/bool.pyi] - [case testWithStmtBoolExitReturnInStub] import stub @@ -1572,6 +1571,370 @@ class C3: def __exit__(self, x, y, z) -> Optional[bool]: pass [builtins fixtures/bool.pyi] +[case testWithStmtScopeBasics] +from m import A, B + +def f1() -> None: + with A() as x: + reveal_type(x) # N: Revealed type is "m.A" + with B() as x: + reveal_type(x) # N: Revealed type is "m.B" + +def f2() -> None: + with A() as x: + reveal_type(x) # N: Revealed type is "m.A" + y = x # Use outside with makes the scope function-level + with B() as x: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + reveal_type(x) # N: Revealed type is "m.A" + +[file m.pyi] +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testWithStmtScopeAndFuncDef] +from m import A, B + +with A() as x: + reveal_type(x) # N: Revealed type is "m.A" + +def f() -> None: + pass # Don't support function definition in the middle + +with B() as x: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + reveal_type(x) # N: Revealed type is "m.A" + +[file m.pyi] +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testWithStmtScopeAndFuncDef2] +from m import A, B + +def f() -> None: + pass # function before with is unsupported + +with A() as x: + reveal_type(x) # N: Revealed type is "m.A" + +with B() as x: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + reveal_type(x) # N: Revealed type is "m.A" + +[file m.pyi] +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testWithStmtScopeAndFuncDef3] +from m import A, B + +with A() as x: + reveal_type(x) # N: Revealed type is "m.A" + +with B() as x: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + reveal_type(x) # N: Revealed type is "m.A" + +def f() -> None: + pass # function after with is unsupported + +[file m.pyi] +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testWithStmtScopeAndFuncDef4] +from m import A, B + +with A() as x: + def f() -> None: + pass # Function within with is unsupported + + reveal_type(x) # N: Revealed type is "m.A" + +with B() as x: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + reveal_type(x) # N: Revealed type is "m.A" + +[file m.pyi] +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testWithStmtScopeAndImport1] +from m import A, B, x + +with A() as x: \ + # E: Incompatible types in assignment (expression has type "A", variable has type "B") + reveal_type(x) # N: Revealed type is "m.B" + +with B() as x: + reveal_type(x) # N: Revealed type is "m.B" + +[file m.pyi] +x: B + +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testWithStmtScopeAndImport2] +from m import A, B +import m as x + +with A() as x: \ + # E: Incompatible types in assignment (expression has type "A", variable has type Module) + pass + +with B() as x: \ + # E: Incompatible types in assignment (expression has type "B", variable has type Module) + pass + +[file m.pyi] +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... +[builtins fixtures/module.pyi] + +[case testWithStmtScopeAndImportStar] +from m import A, B +from m import * + +with A() as x: + pass + +with B() as x: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + pass + +[file m.pyi] +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testWithStmtScopeNestedWith1] +from m import A, B + +with A() as x: + with B() as x: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + reveal_type(x) # N: Revealed type is "m.A" + +with B() as x: + with A() as x: \ + # E: Incompatible types in assignment (expression has type "A", variable has type "B") + reveal_type(x) # N: Revealed type is "m.B" + +[file m.pyi] +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testWithStmtScopeNestedWith2] +from m import A, B + +with A() as x: + with A() as y: + reveal_type(y) # N: Revealed type is "m.A" + with B() as y: + reveal_type(y) # N: Revealed type is "m.B" + +[file m.pyi] +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testWithStmtScopeInnerAndOuterScopes] +from m import A, B + +x = A() # Outer scope should have no impact + +with A() as x: + pass + +def f() -> None: + with A() as x: + reveal_type(x) # N: Revealed type is "m.A" + with B() as x: + reveal_type(x) # N: Revealed type is "m.B" + +y = x + +with A() as x: + pass + +[file m.pyi] +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testWithStmtScopeMultipleContextManagers] +from m import A, B + +with A() as x, B() as y: + reveal_type(x) # N: Revealed type is "m.A" + reveal_type(y) # N: Revealed type is "m.B" +with B() as x, A() as y: + reveal_type(x) # N: Revealed type is "m.B" + reveal_type(y) # N: Revealed type is "m.A" + +[file m.pyi] +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testWithStmtScopeMultipleAssignment] +from m import A, B + +with A() as (x, y): + reveal_type(x) # N: Revealed type is "m.A" + reveal_type(y) # N: Revealed type is "builtins.int" +with B() as [x, y]: + reveal_type(x) # N: Revealed type is "m.B" + reveal_type(y) # N: Revealed type is "builtins.str" + +[file m.pyi] +from typing import Tuple + +class A: + def __enter__(self) -> Tuple[A, int]: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> Tuple[B, str]: ... + def __exit__(self, x, y, z) -> None: ... +[builtins fixtures/tuple.pyi] + +[case testWithStmtScopeComplexAssignments] +from m import A, B, f + +with A() as x: + pass +with B() as x: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + pass +with B() as f(x).x: + pass + +with A() as y: + pass +with B() as y: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + pass +with B() as f(y)[0]: + pass + +[file m.pyi] +def f(x): ... + +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testWithStmtScopeAndClass] +from m import A, B + +with A() as x: + pass + +class C: + with A() as y: + pass + with B() as y: + pass + +with B() as x: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + pass + +[file m.pyi] +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testWithStmtScopeInnerScopeReference] +from m import A, B + +with A() as x: + def f() -> A: + return x + f() + +with B() as x: \ + # E: Incompatible types in assignment (expression has type "B", variable has type "A") + pass +[file m.pyi] +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + +[case testWithStmtScopeAndLambda] +from m import A, B + +# This is technically not correct, since the lambda can outlive the with +# statement, but this behavior seems more intuitive. + +with A() as x: + lambda: reveal_type(x) # N: Revealed type is "m.A" + +with B() as x: + pass +[file m.pyi] +class A: + def __enter__(self) -> A: ... + def __exit__(self, x, y, z) -> None: ... +class B: + def __enter__(self) -> B: ... + def __exit__(self, x, y, z) -> None: ... + -- Chained assignment -- ------------------ diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index 6c4c63dc5c2d..b558e1520798 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -193,7 +193,7 @@ t1[2] # E: Tuple index out of range t1[3] # E: Tuple index out of range t2[1] # E: Tuple index out of range reveal_type(t1[n]) # N: Revealed type is "Union[__main__.A, __main__.B]" -reveal_type(t3[n:]) # N: Revealed type is "builtins.tuple[Union[__main__.A, __main__.B, __main__.C, __main__.D, __main__.E]]" +reveal_type(t3[n:]) # N: Revealed type is "builtins.tuple[Union[__main__.A, __main__.B, __main__.C, __main__.D, __main__.E], ...]" if int(): b = t1[(0)] # E: Incompatible types in assignment (expression has type "A", variable has type "B") @@ -985,15 +985,15 @@ reveal_type(b) # N: Revealed type is "Tuple[builtins.int, builtins.int, builtin [case testTupleWithStarExpr2] a = [1] b = (0, *a) -reveal_type(b) # N: Revealed type is "builtins.tuple[builtins.int*]" +reveal_type(b) # N: Revealed type is "builtins.tuple[builtins.int*, ...]" [builtins fixtures/tuple.pyi] [case testTupleWithStarExpr3] a = [''] b = (0, *a) -reveal_type(b) # N: Revealed type is "builtins.tuple[builtins.object*]" +reveal_type(b) # N: Revealed type is "builtins.tuple[builtins.object*, ...]" c = (*a, '') -reveal_type(c) # N: Revealed type is "builtins.tuple[builtins.str*]" +reveal_type(c) # N: Revealed type is "builtins.tuple[builtins.str*, ...]" [builtins fixtures/tuple.pyi] [case testTupleWithStarExpr4] @@ -1086,12 +1086,12 @@ class B(A): pass fixtup = None # type: Tuple[B, B] vartup_b = None # type: Tuple[B, ...] -reveal_type(fixtup if int() else vartup_b) # N: Revealed type is "builtins.tuple[__main__.B]" -reveal_type(vartup_b if int() else fixtup) # N: Revealed type is "builtins.tuple[__main__.B]" +reveal_type(fixtup if int() else vartup_b) # N: Revealed type is "builtins.tuple[__main__.B, ...]" +reveal_type(vartup_b if int() else fixtup) # N: Revealed type is "builtins.tuple[__main__.B, ...]" vartup_a = None # type: Tuple[A, ...] -reveal_type(fixtup if int() else vartup_a) # N: Revealed type is "builtins.tuple[__main__.A]" -reveal_type(vartup_a if int() else fixtup) # N: Revealed type is "builtins.tuple[__main__.A]" +reveal_type(fixtup if int() else vartup_a) # N: Revealed type is "builtins.tuple[__main__.A, ...]" +reveal_type(vartup_a if int() else fixtup) # N: Revealed type is "builtins.tuple[__main__.A, ...]" [builtins fixtures/tuple.pyi] @@ -1124,12 +1124,12 @@ class A: pass empty = () fixtup = None # type: Tuple[A] -reveal_type(fixtup if int() else empty) # N: Revealed type is "builtins.tuple[__main__.A]" -reveal_type(empty if int() else fixtup) # N: Revealed type is "builtins.tuple[__main__.A]" +reveal_type(fixtup if int() else empty) # N: Revealed type is "builtins.tuple[__main__.A, ...]" +reveal_type(empty if int() else fixtup) # N: Revealed type is "builtins.tuple[__main__.A, ...]" vartup = None # type: Tuple[A, ...] -reveal_type(empty if int() else vartup) # N: Revealed type is "builtins.tuple[__main__.A]" -reveal_type(vartup if int() else empty) # N: Revealed type is "builtins.tuple[__main__.A]" +reveal_type(empty if int() else vartup) # N: Revealed type is "builtins.tuple[__main__.A, ...]" +reveal_type(vartup if int() else empty) # N: Revealed type is "builtins.tuple[__main__.A, ...]" lst = None # type: List[A] reveal_type(empty if int() else lst) # N: Revealed type is "typing.Sequence[__main__.A*]" @@ -1152,8 +1152,8 @@ ntup = None # type: NTup subtup = None # type: SubTuple vartup = None # type: SubVarTuple -reveal_type(ntup if int() else vartup) # N: Revealed type is "builtins.tuple[builtins.int]" -reveal_type(subtup if int() else vartup) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(ntup if int() else vartup) # N: Revealed type is "builtins.tuple[builtins.int, ...]" +reveal_type(subtup if int() else vartup) # N: Revealed type is "builtins.tuple[builtins.int, ...]" [builtins fixtures/tuple.pyi] [out] @@ -1164,14 +1164,14 @@ from typing import Tuple tup1 = None # type: Tuple[bool, int] tup2 = None # type: Tuple[bool] -reveal_type(tup1 if int() else tup2) # N: Revealed type is "builtins.tuple[builtins.int]" -reveal_type(tup2 if int() else tup1) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(tup1 if int() else tup2) # N: Revealed type is "builtins.tuple[builtins.int, ...]" +reveal_type(tup2 if int() else tup1) # N: Revealed type is "builtins.tuple[builtins.int, ...]" -reveal_type(tup1 if int() else ()) # N: Revealed type is "builtins.tuple[builtins.int]" -reveal_type(() if int() else tup1) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(tup1 if int() else ()) # N: Revealed type is "builtins.tuple[builtins.int, ...]" +reveal_type(() if int() else tup1) # N: Revealed type is "builtins.tuple[builtins.int, ...]" -reveal_type(tup2 if int() else ()) # N: Revealed type is "builtins.tuple[builtins.bool]" -reveal_type(() if int() else tup2) # N: Revealed type is "builtins.tuple[builtins.bool]" +reveal_type(tup2 if int() else ()) # N: Revealed type is "builtins.tuple[builtins.bool, ...]" +reveal_type(() if int() else tup2) # N: Revealed type is "builtins.tuple[builtins.bool, ...]" [builtins fixtures/tuple.pyi] [out] @@ -1192,14 +1192,14 @@ tup1 = None # type: NTup1 tup2 = None # type: NTup2 subtup = None # type: SubTuple -reveal_type(tup1 if int() else tup2) # N: Revealed type is "builtins.tuple[builtins.bool]" -reveal_type(tup2 if int() else tup1) # N: Revealed type is "builtins.tuple[builtins.bool]" +reveal_type(tup1 if int() else tup2) # N: Revealed type is "builtins.tuple[builtins.bool, ...]" +reveal_type(tup2 if int() else tup1) # N: Revealed type is "builtins.tuple[builtins.bool, ...]" -reveal_type(tup1 if int() else subtup) # N: Revealed type is "builtins.tuple[builtins.int]" -reveal_type(subtup if int() else tup1) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(tup1 if int() else subtup) # N: Revealed type is "builtins.tuple[builtins.int, ...]" +reveal_type(subtup if int() else tup1) # N: Revealed type is "builtins.tuple[builtins.int, ...]" -reveal_type(tup2 if int() else subtup) # N: Revealed type is "builtins.tuple[builtins.int]" -reveal_type(subtup if int() else tup2) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(tup2 if int() else subtup) # N: Revealed type is "builtins.tuple[builtins.int, ...]" +reveal_type(subtup if int() else tup2) # N: Revealed type is "builtins.tuple[builtins.int, ...]" [builtins fixtures/tuple.pyi] [out] @@ -1263,7 +1263,7 @@ t[y] # E: Invalid tuple index type (actual type "str", expected type "Union[int t = (0, "") x = 0 y = "" -reveal_type(t[x:]) # N: Revealed type is "builtins.tuple[Union[builtins.int, builtins.str]]" +reveal_type(t[x:]) # N: Revealed type is "builtins.tuple[Union[builtins.int, builtins.str], ...]" t[y:] # E: Slice index must be an integer or None [builtins fixtures/tuple.pyi] @@ -1311,7 +1311,7 @@ class CallableTuple(Tuple[str, int]): from typing import Sequence s: Sequence[str] s = tuple() -reveal_type(s) # N: Revealed type is "builtins.tuple[builtins.str]" +reveal_type(s) # N: Revealed type is "builtins.tuple[builtins.str, ...]" [builtins fixtures/tuple.pyi] @@ -1320,7 +1320,7 @@ from typing import Iterable, Tuple x: Iterable[int] = () y: Tuple[int, ...] = (1, 2, 3) x = y -reveal_type(x) # N: Revealed type is "builtins.tuple[builtins.int]" +reveal_type(x) # N: Revealed type is "builtins.tuple[builtins.int, ...]" [builtins fixtures/tuple.pyi] @@ -1481,7 +1481,7 @@ t3 = ('', 1) * 2 reveal_type(t3) # N: Revealed type is "Tuple[builtins.str, builtins.int, builtins.str, builtins.int]" def f() -> Tuple[str, ...]: return ('', ) -reveal_type(f() * 2) # N: Revealed type is "builtins.tuple[builtins.str*]" +reveal_type(f() * 2) # N: Revealed type is "builtins.tuple[builtins.str*, ...]" [builtins fixtures/tuple.pyi] [case testMultiplyTupleByIntegerLiteralReverse] @@ -1494,7 +1494,7 @@ t3 = 2 * ('', 1) reveal_type(t3) # N: Revealed type is "Tuple[builtins.str, builtins.int, builtins.str, builtins.int]" def f() -> Tuple[str, ...]: return ('', ) -reveal_type(2 * f()) # N: Revealed type is "builtins.tuple[builtins.str*]" +reveal_type(2 * f()) # N: Revealed type is "builtins.tuple[builtins.str*, ...]" [builtins fixtures/tuple.pyi] [case testSingleUndefinedTypeAndTuple] diff --git a/test-data/unit/check-type-aliases.test b/test-data/unit/check-type-aliases.test index a697c32d7c49..4c5dacee1b3f 100644 --- a/test-data/unit/check-type-aliases.test +++ b/test-data/unit/check-type-aliases.test @@ -50,6 +50,14 @@ def f(x: A) -> None: f(1) f('x') +[case testNoReturnTypeAlias] +# https://github.com/python/mypy/issues/11903 +from typing import NoReturn +Never = NoReturn +a: Never # Used to be an error here + +def f(a: Never): ... +f(5) # E: Argument 1 to "f" has incompatible type "int"; expected "NoReturn" [case testImportUnionAlias] import typing from _m import U @@ -312,7 +320,7 @@ T = Tuple c: C t: T reveal_type(c) # N: Revealed type is "def (*Any, **Any) -> Any" -reveal_type(t) # N: Revealed type is "builtins.tuple[Any]" +reveal_type(t) # N: Revealed type is "builtins.tuple[Any, ...]" bad: C[int] # E: Bad number of arguments for type alias, expected: 0, given: 1 also_bad: T[int] # E: Bad number of arguments for type alias, expected: 0, given: 1 [builtins fixtures/tuple.pyi] @@ -694,6 +702,30 @@ x: TypeAlias = list(int) # E: Invalid type alias: expression is not a valid typ a: x [builtins fixtures/tuple.pyi] +[case testAliasedImportPep613] +import typing as tpp +import typing_extensions as tpx +from typing import TypeAlias as TPA +from typing_extensions import TypeAlias as TXA +import typing +import typing_extensions + +Int1: tpp.TypeAlias = int +Int2: tpx.TypeAlias = int +Int3: TPA = int +Int4: TXA = int +Int5: typing.TypeAlias = int +Int6: typing_extensions.TypeAlias = int + +x1: Int1 = "str" # E: Incompatible types in assignment (expression has type "str", variable has type "int") +x2: Int2 = "str" # E: Incompatible types in assignment (expression has type "str", variable has type "int") +x3: Int3 = "str" # E: Incompatible types in assignment (expression has type "str", variable has type "int") +x4: Int4 = "str" # E: Incompatible types in assignment (expression has type "str", variable has type "int") +x5: Int5 = "str" # E: Incompatible types in assignment (expression has type "str", variable has type "int") +x6: Int6 = "str" # E: Incompatible types in assignment (expression has type "str", variable has type "int") +[builtins fixtures/tuple.pyi] +[typing fixtures/typing-medium.pyi] + [case testFunctionScopePep613] from typing_extensions import TypeAlias diff --git a/test-data/unit/check-typeddict.test b/test-data/unit/check-typeddict.test index 921d2ab5c46e..a9321826b3ba 100644 --- a/test-data/unit/check-typeddict.test +++ b/test-data/unit/check-typeddict.test @@ -2208,6 +2208,12 @@ class Movie(TypedDict, total=False): year: int [typing fixtures/typing-typeddict.pyi] +[case testRequiredExplicitAny] +# flags: --disallow-any-explicit +from typing import TypedDict +from typing import Required +Foo = TypedDict("Foo", {"a.x": Required[int]}) +[typing fixtures/typing-typeddict.pyi] -- NotRequired[] @@ -2271,6 +2277,13 @@ class Movie(TypedDict): year: int [typing fixtures/typing-typeddict.pyi] +[case testNotRequiredExplicitAny] +# flags: --disallow-any-explicit +from typing import TypedDict +from typing import NotRequired +Foo = TypedDict("Foo", {"a.x": NotRequired[int]}) +[typing fixtures/typing-typeddict.pyi] + -- Union dunders [case testTypedDictUnionGetItem] diff --git a/test-data/unit/check-union-or-syntax.test b/test-data/unit/check-union-or-syntax.test index 3e5a19b8fe61..58526cfd0623 100644 --- a/test-data/unit/check-union-or-syntax.test +++ b/test-data/unit/check-union-or-syntax.test @@ -196,3 +196,30 @@ def f(x: Union[int, str, None]) -> None: else: reveal_type(x) # N: Revealed type is "None" [builtins fixtures/isinstance.pyi] + +[case testImplicit604TypeAliasWithCyclicImportInStub] +# flags: --python-version 3.10 +from was_builtins import foo +reveal_type(foo) # N: Revealed type is "Union[builtins.str, was_mmap.mmap]" +[file was_builtins.pyi] +import was_mmap +WriteableBuffer = was_mmap.mmap +ReadableBuffer = str | WriteableBuffer +foo: ReadableBuffer +[file was_mmap.pyi] +from was_builtins import * +class mmap: ... + +# TODO: Get this test to pass +[case testImplicit604TypeAliasWithCyclicImportNotInStub-xfail] +# flags: --python-version 3.10 +from was_builtins import foo +reveal_type(foo) # N: Revealed type is "Union[builtins.str, was_mmap.mmap]" +[file was_builtins.py] +import was_mmap +WriteableBuffer = was_mmap.mmap +ReadableBuffer = str | WriteableBuffer +foo: ReadableBuffer +[file was_mmap.py] +from was_builtins import * +class mmap: ... diff --git a/test-data/unit/check-unions.test b/test-data/unit/check-unions.test index cf1ff5650d49..6966af289f28 100644 --- a/test-data/unit/check-unions.test +++ b/test-data/unit/check-unions.test @@ -144,6 +144,11 @@ f(1) f(None) f('') # E: Argument 1 to "f" has incompatible type "str"; expected "Optional[int]" +[case testUnionWithNoReturn] +from typing import Union, NoReturn +def f() -> Union[int, NoReturn]: ... +reveal_type(f()) # N: Revealed type is "builtins.int" + [case testUnionSimplificationGenericFunction] from typing import TypeVar, Union, List T = TypeVar('T') diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test index de85f5188bb8..ad604b474ad4 100644 --- a/test-data/unit/check-unreachable-code.test +++ b/test-data/unit/check-unreachable-code.test @@ -936,6 +936,26 @@ if False: reveal_type(x) [builtins fixtures/exception.pyi] +[case testNeverVariants] +from typing import Never +from typing_extensions import Never as TENever +from typing import NoReturn +from typing_extensions import NoReturn as TENoReturn +from mypy_extensions import NoReturn as MENoReturn + +bottom1: Never +reveal_type(bottom1) # N: Revealed type is "" +bottom2: TENever +reveal_type(bottom2) # N: Revealed type is "" +bottom3: NoReturn +reveal_type(bottom3) # N: Revealed type is "" +bottom4: TENoReturn +reveal_type(bottom4) # N: Revealed type is "" +bottom5: MENoReturn +reveal_type(bottom5) # N: Revealed type is "" + +[builtins fixtures/tuple.pyi] + [case testUnreachableFlagExpressions] # flags: --warn-unreachable def foo() -> bool: ... diff --git a/test-data/unit/cmdline.pyproject.test b/test-data/unit/cmdline.pyproject.test index 83f4745d0786..831bce2eb63d 100644 --- a/test-data/unit/cmdline.pyproject.test +++ b/test-data/unit/cmdline.pyproject.test @@ -80,3 +80,56 @@ def g(a: int) -> int: [out] pyproject.toml: toml config file contains [[tool.mypy.overrides]] sections with conflicting values. Module 'x' has two different values for 'disallow_untyped_defs' == Return code: 0 + +[case testMultilineLiteralExcludePyprojectTOML] +# cmd: mypy x +[file pyproject.toml] +\[tool.mypy] +exclude = '''(?x)( + (^|/)[^/]*skipme_\.py$ + |(^|/)_skipme[^/]*\.py$ +)''' +[file x/__init__.py] +i: int = 0 +[file x/_skipme_please.py] +This isn't even syntatically valid! +[file x/please_skipme_.py] +Neither is this! + +[case testMultilineBasicExcludePyprojectTOML] +# cmd: mypy x +[file pyproject.toml] +\[tool.mypy] +exclude = """(?x)( + (^|/)[^/]*skipme_\\.py$ + |(^|/)_skipme[^/]*\\.py$ +)""" +[file x/__init__.py] +i: int = 0 +[file x/_skipme_please.py] +This isn't even syntatically valid! +[file x/please_skipme_.py] +Neither is this! + +[case testSequenceExcludePyprojectTOML] +# cmd: mypy x +[file pyproject.toml] +\[tool.mypy] +exclude = [ + '(^|/)[^/]*skipme_\.py$', # literal (no escaping) + "(^|/)_skipme[^/]*\\.py$", # basic (backslash needs escaping) +] +[file x/__init__.py] +i: int = 0 +[file x/_skipme_please.py] +This isn't even syntatically valid! +[file x/please_skipme_.py] +Neither is this! + +[case testPyprojectTOMLUnicode] +# cmd: mypy x.py +[file pyproject.toml] +\[project] +description = "Factory βΈ» A code generator 🏭" +\[tool.mypy] +[file x.py] diff --git a/test-data/unit/cmdline.test b/test-data/unit/cmdline.test index 6fa4d210a826..f29c183f20ba 100644 --- a/test-data/unit/cmdline.test +++ b/test-data/unit/cmdline.test @@ -59,7 +59,8 @@ undef undef [out] dir/a.py: error: Duplicate module named "a" (also at "dir/subdir/a.py") -dir/a.py: note: Are you missing an __init__.py? Alternatively, consider using --exclude to avoid checking one of them. +dir/a.py: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules for more info +dir/a.py: note: Common resolutions include: a) using `--exclude` to avoid checking one of them, b) adding `__init__.py` somewhere, c) using `--explicit-package-bases` or adjusting MYPYPATH == Return code: 2 [case testCmdlineNonPackageSlash] @@ -125,7 +126,8 @@ mypy: can't decode file 'a.py': unknown encoding: uft-8 # type: ignore [out] two/mod/__init__.py: error: Duplicate module named "mod" (also at "one/mod/__init__.py") -two/mod/__init__.py: note: Are you missing an __init__.py? Alternatively, consider using --exclude to avoid checking one of them. +two/mod/__init__.py: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules for more info +two/mod/__init__.py: note: Common resolutions include: a) using `--exclude` to avoid checking one of them, b) adding `__init__.py` somewhere, c) using `--explicit-package-bases` or adjusting MYPYPATH == Return code: 2 [case testFlagsFile] @@ -1144,6 +1146,7 @@ import foo.bar [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 +src/foo/bar.py: note: Common resolutions include: a) adding `__init__.py` somewhere, b) using `--explicit-package-bases` or adjusting MYPYPATH == Return code: 2 [case testEnableInvalidErrorCode] @@ -1354,9 +1357,10 @@ b/bpkg.py:1: error: "int" not callable # cmd: mypy . [file mypy.ini] \[mypy] -exclude = - abc - b +exclude = (?x)( + ^abc/ + |^b/ + ) [file abc/apkg.py] 1() [file b/bpkg.py] diff --git a/test-data/unit/deps.test b/test-data/unit/deps.test index d833a05e201a..fd593a975ca0 100644 --- a/test-data/unit/deps.test +++ b/test-data/unit/deps.test @@ -1436,6 +1436,7 @@ class B(A): -> , m -> -> , m.B.__init__ + -> -> -> -> diff --git a/test-data/unit/fine-grained-attr.test b/test-data/unit/fine-grained-attr.test new file mode 100644 index 000000000000..0a54f9a6ea59 --- /dev/null +++ b/test-data/unit/fine-grained-attr.test @@ -0,0 +1,23 @@ +[case updateMagicField] +from attr import Attribute +import m + +def g() -> Attribute[int]: + return m.A.__attrs_attrs__[0] + +[file m.py] +from attr import define + +@define +class A: + a: int +[file m.py.2] +from attr import define + +@define +class A: + a: float +[builtins fixtures/attr.pyi] +[out] +== +main:5: error: Incompatible return value type (got "Attribute[float]", expected "Attribute[int]") diff --git a/test-data/unit/fine-grained-blockers.test b/test-data/unit/fine-grained-blockers.test index 17a5c42c1128..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? == @@ -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,7 +515,7 @@ 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") diff --git a/test-data/unit/fine-grained-modules.test b/test-data/unit/fine-grained-modules.test index 856eaaad083c..80a2883ee756 100644 --- a/test-data/unit/fine-grained-modules.test +++ b/test-data/unit/fine-grained-modules.test @@ -1509,11 +1509,12 @@ class C: pass main:3: error: Name "f" is not defined main:4: error: Name "C" is not defined == -main:3: error: Missing positional argument "x" in call to "f" +main:2: error: Unsupported class scoped import main:4: error: Name "C" is not defined == -main:3: error: Missing positional argument "x" in call to "f" +main:2: error: Unsupported class scoped import == +main:2: error: Unsupported class scoped import [case testImportStarAddMissingDependencyInsidePackage1] from p.b import f diff --git a/test-data/unit/fine-grained.test b/test-data/unit/fine-grained.test index ad67ff19dfd2..86872277c6e3 100644 --- a/test-data/unit/fine-grained.test +++ b/test-data/unit/fine-grained.test @@ -2084,6 +2084,7 @@ a.py:5: error: "list" expects 1 type argument, but 2 given == [case testPreviousErrorInOverloadedFunction] +# flags: --strict-optional import a [file a.py] from typing import overload diff --git a/test-data/unit/fixtures/any.pyi b/test-data/unit/fixtures/any.pyi new file mode 100644 index 000000000000..d6d90b7b3e98 --- /dev/null +++ b/test-data/unit/fixtures/any.pyi @@ -0,0 +1,8 @@ +from typing import TypeVar, Iterable + +T = TypeVar('T') + +class int: pass +class str: pass + +def any(i: Iterable[T]) -> bool: pass diff --git a/test-data/unit/fixtures/dict.pyi b/test-data/unit/fixtures/dict.pyi index fd509de8a6c2..f8a5e3481d13 100644 --- a/test-data/unit/fixtures/dict.pyi +++ b/test-data/unit/fixtures/dict.pyi @@ -32,7 +32,11 @@ class dict(Mapping[KT, VT]): def __len__(self) -> int: ... class int: # for convenience - def __add__(self, x: int) -> int: pass + def __add__(self, x: Union[int, complex]) -> int: pass + def __sub__(self, x: Union[int, complex]) -> int: pass + def __neg__(self): pass + real: int + imag: int class str: pass # for keyword argument key type class unicode: pass # needed for py2 docstrings diff --git a/test-data/unit/fixtures/primitives.pyi b/test-data/unit/fixtures/primitives.pyi index 71f59a9c1d8c..c72838535443 100644 --- a/test-data/unit/fixtures/primitives.pyi +++ b/test-data/unit/fixtures/primitives.pyi @@ -1,5 +1,6 @@ # builtins stub with non-generic primitive types -from typing import Generic, TypeVar, Sequence, Iterator, Mapping +from typing import Generic, TypeVar, Sequence, Iterator, Mapping, Iterable, overload + T = TypeVar('T') V = TypeVar('V') @@ -48,5 +49,20 @@ class list(Sequence[T]): def __getitem__(self, item: int) -> T: pass class dict(Mapping[T, V]): def __iter__(self) -> Iterator[T]: pass +class set(Iterable[T]): + def __iter__(self) -> Iterator[T]: pass +class frozenset(Iterable[T]): + def __iter__(self) -> Iterator[T]: pass class function: pass class ellipsis: pass + +class range(Sequence[int]): + @overload + def __init__(self, stop: int) -> None: pass + @overload + def __init__(self, start: int, stop: int, step: int = ...) -> None: pass + def count(self, value: int) -> int: pass + def index(self, value: int) -> int: pass + def __getitem__(self, i: int) -> int: pass + def __iter__(self) -> Iterator[int]: pass + def __contains__(self, other: object) -> bool: pass diff --git a/test-data/unit/fixtures/typing-full.pyi b/test-data/unit/fixtures/typing-full.pyi index 3de9f934b255..739bf703f3e7 100644 --- a/test-data/unit/fixtures/typing-full.pyi +++ b/test-data/unit/fixtures/typing-full.pyi @@ -129,6 +129,10 @@ class Sequence(Iterable[T_co], Container[T_co]): @abstractmethod def __getitem__(self, n: Any) -> T_co: pass +class MutableSequence(Sequence[T]): + @abstractmethod + def __setitem__(self, n: Any, o: T) -> None: pass + class Mapping(Iterable[T], Generic[T, T_co], metaclass=ABCMeta): def __getitem__(self, key: T) -> T_co: pass @overload diff --git a/test-data/unit/fixtures/typing-medium.pyi b/test-data/unit/fixtures/typing-medium.pyi index 7717a6bf1749..923ede2f0c00 100644 --- a/test-data/unit/fixtures/typing-medium.pyi +++ b/test-data/unit/fixtures/typing-medium.pyi @@ -26,6 +26,7 @@ Literal = 0 TypedDict = 0 NoReturn = 0 NewType = 0 +TypeAlias = 0 T = TypeVar('T') T_co = TypeVar('T_co', covariant=True) diff --git a/test-data/unit/fixtures/typing-typeddict.pyi b/test-data/unit/fixtures/typing-typeddict.pyi index 72f500707094..378570b4c19c 100644 --- a/test-data/unit/fixtures/typing-typeddict.pyi +++ b/test-data/unit/fixtures/typing-typeddict.pyi @@ -43,7 +43,8 @@ class Iterator(Iterable[T_co], Protocol): def __next__(self) -> T_co: pass class Sequence(Iterable[T_co]): - def __getitem__(self, n: Any) -> T_co: pass + # misc is for explicit Any. + def __getitem__(self, n: Any) -> T_co: pass # type: ignore[misc] class Mapping(Iterable[T], Generic[T, T_co], metaclass=ABCMeta): def __getitem__(self, key: T) -> T_co: pass diff --git a/test-data/unit/lib-stub/attr/__init__.pyi b/test-data/unit/lib-stub/attr/__init__.pyi index 6ce4b3a64ed5..795e5d3f4f69 100644 --- a/test-data/unit/lib-stub/attr/__init__.pyi +++ b/test-data/unit/lib-stub/attr/__init__.pyi @@ -94,6 +94,7 @@ def attrs(maybe_cls: _C, cache_hash: bool = ..., eq: Optional[bool] = ..., order: Optional[bool] = ..., + match_args: bool = ..., ) -> _C: ... @overload def attrs(maybe_cls: None = ..., @@ -112,6 +113,7 @@ def attrs(maybe_cls: None = ..., cache_hash: bool = ..., eq: Optional[bool] = ..., order: Optional[bool] = ..., + match_args: bool = ..., ) -> Callable[[_C], _C]: ... diff --git a/test-data/unit/lib-stub/collections.pyi b/test-data/unit/lib-stub/collections.pyi index 71f797e565e8..7ea264f764ee 100644 --- a/test-data/unit/lib-stub/collections.pyi +++ b/test-data/unit/lib-stub/collections.pyi @@ -1,4 +1,4 @@ -from typing import Any, Iterable, Union, Optional, Dict, TypeVar, overload, Optional, Callable, Sized +from typing import Any, Iterable, Union, Dict, TypeVar, Optional, Callable, Generic, Sequence, MutableMapping def namedtuple( typename: str, @@ -20,6 +20,6 @@ class defaultdict(Dict[KT, VT]): class Counter(Dict[KT, int], Generic[KT]): ... -class deque(Sized, Iterable[KT], Reversible[KT], Generic[KT]): ... +class deque(Sequence[KT], Generic[KT]): ... class ChainMap(MutableMapping[KT, VT], Generic[KT, VT]): ... diff --git a/test-data/unit/lib-stub/dataclasses.pyi b/test-data/unit/lib-stub/dataclasses.pyi index e0491e14876b..bd33b459266c 100644 --- a/test-data/unit/lib-stub/dataclasses.pyi +++ b/test-data/unit/lib-stub/dataclasses.pyi @@ -15,7 +15,6 @@ def dataclass(*, init: bool = ..., repr: bool = ..., eq: bool = ..., order: bool unsafe_hash: bool = ..., frozen: bool = ..., match_args: bool = ..., kw_only: bool = ..., slots: bool = ...) -> Callable[[Type[_T]], Type[_T]]: ... - @overload def field(*, default: _T, init: bool = ..., repr: bool = ..., hash: Optional[bool] = ..., compare: bool = ..., diff --git a/test-data/unit/lib-stub/enum.pyi b/test-data/unit/lib-stub/enum.pyi index 2c1b03532a5b..11adfc597955 100644 --- a/test-data/unit/lib-stub/enum.pyi +++ b/test-data/unit/lib-stub/enum.pyi @@ -43,3 +43,8 @@ class IntFlag(int, Flag): class auto(IntFlag): value: Any + + +# It is python-3.11+ only: +class StrEnum(str, Enum): + def __new__(cls: Type[_T], value: str | _T) -> _T: ... diff --git a/test-data/unit/lib-stub/types.pyi b/test-data/unit/lib-stub/types.pyi index 6fc596ecbf13..3ac4945ef5a7 100644 --- a/test-data/unit/lib-stub/types.pyi +++ b/test-data/unit/lib-stub/types.pyi @@ -5,8 +5,6 @@ _T = TypeVar('_T') def coroutine(func: _T) -> _T: pass -class bool: ... - class ModuleType: __file__ = ... # type: str diff --git a/test-data/unit/lib-stub/typing.pyi b/test-data/unit/lib-stub/typing.pyi index b9f1752aee1b..1a6c5d36a367 100644 --- a/test-data/unit/lib-stub/typing.pyi +++ b/test-data/unit/lib-stub/typing.pyi @@ -23,6 +23,7 @@ Type = 0 ClassVar = 0 Final = 0 NoReturn = 0 +Never = 0 NewType = 0 ParamSpec = 0 @@ -47,3 +48,5 @@ class Sequence(Iterable[T_co]): class Mapping(Iterable[T], Generic[T, T_co]): pass def final(meth: T) -> T: pass + +def reveal_type(__obj: T) -> T: pass diff --git a/test-data/unit/lib-stub/typing_extensions.pyi b/test-data/unit/lib-stub/typing_extensions.pyi index 5b32449e71cf..38ff331f45d8 100644 --- a/test-data/unit/lib-stub/typing_extensions.pyi +++ b/test-data/unit/lib-stub/typing_extensions.pyi @@ -1,4 +1,4 @@ -from typing import TypeVar, Any, Mapping, Iterator, NoReturn, Dict, Type +from typing import TypeVar, Any, Mapping, Iterator, NoReturn as NoReturn, Dict, Type from typing import TYPE_CHECKING as TYPE_CHECKING from typing import NewType as NewType @@ -27,6 +27,7 @@ Concatenate: _SpecialForm TypeAlias: _SpecialForm TypeGuard: _SpecialForm +Never: _SpecialForm # Fallback type for all typed dicts (does not exist at runtime). class _TypedDict(Mapping[str, object]): @@ -44,3 +45,5 @@ class _TypedDict(Mapping[str, object]): def __delitem__(self, k: NoReturn) -> None: ... def TypedDict(typename: str, fields: Dict[str, Type[_T]], *, total: Any = ...) -> Type[dict]: ... + +def reveal_type(__obj: T) -> T: pass diff --git a/test-data/unit/merge.test b/test-data/unit/merge.test index 836ad87857f8..881e21bb1a92 100644 --- a/test-data/unit/merge.test +++ b/test-data/unit/merge.test @@ -665,21 +665,22 @@ TypeInfo<0>( Names()) TypeInfo<2>( Name(target.N) - Bases(builtins.tuple[target.A<0>]<3>) + Bases(builtins.tuple[target.A<0>, ...]<3>) Mro(target.N<2>, builtins.tuple<3>, typing.Sequence<4>, typing.Iterable<5>, builtins.object<1>) Names( _NT<6> __annotations__<7> (builtins.object<1>) __doc__<8> (builtins.str<9>) - __new__<10> - _asdict<11> - _field_defaults<12> (builtins.object<1>) - _field_types<13> (builtins.object<1>) - _fields<14> (Tuple[builtins.str<9>]) - _make<15> - _replace<16> - _source<17> (builtins.str<9>) - x<18> (target.A<0>))) + __match_args__<10> (Tuple[Literal['x']]) + __new__<11> + _asdict<12> + _field_defaults<13> (builtins.object<1>) + _field_types<14> (builtins.object<1>) + _fields<15> (Tuple[builtins.str<9>]) + _make<16> + _replace<17> + _source<18> (builtins.str<9>) + x<19> (target.A<0>))) ==> TypeInfo<0>( Name(target.A) @@ -688,22 +689,23 @@ TypeInfo<0>( Names()) TypeInfo<2>( Name(target.N) - Bases(builtins.tuple[target.A<0>]<3>) + Bases(builtins.tuple[target.A<0>, ...]<3>) Mro(target.N<2>, builtins.tuple<3>, typing.Sequence<4>, typing.Iterable<5>, builtins.object<1>) Names( _NT<6> __annotations__<7> (builtins.object<1>) __doc__<8> (builtins.str<9>) - __new__<10> - _asdict<11> - _field_defaults<12> (builtins.object<1>) - _field_types<13> (builtins.object<1>) - _fields<14> (Tuple[builtins.str<9>, builtins.str<9>]) - _make<15> - _replace<16> - _source<17> (builtins.str<9>) - x<18> (target.A<0>) - y<19> (target.A<0>))) + __match_args__<10> (Tuple[Literal['x'], Literal['y']]) + __new__<11> + _asdict<12> + _field_defaults<13> (builtins.object<1>) + _field_types<14> (builtins.object<1>) + _fields<15> (Tuple[builtins.str<9>, builtins.str<9>]) + _make<16> + _replace<17> + _source<18> (builtins.str<9>) + x<19> (target.A<0>) + y<20> (target.A<0>))) [case testUnionType_types] import target @@ -1435,7 +1437,7 @@ TypeInfo<0>( Bases(enum.Enum<1>) Mro(target.A<0>, enum.Enum<1>, builtins.object<2>) Names( - X<3> (builtins.int<4>)) + X<3> (Literal[0]?<4>)) MetaclassType(enum.EnumMeta<5>)) ==> TypeInfo<0>( @@ -1443,8 +1445,8 @@ TypeInfo<0>( Bases(enum.Enum<1>) Mro(target.A<0>, enum.Enum<1>, builtins.object<2>) Names( - X<3> (builtins.int<4>) - Y<6> (builtins.int<4>)) + X<3> (Literal[0]?<4>) + Y<6> (Literal[1]?<4>)) MetaclassType(enum.EnumMeta<5>)) [case testLiteralMerge] diff --git a/test-data/unit/parse-python310.test b/test-data/unit/parse-python310.test new file mode 100644 index 000000000000..87e0e9d5d283 --- /dev/null +++ b/test-data/unit/parse-python310.test @@ -0,0 +1,603 @@ +-- Test cases for parser -- Python 3.10 syntax (match statement) +-- +-- See parse.test for a description of this file format. + +[case testSimpleMatch] +match a: + case 1: + pass +[out] +MypyFile:1( + MatchStmt:1( + NameExpr(a) + Pattern( + ValuePattern:2( + IntExpr(1))) + Body( + PassStmt:3()))) + + +[case testTupleMatch] +match a, b: + case 1: + pass +[out] +MypyFile:1( + MatchStmt:1( + TupleExpr:1( + NameExpr(a) + NameExpr(b)) + Pattern( + ValuePattern:2( + IntExpr(1))) + Body( + PassStmt:3()))) + +[case testMatchWithGuard] +match a: + case 1 if f(): + pass + case d if d > 5: + pass +[out] +MypyFile:1( + MatchStmt:1( + NameExpr(a) + Pattern( + ValuePattern:2( + IntExpr(1))) + Guard( + CallExpr:2( + NameExpr(f) + Args())) + Body( + PassStmt:3()) + Pattern( + AsPattern:4( + NameExpr(d))) + Guard( + ComparisonExpr:4( + > + NameExpr(d) + IntExpr(5))) + Body( + PassStmt:5()))) + +[case testAsPattern] +match a: + case 1 as b: + pass +[out] +MypyFile:1( + MatchStmt:1( + NameExpr(a) + Pattern( + AsPattern:2( + ValuePattern:2( + IntExpr(1)) + NameExpr(b))) + Body( + PassStmt:3()))) + + +[case testLiteralPattern] +match a: + case 1: + pass + case -1: + pass + case 1+2j: + pass + case -1+2j: + pass + case 1-2j: + pass + case -1-2j: + pass + case "str": + pass + case b"bytes": + pass + case r"raw_string": + pass + case None: + pass + case True: + pass + case False: + pass +[out] +MypyFile:1( + MatchStmt:1( + NameExpr(a) + Pattern( + ValuePattern:2( + IntExpr(1))) + Body( + PassStmt:3()) + Pattern( + ValuePattern:4( + UnaryExpr:4( + - + IntExpr(1)))) + Body( + PassStmt:5()) + Pattern( + ValuePattern:6( + OpExpr:6( + + + IntExpr(1) + ComplexExpr(2j)))) + Body( + PassStmt:7()) + Pattern( + ValuePattern:8( + OpExpr:8( + + + UnaryExpr:8( + - + IntExpr(1)) + ComplexExpr(2j)))) + Body( + PassStmt:9()) + Pattern( + ValuePattern:10( + OpExpr:10( + - + IntExpr(1) + ComplexExpr(2j)))) + Body( + PassStmt:11()) + Pattern( + ValuePattern:12( + OpExpr:12( + - + UnaryExpr:12( + - + IntExpr(1)) + ComplexExpr(2j)))) + Body( + PassStmt:13()) + Pattern( + ValuePattern:14( + StrExpr(str))) + Body( + PassStmt:15()) + Pattern( + ValuePattern:16( + BytesExpr(bytes))) + Body( + PassStmt:17()) + Pattern( + ValuePattern:18( + StrExpr(raw_string))) + Body( + PassStmt:19()) + Pattern( + SingletonPattern:20()) + Body( + PassStmt:21()) + Pattern( + SingletonPattern:22( + True)) + Body( + PassStmt:23()) + Pattern( + SingletonPattern:24( + False)) + Body( + PassStmt:25()))) + +[case testCapturePattern] +match a: + case x: + pass + case longName: + pass +[out] +MypyFile:1( + MatchStmt:1( + NameExpr(a) + Pattern( + AsPattern:2( + NameExpr(x))) + Body( + PassStmt:3()) + Pattern( + AsPattern:4( + NameExpr(longName))) + Body( + PassStmt:5()))) + +[case testWildcardPattern] +match a: + case _: + pass +[out] +MypyFile:1( + MatchStmt:1( + NameExpr(a) + Pattern( + AsPattern:2()) + Body( + PassStmt:3()))) + +[case testValuePattern] +match a: + case b.c: + pass + case b.c.d.e.f: + pass +[out] +MypyFile:1( + MatchStmt:1( + NameExpr(a) + Pattern( + ValuePattern:2( + MemberExpr:2( + NameExpr(b) + c))) + Body( + PassStmt:3()) + Pattern( + ValuePattern:4( + MemberExpr:4( + MemberExpr:4( + MemberExpr:4( + MemberExpr:4( + NameExpr(b) + c) + d) + e) + f))) + Body( + PassStmt:5()))) + +[case testGroupPattern] +# This is optimized out by the compiler. It doesn't appear in the ast +match a: + case (1): + pass +[out] +MypyFile:1( + MatchStmt:2( + NameExpr(a) + Pattern( + ValuePattern:3( + IntExpr(1))) + Body( + PassStmt:4()))) + +[case testSequencePattern] +match a: + case []: + pass + case (): + pass + case [1]: + pass + case (1,): + pass + case 1,: + pass + case [1, 2, 3]: + pass + case (1, 2, 3): + pass + case 1, 2, 3: + pass + case [1, *a, 2]: + pass + case (1, *a, 2): + pass + case 1, *a, 2: + pass + case [1, *_, 2]: + pass + case (1, *_, 2): + pass + case 1, *_, 2: + pass +[out] +MypyFile:1( + MatchStmt:1( + NameExpr(a) + Pattern( + SequencePattern:2()) + Body( + PassStmt:3()) + Pattern( + SequencePattern:4()) + Body( + PassStmt:5()) + Pattern( + SequencePattern:6( + ValuePattern:6( + IntExpr(1)))) + Body( + PassStmt:7()) + Pattern( + SequencePattern:8( + ValuePattern:8( + IntExpr(1)))) + Body( + PassStmt:9()) + Pattern( + SequencePattern:10( + ValuePattern:10( + IntExpr(1)))) + Body( + PassStmt:11()) + Pattern( + SequencePattern:12( + ValuePattern:12( + IntExpr(1)) + ValuePattern:12( + IntExpr(2)) + ValuePattern:12( + IntExpr(3)))) + Body( + PassStmt:13()) + Pattern( + SequencePattern:14( + ValuePattern:14( + IntExpr(1)) + ValuePattern:14( + IntExpr(2)) + ValuePattern:14( + IntExpr(3)))) + Body( + PassStmt:15()) + Pattern( + SequencePattern:16( + ValuePattern:16( + IntExpr(1)) + ValuePattern:16( + IntExpr(2)) + ValuePattern:16( + IntExpr(3)))) + Body( + PassStmt:17()) + Pattern( + SequencePattern:18( + ValuePattern:18( + IntExpr(1)) + StarredPattern:18( + NameExpr(a)) + ValuePattern:18( + IntExpr(2)))) + Body( + PassStmt:19()) + Pattern( + SequencePattern:20( + ValuePattern:20( + IntExpr(1)) + StarredPattern:20( + NameExpr(a)) + ValuePattern:20( + IntExpr(2)))) + Body( + PassStmt:21()) + Pattern( + SequencePattern:22( + ValuePattern:22( + IntExpr(1)) + StarredPattern:22( + NameExpr(a)) + ValuePattern:22( + IntExpr(2)))) + Body( + PassStmt:23()) + Pattern( + SequencePattern:24( + ValuePattern:24( + IntExpr(1)) + StarredPattern:24() + ValuePattern:24( + IntExpr(2)))) + Body( + PassStmt:25()) + Pattern( + SequencePattern:26( + ValuePattern:26( + IntExpr(1)) + StarredPattern:26() + ValuePattern:26( + IntExpr(2)))) + Body( + PassStmt:27()) + Pattern( + SequencePattern:28( + ValuePattern:28( + IntExpr(1)) + StarredPattern:28() + ValuePattern:28( + IntExpr(2)))) + Body( + PassStmt:29()))) + +[case testMappingPattern] +match a: + case {'k': v}: + pass + case {a.b: v}: + pass + case {1: v}: + pass + case {a.c: v}: + pass + case {'k': v1, a.b: v2, 1: v3, a.c: v4}: + pass + case {'k1': 1, 'k2': "str", 'k3': b'bytes', 'k4': None}: + pass + case {'k': v, **r}: + pass + case {**r}: + pass +[out] +MypyFile:1( + MatchStmt:1( + NameExpr(a) + Pattern( + MappingPattern:2( + Key( + StrExpr(k)) + Value( + AsPattern:2( + NameExpr(v))))) + Body( + PassStmt:3()) + Pattern( + MappingPattern:4( + Key( + MemberExpr:4( + NameExpr(a) + b)) + Value( + AsPattern:4( + NameExpr(v))))) + Body( + PassStmt:5()) + Pattern( + MappingPattern:6( + Key( + IntExpr(1)) + Value( + AsPattern:6( + NameExpr(v))))) + Body( + PassStmt:7()) + Pattern( + MappingPattern:8( + Key( + MemberExpr:8( + NameExpr(a) + c)) + Value( + AsPattern:8( + NameExpr(v))))) + Body( + PassStmt:9()) + Pattern( + MappingPattern:10( + Key( + StrExpr(k)) + Value( + AsPattern:10( + NameExpr(v1))) + Key( + MemberExpr:10( + NameExpr(a) + b)) + Value( + AsPattern:10( + NameExpr(v2))) + Key( + IntExpr(1)) + Value( + AsPattern:10( + NameExpr(v3))) + Key( + MemberExpr:10( + NameExpr(a) + c)) + Value( + AsPattern:10( + NameExpr(v4))))) + Body( + PassStmt:11()) + Pattern( + MappingPattern:12( + Key( + StrExpr(k1)) + Value( + ValuePattern:12( + IntExpr(1))) + Key( + StrExpr(k2)) + Value( + ValuePattern:12( + StrExpr(str))) + Key( + StrExpr(k3)) + Value( + ValuePattern:12( + BytesExpr(bytes))) + Key( + StrExpr(k4)) + Value( + SingletonPattern:12()))) + Body( + PassStmt:13()) + Pattern( + MappingPattern:14( + Key( + StrExpr(k)) + Value( + AsPattern:14( + NameExpr(v))) + Rest( + NameExpr(r)))) + Body( + PassStmt:15()) + Pattern( + MappingPattern:16( + Rest( + NameExpr(r)))) + Body( + PassStmt:17()))) + +[case testClassPattern] +match a: + case A(): + pass + case B(1, 2): + pass + case B(1, b=2): + pass + case B(a=1, b=2): + pass +[out] +MypyFile:1( + MatchStmt:1( + NameExpr(a) + Pattern( + ClassPattern:2( + NameExpr(A))) + Body( + PassStmt:3()) + Pattern( + ClassPattern:4( + NameExpr(B) + Positionals( + ValuePattern:4( + IntExpr(1)) + ValuePattern:4( + IntExpr(2))))) + Body( + PassStmt:5()) + Pattern( + ClassPattern:6( + NameExpr(B) + Positionals( + ValuePattern:6( + IntExpr(1))) + Keyword( + b + ValuePattern:6( + IntExpr(2))))) + Body( + PassStmt:7()) + Pattern( + ClassPattern:8( + NameExpr(B) + Keyword( + a + ValuePattern:8( + IntExpr(1))) + Keyword( + b + ValuePattern:8( + IntExpr(2))))) + Body( + PassStmt:9()))) diff --git a/test-data/unit/parse.test b/test-data/unit/parse.test index 7f3694120b12..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,7 +946,7 @@ 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] diff --git a/test-data/unit/pep561.test b/test-data/unit/pep561.test index 839ca110b94c..364414b202e1 100644 --- a/test-data/unit/pep561.test +++ b/test-data/unit/pep561.test @@ -18,7 +18,7 @@ from typedpkg import dne a = ex(['']) reveal_type(a) [out] -testTypedPkgSimple.py:5: note: Revealed type is "builtins.tuple[builtins.str]" +testTypedPkgSimple.py:5: note: Revealed type is "builtins.tuple[builtins.str, ...]" [case testTypedPkgSimplePackageSearchPath] # pkgs: typedpkg @@ -89,7 +89,7 @@ from typedpkg import dne a = ex(['']) reveal_type(a) [out] -testTypedPkgSimple_python2.py:5: note: Revealed type is "builtins.tuple[builtins.str]" +testTypedPkgSimple_python2.py:5: note: Revealed type is "builtins.tuple[builtins.str, ...]" [case testTypedPkgSimpleEgg] # pkgs: typedpkg; no-pip @@ -98,7 +98,7 @@ from typedpkg import dne a = ex(['']) reveal_type(a) [out] -testTypedPkgSimpleEgg.py:5: note: Revealed type is "builtins.tuple[builtins.str]" +testTypedPkgSimpleEgg.py:5: note: Revealed type is "builtins.tuple[builtins.str, ...]" [case testTypedPkgSimpleEditable] # pkgs: typedpkg; editable @@ -107,7 +107,7 @@ from typedpkg import dne a = ex(['']) reveal_type(a) [out] -testTypedPkgSimpleEditable.py:5: note: Revealed type is "builtins.tuple[builtins.str]" +testTypedPkgSimpleEditable.py:5: note: Revealed type is "builtins.tuple[builtins.str, ...]" [case testTypedPkgSimpleEditableEgg] # pkgs: typedpkg; editable; no-pip @@ -116,7 +116,7 @@ from typedpkg import dne a = ex(['']) reveal_type(a) [out] -testTypedPkgSimpleEditableEgg.py:5: note: Revealed type is "builtins.tuple[builtins.str]" +testTypedPkgSimpleEditableEgg.py:5: note: Revealed type is "builtins.tuple[builtins.str, ...]" [case testTypedPkgNamespaceImportFrom] # pkgs: typedpkg, typedpkg_ns_a diff --git a/test-data/unit/pythoneval-asyncio.test b/test-data/unit/pythoneval-asyncio.test index ffa40a8da68f..b3400fe6010e 100644 --- a/test-data/unit/pythoneval-asyncio.test +++ b/test-data/unit/pythoneval-asyncio.test @@ -346,7 +346,7 @@ from typing import Generator, Any import asyncio from asyncio import Future -asyncio.coroutine +@asyncio.coroutine def slow_operation(future: 'Future[int]') -> 'Generator[Any, None, None]': yield from asyncio.sleep(1) future.set_result('42') #Try to set an str as result to a Future[int] diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 90588a86d8bf..de15055927ae 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -271,8 +271,8 @@ f.write('x') f.write(b'x') f.foobar() [out] -_program.py:3: error: Argument 1 to "write" of "IO" has incompatible type "bytes"; expected "str" -_program.py:4: error: "TextIO" has no attribute "foobar" +_program.py:3: error: Argument 1 to "write" of "TextIOBase" has incompatible type "bytes"; expected "str" +_program.py:4: error: "TextIOWrapper" has no attribute "foobar" [case testOpenReturnTypeInference] reveal_type(open('x')) @@ -281,9 +281,9 @@ reveal_type(open('x', 'rb')) mode = 'rb' reveal_type(open('x', mode)) [out] -_program.py:1: note: Revealed type is "typing.TextIO" -_program.py:2: note: Revealed type is "typing.TextIO" -_program.py:3: note: Revealed type is "typing.BinaryIO" +_program.py:1: note: Revealed type is "io.TextIOWrapper" +_program.py:2: note: Revealed type is "io.TextIOWrapper" +_program.py:3: note: Revealed type is "io.BufferedReader" _program.py:5: note: Revealed type is "typing.IO[Any]" [case testOpenReturnTypeInferenceSpecialCases] @@ -292,8 +292,8 @@ reveal_type(open(file='x', mode='rb')) mode = 'rb' reveal_type(open(mode=mode, file='r')) [out] -_testOpenReturnTypeInferenceSpecialCases.py:1: note: Revealed type is "typing.BinaryIO" -_testOpenReturnTypeInferenceSpecialCases.py:2: note: Revealed type is "typing.BinaryIO" +_testOpenReturnTypeInferenceSpecialCases.py:1: note: Revealed type is "io.BufferedReader" +_testOpenReturnTypeInferenceSpecialCases.py:2: note: Revealed type is "io.BufferedReader" _testOpenReturnTypeInferenceSpecialCases.py:4: note: Revealed type is "typing.IO[Any]" [case testPathOpenReturnTypeInference] @@ -305,21 +305,21 @@ reveal_type(p.open('rb')) mode = 'rb' reveal_type(p.open(mode)) [out] -_program.py:3: note: Revealed type is "typing.TextIO" -_program.py:4: note: Revealed type is "typing.TextIO" -_program.py:5: note: Revealed type is "typing.BinaryIO" +_program.py:3: note: Revealed type is "io.TextIOWrapper" +_program.py:4: note: Revealed type is "io.TextIOWrapper" +_program.py:5: note: Revealed type is "io.BufferedReader" _program.py:7: note: Revealed type is "typing.IO[Any]" [case testPathOpenReturnTypeInferenceSpecialCases] from pathlib import Path p = Path("x") -reveal_type(p.open(mode='rb', errors='replace')) -reveal_type(p.open(errors='replace', mode='rb')) -mode = 'rb' +reveal_type(p.open(mode='r', errors='replace')) +reveal_type(p.open(errors='replace', mode='r')) +mode = 'r' reveal_type(p.open(mode=mode, errors='replace')) [out] -_program.py:3: note: Revealed type is "typing.BinaryIO" -_program.py:4: note: Revealed type is "typing.BinaryIO" +_program.py:3: note: Revealed type is "io.TextIOWrapper" +_program.py:4: note: Revealed type is "io.TextIOWrapper" _program.py:6: note: Revealed type is "typing.IO[Any]" [case testGenericPatterns] @@ -1112,7 +1112,7 @@ c2 = Cell2() reveal_type(c2.pop('value')) [out] _testTypedDictMappingMethods.py:5: note: Revealed type is "builtins.str*" -_testTypedDictMappingMethods.py:6: note: Revealed type is "typing.Iterator[builtins.str*]" +_testTypedDictMappingMethods.py:6: note: Revealed type is "typing.Iterator*[builtins.str*]" _testTypedDictMappingMethods.py:7: note: Revealed type is "builtins.int" _testTypedDictMappingMethods.py:8: note: Revealed type is "builtins.bool" _testTypedDictMappingMethods.py:9: note: Revealed type is "typing.KeysView[builtins.str]" @@ -1152,7 +1152,8 @@ _testCanConvertTypedDictToAnySuperclassOfMapping.py:11: note: def __iter _testCanConvertTypedDictToAnySuperclassOfMapping.py:11: note: Got: _testCanConvertTypedDictToAnySuperclassOfMapping.py:11: note: def __iter__(self) -> Iterator[str] -[case testAsyncioGatherPreciseType] +[case testAsyncioGatherPreciseType-xfail] +# Mysteriously regressed in #11905 import asyncio from typing import Tuple @@ -1328,7 +1329,7 @@ def f() -> Dict[int, str]: def d() -> Dict[int, int]: return {} [out] -_testDictWithStarStarSpecialCase.py:4: error: Argument 1 to "update" of "dict" has incompatible type "Dict[int, int]"; expected "Mapping[int, str]" +_testDictWithStarStarSpecialCase.py:4: error: Argument 1 to "update" of "MutableMapping" has incompatible type "Dict[int, int]"; expected "SupportsKeysAndGetItem[int, str]" [case testLoadsOfOverloads] from typing import overload, Any, TypeVar, Iterable, List, Dict, Callable, Union @@ -1411,7 +1412,7 @@ 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: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" @@ -1573,3 +1574,15 @@ 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]" + +[case testEnumValueWithPlaceholderNodeType] +# https://github.com/python/mypy/issues/11971 +from enum import Enum +from typing import Callable, Dict +class Foo(Enum): + Bar: Foo = Callable[[str], None] + Baz: Foo = Callable[[Dict[str, "Missing"]], None] +[out] +_testEnumValueWithPlaceholderNodeType.py:5: error: Incompatible types in assignment (expression has type "object", variable has type "Foo") +_testEnumValueWithPlaceholderNodeType.py:6: error: Incompatible types in assignment (expression has type "object", variable has type "Foo") +_testEnumValueWithPlaceholderNodeType.py:6: error: Name "Missing" is not defined diff --git a/test-data/unit/semanal-classes.test b/test-data/unit/semanal-classes.test index 3d62fed2b5e7..082a3fe69050 100644 --- a/test-data/unit/semanal-classes.test +++ b/test-data/unit/semanal-classes.test @@ -582,7 +582,7 @@ MypyFile:1( TupleType( Tuple[builtins.int, builtins.str]) BaseType( - builtins.tuple[builtins.object]) + builtins.tuple[builtins.object, ...]) PassStmt:2())) [case testBaseClassFromIgnoredModule] diff --git a/test-data/unit/semanal-errors-python310.test b/test-data/unit/semanal-errors-python310.test new file mode 100644 index 000000000000..68c158cddae6 --- /dev/null +++ b/test-data/unit/semanal-errors-python310.test @@ -0,0 +1,43 @@ +[case testMatchUndefinedSubject] +import typing +match x: + case _: + pass +[out] +main:2: error: Name "x" is not defined + +[case testMatchUndefinedValuePattern] +import typing +x = 1 +match x: + case a.b: + pass +[out] +main:4: error: Name "a" is not defined + +[case testMatchUndefinedClassPattern] +import typing +x = 1 +match x: + case A(): + pass +[out] +main:4: error: Name "A" is not defined + +[case testNoneBindingWildcardPattern] +import typing +x = 1 +match x: + case _: + _ +[out] +main:5: error: Name "_" is not defined + +[case testNoneBindingStarredWildcardPattern] +import typing +x = 1 +match x: + case [*_]: + _ +[out] +main:5: error: Name "_" is not defined diff --git a/test-data/unit/semanal-errors.test b/test-data/unit/semanal-errors.test index e5aea483a210..4b1f4ce00da7 100644 --- a/test-data/unit/semanal-errors.test +++ b/test-data/unit/semanal-errors.test @@ -1435,3 +1435,10 @@ TP = ParamSpec('?') # E: String argument 1 "?" to ParamSpec(...) does not match TP2: int = ParamSpec('TP2') # E: Cannot declare the type of a parameter specification [out] + + +[case testBaseClassAnnotatedWithoutArgs] +# https://github.com/python/mypy/issues/11808 +from typing_extensions import Annotated +# Next line should not crash: +class A(Annotated): pass # E: Annotated[...] must have exactly one type argument and at least one annotation diff --git a/test-data/unit/semanal-modules.test b/test-data/unit/semanal-modules.test index 86bb82d7bd69..16b9a9b18250 100644 --- a/test-data/unit/semanal-modules.test +++ b/test-data/unit/semanal-modules.test @@ -568,7 +568,7 @@ MypyFile:1( ImportFrom:2(_x, [y]) AssignmentStmt:3( NameExpr(z* [m]) - NameExpr(y [_x.y])))) + NameExpr(y [__main__.A.y])))) [case testImportInClassBody2] class A: diff --git a/test-data/unit/semanal-python2.test b/test-data/unit/semanal-python2.test index 97264a5dc503..8bb0f5cf5d9c 100644 --- a/test-data/unit/semanal-python2.test +++ b/test-data/unit/semanal-python2.test @@ -45,7 +45,7 @@ MypyFile:1( ExpressionStmt:2( CastExpr:2( TupleExpr:2() - builtins.tuple[builtins.int]))) + builtins.tuple[builtins.int, ...]))) [case testTupleArgList_python2] def f(x, (y, z)): diff --git a/test-data/unit/semanal-python310.test b/test-data/unit/semanal-python310.test new file mode 100644 index 000000000000..a009636575dc --- /dev/null +++ b/test-data/unit/semanal-python310.test @@ -0,0 +1,204 @@ +-- Python 3.10 semantic analysis test cases. + +[case testCapturePattern] +x = 1 +match x: + case a: + a +[out] +MypyFile:1( + AssignmentStmt:1( + NameExpr(x* [__main__.x]) + IntExpr(1)) + MatchStmt:2( + NameExpr(x [__main__.x]) + Pattern( + AsPattern:3( + NameExpr(a* [__main__.a]))) + Body( + ExpressionStmt:4( + NameExpr(a [__main__.a]))))) + +[case testCapturePatternOutliving] +x = 1 +match x: + case a: + pass +a +[out] +MypyFile:1( + AssignmentStmt:1( + NameExpr(x* [__main__.x]) + IntExpr(1)) + MatchStmt:2( + NameExpr(x [__main__.x]) + Pattern( + AsPattern:3( + NameExpr(a* [__main__.a]))) + Body( + PassStmt:4())) + ExpressionStmt:5( + NameExpr(a [__main__.a]))) + +[case testNestedCapturePatterns] +x = 1 +match x: + case ([a], {'k': b}): + a + b +[out] +MypyFile:1( + AssignmentStmt:1( + NameExpr(x* [__main__.x]) + IntExpr(1)) + MatchStmt:2( + NameExpr(x [__main__.x]) + Pattern( + SequencePattern:3( + SequencePattern:3( + AsPattern:3( + NameExpr(a* [__main__.a]))) + MappingPattern:3( + Key( + StrExpr(k)) + Value( + AsPattern:3( + NameExpr(b* [__main__.b])))))) + Body( + ExpressionStmt:4( + NameExpr(a [__main__.a])) + ExpressionStmt:5( + NameExpr(b [__main__.b]))))) + +[case testMappingPatternRest] +x = 1 +match x: + case {**r}: + r +[out] +MypyFile:1( + AssignmentStmt:1( + NameExpr(x* [__main__.x]) + IntExpr(1)) + MatchStmt:2( + NameExpr(x [__main__.x]) + Pattern( + MappingPattern:3( + Rest( + NameExpr(r* [__main__.r])))) + Body( + ExpressionStmt:4( + NameExpr(r [__main__.r]))))) + + +[case testAsPattern] +x = 1 +match x: + case 1 as a: + a +[out] +MypyFile:1( + AssignmentStmt:1( + NameExpr(x* [__main__.x]) + IntExpr(1)) + MatchStmt:2( + NameExpr(x [__main__.x]) + Pattern( + AsPattern:3( + ValuePattern:3( + IntExpr(1)) + NameExpr(a* [__main__.a]))) + Body( + ExpressionStmt:4( + NameExpr(a [__main__.a]))))) + +[case testGuard] +x = 1 +a = 1 +match x: + case 1 if a: + pass +[out] +MypyFile:1( + AssignmentStmt:1( + NameExpr(x* [__main__.x]) + IntExpr(1)) + AssignmentStmt:2( + NameExpr(a* [__main__.a]) + IntExpr(1)) + MatchStmt:3( + NameExpr(x [__main__.x]) + Pattern( + ValuePattern:4( + IntExpr(1))) + Guard( + NameExpr(a [__main__.a])) + Body( + PassStmt:5()))) + +[case testCapturePatternInGuard] +x = 1 +match x: + case a if a: + pass +[out] +MypyFile:1( + AssignmentStmt:1( + NameExpr(x* [__main__.x]) + IntExpr(1)) + MatchStmt:2( + NameExpr(x [__main__.x]) + Pattern( + AsPattern:3( + NameExpr(a* [__main__.a]))) + Guard( + NameExpr(a [__main__.a])) + Body( + PassStmt:4()))) + +[case testAsPatternInGuard] +x = 1 +match x: + case 1 as a if a: + pass +[out] +MypyFile:1( + AssignmentStmt:1( + NameExpr(x* [__main__.x]) + IntExpr(1)) + MatchStmt:2( + NameExpr(x [__main__.x]) + Pattern( + AsPattern:3( + ValuePattern:3( + IntExpr(1)) + NameExpr(a* [__main__.a]))) + Guard( + NameExpr(a [__main__.a])) + Body( + PassStmt:4()))) + +[case testValuePattern] +import _a + +x = 1 +match x: + case _a.b: + pass +[file _a.py] +b = 1 +[out] +MypyFile:1( + Import:1(_a) + AssignmentStmt:3( + NameExpr(x* [__main__.x]) + IntExpr(1)) + MatchStmt:4( + NameExpr(x [__main__.x]) + Pattern( + ValuePattern:5( + MemberExpr:5( + NameExpr(_a) + b [_a.b]))) + Body( + PassStmt:6()))) diff --git a/test-data/unit/semanal-statements.test b/test-data/unit/semanal-statements.test index 97dd5f048834..fdc5ca2bbbdd 100644 --- a/test-data/unit/semanal-statements.test +++ b/test-data/unit/semanal-statements.test @@ -1058,3 +1058,59 @@ MypyFile:1( AssignmentStmt:6( NameExpr(x [__main__.x]) StrExpr())) + +[case testSimpleWithRenaming] +with 0 as y: + z = y +with 1 as y: + y = 1 +[out] +MypyFile:1( + WithStmt:1( + Expr( + IntExpr(0)) + Target( + NameExpr(y'* [__main__.y'])) + Block:1( + AssignmentStmt:2( + NameExpr(z* [__main__.z]) + NameExpr(y' [__main__.y'])))) + WithStmt:3( + Expr( + IntExpr(1)) + Target( + NameExpr(y* [__main__.y])) + Block:3( + AssignmentStmt:4( + NameExpr(y [__main__.y]) + IntExpr(1))))) + +[case testSimpleWithRenamingFailure] +with 0 as y: + z = y +zz = y +with 1 as y: + y = 1 +[out] +MypyFile:1( + WithStmt:1( + Expr( + IntExpr(0)) + Target( + NameExpr(y* [__main__.y])) + Block:1( + AssignmentStmt:2( + NameExpr(z* [__main__.z]) + NameExpr(y [__main__.y])))) + AssignmentStmt:3( + NameExpr(zz* [__main__.zz]) + NameExpr(y [__main__.y])) + WithStmt:4( + Expr( + IntExpr(1)) + Target( + NameExpr(y [__main__.y])) + Block:4( + AssignmentStmt:5( + NameExpr(y [__main__.y]) + IntExpr(1))))) diff --git a/test-data/unit/semanal-typeddict.test b/test-data/unit/semanal-typeddict.test index 4a74dc6e1cf3..b9eb6e0c2b13 100644 --- a/test-data/unit/semanal-typeddict.test +++ b/test-data/unit/semanal-typeddict.test @@ -1,17 +1,5 @@ -- Create Type --- TODO: Implement support for this syntax. ---[case testCanCreateTypedDictTypeWithKeywordArguments] ---from mypy_extensions import TypedDict ---Point = TypedDict('Point', x=int, y=int) ---[builtins fixtures/dict.pyi] ---[out] ---MypyFile:1( --- ImportFrom:1(mypy_extensions, [TypedDict]) --- AssignmentStmt:2( --- NameExpr(Point* [__main__.Point]) --- TypedDictExpr:2(Point))) - -- TODO: Implement support for this syntax. --[case testCanCreateTypedDictTypeWithDictCall] --from mypy_extensions import TypedDict diff --git a/test-data/unit/semanal-types.test b/test-data/unit/semanal-types.test index 772de61b5900..1a2eca64a9f2 100644 --- a/test-data/unit/semanal-types.test +++ b/test-data/unit/semanal-types.test @@ -679,7 +679,7 @@ MypyFile:1( AssignmentStmt:2( NameExpr(t [__main__.t]) NameExpr(None [builtins.None]) - builtins.tuple[Any]) + builtins.tuple[Any, ...]) AssignmentStmt:3( NameExpr(t1 [__main__.t1]) NameExpr(None [builtins.None]) @@ -699,7 +699,7 @@ MypyFile:1( AssignmentStmt:2( NameExpr(t [__main__.t]) NameExpr(None [builtins.None]) - builtins.tuple[builtins.int])) + builtins.tuple[builtins.int, ...])) [case testInvalidTupleType] from typing import Tuple diff --git a/test-data/unit/stubgen.test b/test-data/unit/stubgen.test index e20073027db2..6592791f9aa3 100644 --- a/test-data/unit/stubgen.test +++ b/test-data/unit/stubgen.test @@ -2580,3 +2580,8 @@ class A: def f(x: int, y: int) -> int: ... @t.overload def f(x: t.Tuple[int, int]) -> int: ... + +[case testNonDefaultKeywordOnlyArgAfterAsterisk] +def func(*, non_default_kwarg: bool, default_kwarg: bool = True): ... +[out] +def func(*, non_default_kwarg: bool, default_kwarg: bool = ...): ... diff --git a/test-requirements.txt b/test-requirements.txt index c5db79ada816..a3d11872fd5c 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,12 +2,13 @@ -r build-requirements.txt attrs>=18.0 flake8==3.9.2 -flake8-bugbear +flake8-bugbear==22.3.20 flake8-pyi>=20.5 -lxml>=4.4.0 +lxml>=4.4.0; python_version<'3.11' psutil>=4.0 -pytest>=6.2.0,<7.0.0 -pytest-xdist>=1.34.0,<2.0.0 +# pytest 6.2.3 does not support Python 3.10 +pytest>=6.2.4 +pytest-xdist>=1.34.0 pytest-forked>=1.3.0,<2.0.0 pytest-cov>=2.10.0,<3.0.0 py>=1.5.2