This commit is contained in:
Dion Moult
2026-07-26 18:03:09 +10:00
parent 7aa967b01a
commit 291d7d8441
72 changed files with 477 additions and 377 deletions
+20 -6
View File
@@ -168,7 +168,9 @@ def _is_in_allowed_headers(cursor, allowed_headers: set[Path]) -> bool:
def _is_in_allowed_namespace(cpp_name: str, config: WrapperConfig) -> bool:
if not config.allowed_namespaces:
return True
return any(cpp_name == namespace or cpp_name.startswith(f"{namespace}::") for namespace in config.allowed_namespaces)
return any(
cpp_name == namespace or cpp_name.startswith(f"{namespace}::") for namespace in config.allowed_namespaces
)
def _matches_ignore(cpp_name: str, ignored: list[str]) -> bool:
@@ -328,7 +330,7 @@ def _python_default_value(
if adapter == "integer":
return cpp_value if cpp_value.lstrip("-").isdigit() else None
if adapter == "string":
return cpp_value if cpp_value.startswith(("\"", "'")) else None
return cpp_value if cpp_value.startswith(('"', "'")) else None
if is_enum_adapter(adapter):
enum_name = enum_py_names.get(adapter.split(":", 1)[1])
if enum_name is None:
@@ -393,9 +395,17 @@ def _finalize_overload_names(callables: list[CallableModel]) -> None:
for index, callable_model in enumerate(group, start=1):
parameter_suffix = "_".join(parameter.name for parameter in callable_model.parameters)
if callable_model.kind == "constructor":
callable_model.py_name = f"{callable_model.py_name}_{parameter_suffix}" if parameter_suffix else f"{callable_model.py_name}_overload_{index}"
callable_model.py_name = (
f"{callable_model.py_name}_{parameter_suffix}"
if parameter_suffix
else f"{callable_model.py_name}_overload_{index}"
)
else:
callable_model.py_name = f"{callable_model.py_name}_with_{parameter_suffix}" if parameter_suffix else f"{callable_model.py_name}_overload_{index}"
callable_model.py_name = (
f"{callable_model.py_name}_with_{parameter_suffix}"
if parameter_suffix
else f"{callable_model.py_name}_overload_{index}"
)
callable_model.c_name = normalize_identifier(callable_model.py_name)
@@ -473,7 +483,9 @@ def _discover_methods(
qualified_name = f"{owner.cpp_name}::{child.spelling}"
if _matches_ignore(qualified_name, config.ignore.methods):
continue
return_adapter = _resolve_return_adapter(child.result_type.spelling, scalar_adapters, enum_cursors, class_models_by_cpp)
return_adapter = _resolve_return_adapter(
child.result_type.spelling, scalar_adapters, enum_cursors, class_models_by_cpp
)
if return_adapter is None:
continue
parameters = _build_parameter_models(child, config, scalar_adapters, enum_cursors)
@@ -535,7 +547,9 @@ def build_module_model(config: WrapperConfig) -> ModuleModel:
for normalized_cpp_name, cursor in class_cursors.items():
owner = class_models_by_cpp[normalized_cpp_name]
owner.callables.extend(_discover_constructors(cursor, owner, config, scalar_adapters, enum_cursors))
owner.callables.extend(_discover_methods(cursor, owner, config, scalar_adapters, enum_cursors, class_models_by_cpp))
owner.callables.extend(
_discover_methods(cursor, owner, config, scalar_adapters, enum_cursors, class_models_by_cpp)
)
owner.callables = _deduplicate_callables(owner.callables)
_finalize_overload_names(owner.callables)
+1 -5
View File
@@ -126,11 +126,7 @@ def resolve_cpp_type_key(cpp_type: str, candidates: set[str]) -> str | None:
if canonical in candidates:
return canonical
leaf = strip_pointer(canonical).rsplit("::", 1)[-1]
matches = [
candidate
for candidate in candidates
if strip_pointer(candidate).rsplit("::", 1)[-1] == leaf
]
matches = [candidate for candidate in candidates if strip_pointer(candidate).rsplit("::", 1)[-1] == leaf]
if len(matches) == 1:
return matches[0]
return None
+39 -17
View File
@@ -173,7 +173,7 @@ def _class_or_enum_cpp_name(adapter: str, model: ModuleModel) -> str:
def _cpp_argument(parameter: ParameterModel, model: ModuleModel) -> str:
if parameter.adapter == "string":
return f"std::string({parameter.name} ? {parameter.name} : \"\")"
return f'std::string({parameter.name} ? {parameter.name} : "")'
if is_enum_adapter(parameter.adapter):
return f"static_cast<{_class_or_enum_cpp_name(parameter.adapter, model)}>({parameter.name})"
if is_handle_adapter(parameter.adapter):
@@ -315,8 +315,7 @@ def emit_c_api_header(model: ModuleModel) -> str:
for variant in _all_variants(model):
return_type = _return_c_type(variant.callable.return_adapter, model)
parameters = ", ".join(
f"{_parameter_c_type(parameter, model)} {parameter.name}"
for parameter in variant.parameters
f"{_parameter_c_type(parameter, model)} {parameter.name}" for parameter in variant.parameters
)
if variant.callable.kind == "method":
self_type = f"{_class_c_type(variant.owner, model)}* handle"
@@ -327,11 +326,15 @@ def emit_c_api_header(model: ModuleModel) -> str:
for class_model in sequence_targets:
list_prefix = f"{model.c_prefix}_{_class_c_identifier(class_model, model)}_list"
lines.append(f"int {list_prefix}_size(const {_list_c_type(class_model, model)}* handle);")
lines.append(f"{_class_c_type(class_model, model)}* {list_prefix}_get(const {_list_c_type(class_model, model)}* handle, int index);")
lines.append(
f"{_class_c_type(class_model, model)}* {list_prefix}_get(const {_list_c_type(class_model, model)}* handle, int index);"
)
lines.append(f"void {list_prefix}_free({_list_c_type(class_model, model)}* handle);")
lines.append("")
for class_model in model.classes:
lines.append(f"void {model.c_prefix}_{_class_c_identifier(class_model, model)}_free({_class_c_type(class_model, model)}* handle);")
lines.append(
f"void {model.c_prefix}_{_class_c_identifier(class_model, model)}_free({_class_c_type(class_model, model)}* handle);"
)
lines.extend(
[
"",
@@ -419,8 +422,7 @@ def emit_c_api_implementation(model: ModuleModel) -> str:
for variant in _all_variants(model):
return_type = _return_c_type(variant.callable.return_adapter, model)
parameter_list = ", ".join(
f"{_parameter_c_type(parameter, model)} {parameter.name}"
for parameter in variant.parameters
f"{_parameter_c_type(parameter, model)} {parameter.name}" for parameter in variant.parameters
)
if variant.callable.kind == "method":
self_type = f"{_class_c_type(variant.owner, model)}* handle"
@@ -435,21 +437,31 @@ def emit_c_api_implementation(model: ModuleModel) -> str:
for parameter in variant.parameters:
if is_handle_adapter(parameter.adapter):
lines.append(f" if ({parameter.name} == nullptr) {{")
lines.append(f' throw std::runtime_error("Null handle parameter received for {parameter.name}");')
lines.append(
f' throw std::runtime_error("Null handle parameter received for {parameter.name}");'
)
lines.append(" }")
call_expression = _call_expression(variant, model)
if variant.callable.kind == "constructor":
lines.append(f" auto constructed_value = {call_expression};")
if variant.owner.handle_kind == "shared_ptr":
lines.append(f" return new {_class_c_type(variant.owner, model)}{{ std::move(constructed_value) }};")
lines.append(
f" return new {_class_c_type(variant.owner, model)}{{ std::move(constructed_value) }};"
)
elif variant.owner.owner_cpp_name is not None:
lines.append(f" return new {_class_c_type(variant.owner, model)}{{ {{}}, std::move(constructed_value) }};")
lines.append(
f" return new {_class_c_type(variant.owner, model)}{{ {{}}, std::move(constructed_value) }};"
)
else:
lines.append(f" return new {_class_c_type(variant.owner, model)}{{ std::move(constructed_value) }};")
lines.append(
f" return new {_class_c_type(variant.owner, model)}{{ std::move(constructed_value) }};"
)
elif variant.callable.return_adapter == "string":
lines.append(f" auto result = {call_expression};")
lines.append(" return duplicate_string(result);")
elif variant.callable.return_adapter in {"integer", "bool", "void"} or is_enum_adapter(variant.callable.return_adapter):
elif variant.callable.return_adapter in {"integer", "bool", "void"} or is_enum_adapter(
variant.callable.return_adapter
):
if variant.callable.return_adapter == "void":
lines.append(f" {call_expression};")
lines.append(" return;")
@@ -503,11 +515,15 @@ def emit_c_api_implementation(model: ModuleModel) -> str:
]
)
if class_model.handle_kind == "shared_ptr":
lines.append(f" auto item_value = std::make_shared<{class_model.cpp_name}>(handle->value.at(static_cast<size_t>(index)));")
lines.append(
f" auto item_value = std::make_shared<{class_model.cpp_name}>(handle->value.at(static_cast<size_t>(index)));"
)
lines.append(f" return new {_class_c_type(class_model, model)}{{ std::move(item_value) }};")
elif class_model.owner_cpp_name is not None:
lines.append(f" auto item_value = handle->value.at(static_cast<size_t>(index));")
lines.append(f" return new {_class_c_type(class_model, model)}{{ handle->owner, std::move(item_value) }};")
lines.append(
f" return new {_class_c_type(class_model, model)}{{ handle->owner, std::move(item_value) }};"
)
else:
lines.append(f" auto item_value = handle->value.at(static_cast<size_t>(index));")
lines.append(f" return new {_class_c_type(class_model, model)}{{ std::move(item_value) }};")
@@ -526,7 +542,9 @@ def emit_c_api_implementation(model: ModuleModel) -> str:
]
)
for class_model in model.classes:
lines.append(f"void {model.c_prefix}_{_class_c_identifier(class_model, model)}_free({_class_c_type(class_model, model)}* handle) {{")
lines.append(
f"void {model.c_prefix}_{_class_c_identifier(class_model, model)}_free({_class_c_type(class_model, model)}* handle) {{"
)
lines.append(" delete handle;")
lines.append("}")
lines.append("")
@@ -706,7 +724,9 @@ def emit_python_extension(model: ModuleModel) -> str:
lines.append(f" {list_prefix}_free(result);")
lines.append(" return values;")
else:
raise RuntimeError(f"Unsupported return adapter in Python extension emitter: {variant.callable.return_adapter}")
raise RuntimeError(
f"Unsupported return adapter in Python extension emitter: {variant.callable.return_adapter}"
)
lines.append("}")
lines.append("")
lines.extend(["static PyMethodDef MODULE_METHODS[] = {"])
@@ -847,7 +867,9 @@ def emit_python_facade(model: ModuleModel) -> str:
lines.append(" self._handle = handle")
lines.append("")
for callable_model in class_model.callables:
parameters = ", ".join(_python_parameter_signature(parameter, model) for parameter in callable_model.parameters)
parameters = ", ".join(
_python_parameter_signature(parameter, model) for parameter in callable_model.parameters
)
full_variant = _full_variant(class_model, callable_model)
call_arguments = ", ".join(_python_native_argument(parameter) for parameter in callable_model.parameters)
return_annotation = _python_type_for_return(callable_model.return_adapter, model)
+1 -5
View File
@@ -27,11 +27,7 @@ def _existing_directories(paths: list[Path]) -> list[str]:
def _discover_headers(src_ifcparse: Path) -> list[str]:
return [
str(path.resolve())
for path in sorted(src_ifcparse.glob("*.h"))
if path.parent.name != "schemas"
]
return [str(path.resolve()) for path in sorted(src_ifcparse.glob("*.h")) if path.parent.name != "schemas"]
def _discover_boost_include_dirs() -> list[Path]:
@@ -13,6 +13,7 @@ class FileType(IntEnum):
FT_UNKNOWN = _native.FT_UNKNOWN
FT_AUTODETECT = _native.FT_AUTODETECT
class exception:
__slots__ = ("_handle",)
@@ -23,6 +24,7 @@ class exception:
def with_message(message: str) -> exception:
return exception(_native.exception_new_with_message(message))
class attribute_out_of_range_exception:
__slots__ = ("_handle",)
@@ -33,6 +35,7 @@ class attribute_out_of_range_exception:
def with_message(message: str) -> attribute_out_of_range_exception:
return attribute_out_of_range_exception(_native.attribute_out_of_range_exception_new_with_message(message))
class invalid_token_exception:
__slots__ = ("_handle",)
@@ -40,8 +43,15 @@ class invalid_token_exception:
self._handle = handle
@staticmethod
def with_token_start_token_string_expected_type(token_start: int, token_string: str, expected_type: str) -> invalid_token_exception:
return invalid_token_exception(_native.invalid_token_exception_new_with_token_start_token_string_expected_type(token_start, token_string, expected_type))
def with_token_start_token_string_expected_type(
token_start: int, token_string: str, expected_type: str
) -> invalid_token_exception:
return invalid_token_exception(
_native.invalid_token_exception_new_with_token_start_token_string_expected_type(
token_start, token_string, expected_type
)
)
class parameter_type:
__slots__ = ("_handle",)
@@ -61,6 +71,7 @@ class parameter_type:
def is_(self, arg0: str) -> bool:
return _native.parameter_type_is(self._handle, arg0)
class named_type:
__slots__ = ("_handle",)
@@ -76,6 +87,7 @@ class named_type:
def is_(self, name: str) -> bool:
return _native.named_type_is(self._handle, name)
class simple_type:
__slots__ = ("_handle",)
@@ -85,6 +97,7 @@ class simple_type:
def as_simple_type(self) -> simple_type:
return simple_type(_native.simple_type_as_simple_type(self._handle))
class aggregation_type:
__slots__ = ("_handle",)
@@ -103,6 +116,7 @@ class aggregation_type:
def as_aggregation_type(self) -> aggregation_type:
return aggregation_type(_native.aggregation_type_as_aggregation_type(self._handle))
class declaration:
__slots__ = ("_handle",)
@@ -143,6 +157,7 @@ class declaration:
def schema(self) -> schema_definition:
return schema_definition(_native.declaration_schema(self._handle))
class type_declaration:
__slots__ = ("_handle",)
@@ -155,6 +170,7 @@ class type_declaration:
def as_type_declaration(self) -> type_declaration:
return type_declaration(_native.type_declaration_as_type_declaration(self._handle))
class select_type:
__slots__ = ("_handle",)
@@ -167,6 +183,7 @@ class select_type:
def as_select_type(self) -> select_type:
return select_type(_native.select_type_as_select_type(self._handle))
class enumeration_type:
__slots__ = ("_handle",)
@@ -179,6 +196,7 @@ class enumeration_type:
def as_enumeration_type(self) -> enumeration_type:
return enumeration_type(_native.enumeration_type_as_enumeration_type(self._handle))
class attribute:
__slots__ = ("_handle",)
@@ -194,6 +212,7 @@ class attribute:
def optional(self) -> bool:
return _native.attribute_optional(self._handle)
class inverse_attribute:
__slots__ = ("_handle",)
@@ -215,6 +234,7 @@ class inverse_attribute:
def attribute_reference(self) -> attribute:
return attribute(_native.inverse_attribute_attribute_reference(self._handle))
class entity:
__slots__ = ("_handle",)
@@ -248,6 +268,7 @@ class entity:
def as_entity(self) -> entity:
return entity(_native.entity_as_entity(self._handle))
class schema_definition:
__slots__ = ("_handle",)
@@ -258,7 +279,9 @@ class schema_definition:
return declaration(_native.schema_definition_declaration_by_name_with_name(self._handle, name))
def declaration_by_name_with_declaration_index(self, declaration_index: int) -> declaration:
return declaration(_native.schema_definition_declaration_by_name_with_declaration_index(self._handle, declaration_index))
return declaration(
_native.schema_definition_declaration_by_name_with_declaration_index(self._handle, declaration_index)
)
def declarations(self) -> list[declaration]:
return [declaration(item) for item in _native.schema_definition_declarations(self._handle)]
@@ -278,6 +301,7 @@ class schema_definition:
def name(self) -> str:
return _native.schema_definition_name(self._handle)
class Base:
__slots__ = ("_handle",)
@@ -301,6 +325,7 @@ class Base:
def id(self) -> int:
return _native.base_id(self._handle)
class Entity:
__slots__ = ("_handle",)
@@ -314,6 +339,7 @@ class Entity:
def get_inverse(self, attribute_name: str) -> list[Entity]:
return [Entity(item) for item in _native.entity_get_inverse(self._handle, attribute_name)]
class Select:
__slots__ = ("_handle",)
@@ -327,6 +353,7 @@ class Select:
def concrete(self) -> Base:
return Base(_native.select_concrete(self._handle))
class DeclaredType:
__slots__ = ("_handle",)
@@ -337,6 +364,7 @@ class DeclaredType:
def create() -> DeclaredType:
return DeclaredType(_native.declared_type_new())
class full_buffer_impl:
__slots__ = ("_handle",)
@@ -365,6 +393,7 @@ class full_buffer_impl:
_native.full_buffer_impl_drop_pages(self._handle, up_to_position)
return None
class paged_file_impl:
__slots__ = ("_handle",)
@@ -373,7 +402,9 @@ class paged_file_impl:
@staticmethod
def with_path_page_size_page_capacity(path: str, page_size: int, page_capacity: int) -> paged_file_impl:
return paged_file_impl(_native.paged_file_impl_new_with_path_page_size_page_capacity(path, page_size, page_capacity))
return paged_file_impl(
_native.paged_file_impl_new_with_path_page_size_page_capacity(path, page_size, page_capacity)
)
def size(self) -> int:
return _native.paged_file_impl_size(self._handle)
@@ -389,6 +420,7 @@ class paged_file_impl:
_native.paged_file_impl_drop_pages(self._handle, up_to_position)
return None
class pushed_sequential_impl:
__slots__ = ("_handle",)
@@ -409,6 +441,7 @@ class pushed_sequential_impl:
_native.pushed_sequential_impl_drop_pages(self._handle, up_to_position)
return None
class character_encoder:
__slots__ = ("_handle",)
@@ -419,6 +452,7 @@ class character_encoder:
def with_input(input: str) -> character_encoder:
return character_encoder(_native.character_encoder_new_with_input(input))
class file_open_status:
__slots__ = ("_handle",)
@@ -427,6 +461,7 @@ class file_open_status:
pass
class spf_header:
__slots__ = ("_handle",)
@@ -435,6 +470,7 @@ class spf_header:
pass
class file:
__slots__ = ("_handle",)
@@ -508,6 +544,7 @@ class file:
_native.file_reset_identity_cache(self._handle)
return None
class global_id:
__slots__ = ("_handle",)