Skip to content

Commit

Permalink
pythongh-109653: typing.py: improve import time by creating soft-de…
Browse files Browse the repository at this point in the history
…precated members on demand (python#109651)

Co-authored-by: Thomas Grainger <tagrain@gmail.com>
  • Loading branch information
AlexWaygood and graingert committed Sep 23, 2023
1 parent 62c7015 commit e8be0c9
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 8 deletions.
4 changes: 4 additions & 0 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -9373,6 +9373,10 @@ def test_all(self):
self.assertIn('SupportsComplex', a)

def test_all_exported_names(self):
# ensure all dynamically created objects are actualised
for name in typing.__all__:
getattr(typing, name)

actual_all = set(typing.__all__)
computed_all = {
k for k, v in vars(typing).items()
Expand Down
26 changes: 18 additions & 8 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,8 @@
from collections import defaultdict
import collections.abc
import copyreg
import contextlib
import functools
import operator
import re as stdlib_re # Avoid confusion with the typing.re namespace on <=3.11
import sys
import types
from types import WrapperDescriptorType, MethodWrapperType, MethodDescriptorType, GenericAlias
Expand Down Expand Up @@ -2580,8 +2578,6 @@ class Other(Leaf): # Error reported by type checker
KeysView = _alias(collections.abc.KeysView, 1)
ItemsView = _alias(collections.abc.ItemsView, 2)
ValuesView = _alias(collections.abc.ValuesView, 1)
ContextManager = _alias(contextlib.AbstractContextManager, 1, name='ContextManager')
AsyncContextManager = _alias(contextlib.AbstractAsyncContextManager, 1, name='AsyncContextManager')
Dict = _alias(dict, 2, inst=False, name='Dict')
DefaultDict = _alias(collections.defaultdict, 2, name='DefaultDict')
OrderedDict = _alias(collections.OrderedDict, 2)
Expand Down Expand Up @@ -3238,10 +3234,6 @@ def __enter__(self) -> 'TextIO':
pass


Pattern = _alias(stdlib_re.Pattern, 1)
Match = _alias(stdlib_re.Match, 1)


def reveal_type[T](obj: T, /) -> T:
"""Reveal the inferred type of a variable.

Expand Down Expand Up @@ -3426,3 +3418,21 @@ def get_protocol_members(tp: type, /) -> frozenset[str]:
if not is_protocol(tp):
raise TypeError(f'{tp!r} is not a Protocol')
return frozenset(tp.__protocol_attrs__)


def __getattr__(attr):
"""Improve the import time of the typing module.
Soft-deprecated objects which are costly to create
are only created on-demand here.
"""
if attr in {"Pattern", "Match"}:
import re
obj = _alias(getattr(re, attr), 1)
elif attr in {"ContextManager", "AsyncContextManager"}:
import contextlib
obj = _alias(getattr(contextlib, f"Abstract{attr}"), 1, name=attr)
else:
raise AttributeError(f"module {__name__!r} has no attribute {attr!r}")
globals()[attr] = obj
return obj
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Reduce the import time of :mod:`typing` by around a third.
Patch by Alex Waygood.

0 comments on commit e8be0c9

Please sign in to comment.