Skip to content

Commit 9b50945

Browse files
Copilotjpfeuffer
andcommitted
Inline ArrayWrapper classes into generated modules (WIP)
Changed approach from separate ArrayWrappers module to inlining the wrapper classes directly into each generated module. This eliminates the ModuleNotFoundError issues. Changes: - Removed cimport from ArrayWrappers - Added inline_array_wrappers() to inject wrapper code into generated modules - Removed ArrayWrappers compilation logic from Utils.py Status: Compilation succeeds but attribute injection has indentation issues that need fixing. The regex-based approach for merging .pxd attributes into .pyx classes needs refinement. Co-authored-by: jpfeuffer <8102638+jpfeuffer@users.noreply.github.com>
1 parent bb049ca commit 9b50945

File tree

3 files changed

+1657
-38
lines changed

3 files changed

+1657
-38
lines changed

autowrap/CodeGenerator.py

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2096,17 +2096,6 @@ def create_default_cimports(self):
20962096
|import numpy as np
20972097
|cimport numpy as numpy
20982098
|import numpy as numpy
2099-
|from ArrayWrappers cimport (
2100-
| ArrayWrapperFloat, ArrayWrapperDouble,
2101-
| ArrayWrapperInt8, ArrayWrapperInt16, ArrayWrapperInt32, ArrayWrapperInt64,
2102-
| ArrayWrapperUInt8, ArrayWrapperUInt16, ArrayWrapperUInt32, ArrayWrapperUInt64,
2103-
| ArrayViewFloat, ArrayViewDouble,
2104-
| ArrayViewInt8, ArrayViewInt16, ArrayViewInt32, ArrayViewInt64,
2105-
| ArrayViewUInt8, ArrayViewUInt16, ArrayViewUInt32, ArrayViewUInt64,
2106-
| _create_view_float, _create_view_double,
2107-
| _create_view_int8, _create_view_int16, _create_view_int32, _create_view_int64,
2108-
| _create_view_uint8, _create_view_uint16, _create_view_uint32, _create_view_uint64
2109-
|)
21102099
"""
21112100
)
21122101

@@ -2119,7 +2108,71 @@ def create_std_cimports(self):
21192108
code.add(stmt)
21202109

21212110
self.top_level_code.append(code)
2111+
2112+
# If numpy is enabled, inline the ArrayWrapper/ArrayView classes
2113+
if self.include_numpy:
2114+
self.inline_array_wrappers()
2115+
21222116
return code
2117+
2118+
def inline_array_wrappers(self):
2119+
"""Inline ArrayWrapper and ArrayView class definitions for buffer protocol support."""
2120+
# Read both the .pyx and .pxd files
2121+
autowrap_dir = os.path.dirname(os.path.abspath(__file__))
2122+
array_wrappers_pyx = os.path.join(autowrap_dir, "data_files", "autowrap", "ArrayWrappers.pyx")
2123+
array_wrappers_pxd = os.path.join(autowrap_dir, "data_files", "autowrap", "ArrayWrappers.pxd")
2124+
2125+
if not os.path.exists(array_wrappers_pyx):
2126+
L.warning("ArrayWrappers.pyx not found, skipping inline array wrappers")
2127+
return
2128+
2129+
with open(array_wrappers_pyx, 'r') as f:
2130+
pyx_content = f.read()
2131+
2132+
# Read .pxd to get attribute declarations
2133+
attribute_declarations = {}
2134+
if os.path.exists(array_wrappers_pxd):
2135+
with open(array_wrappers_pxd, 'r') as f:
2136+
pxd_content = f.read()
2137+
2138+
# Parse .pxd to extract attribute declarations for each class
2139+
import re
2140+
# Pattern to match class declarations with their attributes
2141+
# Match: "cdef class ClassName:\n cdef type attr\n cdef type attr\n..."
2142+
class_pattern = r'cdef class (\w+):\s*\n((?:\s+cdef .+\n)+)'
2143+
for match in re.finditer(class_pattern, pxd_content):
2144+
class_name = match.group(1)
2145+
attrs = match.group(2)
2146+
# Attrs already has proper indentation from .pxd
2147+
attribute_declarations[class_name] = attrs.rstrip()
2148+
2149+
# Now inject the attribute declarations into the .pyx content
2150+
# For each class, add the cdef attributes right after the docstring
2151+
for class_name, attrs in attribute_declarations.items():
2152+
# Find "cdef class ClassName:" and its docstring, then add attributes after
2153+
pattern = rf'(cdef class {class_name}:\s+""".*?""")\s*\n'
2154+
replacement = rf'\1\n{attrs}\n '
2155+
pyx_content = re.sub(pattern, replacement, pyx_content, flags=re.DOTALL)
2156+
2157+
# Remove the first few lines (cython directives and module docstring)
2158+
# Keep everything from the first import onward
2159+
lines = pyx_content.split('\n')
2160+
start_idx = 0
2161+
for i, line in enumerate(lines):
2162+
if line.strip().startswith('from cpython.buffer'):
2163+
start_idx = i
2164+
break
2165+
2166+
wrapper_code_str = '\n'.join(lines[start_idx:])
2167+
2168+
code = Code()
2169+
code.add("""
2170+
|# Inlined ArrayWrapper and ArrayView classes for buffer protocol support
2171+
""")
2172+
# Add the wrapper code directly
2173+
code.add(wrapper_code_str)
2174+
2175+
self.top_level_code.append(code)
21232176

21242177
def create_includes(self):
21252178
code = Code()

autowrap/Utils.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -178,22 +178,8 @@ def compile_and_import(name, source_files, include_dirs=None, **kws):
178178
print("tempdir=", tempdir)
179179
print("\n")
180180

181-
# Check if any source file imports ArrayWrappers (indicates numpy usage)
182-
needs_array_wrappers = False
183-
for source_file in source_files:
184-
if source_file.endswith('.pyx'):
185-
try:
186-
with open(source_file, 'r') as f:
187-
content = f.read()
188-
if 'ArrayWrappers' in content or 'ArrayWrapper' in content or 'ArrayView' in content:
189-
needs_array_wrappers = True
190-
break
191-
except:
192-
pass
193-
194-
# Compile ArrayWrappers first if needed
195-
if needs_array_wrappers:
196-
_compile_array_wrappers_if_needed(tempdir, include_dirs, debug)
181+
# Note: ArrayWrappers classes are now inlined into generated modules,
182+
# so we don't need to compile them separately anymore
197183

198184
for source_file in source_files:
199185
if source_file[-4:] != ".pyx" and source_file[-4:] != ".cpp":

0 commit comments

Comments
 (0)