3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

typing_extensions で利用可能な型ヒントの一覧

Posted at

これは何?

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

typing_extensions.Any

typing_extensions.AsyncContextManager

typing_extensions.AsyncGenerator

typing_extensions.AsyncIterable

typing_extensions.AsyncIterator

typing_extensions.Awaitable

typing_extensions.Callable

typing_extensions.ChainMap

typing_extensions.ClassVar

typing_extensions.Concatenate

typing_extensions.ContextManager

typing_extensions.Coroutine

typing_extensions.Counter

typing_extensions.DefaultDict

typing_extensions.Deque

typing_extensions.Final

typing_extensions.Generic

typing_extensions.GenericMeta

typing_extensions.HAVE_ANNOTATED

typing_extensions.HAVE_PROTOCOLS

typing_extensions.IntVar

typing_extensions.KT

typing_extensions.Literal

typing_extensions.LiteralString

typing_extensions.NamedTuple

typing_extensions.Never

typing_extensions.NewType

typing_extensions.NoReturn

typing_extensions.NotRequired

typing_extensions.OLD_GENERICS

typing_extensions.OrderedDict

typing_extensions.PEP_560

typing_extensions.ParamSpec

typing_extensions.ParamSpecArgs

typing_extensions.ParamSpecKwargs

typing_extensions.Protocol

typing_extensions.Required

typing_extensions.SUBS_TREE

typing_extensions.Self

typing_extensions.SupportsIndex

typing_extensions.T

typing_extensions.TYPE_CHECKING

typing_extensions.T_co

typing_extensions.T_contra

typing_extensions.Text

typing_extensions.Tuple

typing_extensions.Type

typing_extensions.TypeAlias

typing_extensions.TypeGuard

typing_extensions.TypeVar

typing_extensions.TypeVarTuple

typing_extensions.TypedDict

typing_extensions.TypingMeta

typing_extensions.Unpack

typing_extensions.VT

typing_extensions.VT_co

typing_extensions.V_co

typing_extensions.assert_never

typing_extensions.assert_type

typing_extensions.clear_overloads

typing_extensions.dataclass_transform

typing_extensions.final

typing_extensions.get_args

typing_extensions.get_origin

typing_extensions.get_overloads

typing_extensions.get_type_hints

typing_extensions.is_typeddict

typing_extensions.overload

typing_extensions.override

typing_extensions.reveal_type

typing_extensions.runtime

typing_extensions.runtime_checkable

抽出用スクリプト

  • 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())
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?