|
6 | 6 | import functools
|
7 | 7 | import itertools
|
8 | 8 | import pickle
|
| 9 | +import typing |
9 | 10 | import unittest
|
10 | 11 | from annotationlib import (
|
11 | 12 | Format,
|
|
15 | 16 | annotations_to_string,
|
16 | 17 | type_repr,
|
17 | 18 | )
|
18 |
| -from typing import Unpack |
| 19 | +from typing import ( |
| 20 | + Unpack, |
| 21 | + get_type_hints, |
| 22 | + List, |
| 23 | + Union, |
| 24 | +) |
19 | 25 |
|
20 | 26 | from test import support
|
21 | 27 | from test.test_inspect import inspect_stock_annotations
|
@@ -1205,6 +1211,159 @@ def test_annotations_to_string(self):
|
1205 | 1211 | )
|
1206 | 1212 |
|
1207 | 1213 |
|
| 1214 | +class A: |
| 1215 | + pass |
| 1216 | + |
| 1217 | + |
| 1218 | +class ForwardRefTests(unittest.TestCase): |
| 1219 | + def test_forwardref_instance_type_error(self): |
| 1220 | + fr = ForwardRef('int') |
| 1221 | + with self.assertRaises(TypeError): |
| 1222 | + isinstance(42, fr) |
| 1223 | + |
| 1224 | + def test_forwardref_subclass_type_error(self): |
| 1225 | + fr = ForwardRef('int') |
| 1226 | + with self.assertRaises(TypeError): |
| 1227 | + issubclass(int, fr) |
| 1228 | + |
| 1229 | + def test_forwardref_only_str_arg(self): |
| 1230 | + with self.assertRaises(TypeError): |
| 1231 | + ForwardRef(1) # only `str` type is allowed |
| 1232 | + |
| 1233 | + def test_forward_equality(self): |
| 1234 | + fr = ForwardRef('int') |
| 1235 | + self.assertEqual(fr, ForwardRef('int')) |
| 1236 | + self.assertNotEqual(List['int'], List[int]) |
| 1237 | + self.assertNotEqual(fr, ForwardRef('int', module=__name__)) |
| 1238 | + frm = ForwardRef('int', module=__name__) |
| 1239 | + self.assertEqual(frm, ForwardRef('int', module=__name__)) |
| 1240 | + self.assertNotEqual(frm, ForwardRef('int', module='__other_name__')) |
| 1241 | + |
| 1242 | + def test_forward_equality_get_type_hints(self): |
| 1243 | + c1 = ForwardRef('C') |
| 1244 | + c1_gth = ForwardRef('C') |
| 1245 | + c2 = ForwardRef('C') |
| 1246 | + c2_gth = ForwardRef('C') |
| 1247 | + |
| 1248 | + class C: |
| 1249 | + pass |
| 1250 | + def foo(a: c1_gth, b: c2_gth): |
| 1251 | + pass |
| 1252 | + |
| 1253 | + self.assertEqual(get_type_hints(foo, globals(), locals()), {'a': C, 'b': C}) |
| 1254 | + self.assertEqual(c1, c2) |
| 1255 | + self.assertEqual(c1, c1_gth) |
| 1256 | + self.assertEqual(c1_gth, c2_gth) |
| 1257 | + self.assertEqual(List[c1], List[c1_gth]) |
| 1258 | + self.assertNotEqual(List[c1], List[C]) |
| 1259 | + self.assertNotEqual(List[c1_gth], List[C]) |
| 1260 | + self.assertEqual(Union[c1, c1_gth], Union[c1]) |
| 1261 | + self.assertEqual(Union[c1, c1_gth, int], Union[c1, int]) |
| 1262 | + |
| 1263 | + def test_forward_equality_hash(self): |
| 1264 | + c1 = ForwardRef('int') |
| 1265 | + c1_gth = ForwardRef('int') |
| 1266 | + c2 = ForwardRef('int') |
| 1267 | + c2_gth = ForwardRef('int') |
| 1268 | + |
| 1269 | + def foo(a: c1_gth, b: c2_gth): |
| 1270 | + pass |
| 1271 | + get_type_hints(foo, globals(), locals()) |
| 1272 | + |
| 1273 | + self.assertEqual(hash(c1), hash(c2)) |
| 1274 | + self.assertEqual(hash(c1_gth), hash(c2_gth)) |
| 1275 | + self.assertEqual(hash(c1), hash(c1_gth)) |
| 1276 | + |
| 1277 | + c3 = ForwardRef('int', module=__name__) |
| 1278 | + c4 = ForwardRef('int', module='__other_name__') |
| 1279 | + |
| 1280 | + self.assertNotEqual(hash(c3), hash(c1)) |
| 1281 | + self.assertNotEqual(hash(c3), hash(c1_gth)) |
| 1282 | + self.assertNotEqual(hash(c3), hash(c4)) |
| 1283 | + self.assertEqual(hash(c3), hash(ForwardRef('int', module=__name__))) |
| 1284 | + |
| 1285 | + def test_forward_equality_namespace(self): |
| 1286 | + def namespace1(): |
| 1287 | + a = ForwardRef('A') |
| 1288 | + def fun(x: a): |
| 1289 | + pass |
| 1290 | + get_type_hints(fun, globals(), locals()) |
| 1291 | + return a |
| 1292 | + |
| 1293 | + def namespace2(): |
| 1294 | + a = ForwardRef('A') |
| 1295 | + |
| 1296 | + class A: |
| 1297 | + pass |
| 1298 | + def fun(x: a): |
| 1299 | + pass |
| 1300 | + |
| 1301 | + get_type_hints(fun, globals(), locals()) |
| 1302 | + return a |
| 1303 | + |
| 1304 | + self.assertEqual(namespace1(), namespace1()) |
| 1305 | + self.assertEqual(namespace1(), namespace2()) |
| 1306 | + |
| 1307 | + def test_forward_repr(self): |
| 1308 | + self.assertEqual(repr(List['int']), "typing.List[ForwardRef('int')]") |
| 1309 | + self.assertEqual(repr(List[ForwardRef('int', module='mod')]), |
| 1310 | + "typing.List[ForwardRef('int', module='mod')]") |
| 1311 | + |
| 1312 | + def test_forward_recursion_actually(self): |
| 1313 | + def namespace1(): |
| 1314 | + a = ForwardRef('A') |
| 1315 | + A = a |
| 1316 | + def fun(x: a): pass |
| 1317 | + |
| 1318 | + ret = get_type_hints(fun, globals(), locals()) |
| 1319 | + return a |
| 1320 | + |
| 1321 | + def namespace2(): |
| 1322 | + a = ForwardRef('A') |
| 1323 | + A = a |
| 1324 | + def fun(x: a): pass |
| 1325 | + |
| 1326 | + ret = get_type_hints(fun, globals(), locals()) |
| 1327 | + return a |
| 1328 | + |
| 1329 | + r1 = namespace1() |
| 1330 | + r2 = namespace2() |
| 1331 | + self.assertIsNot(r1, r2) |
| 1332 | + self.assertEqual(r1, r2) |
| 1333 | + |
| 1334 | + def test_syntax_error(self): |
| 1335 | + |
| 1336 | + with self.assertRaises(SyntaxError): |
| 1337 | + typing.Generic['/T'] |
| 1338 | + |
| 1339 | + def test_delayed_syntax_error(self): |
| 1340 | + |
| 1341 | + def foo(a: 'Node[T'): |
| 1342 | + pass |
| 1343 | + |
| 1344 | + with self.assertRaises(SyntaxError): |
| 1345 | + get_type_hints(foo) |
| 1346 | + |
| 1347 | + def test_syntax_error_empty_string(self): |
| 1348 | + for form in [typing.List, typing.Set, typing.Type, typing.Deque]: |
| 1349 | + with self.subTest(form=form): |
| 1350 | + with self.assertRaises(SyntaxError): |
| 1351 | + form[''] |
| 1352 | + |
| 1353 | + def test_or(self): |
| 1354 | + X = ForwardRef('X') |
| 1355 | + # __or__/__ror__ itself |
| 1356 | + self.assertEqual(X | "x", Union[X, "x"]) |
| 1357 | + self.assertEqual("x" | X, Union["x", X]) |
| 1358 | + |
| 1359 | + def test_multiple_ways_to_create(self): |
| 1360 | + X1 = Union["X"] |
| 1361 | + self.assertIsInstance(X1, ForwardRef) |
| 1362 | + X2 = ForwardRef("X") |
| 1363 | + self.assertIsInstance(X2, ForwardRef) |
| 1364 | + self.assertEqual(X1, X2) |
| 1365 | + |
| 1366 | + |
1208 | 1367 | class TestAnnotationLib(unittest.TestCase):
|
1209 | 1368 | def test__all__(self):
|
1210 | 1369 | support.check__all__(self, annotationlib)
|
0 commit comments