[Python-checkins] cpython: Update typing.py: remove isinstance() support (Mark struck it from the PEP).

guido.van.rossum python-checkins at python.org
Thu Jun 4 04:12:55 CEST 2015


https://hg.python.org/cpython/rev/4d2ef8f3c424
changeset:   96505:4d2ef8f3c424
user:        Guido van Rossum <guido at python.org>
date:        Wed Jun 03 19:04:42 2015 -0700
summary:
  Update typing.py: remove isinstance() support (Mark struck it from the PEP).

files:
  Lib/test/test_typing.py |  245 +++++----------------------
  Lib/typing.py           |  156 ++---------------
  2 files changed, 71 insertions(+), 330 deletions(-)


diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -41,11 +41,9 @@
 
 class AnyTests(TestCase):
 
-    def test_any_instance(self):
-        self.assertIsInstance(Employee(), Any)
-        self.assertIsInstance(42, Any)
-        self.assertIsInstance(None, Any)
-        self.assertIsInstance(object(), Any)
+    def test_any_instance_type_error(self):
+        with self.assertRaises(TypeError):
+            isinstance(42, Any)
 
     def test_any_subclass(self):
         self.assertTrue(issubclass(Employee, Any))
@@ -109,9 +107,6 @@
 
     def test_basic_plain(self):
         T = TypeVar('T')
-        # Nothing is an instance if T.
-        with self.assertRaises(TypeError):
-            isinstance('', T)
         # Every class is a subclass of T.
         assert issubclass(int, T)
         assert issubclass(str, T)
@@ -119,12 +114,16 @@
         assert T == T
         # T is a subclass of itself.
         assert issubclass(T, T)
+        # T is an instance of TypeVar
+        assert isinstance(T, TypeVar)
+
+    def test_typevar_instance_type_error(self):
+        T = TypeVar('T')
+        with self.assertRaises(TypeError):
+            isinstance(42, T)
 
     def test_basic_constrained(self):
         A = TypeVar('A', str, bytes)
-        # Nothing is an instance of A.
-        with self.assertRaises(TypeError):
-            isinstance('', A)
         # Only str and bytes are subclasses of A.
         assert issubclass(str, A)
         assert issubclass(bytes, A)
@@ -213,8 +212,6 @@
     def test_basics(self):
         u = Union[int, float]
         self.assertNotEqual(u, Union)
-        self.assertIsInstance(42, u)
-        self.assertIsInstance(3.14, u)
         self.assertTrue(issubclass(int, u))
         self.assertTrue(issubclass(float, u))
 
@@ -247,7 +244,6 @@
 
     def test_subclass(self):
         u = Union[int, Employee]
-        self.assertIsInstance(Manager(), u)
         self.assertTrue(issubclass(Manager, u))
 
     def test_self_subclass(self):
@@ -256,7 +252,6 @@
 
     def test_multiple_inheritance(self):
         u = Union[int, Employee]
-        self.assertIsInstance(ManagingFounder(), u)
         self.assertTrue(issubclass(ManagingFounder, u))
 
     def test_single_class_disappears(self):
@@ -309,9 +304,6 @@
         o = Optional[int]
         u = Union[int, None]
         self.assertEqual(o, u)
-        self.assertIsInstance(42, o)
-        self.assertIsInstance(None, o)
-        self.assertNotIsInstance(3.14, o)
 
     def test_empty(self):
         with self.assertRaises(TypeError):
@@ -321,11 +313,9 @@
         assert issubclass(Union[int, str], Union)
         assert not issubclass(int, Union)
 
-    def test_isinstance_union(self):
-        # Nothing is an instance of bare Union.
-        assert not isinstance(42, Union)
-        assert not isinstance(int, Union)
-        assert not isinstance(Union[int, str], Union)
+    def test_union_instance_type_error(self):
+        with self.assertRaises(TypeError):
+            isinstance(42, Union[int, str])
 
 
 class TypeVarUnionTests(TestCase):
@@ -352,22 +342,11 @@
         TU = TypeVar('TU', Union[int, float], None)
         assert issubclass(int, TU)
         assert issubclass(float, TU)
-        with self.assertRaises(TypeError):
-            isinstance(42, TU)
-        with self.assertRaises(TypeError):
-            isinstance('', TU)
 
 
 class TupleTests(TestCase):
 
     def test_basics(self):
-        self.assertIsInstance((42, 3.14, ''), Tuple)
-        self.assertIsInstance((42, 3.14, ''), Tuple[int, float, str])
-        self.assertIsInstance((42,), Tuple[int])
-        self.assertNotIsInstance((3.14,), Tuple[int])
-        self.assertNotIsInstance((42, 3.14), Tuple[int, float, str])
-        self.assertNotIsInstance((42, 3.14, 100), Tuple[int, float, str])
-        self.assertNotIsInstance((42, 3.14, 100), Tuple[int, float])
         self.assertTrue(issubclass(Tuple[int, str], Tuple))
         self.assertTrue(issubclass(Tuple[int, str], Tuple[int, str]))
         self.assertFalse(issubclass(int, Tuple))
@@ -382,14 +361,11 @@
             pass
         self.assertTrue(issubclass(MyTuple, Tuple))
 
-    def test_tuple_ellipsis(self):
-        t = Tuple[int, ...]
-        assert isinstance((), t)
-        assert isinstance((1,), t)
-        assert isinstance((1, 2), t)
-        assert isinstance((1, 2, 3), t)
-        assert not isinstance((3.14,), t)
-        assert not isinstance((1, 2, 3.14,), t)
+    def test_tuple_instance_type_error(self):
+        with self.assertRaises(TypeError):
+            isinstance((0, 0), Tuple[int, int])
+        with self.assertRaises(TypeError):
+            isinstance((0, 0), Tuple)
 
     def test_tuple_ellipsis_subclass(self):
 
@@ -419,18 +395,6 @@
 
 class CallableTests(TestCase):
 
-    def test_basics(self):
-        c = Callable[[int, float], str]
-
-        def flub(a: int, b: float) -> str:
-            return str(a * b)
-
-        def flob(a: int, b: int) -> str:
-            return str(a * b)
-
-        self.assertIsInstance(flub, c)
-        self.assertNotIsInstance(flob, c)
-
     def test_self_subclass(self):
         self.assertTrue(issubclass(Callable[[int], int], Callable))
         self.assertFalse(issubclass(Callable, Callable[[int], int]))
@@ -453,91 +417,6 @@
         self.assertNotEqual(Callable[[int], int], Callable[[], int])
         self.assertNotEqual(Callable[[int], int], Callable)
 
-    def test_with_none(self):
-        c = Callable[[None], None]
-
-        def flub(self: None) -> None:
-            pass
-
-        def flab(self: Any) -> None:
-            pass
-
-        def flob(self: None) -> Any:
-            pass
-
-        self.assertIsInstance(flub, c)
-        self.assertIsInstance(flab, c)
-        self.assertNotIsInstance(flob, c)  # Test contravariance.
-
-    def test_with_subclasses(self):
-        c = Callable[[Employee, Manager], Employee]
-
-        def flub(a: Employee, b: Employee) -> Manager:
-            return Manager()
-
-        def flob(a: Manager, b: Manager) -> Employee:
-            return Employee()
-
-        self.assertIsInstance(flub, c)
-        self.assertNotIsInstance(flob, c)
-
-    def test_with_default_args(self):
-        c = Callable[[int], int]
-
-        def flub(a: int, b: float = 3.14) -> int:
-            return a
-
-        def flab(a: int, *, b: float = 3.14) -> int:
-            return a
-
-        def flob(a: int = 42) -> int:
-            return a
-
-        self.assertIsInstance(flub, c)
-        self.assertIsInstance(flab, c)
-        self.assertIsInstance(flob, c)
-
-    def test_with_varargs(self):
-        c = Callable[[int], int]
-
-        def flub(*args) -> int:
-            return 42
-
-        def flab(*args: int) -> int:
-            return 42
-
-        def flob(*args: float) -> int:
-            return 42
-
-        self.assertIsInstance(flub, c)
-        self.assertIsInstance(flab, c)
-        self.assertNotIsInstance(flob, c)
-
-    def test_with_method(self):
-
-        class C:
-
-            def imethod(self, arg: int) -> int:
-                self.last_arg = arg
-                return arg + 1
-
-            @classmethod
-            def cmethod(cls, arg: int) -> int:
-                cls.last_cls_arg = arg
-                return arg + 1
-
-            @staticmethod
-            def smethod(arg: int) -> int:
-                return arg + 1
-
-        ct = Callable[[int], int]
-        self.assertIsInstance(C().imethod, ct)
-        self.assertIsInstance(C().cmethod, ct)
-        self.assertIsInstance(C.cmethod, ct)
-        self.assertIsInstance(C().smethod, ct)
-        self.assertIsInstance(C.smethod, ct)
-        self.assertIsInstance(C.imethod, Callable[[Any, int], int])
-
     def test_cannot_subclass(self):
         with self.assertRaises(TypeError):
 
@@ -556,21 +435,21 @@
         with self.assertRaises(TypeError):
             c()
 
-    def test_varargs(self):
-        ct = Callable[..., int]
+    def test_callable_instance_works(self):
+        f = lambda: None
+        assert isinstance(f, Callable)
+        assert not isinstance(None, Callable)
 
-        def foo(a, b) -> int:
-            return 42
-
-        def bar(a=42) -> int:
-            return a
-
-        def baz(*, x, y, z) -> int:
-            return 100
-
-        self.assertIsInstance(foo, ct)
-        self.assertIsInstance(bar, ct)
-        self.assertIsInstance(baz, ct)
+    def test_callable_instance_type_error(self):
+        f = lambda: None
+        with self.assertRaises(TypeError):
+            assert isinstance(f, Callable[[], None])
+        with self.assertRaises(TypeError):
+            assert isinstance(f, Callable[[], Any])
+        with self.assertRaises(TypeError):
+            assert not isinstance(None, Callable[[], None])
+        with self.assertRaises(TypeError):
+            assert not isinstance(None, Callable[[], Any])
 
     def test_repr(self):
         ct0 = Callable[[], bool]
@@ -659,6 +538,10 @@
         assert issubclass(list, typing.Reversible)
         assert not issubclass(int, typing.Reversible)
 
+    def test_protocol_instance_type_error(self):
+        with self.assertRaises(TypeError):
+            isinstance([], typing.Reversible)
+
 
 class GenericTests(TestCase):
 
@@ -889,6 +772,11 @@
         right_hints = get_type_hints(t.add_right, globals(), locals())
         assert right_hints['node'] == Optional[Node[T]]
 
+    def test_forwardref_instance_type_error(self):
+        fr = typing._ForwardRef('int')
+        with self.assertRaises(TypeError):
+            isinstance(42, fr)
+
     def test_union_forward(self):
 
         def foo(a: Union['T']):
@@ -1069,50 +957,17 @@
 
     def test_list(self):
         assert issubclass(list, typing.List)
-        assert isinstance([], typing.List)
-        assert not isinstance((), typing.List)
-        t = typing.List[int]
-        assert isinstance([], t)
-        assert isinstance([42], t)
-        assert not isinstance([''], t)
 
     def test_set(self):
         assert issubclass(set, typing.Set)
         assert not issubclass(frozenset, typing.Set)
-        assert isinstance(set(), typing.Set)
-        assert not isinstance({}, typing.Set)
-        t = typing.Set[int]
-        assert isinstance(set(), t)
-        assert isinstance({42}, t)
-        assert not isinstance({''}, t)
 
     def test_frozenset(self):
         assert issubclass(frozenset, typing.FrozenSet)
         assert not issubclass(set, typing.FrozenSet)
-        assert isinstance(frozenset(), typing.FrozenSet)
-        assert not isinstance({}, typing.FrozenSet)
-        t = typing.FrozenSet[int]
-        assert isinstance(frozenset(), t)
-        assert isinstance(frozenset({42}), t)
-        assert not isinstance(frozenset({''}), t)
-        assert not isinstance({42}, t)
-
-    def test_mapping_views(self):
-        # TODO: These tests are kind of lame.
-        assert isinstance({}.keys(), typing.KeysView)
-        assert isinstance({}.items(), typing.ItemsView)
-        assert isinstance({}.values(), typing.ValuesView)
 
     def test_dict(self):
         assert issubclass(dict, typing.Dict)
-        assert isinstance({}, typing.Dict)
-        assert not isinstance([], typing.Dict)
-        t = typing.Dict[int, str]
-        assert isinstance({}, t)
-        assert isinstance({42: ''}, t)
-        assert not isinstance({42: 42}, t)
-        assert not isinstance({'': 42}, t)
-        assert not isinstance({'': ''}, t)
 
     def test_no_list_instantiation(self):
         with self.assertRaises(TypeError):
@@ -1191,8 +1046,6 @@
             yield 42
         g = foo()
         assert issubclass(type(g), typing.Generator)
-        assert isinstance(g, typing.Generator)
-        assert not isinstance(foo, typing.Generator)
         assert issubclass(typing.Generator[Manager, Employee, Manager],
                           typing.Generator[Employee, Manager, Employee])
         assert not issubclass(typing.Generator[Manager, Manager, Manager],
@@ -1228,12 +1081,6 @@
         assert len(MMB[str, str]()) == 0
         assert len(MMB[KT, VT]()) == 0
 
-    def test_recursive_dict(self):
-        D = typing.Dict[int, 'D']  # Uses a _ForwardRef
-        assert isinstance({}, D)  # Easy
-        assert isinstance({0: {}}, D)  # Touches _ForwardRef
-        assert isinstance({0: {0: {}}}, D)  # Etc...
-
 
 class NamedTupleTests(TestCase):
 
@@ -1294,8 +1141,6 @@
     def test_basics(self):
         pat = re.compile('[a-z]+', re.I)
         assert issubclass(pat.__class__, Pattern)
-        assert isinstance(pat, Pattern[str])
-        assert not isinstance(pat, Pattern[bytes])
         assert issubclass(type(pat), Pattern)
         assert issubclass(type(pat), Pattern[str])
 
@@ -1307,12 +1152,10 @@
         assert issubclass(type(mat), Match[str])
 
         p = Pattern[Union[str, bytes]]
-        assert isinstance(pat, p)
         assert issubclass(Pattern[str], Pattern)
         assert issubclass(Pattern[str], p)
 
         m = Match[Union[bytes, str]]
-        assert isinstance(mat, m)
         assert issubclass(Match[bytes], Match)
         assert issubclass(Match[bytes], m)
 
@@ -1327,6 +1170,12 @@
         with self.assertRaises(TypeError):
             # Too complicated?
             m[str]
+        with self.assertRaises(TypeError):
+            # We don't support isinstance().
+            isinstance(42, Pattern)
+        with self.assertRaises(TypeError):
+            # We don't support isinstance().
+            isinstance(42, Pattern[str])
 
     def test_repr(self):
         assert repr(Pattern) == 'Pattern[~AnyStr]'
diff --git a/Lib/typing.py b/Lib/typing.py
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -176,6 +176,9 @@
             self.__forward_evaluated__ = True
         return self.__forward_value__
 
+    def __instancecheck__(self, obj):
+        raise TypeError("Forward references cannot be used with isinstance().")
+
     def __subclasscheck__(self, cls):
         if not self.__forward_evaluated__:
             globalns = self.__forward_frame__.f_globals
@@ -186,16 +189,6 @@
                 return False  # Too early.
         return issubclass(cls, self.__forward_value__)
 
-    def __instancecheck__(self, obj):
-        if not self.__forward_evaluated__:
-            globalns = self.__forward_frame__.f_globals
-            localns = self.__forward_frame__.f_locals
-            try:
-                self._eval_type(globalns, localns)
-            except NameError:
-                return False  # Too early.
-        return isinstance(obj, self.__forward_value__)
-
     def __repr__(self):
         return '_ForwardRef(%r)' % (self.__forward_arg__,)
 
@@ -259,8 +252,7 @@
                               self.impl_type, self.type_checker)
 
     def __instancecheck__(self, obj):
-        return (isinstance(obj, self.impl_type) and
-                isinstance(self.type_checker(obj), self.type_var))
+        raise TypeError("Type aliases cannot be used with isinstance().")
 
     def __subclasscheck__(self, cls):
         if cls is Any:
@@ -332,8 +324,8 @@
         self = super().__new__(cls, name, bases, namespace, _root=_root)
         return self
 
-    def __instancecheck__(self, instance):
-        return True
+    def __instancecheck__(self, obj):
+        raise TypeError("Any cannot be used with isinstance().")
 
     def __subclasscheck__(self, cls):
         if not isinstance(cls, type):
@@ -548,9 +540,8 @@
     def __hash__(self):
         return hash(self.__union_set_params__)
 
-    def __instancecheck__(self, instance):
-        return (self.__union_set_params__ is not None and
-                any(isinstance(instance, t) for t in self.__union_params__))
+    def __instancecheck__(self, obj):
+        raise TypeError("Unions cannot be used with isinstance().")
 
     def __subclasscheck__(self, cls):
         if cls is Any:
@@ -709,18 +700,8 @@
     def __hash__(self):
         return hash(self.__tuple_params__)
 
-    def __instancecheck__(self, t):
-        if not isinstance(t, tuple):
-            return False
-        if self.__tuple_params__ is None:
-            return True
-        if self.__tuple_use_ellipsis__:
-            p = self.__tuple_params__[0]
-            return all(isinstance(x, p) for x in t)
-        else:
-            return (len(t) == len(self.__tuple_params__) and
-                    all(isinstance(x, p)
-                        for x, p in zip(t, self.__tuple_params__)))
+    def __instancecheck__(self, obj):
+        raise TypeError("Tuples cannot be used with isinstance().")
 
     def __subclasscheck__(self, cls):
         if cls is Any:
@@ -826,57 +807,14 @@
     def __hash__(self):
         return hash(self.__args__) ^ hash(self.__result__)
 
-    def __instancecheck__(self, instance):
-        if not callable(instance):
-            return False
+    def __instancecheck__(self, obj):
+        # For unparametrized Callable we allow this, because
+        # typing.Callable should be equivalent to
+        # collections.abc.Callable.
         if self.__args__ is None and self.__result__ is None:
-            return True
-        assert self.__args__ is not None
-        assert self.__result__ is not None
-        my_args, my_result = self.__args__, self.__result__
-        import inspect  # TODO: Avoid this import.
-        # Would it be better to use Signature objects?
-        try:
-            (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults,
-             annotations) = inspect.getfullargspec(instance)
-        except TypeError:
-            return False  # We can't find the signature.  Give up.
-        msg = ("When testing isinstance(<callable>, Callable[...], "
-               "<calleble>'s annotations must be types.")
-        if my_args is not Ellipsis:
-            if kwonlyargs and (not kwonlydefaults or
-                               len(kwonlydefaults) < len(kwonlyargs)):
-                return False
-            if isinstance(instance, types.MethodType):
-                # For methods, getfullargspec() includes self/cls,
-                # but it's not part of the call signature, so drop it.
-                del args[0]
-            min_call_args = len(args)
-            if defaults:
-                min_call_args -= len(defaults)
-            if varargs:
-                max_call_args = 999999999
-                if len(args) < len(my_args):
-                    args += [varargs] * (len(my_args) - len(args))
-            else:
-                max_call_args = len(args)
-            if not min_call_args <= len(my_args) <= max_call_args:
-                return False
-            for my_arg_type, name in zip(my_args, args):
-                if name in annotations:
-                    annot_type = _type_check(annotations[name], msg)
-                else:
-                    annot_type = Any
-                if not issubclass(my_arg_type, annot_type):
-                    return False
-                # TODO: If mutable type, check invariance?
-        if 'return' in annotations:
-            annot_return_type = _type_check(annotations['return'], msg)
-            # Note contravariance here!
-            if not issubclass(annot_return_type, my_result):
-                return False
-        # Can't find anything wrong...
-        return True
+            return isinstance(obj, collections_abc.Callable)
+        else:
+            raise TypeError("Callable[] cannot be used with isinstance().")
 
     def __subclasscheck__(self, cls):
         if cls is Any:
@@ -1073,13 +1011,6 @@
             return False
         return issubclass(cls, self.__extra__)
 
-    def __instancecheck__(self, obj):
-        if super().__instancecheck__(obj):
-            return True
-        if self.__extra__ is None:
-            return False
-        return isinstance(obj, self.__extra__)
-
 
 class Generic(metaclass=GenericMeta):
     """Abstract base class for generic types.
@@ -1234,6 +1165,9 @@
     from Generic.
     """
 
+    def __instancecheck__(self, obj):
+        raise TypeError("Protocols cannot be used with isinstance().")
+
     def __subclasscheck__(self, cls):
         if not self._is_protocol:
             # No structural checks since this isn't a protocol.
@@ -1399,19 +1333,7 @@
 ByteString.register(type(memoryview(b'')))
 
 
-class _ListMeta(GenericMeta):
-
-    def __instancecheck__(self, obj):
-        if not super().__instancecheck__(obj):
-            return False
-        itemtype = self.__parameters__[0]
-        for x in obj:
-            if not isinstance(x, itemtype):
-                return False
-        return True
-
-
-class List(list, MutableSequence[T], metaclass=_ListMeta):
+class List(list, MutableSequence[T]):
 
     def __new__(cls, *args, **kwds):
         if _geqv(cls, List):
@@ -1420,19 +1342,7 @@
         return list.__new__(cls, *args, **kwds)
 
 
-class _SetMeta(GenericMeta):
-
-    def __instancecheck__(self, obj):
-        if not super().__instancecheck__(obj):
-            return False
-        itemtype = self.__parameters__[0]
-        for x in obj:
-            if not isinstance(x, itemtype):
-                return False
-        return True
-
-
-class Set(set, MutableSet[T], metaclass=_SetMeta):
+class Set(set, MutableSet[T]):
 
     def __new__(cls, *args, **kwds):
         if _geqv(cls, Set):
@@ -1441,7 +1351,7 @@
         return set.__new__(cls, *args, **kwds)
 
 
-class _FrozenSetMeta(_SetMeta):
+class _FrozenSetMeta(GenericMeta):
     """This metaclass ensures set is not a subclass of FrozenSet.
 
     Without this metaclass, set would be considered a subclass of
@@ -1454,11 +1364,6 @@
             return False
         return super().__subclasscheck__(cls)
 
-    def __instancecheck__(self, obj):
-        if issubclass(obj.__class__, Set):
-            return False
-        return super().__instancecheck__(obj)
-
 
 class FrozenSet(frozenset, AbstractSet[T_co], metaclass=_FrozenSetMeta):
 
@@ -1488,20 +1393,7 @@
     pass
 
 
-class _DictMeta(GenericMeta):
-
-    def __instancecheck__(self, obj):
-        if not super().__instancecheck__(obj):
-            return False
-        keytype, valuetype = self.__parameters__
-        for key, value in obj.items():
-            if not (isinstance(key, keytype) and
-                    isinstance(value, valuetype)):
-                return False
-        return True
-
-
-class Dict(dict, MutableMapping[KT, VT], metaclass=_DictMeta):
+class Dict(dict, MutableMapping[KT, VT]):
 
     def __new__(cls, *args, **kwds):
         if _geqv(cls, Dict):

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list