self.assertEqual(f.__annotate__(annotationlib.Format.VALUE), annos)
self.assertEqual(f.__annotations__, annos)
+ def test_set_annotations(self):
+ function_code = textwrap.dedent("""
+ def f(x: int):
+ pass
+ """)
+ class_code = textwrap.dedent("""
+ class f:
+ x: int
+ """)
+ for future in (False, True):
+ for label, code in (("function", function_code), ("class", class_code)):
+ with self.subTest(future=future, label=label):
+ if future:
+ code = "from __future__ import annotations\n" + code
+ ns = run_code(code)
+ f = ns["f"]
+ anno = "int" if future else int
+ self.assertEqual(f.__annotations__, {"x": anno})
+
+ f.__annotations__ = {"x": str}
+ self.assertEqual(f.__annotations__, {"x": str})
+
def test_name_clash_with_format(self):
# this test would fail if __annotate__'s parameter was called "format"
# during symbol table construction
return -1;
}
- int result;
PyObject *dict = PyType_GetDict(type);
- if (value != NULL) {
- /* set */
- result = PyDict_SetItem(dict, &_Py_ID(__annotations_cache__), value);
- } else {
- /* delete */
- result = PyDict_Pop(dict, &_Py_ID(__annotations_cache__), NULL);
- if (result == 0) {
- PyErr_SetString(PyExc_AttributeError, "__annotations__");
+ int result = PyDict_ContainsString(dict, "__annotations__");
+ if (result < 0) {
+ Py_DECREF(dict);
+ return -1;
+ }
+ if (result) {
+ // If __annotations__ is currently in the dict, we update it,
+ if (value != NULL) {
+ result = PyDict_SetItem(dict, &_Py_ID(__annotations__), value);
+ } else {
+ result = PyDict_Pop(dict, &_Py_ID(__annotations__), NULL);
+ if (result == 0) {
+ // Somebody else just deleted it?
+ PyErr_SetString(PyExc_AttributeError, "__annotations__");
+ Py_DECREF(dict);
+ return -1;
+ }
+ }
+ if (result < 0) {
Py_DECREF(dict);
return -1;
}
+ // Also clear __annotations_cache__ just in case.
+ result = PyDict_Pop(dict, &_Py_ID(__annotations_cache__), NULL);
+ }
+ else {
+ // Else we update only __annotations_cache__.
+ if (value != NULL) {
+ /* set */
+ result = PyDict_SetItem(dict, &_Py_ID(__annotations_cache__), value);
+ } else {
+ /* delete */
+ result = PyDict_Pop(dict, &_Py_ID(__annotations_cache__), NULL);
+ if (result == 0) {
+ PyErr_SetString(PyExc_AttributeError, "__annotations__");
+ Py_DECREF(dict);
+ return -1;
+ }
+ }
}
if (result < 0) {
Py_DECREF(dict);