Skip to content

Commit fd6125d

Browse files
committed
Add non-function annotate tests
1 parent 414251b commit fd6125d

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed

Lib/test/test_annotationlib.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import itertools
99
import pickle
1010
from string.templatelib import Template, Interpolation
11+
import types
1112
import typing
1213
import sys
1314
import unittest
@@ -1590,6 +1591,141 @@ def annotate(format, /):
15901591
# Some non-Format value
15911592
annotationlib.call_annotate_function(annotate, 7)
15921593

1594+
def test_basic_non_function_annotate(self):
1595+
class Annotate:
1596+
def __call__(self, format, /, __Format=Format,
1597+
__NotImplementedError=NotImplementedError):
1598+
if format == __Format.VALUE:
1599+
return {'x': str}
1600+
elif format == __Format.VALUE_WITH_FAKE_GLOBALS:
1601+
return {'x': int}
1602+
elif format == __Format.STRING:
1603+
return {'x': "float"}
1604+
else:
1605+
raise __NotImplementedError(format)
1606+
1607+
annotations = annotationlib.call_annotate_function(Annotate(), Format.VALUE)
1608+
self.assertEqual(annotations, {"x": str})
1609+
1610+
annotations = annotationlib.call_annotate_function(Annotate(), Format.STRING)
1611+
self.assertEqual(annotations, {"x": "float"})
1612+
1613+
with self.assertRaisesRegex(
1614+
AttributeError,
1615+
"annotate function requires __code__ attribute"
1616+
):
1617+
annotations = annotationlib.call_annotate_function(
1618+
Annotate(), Format.FORWARDREF
1619+
)
1620+
1621+
def test_non_function_annotate(self):
1622+
class Annotate:
1623+
called_formats = []
1624+
1625+
def __call__(self, format=None, *, _self=None):
1626+
if _self is not None:
1627+
self, format = _self, self
1628+
1629+
self.called_formats.append(format)
1630+
if format <= 2: # VALUE or VALUE_WITH_FAKE_GLOBALS
1631+
return {"x": MyType}
1632+
raise NotImplementedError
1633+
1634+
@property
1635+
def __defaults__(self):
1636+
return (None,)
1637+
1638+
@property
1639+
def __kwdefaults__(self):
1640+
return {"_self": self}
1641+
1642+
@property
1643+
def __code__(self):
1644+
return self.__call__.__code__
1645+
1646+
annotate = Annotate()
1647+
1648+
with self.assertRaises(NameError):
1649+
annotationlib.call_annotate_function(annotate, Format.VALUE)
1650+
self.assertEqual(annotate.called_formats[-1], Format.VALUE)
1651+
1652+
annotations = annotationlib.call_annotate_function(annotate, Format.STRING)
1653+
self.assertEqual(annotations["x"], "MyType")
1654+
self.assertIn(Format.STRING, annotate.called_formats)
1655+
self.assertEqual(annotate.called_formats[-1], Format.VALUE_WITH_FAKE_GLOBALS)
1656+
1657+
annotations = annotationlib.call_annotate_function(annotate, Format.FORWARDREF)
1658+
self.assertEqual(annotations["x"], support.EqualToForwardRef("MyType"))
1659+
self.assertIn(Format.FORWARDREF, annotate.called_formats)
1660+
self.assertEqual(annotate.called_formats[-1], Format.VALUE_WITH_FAKE_GLOBALS)
1661+
1662+
def test_full_non_function_annotate(self):
1663+
def outer():
1664+
local = str
1665+
1666+
class Annotate:
1667+
called_formats = []
1668+
1669+
def __call__(self, format=None, *, _self=None):
1670+
nonlocal local
1671+
if _self is not None:
1672+
self, format = _self, self
1673+
1674+
self.called_formats.append(format)
1675+
if format == 1: # VALUE
1676+
return {"x": MyClass, "y": int, "z": local}
1677+
if format == 2: # VALUE_WITH_FAKE_GLOBALS
1678+
return {"w": unknown, "x": MyClass, "y": int, "z": local}
1679+
raise NotImplementedError
1680+
1681+
@property
1682+
def __globals__(self):
1683+
return {"MyClass": MyClass}
1684+
1685+
@property
1686+
def __builtins__(self):
1687+
return {"int": int}
1688+
1689+
@property
1690+
def __closure__(self):
1691+
return (types.CellType(str),)
1692+
1693+
@property
1694+
def __defaults__(self):
1695+
return (None,)
1696+
1697+
@property
1698+
def __kwdefaults__(self):
1699+
return {"_self": self}
1700+
1701+
@property
1702+
def __code__(self):
1703+
return self.__call__.__code__
1704+
1705+
return Annotate()
1706+
1707+
annotate = outer()
1708+
1709+
self.assertEqual(
1710+
annotationlib.call_annotate_function(annotate, Format.VALUE),
1711+
{"x": MyClass, "y": int, "z": str}
1712+
)
1713+
self.assertEqual(annotate.called_formats[-1], Format.VALUE)
1714+
1715+
self.assertEqual(
1716+
annotationlib.call_annotate_function(annotate, Format.STRING),
1717+
{"w": "unknown", "x": "MyClass", "y": "int", "z": "local"}
1718+
)
1719+
self.assertIn(Format.STRING, annotate.called_formats)
1720+
self.assertEqual(annotate.called_formats[-1], Format.VALUE_WITH_FAKE_GLOBALS)
1721+
1722+
self.assertEqual(
1723+
annotationlib.call_annotate_function(annotate, Format.FORWARDREF),
1724+
{"w": support.EqualToForwardRef("unknown"), "x": MyClass, "y": int, "z": str}
1725+
)
1726+
self.assertIn(Format.FORWARDREF, annotate.called_formats)
1727+
self.assertEqual(annotate.called_formats[-1], Format.VALUE_WITH_FAKE_GLOBALS)
1728+
15931729
def test_error_from_value_raised(self):
15941730
# Test that the error from format.VALUE is raised
15951731
# if all formats fail

0 commit comments

Comments
 (0)