10000 Add some tests based on coverage report: Part 2 (#375) · python/typing@370a137 · GitHub
[go: up one dir, main page]

Skip to content

Commit 370a137

Browse files
authored
Add some tests based on coverage report: Part 2 (#375)
* Add more tests based on coverage report * Fix lint on PY2 * Simplify PR to only tests and tiny code clean-up * Remove _right_ code on PY2 * Re-run Travis
1 parent 58c86ad commit 370a137

File tree

4 files changed

+107
-9
lines changed

4 files changed

+107
-9
lines changed

python2/test_typing.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,11 @@ def test_repr(self):
255255
self.assertEqual(repr(u), 'typing.Union[%s.Employee, int]' % __name__)
256256
u = Union[int, Employee]
257257
self.assertEqual(repr(u), 'typing.Union[int, %s.Employee]' % __name__)
258+
T = TypeVar('T')
259+
u = Union[T, int][int]
260+
self.assertEqual(repr(u), repr(int))
261+
u = Union[List[int], int]
262+
self.assertEqual(repr(u), 'typing.Union[typing.List[int], int]')
258263

259264
def test_cannot_subclass(self):
260265
with self.assertRaises(TypeError):
@@ -303,6 +308,14 @@ def test_union_instance_type_error(self):
303308
with self.assertRaises(TypeError):
304309
isinstance(42, Union[int, str])
305310

311+
def test_no_eval_union(self):
312+
u = Union[int, str]
313+
self.assertIs(u._eval_type({}, {}), u)
314+
315+
def test_function_repr_union(self):
316+
def fun(): pass
317+
self.assertEqual(repr(Union[fun, int]), 'typing.Union[fun, int]')
318+
306319
def test_union_str_pattern(self):
307320
# Shouldn't crash; see http://bugs.python.org/issue25390
308321
A = Union[str, Pattern]
@@ -853,6 +866,8 @@ def test_fail_with_bare_generic(self):
853866
Tuple[Generic[T]]
854867
with self.assertRaises(TypeError):
855868
List[typing._Protocol]
869+
with self.assertRaises(TypeError):
870+
isinstance(1, Generic)
856871

857872
def test_type_erasure_special(self):
858873
T = TypeVar('T')
@@ -1191,6 +1206,19 @@ def test_syntax_error(self):
11911206
with self.assertRaises(SyntaxError):
11921207
Generic['/T']
11931208

1209+
def test_forwardref_subclass_type_error(self):
1210+
fr = typing._ForwardRef('int')
1211+
with self.assertRaises(TypeError):
1212+
issubclass(int, fr)
1213+
1214+
def test_forward_equality(self):
1215+
fr = typing._ForwardRef('int')
1216+
self.assertEqual(fr, typing._ForwardRef('int'))
1217+
self.assertNotEqual(List['int'], List[int])
1218+
1219+
def test_forward_repr(self):
1220+
self.assertEqual(repr(List['int']), "typing.List[_ForwardRef(%r)]" % 'int')
1221+
11941222

11951223
class OverloadTests(BaseTestCase):
11961224

@@ -1674,6 +1702,12 @@ def test_basics(self):
16741702
Pattern[Union[str, bytes]]
16751703
Match[Union[bytes, str]]
16761704

1705+
def test_alias_equality(self):
1706+
self.assertEqual(Pattern[str], Pattern[str])
1707+
self.assertNotEqual(Pattern[str], Pattern[bytes])
1708+
self.assertNotEqual(Pattern[str], Match[str])
1709+
self.assertNotEqual(Pattern[str], str)
1710+
16771711
def test_errors(self):
16781712
with self.assertRaises(TypeError):
16791713
# Doesn't fit AnyStr.
@@ -1688,6 +1722,9 @@ def test_errors(self):
16881722
with self.assertRaises(TypeError):
16891723
# We don't support isinstance().
16901724
isinstance(42, Pattern[str])
1725+
with self.assertRaises(TypeError):
1726+
# We don't support issubclass().
1727+
issubclass(Pattern[bytes], Pattern[str])
16911728

16921729
def test_repr(self):
16931730
self.assertEqual(repr(Pattern), 'Pattern[~AnyStr]')

python2/typing.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,15 @@ def _eval_type(self, globalns, localns):
226226
self.__forward_evaluated__ = True
227227
return self.__forward_value__
228228

229+
def __eq__(self, other):
230+
if not isinstance(other, _ForwardRef):
231+
return NotImplemented
232+
return (self.__forward_arg__ == other.__forward_arg__ and
233+
self.__forward_value__ == other.__forward_value__)
234+
235+
def __hash__(self):
236+
return hash((self.__forward_arg__, self.__forward_value__))
237+
229238
def __instancecheck__(self, obj):
230239
raise TypeError("Forward references cannot be used with isinstance().")
231240

@@ -282,6 +291,14 @@ def __getitem__(self, parameter):
282291
return self.__class__(self.name, parameter,
283292
self.impl_type, self.type_checker)
284293

294+
def __eq__(self, other):
295+
if not isinstance(other, _TypeAlias):
296+
return NotImplemented
297+
return self.name == other.name and self.type_var == other.type_var
298+
299+
def __hash__(self):
300+
return hash((self.name, self.type_var))
301+
285302
def __instancecheck__(self, obj):
286303
if not isinstance(self.type_var, TypeVar):
287304
raise TypeError("Parameterized type aliases cannot be used "
@@ -1049,10 +1066,9 @@ def __new__(cls, name, bases, namespace,
10491066
# with issubclass() and isinstance() in the same way as their
10501067
# collections.abc counterparts (e.g., isinstance([], Iterable)).
10511068
if (
1052-
# allow overriding
10531069
'__subclasshook__' not in namespace and extra or
1054-
hasattr(self.__subclasshook__, '__name__') and
1055-
self.__subclasshook__.__name__ == '__extrahook__'
1070+
# allow overriding
1071+
getattr(self.__subclasshook__, '__name__', '') == '__extrahook__'
10561072
):
10571073
self.__subclasshook__ = _make_subclasshook(self)
10581074

src/test_typing.py

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,11 @@ def test_repr(self):
258258
self.assertEqual(repr(u), 'typing.Union[%s.Employee, int]' % __name__)
259259
u = Union[int, Employee]
260260
self.assertEqual(repr(u), 'typing.Union[int, %s.Employee]' % __name__)
261+
T = TypeVar('T')
262+
u = Union[T, int][int]
263+
self.assertEqual(repr(u), repr(int))
264+
u = Union[List[int], int]
265+
self.assertEqual(repr(u), 'typing.Union[typing.List[int], int]')
261266

262267
def test_cannot_subclass(self):
263268
with self.assertRaises(TypeError):
@@ -308,6 +313,15 @@ def test_union_instance_type_error(self):
308313
with self.assertRaises(TypeError):
309314
isinstance(42, Union[int, str])
310315

316+
def test_no_eval_union(self):
317+
u = Union[int, str]
318+
def f(x: u): ...
319+
self.assertIs(get_type_hints(f)['x'], u)
320+
321+
def test_function_repr_union(self):
322+
def fun() -> int: ...
323+
self.assertEqual(repr(Union[fun, int]), 'typing.Union[fun, int]')
324+
311325
def test_union_str_pattern(self):
312326
# Shouldn't crash; see http://bugs.python.org/issue25390
313327
A = Union[str, Pattern]
@@ -892,6 +906,8 @@ def test_fail_with_bare_generic(self):
892906
Tuple[Generic[T]]
893907
with self.assertRaises(TypeError):
894908
List[typing._Protocol]
909+
with self.assertRaises(TypeError):
910+
isinstance(1, Generic)
895911

896912
def test_type_erasure_special(self):
897913
T = TypeVar('T')
@@ -1265,6 +1281,19 @@ def test_forwardref_instance_type_error(self):
12651281
with self.assertRaises(TypeError):
12661282
isinstance(42, fr)
12671283

1284+
def test_forwardref_subclass_type_error(self):
1285+
fr = typing._ForwardRef('int')
1286+
with self.assertRaises(TypeError):
1287+
issubclass(int, fr)
1288+
1289+
def test_forward_equality(self):
1290+
fr = typing._ForwardRef('int')
1291+
self.assertEqual(fr, typing._ForwardRef('int'))
1292+
self.assertNotEqual(List['int'], List[int])
1293+
1294+
def test_forward_repr(self):
1295+
self.assertEqual(repr(List['int']), "typing.List[_ForwardRef('int')]")
1296+
12681297
def test_union_forward(self):
12691298

12701299
def foo(a: Union['T']):
@@ -1472,11 +1501,16 @@ class A:
14721501
class B(A):
14731502
x: ClassVar[Optional['B']] = None
14741503
y: int
1504+
b: int
14751505
class CSub(B):
14761506
z: ClassVar['CSub'] = B()
14771507
class G(Generic[T]):
14781508
lst: ClassVar[List[T]] = []
14791509
1510+
class NoneAndForward:
1511+
parent: 'NoneAndForward'
1512+
meaning: None
1513+
14801514
class CoolEmployee(NamedTuple):
14811515
name: str
14821516
cool: int
@@ -1505,7 +1539,7 @@ def __add__(self, other):
15051539
# fake names for the sake of static analysis
15061540
ann_module = ann_module2 = ann_module3 = None
15071541
A = B = CSub = G = CoolEmployee = CoolEmployeeWithDefault = object
1508-
XMeth = XRepr = object
1542+
XMeth = XRepr = NoneAndForward = object
15091543

15101544
gth = get_type_hints
15111545

@@ -1540,6 +1574,8 @@ def test_get_type_hints_classes(self):
15401574
{'y': Optional[ann_module.C]})
15411575
self.assertEqual(gth(ann_module.S), {'x': str, 'y': str})
15421576
self.assertEqual(gth(ann_module.foo), {'x': int})
1577+
self.assertEqual(gth(NoneAndForward, globals()),
1578+
{'parent': NoneAndForward, 'meaning': type(None)})
15431579

15441580
@skipUnless(PY36, 'Python 3.6 required')
15451581
def test_respect_no_type_check(self):
@@ -1585,9 +1621,10 @@ def test_get_type_hints_ClassVar(self):
15851621
self.assertEqual(gth(ann_module2.CV, ann_module2.__dict__),
15861622
{'var': typing.ClassVar[ann_module2.CV]})
15871623
self.assertEqual(gth(B, globals()),
1588-
{'y': int, 'x': ClassVar[Optional[B]]})
1624+
{'y': int, 'x': ClassVar[Optional[B]], 'b': int})
15891625
self.assertEqual(gth(CSub, globals()),
1590-
{'z': ClassVar[CSub], 'y': int, 'x': ClassVar[Optional[B]]})
1626+
{'z': ClassVar[CSub], 'y': int, 'b': int,
1627+
'x': ClassVar[Optional[B]]})
15911628
self.assertEqual(gth(G), {'lst': ClassVar[List[T]]})
15921629

15931630

@@ -2271,6 +2308,12 @@ def test_basics(self):
22712308
Pattern[Union[str, bytes]]
22722309
Match[Union[bytes, str]]
22732310

2311+
def test_alias_equality(self):
2312+
self.assertEqual(Pattern[str], Pattern[str])
2313+
self.assertNotEqual(Pattern[str], Pattern[bytes])
2314+
self.assertNotEqual(Pattern[str], Match[str])
2315+
self.assertNotEqual(Pattern[str], str)
2316+
22742317
def test_errors(self):
22752318
with self.assertRaises(TypeError):
22762319
# Doesn't fit AnyStr.
@@ -2285,6 +2328,9 @@ def test_errors(self):
22852328
with self.assertRaises(TypeError):
22862329
# We don't support isinstance().
22872330
isinstance(42, Pattern[str])
2331+
with self.assertRaises(TypeError):
2332+
# We don't support issubclass().
2333+
issubclass(Pattern[bytes], Pattern[str])
22882334

22892335
def test_repr(self):
22902336
self.assertEqual(repr(Pattern), 'Pattern[~AnyStr]')

src/typing.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -985,10 +985,9 @@ def __new__(cls, name, bases, namespace,
985985
# with issubclass() and isinstance() in the same way as their
986986
# collections.abc counterparts (e.g., isinstance([], Iterable)).
987987
if (
988-
# allow overriding
989988
'__subclasshook__' not in namespace and extra or
990-
hasattr(self.__subclasshook__, '__name__') and
991-
self.__subclasshook__.__name__ == '__extrahook__'
989+
# allow overriding
990+
getattr(self.__subclasshook__, '__name__', '') == '__extrahook__'
992991
):
993992
self.__subclasshook__ = _make_subclasshook(self)
994993
if isinstance(extra, abc.ABCMeta):

0 commit comments

Comments
 (0)
0