[BUG] cpdef module-level variables not exposed to Python #3959
Describe the bug
# test_cpdef_module_var.pyx ... cpdef str abc = 'this is abc' ...
I would expect that I can access this Python string in the Python space simply by
# test_cpdef_module_var.pyx ... cpdef str _abc = 'this is abc' abc = _abc ...
which is both counterintuitive and cumbersome. I tried searching in the issue tracker but it doesn't seem to be reported yet, and the closest report I found is this (#656) but not exactly the same, so I hope I am simply missing something obvious...
Environment (please complete the following information):
The text was updated successfully, but these errors were encountered:
@leofang cpdef module level variables don't actually exist (hence they don't work) - in most versions of Python it isn't possible to implement module level properties so there's simply not way for expose a C variable for Python. Obviously for your
In more recent versions it might be possible to do using a module-level
Cython should probably tell you that they don't work, so this bug is really a failure of error reporting.
Hi @da-woods Thanks for quick reply during the holiday season!
Interesting, though I am more confused. I thought that module-level
$ cat test_cython_cpdef1.pxd cdef str abc $ cat test_cython_cpdef1.pyx cdef str abc = 'xyz' $ cat test_cython_cpdef2.pyx from test_cython_cpdef1 cimport abc cpdef print_str(): print(abc) # so calling test_cython_cpdef2.print_str() in Python will output "xyz"
So what's special with
By recent version do you mean Python 3.9+?
So I suppose there're two failures for this bug:
Am I right?
Right - I think:
Using PEP 526 would allow readonly variables on Python 3.7+ (so probably isn't a complete solution)
This has the problem that the Python user can do
Point 2 is essentially #656 (although possibly with different syntax - it's suggesting using
Thanks, @da-woods. I understand now what you meant by out of sync. This is certainly unexpected to me:
# test_cpdef_module_var.pyx cpdef str _abc = 'this is abc' abc = _abc cpdef get_python_var(): print(abc) cpdef set_cython_var(a): global _abc _abc = a cpdef get_cython_var(): print(_abc)
>>> import test_cpdef_module_var >>> test_cpdef_module_var.abc 'this is abc' >>> test_cpdef_module_var.get_python_var() this is abc >>> test_cpdef_module_var.get_cython_var() this is abc >>> test_cpdef_module_var.set_cython_var('xyz') >>> test_cpdef_module_var.get_cython_var() xyz >>> test_cpdef_module_var.get_python_var() # <-- out of sync! this is abc
Though I think for my purposes having
A module just stores the attributes in a simple dict, so there's no real control or hooks for modifying what happens when names are accessed. As of Python 3.7 and PEP 562 a
Cython would really need to produce a ModuleType subclass. Multi-phase initialisation supports