Skip to content
This repository was archived by the owner on Aug 25, 2024. It is now read-only.

Commit 03a37d7

Browse files
John Andersenpdxjohnny
authored andcommitted
source: Use standardized pattern
Signed-off-by: John Andersen <john.s.andersen@intel.com>
1 parent 4775b34 commit 03a37d7

File tree

43 files changed

+1755
-1340
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1755
-1340
lines changed

dffml/base.py

Lines changed: 117 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,34 @@
33
they follow a similar API for instantiation and usage.
44
'''
55
import abc
6-
from typing import Dict, Any
6+
from argparse import ArgumentParser
7+
from typing import Dict, Any, Tuple, NamedTuple
8+
9+
from .util.data import traverse_config_set, traverse_config_get
710

811
from .util.entrypoint import Entrypoint
912

1013
from .log import LOGGER
1114

15+
class MissingArg(Exception):
16+
'''
17+
Raised when a BaseConfigurable is missing an argument from the args dict it
18+
created with args(). If this exception is raised then the config() method is
19+
attempting to retrive an argument which was not set in the args() method.
20+
'''
21+
22+
class MissingConfig(Exception):
23+
'''
24+
Raised when a BaseConfigurable is missing an argument from the config dict.
25+
Also raised if there was no default value set and the argument is missing.
26+
'''
27+
28+
class MissingRequiredProperty(Exception):
29+
'''
30+
Raised when a BaseDataFlowFacilitatorObject is missing some property which
31+
should have been defined in the class.
32+
'''
33+
1234
class LoggingLogger(object):
1335
'''
1436
Provide the logger property using Python's builtin logging module.
@@ -28,7 +50,11 @@ class BaseConfig(object):
2850
All DFFML Base Objects should take an object (likely a typing.NamedTuple) as
2951
as their config.
3052
'''
31-
pass
53+
54+
class ConfigurableParsingNamespace(object):
55+
56+
def __init__(self):
57+
self.dest = None
3258

3359
class BaseConfigurable(abc.ABC):
3460
'''
@@ -38,6 +64,8 @@ class BaseConfigurable(abc.ABC):
3864
only parameter to the __init__ of a BaseDataFlowFacilitatorObject.
3965
'''
4066

67+
__argp = ArgumentParser()
68+
4169
def __init__(self, config: BaseConfig) -> None:
4270
'''
4371
BaseConfigurable takes only one argument to __init__,
@@ -47,19 +75,93 @@ def __init__(self, config: BaseConfig) -> None:
4775
'''
4876
self.config = config
4977

78+
@classmethod
79+
def add_orig_label(cls, *above):
80+
return (
81+
list(above) + cls.ENTRY_POINT_NAME + [cls.ENTRY_POINT_ORIG_LABEL]
82+
)
83+
84+
@classmethod
85+
def add_label(cls, *above):
86+
return (
87+
list(above) + cls.ENTRY_POINT_NAME + [cls.ENTRY_POINT_LABEL]
88+
)
89+
90+
@classmethod
91+
def config_set(cls, args, above, *path) -> BaseConfig:
92+
return traverse_config_set(args,
93+
*(cls.add_orig_label(*above) + list(path)))
94+
95+
@classmethod
96+
def config_get(cls, config, above, *path) -> BaseConfig:
97+
# unittest.mock.patch doesn't work if we cache args() output.
98+
args = cls.args({})
99+
args_above = cls.add_orig_label() + list(path)
100+
label_above = cls.add_label(*above) + list(path)
101+
no_label_above = cls.add_label(*above)[:-1] + list(path)
102+
try:
103+
arg = traverse_config_get(args, *args_above)
104+
except KeyError as error:
105+
raise MissingArg('Arg %r missing from %s%s%s' % \
106+
(args_above[-1],
107+
cls.__qualname__,
108+
'.' if args_above[:-1] else '',
109+
'.'.join(args_above[:-1]),)) from error
110+
try:
111+
value = traverse_config_get(config, *label_above)
112+
except KeyError as error:
113+
try:
114+
value = traverse_config_get(config, *no_label_above)
115+
except KeyError as error:
116+
if 'default' in arg:
117+
return arg['default']
118+
raise MissingConfig('%s missing %r from %s' % \
119+
(cls.__qualname__,
120+
label_above[-1],
121+
'.'.join(label_above[:-1]),)) from error
122+
123+
if value is None \
124+
and 'default' in arg:
125+
return arg['default']
126+
# TODO This is a oversimplification of argparse's nargs
127+
if not 'nargs' in arg:
128+
value = value[0]
129+
if 'type' in arg:
130+
# TODO This is a oversimplification of argparse's nargs
131+
if 'nargs' in arg:
132+
value = list(map(arg['type'], value))
133+
else:
134+
value = arg['type'](value)
135+
if 'action' in arg:
136+
if isinstance(arg['action'], str):
137+
# HACK This accesses _pop_action_class from ArgumentParser
138+
# which is prefaced with an underscore indicating it not an API
139+
# we can rely on
140+
arg['action'] = cls.__argp._pop_action_class(arg)
141+
namespace = ConfigurableParsingNamespace()
142+
action = arg['action'](dest='dest', option_strings='')
143+
action(None, namespace, value)
144+
value = namespace.dest
145+
return value
146+
50147
@classmethod
51148
@abc.abstractmethod
52-
def args(cls) -> Dict[str, Any]:
53-
pass
149+
def args(cls, *above) -> Dict[str, Any]:
150+
'''
151+
Return a dict containing arguments required for this class
152+
'''
54153

55154
@classmethod
56155
@abc.abstractmethod
57-
def config(cls, cmd):
58-
pass
156+
def config(cls, config, *above):
157+
'''
158+
Create the BaseConfig required to instantiate this class by parsing the
159+
config dict.
160+
'''
59161

60162
@classmethod
61-
def withconfig(cls, cmd):
62-
return cls(cls.config(cmd))
163+
def withconfig(cls, config, *above):
164+
return cls(cls.config(config, *above))
63165

64166
class BaseDataFlowFacilitatorObjectContext(LoggingLogger):
65167
'''
@@ -110,14 +212,17 @@ def __init__(self, config: BaseConfig) -> None:
110212
self.__ensure_property('CONTEXT')
111213
self.__ensure_property('ENTRY_POINT')
112214

215+
def __repr__(self):
216+
return '%s(%r)' % (self.__class__.__qualname__, self.config)
217+
113218
@abc.abstractmethod
114219
def __call__(self) -> 'BaseDataFlowFacilitatorObjectContext':
115220
pass
116221

117222
@classmethod
118223
def __ensure_property(cls, property_name):
119224
if getattr(cls, property_name, None) is None:
120-
raise ValueError('BaseDataFlowFacilitatorObject\'s may not be ' + \
121-
'created without a `%s`. ' % (property_name,) + \
122-
'Missing %s.%s' \
123-
% (cls.__qualname__, property_name,))
225+
raise MissingRequiredProperty(
226+
'BaseDataFlowFacilitatorObjects may not be '
227+
'created without a `%s`. Missing %s.%s' \
228+
% (property_name, cls.__qualname__, property_name,))

0 commit comments

Comments
 (0)