Commit 9decfca1 authored by da-woods's avatar da-woods Committed by GitHub

Fix some issues with duplicated utilitycode (GH-3743)

* Avoid UtilityCode from cimport_from_pyx files
* Unique names for generated cfunc wrappers, avoid pxd pickle code
* Set .in_pxd on nodes prior to analyse_declarations

Fixes #3716
Fixes #3741
Fixes #3734
parent 8609e0fa
......@@ -285,11 +285,25 @@ def create_pyx_as_pxd_pipeline(context, result):
FlattenInListTransform,
WithTransform
])
from .Visitor import VisitorTransform
class SetInPxdTransform(VisitorTransform):
# A number of nodes have an "in_pxd" attribute which affects AnalyseDeclarationsTransform
# (for example controlling pickling generation). Set it, to make sure we don't mix them up with
# the importing main module.
# FIXME: This should be done closer to the parsing step.
def visit_StatNode(self, node):
if hasattr(node, "in_pxd"):
node.in_pxd = True
self.visitchildren(node)
return node
visit_Node = VisitorTransform.recurse_to_children
for stage in pyx_pipeline:
pipeline.append(stage)
if isinstance(stage, AnalyseDeclarationsTransform):
# This is the last stage we need.
break
pipeline.insert(-1, SetInPxdTransform())
break # This is the last stage we need.
def fake_pxd(root):
for entry in root.scope.entries.values():
if not entry.in_cinclude:
......
......@@ -3252,7 +3252,16 @@ class CFuncType(CType):
if not self.can_coerce_to_pyobject(env):
return False
from .UtilityCode import CythonUtilityCode
to_py_function = "__Pyx_CFunc_%s_to_py" % type_identifier(self, pyrex=True)
# include argument names into the c function name to ensure cname is unique
# between functions with identical types but different argument names
from .Symtab import punycodify_name
def arg_name_part(arg):
return "%s%s" % (len(arg.name), punycodify_name(arg.name)) if arg.name else "0"
arg_names = [ arg_name_part(arg) for arg in self.args ]
arg_names = "_".join(arg_names)
safe_typename = type_identifier(self, pyrex=True)
to_py_function = "__Pyx_CFunc_%s_to_py_%s" % (safe_typename, arg_names)
for arg in self.args:
if not arg.type.is_pyobject and not arg.type.create_from_py_utility_code(env):
......
......@@ -230,3 +230,39 @@ def test_cdef_class_params(a, b):
TypeError: Argument 'b' has incorrect type (expected cfunc_convert.B, got cfunc_convert.A)
"""
return (<object>test_cdef_class_params_cfunc)(a, b)
# There were a few cases where duplicate utility code definitions (i.e. with the same name)
# could be generated, causing C compile errors. This file tests them.
cdef cfunc_dup_f1(x, r):
return "f1"
cdef cfunc_dup_f2(x1, r):
return "f2"
def make_map():
"""
https://github.com/cython/cython/issues/3716
This is testing the generation of wrappers for f1 and f2
>>> for k, f in make_map().items():
... print(k == f(0, 0)) # in both cases the functions should just return their name
True
True
# Test passing of keyword arguments
>>> print(make_map()['f1'](x=1, r=2))
f1
>>> make_map()['f1'](x1=1, r=2) # doctest: +ELLIPSIS
Traceback (most recent call last):
TypeError: ...
>>> print(make_map()['f2'](x1=1, r=2))
f2
>>> make_map()['f2'](x=1, r=2) # doctest: +ELLIPSIS
Traceback (most recent call last):
TypeError: ...
"""
cdef map = {
"f1": cfunc_dup_f1,
"f2": cfunc_dup_f2,
}
return map
PYTHON setup.py build_ext --inplace
PYTHON -c "import modb; modb.ClassB()"
#################### moda.pyx ####################
cdef class ClassA:
cdef int[2] a
#################### modb.pyx #####################
from moda cimport ClassA
cdef class ClassB(ClassA):
cdef int[2] b
###################### setup.py ###################
from setuptools import setup
from Cython.Build import cythonize
import Cython.Compiler.Options
Cython.Compiler.Options.cimport_from_pyx = True
setup(
ext_modules = cythonize(["moda.pyx", "modb.pyx"],
compiler_directives={'language_level': 3})
)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment