aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfrankfeng <frankfeng@google.com>2022-04-13 19:34:52 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-04-13 19:34:52 +0000
commitb0aec83bb2188fa7dec840f6c04dfa1e3da8b9a7 (patch)
tree04520eb0a7356d8ee8e8251ebcf2c6c317bbe65f
parentf75a81beb5413e7e846e60de4e693a29ad65b714 (diff)
parent422e644ed74f09f648592f40218dc28a1ee566a1 (diff)
downloadtyping-b0aec83bb2188fa7dec840f6c04dfa1e3da8b9a7.tar.gz
Merge remote-tracking branch 'aosp/upstream-master' into typing am: a90fb3c4d9 am: f8e1873b59 am: 2ef2783001 am: f6ac0eb79f am: 422e644ed7
Original change: https://android-review.googlesource.com/c/platform/external/python/typing/+/2063011 Change-Id: I61ae84f3df5929a667c96344f1c5ddd5f8856fe2 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.editorconfig12
-rw-r--r--.flake815
-rw-r--r--.flake8-tests28
-rw-r--r--.github/ISSUE_TEMPLATE/documentation-issue.md10
-rw-r--r--.github/ISSUE_TEMPLATE/new-typing-feature.md10
-rw-r--r--.github/ISSUE_TEMPLATE/other-issue.md10
-rw-r--r--.github/ISSUE_TEMPLATE/typing-extensions-issue.md10
-rw-r--r--.github/workflows/build-docs.yml26
-rw-r--r--.github/workflows/ci.yml64
-rw-r--r--.github/workflows/package.yml71
-rw-r--r--.gitignore17
-rw-r--r--CONTRIBUTING.md55
-rw-r--r--LICENSE254
-rw-r--r--METADATA16
-rw-r--r--MODULE_LICENSE_GPL0
-rw-r--r--NOTICE254
-rw-r--r--OWNERS8
-rw-r--r--README.md41
-rw-r--r--docs/Makefile46
-rw-r--r--docs/README.rst50
-rw-r--r--docs/conf.py55
-rw-r--r--docs/index.rst99
-rw-r--r--docs/make.bat35
-rw-r--r--docs/requirements.txt10
-rw-r--r--docs/source/annotations.rst68
-rw-r--r--docs/source/basics.rst3
-rw-r--r--docs/source/dependencies.rst12
-rw-r--r--docs/source/faq.rst23
-rw-r--r--docs/source/guides.rst10
-rw-r--r--docs/source/inference.rst28
-rw-r--r--docs/source/introduction.rst41
-rw-r--r--docs/source/libraries.rst602
-rw-r--r--docs/source/quality.rst200
-rw-r--r--docs/source/reference.rst22
-rw-r--r--docs/source/stubs.rst1129
-rw-r--r--docs/source/type_compatibility.rst17
-rw-r--r--docs/source/type_system.rst58
-rw-r--r--docs/source/unreachable.rst148
-rw-r--r--scripts/requirements.txt2
-rwxr-xr-xscripts/typing-summary.py144
-rw-r--r--test-requirements.txt3
-rw-r--r--typing_extensions/CHANGELOG71
-rw-r--r--typing_extensions/LICENSE254
-rw-r--r--typing_extensions/README.rst146
-rw-r--r--typing_extensions/pyproject.toml58
-rw-r--r--typing_extensions/src/test_typing_extensions.py2779
-rw-r--r--typing_extensions/src/typing_extensions.py1882
-rw-r--r--typing_extensions/tox.ini7
48 files changed, 8903 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..26fb670
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,12 @@
+root = true
+
+[*.{py,pyi,rst,md,yml,yaml,toml,json}]
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = space
+
+[*.{py,pyi,toml,json}]
+indent_size = 4
+
+[*.{yml,yaml}]
+indent_size = 2
diff --git a/.flake8 b/.flake8
new file mode 100644
index 0000000..53cf55a
--- /dev/null
+++ b/.flake8
@@ -0,0 +1,15 @@
+[flake8]
+
+max-line-length = 90
+ignore =
+ # irrelevant plugins
+ B3,
+ DW12,
+ # code is sometimes better without this
+ E129,
+ # consistency with mypy
+ W504
+exclude =
+ # tests have more relaxed formatting rules
+ # and its own specific config in .flake8-tests
+ typing_extensions/src/test_typing_extensions.py,
diff --git a/.flake8-tests b/.flake8-tests
new file mode 100644
index 0000000..5a97fe8
--- /dev/null
+++ b/.flake8-tests
@@ -0,0 +1,28 @@
+# This configuration is specific to test_*.py; you need to invoke it
+# by specifically naming this config, like this:
+#
+# $ flake8 --config=.flake8-tests [SOURCES]
+#
+# This will be possibly merged in the future.
+
+[flake8]
+max-line-length = 100
+ignore =
+ # temporary ignores until we sort it out
+ B017,
+ E302,
+ E303,
+ E306,
+ E501,
+ E701,
+ E704,
+ F722,
+ F811,
+ F821,
+ F841,
+ W503,
+ # irrelevant plugins
+ B3,
+ DW12,
+ # consistency with mypy
+ W504
diff --git a/.github/ISSUE_TEMPLATE/documentation-issue.md b/.github/ISSUE_TEMPLATE/documentation-issue.md
new file mode 100644
index 0000000..6122c8f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/documentation-issue.md
@@ -0,0 +1,10 @@
+---
+name: Documentation issue
+about: Report a problem or suggest changes for the documentation at https://typing.readthedocs.io/
+title: ''
+labels: 'topic: documentation'
+assignees: ''
+
+---
+
+<!-- Please describe the problem or your idea or suggestion below. Please include the URL of the page this issue is about, if applicable. -->
diff --git a/.github/ISSUE_TEMPLATE/new-typing-feature.md b/.github/ISSUE_TEMPLATE/new-typing-feature.md
new file mode 100644
index 0000000..733df29
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/new-typing-feature.md
@@ -0,0 +1,10 @@
+---
+name: New typing feature
+about: Suggest a new feature for Python's typing system
+title: ''
+labels: 'topic: feature'
+assignees: ''
+
+---
+
+<!-- Please describe the problem you face as well as your idea below, ideally using examples for both. -->
diff --git a/.github/ISSUE_TEMPLATE/other-issue.md b/.github/ISSUE_TEMPLATE/other-issue.md
new file mode 100644
index 0000000..484282c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/other-issue.md
@@ -0,0 +1,10 @@
+---
+name: Other issue
+about: Report any other issue
+title: ''
+labels: 'topic: other'
+assignees: ''
+
+---
+
+<!-- Please describe your issue below. -->
diff --git a/.github/ISSUE_TEMPLATE/typing-extensions-issue.md b/.github/ISSUE_TEMPLATE/typing-extensions-issue.md
new file mode 100644
index 0000000..226796e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/typing-extensions-issue.md
@@ -0,0 +1,10 @@
+---
+name: typing-extensions issue
+about: Report a problem or suggest changes for the typing-extensions library
+title: ''
+labels: 'topic: typing-extensions'
+assignees: ''
+
+---
+
+<!-- Please describe your problem or suggestion below, ideally using code examples. Please state which version of Python and typing-extensions you are using. -->
diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml
new file mode 100644
index 0000000..43711d0
--- /dev/null
+++ b/.github/workflows/build-docs.yml
@@ -0,0 +1,26 @@
+name: Build the documentation
+
+on:
+ pull_request:
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+
+ name: Build documentation
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.9
+ - name: Install dependencies
+ run: |
+ pip install --upgrade pip
+ pip install -r docs/requirements.txt
+ - name: Build the documentation
+ run: make -C docs html
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..302b2ca
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,64 @@
+name: Test and lint
+
+on:
+ push:
+ pull_request:
+
+permissions:
+ contents: read
+
+jobs:
+ tests:
+ name: Run tests
+
+ strategy:
+ fail-fast: false
+ matrix:
+ # We try to test on the earliest available bugfix release of each
+ # Python version, because typing sometimes changed between bugfix releases.
+ # For available versions, see:
+ # https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json
+ python-version: ["3.7", "3.7.1", "3.8", "3.8.0", "3.9", "3.9.0", "3.10", "3.10.0", "3.11-dev"]
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Set up Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Test typing_extensions
+ continue-on-error: ${{ matrix.python-version == '3.11-dev' }}
+ run: |
+ # Be wary of running `pip install` here, since it becomes easy for us to
+ # accidentally pick up typing_extensions as installed by a dependency
+ cd typing_extensions/src
+ python -m unittest test_typing_extensions.py
+
+ linting:
+ name: Lint
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python 3
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3
+ cache: "pip"
+ cache-dependency-path: "test-requirements.txt"
+
+ - name: Install dependencies
+ run: |
+ pip install --upgrade pip
+ pip install -r test-requirements.txt
+
+ - name: Lint implementation
+ run: flake8
+
+ - name: Lint tests
+ run: flake8 --config=.flake8-tests typing_extensions/src/test_typing_extensions.py
diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml
new file mode 100644
index 0000000..25f9586
--- /dev/null
+++ b/.github/workflows/package.yml
@@ -0,0 +1,71 @@
+name: Test packaging
+
+on:
+ push:
+ pull_request:
+
+permissions:
+ contents: read
+
+jobs:
+ wheel:
+ name: Test wheel install
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Set up Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3
+
+ - name: Install pypa/build
+ run: |
+ # Be wary of running `pip install` here, since it becomes easy for us to
+ # accidentally pick up typing_extensions as installed by a dependency
+ python -m pip install --upgrade build
+ python -m pip list
+
+ - name: Build and install wheel
+ run: |
+ cd typing_extensions
+ python -m build .
+ export path_to_file=$(find dist -type f -name "typing_extensions-*.whl")
+ echo "::notice::Installing wheel: $path_to_file"
+ pip install -vvv $path_to_file
+ python -m pip list
+
+ - name: Attempt to import typing_extensions
+ run: python -c "import typing_extensions; print(typing_extensions.__all__)"
+
+ sdist:
+ name: Test sdist install
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Set up Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3
+
+ - name: Install pypa/build
+ run: |
+ # Be wary of running `pip install` here, since it becomes easy for us to
+ # accidentally pick up typing_extensions as installed by a dependency
+ python -m pip install --upgrade build
+ python -m pip list
+
+ - name: Build and install sdist
+ run: |
+ cd typing_extensions
+ python -m build .
+ export path_to_file=$(find dist -type f -name "typing_extensions-*.tar.gz")
+ echo "::notice::Installing sdist: $path_to_file"
+ pip install -vvv $path_to_file
+ python -m pip list
+
+ - name: Attempt to import typing_extensions
+ run: python -c "import typing_extensions; print(typing_extensions.__all__)"
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0ad58f4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,17 @@
+MANIFEST
+
+__pycache__/
+build/
+dist/
+tmp/
+venv*/
+
+.cache/
+.idea/
+.tox/
+.venv*/
+.vscode/
+
+*.swp
+*.pyc
+*.egg-info/
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..095e826
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,55 @@
+Code in this repository should follow CPython's style guidelines and
+contributors need to sign the PSF Contributor Agreement.
+
+# typing\_extensions
+
+The `typing_extensions` module provides a way to access new features from the standard
+library `typing` module in older versions of Python. For example, Python 3.10 adds
+`typing.TypeGuard`, but users of older versions of Python can use `typing_extensions` to
+use `TypeGuard` in their code even if they are unable to upgrade to Python 3.10.
+
+If you contribute the runtime implementation of a new `typing` feature to CPython, you
+are encouraged to also implement the feature in `typing_extensions`. Because the runtime
+implementation of much of the infrastructure in the `typing` module has changed over
+time, this may require different code for some older Python versions.
+
+`typing_extensions` may also include experimental features that are not yet part of the
+standard library, so that users can experiment with them before they are added to the
+standard library. Such features should ideally already be specified in a PEP or draft
+PEP.
+
+`typing_extensions` supports Python versions 3.7 and up.
+
+# Versioning scheme
+
+Starting with version 4.0.0, `typing_extensions` uses
+[Semantic Versioning](https://semver.org/). The major version is incremented for all
+backwards-incompatible changes.
+
+# Workflow for PyPI releases
+
+- Ensure that GitHub Actions reports no errors.
+
+- Update the version number in `typing_extensions/pyproject.toml` and in
+ `typing_extensions/CHANGELOG`.
+
+- Make sure your environment is up to date
+
+ - `git checkout master`
+ - `git pull`
+ - `python -m pip install --upgrade build twine`
+
+- Build the source and wheel distributions:
+
+ - `cd typing_extensions`
+ - `rm -rf dist/`
+ - `python -m build .`
+
+- Install the built distributions locally and test (if you were using `tox`, you already
+ tested the source distribution).
+
+- Run `twine upload dist/*`.
+
+- Tag the release. The tag should be just the version number, e.g. `4.1.1`.
+
+- `git push --tags`
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..583f9f6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,254 @@
+A. HISTORY OF THE SOFTWARE
+==========================
+
+Python was created in the early 1990s by Guido van Rossum at Stichting
+Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
+as a successor of a language called ABC. Guido remains Python's
+principal author, although it includes many contributions from others.
+
+In 1995, Guido continued his work on Python at the Corporation for
+National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
+in Reston, Virginia where he released several versions of the
+software.
+
+In May 2000, Guido and the Python core development team moved to
+BeOpen.com to form the BeOpen PythonLabs team. In October of the same
+year, the PythonLabs team moved to Digital Creations (now Zope
+Corporation, see http://www.zope.com). In 2001, the Python Software
+Foundation (PSF, see http://www.python.org/psf/) was formed, a
+non-profit organization created specifically to own Python-related
+Intellectual Property. Zope Corporation is a sponsoring member of
+the PSF.
+
+All Python releases are Open Source (see http://www.opensource.org for
+the Open Source Definition). Historically, most, but not all, Python
+releases have also been GPL-compatible; the table below summarizes
+the various releases.
+
+ Release Derived Year Owner GPL-
+ from compatible? (1)
+
+ 0.9.0 thru 1.2 1991-1995 CWI yes
+ 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
+ 1.6 1.5.2 2000 CNRI no
+ 2.0 1.6 2000 BeOpen.com no
+ 1.6.1 1.6 2001 CNRI yes (2)
+ 2.1 2.0+1.6.1 2001 PSF no
+ 2.0.1 2.0+1.6.1 2001 PSF yes
+ 2.1.1 2.1+2.0.1 2001 PSF yes
+ 2.1.2 2.1.1 2002 PSF yes
+ 2.1.3 2.1.2 2002 PSF yes
+ 2.2 and above 2.1.1 2001-now PSF yes
+
+Footnotes:
+
+(1) GPL-compatible doesn't mean that we're distributing Python under
+ the GPL. All Python licenses, unlike the GPL, let you distribute
+ a modified version without making your changes open source. The
+ GPL-compatible licenses make it possible to combine Python with
+ other software that is released under the GPL; the others don't.
+
+(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
+ because its license has a choice of law clause. According to
+ CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
+ is "not incompatible" with the GPL.
+
+Thanks to the many outside volunteers who have worked under Guido's
+direction to make these releases possible.
+
+
+B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
+===============================================================
+
+PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+--------------------------------------------
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation
+("PSF"), and the Individual or Organization ("Licensee") accessing and
+otherwise using this software ("Python") in source or binary form and
+its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+analyze, test, perform and/or display publicly, prepare derivative works,
+distribute, and otherwise use Python alone or in any derivative version,
+provided, however, that PSF's License Agreement and PSF's notice of copyright,
+i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+2011, 2012, 2013, 2014 Python Software Foundation; All Rights Reserved" are
+retained in Python alone or in any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python.
+
+4. PSF is making Python available to Licensee on an "AS IS"
+basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between PSF and
+Licensee. This License Agreement does not grant permission to use PSF
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Python, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
+-------------------------------------------
+
+BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
+
+1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
+office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
+Individual or Organization ("Licensee") accessing and otherwise using
+this software in source or binary form and its associated
+documentation ("the Software").
+
+2. Subject to the terms and conditions of this BeOpen Python License
+Agreement, BeOpen hereby grants Licensee a non-exclusive,
+royalty-free, world-wide license to reproduce, analyze, test, perform
+and/or display publicly, prepare derivative works, distribute, and
+otherwise use the Software alone or in any derivative version,
+provided, however, that the BeOpen Python License is retained in the
+Software, alone or in any derivative version prepared by Licensee.
+
+3. BeOpen is making the Software available to Licensee on an "AS IS"
+basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
+SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
+AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
+DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+5. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+6. This License Agreement shall be governed by and interpreted in all
+respects by the law of the State of California, excluding conflict of
+law provisions. Nothing in this License Agreement shall be deemed to
+create any relationship of agency, partnership, or joint venture
+between BeOpen and Licensee. This License Agreement does not grant
+permission to use BeOpen trademarks or trade names in a trademark
+sense to endorse or promote products or services of Licensee, or any
+third party. As an exception, the "BeOpen Python" logos available at
+http://www.pythonlabs.com/logos.html may be used according to the
+permissions granted on that web page.
+
+7. By copying, installing or otherwise using the software, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
+---------------------------------------
+
+1. This LICENSE AGREEMENT is between the Corporation for National
+Research Initiatives, having an office at 1895 Preston White Drive,
+Reston, VA 20191 ("CNRI"), and the Individual or Organization
+("Licensee") accessing and otherwise using Python 1.6.1 software in
+source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, CNRI
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use Python 1.6.1
+alone or in any derivative version, provided, however, that CNRI's
+License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
+1995-2001 Corporation for National Research Initiatives; All Rights
+Reserved" are retained in Python 1.6.1 alone or in any derivative
+version prepared by Licensee. Alternately, in lieu of CNRI's License
+Agreement, Licensee may substitute the following text (omitting the
+quotes): "Python 1.6.1 is made available subject to the terms and
+conditions in CNRI's License Agreement. This Agreement together with
+Python 1.6.1 may be located on the Internet using the following
+unique, persistent identifier (known as a handle): 1895.22/1013. This
+Agreement may also be obtained from a proxy server on the Internet
+using the following URL: http://hdl.handle.net/1895.22/1013".
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python 1.6.1 or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python 1.6.1.
+
+4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
+basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. This License Agreement shall be governed by the federal
+intellectual property law of the United States, including without
+limitation the federal copyright law, and, to the extent such
+U.S. federal law does not apply, by the law of the Commonwealth of
+Virginia, excluding Virginia's conflict of law provisions.
+Notwithstanding the foregoing, with regard to derivative works based
+on Python 1.6.1 that incorporate non-separable material that was
+previously distributed under the GNU General Public License (GPL), the
+law of the Commonwealth of Virginia shall govern this License
+Agreement only as to issues arising under or with respect to
+Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
+License Agreement shall be deemed to create any relationship of
+agency, partnership, or joint venture between CNRI and Licensee. This
+License Agreement does not grant permission to use CNRI trademarks or
+trade name in a trademark sense to endorse or promote products or
+services of Licensee, or any third party.
+
+8. By clicking on the "ACCEPT" button where indicated, or by copying,
+installing or otherwise using Python 1.6.1, Licensee agrees to be
+bound by the terms and conditions of this License Agreement.
+
+ ACCEPT
+
+
+CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
+--------------------------------------------------
+
+Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
+The Netherlands. All rights reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..aae60ef
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,16 @@
+name: "typing"
+description:
+ "Static Typing for Python"
+third_party {
+ url {
+ type: HOMEPAGE
+ value: "https://github.com/python/typing"
+ }
+ url {
+ type: GIT
+ value: "https://github.com/python/typing"
+ }
+ version: "4.1.1"
+ last_upgrade_date { year: 2022 month: 4 day: 13 }
+ license_type: NOTICE
+}
diff --git a/MODULE_LICENSE_GPL b/MODULE_LICENSE_GPL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_GPL
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..583f9f6
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,254 @@
+A. HISTORY OF THE SOFTWARE
+==========================
+
+Python was created in the early 1990s by Guido van Rossum at Stichting
+Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
+as a successor of a language called ABC. Guido remains Python's
+principal author, although it includes many contributions from others.
+
+In 1995, Guido continued his work on Python at the Corporation for
+National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
+in Reston, Virginia where he released several versions of the
+software.
+
+In May 2000, Guido and the Python core development team moved to
+BeOpen.com to form the BeOpen PythonLabs team. In October of the same
+year, the PythonLabs team moved to Digital Creations (now Zope
+Corporation, see http://www.zope.com). In 2001, the Python Software
+Foundation (PSF, see http://www.python.org/psf/) was formed, a
+non-profit organization created specifically to own Python-related
+Intellectual Property. Zope Corporation is a sponsoring member of
+the PSF.
+
+All Python releases are Open Source (see http://www.opensource.org for
+the Open Source Definition). Historically, most, but not all, Python
+releases have also been GPL-compatible; the table below summarizes
+the various releases.
+
+ Release Derived Year Owner GPL-
+ from compatible? (1)
+
+ 0.9.0 thru 1.2 1991-1995 CWI yes
+ 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
+ 1.6 1.5.2 2000 CNRI no
+ 2.0 1.6 2000 BeOpen.com no
+ 1.6.1 1.6 2001 CNRI yes (2)
+ 2.1 2.0+1.6.1 2001 PSF no
+ 2.0.1 2.0+1.6.1 2001 PSF yes
+ 2.1.1 2.1+2.0.1 2001 PSF yes
+ 2.1.2 2.1.1 2002 PSF yes
+ 2.1.3 2.1.2 2002 PSF yes
+ 2.2 and above 2.1.1 2001-now PSF yes
+
+Footnotes:
+
+(1) GPL-compatible doesn't mean that we're distributing Python under
+ the GPL. All Python licenses, unlike the GPL, let you distribute
+ a modified version without making your changes open source. The
+ GPL-compatible licenses make it possible to combine Python with
+ other software that is released under the GPL; the others don't.
+
+(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
+ because its license has a choice of law clause. According to
+ CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
+ is "not incompatible" with the GPL.
+
+Thanks to the many outside volunteers who have worked under Guido's
+direction to make these releases possible.
+
+
+B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
+===============================================================
+
+PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+--------------------------------------------
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation
+("PSF"), and the Individual or Organization ("Licensee") accessing and
+otherwise using this software ("Python") in source or binary form and
+its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+analyze, test, perform and/or display publicly, prepare derivative works,
+distribute, and otherwise use Python alone or in any derivative version,
+provided, however, that PSF's License Agreement and PSF's notice of copyright,
+i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+2011, 2012, 2013, 2014 Python Software Foundation; All Rights Reserved" are
+retained in Python alone or in any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python.
+
+4. PSF is making Python available to Licensee on an "AS IS"
+basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between PSF and
+Licensee. This License Agreement does not grant permission to use PSF
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Python, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
+-------------------------------------------
+
+BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
+
+1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
+office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
+Individual or Organization ("Licensee") accessing and otherwise using
+this software in source or binary form and its associated
+documentation ("the Software").
+
+2. Subject to the terms and conditions of this BeOpen Python License
+Agreement, BeOpen hereby grants Licensee a non-exclusive,
+royalty-free, world-wide license to reproduce, analyze, test, perform
+and/or display publicly, prepare derivative works, distribute, and
+otherwise use the Software alone or in any derivative version,
+provided, however, that the BeOpen Python License is retained in the
+Software, alone or in any derivative version prepared by Licensee.
+
+3. BeOpen is making the Software available to Licensee on an "AS IS"
+basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
+SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
+AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
+DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+5. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+6. This License Agreement shall be governed by and interpreted in all
+respects by the law of the State of California, excluding conflict of
+law provisions. Nothing in this License Agreement shall be deemed to
+create any relationship of agency, partnership, or joint venture
+between BeOpen and Licensee. This License Agreement does not grant
+permission to use BeOpen trademarks or trade names in a trademark
+sense to endorse or promote products or services of Licensee, or any
+third party. As an exception, the "BeOpen Python" logos available at
+http://www.pythonlabs.com/logos.html may be used according to the
+permissions granted on that web page.
+
+7. By copying, installing or otherwise using the software, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
+---------------------------------------
+
+1. This LICENSE AGREEMENT is between the Corporation for National
+Research Initiatives, having an office at 1895 Preston White Drive,
+Reston, VA 20191 ("CNRI"), and the Individual or Organization
+("Licensee") accessing and otherwise using Python 1.6.1 software in
+source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, CNRI
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use Python 1.6.1
+alone or in any derivative version, provided, however, that CNRI's
+License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
+1995-2001 Corporation for National Research Initiatives; All Rights
+Reserved" are retained in Python 1.6.1 alone or in any derivative
+version prepared by Licensee. Alternately, in lieu of CNRI's License
+Agreement, Licensee may substitute the following text (omitting the
+quotes): "Python 1.6.1 is made available subject to the terms and
+conditions in CNRI's License Agreement. This Agreement together with
+Python 1.6.1 may be located on the Internet using the following
+unique, persistent identifier (known as a handle): 1895.22/1013. This
+Agreement may also be obtained from a proxy server on the Internet
+using the following URL: http://hdl.handle.net/1895.22/1013".
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python 1.6.1 or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python 1.6.1.
+
+4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
+basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. This License Agreement shall be governed by the federal
+intellectual property law of the United States, including without
+limitation the federal copyright law, and, to the extent such
+U.S. federal law does not apply, by the law of the Commonwealth of
+Virginia, excluding Virginia's conflict of law provisions.
+Notwithstanding the foregoing, with regard to derivative works based
+on Python 1.6.1 that incorporate non-separable material that was
+previously distributed under the GNU General Public License (GPL), the
+law of the Commonwealth of Virginia shall govern this License
+Agreement only as to issues arising under or with respect to
+Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
+License Agreement shall be deemed to create any relationship of
+agency, partnership, or joint venture between CNRI and Licensee. This
+License Agreement does not grant permission to use CNRI trademarks or
+trade name in a trademark sense to endorse or promote products or
+services of Licensee, or any third party.
+
+8. By clicking on the "ACCEPT" button where indicated, or by copying,
+installing or otherwise using Python 1.6.1, Licensee agrees to be
+bound by the terms and conditions of this License Agreement.
+
+ ACCEPT
+
+
+CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
+--------------------------------------------------
+
+Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
+The Netherlands. All rights reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..eb86f14
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,8 @@
+# Android side engprod team
+jdesprez@google.com
+frankfeng@google.com
+murj@google.com
+
+# Mobly team - use for mobly bugs
+angli@google.com
+lancefluger@google.com
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..64b9118
--- /dev/null
+++ b/README.md
@@ -0,0 +1,41 @@
+[![Chat at https://gitter.im/python/typing](https://badges.gitter.im/python/typing.svg)](https://gitter.im/python/typing?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+Static Typing for Python
+========================
+
+Documentation and Support
+-------------------------
+
+The documentation for Python's static typing can be found at
+[typing.readthedocs.io](https://typing.readthedocs.io/). You can get
+help either in our [support forum](https://github.com/python/typing/discussions) or
+chat with us on [Gitter](https://gitter.im/python/typing).
+
+Improvements to the type system should be discussed on the
+[typing-sig](https://mail.python.org/mailman3/lists/typing-sig.python.org/)
+mailing list, although the [issues](https://github.com/python/typing/issues) in this
+repository contain some historic discussions.
+
+Repository Content
+------------------
+
+This GitHub repository is used for several things:
+
+- The `typing_extensions` module lives in the
+ [typing\_extensions](./typing_extensions) directory.
+
+- The documentation at [typing.readthedocs.io](https://typing.readthedocs.io/)
+ is maintained in the [docs directory](./docs).
+
+- A [discussion forum](https://github.com/python/typing/discussions) for typing-related user
+ help is hosted here.
+
+Historically, this repository hosted a backport of the
+[`typing` module](https://docs.python.org/3/library/typing.html) for older
+Python versions. The last released version, supporting Python 2.7 and 3.4,
+is [available at PyPI](https://pypi.org/project/typing/).
+
+Workflow
+--------
+
+See [CONTRIBUTING.md](/CONTRIBUTING.md) for more.
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..4f7c95a
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,46 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SOURCEDIR = .
+SOURCES =
+BUILDDIR = _build
+PYTHON = python3
+VENVDIR = ./venv
+SPHINXBUILD = PATH=$(VENVDIR)/bin:$$PATH sphinx-build
+
+ALLSPHINXOPTS = -b $(BUILDER) -d build/doctrees $(SPHINXOPTS) . build/$(BUILDER) $(SOURCES)
+
+.PHONY: help clean build html text venv Makefile
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+clean:
+ -rm -rf build/* $(VENVDIR)/*
+
+build:
+ -mkdir -p build
+ $(SPHINXBUILD) $(ALLSPHINXOPTS)
+ @echo
+
+html: BUILDER = html
+html: build
+ @echo "Build finished. The HTML pages are in build/html."
+
+text: BUILDER = text
+text: build
+ @echo "Build finished; the text files are in build/text."
+
+venv:
+ $(PYTHON) -m venv $(VENVDIR)
+ $(VENVDIR)/bin/python3 -m pip install -U pip setuptools
+ $(VENVDIR)/bin/python3 -m pip install -r requirements.txt
+ @echo "The venv has been created in the $(VENVDIR) directory"
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/README.rst b/docs/README.rst
new file mode 100644
index 0000000..6b431c8
--- /dev/null
+++ b/docs/README.rst
@@ -0,0 +1,50 @@
+Python Typing Documentation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Reading the docs
+=================
+
+The live documentation for Python's static typing can be found at
+`typing.readthedocs.io <https://typing.readthedocs.io/>`_.
+
+Building the docs
+=================
+
+The documentation is built with tools which are not included in this
+tree but are maintained separately and are available from
+`PyPI <https://pypi.org/>`_.
+
+* `Sphinx <https://pypi.org/project/Sphinx/>`_
+* `python-docs-theme <https://pypi.org/project/python-docs-theme/>`_
+
+The easiest way to install these tools is to create a virtual environment and
+install the tools into there.
+
+Using make
+----------
+
+To get started on UNIX, you can create a virtual environment with the command ::
+
+ make venv
+
+That will install all the tools necessary to build the documentation. Assuming
+the virtual environment was created in the ``venv`` directory (the default;
+configurable with the VENVDIR variable), you can run the following command to
+build the HTML output files::
+
+ make html
+
+By default, if the virtual environment is not created, the Makefile will
+look for instances of sphinxbuild and blurb installed on your process PATH
+(configurable with the SPHINXBUILD and BLURB variables).
+
+Available make targets are:
+
+* "clean", which removes all build files.
+
+* "venv", which creates a virtual environment with all necessary tools
+ installed.
+
+* "html", which builds standalone HTML files for offline viewing.
+
+* "text", which builds a plain text file for each source file.
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..f16401b
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,55 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+
+# -- Project information -----------------------------------------------------
+
+project = 'typing'
+copyright = '2021, The Python Typing Team'
+author = 'The Python Typing Team'
+
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'venv', 'README.rst']
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'python_docs_theme'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = []
+
+extensions = ['sphinx.ext.intersphinx']
+intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..b5fe268
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,99 @@
+*************************
+Static Typing with Python
+*************************
+
+.. Introduction
+.. ============
+..
+.. .. toctree::
+.. :maxdepth: 2
+..
+.. source/introduction
+
+Guides
+======
+
+.. toctree::
+ :maxdepth: 2
+
+ source/guides
+
+Reference
+=========
+
+.. toctree::
+ :maxdepth: 2
+
+ source/reference
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`
+
+Discussions and Support
+=======================
+
+* `User help forum <https://github.com/python/typing/discussions>`_
+* `User chat on Gitter <http://gitter.im/python/typing>`_
+* `Developer mailing list <https://mail.python.org/archives/list/typing-sig@python.org/>`_
+
+Typing-related Tools
+====================
+
+Type Checkers
+-------------
+
+* `mypy <http://mypy-lang.org/>`_, the reference implementation for type
+ checkers. Supports Python 2 and 3.
+* `pyre <https://pyre-check.org/>`_, written in OCaml and optimized for
+ performance. Supports Python 3 only.
+* `pyright <https://github.com/microsoft/pyright>`_, a type checker that
+ emphasizes speed. Supports Python 3 only.
+* `pytype <https://google.github.io/pytype/>`_, checks and infers types for
+ unannotated code. Supports Python 2 and 3.
+
+Development Environments
+------------------------
+
+* `PyCharm <https://www.jetbrains.com/pycharm/>`_, an IDE that supports
+ type stubs both for type checking and code completion.
+* `Visual Studio Code <https://code.visualstudio.com/>`_, a code editor that
+ supports type checking using mypy, pyright, or the
+ `Pylance <https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance>`_
+ extension.
+
+Linters and Formatters
+----------------------
+
+* `black <https://black.readthedocs.io/>`_, a code formatter with support for
+ type stub files.
+* `flake8-pyi <https://github.com/ambv/flake8-pyi>`_, a plugin for the
+ `flake8 <https://flake8.pycqa.org/>`_ linter that adds support for type
+ stubs.
+
+Typing PEPs
+===========
+
+* `PEP 483 <https://www.python.org/dev/peps/pep-0483/>`_, background on type hints
+* `PEP 484 <https://www.python.org/dev/peps/pep-0484/>`_, type hints
+* `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_, variable annotations and ``ClassVar``
+* `PEP 544 <https://www.python.org/dev/peps/pep-0544/>`_, ``Protocol``
+* `PEP 561 <https://www.python.org/dev/peps/pep-0561/>`_, distributing typed packages
+* `PEP 563 <https://www.python.org/dev/peps/pep-0563/>`_, ``from __future__ import annotations``
+* `PEP 585 <https://www.python.org/dev/peps/pep-0585/>`_, subscriptable generics in the standard library
+* `PEP 586 <https://www.python.org/dev/peps/pep-0586/>`_, ``Literal``
+* `PEP 589 <https://www.python.org/dev/peps/pep-0589/>`_, ``TypedDict``
+* `PEP 591 <https://www.python.org/dev/peps/pep-0591/>`_, ``Final``
+* `PEP 593 <https://www.python.org/dev/peps/pep-0593/>`_, ``Annotated``
+* `PEP 604 <https://www.python.org/dev/peps/pep-0604/>`_, union syntax with ``|``
+* `PEP 612 <https://www.python.org/dev/peps/pep-0612/>`_, ``ParamSpec``
+* `PEP 613 <https://www.python.org/dev/peps/pep-0613/>`_, ``TypeAlias``
+* `PEP 646 <https://www.python.org/dev/peps/pep-0646/>`_, variadic generics and ``TypeVarTuple``
+* `PEP 647 <https://www.python.org/dev/peps/pep-0647/>`_, ``TypeGuard``
+* `PEP 655 <https://www.python.org/dev/peps/pep-0655/>`_, ``Required`` and ``NotRequired``
+* `PEP 673 <https://www.python.org/dev/peps/pep-0673/>`_, ``Self``
+* `PEP 675 <https://www.python.org/dev/peps/pep-0675/>`_, ``LiteralString``
+* `PEP 677 <https://www.python.org/dev/peps/pep-0677/>`_ (rejected), callable type syntax
+* `PEP 681 <https://www.python.org/dev/peps/pep-0681/>`_ (draft), ``@dataclass_transform()``
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 0000000..2119f51
--- /dev/null
+++ b/docs/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=.
+set BUILDDIR=_build
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..4aa5fce
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,10 @@
+# Requirements to build the Python documentation
+
+# Sphinx version is pinned so that new versions that introduce new warnings
+# won't suddenly cause build failures. Updating the version is fine as long
+# as no warnings are raised by doing so.
+sphinx==4.2.0
+
+# The theme used by the documentation is stored separately, so we need
+# to install that as well.
+python-docs-theme
diff --git a/docs/source/annotations.rst b/docs/source/annotations.rst
new file mode 100644
index 0000000..ea5c471
--- /dev/null
+++ b/docs/source/annotations.rst
@@ -0,0 +1,68 @@
+****************
+Type Annotations
+****************
+
+Functions
+=========
+
+Parameters
+----------
+
+Asynchronous Functions
+----------------------
+
+Generators
+----------
+
+Lambdas
+-------
+
+
+Classes
+=======
+
+Overloads and Overrides
+-----------------------
+
+Instance vs. Class Attributes
+-----------------------------
+
+Final attributes
+----------------
+
+Abstract base classes
+---------------------
+
+
+Globals
+=======
+
+
+Attributes
+==========
+
+
+Locals
+======
+
+Empty Containers
+----------------
+
+
+Runtime Considerations
+======================
+
+Comment vs. Inline Support
+--------------------------
+
+Forward References
+------------------
+
+Generic types that don't implement `__getitem__`
+------------------------------------------------
+
+Conditioning on static type checking
+------------------------------------
+
+from `__future__` import annotations
+------------------------------------
diff --git a/docs/source/basics.rst b/docs/source/basics.rst
new file mode 100644
index 0000000..9b2bf52
--- /dev/null
+++ b/docs/source/basics.rst
@@ -0,0 +1,3 @@
+**********
+The Basics
+**********
diff --git a/docs/source/dependencies.rst b/docs/source/dependencies.rst
new file mode 100644
index 0000000..b16fa63
--- /dev/null
+++ b/docs/source/dependencies.rst
@@ -0,0 +1,12 @@
+**************************
+Libraries and Dependencies
+**************************
+
+:doc:`libraries`
+
+Typeshed
+========
+
+
+Placeholder Stubs
+=================
diff --git a/docs/source/faq.rst b/docs/source/faq.rst
new file mode 100644
index 0000000..906e277
--- /dev/null
+++ b/docs/source/faq.rst
@@ -0,0 +1,23 @@
+**************************
+Frequently Asked Questions
+**************************
+
+
+Why Types?
+==========
+
+
+Unsupported Python Features
+===========================
+
+
+Common Errors
+=============
+
+
+Typing PEPs
+===========
+
+
+Relevant Talks and Resources
+============================
diff --git a/docs/source/guides.rst b/docs/source/guides.rst
new file mode 100644
index 0000000..c9af381
--- /dev/null
+++ b/docs/source/guides.rst
@@ -0,0 +1,10 @@
+******************
+Type System Guides
+******************
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+
+ libraries
+ unreachable
diff --git a/docs/source/inference.rst b/docs/source/inference.rst
new file mode 100644
index 0000000..291dec4
--- /dev/null
+++ b/docs/source/inference.rst
@@ -0,0 +1,28 @@
+**************
+Type Inference
+**************
+
+Rules for local inference
+=========================
+
+Explicit vs. Implicit Local Types
+---------------------------------
+
+Changing Types
+==============
+
+Asserts
+-------
+
+Casts
+-----
+
+Type Guards
+-----------
+
+
+Protocols and Duck Typing
+=========================
+
+Callback Protocols
+------------------
diff --git a/docs/source/introduction.rst b/docs/source/introduction.rst
new file mode 100644
index 0000000..fb97355
--- /dev/null
+++ b/docs/source/introduction.rst
@@ -0,0 +1,41 @@
+*******************************
+Introduction to Types in Python
+*******************************
+
+
+Background
+==========
+
+How to read type annotations
+----------------------------
+
+When and why types are useful
+-----------------------------
+
+
+Gradual Typing: Static Types in a Dynamic Language
+==================================================
+
+Opt-in type checking
+--------------------
+
+Type stubs
+----------
+
+:doc:`stubs`
+
+Strategies for increasing coverage
+----------------------------------
+
+
+Getting Started
+===============
+
+Python type checkers
+--------------------
+
+How to annotate an existing codebase
+------------------------------------
+
+Typeshed
+--------
diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst
new file mode 100644
index 0000000..96e5370
--- /dev/null
+++ b/docs/source/libraries.rst
@@ -0,0 +1,602 @@
+.. _libraries:
+
+***********************
+Typing Python Libraries
+***********************
+
+Much of Python’s popularity can be attributed to the rich collection of
+Python libraries available to developers. Authors of these libraries
+play an important role in improving the experience for Python
+developers. This document provides some recommendations and guidance for
+Python library authors.
+
+These recommendations are intended to provide the following benefits:
+
+1. Consumers of libraries should have a great coding experience with
+ fast and accurate completion suggestions, class and function
+ documentation, signature help (including parameter default values),
+ hover text, and auto-imports. This should happen by default without
+ needing to download extra packages and without any special
+ configuration. These features should be consistent across the Python
+ ecosystem regardless of a developer’s choice of editor, IDE, notebook
+ environment, etc.
+2. Consumers of libraries should be able to rely on complete and
+ accurate type information so static type checkers can detect and
+ report type inconsistencies and other violations of the interface
+ contract.
+3. Library authors should be able to specify a well-defined interface
+ contract that is enforced by tools. This allows a library
+ implementation to evolve and improve without breaking consumers of
+ the library.
+4. Library authors should have the benefits of static type checking to
+ produce high-quality, bug-free implementations.
+
+Inlined Type Annotations and Type Stubs
+=======================================
+
+`PEP 561 <https://www.python.org/dev/peps/pep-0561/>`__ documents
+several ways type information can be delivered for a library: inlined
+type annotations, type stub files included in the package, a separate
+companion type stub package, and type stubs in the typeshed repository.
+Some of these options fall short on delivering the benefits above. We
+therefore provide the following more specific guidance to library
+authors.
+
+.. note::
+ All libraries should include inlined type annotations for the
+ functions, classes, methods, and constants that comprise the public
+ interface for the library.
+
+Inlined type annotations should be included directly within the source
+code that ships with the package. Of the options listed in PEP 561,
+inlined type annotations offer the most benefits. They typically require
+the least effort to add and maintain, they are always consistent with
+the implementation, and docstrings and default parameter values are
+readily available, allowing language servers to enhance the development
+experience.
+
+There are cases where inlined type annotations are not possible — most
+notably when a library’s exposed functionality is implemented in a
+language other than Python.
+
+.. note::
+ Libraries that expose symbols implemented in languages other than
+ Python should include stub (``.pyi``) files that describe the types for
+ those symbols. These stubs should also contain docstrings and default
+ parameter values.
+
+In many existing type stubs (such as those found in typeshed), default
+parameter values are replaced with with ``...`` and all docstrings are
+removed. We recommend that default values and docstrings remain within
+the type stub file so language servers can display this information to
+developers.
+
+Library Interface
+=================
+
+`PEP 561 <https://www.python.org/dev/peps/pep-0561/>`__ indicates that a
+``py.typed`` marker file must be included in the package if the author
+wishes to support type checking of their code.
+
+If a ``py.typed`` module is present, a type checker will treat all modules
+within that package (i.e. all files that end in ``.py`` or ``.pyi``) as
+importable unless the file name begins with an underscore. These modules
+comprise the supported interface for the library.
+
+Each module exposes a set of symbols. Some of these symbols are
+considered "private” — implementation details that are not part of the
+library’s interface. Type checkers can use the following rules
+to determine which symbols are visible outside of the package.
+
+- Symbols whose names begin with an underscore (but are not dunder
+ names) are considered private.
+- Imported symbols are considered private by default. If they use the
+ ``import A as A`` (a redundant module alias), ``from X import A as A`` (a
+ redundant symbol alias), or ``from . import A`` forms, symbol ``A`` is
+ not private unless the name begins with an underscore. If a file
+ ``__init__.py`` uses form ``from .A import X``, symbol ``A`` is treated
+ likewise. If a wildcard import (of the form ``from X import *``) is
+ used, all symbols referenced by the wildcard are not private.
+- A module can expose an ``__all__`` symbol at the module level that
+ provides a list of names that are considered part of the interface.
+ This overrides all other rules above, allowing imported symbols or
+ symbols whose names begin with an underscore to be included in the
+ interface.
+- Local variables within a function (including nested functions) are
+ always considered private.
+
+The following idioms are supported for defining the values contained
+within ``__all__``. These restrictions allow type checkers to statically
+determine the value of ``__all__``.
+
+- ``__all__ = ('a', b')``
+- ``__all__ = ['a', b']``
+- ``__all__ += ['a', b']``
+- ``__all__ += submodule.__all__``
+- ``__all__.extend(['a', b'])``
+- ``__all__.extend(submodule.__all__)``
+- ``__all__.append('a')``
+- ``__all__.remove('a')``
+
+Type Completeness
+=================
+
+A “py.typed” library should aim to be type complete so that type
+checking and inspection can work to their full extent. Here we say that a
+library is “type complete” if all of the symbols
+that comprise its interface have type annotations that refer to types
+that are fully known. Private symbols are exempt.
+
+The following are best practice recommendations for how to define “type complete”:
+
+Classes:
+
+- All class variables, instance variables, and methods that are
+ “visible” (not overridden) are annotated and refer to known types
+- If a class is a subclass of a generic class, type arguments are
+ provided for each generic type parameter, and these type arguments
+ are known types
+
+Functions and Methods:
+
+- All input parameters have type annotations that refer to known types
+- The return parameter is annotated and refers to a known type
+- The result of applying one or more decorators results in a known type
+
+Type Aliases:
+
+- All of the types referenced by the type alias are known
+
+Variables:
+
+- All variables have type annotations that refer to known types
+
+Type annotations can be omitted in a few specific cases where the type
+is obvious from the context:
+
+- Constants that are assigned simple literal values
+ (e.g. ``RED = '#F00'`` or ``MAX_TIMEOUT = 50`` or
+ ``room_temperature: Final = 20``). A constant is a symbol that is
+ assigned only once and is either annotated with ``Final`` or is named
+ in all-caps. A constant that is not assigned a simple literal value
+ requires explicit annotations, preferably with a ``Final`` annotation
+ (e.g. ``WOODWINDS: Final[List[str]] = ['Oboe', 'Bassoon']``).
+- Enum values within an Enum class do not require annotations because
+ they take on the type of the Enum class.
+- Type aliases do not require annotations. A type alias is a symbol
+ that is defined at a module level with a single assignment where the
+ assigned value is an instantiable type, as opposed to a class
+ instance
+ (e.g. ``Foo = Callable[[Literal["a", "b"]], Union[int, str]]`` or
+ ``Bar = Optional[MyGenericClass[int]]``).
+- The “self” parameter in an instance method and the “cls” parameter in
+ a class method do not require an explicit annotation.
+- The return type for an ``__init__`` method does not need to be
+ specified, since it is always ``None``.
+- The following module-level symbols do not require type annotations:
+ ``__all__``,\ ``__author__``, ``__copyright__``, ``__email__``,
+ ``__license__``, ``__title__``, ``__uri__``, ``__version__``.
+- The following class-level symbols do not require type annotations:
+ ``__class__``, ``__dict__``, ``__doc__``, ``__module__``,
+ ``__slots__``.
+
+Examples of known and unknown types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+
+ # Variable with unknown type
+ a = [3, 4, 5]
+
+ # Variable with known type
+ a: List[int] = [3, 4, 5]
+
+ # Type alias with partially unknown type (because type
+ # arguments are missing for list and dict)
+ DictOrList = Union[list, dict]
+
+ # Type alias with known type
+ DictOrList = Union[List[Any], Dict[str, Any]]
+
+ # Generic type alias with known type
+ _T = TypeVar("_T")
+ DictOrList = Union[List[_T], Dict[str, _T]]
+
+ # Function with known type
+ def func(a: Optional[int], b: Dict[str, float] = {}) -> None:
+ pass
+
+ # Function with partially unknown type (because type annotations
+ # are missing for input parameters and return type)
+ def func(a, b):
+ pass
+
+ # Function with partially unknown type (because of missing
+ # type args on Dict)
+ def func(a: int, b: Dict) -> None:
+ pass
+
+ # Function with partially unknown type (because return type
+ # annotation is missing)
+ def func(a: int, b: Dict[str, float]):
+ pass
+
+ # Decorator with partially unknown type (because type annotations
+ # are missing for input parameters and return type)
+ def my_decorator(func):
+ return func
+
+ # Function with partially unknown type (because type is obscured
+ # by untyped decorator)
+ @my_decorator
+ def func(a: int) -> str:
+ pass
+
+
+ # Class with known type
+ class MyClass:
+ height: float = 2.0
+
+ def __init__(self, name: str, age: int):
+ self.age: int = age
+
+ @property
+ def name(self) -> str:
+ ...
+
+ # Class with partially unknown type
+ class MyClass:
+ # Missing type annotation for class variable
+ height = 2.0
+
+ # Missing input parameter annotations
+ def __init__(self, name, age):
+ # Missing type annotation for instance variable
+ self.age = age
+
+ # Missing return type annotation
+ @property
+ def name(self):
+ ...
+
+ # Class with partially unknown type
+ class BaseClass:
+ # Missing type annotation
+ height = 2.0
+
+ # Missing type annotation
+ def get_stuff(self):
+ ...
+
+ # Class with known type (because it overrides all symbols
+ # exposed by BaseClass that have incomplete types)
+ class DerivedClass(BaseClass):
+ height: float
+
+ def get_stuff(self) -> str:
+ ...
+
+ # Class with partially unknown type because base class
+ # (dict) is generic, and type arguments are not specified.
+ class DictSubclass(dict):
+ pass
+
+Best Practices for Inlined Types
+================================
+
+Wide vs. Narrow Types
+~~~~~~~~~~~~~~~~~~~~~
+
+In type theory, when comparing two types that are related to each other,
+the “wider” type is the one that is more general, and the “narrower”
+type is more specific. For example, ``Sequence[str]`` is a wider type
+than ``List[str]`` because all ``List`` objects are also ``Sequence``
+objects, but the converse is not true. A subclass is narrower than a
+class it derives from. A union of types is wider than the individual
+types that comprise the union.
+
+In general, a function input parameter should be annotated with the
+widest possible type supported by the implementation. For example, if
+the implementation requires the caller to provide an iterable collection
+of strings, the parameter should be annotated as ``Iterable[str]``, not
+as ``List[str]``. The latter type is narrower than necessary, so if a
+user attempts to pass a tuple of strings (which is supported by the
+implementation), a type checker will complain about a type
+incompatibility.
+
+As a specific application of the “use the widest type possible” rule,
+libraries should generally use immutable forms of container types
+instead of mutable forms (unless the function needs to modify the
+container). Use ``Sequence`` rather than ``List``, ``Mapping`` rather
+than ``Dict``, etc. Immutable containers allow for more flexibility
+because their type parameters are covariant rather than invariant. A
+parameter that is typed as ``Sequence[Union[str, int]]`` can accept a
+``List[int]``, ``Sequence[str]``, and a ``Sequence[int]``. But a
+parameter typed as ``List[Union[str, int]]`` is much more restrictive
+and accepts only a ``List[Union[str, int]]``.
+
+Overloads
+~~~~~~~~~
+
+If a function or method can return multiple different types and those
+types can be determined based on the presence or types of certain
+parameters, use the ``@overload`` mechanism defined in `PEP
+484 <https://www.python.org/dev/peps/pep-0484/#id45>`__. When overloads
+are used within a “.py” file, they must appear prior to the function
+implementation, which should not have an ``@overload`` decorator.
+
+Keyword-only Parameters
+~~~~~~~~~~~~~~~~~~~~~~~
+
+If a function or method is intended to take parameters that are
+specified only by name, use the keyword-only separator (``*``).
+
+.. code:: python
+
+ def create_user(age: int, *, dob: Optional[date] = None):
+ ...
+
+Annotating Decorators
+~~~~~~~~~~~~~~~~~~~~~
+
+Decorators modify the behavior of a class or a function. Providing
+annotations for decorators is straightforward if the decorator retains
+the original signature of the decorated function.
+
+.. code:: python
+
+ _F = TypeVar("_F", bound=Callable[..., Any])
+
+ def simple_decorator(_func: _F) -> _F:
+ """
+ Simple decorators are invoked without parentheses like this:
+ @simple_decorator
+ def my_function(): ...
+ """
+ ...
+
+ def complex_decorator(*, mode: str) -> Callable[[_F], _F]:
+ """
+ Complex decorators are invoked with arguments like this:
+ @complex_decorator(mode="easy")
+ def my_function(): ...
+ """
+ ...
+
+Decorators that mutate the signature of the decorated function present
+challenges for type annotations. The ``ParamSpec`` and ``Concatenate``
+mechanisms described in `PEP
+612 <https://www.python.org/dev/peps/pep-0612/>`__ provide some help
+here, but these are available only in Python 3.10 and newer. More
+complex signature mutations may require type annotations that erase the
+original signature, thus blinding type checkers and other tools that
+provide signature assistance. As such, library authors are discouraged
+from creating decorators that mutate function signatures in this manner.
+
+Generic Classes and Functions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Classes and functions that can operate in a generic manner on various
+types should declare themselves as generic using the mechanisms
+described in `PEP 484 <https://www.python.org/dev/peps/pep-0484/>`__.
+This includes the use of ``TypeVar`` symbols. Typically, a ``TypeVar``
+should be private to the file that declares it, and should therefore
+begin with an underscore.
+
+Type Aliases
+~~~~~~~~~~~~
+
+Type aliases are symbols that refer to other types. Generic type aliases
+(those that refer to unspecialized generic classes) are supported by
+most type checkers.
+
+`PEP 613 <https://www.python.org/dev/peps/pep-0613/>`__ provides a way
+to explicitly designate a symbol as a type alias using the new TypeAlias
+annotation.
+
+.. code:: python
+
+ # Simple type alias
+ FamilyPet = Union[Cat, Dog, GoldFish]
+
+ # Generic type alias
+ ListOrTuple = Union[List[_T], Tuple[_T, ...]]
+
+ # Recursive type alias
+ TreeNode = Union[LeafNode, List["TreeNode"]]
+
+ # Explicit type alias using PEP 613 syntax
+ StrOrInt: TypeAlias = Union[str, int]
+
+Abstract Classes and Methods
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Classes that must be subclassed should derive from ``ABC``, and methods
+or properties that must be overridden should be decorated with the
+``@abstractmethod`` decorator. This allows type checkers to validate
+that the required methods have been overridden and provide developers
+with useful error messages when they are not. It is customary to
+implement an abstract method by raising a ``NotImplementedError``
+exception.
+
+.. code:: python
+
+ from abc import ABC, abstractmethod
+
+ class Hashable(ABC):
+ @property
+ @abstractmethod
+ def hash_value(self) -> int:
+ """Subclasses must override"""
+ raise NotImplementedError()
+
+ @abstractmethod
+ def print(self) -> str:
+ """Subclasses must override"""
+ raise NotImplementedError()
+
+Final Classes and Methods
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Classes that are not intended to be subclassed should be decorated as
+``@final`` as described in `PEP
+591 <https://www.python.org/dev/peps/pep-0591/>`__. The same decorator
+can also be used to specify methods that cannot be overridden by
+subclasses.
+
+Literals
+~~~~~~~~
+
+Type annotations should make use of the Literal type where appropriate,
+as described in `PEP 586 <https://www.python.org/dev/peps/pep-0586/>`__.
+Literals allow for more type specificity than their non-literal
+counterparts.
+
+Constants
+~~~~~~~~~
+
+Constant values (those that are read-only) can be specified using the
+Final annotation as described in `PEP
+591 <https://www.python.org/dev/peps/pep-0591/>`__.
+
+Type checkers will also typically treat variables that are named using
+all upper-case characters as constants.
+
+In both cases, it is OK to omit the declared type of a constant if it is
+assigned a literal str, int, float, bool or None value. In such cases,
+the type inference rules are clear and unambiguous, and adding a literal
+type annotation would be redundant.
+
+.. code:: python
+
+ # All-caps constant with inferred type
+ COLOR_FORMAT_RGB = "rgb"
+
+ # All-caps constant with explicit type
+ COLOR_FORMAT_RGB: Literal["rgb"] = "rgb"
+ LATEST_VERSION: Tuple[int, int] = (4, 5)
+
+ # Final variable with inferred type
+ ColorFormatRgb: Final = "rgb"
+
+ # Final variable with explicit type
+ ColorFormatRgb: Final[Literal["rgb"]] = "rgb"
+ LATEST_VERSION: Final[Tuple[int, int]] = (4, 5)
+
+Typed Dictionaries, Data Classes, and Named Tuples
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If your library runs only on newer versions of Python, you are
+encouraged to use some of the new type-friendly classes.
+
+NamedTuple (described in `PEP
+484 <https://www.python.org/dev/peps/pep-0484/>`__) is preferred over
+namedtuple.
+
+Data classes (described in `PEP
+557 <https://www.python.org/dev/peps/pep-0557/>`__) is preferred over
+untyped dictionaries.
+
+TypedDict (described in `PEP
+589 <https://www.python.org/dev/peps/pep-0589/>`__) is preferred over
+untyped dictionaries.
+
+Compatibility with Older Python Versions
+========================================
+
+Each new version of Python from 3.5 onward has introduced new typing
+constructs. This presents a challenge for library authors who want to
+maintain runtime compatibility with older versions of Python. This
+section documents several techniques that can be used to add types while
+maintaining backward compatibility.
+
+Quoted Annotations
+~~~~~~~~~~~~~~~~~~
+
+Type annotations for variables, parameters, and return types can be
+placed in quotes. The Python interpreter will then ignore them, whereas
+a type checker will interpret them as type annotations.
+
+.. code:: python
+
+ # Older versions of Python do not support subscripting
+ # for the OrderedDict type, so the annotation must be
+ # enclosed in quotes.
+ def get_config(self) -> "OrderedDict[str, str]":
+ return self._config
+
+Type Comment Annotations
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Python 3.0 introduced syntax for parameter and return type annotations,
+as specified in `PEP 484 <https://www.python.org/dev/peps/pep-0484/>`__.
+Python 3.6 introduced support for variable type annotations, as
+specified in `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`__.
+
+If you need to support older versions of Python, type annotations can
+still be provided as “type comments”. These comments take the form #
+type: .
+
+.. code:: python
+
+ class Foo:
+ # Variable type comments go at the end of the line
+ # where the variable is assigned.
+ timeout = None # type: Optional[int]
+
+ # Function type comments can be specified on the
+ # line after the function signature.
+ def send_message(self, name, length):
+ # type: (str, int) -> None
+ ...
+
+ # Function type comments can also specify the type
+ # of each parameter on its own line.
+ def receive_message(
+ self,
+ name, # type: str
+ length # type: int
+ ):
+ # type: () -> Message
+ ...
+
+typing_extensions
+~~~~~~~~~~~~~~~~~
+
+New type features that require runtime support are typically included in
+the stdlib ``typing`` module. Where possible, these new features are
+back-ported to a runtime library called ``typing_extensions`` that works
+with older Python runtimes.
+
+TYPE_CHECKING
+~~~~~~~~~~~~~
+
+The ``typing`` module exposes a variable called ``TYPE_CHECKING`` which
+has a value of False within the Python runtime but a value of True when
+the type checker is performing its analysis. This allows type checking
+statements to be conditionalized.
+
+Care should be taken when using ``TYPE_CHECKING`` because behavioral
+changes between type checking and runtime could mask problems that the
+type checker would otherwise catch.
+
+Non-Standard Type Behaviors
+===========================
+
+Type annotations provide a way to annotate typical type behaviors, but
+some classes implement specialized, non-standard behaviors that cannot
+be described using standard type annotations. For now, such types need
+to be annotated as Any, which is unfortunate because the benefits of
+static typing are lost.
+
+Docstrings
+==========
+
+Docstrings should be provided for all classes, functions, and methods in
+the interface. They should be formatted according to `PEP
+257 <https://www.python.org/dev/peps/pep-0257/>`__.
+
+There is currently no single agreed-upon standard for function and
+method docstrings, but several common variants have emerged. We
+recommend using one of these variants.
diff --git a/docs/source/quality.rst b/docs/source/quality.rst
new file mode 100644
index 0000000..328550c
--- /dev/null
+++ b/docs/source/quality.rst
@@ -0,0 +1,200 @@
+.. _tools:
+
+********************************************
+Testing and Ensuring Type Annotation Quality
+********************************************
+
+Testing Annotation Accuracy
+===========================
+
+When creating a package with type annotations, authors may want to validate
+that the annotations they publish meet their expectations.
+This is especially important for library authors, for whom the published
+annotations are part of the public interface to their package.
+
+There are several approaches to this problem, and this document will show
+a few of them.
+
+.. note::
+
+ For simplicity, we will assume that type-checking is done with ``mypy``.
+ Many of these strategies can be applied to other type-checkers as well.
+
+Testing Using ``mypy --warn-unused-ignores``
+--------------------------------------------
+
+Clever use of ``--warn-unused-ignores`` can be used to check that certain
+expressions are or are not well-typed.
+
+The idea is to write normal python files which contain valid expressions along
+with invalid expressions annotated with ``type: ignore`` comments. When
+``mypy --warn-unused-ignores`` is run on these files, it should pass.
+A directory of test files, ``typing_tests/``, can be maintained.
+
+This strategy does not offer strong guarantees about the types under test, but
+it requires no additional tooling.
+
+If the following file is under test
+
+.. code-block:: python
+
+ # foo.py
+ def bar(x: int) -> str:
+ return str(x)
+
+Then the following file tests ``foo.py``:
+
+.. code-block:: python
+
+ bar(42)
+ bar("42") # type: ignore [arg-type]
+ bar(y=42) # type: ignore [call-arg]
+ r1: str = bar(42)
+ r2: int = bar(42) # type: ignore [assignment]
+
+Checking ``reveal_type`` output from ``mypy.api.run``
+-----------------------------------------------------
+
+``mypy`` provides a subpackage named ``api`` for invoking ``mypy`` from a
+python process. In combination with ``reveal_type``, this can be used to write
+a function which gets the ``reveal_type`` output from an expression. Once
+that's obtained, tests can assert strings and regular expression matches
+against it.
+
+This approach requires writing a set of helpers to provide a good testing
+experience, and it runs mypy once per test case (which can be slow).
+However, it builds only on ``mypy`` and the test framework of your choice.
+
+The following example could be integrated into a testsuite written in
+any framework:
+
+.. code-block:: python
+
+ import re
+ from mypy import api
+
+ def get_reveal_type_output(filename):
+ result = api.run([filename])
+ stdout = result[0]
+ match = re.search(r'note: Revealed type is "([^"]+)"', stdout)
+ assert match is not None
+ return match.group(1)
+
+
+For example, we can use the above to provide a ``run_reveal_type`` pytest
+fixture which generates a temporary file and uses it as the input to
+``get_reveal_type_output``:
+
+.. code-block:: python
+
+ import os
+ import pytest
+
+ @pytest.fixture
+ def _in_tmp_path(tmp_path):
+ cur = os.getcwd()
+ try:
+ os.chdir(tmp_path)
+ yield
+ finally:
+ os.chdir(cur)
+
+ @pytest.fixture
+ def run_reveal_type(tmp_path, _in_tmp_path):
+ content_path = tmp_path / "reveal_type_test.py"
+
+ def func(code_snippet, *, preamble = ""):
+ content_path.write_text(preamble + f"reveal_type({code_snippet})")
+ return get_reveal_type_output("reveal_type_test.py")
+
+ return func
+
+
+For more details, see `the documentation on mypy.api
+<https://mypy.readthedocs.io/en/stable/extending_mypy.html#integrating-mypy-into-another-python-application>`_.
+
+pytest-mypy-plugins
+-------------------
+
+`pytest-mypy-plugins <https://github.com/typeddjango/pytest-mypy-plugins>`_ is
+a plugin for ``pytest`` which defines typing test cases as YAML data.
+The test cases are run through ``mypy`` and the output of ``reveal_type`` can
+be asserted.
+
+This project supports complex typing arrangements like ``pytest`` parametrized
+tests and per-test ``mypy`` configuration. It requires that you are using
+``pytest`` to run your tests, and runs ``mypy`` in a subprocess per test case.
+
+This is an example of a parametrized test with ``pytest-mypy-plugins``:
+
+.. code-block:: yaml
+
+ - case: with_params
+ parametrized:
+ - val: 1
+ rt: builtins.int
+ - val: 1.0
+ rt: builtins.float
+ main: |
+ reveal_type({[ val }}) # N: Revealed type is '{{ rt }}'
+
+Improving Type Completeness
+===========================
+
+One of the goals of many libraries is to ensure that they are "fully type
+annotated", meaning that they provide complete and accurate type annotations
+for all functions, classes, and objects. Having full annotations is referred to
+as "type completeness" or "type coverage".
+
+Here are some tips for increasing the type completeness score for your
+library:
+
+- Make type completeness an output of your testing process. Several type
+ checkers have options for generating useful output, warnings, or even
+ reports.
+- If your package includes tests or sample code, consider removing them
+ from the distribution. If there is good reason to include them,
+ consider placing them in a directory that begins with an underscore
+ so they are not considered part of your library’s interface.
+- If your package includes submodules that are meant to be
+ implementation details, rename those files to begin with an
+ underscore.
+- If a symbol is not intended to be part of the library’s interface and
+ is considered an implementation detail, rename it such that it begins
+ with an underscore. It will then be considered private and excluded
+ from the type completeness check.
+- If your package exposes types from other libraries, work with the
+ maintainers of these other libraries to achieve type completeness.
+
+.. warning::
+
+ The ways in which different type checkers evaluate and help you achieve
+ better type coverage may differ. Some of the above recommendations may or
+ may not be helpful to you, depending on which type checking tools you use.
+
+``mypy`` disallow options
+-------------------------
+
+``mypy`` offers several options which can detect untyped code.
+More details can be found in `the mypy documentation on these options
+<https://mypy.readthedocs.io/en/latest/command_line.html#untyped-definitions-and-calls>`_.
+
+Some basic usages which make ``mypy`` error on untyped data are::
+
+ mypy --disallow-untyped-defs
+ mypy --disallow-incomplete-defs
+
+``pyright`` type verification
+-----------------------------
+
+pyright has a special command line flag, ``--verifytypes``, for verifying
+type completeness. You can learn more about it from
+`the pyright documentation on verifying type completeness
+<https://github.com/microsoft/pyright/blob/main/docs/typed-libraries.md#verifying-type-completeness>`_.
+
+``mypy`` reports
+----------------
+
+``mypy`` offers several options options for generating reports on its analysis.
+See `the mypy documentation on report generation
+<https://mypy.readthedocs.io/en/stable/command_line.html#report-generation>`_ for details.
diff --git a/docs/source/reference.rst b/docs/source/reference.rst
new file mode 100644
index 0000000..c7fc57e
--- /dev/null
+++ b/docs/source/reference.rst
@@ -0,0 +1,22 @@
+*********************
+Type System Reference
+*********************
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+
+ stubs
+ quality
+ typing Module Documentation <https://docs.python.org/3/library/typing.html>
+
+.. The following pages are desired in a new TOC which will cover multiple
+.. topics. For now, they are not linked because the pages are empty.
+..
+.. basics
+.. type_system
+.. annotations
+.. inference
+.. type_compatibility
+.. dependencies
+.. faq
diff --git a/docs/source/stubs.rst b/docs/source/stubs.rst
new file mode 100644
index 0000000..ffd6c9b
--- /dev/null
+++ b/docs/source/stubs.rst
@@ -0,0 +1,1129 @@
+.. _stubs:
+
+**********
+Type Stubs
+**********
+
+Introduction
+============
+
+*type stubs*, also called *stub files*, provide type information for untyped
+Python packages and modules. Type stubs serve multiple purposes:
+
+* They are the only way to add type information to extension modules.
+* They can provide type information for packages that do not wish to
+ add them inline.
+* They can be distributed separately from the implementation.
+ This allows stubs to be developed at a different pace or by different
+ authors, which is especially useful when adding type annotations to
+ existing packages.
+* They can act as documentation, succinctly explaining the external
+ API of a package, without including the implementation or private
+ members.
+
+This document aims to give guidance to both authors of type stubs and developers
+of type checkers and other tools. It describes the constructs that can be used safely in type stubs,
+suggests a style guide for them, and lists constructs that type
+checkers are expected to support.
+
+Type stubs that only use constructs described in this document should work with
+all type checkers that also follow this document.
+Type stub authors can elect to use additional constructs, but
+must be prepared that some type checkers will not parse them as expected.
+
+A type checker that conforms to this document will parse a type stub that only uses
+constructs described here without error and will not interpret any
+construct in a contradictory manner. However, type checkers are not
+required to implement checks for all these constructs, and
+can elect to ignore unsupported ones. Additionally type checkers
+can support constructs not described in this document and tool authors are
+encouraged to experiment with additional features.
+
+Syntax
+======
+
+Type stubs are syntactically valid Python 3.7 files with a ``.pyi`` suffix.
+The Python syntax used for type stubs is independent from the Python
+versions supported by the implementation, and from the Python version the type
+checker runs under (if any). Therefore, type stub authors should use the
+latest available syntax features in stubs (up to Python 3.7), even if the
+implementation supports older, pre-3.7 Python versions.
+Type checker authors are encouraged to support syntax features from
+post-3.7 Python versions, although type stub authors should not use such
+features if they wish to maintain compatibility with all type checkers.
+
+For example, Python 3.7 added the ``async`` keyword (see PEP 492 [#pep492]_).
+Stub authors should use it to mark coroutines, even if the implementation
+still uses the ``@coroutine`` decorator. On the other hand, type stubs should
+not use the positional-only syntax from PEP 570 [#pep570]_, introduced in
+Python 3.8, although type checker authors are encouraged to support it.
+
+Stubs are treated as if ``from __future__ import annotations`` is enabled.
+In particular, built-in generics, pipe union syntax (``X | Y``), and forward
+references can be used.
+
+Starting with Python 3.8, the :py:mod:`ast` module from the standard library supports
+all syntax features required by this PEP. Older Python versions can use the
+`typed_ast <https://pypi.org/project/typed-ast/>`_ package from the
+Python Package Index, which also supports Python 3.7 syntax and ``# type``
+comments.
+
+Distribution
+============
+
+Type stubs can be distributed with or separately from the implementation;
+see PEP 561 [#pep561]_ for more information. The
+`typeshed <https://github.com/python/typeshed>`_ project
+includes stubs for Python's standard library and several third-party
+packages. The stubs for the standard library are usually distributed with type checkers and do not
+require separate installation. Stubs for third-party libraries are
+available on the `Python Package Index <https://pypi.org>`_. A stub package for
+a library called ``widget`` will be called ``types-widget``.
+
+Supported Constructs
+====================
+
+This sections lists constructs that type checkers will accept in type stubs.
+Type stub authors can safely use these constructs. If a
+construct is marked as "unspecified", type checkers may handle it
+as they best see fit or report an error. Linters should usually
+flag those constructs. Type stub authors should avoid using them to
+ensure compatibility across type checkers.
+
+Unless otherwise mentioned, type stubs support all features from the
+``typing`` module of the latest released Python version. If a stub uses
+typing features from a later Python version than what the implementation
+supports, these features can be imported from ``typing_extensions`` instead
+of ``typing``.
+
+For example, a stub could use ``Literal``, introduced in Python 3.8,
+for a library supporting Python 3.7+::
+
+ from typing_extensions import Literal
+
+ def foo(x: Literal[""]) -> int: ...
+
+Comments
+--------
+
+Standard Python comments are accepted everywhere Python syntax allows them.
+
+Two kinds of structured comments are accepted:
+
+* A ``# type: X`` comment at the end of a line that defines a variable,
+ declaring that the variable has type ``X``. However, PEP 526-style [#pep526]_
+ variable annotations are preferred over type comments.
+* A ``# type: ignore`` comment at the end of any line, which suppresses all type
+ errors in that line. The type checker mypy supports suppressing certain
+ type errors by using ``# type: ignore[error-type]``. This is not supported
+ by other type checkers and should not be used in stubs.
+
+Imports
+-------
+
+Type stubs distinguish between imports that are re-exported and those
+that are only used internally. Imports are re-exported if they use one of these
+forms:[#pep484]_
+
+* ``import X as X``
+* ``from Y import X as X``
+* ``from Y import *``
+
+Here are some examples of imports that make names available for internal use in
+a stub but do not re-export them::
+
+ import X
+ from Y import X
+ from Y import X as OtherX
+
+Type aliases can be used to re-export an import under a different name::
+
+ from foo import bar as _bar
+ new_bar = _bar # "bar" gets re-exported with the name "new_bar"
+
+Sub-modules are always exported when they are imported in a module.
+For example, consider the following file structure::
+
+ foo/
+ __init__.pyi
+ bar.pyi
+
+Then ``foo`` will export ``bar`` when one of the following constructs is used in
+``__init__.pyi``::
+
+ from . import bar
+ from .bar import Bar
+
+Stubs support customizing star import semantics by defining a module-level
+variable called ``__all__``. In stubs, this must be a string list literal.
+Other types are not supported. Neither is the dynamic creation of this
+variable (for example by concatenation).
+
+By default, ``from foo import *`` imports all names in ``foo`` that
+do not begin with an underscore. When ``__all__`` is defined, only those names
+specified in ``__all__`` are imported::
+
+ __all__ = ['public_attr', '_private_looking_public_attr']
+
+ public_attr: int
+ _private_looking_public_attr: int
+ private_attr: int
+
+Type checkers support cyclic imports in stub files.
+
+Built-in Generics
+-----------------
+
+PEP 585 [#pep585]_ built-in generics are supported and should be used instead
+of the corresponding types from ``typing``::
+
+ from collections import defaultdict
+
+ def foo(t: type[MyClass]) -> list[int]: ...
+ x: defaultdict[int]
+
+Using imports from ``collections.abc`` instead of ``typing`` is
+generally possible and recommended::
+
+ from collections.abc import Iterable
+
+ def foo(iter: Iterable[int]) -> None: ...
+
+Unions
+------
+
+Declaring unions with ``Union`` and ``Optional`` is supported by all
+type checkers. With a few exceptions [#ts-4819]_, the shorthand syntax
+is also supported::
+
+ def foo(x: int | str) -> int | None: ... # recommended
+ def foo(x: Union[int, str]) -> Optional[int]: ... # ok
+
+Module Level Attributes
+-----------------------
+
+Module level variables and constants can be annotated using either
+type comments or variable annotation syntax::
+
+ x: int # recommended
+ x: int = 0
+ x = 0 # type: int
+ x = ... # type: int
+
+The type of a variable is unspecified when the variable is unannotated or
+when the annotation
+and the assigned value disagree. As an exception, the ellipsis literal can
+stand in for any type::
+
+ x = 0 # type is unspecified
+ x = ... # type is unspecified
+ x: int = "" # type is unspecified
+ x: int = ... # type is int
+
+Classes
+-------
+
+Class definition syntax follows general Python syntax, but type checkers
+are only expected to understand the following constructs in class bodies:
+
+* The ellipsis literal ``...`` is ignored and used for empty
+ class bodies. Using ``pass`` in class bodies is undefined.
+* Instance attributes follow the same rules as module level attributes
+ (see above).
+* Method definitions (see below) and properties.
+* Method aliases.
+* Inner class definitions.
+
+More complex statements don't need to be supported::
+
+ class Simple: ...
+
+ class Complex(Base):
+ read_write: int
+ @property
+ def read_only(self) -> int: ...
+ def do_stuff(self, y: str) -> None: ...
+ doStuff = do_stuff
+
+The type of generic classes can be narrowed by annotating the ``self``
+argument of the ``__init__`` method::
+
+ class Foo(Generic[_T]):
+ @overload
+ def __init__(self: Foo[str], type: Literal["s"]) -> None: ...
+ @overload
+ def __init__(self: Foo[int], type: Literal["i"]) -> None: ...
+ @overload
+ def __init__(self, type: str) -> None: ...
+
+The class must match the class in which it is declared. Using other classes,
+including sub or super classes, will not work. In addition, the ``self``
+annotation cannot contain type variables.
+
+.. _supported-functions:
+
+Functions and Methods
+---------------------
+
+Function and method definition syntax follows general Python syntax.
+Unless an argument name is prefixed with two underscores (but not suffixed
+with two underscores), it can be used as a keyword argument [#pep484]_::
+
+ # x is positional-only
+ # y can be used positionally or as keyword argument
+ # z is keyword-only
+ def foo(__x, y, *, z): ...
+
+PEP 570 [#pep570]_ style positional-only parameters are currently not
+supported.
+
+If an argument or return type is unannotated, per PEP 484 [#pep484]_ its
+type is assumed to be ``Any``. It is preferred to leave unknown
+types unannotated rather than explicitly marking them as ``Any``, as some
+type checkers can optionally warn about unannotated arguments.
+
+If an argument has a literal or constant default value, it must match the implementation
+and the type of the argument (if specified) must match the default value.
+Alternatively, ``...`` can be used in place of any default value::
+
+ # The following arguments all have type Any.
+ def unannotated(a, b=42, c=...): ...
+ # The following arguments all have type int.
+ def annotated(a: int, b: int = 42, c: int = ...): ...
+ # The following default values are invalid and the types are unspecified.
+ def invalid(a: int = "", b: Foo = Foo()): ...
+
+For a class ``C``, the type of the first argument to a classmethod is
+assumed to be ``type[C]``, if unannotated. For other non-static methods,
+its type is assumed to be ``C``::
+
+ class Foo:
+ def do_things(self): ... # self has type Foo
+ @classmethod
+ def create_it(cls): ... # cls has type Type[Foo]
+ @staticmethod
+ def utility(x): ... # x has type Any
+
+But::
+
+ _T = TypeVar("_T")
+
+ class Foo:
+ def do_things(self: _T) -> _T: ... # self has type _T
+ @classmethod
+ def create_it(cls: _T) -> _T: ... # cls has type _T
+
+PEP 612 [#pep612]_ parameter specification variables (``ParamSpec``)
+are supported in argument and return types::
+
+ _P = ParamSpec("_P")
+ _R = TypeVar("_R")
+
+ def foo(cb: Callable[_P, _R], *args: _P.args, **kwargs: _P.kwargs) -> _R: ...
+
+However, ``Concatenate`` from PEP 612 is not yet supported; nor is using
+a ``ParamSpec`` to parameterize a generic class.
+
+PEP 647 [#pep647]_ type guards are supported.
+
+Using a function or method body other than the ellipsis literal is currently
+unspecified. Stub authors may experiment with other bodies, but it is up to
+individual type checkers how to interpret them::
+
+ def foo(): ... # compatible
+ def bar(): pass # behavior undefined
+
+All variants of overloaded functions and methods must have an ``@overload``
+decorator::
+
+ @overload
+ def foo(x: str) -> str: ...
+ @overload
+ def foo(x: float) -> int: ...
+
+The following (which would be used in the implementation) is wrong in
+type stubs::
+
+ @overload
+ def foo(x: str) -> str: ...
+ @overload
+ def foo(x: float) -> int: ...
+ def foo(x: str | float) -> Any: ...
+
+Aliases and NewType
+-------------------
+
+Type checkers should accept module-level type aliases, optionally using
+``TypeAlias`` (PEP 613 [#pep613]_), e.g.::
+
+ _IntList = list[int]
+ _StrList: TypeAlias = list[str]
+
+Type checkers should also accept regular module-level or class-level aliases,
+e.g.::
+
+ def a() -> None: ...
+ b = a
+
+ class C:
+ def f(self) -> int: ...
+ g = f
+
+A type alias may contain type variables. As per PEP 484 [#pep484]_,
+all type variables must be substituted when the alias is used::
+
+ _K = TypeVar("_K")
+ _V = TypeVar("_V")
+ _MyMap: TypeAlias = dict[str, dict[_K, _V]]
+
+ # either concrete types or other type variables can be substituted
+ def f(x: _MyMap[str, _V]) -> _V: ...
+ # explicitly substitute in Any rather than using a bare alias
+ def g(x: _MyMap[Any, Any]) -> Any: ...
+
+Otherwise, type variables in aliases follow the same rules as type variables in
+generic class definitions.
+
+``typing.NewType`` is also supported in stubs.
+
+Decorators
+----------
+
+Type stubs may only use decorators defined in the ``typing`` module, plus a
+fixed set of additional ones:
+
+* ``classmethod``
+* ``staticmethod``
+* ``property`` (including ``.setter``)
+* ``abc.abstractmethod``
+* ``dataclasses.dataclass``
+* ``asyncio.coroutine`` (although ``async`` should be used instead)
+
+The behavior of other decorators should instead be incorporated into the types.
+For example, for the following function::
+
+ import contextlib
+ @contextlib.contextmanager
+ def f():
+ yield 42
+
+the stub definition should be::
+
+ from contextlib import AbstractContextManager
+ def f() -> AbstractContextManager[int]: ...
+
+Version and Platform Checks
+---------------------------
+
+Type stubs for libraries that support multiple Python versions can use version
+checks to supply version-specific type hints. Type stubs for different Python
+versions should still conform to the most recent supported Python version's
+syntax, as explain in the Syntax_ section above.
+
+Version checks are if-statements that use ``sys.version_info`` to determine the
+current Python version. Version checks should only check against the ``major`` and
+``minor`` parts of ``sys.version_info``. Type checkers are only required to
+support the tuple-based version check syntax::
+
+ if sys.version_info >= (3,):
+ # Python 3-specific type hints. This tuple-based syntax is recommended.
+ else:
+ # Python 2-specific type hints.
+
+ if sys.version_info >= (3, 5):
+ # Specific minor version features can be easily checked with tuples.
+
+ if sys.version_info < (3,):
+ # This is only necessary when a feature has no Python 3 equivalent.
+
+Type stubs should avoid checking against ``sys.version_info.major``
+directly and should not use comparison operators other than ``<`` and ``>=``.
+
+No::
+
+ if sys.version_info.major >= 3:
+ # Semantically the same as the first tuple check.
+
+ if sys.version_info[0] >= 3:
+ # This is also the same.
+
+ if sys.version_info <= (2, 7):
+ # This does not work because e.g. (2, 7, 1) > (2, 7).
+
+Some type stubs also may need to specify type hints for different platforms.
+Platform checks must be equality comparisons between ``sys.platform`` and the name
+of a platform as a string literal:
+
+Yes::
+
+ if sys.platform == 'win32':
+ # Windows-specific type hints.
+ else:
+ # Posix-specific type hints.
+
+No::
+
+ if sys.platform.startswith('linux'):
+ # Not necessary since Python 3.3.
+
+ if sys.platform in ['linux', 'cygwin', 'darwin']:
+ # Only '==' or '!=' should be used in platform checks.
+
+Version and platform comparisons can be chained using the ``and`` and ``or``
+operators::
+
+ if sys.platform == 'linux' and (sys.version_info < (3,) or sys,version_info >= (3, 7)): ...
+
+Enums
+-----
+
+Enum classes are supported in stubs, regardless of the Python version targeted by
+the stubs.
+
+Enum members may be specified just like other forms of assignments, for example as
+``x: int``, ``x = 0``, or ``x = ...``. The first syntax is preferred because it
+allows type checkers to correctly type the ``.value`` attribute of enum members,
+without providing unnecessary information like the runtime value of the enum member.
+
+Additional properties on enum members should be specified with ``@property``, so they
+do not get interpreted by type checkers as enum members.
+
+Yes::
+
+ from enum import Enum
+
+ class Color(Enum):
+ RED: int
+ BLUE: int
+ @property
+ def rgb_value(self) -> int: ...
+
+ class Color(Enum):
+ # discouraged; type checkers will not understand that Color.RED.value is an int
+ RED = ...
+ BLUE = ...
+ @property
+ def rgb_value(self) -> int: ...
+
+No::
+
+ from enum import Enum
+
+ class Color(Enum):
+ RED: int
+ BLUE: int
+ rgb_value: int # no way for type checkers to know that this is not an enum member
+
+Unsupported Features
+--------------------
+
+Currently, the following features are not supported by all type checkers
+and should not be used in stubs:
+
+* Positional-only argument syntax (PEP 570 [#pep570]_). Instead, use
+ the syntax described in the section :ref:`supported-functions`.
+ [#ts-4972]_
+
+Type Stub Content
+=================
+
+This section documents best practices on what elements to include or
+leave out of type stubs.
+
+Modules excluded fom stubs
+--------------------------
+
+Not all modules should be included into stubs.
+
+It is recommended to exclude:
+
+1. Implementation details, with `multiprocessing/popen_spawn_win32.py <https://github.com/python/cpython/blob/main/Lib/multiprocessing/popen_spawn_win32.py>`_ as a notable example
+2. Modules that are not supposed to be imported, such as ``__main__.py``
+3. Protected modules that start with a single ``_`` char. However, when needed protected modules can still be added (see :ref:`undocumented-objects` section below)
+
+Public Interface
+----------------
+
+Stubs should include the complete public interface (classes, functions,
+constants, etc.) of the module they cover, but it is not always
+clear exactly what is part of the interface.
+
+The following should always be included:
+
+* All objects listed in the module's documentation.
+* All objects included in ``__all__`` (if present).
+
+Other objects may be included if they are not prefixed with an underscore
+or if they are being used in practice. (See the next section.)
+
+.. _undocumented-objects:
+
+Undocumented Objects
+--------------------
+
+Undocumented objects may be included as long as they are marked with a comment
+of the form ``# undocumented``.
+
+Example::
+
+ def list2cmdline(seq: Sequence[str]) -> str: ... # undocumented
+
+Such undocumented objects are allowed because omitting objects can confuse
+users. Users who see an error like "module X has no attribute Y" will
+not know whether the error appeared because their code had a bug or
+because the stub is wrong. Although it may also be helpful for a type
+checker to point out usage of private objects, false negatives (no errors for
+wrong code) are preferable over false positives (type errors
+for correct code). In addition, even for private objects a type checker
+can be helpful in pointing out that an incorrect type was used.
+
+``__all__``
+------------
+
+A type stub should contain an ``__all__`` variable if and only if it also
+present at runtime. In that case, the contents of ``__all__`` should be
+identical in the stub and at runtime. If the runtime dynamically adds
+or removes elements (for example if certain functions are only available on
+some platforms), include all possible elements in the stubs.
+
+Stub-Only Objects
+-----------------
+
+Definitions that do not exist at runtime may be included in stubs to aid in
+expressing types. Sometimes, it is desirable to make a stub-only class available
+to a stub's users - for example, to allow them to type the return value of a
+public method for which a library does not provided a usable runtime type::
+
+ from typing import Protocol
+
+ class _Readable(Protocol):
+ def read(self) -> str: ...
+
+ def get_reader() -> _Readable: ...
+
+Structural Types
+----------------
+
+As seen in the example with ``_Readable`` in the previous section, a common use
+of stub-only objects is to model types that are best described by their
+structure. These objects are called protocols [#pep544]_, and it is encouraged
+to use them freely to describe simple structural types.
+
+It is `recommended <#private-definitions>`_ to prefix stubs-only object names with ``_``.
+
+Incomplete Stubs
+----------------
+
+Partial stubs can be useful, especially for larger packages, but they should
+follow the following guidelines:
+
+* Included functions and methods should list all arguments, but the arguments
+ can be left unannotated.
+* Do not use ``Any`` to mark unannotated arguments or return values.
+* Partial classes should include a ``__getattr__()`` method marked with an
+ ``# incomplete`` comment (see example below).
+* Partial modules (i.e. modules that are missing some or all classes,
+ functions, or attributes) should include a top-level ``__getattr__()``
+ function marked with an ``# incomplete`` comment (see example below).
+* Partial packages (i.e. packages that are missing one or more sub-modules)
+ should have a ``__init__.pyi`` stub that is marked as incomplete (see above).
+ A better alternative is to create empty stubs for all sub-modules and
+ mark them as incomplete individually.
+
+Example of a partial module with a partial class ``Foo`` and a partially
+annotated function ``bar()``::
+
+ def __getattr__(name: str) -> Any: ... # incomplete
+
+ class Foo:
+ def __getattr__(self, name: str) -> Any: # incomplete
+ x: int
+ y: str
+
+ def bar(x: str, y, *, z=...): ...
+
+The ``# incomplete`` comment is mainly intended as a reminder for stub
+authors, but can be used by tools to flag such items.
+
+Attribute Access
+----------------
+
+Python has several methods for customizing attribute access: ``__getattr__``,
+``__getattribute__``, ``__setattr__``, and ``__delattr__``. Of these,
+``__getattr__`` and ``__setattr___`` should sometimes be included in stubs.
+
+In addition to marking incomplete definitions, ``__getattr__`` should be
+included when a class or module allows any name to be accessed. For example, consider
+the following class::
+
+ class Foo:
+ def __getattribute__(self, name):
+ return self.__dict__.setdefault(name)
+
+An appropriate stub definition is::
+
+ from typing import Any
+ class Foo:
+ def __getattr__(self, name: str) -> Any | None: ...
+
+Note that only ``__getattr__``, not ``__getattribute__``, is guaranteed to be
+supported in stubs.
+
+On the other hand, ``__getattr__`` should be omitted even if the source code
+includes it, if only limited names are allowed. For example, consider this class::
+
+ class ComplexNumber:
+ def __init__(self, n):
+ self._n = n
+ def __getattr__(self, name):
+ if name in ("real", "imag"):
+ return getattr(self._n, name)
+ raise AttributeError(name)
+
+In this case, the stub should list the attributes individually::
+
+ class ComplexNumber:
+ @property
+ def real(self) -> float: ...
+ @property
+ def imag(self) -> float: ...
+ def __init__(self, n: complex) -> None: ...
+
+``__setattr___`` should be included when a class allows any name to be set and
+restricts the type. For example::
+
+ class IntHolder:
+ def __setattr__(self, name, value):
+ if isinstance(value, int):
+ return super().__setattr__(name, value)
+ raise ValueError(value)
+
+A good stub definition would be::
+
+ class IntHolder:
+ def __setattr__(self, name: str, value: int) -> None: ...
+
+``__delattr__`` should not be included in stubs.
+
+Finally, even in the presence of ``__getattr__`` and ``__setattr__``, it is
+still recommended to separately define known attributes.
+
+Constants
+---------
+
+When the value of a constant is important, annotate it using ``Literal``
+instead of its type.
+
+Yes::
+
+ TEL_LANDLINE: Literal["landline"]
+ TEL_MOBILE: Literal["mobile"]
+ DAY_FLAG: Literal[0x01]
+ NIGHT_FLAG: Literal[0x02]
+
+No::
+
+ TEL_LANDLINE: str
+ TEL_MOBILE: str
+ DAY_FLAG: int
+ NIGHT_FLAG: int
+
+Documentation or Implementation
+-------------------------------
+
+Sometimes a library's documented types will differ from the actual types in the
+code. In such cases, type stub authors should use their best judgment. Consider
+these two examples::
+
+ def print_elements(x):
+ """Print every element of list x."""
+ for y in x:
+ print(y)
+
+ def maybe_raise(x):
+ """Raise an error if x (a boolean) is true."""
+ if x:
+ raise ValueError()
+
+The implementation of ``print_elements`` takes any iterable, despite the
+documented type of ``list``. In this case, annotate the argument as
+``Iterable[Any]``, to follow this PEP's style recommendation of preferring
+abstract types.
+
+For ``maybe_raise``, on the other hand, it is better to annotate the argument as
+``bool`` even though the implementation accepts any object. This guards against
+common mistakes like unintentionally passing in ``None``.
+
+If in doubt, consider asking the library maintainers about their intent.
+
+Style Guide
+===========
+
+The recommendations in this section are aimed at type stub authors
+who wish to provide a consistent style for type stubs. Type checkers
+should not reject stubs that do not follow these recommendations, but
+linters can warn about them.
+
+Stub files should generally follow the Style Guide for Python Code (PEP 8)
+[#pep8]_. There are a few exceptions, outlined below, that take the
+different structure of stub files into account and are aimed to create
+more concise files.
+
+Maximum Line Length
+-------------------
+
+Type stubs should be limited to 130 characters per line.
+
+Blank Lines
+-----------
+
+Do not use empty lines between functions, methods, and fields, except to
+group them with one empty line. Use one empty line around classes, but do not
+use empty lines between body-less classes, except for grouping.
+
+Yes::
+
+ def time_func() -> None: ...
+ def date_func() -> None: ...
+
+ def ip_func() -> None: ...
+
+ class Foo:
+ x: int
+ y: int
+ def __init__(self) -> None: ...
+
+ class MyError(Exception): ...
+ class AnotherError(Exception): ...
+
+No::
+
+ def time_func() -> None: ...
+
+ def date_func() -> None: ... # do no leave unnecessary empty lines
+
+ def ip_func() -> None: ...
+
+
+ class Foo: # leave only one empty line above
+ x: int
+ class MyError(Exception): ... # leave an empty line between the classes
+
+Shorthand Syntax
+----------------
+
+Where possible, use shorthand syntax for unions instead of
+``Union`` or ``Optional``. ``None`` should be the last
+element of an union.
+
+Yes::
+
+ def foo(x: str | int) -> None: ...
+ def bar(x: str | None) -> int | None: ...
+
+No::
+
+ def foo(x: Union[str, int]) -> None: ...
+ def bar(x: Optional[str]) -> Optional[int]: ...
+ def baz(x: None | str) -> None: ...
+
+Module Level Attributes
+-----------------------
+
+Do not use an assignment for module-level attributes.
+
+Yes::
+
+ CONST: Literal["const"]
+ x: int
+
+No::
+
+ CONST = "const"
+ x: int = 0
+ y: float = ...
+ z = 0 # type: int
+ a = ... # type: int
+
+Type Aliases
+------------
+
+Use ``TypeAlias`` for type aliases (but not for regular aliases).
+
+Yes::
+
+ _IntList: TypeAlias = list[int]
+ g = os.stat
+ Path = pathlib.Path
+ ERROR = errno.EEXIST
+
+No::
+
+ _IntList = list[int]
+ g: TypeAlias = os.stat
+ Path: TypeAlias = pathlib.Path
+ ERROR: TypeAlias = errno.EEXIST
+
+Classes
+-------
+
+Classes without bodies should use the ellipsis literal ``...`` in place
+of the body on the same line as the class definition.
+
+Yes::
+
+ class MyError(Exception): ...
+
+No::
+
+ class MyError(Exception):
+ ...
+ class AnotherError(Exception): pass
+
+Instance attributes and class variables follow the same recommendations as
+module level attributes:
+
+Yes::
+
+ class Foo:
+ c: ClassVar[str]
+ x: int
+
+No::
+
+ class Foo:
+ c: ClassVar[str] = ""
+ d: ClassVar[int] = ...
+ x = 4
+ y: int = ...
+
+Functions and Methods
+---------------------
+
+Use the same argument names as in the implementation, because
+otherwise using keyword arguments will fail. Of course, this
+does not apply to positional-only arguments, which are marked with a double
+underscore.
+
+Use the ellipsis literal ``...`` in place of actual default argument
+values. Use an explicit ``X | None`` annotation instead of
+a ``None`` default.
+
+Yes::
+
+ def foo(x: int = ...) -> None: ...
+ def bar(y: str | None = ...) -> None: ...
+
+No::
+
+ def foo(x: int = 0) -> None: ...
+ def bar(y: str = None) -> None: ...
+ def baz(z: str | None = None) -> None: ...
+
+Do not annotate ``self`` and ``cls`` in method definitions, except when
+referencing a type variable.
+
+Yes::
+
+ _T = TypeVar("_T")
+ class Foo:
+ def bar(self) -> None: ...
+ @classmethod
+ def create(cls: type[_T]) -> _T: ...
+
+No::
+
+ class Foo:
+ def bar(self: Foo) -> None: ...
+ @classmethod
+ def baz(cls: type[Foo]) -> int: ...
+
+The bodies of functions and methods should consist of only the ellipsis
+literal ``...`` on the same line as the closing parenthesis and colon.
+
+Yes::
+
+ def to_int1(x: str) -> int: ...
+ def to_int2(
+ x: str,
+ ) -> int: ...
+
+No::
+
+ def to_int1(x: str) -> int:
+ return int(x)
+ def to_int2(x: str) -> int:
+ ...
+ def to_int3(x: str) -> int: pass
+
+.. _private-definitions:
+
+Private Definitions
+-------------------
+
+Type variables, type aliases, and other definitions that should not
+be used outside the stub should be marked as private by prefixing them
+with an underscore.
+
+Yes::
+
+ _T = TypeVar("_T")
+ _DictList = Dict[str, List[Optional[int]]
+
+No::
+
+ T = TypeVar("T")
+ DictList = Dict[str, List[Optional[int]]]
+
+Language Features
+-----------------
+
+Use the latest language features available as outlined
+in the Syntax_ section, even for stubs targeting older Python versions.
+Do not use quotes around forward references and do not use ``__future__``
+imports.
+
+Yes::
+
+ class Py35Class:
+ x: int
+ forward_reference: OtherClass
+ class OtherClass: ...
+
+No::
+
+ class Py35Class:
+ x = 0 # type: int
+ forward_reference: 'OtherClass'
+ class OtherClass: ...
+
+Types
+-----
+
+Generally, use ``Any`` when a type cannot be expressed appropriately
+with the current type system or using the correct type is unergonomic.
+
+Use ``float`` instead of ``int | float``.
+Use ``None`` instead of ``Literal[None]``.
+For argument types,
+use ``bytes`` instead of ``bytes | memoryview | bytearray``.
+
+Use ``Text`` in stubs that support Python 2 when something accepts both
+``str`` and ``unicode``. Avoid using ``Text`` in stubs or branches for
+Python 3 only.
+
+Yes::
+
+ if sys.version_info < (3,):
+ def foo(s: Text) -> None: ...
+ else:
+ def foo(s: str, *, i: int) -> None: ...
+ def bar(s: Text) -> None: ...
+
+No::
+
+ if sys.version_info < (3,):
+ def foo(s: unicode) -> None: ...
+ else:
+ def foo(s: Text, *, i: int) -> None: ...
+
+For arguments, prefer protocols and abstract types (``Mapping``,
+``Sequence``, ``Iterable``, etc.). If an argument accepts literally any value,
+use ``object`` instead of ``Any``.
+
+For return values, prefer concrete types (``list``, ``dict``, etc.) for
+concrete implementations. The return values of protocols
+and abstract base classes must be judged on a case-by-case basis.
+
+Yes::
+
+ def map_it(input: Iterable[str]) -> list[int]: ...
+ def create_map() -> dict[str, int]: ...
+ def to_string(o: object) -> str: ... # accepts any object
+
+No::
+
+ def map_it(input: list[str]) -> list[int]: ...
+ def create_map() -> MutableMapping[str, int]: ...
+ def to_string(o: Any) -> str: ...
+
+Maybe::
+
+ class MyProto(Protocol):
+ def foo(self) -> list[int]: ...
+ def bar(self) -> Mapping[str]: ...
+
+Avoid union return types, since they require ``isinstance()`` checks.
+Use ``Any`` or ``X | Any`` if necessary.
+
+Use built-in generics instead of the aliases from ``typing``,
+where possible. See the section `Built-in Generics`_ for cases,
+where it's not possible to use them.
+
+Yes::
+
+ from collections.abc import Iterable
+
+ def foo(x: type[MyClass]) -> list[str]: ...
+ def bar(x: Iterable[str]) -> None: ...
+
+No::
+
+ from typing import Iterable, List, Type
+
+ def foo(x: Type[MyClass]) -> List[str]: ...
+ def bar(x: Iterable[str]) -> None: ...
+
+NamedTuple and TypedDict
+------------------------
+
+Use the class-based syntax for ``typing.NamedTuple`` and
+``typing.TypedDict``, following the Classes section of this style guide.
+
+Yes::
+
+ from typing import NamedTuple, TypedDict
+ class Point(NamedTuple):
+ x: float
+ y: float
+
+ class Thing(TypedDict):
+ stuff: str
+ index: int
+
+No::
+
+ from typing import NamedTuple, TypedDict
+ Point = NamedTuple("Point", [('x', float), ('y', float)])
+ Thing = TypedDict("Thing", {'stuff': str, 'index': int})
+
+References
+==========
+
+PEPs
+----
+
+.. [#pep8] PEP 8 -- Style Guide for Python Code, van Rossum et al. (https://www.python.org/dev/peps/pep-0008/)
+.. [#pep484] PEP 484 -- Type Hints, van Rossum et al. (https://www.python.org/dev/peps/pep-0484)
+.. [#pep492] PEP 492 -- Coroutines with async and await syntax, Selivanov (https://www.python.org/dev/peps/pep-0492/)
+.. [#pep526] PEP 526 -- Syntax for Variable Annotations, Gonzalez et al. (https://www.python.org/dev/peps/pep-0526)
+.. [#pep544] PEP 544 -- Protocols: Structural Subtyping, Levkivskyi et al. (https://www.python.org/dev/peps/pep-0544)
+.. [#pep561] PEP 561 -- Distributing and Packaging Type Information, Smith (https://www.python.org/dev/peps/pep-0561)
+.. [#pep570] PEP 570 -- Python Positional-Only Parameters, Hastings et al. (https://www.python.org/dev/peps/pep-0570)
+.. [#pep585] PEP 585 -- Type Hinting Generics In Standard Collections, Langa (https://www.python.org/dev/peps/pep-0585)
+.. [#pep604] PEP 604 -- Allow writing union types as X | Y, Prados and Moss (https://www.python.org/dev/peps/pep-0604)
+.. [#pep612] PEP 612 -- Parameter Specification Variables, Mendoza (https://www.python.org/dev/peps/pep-0612)
+.. [#pep613] PEP 613 -- Explicit Type Aliases, Zhu (https://www.python.org/dev/peps/pep-0613)
+.. [#pep647] PEP 647 -- User-Defined Type Guards, Traut (https://www.python.org/dev/peps/pep-0647)
+.. [#pep3107] PEP 3107 -- Function Annotations, Winter and Lownds (https://www.python.org/dev/peps/pep-3107)
+
+Bugs
+----
+
+.. [#ts-4819] typeshed issue #4819 -- PEP 604 tracker (https://github.com/python/typeshed/issues/4819)
+.. [#ts-4972] typeshed issue #4972 -- PEP 570 tracker (https://github.com/python/typeshed/issues/4972)
+
+Copyright
+=========
+
+This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.
diff --git a/docs/source/type_compatibility.rst b/docs/source/type_compatibility.rst
new file mode 100644
index 0000000..43ebd32
--- /dev/null
+++ b/docs/source/type_compatibility.rst
@@ -0,0 +1,17 @@
+******************
+Type Compatibility
+******************
+
+
+The Class Hierarchy
+===================
+
+Mutable Containers
+------------------
+
+Comparing Callables: Covariance and Contravariance
+--------------------------------------------------
+
+
+Metaclasses
+===========
diff --git a/docs/source/type_system.rst b/docs/source/type_system.rst
new file mode 100644
index 0000000..6d7954b
--- /dev/null
+++ b/docs/source/type_system.rst
@@ -0,0 +1,58 @@
+***************
+The Type System
+***************
+
+Built-in Types
+==============
+
+`typing Module Documentation <https://docs.python.org/3/library/typing.html>`__
+
+Built-in Primitives
+-------------------
+
+Built-in operators
+------------------
+
+Advanced Types
+--------------
+
+
+Simple User-Defined Types
+=========================
+
+
+Type Aliases
+============
+
+Recursive Aliases
+-----------------
+
+
+Data Structures
+===============
+
+Typed Dictionary
+----------------
+
+Dataclass
+---------
+
+
+Generic Types
+=============
+
+
+Type Variables
+==============
+
+TypeVar
+-------
+
+Variadics
+---------
+
+ParamSpec
+^^^^^^^^^
+
+TypeVarTuple
+^^^^^^^^^^^^
diff --git a/docs/source/unreachable.rst b/docs/source/unreachable.rst
new file mode 100644
index 0000000..16c37d8
--- /dev/null
+++ b/docs/source/unreachable.rst
@@ -0,0 +1,148 @@
+.. _unreachable:
+
+********************************************
+Unreachable Code and Exhaustiveness Checking
+********************************************
+
+Sometimes it is necessary to write code that should never execute, and
+sometimes we write code that we expect to execute, but that is actually
+unreachable. The type checker can help in both cases.
+
+In this guide, we'll cover:
+
+- ``Never``, the primitive type used for unreachable code
+- ``assert_never()``, a helper for exhaustiveness checking
+- Directly marking code as unreachable
+- Detecting unexpectedly unreachable code
+
+``Never`` and ``NoReturn``
+==========================
+
+Type theory has a concept of a
+`bottom type <https://en.wikipedia.org/wiki/Bottom_type>`__,
+a type that has no values. Concretely, this can be used to represent
+the return type of a function that never returns, or the argument type
+of a function that may never be called. You can also think of the
+bottom type as a union with no members.
+
+The Python type system has long provided a type called ``NoReturn``.
+While it was originally meant only for functions that never return,
+this concept is naturally extended to the bottom type in general, and all
+type checkers treat ``NoReturn`` as a general bottom type.
+
+To make the meaning of this type more explicit, Python 3.11 and
+typing-extensions 4.1 add a new primitive, ``Never``. To type checkers,
+it has the same meaning as ``NoReturn``.
+
+In this guide, we'll use ``Never`` for the bottom type, but if you cannot
+use it yet, you can always use ``typing.NoReturn`` instead.
+
+``assert_never()`` and Exhaustiveness Checking
+==============================================
+
+The ``Never`` type can be leveraged to perform static exhaustiveness checking,
+where we use the type checker to make sure that we covered all possible
+cases. For example, this can come up when code performs a separate action
+for each member of an enum, or for each type in a union.
+
+To have the type checker do exhaustiveness checking for us, we call a
+function with a parameter typed as ``Never``. The type checker will allow
+this call only if it can prove that the code is not reachable.
+
+As an example, consider this simple calculator:
+
+.. code:: python
+
+ import enum
+ from typing_extensions import Never
+
+ def assert_never(arg: Never) -> Never:
+ raise AssertionError("Expected code to be unreachable")
+
+ class Op(enum.Enum):
+ ADD = 1
+ SUBTRACT = 2
+
+ def calculate(left: int, op: Op, right: int) -> int:
+ match op:
+ case Op.ADD:
+ return left + right
+ case Op.SUBTRACT:
+ return left - right
+ case _:
+ assert_never(op)
+
+The ``match`` statement covers all members of the ``Op`` enum,
+so the ``assert_never()`` call is unreachable and the type checker
+will accept this code. However, if you add another member to the
+enum (say, ``MULTIPLY``) but don't update the ``match`` statement,
+the type checker will give an error saying that you are not handling
+the ``MULTIPLY`` case.
+
+Because the ``assert_never()`` helper function is frequently useful,
+it is provided by the standard library as ``typing.assert_never``
+starting in Python 3.11,
+and is also present in ``typing_extensions`` starting at version 4.1.
+However, it is also possible to define a similar function in your own
+code, for example if you want to customize the runtime error message.
+
+You can also use ``assert_never()`` with a sequence of ``if`` statements:
+
+.. code:: python
+
+ def calculate(left: int, op: Op, right: int) -> int:
+ if op is Op.ADD:
+ return left + right
+ elif op is Op.SUBTRACT:
+ return left - right
+ else:
+ assert_never(op)
+
+Marking Code as Unreachable
+=======================
+
+Sometimes a piece of code is unreachable, but the type system is not
+powerful enough to recognize that. For example, consider a function that
+finds the lowest unused street number in a street:
+
+.. code:: python
+
+ import itertools
+
+ def is_used(street: str, number: int) -> bool:
+ ...
+
+ def lowest_unused(street: str) -> int:
+ for i in itertools.count(1):
+ if not is_used(street, i):
+ return i
+ assert False, "unreachable"
+
+Because ``itertools.count()`` is an infinite iterator, this function
+will never reach the ``assert False`` statement. However, there is
+no way for the type checker to know that, so without the ``assert False``,
+the type checker will complain that the function is missing a return
+statement.
+
+Note how this is different from ``assert_never()``:
+
+- If we used ``assert_never()`` in the ``lowest_unused()`` function,
+ the type checker would produce an error, because the type checker
+ cannot prove that the line is unreachable.
+- If we used ``assert False`` instead of ``assert_never()`` in the
+ ``calculate()`` example above, we would not get the benefits of
+ exhaustiveness checking. If the code is actually reachable,
+ the type checker will not warn us and we could hit the assertion
+ at runtime.
+
+While ``assert False`` is the most idiomatic way to express this pattern,
+any statement that ends execution will do. For example, you could raise
+an exception or call a function that returns ``Never``.
+
+Detecting Unexpectedly Unreachable Code
+=======================================
+
+Another possible problem is code that is supposed to execute, but that
+can actually be statically determined to be unreachable.
+Some type checkers have an option that enables warnings for code
+detected as unreachable (e.g., ``--warn-unreachable`` in mypy).
diff --git a/scripts/requirements.txt b/scripts/requirements.txt
new file mode 100644
index 0000000..d5f8f29
--- /dev/null
+++ b/scripts/requirements.txt
@@ -0,0 +1,2 @@
+requests>=2.25.0,<3
+types-requests>=2.25.0,<3
diff --git a/scripts/typing-summary.py b/scripts/typing-summary.py
new file mode 100755
index 0000000..f5f9825
--- /dev/null
+++ b/scripts/typing-summary.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python3
+
+"""
+Generate a summary of last week's issues tagged with "topic: feature".
+
+The summary will include a list of new and changed issues and is sent each
+Monday at 0200 CE(S)T to the typing-sig mailing list. Due to limitation
+with GitHub Actions, the mail is sent from a private server, currently
+maintained by @srittau.
+"""
+
+from __future__ import annotations
+
+import datetime
+from dataclasses import dataclass
+from typing import Any, Iterable, Sequence
+
+import requests
+
+ISSUES_API_URL = "https://api.github.com/repos/python/typing/issues"
+ISSUES_URL = "https://github.com/python/typing/issues?q=label%3A%22topic%3A+feature%22"
+ISSUES_LABEL = "topic: feature"
+SENDER_EMAIL = "Typing Bot <noreply@python.org>"
+RECEIVER_EMAIL = "typing-sig@python.org"
+
+
+@dataclass
+class Issue:
+ number: int
+ title: str
+ url: str
+ created: datetime.datetime
+ user: str
+ pull_request: bool = False
+
+
+def main() -> None:
+ since = previous_week_start()
+ issues = fetch_issues(since)
+ new, updated = split_issues(issues, since)
+ print_summary(since, new, updated)
+
+
+def previous_week_start() -> datetime.date:
+ today = datetime.date.today()
+ return today - datetime.timedelta(days=today.weekday() + 7)
+
+
+def fetch_issues(since: datetime.date) -> list[Issue]:
+ """Return (new, updated) issues."""
+ j = requests.get(
+ ISSUES_API_URL,
+ params={
+ "labels": ISSUES_LABEL,
+ "since": f"{since:%Y-%m-%d}T00:00:00Z",
+ "per_page": "100",
+ "state": "open",
+ },
+ headers={"Accept": "application/vnd.github.v3+json"},
+ ).json()
+ assert isinstance(j, list)
+ return [parse_issue(j_i) for j_i in j]
+
+
+def parse_issue(j: Any) -> Issue:
+ number = j["number"]
+ title = j["title"]
+ url = j["html_url"]
+ created_at = datetime.datetime.fromisoformat(j["created_at"][:-1])
+ user = j["user"]["login"]
+ pull_request = "pull_request" in j
+ assert isinstance(number, int)
+ assert isinstance(title, str)
+ assert isinstance(url, str)
+ assert isinstance(user, str)
+ return Issue(number, title, url, created_at, user, pull_request)
+
+
+def split_issues(
+ issues: Iterable[Issue], since: datetime.date
+) -> tuple[list[Issue], list[Issue]]:
+ new = []
+ updated = []
+ for issue in issues:
+ if issue.created.date() >= since:
+ new.append(issue)
+ else:
+ updated.append(issue)
+ new.sort(key=lambda i: i.number)
+ updated.sort(key=lambda i: i.number)
+ return new, updated
+
+
+def print_summary(
+ since: datetime.date, new: Sequence[Issue], changed: Sequence[Issue]
+) -> None:
+ print(f"From: {SENDER_EMAIL}")
+ print(f"To: {RECEIVER_EMAIL}")
+ print(f"Subject: Opened and changed typing issues week {since:%G-W%V}")
+ print()
+ print(generate_mail(new, changed))
+
+
+def generate_mail(new: Sequence[Issue], changed: Sequence[Issue]) -> str:
+ if len(new) == 0 and len(changed) == 0:
+ s = (
+ "No issues or pull requests with the label 'topic: feature' were opened\n"
+ "or updated last week in the typing repository on GitHub.\n\n"
+ )
+ else:
+ s = (
+ "The following is an overview of all issues and pull requests in the\n"
+ "typing repository on GitHub with the label 'topic: feature'\n"
+ "that were opened or updated last week, excluding closed issues.\n\n"
+ "---------------------------------------------------\n\n"
+ )
+ if len(new) > 0:
+ s += "The following issues and pull requests were opened last week: \n\n"
+ s += "".join(generate_issue_text(issue) for issue in new)
+ s += "\n---------------------------------------------------\n\n"
+ if len(changed) > 0:
+ s += "The following issues and pull requests were updated last week: \n\n"
+ s += "".join(generate_issue_text(issue) for issue in changed)
+ s += "\n---------------------------------------------------\n\n"
+ s += (
+ "All issues and pull requests with the label 'topic: feature'\n"
+ "can be viewed under the following URL:\n\n"
+ )
+ s += ISSUES_URL
+ return s
+
+
+def generate_issue_text(issue: Issue) -> str:
+ s = f"#{issue.number:<5} "
+ if issue.pull_request:
+ s += "[PR] "
+ s += f"{issue.title}\n"
+ s += f" opened by @{issue.user}\n"
+ s += f" {issue.url}\n"
+ return s
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test-requirements.txt b/test-requirements.txt
new file mode 100644
index 0000000..658ae0a
--- /dev/null
+++ b/test-requirements.txt
@@ -0,0 +1,3 @@
+flake8
+flake8-bugbear
+flake8-pyi
diff --git a/typing_extensions/CHANGELOG b/typing_extensions/CHANGELOG
new file mode 100644
index 0000000..a9a5980
--- /dev/null
+++ b/typing_extensions/CHANGELOG
@@ -0,0 +1,71 @@
+# Unreleased
+
+- Add `typing.assert_type`. Backport from bpo-46480.
+- Drop support for Python 3.6. Original patch by Adam Turner (@AA-Turner).
+
+# Release 4.1.1 (February 13, 2022)
+
+- Fix importing `typing_extensions` on Python 3.7.0 and 3.7.1. Original
+ patch by Nikita Sobolev (@sobolevn).
+
+# Release 4.1.0 (February 12, 2022)
+
+- Runtime support for PEP 646, adding `typing_extensions.TypeVarTuple`
+ and `typing_extensions.Unpack`.
+- Add interaction of `Required` and `NotRequired` with `__required_keys__`,
+ `__optional_keys__` and `get_type_hints()`. Patch by David Cabot (@d-k-bo).
+- Runtime support for PEP 675 and `typing_extensions.LiteralString`.
+- Add `Never` and `assert_never`. Backport from bpo-46475.
+- `ParamSpec` args and kwargs are now equal to themselves. Backport from
+ bpo-46676. Patch by Gregory Beauregard (@GBeauregard).
+- Add `reveal_type`. Backport from bpo-46414.
+- Runtime support for PEP 681 and `typing_extensions.dataclass_transform`.
+- `Annotated` can now wrap `ClassVar` and `Final`. Backport from
+ bpo-46491. Patch by Gregory Beauregard (@GBeauregard).
+- Add missed `Required` and `NotRequired` to `__all__`. Patch by
+ Yuri Karabas (@uriyyo).
+- The `@final` decorator now sets the `__final__` attribute on the
+ decorated object to allow runtime introspection. Backport from
+ bpo-46342.
+- Add `is_typeddict`. Patch by Chris Moradi (@chrismoradi) and James
+ Hilton-Balfe (@Gobot1234).
+
+# Release 4.0.1 (November 30, 2021)
+
+- Fix broken sdist in release 4.0.0. Patch by Adam Turner (@AA-Turner).
+- Fix equality comparison for `Required` and `NotRequired`. Patch by
+ Jelle Zijlstra (@jellezijlstra).
+- Fix usage of `Self` as a type argument. Patch by Chris Wesseling
+ (@CharString) and James Hilton-Balfe (@Gobot1234).
+
+# Release 4.0.0 (November 14, 2021)
+
+- Starting with version 4.0.0, typing_extensions uses Semantic Versioning.
+ See the README for more information.
+- Dropped support for Python versions 3.5 and older, including Python 2.7.
+- Simplified backports for Python 3.6.0 and newer. Patch by Adam Turner (@AA-Turner).
+
+## Added in version 4.0.0
+
+- Runtime support for PEP 673 and `typing_extensions.Self`. Patch by
+ James Hilton-Balfe (@Gobot1234).
+- Runtime support for PEP 655 and `typing_extensions.Required` and `NotRequired`.
+ Patch by David Foster (@davidfstr).
+
+## Removed in version 4.0.0
+
+The following non-exported but non-private names have been removed as they are
+unneeded for supporting Python 3.6 and newer.
+
+- TypingMeta
+- OLD_GENERICS
+- SUBS_TREE
+- HAVE_ANNOTATED
+- HAVE_PROTOCOLS
+- V_co
+- VT_co
+
+# Previous releases
+
+Prior to release 4.0.0 we did not provide a changelog. Please check
+the Git history for details.
diff --git a/typing_extensions/LICENSE b/typing_extensions/LICENSE
new file mode 100644
index 0000000..583f9f6
--- /dev/null
+++ b/typing_extensions/LICENSE
@@ -0,0 +1,254 @@
+A. HISTORY OF THE SOFTWARE
+==========================
+
+Python was created in the early 1990s by Guido van Rossum at Stichting
+Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
+as a successor of a language called ABC. Guido remains Python's
+principal author, although it includes many contributions from others.
+
+In 1995, Guido continued his work on Python at the Corporation for
+National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
+in Reston, Virginia where he released several versions of the
+software.
+
+In May 2000, Guido and the Python core development team moved to
+BeOpen.com to form the BeOpen PythonLabs team. In October of the same
+year, the PythonLabs team moved to Digital Creations (now Zope
+Corporation, see http://www.zope.com). In 2001, the Python Software
+Foundation (PSF, see http://www.python.org/psf/) was formed, a
+non-profit organization created specifically to own Python-related
+Intellectual Property. Zope Corporation is a sponsoring member of
+the PSF.
+
+All Python releases are Open Source (see http://www.opensource.org for
+the Open Source Definition). Historically, most, but not all, Python
+releases have also been GPL-compatible; the table below summarizes
+the various releases.
+
+ Release Derived Year Owner GPL-
+ from compatible? (1)
+
+ 0.9.0 thru 1.2 1991-1995 CWI yes
+ 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
+ 1.6 1.5.2 2000 CNRI no
+ 2.0 1.6 2000 BeOpen.com no
+ 1.6.1 1.6 2001 CNRI yes (2)
+ 2.1 2.0+1.6.1 2001 PSF no
+ 2.0.1 2.0+1.6.1 2001 PSF yes
+ 2.1.1 2.1+2.0.1 2001 PSF yes
+ 2.1.2 2.1.1 2002 PSF yes
+ 2.1.3 2.1.2 2002 PSF yes
+ 2.2 and above 2.1.1 2001-now PSF yes
+
+Footnotes:
+
+(1) GPL-compatible doesn't mean that we're distributing Python under
+ the GPL. All Python licenses, unlike the GPL, let you distribute
+ a modified version without making your changes open source. The
+ GPL-compatible licenses make it possible to combine Python with
+ other software that is released under the GPL; the others don't.
+
+(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
+ because its license has a choice of law clause. According to
+ CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
+ is "not incompatible" with the GPL.
+
+Thanks to the many outside volunteers who have worked under Guido's
+direction to make these releases possible.
+
+
+B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
+===============================================================
+
+PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+--------------------------------------------
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation
+("PSF"), and the Individual or Organization ("Licensee") accessing and
+otherwise using this software ("Python") in source or binary form and
+its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+analyze, test, perform and/or display publicly, prepare derivative works,
+distribute, and otherwise use Python alone or in any derivative version,
+provided, however, that PSF's License Agreement and PSF's notice of copyright,
+i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+2011, 2012, 2013, 2014 Python Software Foundation; All Rights Reserved" are
+retained in Python alone or in any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python.
+
+4. PSF is making Python available to Licensee on an "AS IS"
+basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between PSF and
+Licensee. This License Agreement does not grant permission to use PSF
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Python, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
+-------------------------------------------
+
+BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
+
+1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
+office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
+Individual or Organization ("Licensee") accessing and otherwise using
+this software in source or binary form and its associated
+documentation ("the Software").
+
+2. Subject to the terms and conditions of this BeOpen Python License
+Agreement, BeOpen hereby grants Licensee a non-exclusive,
+royalty-free, world-wide license to reproduce, analyze, test, perform
+and/or display publicly, prepare derivative works, distribute, and
+otherwise use the Software alone or in any derivative version,
+provided, however, that the BeOpen Python License is retained in the
+Software, alone or in any derivative version prepared by Licensee.
+
+3. BeOpen is making the Software available to Licensee on an "AS IS"
+basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
+SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
+AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
+DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+5. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+6. This License Agreement shall be governed by and interpreted in all
+respects by the law of the State of California, excluding conflict of
+law provisions. Nothing in this License Agreement shall be deemed to
+create any relationship of agency, partnership, or joint venture
+between BeOpen and Licensee. This License Agreement does not grant
+permission to use BeOpen trademarks or trade names in a trademark
+sense to endorse or promote products or services of Licensee, or any
+third party. As an exception, the "BeOpen Python" logos available at
+http://www.pythonlabs.com/logos.html may be used according to the
+permissions granted on that web page.
+
+7. By copying, installing or otherwise using the software, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
+---------------------------------------
+
+1. This LICENSE AGREEMENT is between the Corporation for National
+Research Initiatives, having an office at 1895 Preston White Drive,
+Reston, VA 20191 ("CNRI"), and the Individual or Organization
+("Licensee") accessing and otherwise using Python 1.6.1 software in
+source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, CNRI
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use Python 1.6.1
+alone or in any derivative version, provided, however, that CNRI's
+License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
+1995-2001 Corporation for National Research Initiatives; All Rights
+Reserved" are retained in Python 1.6.1 alone or in any derivative
+version prepared by Licensee. Alternately, in lieu of CNRI's License
+Agreement, Licensee may substitute the following text (omitting the
+quotes): "Python 1.6.1 is made available subject to the terms and
+conditions in CNRI's License Agreement. This Agreement together with
+Python 1.6.1 may be located on the Internet using the following
+unique, persistent identifier (known as a handle): 1895.22/1013. This
+Agreement may also be obtained from a proxy server on the Internet
+using the following URL: http://hdl.handle.net/1895.22/1013".
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python 1.6.1 or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python 1.6.1.
+
+4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
+basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. This License Agreement shall be governed by the federal
+intellectual property law of the United States, including without
+limitation the federal copyright law, and, to the extent such
+U.S. federal law does not apply, by the law of the Commonwealth of
+Virginia, excluding Virginia's conflict of law provisions.
+Notwithstanding the foregoing, with regard to derivative works based
+on Python 1.6.1 that incorporate non-separable material that was
+previously distributed under the GNU General Public License (GPL), the
+law of the Commonwealth of Virginia shall govern this License
+Agreement only as to issues arising under or with respect to
+Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
+License Agreement shall be deemed to create any relationship of
+agency, partnership, or joint venture between CNRI and Licensee. This
+License Agreement does not grant permission to use CNRI trademarks or
+trade name in a trademark sense to endorse or promote products or
+services of Licensee, or any third party.
+
+8. By clicking on the "ACCEPT" button where indicated, or by copying,
+installing or otherwise using Python 1.6.1, Licensee agrees to be
+bound by the terms and conditions of this License Agreement.
+
+ ACCEPT
+
+
+CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
+--------------------------------------------------
+
+Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
+The Netherlands. All rights reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/typing_extensions/README.rst b/typing_extensions/README.rst
new file mode 100644
index 0000000..9abed04
--- /dev/null
+++ b/typing_extensions/README.rst
@@ -0,0 +1,146 @@
+=================
+Typing Extensions
+=================
+
+.. image:: https://badges.gitter.im/python/typing.svg
+ :alt: Chat at https://gitter.im/python/typing
+ :target: https://gitter.im/python/typing?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
+
+Overview
+========
+
+The ``typing_extensions`` module serves two related purposes:
+
+- Enable use of new type system features on older Python versions. For example,
+ ``typing.TypeGuard`` is new in Python 3.10, but ``typing_extensions`` allows
+ users on Python 3.6 through 3.9 to use it too.
+- Enable experimentation with new type system PEPs before they are accepted and
+ added to the ``typing`` module.
+
+New features may be added to ``typing_extensions`` as soon as they are specified
+in a PEP that has been added to the `python/peps <https://github.com/python/peps>`_
+repository. If the PEP is accepted, the feature will then be added to ``typing``
+for the next CPython release. No typing PEP has been rejected so far, so we
+haven't yet figured out how to deal with that possibility.
+
+Starting with version 4.0.0, ``typing_extensions`` uses
+`Semantic Versioning <https://semver.org/>`_. The
+major version is incremented for all backwards-incompatible changes.
+Therefore, it's safe to depend
+on ``typing_extensions`` like this: ``typing_extensions >=x.y, <(x+1)``,
+where ``x.y`` is the first version that includes all features you need.
+
+``typing_extensions`` supports Python versions 3.7 and higher. In the future,
+support for older Python versions will be dropped some time after that version
+reaches end of life.
+
+Included items
+==============
+
+This module currently contains the following:
+
+- Experimental features
+
+ - ``@dataclass_transform()`` (see PEP 681)
+
+- In ``typing`` since Python 3.11
+
+ - ``assert_never``
+ - ``assert_type``
+ - ``LiteralString`` (see PEP 675)
+ - ``Never``
+ - ``NotRequired`` (see PEP 655)
+ - ``reveal_type``
+ - ``Required`` (see PEP 655)
+ - ``Self`` (see PEP 673)
+ - ``TypeVarTuple`` (see PEP 646)
+ - ``Unpack`` (see PEP 646)
+
+- In ``typing`` since Python 3.10
+
+ - ``Concatenate`` (see PEP 612)
+ - ``ParamSpec`` (see PEP 612)
+ - ``ParamSpecArgs`` (see PEP 612)
+ - ``ParamSpecKwargs`` (see PEP 612)
+ - ``TypeAlias`` (see PEP 613)
+ - ``TypeGuard`` (see PEP 647)
+ - ``is_typeddict``
+
+- In ``typing`` since Python 3.9
+
+ - ``Annotated`` (see PEP 593)
+
+- In ``typing`` since Python 3.8
+
+ - ``final`` (see PEP 591)
+ - ``Final`` (see PEP 591)
+ - ``Literal`` (see PEP 586)
+ - ``Protocol`` (see PEP 544)
+ - ``runtime_checkable`` (see PEP 544)
+ - ``TypedDict`` (see PEP 589)
+ - ``get_origin`` (``typing_extensions`` provides this function only in Python 3.7+)
+ - ``get_args`` (``typing_extensions`` provides this function only in Python 3.7+)
+
+- In ``typing`` since Python 3.7
+
+ - ``OrderedDict``
+
+- In ``typing`` since Python 3.5 or 3.6 (see `the typing documentation
+ <https://docs.python.org/3.10/library/typing.html>`_ for details)
+
+ - ``AsyncContextManager``
+ - ``AsyncGenerator``
+ - ``AsyncIterable``
+ - ``AsyncIterator``
+ - ``Awaitable``
+ - ``ChainMap``
+ - ``ClassVar`` (see PEP 526)
+ - ``ContextManager``
+ - ``Coroutine``
+ - ``Counter``
+ - ``DefaultDict``
+ - ``Deque``
+ - ``NewType``
+ - ``NoReturn``
+ - ``overload``
+ - ``Text``
+ - ``Type``
+ - ``TYPE_CHECKING``
+ - ``get_type_hints``
+
+Other Notes and Limitations
+===========================
+
+Certain objects were changed after they were added to ``typing``, and
+``typing_extensions`` provides a backport even on newer Python versions:
+
+- ``TypedDict`` does not store runtime information
+ about which (if any) keys are non-required in Python 3.8, and does not
+ honor the "total" keyword with old-style ``TypedDict()`` in Python
+ 3.9.0 and 3.9.1.
+- ``get_origin`` and ``get_args`` lack support for ``Annotated`` in
+ Python 3.8 and lack support for ``ParamSpecArgs`` and ``ParamSpecKwargs``
+ in 3.9.
+- ``@final`` was changed in Python 3.11 to set the ``.__final__`` attribute.
+
+There are a few types whose interface was modified between different
+versions of typing. For example, ``typing.Sequence`` was modified to
+subclass ``typing.Reversible`` as of Python 3.5.3.
+
+These changes are _not_ backported to prevent subtle compatibility
+issues when mixing the differing implementations of modified classes.
+
+Certain types have incorrect runtime behavior due to limitations of older
+versions of the typing module:
+
+- ``ParamSpec`` and ``Concatenate`` will not work with ``get_args`` and
+ ``get_origin``. Certain PEP 612 special cases in user-defined
+ ``Generic``\ s are also not available.
+
+These types are only guaranteed to work for static type checking.
+
+Running tests
+=============
+
+To run tests, navigate into the appropriate source directory and run
+``test_typing_extensions.py``.
diff --git a/typing_extensions/pyproject.toml b/typing_extensions/pyproject.toml
new file mode 100644
index 0000000..fbd0180
--- /dev/null
+++ b/typing_extensions/pyproject.toml
@@ -0,0 +1,58 @@
+# Build system requirements.
+[build-system]
+requires = ["flit_core >=3.4,<4"]
+build-backend = "flit_core.buildapi"
+
+# Project metadata
+[project]
+name = "typing_extensions"
+version = "4.1.1"
+description = "Backported and Experimental Type Hints for Python 3.6+"
+readme = "README.rst"
+requires-python = ">=3.7"
+urls.Home = "https://github.com/python/typing/blob/master/typing_extensions/README.rst"
+license.file = "LICENSE"
+keywords = [
+ "annotations",
+ "backport",
+ "checker",
+ "checking",
+ "function",
+ "hinting",
+ "hints",
+ "type",
+ "typechecking",
+ "typehinting",
+ "typehints",
+ "typing"
+]
+# Classifiers list: https://pypi.org/classifiers/
+classifiers = [
+ "Development Status :: 3 - Alpha",
+ "Environment :: Console",
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: Python Software Foundation License",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3 :: Only",
+ "Programming Language :: Python :: 3.6",
+ "Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Topic :: Software Development"
+]
+
+# Project metadata -- authors. Flit stores this as a list of dicts, so it can't
+# be inline above.
+[[project.authors]]
+name = "Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Michael Lee"
+email = "levkivskyi@gmail.com"
+
+[tool.flit.sdist]
+include = [
+ "CHANGELOG",
+ "README.rst",
+ "*/test*.py"
+]
+exclude = []
diff --git a/typing_extensions/src/test_typing_extensions.py b/typing_extensions/src/test_typing_extensions.py
new file mode 100644
index 0000000..b8fe5e3
--- /dev/null
+++ b/typing_extensions/src/test_typing_extensions.py
@@ -0,0 +1,2779 @@
+import sys
+import os
+import abc
+import contextlib
+import collections
+import collections.abc
+from functools import lru_cache
+import inspect
+import pickle
+import subprocess
+import types
+from unittest import TestCase, main, skipUnless, skipIf
+from test import ann_module, ann_module2, ann_module3
+import typing
+from typing import TypeVar, Optional, Union, Any, AnyStr
+from typing import T, KT, VT # Not in __all__.
+from typing import Tuple, List, Dict, Iterable, Iterator, Callable
+from typing import Generic, NamedTuple
+from typing import no_type_check
+import typing_extensions
+from typing_extensions import NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict, Self
+from typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs, TypeGuard
+from typing_extensions import Awaitable, AsyncIterator, AsyncContextManager, Required, NotRequired
+from typing_extensions import Protocol, runtime, runtime_checkable, Annotated, overload, final, is_typeddict
+from typing_extensions import TypeVarTuple, Unpack, dataclass_transform, reveal_type, Never, assert_never, LiteralString
+from typing_extensions import assert_type, get_type_hints, get_origin, get_args
+
+# Flags used to mark tests that only apply after a specific
+# version of the typing module.
+TYPING_3_8_0 = sys.version_info[:3] >= (3, 8, 0)
+TYPING_3_10_0 = sys.version_info[:3] >= (3, 10, 0)
+TYPING_3_11_0 = sys.version_info[:3] >= (3, 11, 0)
+
+
+class BaseTestCase(TestCase):
+ def assertIsSubclass(self, cls, class_or_tuple, msg=None):
+ if not issubclass(cls, class_or_tuple):
+ message = f'{cls!r} is not a subclass of {repr(class_or_tuple)}'
+ if msg is not None:
+ message += f' : {msg}'
+ raise self.failureException(message)
+
+ def assertNotIsSubclass(self, cls, class_or_tuple, msg=None):
+ if issubclass(cls, class_or_tuple):
+ message = f'{cls!r} is a subclass of {repr(class_or_tuple)}'
+ if msg is not None:
+ message += f' : {msg}'
+ raise self.failureException(message)
+
+
+class Employee:
+ pass
+
+
+class BottomTypeTestsMixin:
+ bottom_type: ClassVar[Any]
+
+ def test_equality(self):
+ self.assertEqual(self.bottom_type, self.bottom_type)
+ self.assertIs(self.bottom_type, self.bottom_type)
+ self.assertNotEqual(self.bottom_type, None)
+
+ def test_get_origin(self):
+ self.assertIs(get_origin(self.bottom_type), None)
+
+ def test_instance_type_error(self):
+ with self.assertRaises(TypeError):
+ isinstance(42, self.bottom_type)
+
+ def test_subclass_type_error(self):
+ with self.assertRaises(TypeError):
+ issubclass(Employee, self.bottom_type)
+ with self.assertRaises(TypeError):
+ issubclass(NoReturn, self.bottom_type)
+
+ def test_not_generic(self):
+ with self.assertRaises(TypeError):
+ self.bottom_type[int]
+
+ def test_cannot_subclass(self):
+ with self.assertRaises(TypeError):
+ class A(self.bottom_type):
+ pass
+ with self.assertRaises(TypeError):
+ class A(type(self.bottom_type)):
+ pass
+
+ def test_cannot_instantiate(self):
+ with self.assertRaises(TypeError):
+ self.bottom_type()
+ with self.assertRaises(TypeError):
+ type(self.bottom_type)()
+
+ def test_pickle(self):
+ for proto in range(pickle.HIGHEST_PROTOCOL):
+ pickled = pickle.dumps(self.bottom_type, protocol=proto)
+ self.assertIs(self.bottom_type, pickle.loads(pickled))
+
+
+class NoReturnTests(BottomTypeTestsMixin, BaseTestCase):
+ bottom_type = NoReturn
+
+ def test_repr(self):
+ if hasattr(typing, 'NoReturn'):
+ self.assertEqual(repr(NoReturn), 'typing.NoReturn')
+ else:
+ self.assertEqual(repr(NoReturn), 'typing_extensions.NoReturn')
+
+ def test_get_type_hints(self):
+ def some(arg: NoReturn) -> NoReturn: ...
+ def some_str(arg: 'NoReturn') -> 'typing.NoReturn': ...
+
+ expected = {'arg': NoReturn, 'return': NoReturn}
+ targets = [some]
+
+ # On 3.7.0 and 3.7.1, https://github.com/python/cpython/pull/10772
+ # wasn't applied yet and NoReturn fails _type_check.
+ if not ((3, 7, 0) <= sys.version_info < (3, 7, 2)):
+ targets.append(some_str)
+ for target in targets:
+ with self.subTest(target=target):
+ self.assertEqual(gth(target), expected)
+
+ def test_not_equality(self):
+ self.assertNotEqual(NoReturn, Never)
+ self.assertNotEqual(Never, NoReturn)
+
+
+class NeverTests(BottomTypeTestsMixin, BaseTestCase):
+ bottom_type = Never
+
+ def test_repr(self):
+ if hasattr(typing, 'Never'):
+ self.assertEqual(repr(Never), 'typing.Never')
+ else:
+ self.assertEqual(repr(Never), 'typing_extensions.Never')
+
+ def test_get_type_hints(self):
+ def some(arg: Never) -> Never: ...
+ def some_str(arg: 'Never') -> 'typing_extensions.Never': ...
+
+ expected = {'arg': Never, 'return': Never}
+ for target in [some, some_str]:
+ with self.subTest(target=target):
+ self.assertEqual(gth(target), expected)
+
+
+class AssertNeverTests(BaseTestCase):
+ def test_exception(self):
+ with self.assertRaises(AssertionError):
+ assert_never(None)
+
+
+class ClassVarTests(BaseTestCase):
+
+ def test_basics(self):
+ with self.assertRaises(TypeError):
+ ClassVar[1]
+ with self.assertRaises(TypeError):
+ ClassVar[int, str]
+ with self.assertRaises(TypeError):
+ ClassVar[int][str]
+
+ def test_repr(self):
+ if hasattr(typing, 'ClassVar'):
+ mod_name = 'typing'
+ else:
+ mod_name = 'typing_extensions'
+ self.assertEqual(repr(ClassVar), mod_name + '.ClassVar')
+ cv = ClassVar[int]
+ self.assertEqual(repr(cv), mod_name + '.ClassVar[int]')
+ cv = ClassVar[Employee]
+ self.assertEqual(repr(cv), mod_name + f'.ClassVar[{__name__}.Employee]')
+
+ def test_cannot_subclass(self):
+ with self.assertRaises(TypeError):
+ class C(type(ClassVar)):
+ pass
+ with self.assertRaises(TypeError):
+ class C(type(ClassVar[int])):
+ pass
+
+ def test_cannot_init(self):
+ with self.assertRaises(TypeError):
+ ClassVar()
+ with self.assertRaises(TypeError):
+ type(ClassVar)()
+ with self.assertRaises(TypeError):
+ type(ClassVar[Optional[int]])()
+
+ def test_no_isinstance(self):
+ with self.assertRaises(TypeError):
+ isinstance(1, ClassVar[int])
+ with self.assertRaises(TypeError):
+ issubclass(int, ClassVar)
+
+
+class FinalTests(BaseTestCase):
+
+ def test_basics(self):
+ with self.assertRaises(TypeError):
+ Final[1]
+ with self.assertRaises(TypeError):
+ Final[int, str]
+ with self.assertRaises(TypeError):
+ Final[int][str]
+
+ def test_repr(self):
+ if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7):
+ mod_name = 'typing'
+ else:
+ mod_name = 'typing_extensions'
+ self.assertEqual(repr(Final), mod_name + '.Final')
+ cv = Final[int]
+ self.assertEqual(repr(cv), mod_name + '.Final[int]')
+ cv = Final[Employee]
+ self.assertEqual(repr(cv), mod_name + f'.Final[{__name__}.Employee]')
+
+ def test_cannot_subclass(self):
+ with self.assertRaises(TypeError):
+ class C(type(Final)):
+ pass
+ with self.assertRaises(TypeError):
+ class C(type(Final[int])):
+ pass
+
+ def test_cannot_init(self):
+ with self.assertRaises(TypeError):
+ Final()
+ with self.assertRaises(TypeError):
+ type(Final)()
+ with self.assertRaises(TypeError):
+ type(Final[Optional[int]])()
+
+ def test_no_isinstance(self):
+ with self.assertRaises(TypeError):
+ isinstance(1, Final[int])
+ with self.assertRaises(TypeError):
+ issubclass(int, Final)
+
+
+class RequiredTests(BaseTestCase):
+
+ def test_basics(self):
+ with self.assertRaises(TypeError):
+ Required[1]
+ with self.assertRaises(TypeError):
+ Required[int, str]
+ with self.assertRaises(TypeError):
+ Required[int][str]
+
+ def test_repr(self):
+ if hasattr(typing, 'Required'):
+ mod_name = 'typing'
+ else:
+ mod_name = 'typing_extensions'
+ self.assertEqual(repr(Required), mod_name + '.Required')
+ cv = Required[int]
+ self.assertEqual(repr(cv), mod_name + '.Required[int]')
+ cv = Required[Employee]
+ self.assertEqual(repr(cv), mod_name + '.Required[%s.Employee]' % __name__)
+
+ def test_cannot_subclass(self):
+ with self.assertRaises(TypeError):
+ class C(type(Required)):
+ pass
+ with self.assertRaises(TypeError):
+ class C(type(Required[int])):
+ pass
+
+ def test_cannot_init(self):
+ with self.assertRaises(TypeError):
+ Required()
+ with self.assertRaises(TypeError):
+ type(Required)()
+ with self.assertRaises(TypeError):
+ type(Required[Optional[int]])()
+
+ def test_no_isinstance(self):
+ with self.assertRaises(TypeError):
+ isinstance(1, Required[int])
+ with self.assertRaises(TypeError):
+ issubclass(int, Required)
+
+
+class NotRequiredTests(BaseTestCase):
+
+ def test_basics(self):
+ with self.assertRaises(TypeError):
+ NotRequired[1]
+ with self.assertRaises(TypeError):
+ NotRequired[int, str]
+ with self.assertRaises(TypeError):
+ NotRequired[int][str]
+
+ def test_repr(self):
+ if hasattr(typing, 'NotRequired'):
+ mod_name = 'typing'
+ else:
+ mod_name = 'typing_extensions'
+ self.assertEqual(repr(NotRequired), mod_name + '.NotRequired')
+ cv = NotRequired[int]
+ self.assertEqual(repr(cv), mod_name + '.NotRequired[int]')
+ cv = NotRequired[Employee]
+ self.assertEqual(repr(cv), mod_name + '.NotRequired[%s.Employee]' % __name__)
+
+ def test_cannot_subclass(self):
+ with self.assertRaises(TypeError):
+ class C(type(NotRequired)):
+ pass
+ with self.assertRaises(TypeError):
+ class C(type(NotRequired[int])):
+ pass
+
+ def test_cannot_init(self):
+ with self.assertRaises(TypeError):
+ NotRequired()
+ with self.assertRaises(TypeError):
+ type(NotRequired)()
+ with self.assertRaises(TypeError):
+ type(NotRequired[Optional[int]])()
+
+ def test_no_isinstance(self):
+ with self.assertRaises(TypeError):
+ isinstance(1, NotRequired[int])
+ with self.assertRaises(TypeError):
+ issubclass(int, NotRequired)
+
+
+class IntVarTests(BaseTestCase):
+ def test_valid(self):
+ T_ints = IntVar("T_ints") # noqa
+
+ def test_invalid(self):
+ with self.assertRaises(TypeError):
+ T_ints = IntVar("T_ints", int)
+ with self.assertRaises(TypeError):
+ T_ints = IntVar("T_ints", bound=int)
+ with self.assertRaises(TypeError):
+ T_ints = IntVar("T_ints", covariant=True) # noqa
+
+
+class LiteralTests(BaseTestCase):
+ def test_basics(self):
+ Literal[1]
+ Literal[1, 2, 3]
+ Literal["x", "y", "z"]
+ Literal[None]
+
+ def test_illegal_parameters_do_not_raise_runtime_errors(self):
+ # Type checkers should reject these types, but we do not
+ # raise errors at runtime to maintain maximum flexibility
+ Literal[int]
+ Literal[Literal[1, 2], Literal[4, 5]]
+ Literal[3j + 2, ..., ()]
+ Literal[b"foo", u"bar"]
+ Literal[{"foo": 3, "bar": 4}]
+ Literal[T]
+
+ def test_literals_inside_other_types(self):
+ List[Literal[1, 2, 3]]
+ List[Literal[("foo", "bar", "baz")]]
+
+ def test_repr(self):
+ if hasattr(typing, 'Literal'):
+ mod_name = 'typing'
+ else:
+ mod_name = 'typing_extensions'
+ self.assertEqual(repr(Literal[1]), mod_name + ".Literal[1]")
+ self.assertEqual(repr(Literal[1, True, "foo"]), mod_name + ".Literal[1, True, 'foo']")
+ self.assertEqual(repr(Literal[int]), mod_name + ".Literal[int]")
+ self.assertEqual(repr(Literal), mod_name + ".Literal")
+ self.assertEqual(repr(Literal[None]), mod_name + ".Literal[None]")
+
+ def test_cannot_init(self):
+ with self.assertRaises(TypeError):
+ Literal()
+ with self.assertRaises(TypeError):
+ Literal[1]()
+ with self.assertRaises(TypeError):
+ type(Literal)()
+ with self.assertRaises(TypeError):
+ type(Literal[1])()
+
+ def test_no_isinstance_or_issubclass(self):
+ with self.assertRaises(TypeError):
+ isinstance(1, Literal[1])
+ with self.assertRaises(TypeError):
+ isinstance(int, Literal[1])
+ with self.assertRaises(TypeError):
+ issubclass(1, Literal[1])
+ with self.assertRaises(TypeError):
+ issubclass(int, Literal[1])
+
+ def test_no_subclassing(self):
+ with self.assertRaises(TypeError):
+ class Foo(Literal[1]): pass
+ with self.assertRaises(TypeError):
+ class Bar(Literal): pass
+
+ def test_no_multiple_subscripts(self):
+ with self.assertRaises(TypeError):
+ Literal[1][1]
+
+
+class OverloadTests(BaseTestCase):
+
+ def test_overload_fails(self):
+ with self.assertRaises(RuntimeError):
+
+ @overload
+ def blah():
+ pass
+
+ blah()
+
+ def test_overload_succeeds(self):
+ @overload
+ def blah():
+ pass
+
+ def blah():
+ pass
+
+ blah()
+
+
+class AssertTypeTests(BaseTestCase):
+
+ def test_basics(self):
+ arg = 42
+ self.assertIs(assert_type(arg, int), arg)
+ self.assertIs(assert_type(arg, Union[str, float]), arg)
+ self.assertIs(assert_type(arg, AnyStr), arg)
+ self.assertIs(assert_type(arg, None), arg)
+
+ def test_errors(self):
+ # Bogus calls are not expected to fail.
+ arg = 42
+ self.assertIs(assert_type(arg, 42), arg)
+ self.assertIs(assert_type(arg, 'hello'), arg)
+
+
+T_a = TypeVar('T_a')
+
+class AwaitableWrapper(Awaitable[T_a]):
+
+ def __init__(self, value):
+ self.value = value
+
+ def __await__(self) -> typing.Iterator[T_a]:
+ yield
+ return self.value
+
+class AsyncIteratorWrapper(AsyncIterator[T_a]):
+
+ def __init__(self, value: Iterable[T_a]):
+ self.value = value
+
+ def __aiter__(self) -> AsyncIterator[T_a]:
+ return self
+
+ async def __anext__(self) -> T_a:
+ data = await self.value
+ if data:
+ return data
+ else:
+ raise StopAsyncIteration
+
+class ACM:
+ async def __aenter__(self) -> int:
+ return 42
+
+ async def __aexit__(self, etype, eval, tb):
+ return None
+
+
+
+class A:
+ y: float
+class B(A):
+ x: ClassVar[Optional['B']] = None
+ y: int
+ b: int
+class CSub(B):
+ z: ClassVar['CSub'] = B()
+class G(Generic[T]):
+ lst: ClassVar[List[T]] = []
+
+class Loop:
+ attr: Final['Loop']
+
+class NoneAndForward:
+ parent: 'NoneAndForward'
+ meaning: None
+
+class XRepr(NamedTuple):
+ x: int
+ y: int = 1
+
+ def __str__(self):
+ return f'{self.x} -> {self.y}'
+
+ def __add__(self, other):
+ return 0
+
+@runtime
+class HasCallProtocol(Protocol):
+ __call__: typing.Callable
+
+
+async def g_with(am: AsyncContextManager[int]):
+ x: int
+ async with am as x:
+ return x
+
+try:
+ g_with(ACM()).send(None)
+except StopIteration as e:
+ assert e.args[0] == 42
+
+Label = TypedDict('Label', [('label', str)])
+
+class Point2D(TypedDict):
+ x: int
+ y: int
+
+class Point2Dor3D(Point2D, total=False):
+ z: int
+
+class LabelPoint2D(Point2D, Label): ...
+
+class Options(TypedDict, total=False):
+ log_level: int
+ log_path: str
+
+class BaseAnimal(TypedDict):
+ name: str
+
+class Animal(BaseAnimal, total=False):
+ voice: str
+ tail: bool
+
+class Cat(Animal):
+ fur_color: str
+
+class TotalMovie(TypedDict):
+ title: str
+ year: NotRequired[int]
+
+class NontotalMovie(TypedDict, total=False):
+ title: Required[str]
+ year: int
+
+class AnnotatedMovie(TypedDict):
+ title: Annotated[Required[str], "foobar"]
+ year: NotRequired[Annotated[int, 2000]]
+
+
+gth = get_type_hints
+
+
+class GetTypeHintTests(BaseTestCase):
+ def test_get_type_hints_modules(self):
+ ann_module_type_hints = {1: 2, 'f': Tuple[int, int], 'x': int, 'y': str}
+ if (TYPING_3_11_0
+ or (TYPING_3_10_0 and sys.version_info.releaselevel in {'candidate', 'final'})):
+ # More tests were added in 3.10rc1.
+ ann_module_type_hints['u'] = int | float
+ self.assertEqual(gth(ann_module), ann_module_type_hints)
+ self.assertEqual(gth(ann_module2), {})
+ self.assertEqual(gth(ann_module3), {})
+
+ def test_get_type_hints_classes(self):
+ self.assertEqual(gth(ann_module.C, ann_module.__dict__),
+ {'y': Optional[ann_module.C]})
+ self.assertIsInstance(gth(ann_module.j_class), dict)
+ self.assertEqual(gth(ann_module.M), {'123': 123, 'o': type})
+ self.assertEqual(gth(ann_module.D),
+ {'j': str, 'k': str, 'y': Optional[ann_module.C]})
+ self.assertEqual(gth(ann_module.Y), {'z': int})
+ self.assertEqual(gth(ann_module.h_class),
+ {'y': Optional[ann_module.C]})
+ self.assertEqual(gth(ann_module.S), {'x': str, 'y': str})
+ self.assertEqual(gth(ann_module.foo), {'x': int})
+ self.assertEqual(gth(NoneAndForward, globals()),
+ {'parent': NoneAndForward, 'meaning': type(None)})
+
+ def test_respect_no_type_check(self):
+ @no_type_check
+ class NoTpCheck:
+ class Inn:
+ def __init__(self, x: 'not a type'): ... # noqa
+ self.assertTrue(NoTpCheck.__no_type_check__)
+ self.assertTrue(NoTpCheck.Inn.__init__.__no_type_check__)
+ self.assertEqual(gth(ann_module2.NTC.meth), {})
+ class ABase(Generic[T]):
+ def meth(x: int): ...
+ @no_type_check
+ class Der(ABase): ...
+ self.assertEqual(gth(ABase.meth), {'x': int})
+
+ def test_get_type_hints_ClassVar(self):
+ self.assertEqual(gth(ann_module2.CV, ann_module2.__dict__),
+ {'var': ClassVar[ann_module2.CV]})
+ self.assertEqual(gth(B, globals()),
+ {'y': int, 'x': ClassVar[Optional[B]], 'b': int})
+ self.assertEqual(gth(CSub, globals()),
+ {'z': ClassVar[CSub], 'y': int, 'b': int,
+ 'x': ClassVar[Optional[B]]})
+ self.assertEqual(gth(G), {'lst': ClassVar[List[T]]})
+
+ def test_final_forward_ref(self):
+ self.assertEqual(gth(Loop, globals())['attr'], Final[Loop])
+ self.assertNotEqual(gth(Loop, globals())['attr'], Final[int])
+ self.assertNotEqual(gth(Loop, globals())['attr'], Final)
+
+
+class GetUtilitiesTestCase(TestCase):
+ def test_get_origin(self):
+ T = TypeVar('T')
+ P = ParamSpec('P')
+ Ts = TypeVarTuple('Ts')
+ class C(Generic[T]): pass
+ self.assertIs(get_origin(C[int]), C)
+ self.assertIs(get_origin(C[T]), C)
+ self.assertIs(get_origin(int), None)
+ self.assertIs(get_origin(ClassVar[int]), ClassVar)
+ self.assertIs(get_origin(Union[int, str]), Union)
+ self.assertIs(get_origin(Literal[42, 43]), Literal)
+ self.assertIs(get_origin(Final[List[int]]), Final)
+ self.assertIs(get_origin(Generic), Generic)
+ self.assertIs(get_origin(Generic[T]), Generic)
+ self.assertIs(get_origin(List[Tuple[T, T]][int]), list)
+ self.assertIs(get_origin(Annotated[T, 'thing']), Annotated)
+ self.assertIs(get_origin(List), list)
+ self.assertIs(get_origin(Tuple), tuple)
+ self.assertIs(get_origin(Callable), collections.abc.Callable)
+ if sys.version_info >= (3, 9):
+ self.assertIs(get_origin(list[int]), list)
+ self.assertIs(get_origin(list), None)
+ self.assertIs(get_origin(P.args), P)
+ self.assertIs(get_origin(P.kwargs), P)
+ self.assertIs(get_origin(Required[int]), Required)
+ self.assertIs(get_origin(NotRequired[int]), NotRequired)
+ self.assertIs(get_origin(Unpack[Ts]), Unpack)
+ self.assertIs(get_origin(Unpack), None)
+
+ def test_get_args(self):
+ T = TypeVar('T')
+ Ts = TypeVarTuple('Ts')
+ class C(Generic[T]): pass
+ self.assertEqual(get_args(C[int]), (int,))
+ self.assertEqual(get_args(C[T]), (T,))
+ self.assertEqual(get_args(int), ())
+ self.assertEqual(get_args(ClassVar[int]), (int,))
+ self.assertEqual(get_args(Union[int, str]), (int, str))
+ self.assertEqual(get_args(Literal[42, 43]), (42, 43))
+ self.assertEqual(get_args(Final[List[int]]), (List[int],))
+ self.assertEqual(get_args(Union[int, Tuple[T, int]][str]),
+ (int, Tuple[str, int]))
+ self.assertEqual(get_args(typing.Dict[int, Tuple[T, T]][Optional[int]]),
+ (int, Tuple[Optional[int], Optional[int]]))
+ self.assertEqual(get_args(Callable[[], T][int]), ([], int))
+ self.assertEqual(get_args(Callable[..., int]), (..., int))
+ self.assertEqual(get_args(Union[int, Callable[[Tuple[T, ...]], str]]),
+ (int, Callable[[Tuple[T, ...]], str]))
+ self.assertEqual(get_args(Tuple[int, ...]), (int, ...))
+ self.assertEqual(get_args(Tuple[()]), ((),))
+ self.assertEqual(get_args(Annotated[T, 'one', 2, ['three']]), (T, 'one', 2, ['three']))
+ self.assertEqual(get_args(List), ())
+ self.assertEqual(get_args(Tuple), ())
+ self.assertEqual(get_args(Callable), ())
+ if sys.version_info >= (3, 9):
+ self.assertEqual(get_args(list[int]), (int,))
+ self.assertEqual(get_args(list), ())
+ if sys.version_info >= (3, 9):
+ # Support Python versions with and without the fix for
+ # https://bugs.python.org/issue42195
+ # The first variant is for 3.9.2+, the second for 3.9.0 and 1
+ self.assertIn(get_args(collections.abc.Callable[[int], str]),
+ (([int], str), ([[int]], str)))
+ self.assertIn(get_args(collections.abc.Callable[[], str]),
+ (([], str), ([[]], str)))
+ self.assertEqual(get_args(collections.abc.Callable[..., str]), (..., str))
+ P = ParamSpec('P')
+ # In 3.9 and lower we use typing_extensions's hacky implementation
+ # of ParamSpec, which gets incorrectly wrapped in a list
+ self.assertIn(get_args(Callable[P, int]), [(P, int), ([P], int)])
+ self.assertEqual(get_args(Callable[Concatenate[int, P], int]),
+ (Concatenate[int, P], int))
+ self.assertEqual(get_args(Required[int]), (int,))
+ self.assertEqual(get_args(NotRequired[int]), (int,))
+ self.assertEqual(get_args(Unpack[Ts]), (Ts,))
+ self.assertEqual(get_args(Unpack), ())
+
+
+class CollectionsAbcTests(BaseTestCase):
+
+ def test_isinstance_collections(self):
+ self.assertNotIsInstance(1, collections.abc.Mapping)
+ self.assertNotIsInstance(1, collections.abc.Iterable)
+ self.assertNotIsInstance(1, collections.abc.Container)
+ self.assertNotIsInstance(1, collections.abc.Sized)
+ with self.assertRaises(TypeError):
+ isinstance(collections.deque(), typing_extensions.Deque[int])
+ with self.assertRaises(TypeError):
+ issubclass(collections.Counter, typing_extensions.Counter[str])
+
+ def test_awaitable(self):
+ ns = {}
+ exec(
+ "async def foo() -> typing_extensions.Awaitable[int]:\n"
+ " return await AwaitableWrapper(42)\n",
+ globals(), ns)
+ foo = ns['foo']
+ g = foo()
+ self.assertIsInstance(g, typing_extensions.Awaitable)
+ self.assertNotIsInstance(foo, typing_extensions.Awaitable)
+ g.send(None) # Run foo() till completion, to avoid warning.
+
+ def test_coroutine(self):
+ ns = {}
+ exec(
+ "async def foo():\n"
+ " return\n",
+ globals(), ns)
+ foo = ns['foo']
+ g = foo()
+ self.assertIsInstance(g, typing_extensions.Coroutine)
+ with self.assertRaises(TypeError):
+ isinstance(g, typing_extensions.Coroutine[int])
+ self.assertNotIsInstance(foo, typing_extensions.Coroutine)
+ try:
+ g.send(None)
+ except StopIteration:
+ pass
+
+ def test_async_iterable(self):
+ base_it = range(10) # type: Iterator[int]
+ it = AsyncIteratorWrapper(base_it)
+ self.assertIsInstance(it, typing_extensions.AsyncIterable)
+ self.assertIsInstance(it, typing_extensions.AsyncIterable)
+ self.assertNotIsInstance(42, typing_extensions.AsyncIterable)
+
+ def test_async_iterator(self):
+ base_it = range(10) # type: Iterator[int]
+ it = AsyncIteratorWrapper(base_it)
+ self.assertIsInstance(it, typing_extensions.AsyncIterator)
+ self.assertNotIsInstance(42, typing_extensions.AsyncIterator)
+
+ def test_deque(self):
+ self.assertIsSubclass(collections.deque, typing_extensions.Deque)
+ class MyDeque(typing_extensions.Deque[int]): ...
+ self.assertIsInstance(MyDeque(), collections.deque)
+
+ def test_counter(self):
+ self.assertIsSubclass(collections.Counter, typing_extensions.Counter)
+
+ def test_defaultdict_instantiation(self):
+ self.assertIs(
+ type(typing_extensions.DefaultDict()),
+ collections.defaultdict)
+ self.assertIs(
+ type(typing_extensions.DefaultDict[KT, VT]()),
+ collections.defaultdict)
+ self.assertIs(
+ type(typing_extensions.DefaultDict[str, int]()),
+ collections.defaultdict)
+
+ def test_defaultdict_subclass(self):
+
+ class MyDefDict(typing_extensions.DefaultDict[str, int]):
+ pass
+
+ dd = MyDefDict()
+ self.assertIsInstance(dd, MyDefDict)
+
+ self.assertIsSubclass(MyDefDict, collections.defaultdict)
+ self.assertNotIsSubclass(collections.defaultdict, MyDefDict)
+
+ def test_ordereddict_instantiation(self):
+ self.assertIs(
+ type(typing_extensions.OrderedDict()),
+ collections.OrderedDict)
+ self.assertIs(
+ type(typing_extensions.OrderedDict[KT, VT]()),
+ collections.OrderedDict)
+ self.assertIs(
+ type(typing_extensions.OrderedDict[str, int]()),
+ collections.OrderedDict)
+
+ def test_ordereddict_subclass(self):
+
+ class MyOrdDict(typing_extensions.OrderedDict[str, int]):
+ pass
+
+ od = MyOrdDict()
+ self.assertIsInstance(od, MyOrdDict)
+
+ self.assertIsSubclass(MyOrdDict, collections.OrderedDict)
+ self.assertNotIsSubclass(collections.OrderedDict, MyOrdDict)
+
+ def test_chainmap_instantiation(self):
+ self.assertIs(type(typing_extensions.ChainMap()), collections.ChainMap)
+ self.assertIs(type(typing_extensions.ChainMap[KT, VT]()), collections.ChainMap)
+ self.assertIs(type(typing_extensions.ChainMap[str, int]()), collections.ChainMap)
+ class CM(typing_extensions.ChainMap[KT, VT]): ...
+ self.assertIs(type(CM[int, str]()), CM)
+
+ def test_chainmap_subclass(self):
+
+ class MyChainMap(typing_extensions.ChainMap[str, int]):
+ pass
+
+ cm = MyChainMap()
+ self.assertIsInstance(cm, MyChainMap)
+
+ self.assertIsSubclass(MyChainMap, collections.ChainMap)
+ self.assertNotIsSubclass(collections.ChainMap, MyChainMap)
+
+ def test_deque_instantiation(self):
+ self.assertIs(type(typing_extensions.Deque()), collections.deque)
+ self.assertIs(type(typing_extensions.Deque[T]()), collections.deque)
+ self.assertIs(type(typing_extensions.Deque[int]()), collections.deque)
+ class D(typing_extensions.Deque[T]): ...
+ self.assertIs(type(D[int]()), D)
+
+ def test_counter_instantiation(self):
+ self.assertIs(type(typing_extensions.Counter()), collections.Counter)
+ self.assertIs(type(typing_extensions.Counter[T]()), collections.Counter)
+ self.assertIs(type(typing_extensions.Counter[int]()), collections.Counter)
+ class C(typing_extensions.Counter[T]): ...
+ self.assertIs(type(C[int]()), C)
+ self.assertEqual(C.__bases__, (collections.Counter, typing.Generic))
+
+ def test_counter_subclass_instantiation(self):
+
+ class MyCounter(typing_extensions.Counter[int]):
+ pass
+
+ d = MyCounter()
+ self.assertIsInstance(d, MyCounter)
+ self.assertIsInstance(d, collections.Counter)
+ self.assertIsInstance(d, typing_extensions.Counter)
+
+ def test_async_generator(self):
+ ns = {}
+ exec("async def f():\n"
+ " yield 42\n", globals(), ns)
+ g = ns['f']()
+ self.assertIsSubclass(type(g), typing_extensions.AsyncGenerator)
+
+ def test_no_async_generator_instantiation(self):
+ with self.assertRaises(TypeError):
+ typing_extensions.AsyncGenerator()
+ with self.assertRaises(TypeError):
+ typing_extensions.AsyncGenerator[T, T]()
+ with self.assertRaises(TypeError):
+ typing_extensions.AsyncGenerator[int, int]()
+
+ def test_subclassing_async_generator(self):
+ class G(typing_extensions.AsyncGenerator[int, int]):
+ def asend(self, value):
+ pass
+ def athrow(self, typ, val=None, tb=None):
+ pass
+
+ ns = {}
+ exec('async def g(): yield 0', globals(), ns)
+ g = ns['g']
+ self.assertIsSubclass(G, typing_extensions.AsyncGenerator)
+ self.assertIsSubclass(G, typing_extensions.AsyncIterable)
+ self.assertIsSubclass(G, collections.abc.AsyncGenerator)
+ self.assertIsSubclass(G, collections.abc.AsyncIterable)
+ self.assertNotIsSubclass(type(g), G)
+
+ instance = G()
+ self.assertIsInstance(instance, typing_extensions.AsyncGenerator)
+ self.assertIsInstance(instance, typing_extensions.AsyncIterable)
+ self.assertIsInstance(instance, collections.abc.AsyncGenerator)
+ self.assertIsInstance(instance, collections.abc.AsyncIterable)
+ self.assertNotIsInstance(type(g), G)
+ self.assertNotIsInstance(g, G)
+
+
+class OtherABCTests(BaseTestCase):
+
+ def test_contextmanager(self):
+ @contextlib.contextmanager
+ def manager():
+ yield 42
+
+ cm = manager()
+ self.assertIsInstance(cm, typing_extensions.ContextManager)
+ self.assertNotIsInstance(42, typing_extensions.ContextManager)
+
+ def test_async_contextmanager(self):
+ class NotACM:
+ pass
+ self.assertIsInstance(ACM(), typing_extensions.AsyncContextManager)
+ self.assertNotIsInstance(NotACM(), typing_extensions.AsyncContextManager)
+ @contextlib.contextmanager
+ def manager():
+ yield 42
+
+ cm = manager()
+ self.assertNotIsInstance(cm, typing_extensions.AsyncContextManager)
+ self.assertEqual(typing_extensions.AsyncContextManager[int].__args__, (int,))
+ with self.assertRaises(TypeError):
+ isinstance(42, typing_extensions.AsyncContextManager[int])
+ with self.assertRaises(TypeError):
+ typing_extensions.AsyncContextManager[int, str]
+
+
+class TypeTests(BaseTestCase):
+
+ def test_type_basic(self):
+
+ class User: pass
+ class BasicUser(User): pass
+ class ProUser(User): pass
+
+ def new_user(user_class: Type[User]) -> User:
+ return user_class()
+
+ new_user(BasicUser)
+
+ def test_type_typevar(self):
+
+ class User: pass
+ class BasicUser(User): pass
+ class ProUser(User): pass
+
+ U = TypeVar('U', bound=User)
+
+ def new_user(user_class: Type[U]) -> U:
+ return user_class()
+
+ new_user(BasicUser)
+
+ def test_type_optional(self):
+ A = Optional[Type[BaseException]]
+
+ def foo(a: A) -> Optional[BaseException]:
+ if a is None:
+ return None
+ else:
+ return a()
+
+ assert isinstance(foo(KeyboardInterrupt), KeyboardInterrupt)
+ assert foo(None) is None
+
+
+class NewTypeTests(BaseTestCase):
+
+ def test_basic(self):
+ UserId = NewType('UserId', int)
+ UserName = NewType('UserName', str)
+ self.assertIsInstance(UserId(5), int)
+ self.assertIsInstance(UserName('Joe'), str)
+ self.assertEqual(UserId(5) + 1, 6)
+
+ def test_errors(self):
+ UserId = NewType('UserId', int)
+ UserName = NewType('UserName', str)
+ with self.assertRaises(TypeError):
+ issubclass(UserId, int)
+ with self.assertRaises(TypeError):
+ class D(UserName):
+ pass
+
+
+class Coordinate(Protocol):
+ x: int
+ y: int
+
+@runtime
+class Point(Coordinate, Protocol):
+ label: str
+
+class MyPoint:
+ x: int
+ y: int
+ label: str
+
+class XAxis(Protocol):
+ x: int
+
+class YAxis(Protocol):
+ y: int
+
+@runtime
+class Position(XAxis, YAxis, Protocol):
+ pass
+
+@runtime
+class Proto(Protocol):
+ attr: int
+
+ def meth(self, arg: str) -> int:
+ ...
+
+class Concrete(Proto):
+ pass
+
+class Other:
+ attr: int = 1
+
+ def meth(self, arg: str) -> int:
+ if arg == 'this':
+ return 1
+ return 0
+
+class NT(NamedTuple):
+ x: int
+ y: int
+
+
+class ProtocolTests(BaseTestCase):
+
+ def test_basic_protocol(self):
+ @runtime
+ class P(Protocol):
+ def meth(self):
+ pass
+ class C: pass
+ class D:
+ def meth(self):
+ pass
+ def f():
+ pass
+ self.assertIsSubclass(D, P)
+ self.assertIsInstance(D(), P)
+ self.assertNotIsSubclass(C, P)
+ self.assertNotIsInstance(C(), P)
+ self.assertNotIsSubclass(types.FunctionType, P)
+ self.assertNotIsInstance(f, P)
+
+ def test_everything_implements_empty_protocol(self):
+ @runtime
+ class Empty(Protocol): pass
+ class C: pass
+ def f():
+ pass
+ for thing in (object, type, tuple, C, types.FunctionType):
+ self.assertIsSubclass(thing, Empty)
+ for thing in (object(), 1, (), typing, f):
+ self.assertIsInstance(thing, Empty)
+
+ def test_function_implements_protocol(self):
+ def f():
+ pass
+ self.assertIsInstance(f, HasCallProtocol)
+
+ def test_no_inheritance_from_nominal(self):
+ class C: pass
+ class BP(Protocol): pass
+ with self.assertRaises(TypeError):
+ class P(C, Protocol):
+ pass
+ with self.assertRaises(TypeError):
+ class P(Protocol, C):
+ pass
+ with self.assertRaises(TypeError):
+ class P(BP, C, Protocol):
+ pass
+ class D(BP, C): pass
+ class E(C, BP): pass
+ self.assertNotIsInstance(D(), E)
+ self.assertNotIsInstance(E(), D)
+
+ def test_no_instantiation(self):
+ class P(Protocol): pass
+ with self.assertRaises(TypeError):
+ P()
+ class C(P): pass
+ self.assertIsInstance(C(), C)
+ T = TypeVar('T')
+ class PG(Protocol[T]): pass
+ with self.assertRaises(TypeError):
+ PG()
+ with self.assertRaises(TypeError):
+ PG[int]()
+ with self.assertRaises(TypeError):
+ PG[T]()
+ class CG(PG[T]): pass
+ self.assertIsInstance(CG[int](), CG)
+
+ def test_cannot_instantiate_abstract(self):
+ @runtime
+ class P(Protocol):
+ @abc.abstractmethod
+ def ameth(self) -> int:
+ raise NotImplementedError
+ class B(P):
+ pass
+ class C(B):
+ def ameth(self) -> int:
+ return 26
+ with self.assertRaises(TypeError):
+ B()
+ self.assertIsInstance(C(), P)
+
+ def test_subprotocols_extending(self):
+ class P1(Protocol):
+ def meth1(self):
+ pass
+ @runtime
+ class P2(P1, Protocol):
+ def meth2(self):
+ pass
+ class C:
+ def meth1(self):
+ pass
+ def meth2(self):
+ pass
+ class C1:
+ def meth1(self):
+ pass
+ class C2:
+ def meth2(self):
+ pass
+ self.assertNotIsInstance(C1(), P2)
+ self.assertNotIsInstance(C2(), P2)
+ self.assertNotIsSubclass(C1, P2)
+ self.assertNotIsSubclass(C2, P2)
+ self.assertIsInstance(C(), P2)
+ self.assertIsSubclass(C, P2)
+
+ def test_subprotocols_merging(self):
+ class P1(Protocol):
+ def meth1(self):
+ pass
+ class P2(Protocol):
+ def meth2(self):
+ pass
+ @runtime
+ class P(P1, P2, Protocol):
+ pass
+ class C:
+ def meth1(self):
+ pass
+ def meth2(self):
+ pass
+ class C1:
+ def meth1(self):
+ pass
+ class C2:
+ def meth2(self):
+ pass
+ self.assertNotIsInstance(C1(), P)
+ self.assertNotIsInstance(C2(), P)
+ self.assertNotIsSubclass(C1, P)
+ self.assertNotIsSubclass(C2, P)
+ self.assertIsInstance(C(), P)
+ self.assertIsSubclass(C, P)
+
+ def test_protocols_issubclass(self):
+ T = TypeVar('T')
+ @runtime
+ class P(Protocol):
+ def x(self): ...
+ @runtime
+ class PG(Protocol[T]):
+ def x(self): ...
+ class BadP(Protocol):
+ def x(self): ...
+ class BadPG(Protocol[T]):
+ def x(self): ...
+ class C:
+ def x(self): ...
+ self.assertIsSubclass(C, P)
+ self.assertIsSubclass(C, PG)
+ self.assertIsSubclass(BadP, PG)
+ with self.assertRaises(TypeError):
+ issubclass(C, PG[T])
+ with self.assertRaises(TypeError):
+ issubclass(C, PG[C])
+ with self.assertRaises(TypeError):
+ issubclass(C, BadP)
+ with self.assertRaises(TypeError):
+ issubclass(C, BadPG)
+ with self.assertRaises(TypeError):
+ issubclass(P, PG[T])
+ with self.assertRaises(TypeError):
+ issubclass(PG, PG[int])
+
+ def test_protocols_issubclass_non_callable(self):
+ class C:
+ x = 1
+ @runtime
+ class PNonCall(Protocol):
+ x = 1
+ with self.assertRaises(TypeError):
+ issubclass(C, PNonCall)
+ self.assertIsInstance(C(), PNonCall)
+ PNonCall.register(C)
+ with self.assertRaises(TypeError):
+ issubclass(C, PNonCall)
+ self.assertIsInstance(C(), PNonCall)
+ # check that non-protocol subclasses are not affected
+ class D(PNonCall): ...
+ self.assertNotIsSubclass(C, D)
+ self.assertNotIsInstance(C(), D)
+ D.register(C)
+ self.assertIsSubclass(C, D)
+ self.assertIsInstance(C(), D)
+ with self.assertRaises(TypeError):
+ issubclass(D, PNonCall)
+
+ def test_protocols_isinstance(self):
+ T = TypeVar('T')
+ @runtime
+ class P(Protocol):
+ def meth(x): ...
+ @runtime
+ class PG(Protocol[T]):
+ def meth(x): ...
+ class BadP(Protocol):
+ def meth(x): ...
+ class BadPG(Protocol[T]):
+ def meth(x): ...
+ class C:
+ def meth(x): ...
+ self.assertIsInstance(C(), P)
+ self.assertIsInstance(C(), PG)
+ with self.assertRaises(TypeError):
+ isinstance(C(), PG[T])
+ with self.assertRaises(TypeError):
+ isinstance(C(), PG[C])
+ with self.assertRaises(TypeError):
+ isinstance(C(), BadP)
+ with self.assertRaises(TypeError):
+ isinstance(C(), BadPG)
+
+ def test_protocols_isinstance_py36(self):
+ class APoint:
+ def __init__(self, x, y, label):
+ self.x = x
+ self.y = y
+ self.label = label
+ class BPoint:
+ label = 'B'
+ def __init__(self, x, y):
+ self.x = x
+ self.y = y
+ class C:
+ def __init__(self, attr):
+ self.attr = attr
+ def meth(self, arg):
+ return 0
+ class Bad: pass
+ self.assertIsInstance(APoint(1, 2, 'A'), Point)
+ self.assertIsInstance(BPoint(1, 2), Point)
+ self.assertNotIsInstance(MyPoint(), Point)
+ self.assertIsInstance(BPoint(1, 2), Position)
+ self.assertIsInstance(Other(), Proto)
+ self.assertIsInstance(Concrete(), Proto)
+ self.assertIsInstance(C(42), Proto)
+ self.assertNotIsInstance(Bad(), Proto)
+ self.assertNotIsInstance(Bad(), Point)
+ self.assertNotIsInstance(Bad(), Position)
+ self.assertNotIsInstance(Bad(), Concrete)
+ self.assertNotIsInstance(Other(), Concrete)
+ self.assertIsInstance(NT(1, 2), Position)
+
+ def test_protocols_isinstance_init(self):
+ T = TypeVar('T')
+ @runtime
+ class P(Protocol):
+ x = 1
+ @runtime
+ class PG(Protocol[T]):
+ x = 1
+ class C:
+ def __init__(self, x):
+ self.x = x
+ self.assertIsInstance(C(1), P)
+ self.assertIsInstance(C(1), PG)
+
+ def test_protocols_support_register(self):
+ @runtime
+ class P(Protocol):
+ x = 1
+ class PM(Protocol):
+ def meth(self): pass
+ class D(PM): pass
+ class C: pass
+ D.register(C)
+ P.register(C)
+ self.assertIsInstance(C(), P)
+ self.assertIsInstance(C(), D)
+
+ def test_none_on_non_callable_doesnt_block_implementation(self):
+ @runtime
+ class P(Protocol):
+ x = 1
+ class A:
+ x = 1
+ class B(A):
+ x = None
+ class C:
+ def __init__(self):
+ self.x = None
+ self.assertIsInstance(B(), P)
+ self.assertIsInstance(C(), P)
+
+ def test_none_on_callable_blocks_implementation(self):
+ @runtime
+ class P(Protocol):
+ def x(self): ...
+ class A:
+ def x(self): ...
+ class B(A):
+ x = None
+ class C:
+ def __init__(self):
+ self.x = None
+ self.assertNotIsInstance(B(), P)
+ self.assertNotIsInstance(C(), P)
+
+ def test_non_protocol_subclasses(self):
+ class P(Protocol):
+ x = 1
+ @runtime
+ class PR(Protocol):
+ def meth(self): pass
+ class NonP(P):
+ x = 1
+ class NonPR(PR): pass
+ class C:
+ x = 1
+ class D:
+ def meth(self): pass
+ self.assertNotIsInstance(C(), NonP)
+ self.assertNotIsInstance(D(), NonPR)
+ self.assertNotIsSubclass(C, NonP)
+ self.assertNotIsSubclass(D, NonPR)
+ self.assertIsInstance(NonPR(), PR)
+ self.assertIsSubclass(NonPR, PR)
+
+ def test_custom_subclasshook(self):
+ class P(Protocol):
+ x = 1
+ class OKClass: pass
+ class BadClass:
+ x = 1
+ class C(P):
+ @classmethod
+ def __subclasshook__(cls, other):
+ return other.__name__.startswith("OK")
+ self.assertIsInstance(OKClass(), C)
+ self.assertNotIsInstance(BadClass(), C)
+ self.assertIsSubclass(OKClass, C)
+ self.assertNotIsSubclass(BadClass, C)
+
+ def test_issubclass_fails_correctly(self):
+ @runtime
+ class P(Protocol):
+ x = 1
+ class C: pass
+ with self.assertRaises(TypeError):
+ issubclass(C(), P)
+
+ def test_defining_generic_protocols(self):
+ T = TypeVar('T')
+ S = TypeVar('S')
+ @runtime
+ class PR(Protocol[T, S]):
+ def meth(self): pass
+ class P(PR[int, T], Protocol[T]):
+ y = 1
+ with self.assertRaises(TypeError):
+ issubclass(PR[int, T], PR)
+ with self.assertRaises(TypeError):
+ issubclass(P[str], PR)
+ with self.assertRaises(TypeError):
+ PR[int]
+ with self.assertRaises(TypeError):
+ P[int, str]
+ if not TYPING_3_10_0:
+ with self.assertRaises(TypeError):
+ PR[int, 1]
+ with self.assertRaises(TypeError):
+ PR[int, ClassVar]
+ class C(PR[int, T]): pass
+ self.assertIsInstance(C[str](), C)
+
+ def test_defining_generic_protocols_old_style(self):
+ T = TypeVar('T')
+ S = TypeVar('S')
+ @runtime
+ class PR(Protocol, Generic[T, S]):
+ def meth(self): pass
+ class P(PR[int, str], Protocol):
+ y = 1
+ with self.assertRaises(TypeError):
+ self.assertIsSubclass(PR[int, str], PR)
+ self.assertIsSubclass(P, PR)
+ with self.assertRaises(TypeError):
+ PR[int]
+ if not TYPING_3_10_0:
+ with self.assertRaises(TypeError):
+ PR[int, 1]
+ class P1(Protocol, Generic[T]):
+ def bar(self, x: T) -> str: ...
+ class P2(Generic[T], Protocol):
+ def bar(self, x: T) -> str: ...
+ @runtime
+ class PSub(P1[str], Protocol):
+ x = 1
+ class Test:
+ x = 1
+ def bar(self, x: str) -> str:
+ return x
+ self.assertIsInstance(Test(), PSub)
+ if not TYPING_3_10_0:
+ with self.assertRaises(TypeError):
+ PR[int, ClassVar]
+
+ def test_init_called(self):
+ T = TypeVar('T')
+ class P(Protocol[T]): pass
+ class C(P[T]):
+ def __init__(self):
+ self.test = 'OK'
+ self.assertEqual(C[int]().test, 'OK')
+
+ def test_protocols_bad_subscripts(self):
+ T = TypeVar('T')
+ S = TypeVar('S')
+ with self.assertRaises(TypeError):
+ class P(Protocol[T, T]): pass
+ with self.assertRaises(TypeError):
+ class P(Protocol[int]): pass
+ with self.assertRaises(TypeError):
+ class P(Protocol[T], Protocol[S]): pass
+ with self.assertRaises(TypeError):
+ class P(typing.Mapping[T, S], Protocol[T]): pass
+
+ def test_generic_protocols_repr(self):
+ T = TypeVar('T')
+ S = TypeVar('S')
+ class P(Protocol[T, S]): pass
+ self.assertTrue(repr(P[T, S]).endswith('P[~T, ~S]'))
+ self.assertTrue(repr(P[int, str]).endswith('P[int, str]'))
+
+ def test_generic_protocols_eq(self):
+ T = TypeVar('T')
+ S = TypeVar('S')
+ class P(Protocol[T, S]): pass
+ self.assertEqual(P, P)
+ self.assertEqual(P[int, T], P[int, T])
+ self.assertEqual(P[T, T][Tuple[T, S]][int, str],
+ P[Tuple[int, str], Tuple[int, str]])
+
+ def test_generic_protocols_special_from_generic(self):
+ T = TypeVar('T')
+ class P(Protocol[T]): pass
+ self.assertEqual(P.__parameters__, (T,))
+ self.assertEqual(P[int].__parameters__, ())
+ self.assertEqual(P[int].__args__, (int,))
+ self.assertIs(P[int].__origin__, P)
+
+ def test_generic_protocols_special_from_protocol(self):
+ @runtime
+ class PR(Protocol):
+ x = 1
+ class P(Protocol):
+ def meth(self):
+ pass
+ T = TypeVar('T')
+ class PG(Protocol[T]):
+ x = 1
+ def meth(self):
+ pass
+ self.assertTrue(P._is_protocol)
+ self.assertTrue(PR._is_protocol)
+ self.assertTrue(PG._is_protocol)
+ if hasattr(typing, 'Protocol'):
+ self.assertFalse(P._is_runtime_protocol)
+ else:
+ with self.assertRaises(AttributeError):
+ self.assertFalse(P._is_runtime_protocol)
+ self.assertTrue(PR._is_runtime_protocol)
+ self.assertTrue(PG[int]._is_protocol)
+ self.assertEqual(typing_extensions._get_protocol_attrs(P), {'meth'})
+ self.assertEqual(typing_extensions._get_protocol_attrs(PR), {'x'})
+ self.assertEqual(frozenset(typing_extensions._get_protocol_attrs(PG)),
+ frozenset({'x', 'meth'}))
+
+ def test_no_runtime_deco_on_nominal(self):
+ with self.assertRaises(TypeError):
+ @runtime
+ class C: pass
+ class Proto(Protocol):
+ x = 1
+ with self.assertRaises(TypeError):
+ @runtime
+ class Concrete(Proto):
+ pass
+
+ def test_none_treated_correctly(self):
+ @runtime
+ class P(Protocol):
+ x = None # type: int
+ class B(object): pass
+ self.assertNotIsInstance(B(), P)
+ class C:
+ x = 1
+ class D:
+ x = None
+ self.assertIsInstance(C(), P)
+ self.assertIsInstance(D(), P)
+ class CI:
+ def __init__(self):
+ self.x = 1
+ class DI:
+ def __init__(self):
+ self.x = None
+ self.assertIsInstance(C(), P)
+ self.assertIsInstance(D(), P)
+
+ def test_protocols_in_unions(self):
+ class P(Protocol):
+ x = None # type: int
+ Alias = typing.Union[typing.Iterable, P]
+ Alias2 = typing.Union[P, typing.Iterable]
+ self.assertEqual(Alias, Alias2)
+
+ def test_protocols_pickleable(self):
+ global P, CP # pickle wants to reference the class by name
+ T = TypeVar('T')
+
+ @runtime
+ class P(Protocol[T]):
+ x = 1
+ class CP(P[int]):
+ pass
+
+ c = CP()
+ c.foo = 42
+ c.bar = 'abc'
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ z = pickle.dumps(c, proto)
+ x = pickle.loads(z)
+ self.assertEqual(x.foo, 42)
+ self.assertEqual(x.bar, 'abc')
+ self.assertEqual(x.x, 1)
+ self.assertEqual(x.__dict__, {'foo': 42, 'bar': 'abc'})
+ s = pickle.dumps(P)
+ D = pickle.loads(s)
+ class E:
+ x = 1
+ self.assertIsInstance(E(), D)
+
+ def test_collections_protocols_allowed(self):
+ @runtime_checkable
+ class Custom(collections.abc.Iterable, Protocol):
+ def close(self): pass
+
+ class A: ...
+ class B:
+ def __iter__(self):
+ return []
+ def close(self):
+ return 0
+
+ self.assertIsSubclass(B, Custom)
+ self.assertNotIsSubclass(A, Custom)
+
+ def test_no_init_same_for_different_protocol_implementations(self):
+ class CustomProtocolWithoutInitA(Protocol):
+ pass
+
+ class CustomProtocolWithoutInitB(Protocol):
+ pass
+
+ self.assertEqual(CustomProtocolWithoutInitA.__init__, CustomProtocolWithoutInitB.__init__)
+
+
+class TypedDictTests(BaseTestCase):
+
+ def test_basics_iterable_syntax(self):
+ Emp = TypedDict('Emp', {'name': str, 'id': int})
+ self.assertIsSubclass(Emp, dict)
+ self.assertIsSubclass(Emp, typing.MutableMapping)
+ self.assertNotIsSubclass(Emp, collections.abc.Sequence)
+ jim = Emp(name='Jim', id=1)
+ self.assertIs(type(jim), dict)
+ self.assertEqual(jim['name'], 'Jim')
+ self.assertEqual(jim['id'], 1)
+ self.assertEqual(Emp.__name__, 'Emp')
+ self.assertEqual(Emp.__module__, __name__)
+ self.assertEqual(Emp.__bases__, (dict,))
+ self.assertEqual(Emp.__annotations__, {'name': str, 'id': int})
+ self.assertEqual(Emp.__total__, True)
+
+ def test_basics_keywords_syntax(self):
+ Emp = TypedDict('Emp', name=str, id=int)
+ self.assertIsSubclass(Emp, dict)
+ self.assertIsSubclass(Emp, typing.MutableMapping)
+ self.assertNotIsSubclass(Emp, collections.abc.Sequence)
+ jim = Emp(name='Jim', id=1)
+ self.assertIs(type(jim), dict)
+ self.assertEqual(jim['name'], 'Jim')
+ self.assertEqual(jim['id'], 1)
+ self.assertEqual(Emp.__name__, 'Emp')
+ self.assertEqual(Emp.__module__, __name__)
+ self.assertEqual(Emp.__bases__, (dict,))
+ self.assertEqual(Emp.__annotations__, {'name': str, 'id': int})
+ self.assertEqual(Emp.__total__, True)
+
+ def test_typeddict_special_keyword_names(self):
+ TD = TypedDict("TD", cls=type, self=object, typename=str, _typename=int,
+ fields=list, _fields=dict)
+ self.assertEqual(TD.__name__, 'TD')
+ self.assertEqual(TD.__annotations__, {'cls': type, 'self': object, 'typename': str,
+ '_typename': int, 'fields': list, '_fields': dict})
+ a = TD(cls=str, self=42, typename='foo', _typename=53,
+ fields=[('bar', tuple)], _fields={'baz', set})
+ self.assertEqual(a['cls'], str)
+ self.assertEqual(a['self'], 42)
+ self.assertEqual(a['typename'], 'foo')
+ self.assertEqual(a['_typename'], 53)
+ self.assertEqual(a['fields'], [('bar', tuple)])
+ self.assertEqual(a['_fields'], {'baz', set})
+
+ @skipIf(hasattr(typing, 'TypedDict'), "Should be tested by upstream")
+ def test_typeddict_create_errors(self):
+ with self.assertRaises(TypeError):
+ TypedDict.__new__()
+ with self.assertRaises(TypeError):
+ TypedDict()
+ with self.assertRaises(TypeError):
+ TypedDict('Emp', [('name', str)], None)
+
+ with self.assertWarns(DeprecationWarning):
+ Emp = TypedDict(_typename='Emp', name=str, id=int)
+ self.assertEqual(Emp.__name__, 'Emp')
+ self.assertEqual(Emp.__annotations__, {'name': str, 'id': int})
+
+ with self.assertWarns(DeprecationWarning):
+ Emp = TypedDict('Emp', _fields={'name': str, 'id': int})
+ self.assertEqual(Emp.__name__, 'Emp')
+ self.assertEqual(Emp.__annotations__, {'name': str, 'id': int})
+
+ def test_typeddict_errors(self):
+ Emp = TypedDict('Emp', {'name': str, 'id': int})
+ if hasattr(typing, "Required"):
+ self.assertEqual(TypedDict.__module__, 'typing')
+ else:
+ self.assertEqual(TypedDict.__module__, 'typing_extensions')
+ jim = Emp(name='Jim', id=1)
+ with self.assertRaises(TypeError):
+ isinstance({}, Emp)
+ with self.assertRaises(TypeError):
+ isinstance(jim, Emp)
+ with self.assertRaises(TypeError):
+ issubclass(dict, Emp)
+ with self.assertRaises(TypeError):
+ TypedDict('Hi', x=1)
+ with self.assertRaises(TypeError):
+ TypedDict('Hi', [('x', int), ('y', 1)])
+ with self.assertRaises(TypeError):
+ TypedDict('Hi', [('x', int)], y=int)
+
+ def test_py36_class_syntax_usage(self):
+ self.assertEqual(LabelPoint2D.__name__, 'LabelPoint2D')
+ self.assertEqual(LabelPoint2D.__module__, __name__)
+ self.assertEqual(get_type_hints(LabelPoint2D), {'x': int, 'y': int, 'label': str})
+ self.assertEqual(LabelPoint2D.__bases__, (dict,))
+ self.assertEqual(LabelPoint2D.__total__, True)
+ self.assertNotIsSubclass(LabelPoint2D, typing.Sequence)
+ not_origin = Point2D(x=0, y=1)
+ self.assertEqual(not_origin['x'], 0)
+ self.assertEqual(not_origin['y'], 1)
+ other = LabelPoint2D(x=0, y=1, label='hi')
+ self.assertEqual(other['label'], 'hi')
+
+ def test_pickle(self):
+ global EmpD # pickle wants to reference the class by name
+ EmpD = TypedDict('EmpD', name=str, id=int)
+ jane = EmpD({'name': 'jane', 'id': 37})
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ z = pickle.dumps(jane, proto)
+ jane2 = pickle.loads(z)
+ self.assertEqual(jane2, jane)
+ self.assertEqual(jane2, {'name': 'jane', 'id': 37})
+ ZZ = pickle.dumps(EmpD, proto)
+ EmpDnew = pickle.loads(ZZ)
+ self.assertEqual(EmpDnew({'name': 'jane', 'id': 37}), jane)
+
+ def test_optional(self):
+ EmpD = TypedDict('EmpD', name=str, id=int)
+
+ self.assertEqual(typing.Optional[EmpD], typing.Union[None, EmpD])
+ self.assertNotEqual(typing.List[EmpD], typing.Tuple[EmpD])
+
+ def test_total(self):
+ D = TypedDict('D', {'x': int}, total=False)
+ self.assertEqual(D(), {})
+ self.assertEqual(D(x=1), {'x': 1})
+ self.assertEqual(D.__total__, False)
+ self.assertEqual(D.__required_keys__, frozenset())
+ self.assertEqual(D.__optional_keys__, {'x'})
+
+ self.assertEqual(Options(), {})
+ self.assertEqual(Options(log_level=2), {'log_level': 2})
+ self.assertEqual(Options.__total__, False)
+ self.assertEqual(Options.__required_keys__, frozenset())
+ self.assertEqual(Options.__optional_keys__, {'log_level', 'log_path'})
+
+ def test_optional_keys(self):
+ assert Point2Dor3D.__required_keys__ == frozenset(['x', 'y'])
+ assert Point2Dor3D.__optional_keys__ == frozenset(['z'])
+
+ def test_required_notrequired_keys(self):
+ assert NontotalMovie.__required_keys__ == frozenset({'title'})
+ assert NontotalMovie.__optional_keys__ == frozenset({'year'})
+
+ assert TotalMovie.__required_keys__ == frozenset({'title'})
+ assert TotalMovie.__optional_keys__ == frozenset({'year'})
+
+
+ def test_keys_inheritance(self):
+ assert BaseAnimal.__required_keys__ == frozenset(['name'])
+ assert BaseAnimal.__optional_keys__ == frozenset([])
+ assert get_type_hints(BaseAnimal) == {'name': str}
+
+ assert Animal.__required_keys__ == frozenset(['name'])
+ assert Animal.__optional_keys__ == frozenset(['tail', 'voice'])
+ assert get_type_hints(Animal) == {
+ 'name': str,
+ 'tail': bool,
+ 'voice': str,
+ }
+
+ assert Cat.__required_keys__ == frozenset(['name', 'fur_color'])
+ assert Cat.__optional_keys__ == frozenset(['tail', 'voice'])
+ assert get_type_hints(Cat) == {
+ 'fur_color': str,
+ 'name': str,
+ 'tail': bool,
+ 'voice': str,
+ }
+
+ def test_is_typeddict(self):
+ assert is_typeddict(Point2D) is True
+ assert is_typeddict(Point2Dor3D) is True
+ assert is_typeddict(Union[str, int]) is False
+ # classes, not instances
+ assert is_typeddict(Point2D()) is False
+
+ @skipUnless(TYPING_3_8_0, "Python 3.8+ required")
+ def test_is_typeddict_against_typeddict_from_typing(self):
+ Point = typing.TypedDict('Point', {'x': int, 'y': int})
+
+ class PointDict2D(typing.TypedDict):
+ x: int
+ y: int
+
+ class PointDict3D(PointDict2D, total=False):
+ z: int
+
+ assert is_typeddict(Point) is True
+ assert is_typeddict(PointDict2D) is True
+ assert is_typeddict(PointDict3D) is True
+
+
+class AnnotatedTests(BaseTestCase):
+
+ def test_repr(self):
+ if hasattr(typing, 'Annotated'):
+ mod_name = 'typing'
+ else:
+ mod_name = "typing_extensions"
+ self.assertEqual(
+ repr(Annotated[int, 4, 5]),
+ mod_name + ".Annotated[int, 4, 5]"
+ )
+ self.assertEqual(
+ repr(Annotated[List[int], 4, 5]),
+ mod_name + ".Annotated[typing.List[int], 4, 5]"
+ )
+
+ def test_flatten(self):
+ A = Annotated[Annotated[int, 4], 5]
+ self.assertEqual(A, Annotated[int, 4, 5])
+ self.assertEqual(A.__metadata__, (4, 5))
+ self.assertEqual(A.__origin__, int)
+
+ def test_specialize(self):
+ L = Annotated[List[T], "my decoration"]
+ LI = Annotated[List[int], "my decoration"]
+ self.assertEqual(L[int], Annotated[List[int], "my decoration"])
+ self.assertEqual(L[int].__metadata__, ("my decoration",))
+ self.assertEqual(L[int].__origin__, List[int])
+ with self.assertRaises(TypeError):
+ LI[int]
+ with self.assertRaises(TypeError):
+ L[int, float]
+
+ def test_hash_eq(self):
+ self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1)
+ self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4])
+ self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5])
+ self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4])
+ self.assertEqual(
+ {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]},
+ {Annotated[int, 4, 5], Annotated[T, 4, 5]}
+ )
+
+ def test_instantiate(self):
+ class C:
+ classvar = 4
+
+ def __init__(self, x):
+ self.x = x
+
+ def __eq__(self, other):
+ if not isinstance(other, C):
+ return NotImplemented
+ return other.x == self.x
+
+ A = Annotated[C, "a decoration"]
+ a = A(5)
+ c = C(5)
+ self.assertEqual(a, c)
+ self.assertEqual(a.x, c.x)
+ self.assertEqual(a.classvar, c.classvar)
+
+ def test_instantiate_generic(self):
+ MyCount = Annotated[typing_extensions.Counter[T], "my decoration"]
+ self.assertEqual(MyCount([4, 4, 5]), {4: 2, 5: 1})
+ self.assertEqual(MyCount[int]([4, 4, 5]), {4: 2, 5: 1})
+
+ def test_cannot_instantiate_forward(self):
+ A = Annotated["int", (5, 6)]
+ with self.assertRaises(TypeError):
+ A(5)
+
+ def test_cannot_instantiate_type_var(self):
+ A = Annotated[T, (5, 6)]
+ with self.assertRaises(TypeError):
+ A(5)
+
+ def test_cannot_getattr_typevar(self):
+ with self.assertRaises(AttributeError):
+ Annotated[T, (5, 7)].x
+
+ def test_attr_passthrough(self):
+ class C:
+ classvar = 4
+
+ A = Annotated[C, "a decoration"]
+ self.assertEqual(A.classvar, 4)
+ A.x = 5
+ self.assertEqual(C.x, 5)
+
+ @skipIf(sys.version_info[:2] in ((3, 9), (3, 10)), "Waiting for bpo-46491 bugfix.")
+ def test_special_form_containment(self):
+ class C:
+ classvar: Annotated[ClassVar[int], "a decoration"] = 4
+ const: Annotated[Final[int], "Const"] = 4
+
+ if sys.version_info[:2] >= (3, 7):
+ self.assertEqual(get_type_hints(C, globals())["classvar"], ClassVar[int])
+ self.assertEqual(get_type_hints(C, globals())["const"], Final[int])
+ else:
+ self.assertEqual(
+ get_type_hints(C, globals())["classvar"],
+ Annotated[ClassVar[int], "a decoration"]
+ )
+ self.assertEqual(
+ get_type_hints(C, globals())["const"], Annotated[Final[int], "Const"]
+ )
+
+ def test_hash_eq(self):
+ self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1)
+ self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4])
+ self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5])
+ self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4])
+ self.assertEqual(
+ {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]},
+ {Annotated[int, 4, 5], Annotated[T, 4, 5]}
+ )
+
+ def test_cannot_subclass(self):
+ with self.assertRaisesRegex(TypeError, "Cannot subclass .*Annotated"):
+ class C(Annotated):
+ pass
+
+ def test_cannot_check_instance(self):
+ with self.assertRaises(TypeError):
+ isinstance(5, Annotated[int, "positive"])
+
+ def test_cannot_check_subclass(self):
+ with self.assertRaises(TypeError):
+ issubclass(int, Annotated[int, "positive"])
+
+ def test_pickle(self):
+ samples = [typing.Any, typing.Union[int, str],
+ typing.Optional[str], Tuple[int, ...],
+ typing.Callable[[str], bytes],
+ Self, LiteralString, Never]
+
+ for t in samples:
+ x = Annotated[t, "a"]
+
+ for prot in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(protocol=prot, type=t):
+ pickled = pickle.dumps(x, prot)
+ restored = pickle.loads(pickled)
+ self.assertEqual(x, restored)
+
+ global _Annotated_test_G
+
+ class _Annotated_test_G(Generic[T]):
+ x = 1
+
+ G = Annotated[_Annotated_test_G[int], "A decoration"]
+ G.foo = 42
+ G.bar = 'abc'
+
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ z = pickle.dumps(G, proto)
+ x = pickle.loads(z)
+ self.assertEqual(x.foo, 42)
+ self.assertEqual(x.bar, 'abc')
+ self.assertEqual(x.x, 1)
+
+ def test_subst(self):
+ dec = "a decoration"
+ dec2 = "another decoration"
+
+ S = Annotated[T, dec2]
+ self.assertEqual(S[int], Annotated[int, dec2])
+
+ self.assertEqual(S[Annotated[int, dec]], Annotated[int, dec, dec2])
+ L = Annotated[List[T], dec]
+
+ self.assertEqual(L[int], Annotated[List[int], dec])
+ with self.assertRaises(TypeError):
+ L[int, int]
+
+ self.assertEqual(S[L[int]], Annotated[List[int], dec, dec2])
+
+ D = Annotated[Dict[KT, VT], dec]
+ self.assertEqual(D[str, int], Annotated[Dict[str, int], dec])
+ with self.assertRaises(TypeError):
+ D[int]
+
+ It = Annotated[int, dec]
+ with self.assertRaises(TypeError):
+ It[None]
+
+ LI = L[int]
+ with self.assertRaises(TypeError):
+ LI[None]
+
+ def test_annotated_in_other_types(self):
+ X = List[Annotated[T, 5]]
+ self.assertEqual(X[int], List[Annotated[int, 5]])
+
+
+class GetTypeHintsTests(BaseTestCase):
+ def test_get_type_hints(self):
+ def foobar(x: List['X']): ...
+ X = Annotated[int, (1, 10)]
+ self.assertEqual(
+ get_type_hints(foobar, globals(), locals()),
+ {'x': List[int]}
+ )
+ self.assertEqual(
+ get_type_hints(foobar, globals(), locals(), include_extras=True),
+ {'x': List[Annotated[int, (1, 10)]]}
+ )
+ BA = Tuple[Annotated[T, (1, 0)], ...]
+ def barfoo(x: BA): ...
+ self.assertEqual(get_type_hints(barfoo, globals(), locals())['x'], Tuple[T, ...])
+ self.assertIs(
+ get_type_hints(barfoo, globals(), locals(), include_extras=True)['x'],
+ BA
+ )
+ def barfoo2(x: typing.Callable[..., Annotated[List[T], "const"]],
+ y: typing.Union[int, Annotated[T, "mutable"]]): ...
+ self.assertEqual(
+ get_type_hints(barfoo2, globals(), locals()),
+ {'x': typing.Callable[..., List[T]], 'y': typing.Union[int, T]}
+ )
+ BA2 = typing.Callable[..., List[T]]
+ def barfoo3(x: BA2): ...
+ self.assertIs(
+ get_type_hints(barfoo3, globals(), locals(), include_extras=True)["x"],
+ BA2
+ )
+
+ def test_get_type_hints_refs(self):
+
+ Const = Annotated[T, "Const"]
+
+ class MySet(Generic[T]):
+
+ def __ior__(self, other: "Const[MySet[T]]") -> "MySet[T]":
+ ...
+
+ def __iand__(self, other: Const["MySet[T]"]) -> "MySet[T]":
+ ...
+
+ self.assertEqual(
+ get_type_hints(MySet.__iand__, globals(), locals()),
+ {'other': MySet[T], 'return': MySet[T]}
+ )
+
+ self.assertEqual(
+ get_type_hints(MySet.__iand__, globals(), locals(), include_extras=True),
+ {'other': Const[MySet[T]], 'return': MySet[T]}
+ )
+
+ self.assertEqual(
+ get_type_hints(MySet.__ior__, globals(), locals()),
+ {'other': MySet[T], 'return': MySet[T]}
+ )
+
+ def test_get_type_hints_typeddict(self):
+ assert get_type_hints(TotalMovie) == {'title': str, 'year': int}
+ assert get_type_hints(TotalMovie, include_extras=True) == {
+ 'title': str,
+ 'year': NotRequired[int],
+ }
+
+ assert get_type_hints(AnnotatedMovie) == {'title': str, 'year': int}
+ assert get_type_hints(AnnotatedMovie, include_extras=True) == {
+ 'title': Annotated[Required[str], "foobar"],
+ 'year': NotRequired[Annotated[int, 2000]],
+ }
+
+
+class TypeAliasTests(BaseTestCase):
+ def test_canonical_usage_with_variable_annotation(self):
+ ns = {}
+ exec('Alias: TypeAlias = Employee', globals(), ns)
+
+ def test_canonical_usage_with_type_comment(self):
+ Alias = Employee # type: TypeAlias
+
+ def test_cannot_instantiate(self):
+ with self.assertRaises(TypeError):
+ TypeAlias()
+
+ def test_no_isinstance(self):
+ with self.assertRaises(TypeError):
+ isinstance(42, TypeAlias)
+
+ def test_no_issubclass(self):
+ with self.assertRaises(TypeError):
+ issubclass(Employee, TypeAlias)
+
+ with self.assertRaises(TypeError):
+ issubclass(TypeAlias, Employee)
+
+ def test_cannot_subclass(self):
+ with self.assertRaises(TypeError):
+ class C(TypeAlias):
+ pass
+
+ with self.assertRaises(TypeError):
+ class C(type(TypeAlias)):
+ pass
+
+ def test_repr(self):
+ if hasattr(typing, 'TypeAlias'):
+ self.assertEqual(repr(TypeAlias), 'typing.TypeAlias')
+ else:
+ self.assertEqual(repr(TypeAlias), 'typing_extensions.TypeAlias')
+
+ def test_cannot_subscript(self):
+ with self.assertRaises(TypeError):
+ TypeAlias[int]
+
+class ParamSpecTests(BaseTestCase):
+
+ def test_basic_plain(self):
+ P = ParamSpec('P')
+ self.assertEqual(P, P)
+ self.assertIsInstance(P, ParamSpec)
+ # Should be hashable
+ hash(P)
+
+ def test_repr(self):
+ P = ParamSpec('P')
+ P_co = ParamSpec('P_co', covariant=True)
+ P_contra = ParamSpec('P_contra', contravariant=True)
+ P_2 = ParamSpec('P_2')
+ self.assertEqual(repr(P), '~P')
+ self.assertEqual(repr(P_2), '~P_2')
+
+ # Note: PEP 612 doesn't require these to be repr-ed correctly, but
+ # just follow CPython.
+ self.assertEqual(repr(P_co), '+P_co')
+ self.assertEqual(repr(P_contra), '-P_contra')
+
+ def test_valid_uses(self):
+ P = ParamSpec('P')
+ T = TypeVar('T')
+ C1 = typing.Callable[P, int]
+ self.assertEqual(C1.__args__, (P, int))
+ self.assertEqual(C1.__parameters__, (P,))
+ C2 = typing.Callable[P, T]
+ self.assertEqual(C2.__args__, (P, T))
+ self.assertEqual(C2.__parameters__, (P, T))
+
+
+ # Test collections.abc.Callable too.
+ if sys.version_info[:2] >= (3, 9):
+ # Note: no tests for Callable.__parameters__ here
+ # because types.GenericAlias Callable is hardcoded to search
+ # for tp_name "TypeVar" in C. This was changed in 3.10.
+ C3 = collections.abc.Callable[P, int]
+ self.assertEqual(C3.__args__, (P, int))
+ C4 = collections.abc.Callable[P, T]
+ self.assertEqual(C4.__args__, (P, T))
+
+ # ParamSpec instances should also have args and kwargs attributes.
+ # Note: not in dir(P) because of __class__ hacks
+ self.assertTrue(hasattr(P, 'args'))
+ self.assertTrue(hasattr(P, 'kwargs'))
+
+ @skipIf((3, 10, 0) <= sys.version_info[:3] <= (3, 10, 2), "Needs bpo-46676.")
+ def test_args_kwargs(self):
+ P = ParamSpec('P')
+ P_2 = ParamSpec('P_2')
+ # Note: not in dir(P) because of __class__ hacks
+ self.assertTrue(hasattr(P, 'args'))
+ self.assertTrue(hasattr(P, 'kwargs'))
+ self.assertIsInstance(P.args, ParamSpecArgs)
+ self.assertIsInstance(P.kwargs, ParamSpecKwargs)
+ self.assertIs(P.args.__origin__, P)
+ self.assertIs(P.kwargs.__origin__, P)
+ self.assertEqual(P.args, P.args)
+ self.assertEqual(P.kwargs, P.kwargs)
+ self.assertNotEqual(P.args, P_2.args)
+ self.assertNotEqual(P.kwargs, P_2.kwargs)
+ self.assertNotEqual(P.args, P.kwargs)
+ self.assertNotEqual(P.kwargs, P.args)
+ self.assertNotEqual(P.args, P_2.kwargs)
+ self.assertEqual(repr(P.args), "P.args")
+ self.assertEqual(repr(P.kwargs), "P.kwargs")
+
+ def test_user_generics(self):
+ T = TypeVar("T")
+ P = ParamSpec("P")
+ P_2 = ParamSpec("P_2")
+
+ class X(Generic[T, P]):
+ pass
+
+ G1 = X[int, P_2]
+ self.assertEqual(G1.__args__, (int, P_2))
+ self.assertEqual(G1.__parameters__, (P_2,))
+
+ G2 = X[int, Concatenate[int, P_2]]
+ self.assertEqual(G2.__args__, (int, Concatenate[int, P_2]))
+ self.assertEqual(G2.__parameters__, (P_2,))
+
+ # The following are some valid uses cases in PEP 612 that don't work:
+ # These do not work in 3.9, _type_check blocks the list and ellipsis.
+ # G3 = X[int, [int, bool]]
+ # G4 = X[int, ...]
+ # G5 = Z[[int, str, bool]]
+ # Not working because this is special-cased in 3.10.
+ # G6 = Z[int, str, bool]
+
+ class Z(Generic[P]):
+ pass
+
+ def test_pickle(self):
+ global P, P_co, P_contra
+ P = ParamSpec('P')
+ P_co = ParamSpec('P_co', covariant=True)
+ P_contra = ParamSpec('P_contra', contravariant=True)
+ for proto in range(pickle.HIGHEST_PROTOCOL):
+ with self.subTest(f'Pickle protocol {proto}'):
+ for paramspec in (P, P_co, P_contra):
+ z = pickle.loads(pickle.dumps(paramspec, proto))
+ self.assertEqual(z.__name__, paramspec.__name__)
+ self.assertEqual(z.__covariant__, paramspec.__covariant__)
+ self.assertEqual(z.__contravariant__, paramspec.__contravariant__)
+ self.assertEqual(z.__bound__, paramspec.__bound__)
+
+ def test_eq(self):
+ P = ParamSpec('P')
+ self.assertEqual(P, P)
+ self.assertEqual(hash(P), hash(P))
+ # ParamSpec should compare by id similar to TypeVar in CPython
+ self.assertNotEqual(ParamSpec('P'), P)
+ self.assertIsNot(ParamSpec('P'), P)
+ # Note: normally you don't test this as it breaks when there's
+ # a hash collision. However, ParamSpec *must* guarantee that
+ # as long as two objects don't have the same ID, their hashes
+ # won't be the same.
+ self.assertNotEqual(hash(ParamSpec('P')), hash(P))
+
+
+class ConcatenateTests(BaseTestCase):
+ def test_basics(self):
+ P = ParamSpec('P')
+
+ class MyClass: ...
+
+ c = Concatenate[MyClass, P]
+ self.assertNotEqual(c, Concatenate)
+
+ def test_valid_uses(self):
+ P = ParamSpec('P')
+ T = TypeVar('T')
+
+ C1 = Callable[Concatenate[int, P], int]
+ C2 = Callable[Concatenate[int, T, P], T]
+
+ # Test collections.abc.Callable too.
+ if sys.version_info[:2] >= (3, 9):
+ C3 = collections.abc.Callable[Concatenate[int, P], int]
+ C4 = collections.abc.Callable[Concatenate[int, T, P], T]
+
+ def test_invalid_uses(self):
+ P = ParamSpec('P')
+ T = TypeVar('T')
+
+ with self.assertRaisesRegex(
+ TypeError,
+ 'Cannot take a Concatenate of no types',
+ ):
+ Concatenate[()]
+
+ with self.assertRaisesRegex(
+ TypeError,
+ 'The last parameter to Concatenate should be a ParamSpec variable',
+ ):
+ Concatenate[P, T]
+
+ with self.assertRaisesRegex(
+ TypeError,
+ 'each arg must be a type',
+ ):
+ Concatenate[1, P]
+
+ def test_basic_introspection(self):
+ P = ParamSpec('P')
+ C1 = Concatenate[int, P]
+ C2 = Concatenate[int, T, P]
+ self.assertEqual(C1.__origin__, Concatenate)
+ self.assertEqual(C1.__args__, (int, P))
+ self.assertEqual(C2.__origin__, Concatenate)
+ self.assertEqual(C2.__args__, (int, T, P))
+
+ def test_eq(self):
+ P = ParamSpec('P')
+ C1 = Concatenate[int, P]
+ C2 = Concatenate[int, P]
+ C3 = Concatenate[int, T, P]
+ self.assertEqual(C1, C2)
+ self.assertEqual(hash(C1), hash(C2))
+ self.assertNotEqual(C1, C3)
+
+
+class TypeGuardTests(BaseTestCase):
+ def test_basics(self):
+ TypeGuard[int] # OK
+ self.assertEqual(TypeGuard[int], TypeGuard[int])
+
+ def foo(arg) -> TypeGuard[int]: ...
+ self.assertEqual(gth(foo), {'return': TypeGuard[int]})
+
+ def test_repr(self):
+ if hasattr(typing, 'TypeGuard'):
+ mod_name = 'typing'
+ else:
+ mod_name = 'typing_extensions'
+ self.assertEqual(repr(TypeGuard), f'{mod_name}.TypeGuard')
+ cv = TypeGuard[int]
+ self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[int]')
+ cv = TypeGuard[Employee]
+ self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[{__name__}.Employee]')
+ cv = TypeGuard[Tuple[int]]
+ self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[typing.Tuple[int]]')
+
+ def test_cannot_subclass(self):
+ with self.assertRaises(TypeError):
+ class C(type(TypeGuard)):
+ pass
+ with self.assertRaises(TypeError):
+ class C(type(TypeGuard[int])):
+ pass
+
+ def test_cannot_init(self):
+ with self.assertRaises(TypeError):
+ TypeGuard()
+ with self.assertRaises(TypeError):
+ type(TypeGuard)()
+ with self.assertRaises(TypeError):
+ type(TypeGuard[Optional[int]])()
+
+ def test_no_isinstance(self):
+ with self.assertRaises(TypeError):
+ isinstance(1, TypeGuard[int])
+ with self.assertRaises(TypeError):
+ issubclass(int, TypeGuard)
+
+
+class LiteralStringTests(BaseTestCase):
+ def test_basics(self):
+ class Foo:
+ def bar(self) -> LiteralString: ...
+ def baz(self) -> "LiteralString": ...
+
+ self.assertEqual(gth(Foo.bar), {'return': LiteralString})
+ self.assertEqual(gth(Foo.baz), {'return': LiteralString})
+
+ def test_get_origin(self):
+ self.assertIsNone(get_origin(LiteralString))
+
+ def test_repr(self):
+ if hasattr(typing, 'LiteralString'):
+ mod_name = 'typing'
+ else:
+ mod_name = 'typing_extensions'
+ self.assertEqual(repr(LiteralString), '{}.LiteralString'.format(mod_name))
+
+ def test_cannot_subscript(self):
+ with self.assertRaises(TypeError):
+ LiteralString[int]
+
+ def test_cannot_subclass(self):
+ with self.assertRaises(TypeError):
+ class C(type(LiteralString)):
+ pass
+ with self.assertRaises(TypeError):
+ class C(LiteralString):
+ pass
+
+ def test_cannot_init(self):
+ with self.assertRaises(TypeError):
+ LiteralString()
+ with self.assertRaises(TypeError):
+ type(LiteralString)()
+
+ def test_no_isinstance(self):
+ with self.assertRaises(TypeError):
+ isinstance(1, LiteralString)
+ with self.assertRaises(TypeError):
+ issubclass(int, LiteralString)
+
+ def test_alias(self):
+ StringTuple = Tuple[LiteralString, LiteralString]
+ class Alias:
+ def return_tuple(self) -> StringTuple:
+ return ("foo", "pep" + "675")
+
+ def test_typevar(self):
+ StrT = TypeVar("StrT", bound=LiteralString)
+ self.assertIs(StrT.__bound__, LiteralString)
+
+ def test_pickle(self):
+ for proto in range(pickle.HIGHEST_PROTOCOL):
+ pickled = pickle.dumps(LiteralString, protocol=proto)
+ self.assertIs(LiteralString, pickle.loads(pickled))
+
+
+class SelfTests(BaseTestCase):
+ def test_basics(self):
+ class Foo:
+ def bar(self) -> Self: ...
+
+ self.assertEqual(gth(Foo.bar), {'return': Self})
+
+ def test_repr(self):
+ if hasattr(typing, 'Self'):
+ mod_name = 'typing'
+ else:
+ mod_name = 'typing_extensions'
+ self.assertEqual(repr(Self), '{}.Self'.format(mod_name))
+
+ def test_cannot_subscript(self):
+ with self.assertRaises(TypeError):
+ Self[int]
+
+ def test_cannot_subclass(self):
+ with self.assertRaises(TypeError):
+ class C(type(Self)):
+ pass
+
+ def test_cannot_init(self):
+ with self.assertRaises(TypeError):
+ Self()
+ with self.assertRaises(TypeError):
+ type(Self)()
+
+ def test_no_isinstance(self):
+ with self.assertRaises(TypeError):
+ isinstance(1, Self)
+ with self.assertRaises(TypeError):
+ issubclass(int, Self)
+
+ def test_alias(self):
+ TupleSelf = Tuple[Self, Self]
+ class Alias:
+ def return_tuple(self) -> TupleSelf:
+ return (self, self)
+
+ def test_pickle(self):
+ for proto in range(pickle.HIGHEST_PROTOCOL):
+ pickled = pickle.dumps(Self, protocol=proto)
+ self.assertIs(Self, pickle.loads(pickled))
+
+
+class UnpackTests(BaseTestCase):
+ def test_basic_plain(self):
+ Ts = TypeVarTuple('Ts')
+ self.assertEqual(Unpack[Ts], Unpack[Ts])
+ with self.assertRaises(TypeError):
+ Unpack()
+
+ def test_repr(self):
+ Ts = TypeVarTuple('Ts')
+ self.assertEqual(repr(Unpack[Ts]), 'typing_extensions.Unpack[Ts]')
+
+ def test_cannot_subclass_vars(self):
+ with self.assertRaises(TypeError):
+ class V(Unpack[TypeVarTuple('Ts')]):
+ pass
+
+ def test_tuple(self):
+ Ts = TypeVarTuple('Ts')
+ Tuple[Unpack[Ts]]
+
+ def test_union(self):
+ Xs = TypeVarTuple('Xs')
+ Ys = TypeVarTuple('Ys')
+ self.assertEqual(
+ Union[Unpack[Xs]],
+ Unpack[Xs]
+ )
+ self.assertNotEqual(
+ Union[Unpack[Xs]],
+ Union[Unpack[Xs], Unpack[Ys]]
+ )
+ self.assertEqual(
+ Union[Unpack[Xs], Unpack[Xs]],
+ Unpack[Xs]
+ )
+ self.assertNotEqual(
+ Union[Unpack[Xs], int],
+ Union[Unpack[Xs]]
+ )
+ self.assertNotEqual(
+ Union[Unpack[Xs], int],
+ Union[int]
+ )
+ self.assertEqual(
+ Union[Unpack[Xs], int].__args__,
+ (Unpack[Xs], int)
+ )
+ self.assertEqual(
+ Union[Unpack[Xs], int].__parameters__,
+ (Xs,)
+ )
+ self.assertIs(
+ Union[Unpack[Xs], int].__origin__,
+ Union
+ )
+
+ def test_concatenation(self):
+ Xs = TypeVarTuple('Xs')
+ self.assertEqual(Tuple[int, Unpack[Xs]].__args__, (int, Unpack[Xs]))
+ self.assertEqual(Tuple[Unpack[Xs], int].__args__, (Unpack[Xs], int))
+ self.assertEqual(Tuple[int, Unpack[Xs], str].__args__,
+ (int, Unpack[Xs], str))
+ class C(Generic[Unpack[Xs]]): pass
+ self.assertEqual(C[int, Unpack[Xs]].__args__, (int, Unpack[Xs]))
+ self.assertEqual(C[Unpack[Xs], int].__args__, (Unpack[Xs], int))
+ self.assertEqual(C[int, Unpack[Xs], str].__args__,
+ (int, Unpack[Xs], str))
+
+ def test_class(self):
+ Ts = TypeVarTuple('Ts')
+
+ class C(Generic[Unpack[Ts]]): pass
+ self.assertEqual(C[int].__args__, (int,))
+ self.assertEqual(C[int, str].__args__, (int, str))
+
+ with self.assertRaises(TypeError):
+ class C(Generic[Unpack[Ts], int]): pass
+
+ T1 = TypeVar('T')
+ T2 = TypeVar('T')
+ class C(Generic[T1, T2, Unpack[Ts]]): pass
+ self.assertEqual(C[int, str].__args__, (int, str))
+ self.assertEqual(C[int, str, float].__args__, (int, str, float))
+ self.assertEqual(C[int, str, float, bool].__args__, (int, str, float, bool))
+ with self.assertRaises(TypeError):
+ C[int]
+
+
+class TypeVarTupleTests(BaseTestCase):
+
+ def test_basic_plain(self):
+ Ts = TypeVarTuple('Ts')
+ self.assertEqual(Ts, Ts)
+ self.assertIsInstance(Ts, TypeVarTuple)
+ Xs = TypeVarTuple('Xs')
+ Ys = TypeVarTuple('Ys')
+ self.assertNotEqual(Xs, Ys)
+
+ def test_repr(self):
+ Ts = TypeVarTuple('Ts')
+ self.assertEqual(repr(Ts), 'Ts')
+
+ def test_no_redefinition(self):
+ self.assertNotEqual(TypeVarTuple('Ts'), TypeVarTuple('Ts'))
+
+ def test_cannot_subclass_vars(self):
+ with self.assertRaises(TypeError):
+ class V(TypeVarTuple('Ts')):
+ pass
+
+ def test_cannot_subclass_var_itself(self):
+ with self.assertRaises(TypeError):
+ class V(TypeVarTuple):
+ pass
+
+ def test_cannot_instantiate_vars(self):
+ Ts = TypeVarTuple('Ts')
+ with self.assertRaises(TypeError):
+ Ts()
+
+ def test_tuple(self):
+ Ts = TypeVarTuple('Ts')
+ # Not legal at type checking time but we can't really check against it.
+ Tuple[Ts]
+
+ def test_args_and_parameters(self):
+ Ts = TypeVarTuple('Ts')
+
+ t = Tuple[tuple(Ts)]
+ self.assertEqual(t.__args__, (Ts.__unpacked__,))
+ self.assertEqual(t.__parameters__, (Ts,))
+
+
+class FinalDecoratorTests(BaseTestCase):
+ def test_final_unmodified(self):
+ def func(x): ...
+ self.assertIs(func, final(func))
+
+ def test_dunder_final(self):
+ @final
+ def func(): ...
+ @final
+ class Cls: ...
+ self.assertIs(True, func.__final__)
+ self.assertIs(True, Cls.__final__)
+
+ class Wrapper:
+ __slots__ = ("func",)
+ def __init__(self, func):
+ self.func = func
+ def __call__(self, *args, **kwargs):
+ return self.func(*args, **kwargs)
+
+ # Check that no error is thrown if the attribute
+ # is not writable.
+ @final
+ @Wrapper
+ def wrapped(): ...
+ self.assertIsInstance(wrapped, Wrapper)
+ self.assertIs(False, hasattr(wrapped, "__final__"))
+
+ class Meta(type):
+ @property
+ def __final__(self): return "can't set me"
+ @final
+ class WithMeta(metaclass=Meta): ...
+ self.assertEqual(WithMeta.__final__, "can't set me")
+
+ # Builtin classes throw TypeError if you try to set an
+ # attribute.
+ final(int)
+ self.assertIs(False, hasattr(int, "__final__"))
+
+ # Make sure it works with common builtin decorators
+ class Methods:
+ @final
+ @classmethod
+ def clsmethod(cls): ...
+
+ @final
+ @staticmethod
+ def stmethod(): ...
+
+ # The other order doesn't work because property objects
+ # don't allow attribute assignment.
+ @property
+ @final
+ def prop(self): ...
+
+ @final
+ @lru_cache() # noqa: B019
+ def cached(self): ...
+
+ # Use getattr_static because the descriptor returns the
+ # underlying function, which doesn't have __final__.
+ self.assertIs(
+ True,
+ inspect.getattr_static(Methods, "clsmethod").__final__
+ )
+ self.assertIs(
+ True,
+ inspect.getattr_static(Methods, "stmethod").__final__
+ )
+ self.assertIs(True, Methods.prop.fget.__final__)
+ self.assertIs(True, Methods.cached.__final__)
+
+
+class RevealTypeTests(BaseTestCase):
+ def test_reveal_type(self):
+ obj = object()
+ self.assertIs(obj, reveal_type(obj))
+
+
+class DataclassTransformTests(BaseTestCase):
+ def test_decorator(self):
+ def create_model(*, frozen: bool = False, kw_only: bool = True):
+ return lambda cls: cls
+
+ decorated = dataclass_transform(kw_only_default=True, order_default=False)(create_model)
+
+ class CustomerModel:
+ id: int
+
+ self.assertIs(decorated, create_model)
+ self.assertEqual(
+ decorated.__dataclass_transform__,
+ {
+ "eq_default": True,
+ "order_default": False,
+ "kw_only_default": True,
+ "field_descriptors": (),
+ }
+ )
+ self.assertIs(
+ decorated(frozen=True, kw_only=False)(CustomerModel),
+ CustomerModel
+ )
+
+ def test_base_class(self):
+ class ModelBase:
+ def __init_subclass__(cls, *, frozen: bool = False): ...
+
+ Decorated = dataclass_transform(eq_default=True, order_default=True)(ModelBase)
+
+ class CustomerModel(Decorated, frozen=True):
+ id: int
+
+ self.assertIs(Decorated, ModelBase)
+ self.assertEqual(
+ Decorated.__dataclass_transform__,
+ {
+ "eq_default": True,
+ "order_default": True,
+ "kw_only_default": False,
+ "field_descriptors": (),
+ }
+ )
+ self.assertIsSubclass(CustomerModel, Decorated)
+
+ def test_metaclass(self):
+ class Field: ...
+
+ class ModelMeta(type):
+ def __new__(
+ cls, name, bases, namespace, *, init: bool = True,
+ ):
+ return super().__new__(cls, name, bases, namespace)
+
+ Decorated = dataclass_transform(
+ order_default=True, field_descriptors=(Field,)
+ )(ModelMeta)
+
+ class ModelBase(metaclass=Decorated): ...
+
+ class CustomerModel(ModelBase, init=False):
+ id: int
+
+ self.assertIs(Decorated, ModelMeta)
+ self.assertEqual(
+ Decorated.__dataclass_transform__,
+ {
+ "eq_default": True,
+ "order_default": True,
+ "kw_only_default": False,
+ "field_descriptors": (Field,),
+ }
+ )
+ self.assertIsInstance(CustomerModel, Decorated)
+
+
+class AllTests(BaseTestCase):
+
+ def test_typing_extensions_includes_standard(self):
+ a = typing_extensions.__all__
+ self.assertIn('ClassVar', a)
+ self.assertIn('Type', a)
+ self.assertIn('ChainMap', a)
+ self.assertIn('ContextManager', a)
+ self.assertIn('Counter', a)
+ self.assertIn('DefaultDict', a)
+ self.assertIn('Deque', a)
+ self.assertIn('NewType', a)
+ self.assertIn('overload', a)
+ self.assertIn('Text', a)
+ self.assertIn('TYPE_CHECKING', a)
+ self.assertIn('TypeAlias', a)
+ self.assertIn('ParamSpec', a)
+ self.assertIn("Concatenate", a)
+
+ self.assertIn('Annotated', a)
+ self.assertIn('get_type_hints', a)
+
+ self.assertIn('Awaitable', a)
+ self.assertIn('AsyncIterator', a)
+ self.assertIn('AsyncIterable', a)
+ self.assertIn('Coroutine', a)
+ self.assertIn('AsyncContextManager', a)
+
+ self.assertIn('AsyncGenerator', a)
+
+ self.assertIn('Protocol', a)
+ self.assertIn('runtime', a)
+
+ # Check that all objects in `__all__` are present in the module
+ for name in a:
+ self.assertTrue(hasattr(typing_extensions, name))
+
+ def test_typing_extensions_defers_when_possible(self):
+ exclude = {
+ 'overload',
+ 'Text',
+ 'TypedDict',
+ 'TYPE_CHECKING',
+ 'Final',
+ 'get_type_hints',
+ 'is_typeddict',
+ }
+ if sys.version_info < (3, 10):
+ exclude |= {'get_args', 'get_origin'}
+ if sys.version_info < (3, 11):
+ exclude.add('final')
+ for item in typing_extensions.__all__:
+ if item not in exclude and hasattr(typing, item):
+ self.assertIs(
+ getattr(typing_extensions, item),
+ getattr(typing, item))
+
+ def test_typing_extensions_compiles_with_opt(self):
+ file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
+ 'typing_extensions.py')
+ try:
+ subprocess.check_output(f'{sys.executable} -OO {file_path}',
+ stderr=subprocess.STDOUT,
+ shell=True)
+ except subprocess.CalledProcessError:
+ self.fail('Module does not compile with optimize=2 (-OO flag).')
+
+
+
+if __name__ == '__main__':
+ main()
diff --git a/typing_extensions/src/typing_extensions.py b/typing_extensions/src/typing_extensions.py
new file mode 100644
index 0000000..5698a76
--- /dev/null
+++ b/typing_extensions/src/typing_extensions.py
@@ -0,0 +1,1882 @@
+import abc
+import collections
+import collections.abc
+import operator
+import sys
+import types as _types
+import typing
+
+
+# Please keep __all__ alphabetized within each category.
+__all__ = [
+ # Super-special typing primitives.
+ 'ClassVar',
+ 'Concatenate',
+ 'Final',
+ 'LiteralString',
+ 'ParamSpec',
+ 'Self',
+ 'Type',
+ 'TypeVarTuple',
+ 'Unpack',
+
+ # ABCs (from collections.abc).
+ 'Awaitable',
+ 'AsyncIterator',
+ 'AsyncIterable',
+ 'Coroutine',
+ 'AsyncGenerator',
+ 'AsyncContextManager',
+ 'ChainMap',
+
+ # Concrete collection types.
+ 'ContextManager',
+ 'Counter',
+ 'Deque',
+ 'DefaultDict',
+ 'OrderedDict',
+ 'TypedDict',
+
+ # Structural checks, a.k.a. protocols.
+ 'SupportsIndex',
+
+ # One-off things.
+ 'Annotated',
+ 'assert_never',
+ 'dataclass_transform',
+ 'final',
+ 'get_args',
+ 'get_origin',
+ 'get_type_hints',
+ 'IntVar',
+ 'is_typeddict',
+ 'Literal',
+ 'NewType',
+ 'overload',
+ 'Protocol',
+ 'reveal_type',
+ 'runtime',
+ 'runtime_checkable',
+ 'Text',
+ 'TypeAlias',
+ 'TypeGuard',
+ 'TYPE_CHECKING',
+ 'Never',
+ 'NoReturn',
+ 'Required',
+ 'NotRequired',
+]
+
+# for backward compatibility
+PEP_560 = True
+GenericMeta = type
+
+# The functions below are modified copies of typing internal helpers.
+# They are needed by _ProtocolMeta and they provide support for PEP 646.
+
+_marker = object()
+
+
+def _check_generic(cls, parameters, elen=_marker):
+ """Check correct count for parameters of a generic cls (internal helper).
+ This gives a nice error message in case of count mismatch.
+ """
+ if not elen:
+ raise TypeError(f"{cls} is not a generic class")
+ if elen is _marker:
+ if not hasattr(cls, "__parameters__") or not cls.__parameters__:
+ raise TypeError(f"{cls} is not a generic class")
+ elen = len(cls.__parameters__)
+ alen = len(parameters)
+ if alen != elen:
+ if hasattr(cls, "__parameters__"):
+ parameters = [p for p in cls.__parameters__ if not _is_unpack(p)]
+ num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters)
+ if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples):
+ return
+ raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};"
+ f" actual {alen}, expected {elen}")
+
+
+if sys.version_info >= (3, 10):
+ def _should_collect_from_parameters(t):
+ return isinstance(
+ t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType)
+ )
+elif sys.version_info >= (3, 9):
+ def _should_collect_from_parameters(t):
+ return isinstance(t, (typing._GenericAlias, _types.GenericAlias))
+else:
+ def _should_collect_from_parameters(t):
+ return isinstance(t, typing._GenericAlias) and not t._special
+
+
+def _collect_type_vars(types, typevar_types=None):
+ """Collect all type variable contained in types in order of
+ first appearance (lexicographic order). For example::
+
+ _collect_type_vars((T, List[S, T])) == (T, S)
+ """
+ if typevar_types is None:
+ typevar_types = typing.TypeVar
+ tvars = []
+ for t in types:
+ if (
+ isinstance(t, typevar_types) and
+ t not in tvars and
+ not _is_unpack(t)
+ ):
+ tvars.append(t)
+ if _should_collect_from_parameters(t):
+ tvars.extend([t for t in t.__parameters__ if t not in tvars])
+ return tuple(tvars)
+
+
+NoReturn = typing.NoReturn
+
+# Some unconstrained type variables. These are used by the container types.
+# (These are not for export.)
+T = typing.TypeVar('T') # Any type.
+KT = typing.TypeVar('KT') # Key type.
+VT = typing.TypeVar('VT') # Value type.
+T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers.
+T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant.
+
+ClassVar = typing.ClassVar
+
+# On older versions of typing there is an internal class named "Final".
+# 3.8+
+if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7):
+ Final = typing.Final
+# 3.7
+else:
+ class _FinalForm(typing._SpecialForm, _root=True):
+
+ def __repr__(self):
+ return 'typing_extensions.' + self._name
+
+ def __getitem__(self, parameters):
+ item = typing._type_check(parameters,
+ f'{self._name} accepts only single type')
+ return typing._GenericAlias(self, (item,))
+
+ Final = _FinalForm('Final',
+ doc="""A special typing construct to indicate that a name
+ cannot be re-assigned or overridden in a subclass.
+ For example:
+
+ MAX_SIZE: Final = 9000
+ MAX_SIZE += 1 # Error reported by type checker
+
+ class Connection:
+ TIMEOUT: Final[int] = 10
+ class FastConnector(Connection):
+ TIMEOUT = 1 # Error reported by type checker
+
+ There is no runtime checking of these properties.""")
+
+if sys.version_info >= (3, 11):
+ final = typing.final
+else:
+ # @final exists in 3.8+, but we backport it for all versions
+ # before 3.11 to keep support for the __final__ attribute.
+ # See https://bugs.python.org/issue46342
+ def final(f):
+ """This decorator can be used to indicate to type checkers that
+ the decorated method cannot be overridden, and decorated class
+ cannot be subclassed. For example:
+
+ class Base:
+ @final
+ def done(self) -> None:
+ ...
+ class Sub(Base):
+ def done(self) -> None: # Error reported by type checker
+ ...
+ @final
+ class Leaf:
+ ...
+ class Other(Leaf): # Error reported by type checker
+ ...
+
+ There is no runtime checking of these properties. The decorator
+ sets the ``__final__`` attribute to ``True`` on the decorated object
+ to allow runtime introspection.
+ """
+ try:
+ f.__final__ = True
+ except (AttributeError, TypeError):
+ # Skip the attribute silently if it is not writable.
+ # AttributeError happens if the object has __slots__ or a
+ # read-only property, TypeError if it's a builtin class.
+ pass
+ return f
+
+
+def IntVar(name):
+ return typing.TypeVar(name)
+
+
+# 3.8+:
+if hasattr(typing, 'Literal'):
+ Literal = typing.Literal
+# 3.7:
+else:
+ class _LiteralForm(typing._SpecialForm, _root=True):
+
+ def __repr__(self):
+ return 'typing_extensions.' + self._name
+
+ def __getitem__(self, parameters):
+ return typing._GenericAlias(self, parameters)
+
+ Literal = _LiteralForm('Literal',
+ doc="""A type that can be used to indicate to type checkers
+ that the corresponding value has a value literally equivalent
+ to the provided parameter. For example:
+
+ var: Literal[4] = 4
+
+ The type checker understands that 'var' is literally equal to
+ the value 4 and no other value.
+
+ Literal[...] cannot be subclassed. There is no runtime
+ checking verifying that the parameter is actually a value
+ instead of a type.""")
+
+
+_overload_dummy = typing._overload_dummy # noqa
+overload = typing.overload
+
+
+# This is not a real generic class. Don't use outside annotations.
+Type = typing.Type
+
+# Various ABCs mimicking those in collections.abc.
+# A few are simply re-exported for completeness.
+
+
+Awaitable = typing.Awaitable
+Coroutine = typing.Coroutine
+AsyncIterable = typing.AsyncIterable
+AsyncIterator = typing.AsyncIterator
+Deque = typing.Deque
+ContextManager = typing.ContextManager
+AsyncContextManager = typing.AsyncContextManager
+DefaultDict = typing.DefaultDict
+
+# 3.7.2+
+if hasattr(typing, 'OrderedDict'):
+ OrderedDict = typing.OrderedDict
+# 3.7.0-3.7.2
+else:
+ OrderedDict = typing._alias(collections.OrderedDict, (KT, VT))
+
+Counter = typing.Counter
+ChainMap = typing.ChainMap
+AsyncGenerator = typing.AsyncGenerator
+NewType = typing.NewType
+Text = typing.Text
+TYPE_CHECKING = typing.TYPE_CHECKING
+
+
+_PROTO_WHITELIST = ['Callable', 'Awaitable',
+ 'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator',
+ 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible',
+ 'ContextManager', 'AsyncContextManager']
+
+
+def _get_protocol_attrs(cls):
+ attrs = set()
+ for base in cls.__mro__[:-1]: # without object
+ if base.__name__ in ('Protocol', 'Generic'):
+ continue
+ annotations = getattr(base, '__annotations__', {})
+ for attr in list(base.__dict__.keys()) + list(annotations.keys()):
+ if (not attr.startswith('_abc_') and attr not in (
+ '__abstractmethods__', '__annotations__', '__weakref__',
+ '_is_protocol', '_is_runtime_protocol', '__dict__',
+ '__args__', '__slots__',
+ '__next_in_mro__', '__parameters__', '__origin__',
+ '__orig_bases__', '__extra__', '__tree_hash__',
+ '__doc__', '__subclasshook__', '__init__', '__new__',
+ '__module__', '_MutableMapping__marker', '_gorg')):
+ attrs.add(attr)
+ return attrs
+
+
+def _is_callable_members_only(cls):
+ return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls))
+
+
+# 3.8+
+if hasattr(typing, 'Protocol'):
+ Protocol = typing.Protocol
+# 3.7
+else:
+
+ def _no_init(self, *args, **kwargs):
+ if type(self)._is_protocol:
+ raise TypeError('Protocols cannot be instantiated')
+
+ class _ProtocolMeta(abc.ABCMeta):
+ # This metaclass is a bit unfortunate and exists only because of the lack
+ # of __instancehook__.
+ def __instancecheck__(cls, instance):
+ # We need this method for situations where attributes are
+ # assigned in __init__.
+ if ((not getattr(cls, '_is_protocol', False) or
+ _is_callable_members_only(cls)) and
+ issubclass(instance.__class__, cls)):
+ return True
+ if cls._is_protocol:
+ if all(hasattr(instance, attr) and
+ (not callable(getattr(cls, attr, None)) or
+ getattr(instance, attr) is not None)
+ for attr in _get_protocol_attrs(cls)):
+ return True
+ return super().__instancecheck__(instance)
+
+ class Protocol(metaclass=_ProtocolMeta):
+ # There is quite a lot of overlapping code with typing.Generic.
+ # Unfortunately it is hard to avoid this while these live in two different
+ # modules. The duplicated code will be removed when Protocol is moved to typing.
+ """Base class for protocol classes. Protocol classes are defined as::
+
+ class Proto(Protocol):
+ def meth(self) -> int:
+ ...
+
+ Such classes are primarily used with static type checkers that recognize
+ structural subtyping (static duck-typing), for example::
+
+ class C:
+ def meth(self) -> int:
+ return 0
+
+ def func(x: Proto) -> int:
+ return x.meth()
+
+ func(C()) # Passes static type check
+
+ See PEP 544 for details. Protocol classes decorated with
+ @typing_extensions.runtime act as simple-minded runtime protocol that checks
+ only the presence of given attributes, ignoring their type signatures.
+
+ Protocol classes can be generic, they are defined as::
+
+ class GenProto(Protocol[T]):
+ def meth(self) -> T:
+ ...
+ """
+ __slots__ = ()
+ _is_protocol = True
+
+ def __new__(cls, *args, **kwds):
+ if cls is Protocol:
+ raise TypeError("Type Protocol cannot be instantiated; "
+ "it can only be used as a base class")
+ return super().__new__(cls)
+
+ @typing._tp_cache
+ def __class_getitem__(cls, params):
+ if not isinstance(params, tuple):
+ params = (params,)
+ if not params and cls is not typing.Tuple:
+ raise TypeError(
+ f"Parameter list to {cls.__qualname__}[...] cannot be empty")
+ msg = "Parameters to generic types must be types."
+ params = tuple(typing._type_check(p, msg) for p in params) # noqa
+ if cls is Protocol:
+ # Generic can only be subscripted with unique type variables.
+ if not all(isinstance(p, typing.TypeVar) for p in params):
+ i = 0
+ while isinstance(params[i], typing.TypeVar):
+ i += 1
+ raise TypeError(
+ "Parameters to Protocol[...] must all be type variables."
+ f" Parameter {i + 1} is {params[i]}")
+ if len(set(params)) != len(params):
+ raise TypeError(
+ "Parameters to Protocol[...] must all be unique")
+ else:
+ # Subscripting a regular Generic subclass.
+ _check_generic(cls, params, len(cls.__parameters__))
+ return typing._GenericAlias(cls, params)
+
+ def __init_subclass__(cls, *args, **kwargs):
+ tvars = []
+ if '__orig_bases__' in cls.__dict__:
+ error = typing.Generic in cls.__orig_bases__
+ else:
+ error = typing.Generic in cls.__bases__
+ if error:
+ raise TypeError("Cannot inherit from plain Generic")
+ if '__orig_bases__' in cls.__dict__:
+ tvars = typing._collect_type_vars(cls.__orig_bases__)
+ # Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn].
+ # If found, tvars must be a subset of it.
+ # If not found, tvars is it.
+ # Also check for and reject plain Generic,
+ # and reject multiple Generic[...] and/or Protocol[...].
+ gvars = None
+ for base in cls.__orig_bases__:
+ if (isinstance(base, typing._GenericAlias) and
+ base.__origin__ in (typing.Generic, Protocol)):
+ # for error messages
+ the_base = base.__origin__.__name__
+ if gvars is not None:
+ raise TypeError(
+ "Cannot inherit from Generic[...]"
+ " and/or Protocol[...] multiple types.")
+ gvars = base.__parameters__
+ if gvars is None:
+ gvars = tvars
+ else:
+ tvarset = set(tvars)
+ gvarset = set(gvars)
+ if not tvarset <= gvarset:
+ s_vars = ', '.join(str(t) for t in tvars if t not in gvarset)
+ s_args = ', '.join(str(g) for g in gvars)
+ raise TypeError(f"Some type variables ({s_vars}) are"
+ f" not listed in {the_base}[{s_args}]")
+ tvars = gvars
+ cls.__parameters__ = tuple(tvars)
+
+ # Determine if this is a protocol or a concrete subclass.
+ if not cls.__dict__.get('_is_protocol', None):
+ cls._is_protocol = any(b is Protocol for b in cls.__bases__)
+
+ # Set (or override) the protocol subclass hook.
+ def _proto_hook(other):
+ if not cls.__dict__.get('_is_protocol', None):
+ return NotImplemented
+ if not getattr(cls, '_is_runtime_protocol', False):
+ if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']:
+ return NotImplemented
+ raise TypeError("Instance and class checks can only be used with"
+ " @runtime protocols")
+ if not _is_callable_members_only(cls):
+ if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']:
+ return NotImplemented
+ raise TypeError("Protocols with non-method members"
+ " don't support issubclass()")
+ if not isinstance(other, type):
+ # Same error as for issubclass(1, int)
+ raise TypeError('issubclass() arg 1 must be a class')
+ for attr in _get_protocol_attrs(cls):
+ for base in other.__mro__:
+ if attr in base.__dict__:
+ if base.__dict__[attr] is None:
+ return NotImplemented
+ break
+ annotations = getattr(base, '__annotations__', {})
+ if (isinstance(annotations, typing.Mapping) and
+ attr in annotations and
+ isinstance(other, _ProtocolMeta) and
+ other._is_protocol):
+ break
+ else:
+ return NotImplemented
+ return True
+ if '__subclasshook__' not in cls.__dict__:
+ cls.__subclasshook__ = _proto_hook
+
+ # We have nothing more to do for non-protocols.
+ if not cls._is_protocol:
+ return
+
+ # Check consistency of bases.
+ for base in cls.__bases__:
+ if not (base in (object, typing.Generic) or
+ base.__module__ == 'collections.abc' and
+ base.__name__ in _PROTO_WHITELIST or
+ isinstance(base, _ProtocolMeta) and base._is_protocol):
+ raise TypeError('Protocols can only inherit from other'
+ f' protocols, got {repr(base)}')
+ cls.__init__ = _no_init
+
+
+# 3.8+
+if hasattr(typing, 'runtime_checkable'):
+ runtime_checkable = typing.runtime_checkable
+# 3.7
+else:
+ def runtime_checkable(cls):
+ """Mark a protocol class as a runtime protocol, so that it
+ can be used with isinstance() and issubclass(). Raise TypeError
+ if applied to a non-protocol class.
+
+ This allows a simple-minded structural check very similar to the
+ one-offs in collections.abc such as Hashable.
+ """
+ if not isinstance(cls, _ProtocolMeta) or not cls._is_protocol:
+ raise TypeError('@runtime_checkable can be only applied to protocol classes,'
+ f' got {cls!r}')
+ cls._is_runtime_protocol = True
+ return cls
+
+
+# Exists for backwards compatibility.
+runtime = runtime_checkable
+
+
+# 3.8+
+if hasattr(typing, 'SupportsIndex'):
+ SupportsIndex = typing.SupportsIndex
+# 3.7
+else:
+ @runtime_checkable
+ class SupportsIndex(Protocol):
+ __slots__ = ()
+
+ @abc.abstractmethod
+ def __index__(self) -> int:
+ pass
+
+
+if hasattr(typing, "Required"):
+ # The standard library TypedDict in Python 3.8 does not store runtime information
+ # about which (if any) keys are optional. See https://bugs.python.org/issue38834
+ # The standard library TypedDict in Python 3.9.0/1 does not honour the "total"
+ # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059
+ # The standard library TypedDict below Python 3.11 does not store runtime
+ # information about optional and required keys when using Required or NotRequired.
+ TypedDict = typing.TypedDict
+ _TypedDictMeta = typing._TypedDictMeta
+ is_typeddict = typing.is_typeddict
+else:
+ def _check_fails(cls, other):
+ try:
+ if sys._getframe(1).f_globals['__name__'] not in ['abc',
+ 'functools',
+ 'typing']:
+ # Typed dicts are only for static structural subtyping.
+ raise TypeError('TypedDict does not support instance and class checks')
+ except (AttributeError, ValueError):
+ pass
+ return False
+
+ def _dict_new(*args, **kwargs):
+ if not args:
+ raise TypeError('TypedDict.__new__(): not enough arguments')
+ _, args = args[0], args[1:] # allow the "cls" keyword be passed
+ return dict(*args, **kwargs)
+
+ _dict_new.__text_signature__ = '($cls, _typename, _fields=None, /, **kwargs)'
+
+ def _typeddict_new(*args, total=True, **kwargs):
+ if not args:
+ raise TypeError('TypedDict.__new__(): not enough arguments')
+ _, args = args[0], args[1:] # allow the "cls" keyword be passed
+ if args:
+ typename, args = args[0], args[1:] # allow the "_typename" keyword be passed
+ elif '_typename' in kwargs:
+ typename = kwargs.pop('_typename')
+ import warnings
+ warnings.warn("Passing '_typename' as keyword argument is deprecated",
+ DeprecationWarning, stacklevel=2)
+ else:
+ raise TypeError("TypedDict.__new__() missing 1 required positional "
+ "argument: '_typename'")
+ if args:
+ try:
+ fields, = args # allow the "_fields" keyword be passed
+ except ValueError:
+ raise TypeError('TypedDict.__new__() takes from 2 to 3 '
+ f'positional arguments but {len(args) + 2} '
+ 'were given')
+ elif '_fields' in kwargs and len(kwargs) == 1:
+ fields = kwargs.pop('_fields')
+ import warnings
+ warnings.warn("Passing '_fields' as keyword argument is deprecated",
+ DeprecationWarning, stacklevel=2)
+ else:
+ fields = None
+
+ if fields is None:
+ fields = kwargs
+ elif kwargs:
+ raise TypeError("TypedDict takes either a dict or keyword arguments,"
+ " but not both")
+
+ ns = {'__annotations__': dict(fields)}
+ try:
+ # Setting correct module is necessary to make typed dict classes pickleable.
+ ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__')
+ except (AttributeError, ValueError):
+ pass
+
+ return _TypedDictMeta(typename, (), ns, total=total)
+
+ _typeddict_new.__text_signature__ = ('($cls, _typename, _fields=None,'
+ ' /, *, total=True, **kwargs)')
+
+ class _TypedDictMeta(type):
+ def __init__(cls, name, bases, ns, total=True):
+ super().__init__(name, bases, ns)
+
+ def __new__(cls, name, bases, ns, total=True):
+ # Create new typed dict class object.
+ # This method is called directly when TypedDict is subclassed,
+ # or via _typeddict_new when TypedDict is instantiated. This way
+ # TypedDict supports all three syntaxes described in its docstring.
+ # Subclasses and instances of TypedDict return actual dictionaries
+ # via _dict_new.
+ ns['__new__'] = _typeddict_new if name == 'TypedDict' else _dict_new
+ tp_dict = super().__new__(cls, name, (dict,), ns)
+
+ annotations = {}
+ own_annotations = ns.get('__annotations__', {})
+ msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
+ own_annotations = {
+ n: typing._type_check(tp, msg) for n, tp in own_annotations.items()
+ }
+ required_keys = set()
+ optional_keys = set()
+
+ for base in bases:
+ annotations.update(base.__dict__.get('__annotations__', {}))
+ required_keys.update(base.__dict__.get('__required_keys__', ()))
+ optional_keys.update(base.__dict__.get('__optional_keys__', ()))
+
+ annotations.update(own_annotations)
+ for annotation_key, annotation_type in own_annotations.items():
+ annotation_origin = get_origin(annotation_type)
+ if annotation_origin is Annotated:
+ annotation_args = get_args(annotation_type)
+ if annotation_args:
+ annotation_type = annotation_args[0]
+ annotation_origin = get_origin(annotation_type)
+
+ if annotation_origin is Required:
+ required_keys.add(annotation_key)
+ elif annotation_origin is NotRequired:
+ optional_keys.add(annotation_key)
+ elif total:
+ required_keys.add(annotation_key)
+ else:
+ optional_keys.add(annotation_key)
+
+ tp_dict.__annotations__ = annotations
+ tp_dict.__required_keys__ = frozenset(required_keys)
+ tp_dict.__optional_keys__ = frozenset(optional_keys)
+ if not hasattr(tp_dict, '__total__'):
+ tp_dict.__total__ = total
+ return tp_dict
+
+ __instancecheck__ = __subclasscheck__ = _check_fails
+
+ TypedDict = _TypedDictMeta('TypedDict', (dict,), {})
+ TypedDict.__module__ = __name__
+ TypedDict.__doc__ = \
+ """A simple typed name space. At runtime it is equivalent to a plain dict.
+
+ TypedDict creates a dictionary type that expects all of its
+ instances to have a certain set of keys, with each key
+ associated with a value of a consistent type. This expectation
+ is not checked at runtime but is only enforced by type checkers.
+ Usage::
+
+ class Point2D(TypedDict):
+ x: int
+ y: int
+ label: str
+
+ a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK
+ b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check
+
+ assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')
+
+ The type info can be accessed via the Point2D.__annotations__ dict, and
+ the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets.
+ TypedDict supports two additional equivalent forms::
+
+ Point2D = TypedDict('Point2D', x=int, y=int, label=str)
+ Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
+
+ The class syntax is only supported in Python 3.6+, while two other
+ syntax forms work for Python 2.7 and 3.2+
+ """
+
+ if hasattr(typing, "_TypedDictMeta"):
+ _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta)
+ else:
+ _TYPEDDICT_TYPES = (_TypedDictMeta,)
+
+ def is_typeddict(tp):
+ """Check if an annotation is a TypedDict class
+
+ For example::
+ class Film(TypedDict):
+ title: str
+ year: int
+
+ is_typeddict(Film) # => True
+ is_typeddict(Union[list, str]) # => False
+ """
+ return isinstance(tp, tuple(_TYPEDDICT_TYPES))
+
+
+if hasattr(typing, "assert_type"):
+ assert_type = typing.assert_type
+
+else:
+ def assert_type(__val, __typ):
+ """Assert (to the type checker) that the value is of the given type.
+
+ When the type checker encounters a call to assert_type(), it
+ emits an error if the value is not of the specified type::
+
+ def greet(name: str) -> None:
+ assert_type(name, str) # ok
+ assert_type(name, int) # type checker error
+
+ At runtime this returns the first argument unchanged and otherwise
+ does nothing.
+ """
+ return __val
+
+
+if hasattr(typing, "Required"):
+ get_type_hints = typing.get_type_hints
+else:
+ import functools
+ import types
+
+ # replaces _strip_annotations()
+ def _strip_extras(t):
+ """Strips Annotated, Required and NotRequired from a given type."""
+ if isinstance(t, _AnnotatedAlias):
+ return _strip_extras(t.__origin__)
+ if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired):
+ return _strip_extras(t.__args__[0])
+ if isinstance(t, typing._GenericAlias):
+ stripped_args = tuple(_strip_extras(a) for a in t.__args__)
+ if stripped_args == t.__args__:
+ return t
+ return t.copy_with(stripped_args)
+ if hasattr(types, "GenericAlias") and isinstance(t, types.GenericAlias):
+ stripped_args = tuple(_strip_extras(a) for a in t.__args__)
+ if stripped_args == t.__args__:
+ return t
+ return types.GenericAlias(t.__origin__, stripped_args)
+ if hasattr(types, "UnionType") and isinstance(t, types.UnionType):
+ stripped_args = tuple(_strip_extras(a) for a in t.__args__)
+ if stripped_args == t.__args__:
+ return t
+ return functools.reduce(operator.or_, stripped_args)
+
+ return t
+
+ def get_type_hints(obj, globalns=None, localns=None, include_extras=False):
+ """Return type hints for an object.
+
+ This is often the same as obj.__annotations__, but it handles
+ forward references encoded as string literals, adds Optional[t] if a
+ default value equal to None is set and recursively replaces all
+ 'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T'
+ (unless 'include_extras=True').
+
+ The argument may be a module, class, method, or function. The annotations
+ are returned as a dictionary. For classes, annotations include also
+ inherited members.
+
+ TypeError is raised if the argument is not of a type that can contain
+ annotations, and an empty dictionary is returned if no annotations are
+ present.
+
+ BEWARE -- the behavior of globalns and localns is counterintuitive
+ (unless you are familiar with how eval() and exec() work). The
+ search order is locals first, then globals.
+
+ - If no dict arguments are passed, an attempt is made to use the
+ globals from obj (or the respective module's globals for classes),
+ and these are also used as the locals. If the object does not appear
+ to have globals, an empty dictionary is used.
+
+ - If one dict argument is passed, it is used for both globals and
+ locals.
+
+ - If two dict arguments are passed, they specify globals and
+ locals, respectively.
+ """
+ if hasattr(typing, "Annotated"):
+ hint = typing.get_type_hints(
+ obj, globalns=globalns, localns=localns, include_extras=True
+ )
+ else:
+ hint = typing.get_type_hints(obj, globalns=globalns, localns=localns)
+ if include_extras:
+ return hint
+ return {k: _strip_extras(t) for k, t in hint.items()}
+
+
+# Python 3.9+ has PEP 593 (Annotated)
+if hasattr(typing, 'Annotated'):
+ Annotated = typing.Annotated
+ # Not exported and not a public API, but needed for get_origin() and get_args()
+ # to work.
+ _AnnotatedAlias = typing._AnnotatedAlias
+# 3.7-3.8
+else:
+ class _AnnotatedAlias(typing._GenericAlias, _root=True):
+ """Runtime representation of an annotated type.
+
+ At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't'
+ with extra annotations. The alias behaves like a normal typing alias,
+ instantiating is the same as instantiating the underlying type, binding
+ it to types is also the same.
+ """
+ def __init__(self, origin, metadata):
+ if isinstance(origin, _AnnotatedAlias):
+ metadata = origin.__metadata__ + metadata
+ origin = origin.__origin__
+ super().__init__(origin, origin)
+ self.__metadata__ = metadata
+
+ def copy_with(self, params):
+ assert len(params) == 1
+ new_type = params[0]
+ return _AnnotatedAlias(new_type, self.__metadata__)
+
+ def __repr__(self):
+ return (f"typing_extensions.Annotated[{typing._type_repr(self.__origin__)}, "
+ f"{', '.join(repr(a) for a in self.__metadata__)}]")
+
+ def __reduce__(self):
+ return operator.getitem, (
+ Annotated, (self.__origin__,) + self.__metadata__
+ )
+
+ def __eq__(self, other):
+ if not isinstance(other, _AnnotatedAlias):
+ return NotImplemented
+ if self.__origin__ != other.__origin__:
+ return False
+ return self.__metadata__ == other.__metadata__
+
+ def __hash__(self):
+ return hash((self.__origin__, self.__metadata__))
+
+ class Annotated:
+ """Add context specific metadata to a type.
+
+ Example: Annotated[int, runtime_check.Unsigned] indicates to the
+ hypothetical runtime_check module that this type is an unsigned int.
+ Every other consumer of this type can ignore this metadata and treat
+ this type as int.
+
+ The first argument to Annotated must be a valid type (and will be in
+ the __origin__ field), the remaining arguments are kept as a tuple in
+ the __extra__ field.
+
+ Details:
+
+ - It's an error to call `Annotated` with less than two arguments.
+ - Nested Annotated are flattened::
+
+ Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3]
+
+ - Instantiating an annotated type is equivalent to instantiating the
+ underlying type::
+
+ Annotated[C, Ann1](5) == C(5)
+
+ - Annotated can be used as a generic type alias::
+
+ Optimized = Annotated[T, runtime.Optimize()]
+ Optimized[int] == Annotated[int, runtime.Optimize()]
+
+ OptimizedList = Annotated[List[T], runtime.Optimize()]
+ OptimizedList[int] == Annotated[List[int], runtime.Optimize()]
+ """
+
+ __slots__ = ()
+
+ def __new__(cls, *args, **kwargs):
+ raise TypeError("Type Annotated cannot be instantiated.")
+
+ @typing._tp_cache
+ def __class_getitem__(cls, params):
+ if not isinstance(params, tuple) or len(params) < 2:
+ raise TypeError("Annotated[...] should be used "
+ "with at least two arguments (a type and an "
+ "annotation).")
+ allowed_special_forms = (ClassVar, Final)
+ if get_origin(params[0]) in allowed_special_forms:
+ origin = params[0]
+ else:
+ msg = "Annotated[t, ...]: t must be a type."
+ origin = typing._type_check(params[0], msg)
+ metadata = tuple(params[1:])
+ return _AnnotatedAlias(origin, metadata)
+
+ def __init_subclass__(cls, *args, **kwargs):
+ raise TypeError(
+ f"Cannot subclass {cls.__module__}.Annotated"
+ )
+
+# Python 3.8 has get_origin() and get_args() but those implementations aren't
+# Annotated-aware, so we can't use those. Python 3.9's versions don't support
+# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do.
+if sys.version_info[:2] >= (3, 10):
+ get_origin = typing.get_origin
+ get_args = typing.get_args
+# 3.7-3.9
+else:
+ try:
+ # 3.9+
+ from typing import _BaseGenericAlias
+ except ImportError:
+ _BaseGenericAlias = typing._GenericAlias
+ try:
+ # 3.9+
+ from typing import GenericAlias
+ except ImportError:
+ GenericAlias = typing._GenericAlias
+
+ def get_origin(tp):
+ """Get the unsubscripted version of a type.
+
+ This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar
+ and Annotated. Return None for unsupported types. Examples::
+
+ get_origin(Literal[42]) is Literal
+ get_origin(int) is None
+ get_origin(ClassVar[int]) is ClassVar
+ get_origin(Generic) is Generic
+ get_origin(Generic[T]) is Generic
+ get_origin(Union[T, int]) is Union
+ get_origin(List[Tuple[T, T]][int]) == list
+ get_origin(P.args) is P
+ """
+ if isinstance(tp, _AnnotatedAlias):
+ return Annotated
+ if isinstance(tp, (typing._GenericAlias, GenericAlias, _BaseGenericAlias,
+ ParamSpecArgs, ParamSpecKwargs)):
+ return tp.__origin__
+ if tp is typing.Generic:
+ return typing.Generic
+ return None
+
+ def get_args(tp):
+ """Get type arguments with all substitutions performed.
+
+ For unions, basic simplifications used by Union constructor are performed.
+ Examples::
+ get_args(Dict[str, int]) == (str, int)
+ get_args(int) == ()
+ get_args(Union[int, Union[T, int], str][int]) == (int, str)
+ get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int])
+ get_args(Callable[[], T][int]) == ([], int)
+ """
+ if isinstance(tp, _AnnotatedAlias):
+ return (tp.__origin__,) + tp.__metadata__
+ if isinstance(tp, (typing._GenericAlias, GenericAlias)):
+ if getattr(tp, "_special", False):
+ return ()
+ res = tp.__args__
+ if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis:
+ res = (list(res[:-1]), res[-1])
+ return res
+ return ()
+
+
+# 3.10+
+if hasattr(typing, 'TypeAlias'):
+ TypeAlias = typing.TypeAlias
+# 3.9
+elif sys.version_info[:2] >= (3, 9):
+ class _TypeAliasForm(typing._SpecialForm, _root=True):
+ def __repr__(self):
+ return 'typing_extensions.' + self._name
+
+ @_TypeAliasForm
+ def TypeAlias(self, parameters):
+ """Special marker indicating that an assignment should
+ be recognized as a proper type alias definition by type
+ checkers.
+
+ For example::
+
+ Predicate: TypeAlias = Callable[..., bool]
+
+ It's invalid when used anywhere except as in the example above.
+ """
+ raise TypeError(f"{self} is not subscriptable")
+# 3.7-3.8
+else:
+ class _TypeAliasForm(typing._SpecialForm, _root=True):
+ def __repr__(self):
+ return 'typing_extensions.' + self._name
+
+ TypeAlias = _TypeAliasForm('TypeAlias',
+ doc="""Special marker indicating that an assignment should
+ be recognized as a proper type alias definition by type
+ checkers.
+
+ For example::
+
+ Predicate: TypeAlias = Callable[..., bool]
+
+ It's invalid when used anywhere except as in the example
+ above.""")
+
+
+# Python 3.10+ has PEP 612
+if hasattr(typing, 'ParamSpecArgs'):
+ ParamSpecArgs = typing.ParamSpecArgs
+ ParamSpecKwargs = typing.ParamSpecKwargs
+# 3.7-3.9
+else:
+ class _Immutable:
+ """Mixin to indicate that object should not be copied."""
+ __slots__ = ()
+
+ def __copy__(self):
+ return self
+
+ def __deepcopy__(self, memo):
+ return self
+
+ class ParamSpecArgs(_Immutable):
+ """The args for a ParamSpec object.
+
+ Given a ParamSpec object P, P.args is an instance of ParamSpecArgs.
+
+ ParamSpecArgs objects have a reference back to their ParamSpec:
+
+ P.args.__origin__ is P
+
+ This type is meant for runtime introspection and has no special meaning to
+ static type checkers.
+ """
+ def __init__(self, origin):
+ self.__origin__ = origin
+
+ def __repr__(self):
+ return f"{self.__origin__.__name__}.args"
+
+ def __eq__(self, other):
+ if not isinstance(other, ParamSpecArgs):
+ return NotImplemented
+ return self.__origin__ == other.__origin__
+
+ class ParamSpecKwargs(_Immutable):
+ """The kwargs for a ParamSpec object.
+
+ Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs.
+
+ ParamSpecKwargs objects have a reference back to their ParamSpec:
+
+ P.kwargs.__origin__ is P
+
+ This type is meant for runtime introspection and has no special meaning to
+ static type checkers.
+ """
+ def __init__(self, origin):
+ self.__origin__ = origin
+
+ def __repr__(self):
+ return f"{self.__origin__.__name__}.kwargs"
+
+ def __eq__(self, other):
+ if not isinstance(other, ParamSpecKwargs):
+ return NotImplemented
+ return self.__origin__ == other.__origin__
+
+# 3.10+
+if hasattr(typing, 'ParamSpec'):
+ ParamSpec = typing.ParamSpec
+# 3.7-3.9
+else:
+
+ # Inherits from list as a workaround for Callable checks in Python < 3.9.2.
+ class ParamSpec(list):
+ """Parameter specification variable.
+
+ Usage::
+
+ P = ParamSpec('P')
+
+ Parameter specification variables exist primarily for the benefit of static
+ type checkers. They are used to forward the parameter types of one
+ callable to another callable, a pattern commonly found in higher order
+ functions and decorators. They are only valid when used in ``Concatenate``,
+ or s the first argument to ``Callable``. In Python 3.10 and higher,
+ they are also supported in user-defined Generics at runtime.
+ See class Generic for more information on generic types. An
+ example for annotating a decorator::
+
+ T = TypeVar('T')
+ P = ParamSpec('P')
+
+ def add_logging(f: Callable[P, T]) -> Callable[P, T]:
+ '''A type-safe decorator to add logging to a function.'''
+ def inner(*args: P.args, **kwargs: P.kwargs) -> T:
+ logging.info(f'{f.__name__} was called')
+ return f(*args, **kwargs)
+ return inner
+
+ @add_logging
+ def add_two(x: float, y: float) -> float:
+ '''Add two numbers together.'''
+ return x + y
+
+ Parameter specification variables defined with covariant=True or
+ contravariant=True can be used to declare covariant or contravariant
+ generic types. These keyword arguments are valid, but their actual semantics
+ are yet to be decided. See PEP 612 for details.
+
+ Parameter specification variables can be introspected. e.g.:
+
+ P.__name__ == 'T'
+ P.__bound__ == None
+ P.__covariant__ == False
+ P.__contravariant__ == False
+
+ Note that only parameter specification variables defined in global scope can
+ be pickled.
+ """
+
+ # Trick Generic __parameters__.
+ __class__ = typing.TypeVar
+
+ @property
+ def args(self):
+ return ParamSpecArgs(self)
+
+ @property
+ def kwargs(self):
+ return ParamSpecKwargs(self)
+
+ def __init__(self, name, *, bound=None, covariant=False, contravariant=False):
+ super().__init__([self])
+ self.__name__ = name
+ self.__covariant__ = bool(covariant)
+ self.__contravariant__ = bool(contravariant)
+ if bound:
+ self.__bound__ = typing._type_check(bound, 'Bound must be a type.')
+ else:
+ self.__bound__ = None
+
+ # for pickling:
+ try:
+ def_mod = sys._getframe(1).f_globals.get('__name__', '__main__')
+ except (AttributeError, ValueError):
+ def_mod = None
+ if def_mod != 'typing_extensions':
+ self.__module__ = def_mod
+
+ def __repr__(self):
+ if self.__covariant__:
+ prefix = '+'
+ elif self.__contravariant__:
+ prefix = '-'
+ else:
+ prefix = '~'
+ return prefix + self.__name__
+
+ def __hash__(self):
+ return object.__hash__(self)
+
+ def __eq__(self, other):
+ return self is other
+
+ def __reduce__(self):
+ return self.__name__
+
+ # Hack to get typing._type_check to pass.
+ def __call__(self, *args, **kwargs):
+ pass
+
+
+# 3.7-3.9
+if not hasattr(typing, 'Concatenate'):
+ # Inherits from list as a workaround for Callable checks in Python < 3.9.2.
+ class _ConcatenateGenericAlias(list):
+
+ # Trick Generic into looking into this for __parameters__.
+ __class__ = typing._GenericAlias
+
+ # Flag in 3.8.
+ _special = False
+
+ def __init__(self, origin, args):
+ super().__init__(args)
+ self.__origin__ = origin
+ self.__args__ = args
+
+ def __repr__(self):
+ _type_repr = typing._type_repr
+ return (f'{_type_repr(self.__origin__)}'
+ f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]')
+
+ def __hash__(self):
+ return hash((self.__origin__, self.__args__))
+
+ # Hack to get typing._type_check to pass in Generic.
+ def __call__(self, *args, **kwargs):
+ pass
+
+ @property
+ def __parameters__(self):
+ return tuple(
+ tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec))
+ )
+
+
+# 3.7-3.9
+@typing._tp_cache
+def _concatenate_getitem(self, parameters):
+ if parameters == ():
+ raise TypeError("Cannot take a Concatenate of no types.")
+ if not isinstance(parameters, tuple):
+ parameters = (parameters,)
+ if not isinstance(parameters[-1], ParamSpec):
+ raise TypeError("The last parameter to Concatenate should be a "
+ "ParamSpec variable.")
+ msg = "Concatenate[arg, ...]: each arg must be a type."
+ parameters = tuple(typing._type_check(p, msg) for p in parameters)
+ return _ConcatenateGenericAlias(self, parameters)
+
+
+# 3.10+
+if hasattr(typing, 'Concatenate'):
+ Concatenate = typing.Concatenate
+ _ConcatenateGenericAlias = typing._ConcatenateGenericAlias # noqa
+# 3.9
+elif sys.version_info[:2] >= (3, 9):
+ @_TypeAliasForm
+ def Concatenate(self, parameters):
+ """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a
+ higher order function which adds, removes or transforms parameters of a
+ callable.
+
+ For example::
+
+ Callable[Concatenate[int, P], int]
+
+ See PEP 612 for detailed information.
+ """
+ return _concatenate_getitem(self, parameters)
+# 3.7-8
+else:
+ class _ConcatenateForm(typing._SpecialForm, _root=True):
+ def __repr__(self):
+ return 'typing_extensions.' + self._name
+
+ def __getitem__(self, parameters):
+ return _concatenate_getitem(self, parameters)
+
+ Concatenate = _ConcatenateForm(
+ 'Concatenate',
+ doc="""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a
+ higher order function which adds, removes or transforms parameters of a
+ callable.
+
+ For example::
+
+ Callable[Concatenate[int, P], int]
+
+ See PEP 612 for detailed information.
+ """)
+
+# 3.10+
+if hasattr(typing, 'TypeGuard'):
+ TypeGuard = typing.TypeGuard
+# 3.9
+elif sys.version_info[:2] >= (3, 9):
+ class _TypeGuardForm(typing._SpecialForm, _root=True):
+ def __repr__(self):
+ return 'typing_extensions.' + self._name
+
+ @_TypeGuardForm
+ def TypeGuard(self, parameters):
+ """Special typing form used to annotate the return type of a user-defined
+ type guard function. ``TypeGuard`` only accepts a single type argument.
+ At runtime, functions marked this way should return a boolean.
+
+ ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static
+ type checkers to determine a more precise type of an expression within a
+ program's code flow. Usually type narrowing is done by analyzing
+ conditional code flow and applying the narrowing to a block of code. The
+ conditional expression here is sometimes referred to as a "type guard".
+
+ Sometimes it would be convenient to use a user-defined boolean function
+ as a type guard. Such a function should use ``TypeGuard[...]`` as its
+ return type to alert static type checkers to this intention.
+
+ Using ``-> TypeGuard`` tells the static type checker that for a given
+ function:
+
+ 1. The return value is a boolean.
+ 2. If the return value is ``True``, the type of its argument
+ is the type inside ``TypeGuard``.
+
+ For example::
+
+ def is_str(val: Union[str, float]):
+ # "isinstance" type guard
+ if isinstance(val, str):
+ # Type of ``val`` is narrowed to ``str``
+ ...
+ else:
+ # Else, type of ``val`` is narrowed to ``float``.
+ ...
+
+ Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower
+ form of ``TypeA`` (it can even be a wider form) and this may lead to
+ type-unsafe results. The main reason is to allow for things like
+ narrowing ``List[object]`` to ``List[str]`` even though the latter is not
+ a subtype of the former, since ``List`` is invariant. The responsibility of
+ writing type-safe type guards is left to the user.
+
+ ``TypeGuard`` also works with type variables. For more information, see
+ PEP 647 (User-Defined Type Guards).
+ """
+ item = typing._type_check(parameters, f'{self} accepts only single type.')
+ return typing._GenericAlias(self, (item,))
+# 3.7-3.8
+else:
+ class _TypeGuardForm(typing._SpecialForm, _root=True):
+
+ def __repr__(self):
+ return 'typing_extensions.' + self._name
+
+ def __getitem__(self, parameters):
+ item = typing._type_check(parameters,
+ f'{self._name} accepts only a single type')
+ return typing._GenericAlias(self, (item,))
+
+ TypeGuard = _TypeGuardForm(
+ 'TypeGuard',
+ doc="""Special typing form used to annotate the return type of a user-defined
+ type guard function. ``TypeGuard`` only accepts a single type argument.
+ At runtime, functions marked this way should return a boolean.
+
+ ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static
+ type checkers to determine a more precise type of an expression within a
+ program's code flow. Usually type narrowing is done by analyzing
+ conditional code flow and applying the narrowing to a block of code. The
+ conditional expression here is sometimes referred to as a "type guard".
+
+ Sometimes it would be convenient to use a user-defined boolean function
+ as a type guard. Such a function should use ``TypeGuard[...]`` as its
+ return type to alert static type checkers to this intention.
+
+ Using ``-> TypeGuard`` tells the static type checker that for a given
+ function:
+
+ 1. The return value is a boolean.
+ 2. If the return value is ``True``, the type of its argument
+ is the type inside ``TypeGuard``.
+
+ For example::
+
+ def is_str(val: Union[str, float]):
+ # "isinstance" type guard
+ if isinstance(val, str):
+ # Type of ``val`` is narrowed to ``str``
+ ...
+ else:
+ # Else, type of ``val`` is narrowed to ``float``.
+ ...
+
+ Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower
+ form of ``TypeA`` (it can even be a wider form) and this may lead to
+ type-unsafe results. The main reason is to allow for things like
+ narrowing ``List[object]`` to ``List[str]`` even though the latter is not
+ a subtype of the former, since ``List`` is invariant. The responsibility of
+ writing type-safe type guards is left to the user.
+
+ ``TypeGuard`` also works with type variables. For more information, see
+ PEP 647 (User-Defined Type Guards).
+ """)
+
+
+# Vendored from cpython typing._SpecialFrom
+class _SpecialForm(typing._Final, _root=True):
+ __slots__ = ('_name', '__doc__', '_getitem')
+
+ def __init__(self, getitem):
+ self._getitem = getitem
+ self._name = getitem.__name__
+ self.__doc__ = getitem.__doc__
+
+ def __getattr__(self, item):
+ if item in {'__name__', '__qualname__'}:
+ return self._name
+
+ raise AttributeError(item)
+
+ def __mro_entries__(self, bases):
+ raise TypeError(f"Cannot subclass {self!r}")
+
+ def __repr__(self):
+ return f'typing_extensions.{self._name}'
+
+ def __reduce__(self):
+ return self._name
+
+ def __call__(self, *args, **kwds):
+ raise TypeError(f"Cannot instantiate {self!r}")
+
+ def __or__(self, other):
+ return typing.Union[self, other]
+
+ def __ror__(self, other):
+ return typing.Union[other, self]
+
+ def __instancecheck__(self, obj):
+ raise TypeError(f"{self} cannot be used with isinstance()")
+
+ def __subclasscheck__(self, cls):
+ raise TypeError(f"{self} cannot be used with issubclass()")
+
+ @typing._tp_cache
+ def __getitem__(self, parameters):
+ return self._getitem(self, parameters)
+
+
+if hasattr(typing, "LiteralString"):
+ LiteralString = typing.LiteralString
+else:
+ @_SpecialForm
+ def LiteralString(self, params):
+ """Represents an arbitrary literal string.
+
+ Example::
+
+ from typing_extensions import LiteralString
+
+ def query(sql: LiteralString) -> ...:
+ ...
+
+ query("SELECT * FROM table") # ok
+ query(f"SELECT * FROM {input()}") # not ok
+
+ See PEP 675 for details.
+
+ """
+ raise TypeError(f"{self} is not subscriptable")
+
+
+if hasattr(typing, "Self"):
+ Self = typing.Self
+else:
+ @_SpecialForm
+ def Self(self, params):
+ """Used to spell the type of "self" in classes.
+
+ Example::
+
+ from typing import Self
+
+ class ReturnsSelf:
+ def parse(self, data: bytes) -> Self:
+ ...
+ return self
+
+ """
+
+ raise TypeError(f"{self} is not subscriptable")
+
+
+if hasattr(typing, "Never"):
+ Never = typing.Never
+else:
+ @_SpecialForm
+ def Never(self, params):
+ """The bottom type, a type that has no members.
+
+ This can be used to define a function that should never be
+ called, or a function that never returns::
+
+ from typing_extensions import Never
+
+ def never_call_me(arg: Never) -> None:
+ pass
+
+ def int_or_str(arg: int | str) -> None:
+ never_call_me(arg) # type checker error
+ match arg:
+ case int():
+ print("It's an int")
+ case str():
+ print("It's a str")
+ case _:
+ never_call_me(arg) # ok, arg is of type Never
+
+ """
+
+ raise TypeError(f"{self} is not subscriptable")
+
+
+if hasattr(typing, 'Required'):
+ Required = typing.Required
+ NotRequired = typing.NotRequired
+elif sys.version_info[:2] >= (3, 9):
+ class _ExtensionsSpecialForm(typing._SpecialForm, _root=True):
+ def __repr__(self):
+ return 'typing_extensions.' + self._name
+
+ @_ExtensionsSpecialForm
+ def Required(self, parameters):
+ """A special typing construct to mark a key of a total=False TypedDict
+ as required. For example:
+
+ class Movie(TypedDict, total=False):
+ title: Required[str]
+ year: int
+
+ m = Movie(
+ title='The Matrix', # typechecker error if key is omitted
+ year=1999,
+ )
+
+ There is no runtime checking that a required key is actually provided
+ when instantiating a related TypedDict.
+ """
+ item = typing._type_check(parameters, f'{self._name} accepts only single type')
+ return typing._GenericAlias(self, (item,))
+
+ @_ExtensionsSpecialForm
+ def NotRequired(self, parameters):
+ """A special typing construct to mark a key of a TypedDict as
+ potentially missing. For example:
+
+ class Movie(TypedDict):
+ title: str
+ year: NotRequired[int]
+
+ m = Movie(
+ title='The Matrix', # typechecker error if key is omitted
+ year=1999,
+ )
+ """
+ item = typing._type_check(parameters, f'{self._name} accepts only single type')
+ return typing._GenericAlias(self, (item,))
+
+else:
+ class _RequiredForm(typing._SpecialForm, _root=True):
+ def __repr__(self):
+ return 'typing_extensions.' + self._name
+
+ def __getitem__(self, parameters):
+ item = typing._type_check(parameters,
+ '{} accepts only single type'.format(self._name))
+ return typing._GenericAlias(self, (item,))
+
+ Required = _RequiredForm(
+ 'Required',
+ doc="""A special typing construct to mark a key of a total=False TypedDict
+ as required. For example:
+
+ class Movie(TypedDict, total=False):
+ title: Required[str]
+ year: int
+
+ m = Movie(
+ title='The Matrix', # typechecker error if key is omitted
+ year=1999,
+ )
+
+ There is no runtime checking that a required key is actually provided
+ when instantiating a related TypedDict.
+ """)
+ NotRequired = _RequiredForm(
+ 'NotRequired',
+ doc="""A special typing construct to mark a key of a TypedDict as
+ potentially missing. For example:
+
+ class Movie(TypedDict):
+ title: str
+ year: NotRequired[int]
+
+ m = Movie(
+ title='The Matrix', # typechecker error if key is omitted
+ year=1999,
+ )
+ """)
+
+
+if sys.version_info[:2] >= (3, 9):
+ class _UnpackSpecialForm(typing._SpecialForm, _root=True):
+ def __repr__(self):
+ return 'typing_extensions.' + self._name
+
+ class _UnpackAlias(typing._GenericAlias, _root=True):
+ __class__ = typing.TypeVar
+
+ @_UnpackSpecialForm
+ def Unpack(self, parameters):
+ """A special typing construct to unpack a variadic type. For example:
+
+ Shape = TypeVarTuple('Shape')
+ Batch = NewType('Batch', int)
+
+ def add_batch_axis(
+ x: Array[Unpack[Shape]]
+ ) -> Array[Batch, Unpack[Shape]]: ...
+
+ """
+ item = typing._type_check(parameters, f'{self._name} accepts only single type')
+ return _UnpackAlias(self, (item,))
+
+ def _is_unpack(obj):
+ return isinstance(obj, _UnpackAlias)
+
+else:
+ class _UnpackAlias(typing._GenericAlias, _root=True):
+ __class__ = typing.TypeVar
+
+ class _UnpackForm(typing._SpecialForm, _root=True):
+ def __repr__(self):
+ return 'typing_extensions.' + self._name
+
+ def __getitem__(self, parameters):
+ item = typing._type_check(parameters,
+ f'{self._name} accepts only single type')
+ return _UnpackAlias(self, (item,))
+
+ Unpack = _UnpackForm(
+ 'Unpack',
+ doc="""A special typing construct to unpack a variadic type. For example:
+
+ Shape = TypeVarTuple('Shape')
+ Batch = NewType('Batch', int)
+
+ def add_batch_axis(
+ x: Array[Unpack[Shape]]
+ ) -> Array[Batch, Unpack[Shape]]: ...
+
+ """)
+
+ def _is_unpack(obj):
+ return isinstance(obj, _UnpackAlias)
+
+
+class TypeVarTuple:
+ """Type variable tuple.
+
+ Usage::
+
+ Ts = TypeVarTuple('Ts')
+
+ In the same way that a normal type variable is a stand-in for a single
+ type such as ``int``, a type variable *tuple* is a stand-in for a *tuple* type such as
+ ``Tuple[int, str]``.
+
+ Type variable tuples can be used in ``Generic`` declarations.
+ Consider the following example::
+
+ class Array(Generic[*Ts]): ...
+
+ The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``,
+ where ``T1`` and ``T2`` are type variables. To use these type variables
+ as type parameters of ``Array``, we must *unpack* the type variable tuple using
+ the star operator: ``*Ts``. The signature of ``Array`` then behaves
+ as if we had simply written ``class Array(Generic[T1, T2]): ...``.
+ In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows
+ us to parameterise the class with an *arbitrary* number of type parameters.
+
+ Type variable tuples can be used anywhere a normal ``TypeVar`` can.
+ This includes class definitions, as shown above, as well as function
+ signatures and variable annotations::
+
+ class Array(Generic[*Ts]):
+
+ def __init__(self, shape: Tuple[*Ts]):
+ self._shape: Tuple[*Ts] = shape
+
+ def get_shape(self) -> Tuple[*Ts]:
+ return self._shape
+
+ shape = (Height(480), Width(640))
+ x: Array[Height, Width] = Array(shape)
+ y = abs(x) # Inferred type is Array[Height, Width]
+ z = x + x # ... is Array[Height, Width]
+ x.get_shape() # ... is tuple[Height, Width]
+
+ """
+
+ # Trick Generic __parameters__.
+ __class__ = typing.TypeVar
+
+ def __iter__(self):
+ yield self.__unpacked__
+
+ def __init__(self, name):
+ self.__name__ = name
+
+ # for pickling:
+ try:
+ def_mod = sys._getframe(1).f_globals.get('__name__', '__main__')
+ except (AttributeError, ValueError):
+ def_mod = None
+ if def_mod != 'typing_extensions':
+ self.__module__ = def_mod
+
+ self.__unpacked__ = Unpack[self]
+
+ def __repr__(self):
+ return self.__name__
+
+ def __hash__(self):
+ return object.__hash__(self)
+
+ def __eq__(self, other):
+ return self is other
+
+ def __reduce__(self):
+ return self.__name__
+
+ def __init_subclass__(self, *args, **kwds):
+ if '_root' not in kwds:
+ raise TypeError("Cannot subclass special typing classes")
+
+
+if hasattr(typing, "reveal_type"):
+ reveal_type = typing.reveal_type
+else:
+ def reveal_type(__obj: T) -> T:
+ """Reveal the inferred type of a variable.
+
+ When a static type checker encounters a call to ``reveal_type()``,
+ it will emit the inferred type of the argument::
+
+ x: int = 1
+ reveal_type(x)
+
+ Running a static type checker (e.g., ``mypy``) on this example
+ will produce output similar to 'Revealed type is "builtins.int"'.
+
+ At runtime, the function prints the runtime type of the
+ argument and returns it unchanged.
+
+ """
+ print(f"Runtime type is {type(__obj).__name__!r}", file=sys.stderr)
+ return __obj
+
+
+if hasattr(typing, "assert_never"):
+ assert_never = typing.assert_never
+else:
+ def assert_never(__arg: Never) -> Never:
+ """Assert to the type checker that a line of code is unreachable.
+
+ Example::
+
+ def int_or_str(arg: int | str) -> None:
+ match arg:
+ case int():
+ print("It's an int")
+ case str():
+ print("It's a str")
+ case _:
+ assert_never(arg)
+
+ If a type checker finds that a call to assert_never() is
+ reachable, it will emit an error.
+
+ At runtime, this throws an exception when called.
+
+ """
+ raise AssertionError("Expected code to be unreachable")
+
+
+if hasattr(typing, 'dataclass_transform'):
+ dataclass_transform = typing.dataclass_transform
+else:
+ def dataclass_transform(
+ *,
+ eq_default: bool = True,
+ order_default: bool = False,
+ kw_only_default: bool = False,
+ field_descriptors: typing.Tuple[
+ typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]],
+ ...
+ ] = (),
+ ) -> typing.Callable[[T], T]:
+ """Decorator that marks a function, class, or metaclass as providing
+ dataclass-like behavior.
+
+ Example:
+
+ from typing_extensions import dataclass_transform
+
+ _T = TypeVar("_T")
+
+ # Used on a decorator function
+ @dataclass_transform()
+ def create_model(cls: type[_T]) -> type[_T]:
+ ...
+ return cls
+
+ @create_model
+ class CustomerModel:
+ id: int
+ name: str
+
+ # Used on a base class
+ @dataclass_transform()
+ class ModelBase: ...
+
+ class CustomerModel(ModelBase):
+ id: int
+ name: str
+
+ # Used on a metaclass
+ @dataclass_transform()
+ class ModelMeta(type): ...
+
+ class ModelBase(metaclass=ModelMeta): ...
+
+ class CustomerModel(ModelBase):
+ id: int
+ name: str
+
+ Each of the ``CustomerModel`` classes defined in this example will now
+ behave similarly to a dataclass created with the ``@dataclasses.dataclass``
+ decorator. For example, the type checker will synthesize an ``__init__``
+ method.
+
+ The arguments to this decorator can be used to customize this behavior:
+ - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be
+ True or False if it is omitted by the caller.
+ - ``order_default`` indicates whether the ``order`` parameter is
+ assumed to be True or False if it is omitted by the caller.
+ - ``kw_only_default`` indicates whether the ``kw_only`` parameter is
+ assumed to be True or False if it is omitted by the caller.
+ - ``field_descriptors`` specifies a static list of supported classes
+ or functions, that describe fields, similar to ``dataclasses.field()``.
+
+ At runtime, this decorator records its arguments in the
+ ``__dataclass_transform__`` attribute on the decorated object.
+
+ See PEP 681 for details.
+
+ """
+ def decorator(cls_or_fn):
+ cls_or_fn.__dataclass_transform__ = {
+ "eq_default": eq_default,
+ "order_default": order_default,
+ "kw_only_default": kw_only_default,
+ "field_descriptors": field_descriptors,
+ }
+ return cls_or_fn
+ return decorator
+
+
+# We have to do some monkey patching to deal with the dual nature of
+# Unpack/TypeVarTuple:
+# - We want Unpack to be a kind of TypeVar so it gets accepted in
+# Generic[Unpack[Ts]]
+# - We want it to *not* be treated as a TypeVar for the purposes of
+# counting generic parameters, so that when we subscript a generic,
+# the runtime doesn't try to substitute the Unpack with the subscripted type.
+if not hasattr(typing, "TypeVarTuple"):
+ typing._collect_type_vars = _collect_type_vars
+ typing._check_generic = _check_generic
diff --git a/typing_extensions/tox.ini b/typing_extensions/tox.ini
new file mode 100644
index 0000000..0886936
--- /dev/null
+++ b/typing_extensions/tox.ini
@@ -0,0 +1,7 @@
+[tox]
+isolated_build = True
+envlist = py36, py37, py38, py39, py310
+
+[testenv]
+changedir = src
+commands = python -m unittest discover