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:
|
static int |
|
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); |
|
return 0; |
|
} |
|
else if (PyCallable_Check(value)) { |
|
Py_XSETREF(self->func_annotate, Py_XNewRef(value)); |
|
Py_CLEAR(self->func_annotations); |
|
return 0; |
|
} |
|
else { |
|
PyErr_SetString(PyExc_TypeError, |
|
"__annotate__ must be callable or None"); |
|
return -1; |
|
} |
|
} |
This initially seems fine, but leads to some weird bugs.
class C:
def __call__(self, format, /):
if format > 2:
raise NotImplementedError
return {'x': int}
def f(x): ...
f.__annotate__ = C()
from annotationlib import get_annotations, Format
get_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