inspection_helpers
Contains a variety of functions for inspecting classes and class method data.
To import...
from dynamite_nsm.cmd import inspection_helpers
ArgparseParameters
Represent the **kwargs that can be provided to the argparse.ArgumentParser
class
__init__(self, name, **kwargs)
special
Setup from a dictionary
Parameters:
Name | Type | Description | Default |
---|---|---|---|
name |
|
The name of a commandline parameter (E.G setup, stdout, verbose, any_func_name) |
required |
kwargs |
|
A list of kwargs accepted by argparse.ArgumentParser.add_argument method |
{} |
Source code in dynamite_nsm/cmd/inspection_helpers.py
def __init__(self, name, **kwargs):
"""Setup from a dictionary
Args:
name: The name of a commandline parameter (E.G setup, stdout, verbose, any_func_name)
kwargs: A list of kwargs accepted by argparse.ArgumentParser.add_argument method
"""
self.name = name
self.flags = ['--' + self.name.replace('_', '-')]
self.kwargs = kwargs
create_from_typing_annotation(name, python_type, default=None, required=True)
classmethod
Convenience method for creating argparse parameters from a python
Parameters:
Name | Type | Description | Default |
---|---|---|---|
name |
str |
The name of the commandline parameter |
required |
python_type |
type |
The datatype that best describes the parameter |
required |
default |
Optional[Any] |
The default value for the parameter being evaluated |
None |
required |
Optional[bool] |
If True, argparse will interpret this argument as required |
True |
Returns:
Type | Description |
---|---|
|
None |
Source code in dynamite_nsm/cmd/inspection_helpers.py
@classmethod
def create_from_typing_annotation(cls, name: str, python_type: type, default: Optional[Any] = None,
required: Optional[bool] = True):
"""Convenience method for creating argparse parameters from a python <class type>
Args:
name: The name of the commandline parameter
python_type: The datatype that best describes the parameter
default: The default value for the parameter being evaluated
required: If True, argparse will interpret this argument as required
Returns:
None
"""
return cls(name, **cls.derive_params_from_type_annotation(python_type, default=default, required=required))
derive_params_from_type_annotation(python_type, default=None, required=True)
staticmethod
Convert from a typing annotation string to an argparse.ArgumentParser
type
Parameters:
Name | Type | Description | Default |
---|---|---|---|
python_type |
Any |
A |
required |
default |
Optional[Any] |
The default value for the parameter being evaluated |
None |
required |
Optional[bool] |
If true, the |
True |
Returns:
Type | Description |
---|---|
Dict |
A dictionary of supported **kwargs used to instantiate an |
Source code in dynamite_nsm/cmd/inspection_helpers.py
@staticmethod
def derive_params_from_type_annotation(python_type: Any, default: Optional[Any] = None,
required: Optional[bool] = True) -> Dict:
"""Convert from a typing annotation string to an `argparse.ArgumentParser` `type`
Args:
python_type: A <class 'type'> or typing derived class
default: The default value for the parameter being evaluated
required: If true, the `required` parameter will be added to the parameter dictionary
Returns:
A dictionary of supported **kwargs used to instantiate an `argparse.ArgumentParser` object
"""
python_type = str(python_type)
action, default, nargs = None, default, None
_type = str
if default:
required = False
if 'Union' in python_type and 'NoneType' in python_type:
required = False
if 'Optional' in python_type:
required = False
if 'List' in python_type:
nargs = '+'
if 'list' in python_type:
nargs = '+'
if 'bool' in python_type:
action = 'store_true'
_type = None
elif 'int' in python_type:
_type = int
elif 'float' in python_type:
_type = float
elif 'str' in python_type:
_type = str
derived_args = dict(
required=required,
action=action,
default=default,
nargs=nargs,
type=_type
)
derived_args = {k: v for k, v in derived_args.items() if v is not None and v != ''}
return derived_args
get_argparse_parameters(func_def, defaults)
Given a callable function returns a list of argparse compatible arguments
Parameters:
Name | Type | Description | Default |
---|---|---|---|
func_def |
Tuple[str, dict, str] |
A tuple containing the |
required |
defaults |
Optional[Dict] |
A dictionary where the key a parameter name and the value represents the value to default it too. |
required |
Returns:
Type | Description |
---|---|
List[dynamite_nsm.cmd.inspection_helpers.ArgparseParameters] |
A list of |
Source code in dynamite_nsm/cmd/inspection_helpers.py
def get_argparse_parameters(func_def: Tuple[str, dict, str], defaults: Optional[Dict]) -> List[ArgparseParameters]:
"""Given a callable function returns a list of argparse compatible arguments
Args:
func_def: A tuple containing the `function.__name__`, `function.__annotations__`, `inspect.getdoc(function)`
defaults: A dictionary where the key a parameter name and the value represents the value to default it too.
Returns:
A list of `ArgparseParameters`
"""
argparse_parameter_group = []
param_map = {}
_, annotations, docs = func_def
try:
docstring_params = docstring_parse(docs).params
except ValueError as e:
newline_delim_doc_str = '\\n'.join(docs.split('\n'))
raise Exception(
f'Docs: {newline_delim_doc_str} failed to parse: {e} likely because this docstring has a '
f'newline in it somewhere.')
for doc_param in docstring_params:
_, arg_name = doc_param.args
if '***' in doc_param.description:
split_token = '***'
elif '---' in docstring_params:
split_token = '---'
else:
split_token = '___'
# If an explicit line break is detected in our docstrings we don't parse parameters passed that line break.
param_map[arg_name] = doc_param.description.split(split_token)[0]
for param_name, data_type in annotations.items():
argparse_params = ArgparseParameters.create_from_typing_annotation(name=param_name, python_type=data_type)
if param_name == 'return':
continue
if defaults and defaults.get(param_name):
argparse_params = ArgparseParameters.create_from_typing_annotation(name=param_name, python_type=data_type,
default=defaults.get(param_name))
try:
argparse_params.add_description(param_map[param_name])
except KeyError:
pass
argparse_parameter_group.append(argparse_params)
return argparse_parameter_group
get_class_instance_methods(cls, defaults=None, use_parent_init=True)
Given a class retrieves all the methods with their corresponding parameters
Parameters:
Name | Type | Description | Default |
---|---|---|---|
cls |
object |
The class that you wish to enumerate |
required |
use_parent_init |
Optional[bool] |
If True, the parent class' init arguments will be scanned as well |
True |
defaults |
Optional[Dict] |
A dictionary where the key a parameter name and the value represents the value to default it too. |
None |
Returns:
Type | Description |
---|---|
Tuple[List[dynamite_nsm.cmd.inspection_helpers.ArgparseParameters], Dict[str, List[dynamite_nsm.cmd.inspection_helpers.ArgparseParameters]]] |
A tuple containing the base_params for the init method in the first position; and a dictionary containing a
map of remaining function names to lists of their corresponding parameters
(E.G |
Source code in dynamite_nsm/cmd/inspection_helpers.py
def get_class_instance_methods(cls: object, defaults: Optional[Dict] = None, use_parent_init: Optional[bool] = True) -> \
Tuple[List[ArgparseParameters], Dict[str, List[ArgparseParameters]]]:
"""Given a class retrieves all the methods with their corresponding parameters
Args:
cls: The class that you wish to enumerate
use_parent_init: If True, the parent class' init arguments will be scanned as well
defaults: A dictionary where the key a parameter name and the value represents the value to default it too.
Returns:
A tuple containing the base_params for the __init__ method in the first position; and a dictionary containing a
map of remaining function names to lists of their corresponding parameters
(E.G `{func_name [ArgparseParameters, ArgparseParam...], func_name_2 [ArgparseParameters, Argp...]}`)
"""
interface_functions = {}
# Enumerate the class instance methods as well as any parent classes instance methods
try:
method_resolution_order = cls.__mro__
except AttributeError:
method_resolution_order = cls.__class__.__mro__
for c in method_resolution_order:
for callable in c.__dict__.values():
func_def = get_function_definition(callable)
if not func_def:
continue
else:
# func_name, annotations, docs
func_name, _, _ = func_def
if func_name == '__init__':
continue
# Store the rest of our method parameters in a dictionary
# {func_name: [ArgparseParameters, ArgparseParam...], func_name_2: [ArgparseParameters, Argp...]}
else:
# Look first in the top level class then parent classes
if func_name not in interface_functions.keys():
interface_functions[func_name] = get_argparse_parameters(func_def, defaults=defaults)
# and parent class is selected
try:
parent_class = method_resolution_order[1]
except IndexError:
parent_class = cls
if use_parent_init:
func_def = get_function_definition(parent_class.__init__)
else:
func_def = get_function_definition(cls.__init__)
base_params = get_argparse_parameters(func_def, defaults=defaults)
return base_params, interface_functions
get_function_definition(func)
Given a callable function returns a three part definition for that function
Parameters:
Name | Type | Description | Default |
---|---|---|---|
func |
Callable |
A callable function |
required |
Returns:
Type | Description |
---|---|
Optional[Tuple[str, dict, str]] |
A tuple with the ( |
Source code in dynamite_nsm/cmd/inspection_helpers.py
def get_function_definition(func: Callable) -> Union[Tuple[str, dict, str], None]:
"""Given a callable function returns a three part definition for that function
Args:
func: A callable function
Returns:
A tuple with the (`function.__name__`, `function.__annotations__`, `inspect.getdoc(function)`)
"""
if not isinstance(func, Callable):
return None
if func.__name__ == '__init__':
name = '__init__'
annotations = dict(inspect.signature(func).parameters.items())
annotations.pop('self', None)
docs = inspect.getdoc(func)
else:
try:
name, annotations = func.__name__, func.__annotations__
docs = inspect.getdoc(func)
except AttributeError:
return None
return name, annotations, docs