Squashed 'wrap/' changes from d9ae5ce03..571c23952

571c23952 Merge pull request #119 from borglab/feature/remove-loguru
0e5178251 remove loguru as a dependency
5b76595cf fix type info and do some refactoring

git-subtree-dir: wrap
git-subtree-split: 571c2395242e33dfd0596a240fbcb87775b9ba0c
release/4.3a0
Varun Agrawal 2021-07-22 11:51:22 -04:00
parent 4c410fcd0e
commit 3a5e715848
8 changed files with 68 additions and 88 deletions

View File

@ -10,7 +10,7 @@ Parser classes and rules for parsing C++ classes.
Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar, Varun Agrawal, and Frank Dellaert Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar, Varun Agrawal, and Frank Dellaert
""" """
from typing import Iterable, List, Union from typing import Any, Iterable, List, Union
from pyparsing import Literal, Optional, ZeroOrMore # type: ignore from pyparsing import Literal, Optional, ZeroOrMore # type: ignore
@ -48,12 +48,12 @@ class Method:
args_list, t.is_const)) args_list, t.is_const))
def __init__(self, def __init__(self,
template: str, template: Union[Template, Any],
name: str, name: str,
return_type: ReturnType, return_type: ReturnType,
args: ArgumentList, args: ArgumentList,
is_const: str, is_const: str,
parent: Union[str, "Class"] = ''): parent: Union["Class", Any] = ''):
self.template = template self.template = template
self.name = name self.name = name
self.return_type = return_type self.return_type = return_type
@ -98,7 +98,7 @@ class StaticMethod:
name: str, name: str,
return_type: ReturnType, return_type: ReturnType,
args: ArgumentList, args: ArgumentList,
parent: Union[str, "Class"] = ''): parent: Union["Class", Any] = ''):
self.name = name self.name = name
self.return_type = return_type self.return_type = return_type
self.args = args self.args = args
@ -129,7 +129,7 @@ class Constructor:
def __init__(self, def __init__(self,
name: str, name: str,
args: ArgumentList, args: ArgumentList,
parent: Union["Class", str] = ''): parent: Union["Class", Any] = ''):
self.name = name self.name = name
self.args = args self.args = args
@ -167,7 +167,7 @@ class Operator:
return_type: ReturnType, return_type: ReturnType,
args: ArgumentList, args: ArgumentList,
is_const: str, is_const: str,
parent: Union[str, "Class"] = ''): parent: Union["Class", Any] = ''):
self.name = name self.name = name
self.operator = operator self.operator = operator
self.return_type = return_type self.return_type = return_type
@ -284,7 +284,7 @@ class Class:
properties: List[Variable], properties: List[Variable],
operators: List[Operator], operators: List[Operator],
enums: List[Enum], enums: List[Enum],
parent: str = '', parent: Any = '',
): ):
self.template = template self.template = template
self.is_virtual = is_virtual self.is_virtual = is_virtual

View File

@ -169,7 +169,7 @@ class GlobalFunction:
return_type: ReturnType, return_type: ReturnType,
args_list: ArgumentList, args_list: ArgumentList,
template: Template, template: Template,
parent: str = ''): parent: Any = ''):
self.name = name self.name = name
self.return_type = return_type self.return_type = return_type
self.args = args_list self.args = args_list

View File

@ -12,7 +12,7 @@ Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar, Varun Agrawal, and Frank Dellae
# pylint: disable=unnecessary-lambda, expression-not-assigned # pylint: disable=unnecessary-lambda, expression-not-assigned
from typing import Iterable, List, Union from typing import List, Sequence, Union
from pyparsing import (Forward, Optional, Or, ParseResults, # type: ignore from pyparsing import (Forward, Optional, Or, ParseResults, # type: ignore
delimitedList) delimitedList)
@ -49,12 +49,12 @@ class Typename:
def __init__(self, def __init__(self,
t: ParseResults, t: ParseResults,
instantiations: Iterable[ParseResults] = ()): instantiations: Sequence[ParseResults] = ()):
self.name = t[-1] # the name is the last element in this list self.name = t[-1] # the name is the last element in this list
self.namespaces = t[:-1] self.namespaces = t[:-1]
if instantiations: if instantiations:
if isinstance(instantiations, Iterable): if isinstance(instantiations, Sequence):
self.instantiations = instantiations # type: ignore self.instantiations = instantiations # type: ignore
else: else:
self.instantiations = instantiations.asList() self.instantiations = instantiations.asList()

View File

@ -1,5 +1,7 @@
"""Mixins for reducing the amount of boilerplate in the main wrapper class.""" """Mixins for reducing the amount of boilerplate in the main wrapper class."""
from typing import Any, Tuple, Union
import gtwrap.interface_parser as parser import gtwrap.interface_parser as parser
import gtwrap.template_instantiator as instantiator import gtwrap.template_instantiator as instantiator
@ -7,13 +9,14 @@ import gtwrap.template_instantiator as instantiator
class CheckMixin: class CheckMixin:
"""Mixin to provide various checks.""" """Mixin to provide various checks."""
# Data types that are primitive types # Data types that are primitive types
not_ptr_type = ['int', 'double', 'bool', 'char', 'unsigned char', 'size_t'] not_ptr_type: Tuple = ('int', 'double', 'bool', 'char', 'unsigned char',
'size_t')
# Ignore the namespace for these datatypes # Ignore the namespace for these datatypes
ignore_namespace = ['Matrix', 'Vector', 'Point2', 'Point3'] ignore_namespace: Tuple = ('Matrix', 'Vector', 'Point2', 'Point3')
# Methods that should be ignored # Methods that should be ignored
ignore_methods = ['pickle'] ignore_methods: Tuple = ('pickle', )
# Methods that should not be wrapped directly # Methods that should not be wrapped directly
whitelist = ['serializable', 'serialize'] whitelist: Tuple = ('serializable', 'serialize')
# Datatypes that do not need to be checked in methods # Datatypes that do not need to be checked in methods
not_check_type: list = [] not_check_type: list = []
@ -23,7 +26,7 @@ class CheckMixin:
return True return True
return False return False
def is_shared_ptr(self, arg_type): def is_shared_ptr(self, arg_type: parser.Type):
""" """
Determine if the `interface_parser.Type` should be treated as a Determine if the `interface_parser.Type` should be treated as a
shared pointer in the wrapper. shared pointer in the wrapper.
@ -33,7 +36,7 @@ class CheckMixin:
and arg_type.typename.name not in self.ignore_namespace and arg_type.typename.name not in self.ignore_namespace
and arg_type.typename.name != 'string') and arg_type.typename.name != 'string')
def is_ptr(self, arg_type): def is_ptr(self, arg_type: parser.Type):
""" """
Determine if the `interface_parser.Type` should be treated as a Determine if the `interface_parser.Type` should be treated as a
raw pointer in the wrapper. raw pointer in the wrapper.
@ -43,7 +46,7 @@ class CheckMixin:
and arg_type.typename.name not in self.ignore_namespace and arg_type.typename.name not in self.ignore_namespace
and arg_type.typename.name != 'string') and arg_type.typename.name != 'string')
def is_ref(self, arg_type): def is_ref(self, arg_type: parser.Type):
""" """
Determine if the `interface_parser.Type` should be treated as a Determine if the `interface_parser.Type` should be treated as a
reference in the wrapper. reference in the wrapper.
@ -55,7 +58,14 @@ class CheckMixin:
class FormatMixin: class FormatMixin:
"""Mixin to provide formatting utilities.""" """Mixin to provide formatting utilities."""
def _clean_class_name(self, instantiated_class):
ignore_namespace: tuple
data_type: Any
data_type_param: Any
_return_count: Any
def _clean_class_name(self,
instantiated_class: instantiator.InstantiatedClass):
"""Reformatted the C++ class name to fit Matlab defined naming """Reformatted the C++ class name to fit Matlab defined naming
standards standards
""" """
@ -65,23 +75,23 @@ class FormatMixin:
return instantiated_class.name return instantiated_class.name
def _format_type_name(self, def _format_type_name(self,
type_name, type_name: parser.Typename,
separator='::', separator: str = '::',
include_namespace=True, include_namespace: bool = True,
constructor=False, is_constructor: bool = False,
method=False): is_method: bool = False):
""" """
Args: Args:
type_name: an interface_parser.Typename to reformat type_name: an interface_parser.Typename to reformat
separator: the statement to add between namespaces and typename separator: the statement to add between namespaces and typename
include_namespace: whether to include namespaces when reformatting include_namespace: whether to include namespaces when reformatting
constructor: if the typename will be in a constructor is_constructor: if the typename will be in a constructor
method: if the typename will be in a method is_method: if the typename will be in a method
Raises: Raises:
constructor and method cannot both be true constructor and method cannot both be true
""" """
if constructor and method: if is_constructor and is_method:
raise ValueError( raise ValueError(
'Constructor and method parameters cannot both be True') 'Constructor and method parameters cannot both be True')
@ -93,9 +103,9 @@ class FormatMixin:
if name not in self.ignore_namespace and namespace != '': if name not in self.ignore_namespace and namespace != '':
formatted_type_name += namespace + separator formatted_type_name += namespace + separator
if constructor: if is_constructor:
formatted_type_name += self.data_type.get(name) or name formatted_type_name += self.data_type.get(name) or name
elif method: elif is_method:
formatted_type_name += self.data_type_param.get(name) or name formatted_type_name += self.data_type_param.get(name) or name
else: else:
formatted_type_name += name formatted_type_name += name
@ -106,8 +116,8 @@ class FormatMixin:
template = '{}'.format( template = '{}'.format(
self._format_type_name(type_name.instantiations[idx], self._format_type_name(type_name.instantiations[idx],
include_namespace=include_namespace, include_namespace=include_namespace,
constructor=constructor, is_constructor=is_constructor,
method=method)) is_method=is_method))
templates.append(template) templates.append(template)
if len(templates) > 0: # If there are no templates if len(templates) > 0: # If there are no templates
@ -119,15 +129,15 @@ class FormatMixin:
self._format_type_name(type_name.instantiations[idx], self._format_type_name(type_name.instantiations[idx],
separator=separator, separator=separator,
include_namespace=False, include_namespace=False,
constructor=constructor, is_constructor=is_constructor,
method=method)) is_method=is_method))
return formatted_type_name return formatted_type_name
def _format_return_type(self, def _format_return_type(self,
return_type, return_type: parser.function.ReturnType,
include_namespace=False, include_namespace: bool = False,
separator="::"): separator: str = "::"):
"""Format return_type. """Format return_type.
Args: Args:
@ -154,18 +164,15 @@ class FormatMixin:
return return_wrap return return_wrap
def _format_class_name(self, instantiated_class, separator=''): def _format_class_name(self,
instantiated_class: instantiator.InstantiatedClass,
separator: str = ''):
"""Format a template_instantiator.InstantiatedClass name.""" """Format a template_instantiator.InstantiatedClass name."""
if instantiated_class.parent == '': if instantiated_class.parent == '':
parent_full_ns = [''] parent_full_ns = ['']
else: else:
parent_full_ns = instantiated_class.parent.full_namespaces() parent_full_ns = instantiated_class.parent.full_namespaces()
# class_name = instantiated_class.parent.name
#
# if class_name != '':
# class_name += separator
#
# class_name += instantiated_class.name
parentname = "".join([separator + x parentname = "".join([separator + x
for x in parent_full_ns]) + separator for x in parent_full_ns]) + separator
@ -175,10 +182,12 @@ class FormatMixin:
return class_name return class_name
def _format_static_method(self, static_method, separator=''): def _format_static_method(self,
"""Example: static_method: parser.StaticMethod,
separator: str = ''):
gtsamPoint3.staticFunction """
Example:
gtsam.Point3.staticFunction()
""" """
method = '' method = ''
@ -188,35 +197,17 @@ class FormatMixin:
return method[2 * len(separator):] return method[2 * len(separator):]
def _format_instance_method(self, instance_method, separator=''): def _format_global_function(self,
function: Union[parser.GlobalFunction, Any],
separator: str = ''):
"""Example: """Example:
gtsamPoint3.staticFunction gtsamPoint3.staticFunction
""" """
method = '' method = ''
if isinstance(instance_method, instantiator.InstantiatedMethod): if isinstance(function, parser.GlobalFunction):
method_list = [ method += "".join([separator + x for x in function.parent.full_namespaces()]) + \
separator + x
for x in instance_method.parent.parent.full_namespaces()
]
method += "".join(method_list) + separator
method += instance_method.parent.name + separator
method += instance_method.original.name
method += "<" + instance_method.instantiations.to_cpp() + ">"
return method[2 * len(separator):]
def _format_global_method(self, static_method, separator=''):
"""Example:
gtsamPoint3.staticFunction
"""
method = ''
if isinstance(static_method, parser.GlobalFunction):
method += "".join([separator + x for x in static_method.parent.full_namespaces()]) + \
separator separator
return method[2 * len(separator):] return method[2 * len(separator):]

View File

@ -11,8 +11,6 @@ import textwrap
from functools import partial, reduce from functools import partial, reduce
from typing import Dict, Iterable, List, Union from typing import Dict, Iterable, List, Union
from loguru import logger
import gtwrap.interface_parser as parser import gtwrap.interface_parser as parser
import gtwrap.template_instantiator as instantiator import gtwrap.template_instantiator as instantiator
from gtwrap.matlab_wrapper.mixins import CheckMixin, FormatMixin from gtwrap.matlab_wrapper.mixins import CheckMixin, FormatMixin
@ -200,7 +198,7 @@ class MatlabWrapper(CheckMixin, FormatMixin):
check_type = self._format_type_name( check_type = self._format_type_name(
arg.ctype.typename, arg.ctype.typename,
separator='.', separator='.',
constructor=not wrap_datatypes) is_constructor=not wrap_datatypes)
var_arg_wrap += " && isa(varargin{{{num}}},'{data_type}')".format( var_arg_wrap += " && isa(varargin{{{num}}},'{data_type}')".format(
num=i, data_type=check_type) num=i, data_type=check_type)
@ -1090,11 +1088,10 @@ class MatlabWrapper(CheckMixin, FormatMixin):
if method.instantiations: if method.instantiations:
# method_name += '<{}>'.format( # method_name += '<{}>'.format(
# self._format_type_name(method.instantiations)) # self._format_type_name(method.instantiations))
# method_name = self._format_instance_method(method, '::')
method = method.to_cpp() method = method.to_cpp()
elif isinstance(method, parser.GlobalFunction): elif isinstance(method, parser.GlobalFunction):
method_name = self._format_global_method(method, '::') method_name = self._format_global_function(method, '::')
method_name += method.name method_name += method.name
else: else:

View File

@ -4,7 +4,7 @@
import itertools import itertools
from copy import deepcopy from copy import deepcopy
from typing import Iterable, List from typing import Any, Iterable, List, Sequence
import gtwrap.interface_parser as parser import gtwrap.interface_parser as parser
@ -214,17 +214,17 @@ class InstantiatedMethod(parser.Method):
} }
""" """
def __init__(self, def __init__(self,
original, original: parser.Method,
instantiations: Iterable[parser.Typename] = ()): instantiations: Iterable[parser.Typename] = ()):
self.original = original self.original = original
self.instantiations = instantiations self.instantiations = instantiations
self.template = '' self.template: Any = ''
self.is_const = original.is_const self.is_const = original.is_const
self.parent = original.parent self.parent = original.parent
# Check for typenames if templated. # Check for typenames if templated.
# This way, we can gracefully handle both templated and non-templated methods. # This way, we can gracefully handle both templated and non-templated methods.
typenames = self.original.template.typenames if self.original.template else [] typenames: Sequence = self.original.template.typenames if self.original.template else []
self.name = instantiate_name(original.name, self.instantiations) self.name = instantiate_name(original.name, self.instantiations)
self.return_type = instantiate_return_type( self.return_type = instantiate_return_type(
original.return_type, original.return_type,
@ -348,13 +348,12 @@ class InstantiatedClass(parser.Class):
return "{virtual}Class {cpp_class} : {parent_class}\n"\ return "{virtual}Class {cpp_class} : {parent_class}\n"\
"{ctors}\n{static_methods}\n{methods}\n{operators}".format( "{ctors}\n{static_methods}\n{methods}\n{operators}".format(
virtual="virtual " if self.is_virtual else '', virtual="virtual " if self.is_virtual else '',
name=self.name,
cpp_class=self.to_cpp(), cpp_class=self.to_cpp(),
parent_class=self.parent, parent_class=self.parent,
ctors="\n".join([repr(ctor) for ctor in self.ctors]), ctors="\n".join([repr(ctor) for ctor in self.ctors]),
methods="\n".join([repr(m) for m in self.methods]),
static_methods="\n".join([repr(m) static_methods="\n".join([repr(m)
for m in self.static_methods]), for m in self.static_methods]),
methods="\n".join([repr(m) for m in self.methods]),
operators="\n".join([repr(op) for op in self.operators]) operators="\n".join([repr(op) for op in self.operators])
) )

View File

@ -1,3 +1,2 @@
pyparsing pyparsing
pytest pytest
loguru

View File

@ -11,8 +11,6 @@ import os.path as osp
import sys import sys
import unittest import unittest
from loguru import logger
sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__))))
from gtwrap.matlab_wrapper import MatlabWrapper from gtwrap.matlab_wrapper import MatlabWrapper
@ -44,10 +42,6 @@ class TestWrap(unittest.TestCase):
# Create the `actual/matlab` directory # Create the `actual/matlab` directory
os.makedirs(self.MATLAB_ACTUAL_DIR, exist_ok=True) os.makedirs(self.MATLAB_ACTUAL_DIR, exist_ok=True)
# set the log level to INFO by default
logger.remove() # remove the default sink
logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
def compare_and_diff(self, file): def compare_and_diff(self, file):
""" """
Compute the comparison between the expected and actual file, Compute the comparison between the expected and actual file,