Bug report
Bug description:
According to the Python docs, annotate functions need to be actual functions. However, the C code doesn't enforce this, it enforces (using PyCallable_Check()) that the annotate 'function' is any callable:
| staticint |
| function___annotate___set_impl(PyFunctionObject*self, PyObject*value) |
| /*[clinic end generated code: output=05b7dfc07ada66cd input=eb6225e358d97448]*/ |
| { |
| if (value==NULL) { |
| PyErr_SetString(PyExc_TypeError, |
| "__annotate__ cannot be deleted"); |
| return-1; |
| } |
| if (Py_IsNone(value)) { |
| Py_XSETREF(self->func_annotate, value); |
| return0; |
| } |
| elseif (PyCallable_Check(value)) { |
| Py_XSETREF(self->func_annotate, Py_XNewRef(value)); |
| Py_CLEAR(self->func_annotations); |
| return0; |
| } |
| else { |
| PyErr_SetString(PyExc_TypeError, |
| "__annotate__ must be callable or None"); |
| return-1; |
| } |
| } |
This initially seems fine, but leads to some weird bugs.
classC:
def__call__(self, format, /):
ifformat>2:
raiseNotImplementedErrorreturn {'x': int}
deff(x): ...
f.__annotate__=C()
fromannotationlibimportget_annotations, Formatget_annotations(f, format=Format.STRING) # AttributeError: 'C' object has no attribute '__closure__' ...And similar for get_annotations(f, format=Format.FORWARDREF), trying to find the annotation function's __builtins__, which only exists on functions (not arbitrary callables).
I'm happy to make a PR to replace the PyCallable_Check() with PyFunction_Check() in the relevant C code for setting __annotate__, but I guess this might be a breaking change? I'm not sure, so I thought I'd check first before making it. The other option would be checking for the presence of __closure__/__builtins__/etc. before accessing them in annotationlib.
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
Bug report
Bug description:
According to the Python docs, annotate functions need to be actual functions. However, the C code doesn't enforce this, it enforces (using
PyCallable_Check()) that the annotate 'function' is any callable:cpython/Objects/funcobject.c
Lines 865 to 888 in 9cb8c52
This initially seems fine, but leads to some weird bugs.
And similar for
get_annotations(f, format=Format.FORWARDREF), trying to find the annotation function's__builtins__, which only exists on functions (not arbitrary callables).I'm happy to make a PR to replace the
PyCallable_Check()withPyFunction_Check()in the relevant C code for setting__annotate__, but I guess this might be a breaking change? I'm not sure, so I thought I'd check first before making it. The other option would be checking for the presence of__closure__/__builtins__/etc. before accessing them inannotationlib.CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs