Skip to content

Commit 7d1aeea

Browse files
authored
Implement typing_extensions.Any (#68)
1 parent 9683c1a commit 7d1aeea

File tree

3 files changed

+82
-3
lines changed

3 files changed

+82
-3
lines changed

Diff for: CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# Release 4.4.0 ()
2+
- Add `typing_extensions.Any` a backport of python 3.11's Any class which is
3+
subclassable at runtime. (backport from python/cpython#31841, by Shantanu
4+
and Jelle Zijlstra). Patch by James Hilton-Balfe (@Gobot1234).
5+
16
# Release 4.3.0 (July 1, 2022)
27

38
- Add `typing_extensions.NamedTuple`, allowing for generic `NamedTuple`s on

Diff for: src/test_typing_extensions.py

+45-3
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515
from unittest.mock import patch
1616
from test import ann_module, ann_module2, ann_module3
1717
import typing
18-
from typing import TypeVar, Optional, Union, Any, AnyStr
18+
from typing import TypeVar, Optional, Union, AnyStr
1919
from typing import T, KT, VT # Not in __all__.
2020
from typing import Tuple, List, Dict, Iterable, Iterator, Callable
2121
from typing import Generic
2222
from typing import no_type_check
2323
import typing_extensions
24-
from typing_extensions import NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict, Self
24+
from typing_extensions import NoReturn, Any, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict, Self
2525
from typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs, TypeGuard
2626
from typing_extensions import Awaitable, AsyncIterator, AsyncContextManager, Required, NotRequired
2727
from typing_extensions import Protocol, runtime, runtime_checkable, Annotated, final, is_typeddict
@@ -160,6 +160,48 @@ def test_exception(self):
160160
assert_never(None)
161161

162162

163+
class AnyTests(BaseTestCase):
164+
def test_can_subclass(self):
165+
class Mock(Any): pass
166+
self.assertTrue(issubclass(Mock, Any))
167+
self.assertIsInstance(Mock(), Mock)
168+
169+
class Something: pass
170+
self.assertFalse(issubclass(Something, Any))
171+
self.assertNotIsInstance(Something(), Mock)
172+
173+
class MockSomething(Something, Mock): pass
174+
self.assertTrue(issubclass(MockSomething, Any))
175+
ms = MockSomething()
176+
self.assertIsInstance(ms, MockSomething)
177+
self.assertIsInstance(ms, Something)
178+
self.assertIsInstance(ms, Mock)
179+
180+
class SubclassesAny(Any):
181+
...
182+
183+
def test_repr(self):
184+
if sys.version_info >= (3, 11):
185+
mod_name = 'typing'
186+
else:
187+
mod_name = 'typing_extensions'
188+
self.assertEqual(repr(Any), f"{mod_name}.Any")
189+
if sys.version_info < (3, 11): # skip for now on 3.11+ see python/cpython#95987
190+
self.assertEqual(repr(self.SubclassesAny), "<class 'test_typing_extensions.AnyTests.SubclassesAny'>")
191+
192+
def test_instantiation(self):
193+
with self.assertRaises(TypeError):
194+
Any()
195+
196+
self.SubclassesAny()
197+
198+
def test_isinstance(self):
199+
with self.assertRaises(TypeError):
200+
isinstance(object(), Any)
201+
202+
isinstance(object(), self.SubclassesAny)
203+
204+
163205
class ClassVarTests(BaseTestCase):
164206

165207
def test_basics(self):
@@ -3018,7 +3060,7 @@ def test_typing_extensions_defers_when_possible(self):
30183060
if sys.version_info < (3, 10):
30193061
exclude |= {'get_args', 'get_origin'}
30203062
if sys.version_info < (3, 11):
3021-
exclude |= {'final', 'NamedTuple'}
3063+
exclude |= {'final', 'NamedTuple', 'Any'}
30223064
for item in typing_extensions.__all__:
30233065
if item not in exclude and hasattr(typing, item):
30243066
self.assertIs(

Diff for: src/typing_extensions.py

+32
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# Please keep __all__ alphabetized within each category.
1212
__all__ = [
1313
# Super-special typing primitives.
14+
'Any',
1415
'ClassVar',
1516
'Concatenate',
1617
'Final',
@@ -149,6 +150,37 @@ def _collect_type_vars(types, typevar_types=None):
149150
T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers.
150151
T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant.
151152

153+
154+
if sys.version_info >= (3, 11):
155+
from typing import Any
156+
else:
157+
158+
class _AnyMeta(type):
159+
def __instancecheck__(self, obj):
160+
if self is Any:
161+
raise TypeError("typing_extensions.Any cannot be used with isinstance()")
162+
return super().__instancecheck__(obj)
163+
164+
def __repr__(self):
165+
if self is Any:
166+
return "typing_extensions.Any"
167+
return super().__repr__()
168+
169+
class Any(metaclass=_AnyMeta):
170+
"""Special type indicating an unconstrained type.
171+
- Any is compatible with every type.
172+
- Any assumed to have all methods.
173+
- All values assumed to be instances of Any.
174+
Note that all the above statements are true from the point of view of
175+
static type checkers. At runtime, Any should not be used with instance
176+
checks.
177+
"""
178+
def __new__(cls, *args, **kwargs):
179+
if cls is Any:
180+
raise TypeError("Any cannot be instantiated")
181+
return super().__new__(cls, *args, **kwargs)
182+
183+
152184
ClassVar = typing.ClassVar
153185

154186
# On older versions of typing there is an internal class named "Final".

0 commit comments

Comments
 (0)