Skip to content

Commit

Permalink
Fix some more duplicate enum to_py utility code names (#5905)
Browse files Browse the repository at this point in the history
* Fix some more duplicate enum to_py utility code names

It's possible to declare an extern enum multiple times, in a way
that makes the declaration name the same. Therefore, also prefix
declaration names with the module qualified name where possible.

* Use scope mangling
  • Loading branch information
da-woods committed Feb 10, 2024
1 parent 5378181 commit 0185350
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 4 deletions.
15 changes: 11 additions & 4 deletions Cython/Compiler/PyrexTypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5429,19 +5429,26 @@ def type_list_identifier(types):
).sub, lambda match: _special_type_characters[match.group(1)])

def type_identifier(type, pyrex=False):
scope = None
decl = type.empty_declaration_code(pyrex=pyrex)
return type_identifier_from_declaration(decl)
entry = getattr(type, "entry", None)
if entry and entry.scope:
scope = entry.scope
return type_identifier_from_declaration(decl, scope=scope)

_type_identifier_cache = {}
def type_identifier_from_declaration(decl):
safe = _type_identifier_cache.get(decl)
def type_identifier_from_declaration(decl, scope = None):
key = (decl, scope)
safe = _type_identifier_cache.get(key)
if safe is None:
safe = decl
if scope:
safe = scope.mangle(prefix="", name=safe)
safe = re.sub(' +', ' ', safe)
safe = re.sub(' ?([^a-zA-Z0-9_]) ?', r'\1', safe)
safe = _escape_special_type_characters(safe)
safe = cap_length(re.sub('[^a-zA-Z0-9_]', lambda x: '__%X' % ord(x.group(0)), safe))
_type_identifier_cache[decl] = safe
_type_identifier_cache[key] = safe
return safe

def cap_length(s, max_prefix=63, max_len=1024):
Expand Down
36 changes: 36 additions & 0 deletions tests/run/cpdef_enums_import.srctree
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,39 @@ cpdef enum NamedEnumType:
cpdef enum EnumTypeNotInPyx:
AnotherEnumValue = 500

######## c_enum.h #############

enum CEnum {
CEnumVal1, CEnumVal2
};

######## external_enums1.pxd ######

cdef extern from "c_enum.h":
cpdef enum CEnum:
CEnumVal1
CEnumVal2

######## external_enums1.pyx ######

######## external_enums2.pxd ######

# external_enums1 and external_enums2 expose the same
# enum - this shouldn't lead to duplicate utility code
cdef extern from "c_enum.h":
cpdef enum CEnum:
CEnumVal1
CEnumVal2

######## external_enums2.pyx ######

######## no_enums.pyx ########

from enums cimport *
from enums_without_pyx cimport *
cimport enums_same_name
cimport external_enums1
cimport external_enums2

def get_named_enum_value():
return NamedEnumType.NamedEnumValue
Expand All @@ -59,6 +87,12 @@ def get_named_without_pyx():
# This'll generate a warning but return a c int
return EnumTypeNotInPyx.AnotherEnumValue

def get_external1():
return external_enums1.CEnumVal1

def get_external2():
return external_enums2.CEnumVal1

######## import_enums_test.py ########

# We can import enums with a star import.
Expand All @@ -81,3 +115,5 @@ assert no_enums.get_named_enum_value() == NamedEnumType.NamedEnumValue
assert no_enums.get_named_without_pyx() == 500

assert no_enums.get_from_enums_same_name() == enums_same_name.NamedEnumType.Value

assert no_enums.get_external1() == no_enums.get_external2()

0 comments on commit 0185350

Please sign in to comment.