In my code base, I use Cython to create shared object files from my modules. When I try to access the function __annotations__, I get the different behavior when I use Cython and when I do not, and I am wondering why this is the case:
I tried to produce a minimal reproducable example and came up with the following two files main.py and setup.py that I create within the same directory. Requirements: pip install Cython setuptools.
main.py
import setup
def test(name: str): pass
if __name__ == '__main__':
print(test.__annotations__, setup.test.__annotations__)
Setup.py
from Cython.Build import cythonize
from setuptools import setup, Extension
def test(name: str): pass
if __name__ == '__main__':
setup(python_requires='>=3.6', ext_modules=cythonize([Extension('setup', ['setup.py']), ], language_level="3"))
Execution
python main.py
> {'name': <class 'str'>}
> {'name': <class 'str'>}
python setup.py build_ext --inplace
python main.py
> {'name': <class 'str'>}
> {'name': 'unicode'}
I would have expected the __annotations__ to yield str also when using the shared object files, but it yields unicode instead. Why is this the case?
I use Python 3.9.2 and Cython version 0.29.21.
This is really more of a bug report than a question, so probably should be on the Cython bug tracker instead of here. Fortunately something similar already is reported.
There's a few things going on here:
unicode rather than str for strings that it knows are definitely unicode to ensure that both are supported.language_level=3 also affects it - strings are unicode whether or not it's running in Python 2 or 3. If you use language_level=3str it uses "native" strings instead and thus returns str (i.e. bytes on Py2, unicode on Py3).'unicode' rather than <class 'unicode'>. This reflects the future behaviour of Python. I didn't think this change was in Cython 0.29.x so I'm a little surprised that you see it here - it's probably a shortcut that's accidentally "right" in this case.The forthcoming Cython 3 release is aiming to improve treatments of annotations (and other introspection features) to be closer to Python behaviour. The 0.29 branch probably won't see changes to this.