Skip to content

Commit

Permalink
#20 test with flake8-docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
kwabenantim committed Mar 20, 2024
1 parent 570972a commit 2a9a97b
Show file tree
Hide file tree
Showing 27 changed files with 207 additions and 169 deletions.
2 changes: 2 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ exclude=
build,
doc,
examples,
cppwg/templates,
tests,
docstring-convention=numpy
30 changes: 29 additions & 1 deletion cppwg/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
from .generators import CppWrapperGenerator
"""
cppwg: an automatic Python wrapper generator for C++ code.
Available subpackages
---------------------
generators
Contains the main interface for generating Python wrappers.
input
Contains information structures for C++ code to be wrapped.
parsers
Contains parsers for C++ code and input yaml.
templates
Contains string templates for Python wrappers.
utils
Contains utility functions and constants.
writers
Contains writers for creating Python wrappers and writing to file.
Utilities
---------
__version__
cppwg version string
"""

from importlib import metadata

from cppwg.generators import CppWrapperGenerator

__all__ = [
"CppWrapperGenerator",
]

__version__ = metadata.version("cppwg")
48 changes: 21 additions & 27 deletions cppwg/generators.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Contains the main interface for generating Python wrappers."""

import fnmatch
import logging
import os
Expand All @@ -23,7 +25,7 @@

class CppWrapperGenerator:
"""
Main class for generating C++ wrappers
Main class for generating C++ wrappers.
Attributes
----------
Expand Down Expand Up @@ -149,11 +151,12 @@ def __init__(

def collect_source_hpp_files(self) -> None:
"""
Collect *.hpp files from the source root.
Walk through the source root and add any files matching the provided
patterns e.g. "*.hpp". Skip the wrapper root and wrappers to
avoid pollution.
"""

for root, _, filenames in os.walk(self.source_root, followlinks=True):
for pattern in self.package_info.source_hpp_patterns:
for filename in fnmatch.filter(filenames, pattern):
Expand All @@ -171,19 +174,18 @@ def collect_source_hpp_files(self) -> None:
self.package_info.source_hpp_files.append(filepath)

def extract_templates_from_source(self) -> None:
"""
Extract template arguments for each class from the associated source file
"""

"""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:
info_helper.extract_templates_from_source(class_info)

def map_classes_to_hpp_files(self) -> None:
"""
Map each class to a header file.
Attempt to map source file paths to each class, assuming the containing
file name is the class name
file name is the class name.
"""
for module_info in self.package_info.module_info_collection:
for class_info in module_info.class_info_collection:
Expand All @@ -196,10 +198,11 @@ def map_classes_to_hpp_files(self) -> None:

def parse_header_collection(self) -> None:
"""
Parse the hpp files to collect C++ declarations.
Parse the headers with pygccxml and CastXML to populate the source
namespace with C++ declarations collected from the source tree
namespace with C++ declarations collected from the source tree.
"""

source_parser = CppSourceParser(
self.source_root,
self.header_collection_filepath,
Expand All @@ -209,11 +212,8 @@ def parse_header_collection(self) -> None:
)
self.source_ns = source_parser.parse()

def parse_package_info(self):
"""
Parse the package info file to create a PackageInfo object
"""

def parse_package_info(self) -> None:
"""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 @@ -225,10 +225,11 @@ def parse_package_info(self):

def update_class_info(self) -> None:
"""
Add decls to class info objects.
Update the class info with class declarations parsed by pygccxml from
the C++ source code.
"""

for module_info in self.package_info.module_info_collection:
if module_info.use_all_classes:
# Create class info objects for all class declarations found
Expand Down Expand Up @@ -256,10 +257,11 @@ def update_class_info(self) -> None:

def update_free_function_info(self) -> None:
"""
Add decls to free function info objects.
Update the free function info with declarations parsed by pygccxml from
the C++ source code.
"""

for module_info in self.package_info.module_info_collection:
if module_info.use_all_free_functions:
# Create free function info objects for all free function
Expand All @@ -286,10 +288,7 @@ def update_free_function_info(self) -> None:
free_function_info.decl = free_functions[0]

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 @@ -298,9 +297,7 @@ 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(
self.source_ns,
Expand All @@ -311,10 +308,7 @@ def write_wrappers(self) -> None:
module_writer.write()

def generate_wrapper(self) -> None:
"""
Main method for generating all the 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 Down
1 change: 1 addition & 0 deletions cppwg/input/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Contains information structures for C++ code to be wrapped."""
21 changes: 16 additions & 5 deletions cppwg/input/base_info.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
"""Generic information structure."""

from typing import Any, Dict, List, Optional


class BaseInfo:
"""
Generic information structure for features (i.e packages, modules, classes,
free functions, etc.)
A generic information structure for features.
Features include packages, modules, classes, free functions, etc.
Information structures are used to store information about the features. The
information structures for each feature type inherit from BaseInfo, which
sets a number of default attributes common to all features.
Attributes
----------
Expand Down Expand Up @@ -39,7 +45,8 @@ class BaseInfo:
arg_type_excludes : List[str]
List of exclude patterns for arg types.
name_replacements : Dict[str, str]
A dictionary of name replacements e.g. {"double":"Double", "unsigned int":"Unsigned"}
A dictionary of name replacements e.g. {"double":"Double", "unsigned
int":"Unsigned"}
"""

def __init__(self, name):
Expand Down Expand Up @@ -77,6 +84,8 @@ def __init__(self, name):
@property
def parent(self) -> Optional["BaseInfo"]:
"""
Get this object's parent.
Return the parent object of the feature in the hierarchy. This is
overriden in subclasses e.g. ModuleInfo returns a PackageInfo, ClassInfo
returns a ModuleInfo, etc.
Expand All @@ -90,6 +99,8 @@ def parent(self) -> Optional["BaseInfo"]:

def hierarchy_attribute(self, attribute_name: str) -> Any:
"""
Get the attribute value from this object or one of its parents.
For the supplied attribute, iterate through parent objects until a non-None
value is found. If the top level parent (i.e. package) attribute is
None, return None.
Expand All @@ -104,7 +115,6 @@ def hierarchy_attribute(self, attribute_name: str) -> Any:
Any
The attribute value.
"""

if hasattr(self, attribute_name) and getattr(self, attribute_name) is not None:
return getattr(self, attribute_name)

Expand All @@ -115,6 +125,8 @@ def hierarchy_attribute(self, attribute_name: str) -> Any:

def hierarchy_attribute_gather(self, attribute_name: str) -> List[Any]:
"""
Get a list of attribute values from this object and its parents.
For the supplied attribute, iterate through parent objects gathering list entries.
Parameters
Expand All @@ -127,7 +139,6 @@ def hierarchy_attribute_gather(self, attribute_name: str) -> List[Any]:
List[Any]
The list of attribute values.
"""

att_list: List[Any] = []

if hasattr(self, attribute_name) and getattr(self, attribute_name) is not None:
Expand Down
10 changes: 4 additions & 6 deletions cppwg/input/class_info.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
"""Class information structure."""

from typing import Any, Dict, Optional

from cppwg.input.cpp_type_info import CppTypeInfo


class CppClassInfo(CppTypeInfo):
"""
This class holds information for individual C++ classes to be wrapped
"""
"""An information structure for individual C++ classes to be wrapped."""

def __init__(self, name: str, class_config: Optional[Dict[str, Any]] = None):

super(CppClassInfo, self).__init__(name, class_config)

@property
def parent(self) -> "ModuleInfo": # noqa: F821
"""
Returns the parent module info object
"""
"""Returns the parent module info object."""
return self.module_info
26 changes: 12 additions & 14 deletions cppwg/input/cpp_type_info.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""C++ type information structure."""

from typing import Any, Dict, List, Optional

from pygccxml.declarations import declaration_t
Expand All @@ -7,7 +9,7 @@

class CppTypeInfo(BaseInfo):
"""
This class holds information for C++ types including classes, free functions etc.
An information structure for C++ types including classes, free functions etc.
Attributes
----------
Expand Down Expand Up @@ -43,6 +45,8 @@ def __init__(self, name: str, type_config: Optional[Dict[str, Any]] = None):
# TODO: Consider setting short and full names on init as read-only properties
def get_short_names(self) -> List[str]:
"""
Get the Python name for the class e.g. Foo2_2.
Return the name of the class as it will appear on the Python side. This
collapses template arguments, separating them by underscores and removes
special characters. The return type is a list, as a class can have
Expand All @@ -55,7 +59,6 @@ def get_short_names(self) -> List[str]:
List[str]
The list of short names
"""

# Handles untemplated classes
if self.template_arg_lists is None:
if self.name_override is None:
Expand Down Expand Up @@ -114,6 +117,8 @@ def get_short_names(self) -> List[str]:

def get_full_names(self) -> List[str]:
"""
Get the C++ name for the class e.g. Foo<2,2>.
Return the name (declaration) of the class as it appears on the C++
side. The return type is a list, as a class can have multiple names
(declarations) if it is templated. For example, a class "Foo" with
Expand All @@ -125,7 +130,6 @@ def get_full_names(self) -> List[str]:
List[str]
The list of full names
"""

# Handles untemplated classes
if self.template_arg_lists is None:
return [self.name]
Expand All @@ -143,10 +147,7 @@ def get_full_names(self) -> List[str]:

# TODO: This method is not used, remove it?
def needs_header_file_instantiation(self):
"""
Does this class need to be instantiated in the header file
"""

"""Check if this class needs to be instantiated in the header file."""
return (
(self.template_arg_lists is not None)
and (not self.include_file_only)
Expand All @@ -156,16 +157,13 @@ def needs_header_file_instantiation(self):
# TODO: This method is not used, remove it?
def needs_header_file_typdef(self):
"""
Does this type need to be typdef'd with a nicer name in the header
file. All template classes need this.
"""
Check if this type need to be typdef'd with a nicer name.
The typedefs are declared in the header file. All template classes need this.
"""
return (self.template_arg_lists is not None) and (not self.include_file_only)

# TODO: This method is not used, remove it?
def needs_auto_wrapper_generation(self):
"""
Does this class need a wrapper to be autogenerated.
"""

"""Check if this class needs a wrapper to be autogenerated."""
return not self.include_file_only
10 changes: 4 additions & 6 deletions cppwg/input/free_function_info.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""Free function information structure."""

from typing import Any, Dict, Optional

from cppwg.input.cpp_type_info import CppTypeInfo


class CppFreeFunctionInfo(CppTypeInfo):
"""
This class holds information for individual free functions to be wrapped
"""
"""An information structure for individual free functions to be wrapped."""

def __init__(
self, name: str, free_function_config: Optional[Dict[str, Any]] = None
Expand All @@ -16,7 +16,5 @@ def __init__(

@property
def parent(self) -> "ModuleInfo": # noqa: F821
"""
Returns the parent module info object
"""
"""Returns the parent module info object."""
return self.module_info
Loading

0 comments on commit 2a9a97b

Please sign in to comment.