これは何?
typing-extensions
は Python 標準ライブラリ typing
のバックポートです。
たとえば、 Python==3.11 で追加された型ヒントを、 Python<3.11 でも利用したい場合、
typing-extensions
をインストールしてこちらから import すれば利用できます。
この記事では以下についてまとめています。
- どの型ヒントがバックポートされているのか
- 特定の型ヒントが実装されたのはどのバージョンからか
typing-extensions>=4
であれば CHANGELOG.md を読めばわかります
typing-extensions<4
では、まとまった情報が無いように見えたので、抽出したものをまとめておきます。
History of typing_extensions
typing_extensions.Annotated
- Added typing-extensions==3.7.4
typing_extensions.Any
- Added typing-extensions==4.4.0
typing_extensions.AsyncContextManager
- Added typing-extensions==3.6.5
typing_extensions.AsyncGenerator
- Added typing-extensions==3.6.5
typing_extensions.AsyncIterable
- Added typing-extensions==3.6.5
typing_extensions.AsyncIterator
- Added typing-extensions==3.6.5
typing_extensions.Awaitable
- Added typing-extensions==3.6.5
typing_extensions.Callable
- Added typing-extensions==3.6.5
- Removed typing-extensions==4.0.0
typing_extensions.ChainMap
- Added typing-extensions==3.6.5
typing_extensions.ClassVar
- Added typing-extensions==3.6.5
typing_extensions.Concatenate
typing_extensions.ContextManager
- Added typing-extensions==3.6.5
typing_extensions.Coroutine
- Added typing-extensions==3.6.5
typing_extensions.Counter
- Added typing-extensions==3.6.5
typing_extensions.DefaultDict
- Added typing-extensions==3.6.5
typing_extensions.Deque
- Added typing-extensions==3.6.5
typing_extensions.Final
- Added typing-extensions==3.7.4
typing_extensions.Generic
- Added typing-extensions==3.6.5
- Removed typing-extensions==4.0.0
typing_extensions.GenericMeta
- Added typing-extensions==3.6.5
typing_extensions.HAVE_ANNOTATED
- Added typing-extensions==3.7.4
- Removed typing-extensions==4.0.0
typing_extensions.HAVE_PROTOCOLS
- Added typing-extensions==3.6.5
- Removed typing-extensions==4.0.0
typing_extensions.IntVar
- Added typing-extensions==3.7.4
typing_extensions.KT
- Added typing-extensions==3.6.5
typing_extensions.Literal
- Added typing-extensions==3.7.4
typing_extensions.LiteralString
- Added typing-extensions==4.1.0
typing_extensions.NamedTuple
- Added typing-extensions==4.3.0
typing_extensions.Never
- Added typing-extensions==4.1.0
typing_extensions.NewType
- Added typing-extensions==3.6.5
typing_extensions.NoReturn
- Added typing-extensions==3.6.5
typing_extensions.NotRequired
- Added typing-extensions==4.0.0
typing_extensions.OLD_GENERICS
- Added typing-extensions==3.6.5
- Removed typing-extensions==4.0.0
typing_extensions.OrderedDict
typing_extensions.PEP_560
- Added typing-extensions==3.6.5
typing_extensions.ParamSpec
typing_extensions.ParamSpecArgs
typing_extensions.ParamSpecKwargs
typing_extensions.Protocol
- Added typing-extensions==3.6.5
typing_extensions.Required
- Added typing-extensions==4.0.0
typing_extensions.SUBS_TREE
- Added typing-extensions==3.7.4
- Removed typing-extensions==4.0.0
typing_extensions.Self
- Added typing-extensions==4.0.0
typing_extensions.SupportsIndex
typing_extensions.T
- Added typing-extensions==3.6.5
typing_extensions.TYPE_CHECKING
- Added typing-extensions==3.6.5
typing_extensions.T_co
- Added typing-extensions==3.6.5
typing_extensions.T_contra
- Added typing-extensions==3.6.5
typing_extensions.Text
- Added typing-extensions==3.6.5
typing_extensions.Tuple
- Added typing-extensions==3.6.5
- Removed typing-extensions==4.0.0
typing_extensions.Type
- Added typing-extensions==3.6.5
typing_extensions.TypeAlias
typing_extensions.TypeGuard
typing_extensions.TypeVar
- Added typing-extensions==3.6.5
- Removed typing-extensions==4.0.0
- Added typing-extensions==4.4.0
typing_extensions.TypeVarTuple
- Added typing-extensions==4.1.0
typing_extensions.TypedDict
- Added typing-extensions==3.7.4
typing_extensions.TypingMeta
- Added typing-extensions==3.6.5
- Removed typing-extensions==4.0.0
typing_extensions.Unpack
- Added typing-extensions==4.1.0
typing_extensions.VT
- Added typing-extensions==3.6.5
typing_extensions.VT_co
- Added typing-extensions==3.6.5
- Removed typing-extensions==4.0.0
typing_extensions.V_co
- Added typing-extensions==3.6.5
- Removed typing-extensions==4.0.0
typing_extensions.assert_never
- Added typing-extensions==4.1.0
typing_extensions.assert_type
- Added typing-extensions==4.2.0
typing_extensions.clear_overloads
- Added typing-extensions==4.2.0
typing_extensions.dataclass_transform
- Added typing-extensions==4.1.0
typing_extensions.final
- Added typing-extensions==3.7.4
typing_extensions.get_args
typing_extensions.get_origin
typing_extensions.get_overloads
- Added typing-extensions==4.2.0
typing_extensions.get_type_hints
- Added typing-extensions==3.7.4
typing_extensions.is_typeddict
- Added typing-extensions==4.1.0
typing_extensions.overload
- Added typing-extensions==3.6.5
typing_extensions.override
- Added typing-extensions==4.4.0
typing_extensions.reveal_type
- Added typing-extensions==4.1.0
typing_extensions.runtime
- Added typing-extensions==3.6.5
typing_extensions.runtime_checkable
- Added typing-extensions==3.7.4
抽出用スクリプト
- PyPI の #history ページから バージョン番号を昇順に集める
- バージョン番号ごとに仮想環境を作る
-
typing_extensions
をインストールする - 仮想環境で
typing_extensions
をインポートして、要素の一覧を出す
-
- 要素ごとに追加/削除されたバージョンをリンク付きで書きだす
from typing import NewType
from aiohttp import ClientSession
from contextlib import AsyncExitStack
from lxml import html
from collections.abc import AsyncIterator
from asyncio import run, gather, create_subprocess_exec
from functools import partial
from tempfile import TemporaryDirectory
from pathlib import Path
import sys
from subprocess import PIPE
from functools import reduce
from operator import or_
URI = NewType("URI", str)
VersionString = NewType("VersionString", str)
async def main():
package = "typing-extensions"
_get_attributes = partial(get_attributes, package)
items = await gather(
*map(
_get_attributes,
[version async for version in get_versions(package)],
)
)
versions_and_attrs = {key: value for key, value in items if value is not None}
all_attrs = reduce(or_, versions_and_attrs.values())
for attr in sorted(all_attrs):
print(f"## `typing_extensions.{attr}`")
print()
prev_exists = False
for version, attrs in versions_and_attrs.items():
exists = attr in attrs
if exists != prev_exists:
if exists:
print(
f"- Added [{package}=={version}](https://pypi.org/project/typing-extensions/{version}/)"
)
else:
print(
f"- Removed [{[package]}=={version}](https://pypi.org/project/typing-extensions/{version}/)"
)
prev_exists = exists
print()
async def get_element(uri: URI):
async with AsyncExitStack() as stack:
aenter = stack.enter_async_context
session = await aenter(ClientSession())
response = await aenter(session.get(uri))
return html.fromstring(await response.text())
async def get_versions(package: str) -> AsyncIterator[VersionString]:
root = await get_element(f"https://pypi.org/project/{package}/#history")
versions = list(root.xpath('//p[@class="release__version"]/text()'))
for version in reversed(versions):
yield version.strip()
async def get_attributes(
package: str, version: VersionString
) -> tuple[VersionString, list[str]]:
async with AsyncExitStack() as stack:
aenter = stack.enter_async_context
enter = stack.enter_context
directory = Path(enter(TemporaryDirectory()))
venv_cmd = [sys.executable, "-m", "venv", f"{directory}"]
print(*venv_cmd, sep=" ")
venv = await create_subprocess_exec(*venv_cmd)
assert await venv.wait() == 0
(executable,) = directory.rglob("python")
pip_upgrade_cmd = [f"{executable}", "-m", "pip", "install", "--upgrade", "pip"]
print(*pip_upgrade_cmd, sep=" ")
pip_upgrade = await create_subprocess_exec(*pip_upgrade_cmd)
assert await pip_upgrade.wait() == 0
package_install_cmd = [
f"{executable}",
"-m",
"pip",
"install",
f"{package}=={version}",
]
print(*package_install_cmd, sep=" ")
package_install = await create_subprocess_exec(*package_install_cmd)
assert await package_install.wait() == 0
listup_cmd = [
f"{executable}",
"-c",
r"""\
import typing_extensions
from types import ModuleType
for attr in dir(typing_extensions):
obj = getattr(typing_extensions, attr)
if attr.startswith("_") or isinstance(obj, ModuleType):
continue
print(attr)
""",
]
listup = await create_subprocess_exec(*listup_cmd, stdout=PIPE)
stdout, _ = await listup.communicate()
if listup.returncode != 0:
return version, None
else:
return version, set(stdout.decode("utf-8").splitlines(keepends=False))
if __name__ == "__main__":
run(main())