Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions autowrap/CodeGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ def create_pyx_file(self, debug: bool = False) -> None:
self.setup_cimport_paths()
self.create_cimports()
self.create_foreign_cimports()
self.create_foreign_enum_imports()
self.create_includes()

def create_for(
Expand Down Expand Up @@ -2036,6 +2037,40 @@ def create_foreign_cimports(self):

self.top_level_code.append(code)

def create_foreign_enum_imports(self):
"""Generate Python imports for enum classes used in type assertions across modules.

When autowrap splits classes across multiple output modules, enum classes
(e.g., _PyPolarity, _PySpectrumType) may be defined in one module but used
in type assertions in another module. This method generates the necessary
Python-level imports for these enum classes.

Note: This is separate from create_foreign_cimports() which handles Cython-level
cimports. Scoped enum classes are pure Python IntEnum subclasses and need
regular imports. Unscoped enums are cdef classes and use cimport instead.
"""
code = Code()
L.info("Create foreign enum imports for module %s" % self.target_path)
for module in self.all_decl:
mname = module
if sys.version_info >= (3, 0) and self.add_relative:
mname = "." + module

if os.path.basename(self.target_path).split(".pyx")[0] != module:
for resolved in self.all_decl[module]["decls"]:
if resolved.__class__ in (ResolvedEnum,):
# Only import scoped enums (Python IntEnum classes)
# Unscoped enums are cdef classes and use cimport
if resolved.scoped and not resolved.wrap_ignore:
# Determine the correct Python name based on wrap-attach
if resolved.cpp_decl.annotations.get("wrap-attach"):
py_name = "_Py" + resolved.name
else:
py_name = resolved.name
code.add("from $mname import $py_name", locals())

self.top_level_pyx_code.append(code)

def create_cimports(self):
self.create_std_cimports()
code = Code()
Expand Down
11 changes: 9 additions & 2 deletions autowrap/ConversionProvider.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,8 +431,15 @@ def input_conversion(
def output_conversion(
self, cpp_type: CppType, input_cpp_var: str, output_py_var: str
) -> Optional[str]:
# TODO check what to do for non-int scoped enums
return "%s = <int>%s" % (output_py_var, input_cpp_var)
if not self.enum.scoped:
return "%s = <int>%s" % (output_py_var, input_cpp_var)
else:
# For scoped enums, wrap the int value in the Python enum class
if self.enum.cpp_decl.annotations.get("wrap-attach"):
name = "_Py" + self.enum.name
else:
name = self.enum.name
return "%s = %s(<int>%s)" % (output_py_var, name, input_cpp_var)


class CharConverter(TypeConverterBase):
Expand Down
Loading