From 45ed0f861c41204d64ad77ce82cad93f4eea5d88 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 30 Aug 2016 15:51:27 -0700 Subject: [PATCH] Make Mapping covariant in keys (too). --- python2/test_typing.py | 10 +++++----- python2/typing.py | 7 +++++-- src/test_typing.py | 10 +++++----- src/typing.py | 9 ++++++--- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/python2/test_typing.py b/python2/test_typing.py index d72a5896..d7675377 100644 --- a/python2/test_typing.py +++ b/python2/test_typing.py @@ -838,15 +838,15 @@ def test_covariance_sequence(self): typing.Sequence[Manager]) def test_covariance_mapping(self): - # Ditto for Mapping (covariant in the value, invariant in the key). + # Ditto for Mapping (covariant in key and value). self.assertIsSubclass(typing.Mapping[Employee, Manager], - typing.Mapping[Employee, Employee]) - self.assertNotIsSubclass(typing.Mapping[Manager, Employee], + typing.Mapping[Employee, Employee]) + self.assertIsSubclass(typing.Mapping[Manager, Employee], typing.Mapping[Employee, Employee]) self.assertNotIsSubclass(typing.Mapping[Employee, Manager], - typing.Mapping[Manager, Manager]) + typing.Mapping[Manager, Manager]) self.assertNotIsSubclass(typing.Mapping[Manager, Employee], - typing.Mapping[Manager, Manager]) + typing.Mapping[Manager, Manager]) class CastTests(BaseTestCase): diff --git a/python2/typing.py b/python2/typing.py index 03632eaf..00987e34 100644 --- a/python2/typing.py +++ b/python2/typing.py @@ -459,6 +459,7 @@ def __subclasscheck__(self, cls): VT = TypeVar('VT') # Value type. T_co = TypeVar('T_co', covariant=True) # Any type covariant containers. V_co = TypeVar('V_co', covariant=True) # Any type covariant containers. +KT_co = TypeVar('KT', covariant=True) # Key type covariant containers. VT_co = TypeVar('VT_co', covariant=True) # Value type covariant containers. T_contra = TypeVar('T_contra', contravariant=True) # Ditto contravariant. @@ -1391,8 +1392,10 @@ class MutableSet(AbstractSet[T]): __extra__ = collections_abc.MutableSet -# NOTE: It is only covariant in the value type. -class Mapping(Sized, Iterable[KT], Container[KT], Generic[KT, VT_co]): +# NOTE: Covariance in the key type is theoretically problematic because +# there are methods with KT parameters, but in this case it's okay. +# See https://github.com/python/typeshed/issues/510. +class Mapping(Sized, Iterable[KT_co], Container[KT_co], Generic[KT_co, VT_co]): __extra__ = collections_abc.Mapping diff --git a/src/test_typing.py b/src/test_typing.py index 1f5e72fe..50c99d0b 100644 --- a/src/test_typing.py +++ b/src/test_typing.py @@ -863,15 +863,15 @@ def test_covariance_sequence(self): typing.Sequence[Manager]) def test_covariance_mapping(self): - # Ditto for Mapping (covariant in the value, invariant in the key). + # Ditto for Mapping (covariant in key and value). self.assertIsSubclass(typing.Mapping[Employee, Manager], - typing.Mapping[Employee, Employee]) - self.assertNotIsSubclass(typing.Mapping[Manager, Employee], + typing.Mapping[Employee, Employee]) + self.assertIsSubclass(typing.Mapping[Manager, Employee], typing.Mapping[Employee, Employee]) self.assertNotIsSubclass(typing.Mapping[Employee, Manager], - typing.Mapping[Manager, Manager]) + typing.Mapping[Manager, Manager]) self.assertNotIsSubclass(typing.Mapping[Manager, Employee], - typing.Mapping[Manager, Manager]) + typing.Mapping[Manager, Manager]) class CastTests(BaseTestCase): diff --git a/src/typing.py b/src/typing.py index b628ba3d..2348f69a 100644 --- a/src/typing.py +++ b/src/typing.py @@ -452,6 +452,7 @@ def __subclasscheck__(self, cls): VT = TypeVar('VT') # Value type. T_co = TypeVar('T_co', covariant=True) # Any type covariant containers. V_co = TypeVar('V_co', covariant=True) # Any type covariant containers. +KT_co = TypeVar('KT', covariant=True) # Key type covariant containers. VT_co = TypeVar('VT_co', covariant=True) # Value type covariant containers. T_contra = TypeVar('T_contra', contravariant=True) # Ditto contravariant. @@ -1454,13 +1455,15 @@ class MutableSet(AbstractSet[T], extra=collections_abc.MutableSet): pass -# NOTE: It is only covariant in the value type. +# NOTE: Covariance in the key type is theoretically problematic because +# there are methods with KT parameters, but in this case it's okay. +# See https://github.com/python/typeshed/issues/510. if hasattr(collections_abc, 'Collection'): - class Mapping(Collection[KT], Generic[KT, VT_co], + class Mapping(Collection[KT_co], Generic[KT_co, VT_co], extra=collections_abc.Mapping): pass else: - class Mapping(Sized, Iterable[KT], Container[KT], Generic[KT, VT_co], + class Mapping(Sized, Iterable[KT_co], Container[KT_co], Generic[KT_co, VT_co], extra=collections_abc.Mapping): pass