IncludeCPP 3.4.0__tar.gz → 3.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {includecpp-3.4.0 → includecpp-3.4.1}/IncludeCPP.egg-info/PKG-INFO +11 -2
- {includecpp-3.4.0 → includecpp-3.4.1}/PKG-INFO +11 -2
- {includecpp-3.4.0 → includecpp-3.4.1}/README.md +10 -1
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/__init__.py +1 -1
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/cli/commands.py +3 -1
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/core/cppy_converter.py +101 -18
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/generator/parser.cpp +41 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/pyproject.toml +1 -1
- {includecpp-3.4.0 → includecpp-3.4.1}/setup.py +1 -1
- {includecpp-3.4.0 → includecpp-3.4.1}/IncludeCPP.egg-info/SOURCES.txt +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/IncludeCPP.egg-info/dependency_links.txt +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/IncludeCPP.egg-info/entry_points.txt +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/IncludeCPP.egg-info/requires.txt +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/IncludeCPP.egg-info/top_level.txt +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/LICENSE +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/MANIFEST.in +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/__init__.pyi +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/__main__.py +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/cli/__init__.py +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/cli/config_parser.py +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/core/__init__.py +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/core/ai_integration.py +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/core/build_manager.py +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/core/cpp_api.py +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/core/cpp_api.pyi +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/core/error_catalog.py +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/core/error_formatter.py +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/core/exceptions.py +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/core/path_discovery.py +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/core/project_ui.py +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/core/settings_ui.py +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/generator/__init__.py +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/generator/parser.h +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/generator/type_resolver.cpp +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/generator/type_resolver.h +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/py.typed +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/includecpp/templates/cpp.proj.template +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/requirements.txt +0 -0
- {includecpp-3.4.0 → includecpp-3.4.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: IncludeCPP
|
|
3
|
-
Version: 3.4.
|
|
3
|
+
Version: 3.4.1
|
|
4
4
|
Summary: Professional C++ Python bindings with type-generic templates, pystubs and native threading
|
|
5
5
|
Home-page: https://github.com/liliassg/IncludeCPP
|
|
6
6
|
Author: Lilias Hatterscheidt
|
|
@@ -625,6 +625,15 @@ Use at your own discretion. Report issues at: https://github.com/hatte/IncludeCP
|
|
|
625
625
|
|
|
626
626
|
# Changelog
|
|
627
627
|
|
|
628
|
+
## v3.4.1
|
|
629
|
+
- **Bug Fixes:**
|
|
630
|
+
- fix command: Fixed false positives for unused variables (sum, memory_) using word-boundary matching
|
|
631
|
+
- CPPY: C++ reserved words (double, int, void, etc.) now properly escaped as Python identifiers
|
|
632
|
+
- CPPY: C++ STL functions (accumulate, find, sort, reverse) properly converted to Python equivalents
|
|
633
|
+
- CPPY: Member variables with trailing underscore (memory_) now get self. prefix
|
|
634
|
+
- CPPY: Private class members now detected for self. prefix conversion
|
|
635
|
+
- Plugin: Auto-detect header files from #include directives in source files
|
|
636
|
+
|
|
628
637
|
## v3.4.0
|
|
629
638
|
- **CodeMaker Major Update:**
|
|
630
639
|
- New Source node type with 8 connection ports for code generation
|
|
@@ -787,4 +796,4 @@ Use at your own discretion. Report issues at: https://github.com/hatte/IncludeCP
|
|
|
787
796
|
|
|
788
797
|
---
|
|
789
798
|
|
|
790
|
-
MIT License | v3.4.
|
|
799
|
+
MIT License | v3.4.1 | [GitHub](https://github.com/liliassg/IncludeCPP)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: IncludeCPP
|
|
3
|
-
Version: 3.4.
|
|
3
|
+
Version: 3.4.1
|
|
4
4
|
Summary: Professional C++ Python bindings with type-generic templates, pystubs and native threading
|
|
5
5
|
Home-page: https://github.com/liliassg/IncludeCPP
|
|
6
6
|
Author: Lilias Hatterscheidt
|
|
@@ -625,6 +625,15 @@ Use at your own discretion. Report issues at: https://github.com/hatte/IncludeCP
|
|
|
625
625
|
|
|
626
626
|
# Changelog
|
|
627
627
|
|
|
628
|
+
## v3.4.1
|
|
629
|
+
- **Bug Fixes:**
|
|
630
|
+
- fix command: Fixed false positives for unused variables (sum, memory_) using word-boundary matching
|
|
631
|
+
- CPPY: C++ reserved words (double, int, void, etc.) now properly escaped as Python identifiers
|
|
632
|
+
- CPPY: C++ STL functions (accumulate, find, sort, reverse) properly converted to Python equivalents
|
|
633
|
+
- CPPY: Member variables with trailing underscore (memory_) now get self. prefix
|
|
634
|
+
- CPPY: Private class members now detected for self. prefix conversion
|
|
635
|
+
- Plugin: Auto-detect header files from #include directives in source files
|
|
636
|
+
|
|
628
637
|
## v3.4.0
|
|
629
638
|
- **CodeMaker Major Update:**
|
|
630
639
|
- New Source node type with 8 connection ports for code generation
|
|
@@ -787,4 +796,4 @@ Use at your own discretion. Report issues at: https://github.com/hatte/IncludeCP
|
|
|
787
796
|
|
|
788
797
|
---
|
|
789
798
|
|
|
790
|
-
MIT License | v3.4.
|
|
799
|
+
MIT License | v3.4.1 | [GitHub](https://github.com/liliassg/IncludeCPP)
|
|
@@ -591,6 +591,15 @@ Use at your own discretion. Report issues at: https://github.com/hatte/IncludeCP
|
|
|
591
591
|
|
|
592
592
|
# Changelog
|
|
593
593
|
|
|
594
|
+
## v3.4.1
|
|
595
|
+
- **Bug Fixes:**
|
|
596
|
+
- fix command: Fixed false positives for unused variables (sum, memory_) using word-boundary matching
|
|
597
|
+
- CPPY: C++ reserved words (double, int, void, etc.) now properly escaped as Python identifiers
|
|
598
|
+
- CPPY: C++ STL functions (accumulate, find, sort, reverse) properly converted to Python equivalents
|
|
599
|
+
- CPPY: Member variables with trailing underscore (memory_) now get self. prefix
|
|
600
|
+
- CPPY: Private class members now detected for self. prefix conversion
|
|
601
|
+
- Plugin: Auto-detect header files from #include directives in source files
|
|
602
|
+
|
|
594
603
|
## v3.4.0
|
|
595
604
|
- **CodeMaker Major Update:**
|
|
596
605
|
- New Source node type with 8 connection ports for code generation
|
|
@@ -753,4 +762,4 @@ Use at your own discretion. Report issues at: https://github.com/hatte/IncludeCP
|
|
|
753
762
|
|
|
754
763
|
---
|
|
755
764
|
|
|
756
|
-
MIT License | v3.4.
|
|
765
|
+
MIT License | v3.4.1 | [GitHub](https://github.com/liliassg/IncludeCPP)
|
|
@@ -4436,8 +4436,10 @@ def fix(module_name, all_modules, exclude, undo, auto_fix, verbose, use_ai):
|
|
|
4436
4436
|
if var_decl:
|
|
4437
4437
|
var_name = var_decl.group(1)
|
|
4438
4438
|
# Check if variable appears again in rest of content
|
|
4439
|
+
# v3.4.1: Use word boundaries to avoid false positives from substring matches
|
|
4439
4440
|
rest_content = '\n'.join(lines[i:])
|
|
4440
|
-
|
|
4441
|
+
uses = len(re.findall(rf'\b{re.escape(var_name)}\b', rest_content))
|
|
4442
|
+
if uses <= 1:
|
|
4441
4443
|
add_issue('info', 'Mistake', file_path, i, 'C003',
|
|
4442
4444
|
f"Variable '{var_name}' may be unused",
|
|
4443
4445
|
"Remove unused variable or mark as [[maybe_unused]]")
|
|
@@ -34,6 +34,24 @@ PYTHON_KEYWORDS = {
|
|
|
34
34
|
'while', 'with', 'yield'
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
# v3.4.1: C++ reserved words that need escaping when used as Python identifiers
|
|
38
|
+
# These are C++ types/keywords that are valid Python identifiers but confusing
|
|
39
|
+
CPP_RESERVED_WORDS = {
|
|
40
|
+
# Primitive types
|
|
41
|
+
'int', 'float', 'double', 'char', 'bool', 'void', 'auto',
|
|
42
|
+
'short', 'long', 'signed', 'unsigned', 'wchar_t',
|
|
43
|
+
# Type modifiers
|
|
44
|
+
'const', 'static', 'virtual', 'volatile', 'mutable', 'extern',
|
|
45
|
+
'register', 'inline', 'explicit', 'constexpr', 'consteval',
|
|
46
|
+
# Access modifiers
|
|
47
|
+
'public', 'private', 'protected',
|
|
48
|
+
# Other keywords
|
|
49
|
+
'template', 'typename', 'namespace', 'using', 'typedef',
|
|
50
|
+
'struct', 'union', 'enum', 'sizeof', 'alignof', 'decltype',
|
|
51
|
+
'new', 'delete', 'operator', 'friend', 'this',
|
|
52
|
+
'throw', 'catch', 'noexcept', 'final', 'override',
|
|
53
|
+
}
|
|
54
|
+
|
|
37
55
|
|
|
38
56
|
def _escape_python_keyword(name: str) -> str:
|
|
39
57
|
"""Escape Python reserved keywords by adding underscore suffix.
|
|
@@ -45,6 +63,27 @@ def _escape_python_keyword(name: str) -> str:
|
|
|
45
63
|
return name
|
|
46
64
|
|
|
47
65
|
|
|
66
|
+
def _escape_cpp_reserved(name: str) -> str:
|
|
67
|
+
"""Escape C++ reserved words when used as Python identifiers.
|
|
68
|
+
|
|
69
|
+
Example: 'double' -> 'double_', 'int' -> 'int_', 'void' -> 'void_'
|
|
70
|
+
v3.4.1: Prevents C++ type names from being used as Python function/variable names.
|
|
71
|
+
"""
|
|
72
|
+
if name in CPP_RESERVED_WORDS:
|
|
73
|
+
return name + '_'
|
|
74
|
+
return name
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _escape_identifier(name: str) -> str:
|
|
78
|
+
"""Escape both Python keywords and C++ reserved words.
|
|
79
|
+
|
|
80
|
+
Combines both escaping functions for comprehensive identifier safety.
|
|
81
|
+
"""
|
|
82
|
+
name = _escape_python_keyword(name)
|
|
83
|
+
name = _escape_cpp_reserved(name)
|
|
84
|
+
return name
|
|
85
|
+
|
|
86
|
+
|
|
48
87
|
# Python type to C++ type mapping
|
|
49
88
|
PY_TO_CPP_TYPES = {
|
|
50
89
|
'int': 'int',
|
|
@@ -2225,11 +2264,31 @@ class CppToPythonConverter:
|
|
|
2225
2264
|
|
|
2226
2265
|
def _parse_class_fields(self, body: str) -> List[Tuple[str, str, Optional[str]]]:
|
|
2227
2266
|
fields = []
|
|
2267
|
+
all_field_names = set() # v3.4.1: Track ALL fields for self. prefix
|
|
2228
2268
|
|
|
2269
|
+
# v3.4.1: Parse fields from ALL sections (public, private, protected)
|
|
2270
|
+
# for self. prefix detection, but only return public fields for dataclass
|
|
2229
2271
|
sections = re.split(r'(?:public|private|protected)\s*:', body)
|
|
2230
|
-
public_section = sections[1] if len(sections) > 1 else body
|
|
2231
2272
|
|
|
2232
2273
|
field_pattern = r'(\w+(?:<[^>]+>)?)\s+(\w+)\s*(?:=\s*([^;]+))?\s*;'
|
|
2274
|
+
|
|
2275
|
+
# First pass: collect ALL field names from all sections
|
|
2276
|
+
for section in sections:
|
|
2277
|
+
for match in re.finditer(field_pattern, section):
|
|
2278
|
+
field_type = match.group(1)
|
|
2279
|
+
field_name = match.group(2)
|
|
2280
|
+
|
|
2281
|
+
if '(' in field_type or field_type in ('return', 'if', 'for', 'while'):
|
|
2282
|
+
continue
|
|
2283
|
+
|
|
2284
|
+
all_field_names.add(field_name)
|
|
2285
|
+
|
|
2286
|
+
# Store all field names for self. prefix detection
|
|
2287
|
+
self._current_class_fields = all_field_names
|
|
2288
|
+
|
|
2289
|
+
# Second pass: return only public fields for the Python class definition
|
|
2290
|
+
public_section = sections[1] if len(sections) > 1 else body
|
|
2291
|
+
|
|
2233
2292
|
for match in re.finditer(field_pattern, public_section):
|
|
2234
2293
|
field_type = match.group(1)
|
|
2235
2294
|
field_name = match.group(2)
|
|
@@ -2594,13 +2653,30 @@ class CppToPythonConverter:
|
|
|
2594
2653
|
expr = re.sub(r'std::max\(([^,]+),\s*([^)]+)\)', r'max(\1, \2)', expr)
|
|
2595
2654
|
|
|
2596
2655
|
# Handle std::accumulate(container.begin(), container.end(), init) -> sum(container) [+ init]
|
|
2656
|
+
# v3.4.1: Also handle accumulate without std:: prefix
|
|
2597
2657
|
def _accumulate_to_sum(m):
|
|
2598
2658
|
container = m.group(1)
|
|
2599
2659
|
init_val = m.group(2).strip()
|
|
2600
2660
|
if init_val == '0' or init_val == '0.0':
|
|
2601
2661
|
return f'sum({container})'
|
|
2602
2662
|
return f'sum({container}) + {init_val}'
|
|
2603
|
-
expr = re.sub(r'std::accumulate\((\w+)\.begin\(\),\s*\1\.end\(\),\s*([^)]+)\)', _accumulate_to_sum, expr)
|
|
2663
|
+
expr = re.sub(r'(?:std::)?accumulate\((\w+)\.begin\(\),\s*\1\.end\(\),\s*([^)]+)\)', _accumulate_to_sum, expr)
|
|
2664
|
+
|
|
2665
|
+
# v3.4.1: Handle std::find, std::count, std::sort with .begin()/.end()
|
|
2666
|
+
# std::find(vec.begin(), vec.end(), val) -> val in vec
|
|
2667
|
+
expr = re.sub(r'(?:std::)?find\((\w+)\.begin\(\),\s*\1\.end\(\),\s*([^)]+)\)\s*!=\s*\1\.end\(\)', r'\2 in \1', expr)
|
|
2668
|
+
# std::count(vec.begin(), vec.end(), val) -> vec.count(val)
|
|
2669
|
+
expr = re.sub(r'(?:std::)?count\((\w+)\.begin\(\),\s*\1\.end\(\),\s*([^)]+)\)', r'\1.count(\2)', expr)
|
|
2670
|
+
# std::sort(vec.begin(), vec.end()) -> vec.sort()
|
|
2671
|
+
expr = re.sub(r'(?:std::)?sort\((\w+)\.begin\(\),\s*\1\.end\(\)\)', r'\1.sort()', expr)
|
|
2672
|
+
# std::reverse(vec.begin(), vec.end()) -> vec.reverse()
|
|
2673
|
+
expr = re.sub(r'(?:std::)?reverse\((\w+)\.begin\(\),\s*\1\.end\(\)\)', r'\1.reverse()', expr)
|
|
2674
|
+
|
|
2675
|
+
# v3.4.1: Clean up any remaining .begin()/.end() that couldn't be converted
|
|
2676
|
+
# container.begin() -> iter(container) for iteration context
|
|
2677
|
+
# But typically these are errors - flag as comment if they remain
|
|
2678
|
+
expr = re.sub(r'(\w+)\.begin\(\)', r'\1[0]', expr) # Approximate as first element
|
|
2679
|
+
expr = re.sub(r'(\w+)\.end\(\)', r'len(\1)', expr) # Approximate as length
|
|
2604
2680
|
|
|
2605
2681
|
# Handle .size() -> len()
|
|
2606
2682
|
expr = re.sub(r'(\w+)\.size\(\)', r'len(\1)', expr)
|
|
@@ -2646,26 +2722,33 @@ class CppToPythonConverter:
|
|
|
2646
2722
|
# Fixed lookahead to be more permissive - match non-word chars or end
|
|
2647
2723
|
expr = re.sub(rf'(?<![.\w])(?<!self\.){re.escape(field)}(?=\W|$)', f'self.{field}', expr)
|
|
2648
2724
|
|
|
2649
|
-
# v3.
|
|
2650
|
-
# Convert m_name
|
|
2725
|
+
# v3.4.1: Handle common C++ member naming conventions
|
|
2726
|
+
# Convert m_name to self.name when in class context
|
|
2651
2727
|
if self._current_class_fields:
|
|
2652
2728
|
# Convert m_xxx to self.xxx
|
|
2653
2729
|
expr = re.sub(r'(?<![.\w])m_(\w+)(?=\W|$)', r'self.\1', expr)
|
|
2730
|
+
# Convert _xxx to self.xxx (leading underscore)
|
|
2731
|
+
expr = re.sub(r'(?<![.\w])_(\w+)(?=\W|$)', r'self.\1', expr)
|
|
2732
|
+
# v3.4.1: Convert xxx_ to self.xxx_ (trailing underscore - Google style)
|
|
2733
|
+
# Only if it's a known field or matches the pattern
|
|
2734
|
+
for field in self._current_class_fields:
|
|
2735
|
+
if field.endswith('_') and field not in ('self_',):
|
|
2736
|
+
expr = re.sub(rf'(?<![.\w]){re.escape(field)}(?=\W|$)', f'self.{field}', expr)
|
|
2654
2737
|
|
|
2655
2738
|
return expr
|
|
2656
2739
|
|
|
2657
2740
|
def _generate_struct(self, struct: StructInfo) -> List[str]:
|
|
2658
2741
|
lines = ['@dataclass']
|
|
2659
|
-
# v3.
|
|
2660
|
-
struct_name =
|
|
2742
|
+
# v3.4.1: Escape Python keywords and C++ reserved words in struct/class names
|
|
2743
|
+
struct_name = _escape_identifier(struct.name)
|
|
2661
2744
|
lines.append(f'class {struct_name}:')
|
|
2662
2745
|
|
|
2663
2746
|
if not struct.fields:
|
|
2664
2747
|
lines.append(f'{self.indent}pass')
|
|
2665
2748
|
else:
|
|
2666
2749
|
for fname, ftype in struct.fields:
|
|
2667
|
-
# v3.
|
|
2668
|
-
escaped_fname =
|
|
2750
|
+
# v3.4.1: Escape Python keywords and C++ reserved words in field names
|
|
2751
|
+
escaped_fname = _escape_identifier(fname)
|
|
2669
2752
|
lines.append(f'{self.indent}{escaped_fname}: {ftype}')
|
|
2670
2753
|
|
|
2671
2754
|
return lines
|
|
@@ -2673,8 +2756,8 @@ class CppToPythonConverter:
|
|
|
2673
2756
|
def _generate_class(self, cls: ClassInfo) -> List[str]:
|
|
2674
2757
|
lines = []
|
|
2675
2758
|
|
|
2676
|
-
# v3.
|
|
2677
|
-
class_name =
|
|
2759
|
+
# v3.4.1: Escape Python keywords and C++ reserved words in class names
|
|
2760
|
+
class_name = _escape_identifier(cls.name)
|
|
2678
2761
|
if cls.bases:
|
|
2679
2762
|
lines.append(f'class {class_name}({", ".join(cls.bases)}):')
|
|
2680
2763
|
else:
|
|
@@ -2700,8 +2783,8 @@ class CppToPythonConverter:
|
|
|
2700
2783
|
|
|
2701
2784
|
params = ['self'] if not method.is_static else []
|
|
2702
2785
|
for pname, ptype in method.params:
|
|
2703
|
-
# v3.
|
|
2704
|
-
escaped_pname =
|
|
2786
|
+
# v3.4.1: Escape Python keywords and C++ reserved words in parameter names
|
|
2787
|
+
escaped_pname = _escape_identifier(pname)
|
|
2705
2788
|
if ptype and ptype != 'Any':
|
|
2706
2789
|
params.append(f'{escaped_pname}: {ptype}')
|
|
2707
2790
|
else:
|
|
@@ -2711,8 +2794,8 @@ class CppToPythonConverter:
|
|
|
2711
2794
|
if not is_init and method.return_type and method.return_type != 'None':
|
|
2712
2795
|
ret_type = f' -> {method.return_type}'
|
|
2713
2796
|
|
|
2714
|
-
# v3.
|
|
2715
|
-
method_name = '__init__' if is_init else
|
|
2797
|
+
# v3.4.1: Escape Python keywords and C++ reserved words in method names
|
|
2798
|
+
method_name = '__init__' if is_init else _escape_identifier(method.name)
|
|
2716
2799
|
lines.append(f'{self.indent}def {method_name}({", ".join(params)}){ret_type}:')
|
|
2717
2800
|
|
|
2718
2801
|
body_lines = method.body.split('\n')
|
|
@@ -2729,8 +2812,8 @@ class CppToPythonConverter:
|
|
|
2729
2812
|
|
|
2730
2813
|
params = []
|
|
2731
2814
|
for pname, ptype in func.params:
|
|
2732
|
-
# v3.
|
|
2733
|
-
escaped_pname =
|
|
2815
|
+
# v3.4.1: Escape Python keywords and C++ reserved words in parameter names
|
|
2816
|
+
escaped_pname = _escape_identifier(pname)
|
|
2734
2817
|
if ptype and ptype != 'Any':
|
|
2735
2818
|
params.append(f'{escaped_pname}: {ptype}')
|
|
2736
2819
|
else:
|
|
@@ -2740,8 +2823,8 @@ class CppToPythonConverter:
|
|
|
2740
2823
|
if func.return_type and func.return_type != 'None':
|
|
2741
2824
|
ret_type = f' -> {func.return_type}'
|
|
2742
2825
|
|
|
2743
|
-
# v3.
|
|
2744
|
-
func_name =
|
|
2826
|
+
# v3.4.1: Escape Python keywords and C++ reserved words in function names
|
|
2827
|
+
func_name = _escape_identifier(func.name)
|
|
2745
2828
|
lines.append(f'def {func_name}({", ".join(params)}){ret_type}:')
|
|
2746
2829
|
|
|
2747
2830
|
body_lines = func.body.split('\n')
|
|
@@ -700,6 +700,47 @@ ModuleDescriptor API::parse_cp_file(const std::string& filepath) {
|
|
|
700
700
|
validate_namespace_includecpp(desc.source_path, desc.module_name);
|
|
701
701
|
}
|
|
702
702
|
|
|
703
|
+
// v3.4.1: Auto-detect header from #include directives in source file
|
|
704
|
+
if (!desc.has_header && !desc.source_path.empty()) {
|
|
705
|
+
std::ifstream source_file(desc.source_path);
|
|
706
|
+
if (source_file.is_open()) {
|
|
707
|
+
std::string line;
|
|
708
|
+
std::regex include_regex(R"(^\s*#include\s*"([^"]+\.h(?:pp)?)")");
|
|
709
|
+
std::smatch match;
|
|
710
|
+
|
|
711
|
+
while (std::getline(source_file, line)) {
|
|
712
|
+
if (std::regex_search(line, match, include_regex)) {
|
|
713
|
+
std::string header_name = match[1].str();
|
|
714
|
+
// Skip standard headers and pybind11 headers
|
|
715
|
+
if (header_name.find("pybind11") == std::string::npos &&
|
|
716
|
+
header_name.find("std") == std::string::npos) {
|
|
717
|
+
// Found a local header - construct the path
|
|
718
|
+
std::filesystem::path source_path(desc.source_path);
|
|
719
|
+
std::filesystem::path header_path = source_path.parent_path() / header_name;
|
|
720
|
+
|
|
721
|
+
// Check if the header file exists
|
|
722
|
+
if (std::filesystem::exists(header_path)) {
|
|
723
|
+
desc.header_path = header_path.string();
|
|
724
|
+
desc.has_header = true;
|
|
725
|
+
std::cout << "NOTE: Auto-detected header for '" << desc.module_name
|
|
726
|
+
<< "': " << desc.header_path << std::endl;
|
|
727
|
+
break;
|
|
728
|
+
}
|
|
729
|
+
// Also try in include/ subdirectory
|
|
730
|
+
header_path = source_path.parent_path().parent_path() / "include" / header_name;
|
|
731
|
+
if (std::filesystem::exists(header_path)) {
|
|
732
|
+
desc.header_path = header_path.string();
|
|
733
|
+
desc.has_header = true;
|
|
734
|
+
std::cout << "NOTE: Auto-detected header for '" << desc.module_name
|
|
735
|
+
<< "': " << desc.header_path << std::endl;
|
|
736
|
+
break;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
703
744
|
return desc;
|
|
704
745
|
}
|
|
705
746
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "IncludeCPP"
|
|
7
|
-
version = "3.4.
|
|
7
|
+
version = "3.4.1"
|
|
8
8
|
description = "Professional C++ Python bindings with type-generic templates, pystubs and native threading"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -6,7 +6,7 @@ long_description = (this_directory / "README.md").read_text(encoding="utf-8")
|
|
|
6
6
|
|
|
7
7
|
setup(
|
|
8
8
|
name="IncludeCPP",
|
|
9
|
-
version="3.4.
|
|
9
|
+
version="3.4.1",
|
|
10
10
|
author="Lilias Hatterscheidt",
|
|
11
11
|
author_email="lilias@includecpp.dev",
|
|
12
12
|
description="Professional C++ Python bindings with type-generic templates and native threading",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|