Skip to content

Commit

Permalink
#12 Remove info_helper
Browse files Browse the repository at this point in the history
  • Loading branch information
kwabenantim committed Sep 22, 2024
1 parent 24d3b50 commit a363ad2
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 140 deletions.
8 changes: 7 additions & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
[flake8]
max_line_length = 120
exclude=

exclude =
__pycache__,
.git,
.github,
build,
Expand All @@ -9,4 +11,8 @@ exclude=
cppwg/templates,
tests,
venv,

docstring-convention=numpy

# D200 One-line docstring should fit on one line with quotes
extend-ignore = D200
49 changes: 28 additions & 21 deletions cppwg/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

import pygccxml

from cppwg.input.info_helper import CppInfoHelper
from cppwg.input.package_info import PackageInfo
from cppwg.parsers.package_info_parser import PackageInfoParser
from cppwg.parsers.source_parser import CppSourceParser
Expand Down Expand Up @@ -196,19 +195,10 @@ def collect_source_hpp_files(self) -> None:
logger.error(f"No header files found in source root: {self.source_root}")
raise FileNotFoundError()

def extract_templates_from_source(self) -> None:
"""Extract template arguments for each class from the associated source file."""
for module_info in self.package_info.module_info_collection:
info_helper = CppInfoHelper(module_info)
for class_info in module_info.class_info_collection:
# Skip excluded classes
if class_info.excluded:
continue
info_helper.extract_templates_from_source(class_info)
class_info.update_names()

def log_unknown_classes(self) -> None:
"""Get unwrapped classes."""
"""
Log unwrapped classes.
"""
logger = logging.getLogger()

all_class_decls = self.source_ns.classes(allow_empty=True)
Expand Down Expand Up @@ -277,7 +267,9 @@ def parse_header_collection(self) -> None:
self.source_ns = source_parser.parse()

def parse_package_info(self) -> None:
"""Parse the package info file to create a PackageInfo object."""
"""
Parse the package info file to create a PackageInfo object.
"""
if self.package_info_path:
# If a package info file exists, parse it to create a PackageInfo object
info_parser = PackageInfoParser(self.package_info_path, self.source_root)
Expand All @@ -288,12 +280,23 @@ def parse_package_info(self) -> None:
self.package_info = PackageInfo("cppwg_package", self.source_root)

def update_from_ns(self) -> None:
"""Update modules with information from the source namespace."""
"""
Update modules with information from the parsed source namespace.
"""
for module_info in self.package_info.module_info_collection:
module_info.update_from_ns(self.source_ns)

def update_from_source(self) -> None:
"""
Update modules with information from the source headers.
"""
for module_info in self.package_info.module_info_collection:
module_info.update_from_source()

def write_header_collection(self) -> None:
"""Write the header collection to file."""
"""
Write the header collection to file.
"""
header_collection_writer = CppHeaderCollectionWriter(
self.package_info,
self.wrapper_root,
Expand All @@ -302,7 +305,9 @@ def write_header_collection(self) -> None:
header_collection_writer.write()

def write_wrappers(self) -> None:
"""Write all the wrappers required for the package."""
"""
Write all the wrappers required for the package.
"""
for module_info in self.package_info.module_info_collection:
module_writer = CppModuleWrapperWriter(
module_info,
Expand All @@ -312,7 +317,9 @@ def write_wrappers(self) -> None:
module_writer.write()

def generate_wrapper(self) -> None:
"""Parse input yaml and C++ source to generate Python wrappers."""
"""
Parse input yaml and C++ source to generate Python wrappers.
"""
# Parse the input yaml for package, module, and class information
self.parse_package_info()

Expand All @@ -322,16 +329,16 @@ def generate_wrapper(self) -> None:
# Map each class to a header file
self.map_classes_to_hpp_files()

# Attempt to extract templates for each class from the source files
self.extract_templates_from_source()
# Update modules with information from the source headers
self.update_from_source()

# Write the header collection to file
self.write_header_collection()

# Parse the headers with pygccxml and castxml
self.parse_header_collection()

# Update modules with information from the source namespace
# Update modules with information from the parsed source namespace
self.update_from_ns()

# Log list of unknown classes in the source root
Expand Down
83 changes: 81 additions & 2 deletions cppwg/input/class_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from pygccxml.declarations.runtime_errors import declaration_not_found_t

from cppwg.input.cpp_type_info import CppTypeInfo
from cppwg.utils import utils


class CppClassInfo(CppTypeInfo):
Expand All @@ -32,6 +33,69 @@ def __init__(self, name: str, class_config: Optional[Dict[str, Any]] = None):
self.py_names: List[str] = None
self.base_decls: Optional[List["declaration_t"]] = None # noqa: F821

def extract_templates_from_source(self) -> None:
"""
Extract template args from the associated source file.
Search the source file for a class signature matching one of the
template signatures defined in `template_substitutions`. If a match
is found, set the corresponding template arg replacements for the class.
"""
# Skip if there are template args attached directly to the class
if self.template_arg_lists:
return

# Skip if there is no source file
source_path = self.source_file_full_path
if not source_path:
return

# Get list of template substitutions applicable to this class
# e.g. [ {"signature":"<int A, int B>", "replacement":[[2,2], [3,3]]} ]
substitutions = self.hierarchy_attribute_gather("template_substitutions")

# Skip if there are no applicable template substitutions
if not substitutions:
return

source = utils.read_source_file(
source_path,
strip_comments=True,
strip_preprocessor=True,
strip_whitespace=True,
)

# Search for template signatures in the source file
for substitution in substitutions:
# Signature e.g. <int A, int B>
signature = substitution["signature"].strip()

class_list = utils.find_classes_in_source(
source,
class_name=self.name,
template_signature=signature,
)

if class_list:
self.template_signature = signature

# Replacement e.g. [[2,2], [3,3]]
self.template_arg_lists = substitution["replacement"]

# Extract parameters ["A", "B"] from "<int A, int B = A>"
self.template_params = []
for part in signature.split(","):
param = (
part.strip()
.replace("<", "")
.replace(">", "")
.split(" ")[1]
.split("=")[0]
.strip()
)
self.template_params.append(param)
break

def is_child_of(self, other: "ClassInfo") -> bool: # noqa: F821
"""
Check if the class is a child of the specified class.
Expand Down Expand Up @@ -151,6 +215,17 @@ def update_from_ns(self, source_ns: "namespace_t") -> None: # noqa: F821
base.related_class for decl in self.decls for base in decl.bases
]

def update_from_source(self) -> None:
"""
Update class with information from the source headers.
"""
# Skip excluded classes
if self.excluded:
return

self.extract_templates_from_source()
self.update_names()

def update_py_names(self) -> None:
"""
Set the Python names for the class, accounting for template args.
Expand Down Expand Up @@ -243,11 +318,15 @@ def update_cpp_names(self) -> None:
self.cpp_names.append(self.name + template_string)

def update_names(self) -> None:
"""Update the C++ and Python names for the class."""
"""
Update the C++ and Python names for the class.
"""
self.update_cpp_names()
self.update_py_names()

@property
def parent(self) -> "ModuleInfo": # noqa: F821
"""Returns the parent module info object."""
"""
Returns the parent module info object.
"""
return self.module_info
3 changes: 2 additions & 1 deletion cppwg/input/free_function_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ def update_from_ns(self, source_ns: "namespace_t") -> None: # noqa: F821
source_ns : pygccxml.declarations.namespace_t
The source namespace
"""
self.decls = source_ns.free_functions(self.name, allow_empty=True)[0]
ff_decls = source_ns.free_functions(self.name, allow_empty=True)
self.decls = [ff_decls[0]]
115 changes: 0 additions & 115 deletions cppwg/input/info_helper.py

This file was deleted.

8 changes: 8 additions & 0 deletions cppwg/input/module_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,11 @@ def update_from_ns(self, source_ns: "namespace_t") -> None: # noqa: F821
# Update free functions with information from source namespace.
for ff_info in self.free_function_info_collection:
ff_info.update_from_ns(source_ns)

def update_from_source(self) -> None:
"""
Update module with information from the source headers.
"""
for class_info in self.class_info_collection:
class_info.update_from_source()

0 comments on commit a363ad2

Please sign in to comment.