1- '''
1+ """
22Base classes for DFFML. All classes in DFFML should inherit from these so that
33they follow a similar API for instantiation and usage.
4- '''
4+ """
55import abc
66from argparse import ArgumentParser
77from typing import Dict , Any , Tuple , NamedTuple
1212
1313from .log import LOGGER
1414
15+
1516class MissingArg (Exception ):
16- '''
17+ """
1718 Raised when a BaseConfigurable is missing an argument from the args dict it
1819 created with args(). If this exception is raised then the config() method is
1920 attempting to retrive an argument which was not set in the args() method.
20- '''
21+ """
22+
2123
2224class MissingConfig (Exception ):
23- '''
25+ """
2426 Raised when a BaseConfigurable is missing an argument from the config dict.
2527 Also raised if there was no default value set and the argument is missing.
26- '''
28+ """
29+
2730
2831class MissingRequiredProperty (Exception ):
29- '''
32+ """
3033 Raised when a BaseDataFlowFacilitatorObject is missing some property which
3134 should have been defined in the class.
32- '''
35+ """
36+
3337
3438class LoggingLogger (object ):
35- '''
39+ """
3640 Provide the logger property using Python's builtin logging module.
37- '''
41+ """
3842
3943 @property
4044 def logger (self ):
41- prop_name = ' __%s_logger' % (self .__class__ .__qualname__ ,)
45+ prop_name = " __%s_logger" % (self .__class__ .__qualname__ ,)
4246 logger = getattr (self , prop_name , False )
4347 if logger is False :
4448 logger = LOGGER .getChild (self .__class__ .__qualname__ )
4549 setattr (self , prop_name , logger )
4650 return logger
4751
52+
4853class BaseConfig (object ):
49- '''
54+ """
5055 All DFFML Base Objects should take an object (likely a typing.NamedTuple) as
5156 as their config.
52- '''
57+ """
5358
54- class ConfigurableParsingNamespace (object ):
5559
60+ class ConfigurableParsingNamespace (object ):
5661 def __init__ (self ):
5762 self .dest = None
5863
64+
5965class BaseConfigurable (abc .ABC ):
60- '''
66+ """
6167 Class which produces a config for itself by providing Args to a CMD (from
6268 dffml.util.cli.base) and then using a CMD after it contains parsed args to
6369 instantiate a config (deriving from BaseConfig) which will be used as the
6470 only parameter to the __init__ of a BaseDataFlowFacilitatorObject.
65- '''
71+ """
6672
6773 __argp = ArgumentParser ()
6874
6975 def __init__ (self , config : BaseConfig ) -> None :
70- '''
76+ """
7177 BaseConfigurable takes only one argument to __init__,
7278 its config, which should inherit from BaseConfig. It shall be a object
7379 containing any information needed to configure the class and it's child
7480 context's.
75- '''
81+ """
7682 self .config = config
7783
7884 @classmethod
@@ -83,14 +89,13 @@ def add_orig_label(cls, *above):
8389
8490 @classmethod
8591 def add_label (cls , * above ):
86- return (
87- list (above ) + cls .ENTRY_POINT_NAME + [cls .ENTRY_POINT_LABEL ]
88- )
92+ return list (above ) + cls .ENTRY_POINT_NAME + [cls .ENTRY_POINT_LABEL ]
8993
9094 @classmethod
9195 def config_set (cls , args , above , * path ) -> BaseConfig :
92- return traverse_config_set (args ,
93- * (cls .add_orig_label (* above ) + list (path )))
96+ return traverse_config_set (
97+ args , * (cls .add_orig_label (* above ) + list (path ))
98+ )
9499
95100 @classmethod
96101 def config_get (cls , config , above , * path ) -> BaseConfig :
@@ -102,69 +107,77 @@ def config_get(cls, config, above, *path) -> BaseConfig:
102107 try :
103108 arg = traverse_config_get (args , * args_above )
104109 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+ raise MissingArg (
111+ "Arg %r missing from %s%s%s"
112+ % (
113+ args_above [- 1 ],
114+ cls .__qualname__ ,
115+ "." if args_above [:- 1 ] else "" ,
116+ "." .join (args_above [:- 1 ]),
117+ )
118+ ) from error
110119 try :
111120 value = traverse_config_get (config , * label_above )
112121 except KeyError as error :
113122 try :
114123 value = traverse_config_get (config , * no_label_above )
115124 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' ]
125+ if "default" in arg :
126+ return arg ["default" ]
127+ raise MissingConfig (
128+ "%s missing %r from %s"
129+ % (
130+ cls .__qualname__ ,
131+ label_above [- 1 ],
132+ "." .join (label_above [:- 1 ]),
133+ )
134+ ) from error
135+
136+ if value is None and "default" in arg :
137+ return arg ["default" ]
126138 # TODO This is a oversimplification of argparse's nargs
127- if not ' nargs' in arg :
139+ if not " nargs" in arg :
128140 value = value [0 ]
129- if ' type' in arg :
141+ if " type" in arg :
130142 # TODO This is a oversimplification of argparse's nargs
131- if ' nargs' in arg :
132- value = list (map (arg [' type' ], value ))
143+ if " nargs" in arg :
144+ value = list (map (arg [" type" ], value ))
133145 else :
134- value = arg [' type' ](value )
135- if ' action' in arg :
136- if isinstance (arg [' action' ], str ):
146+ value = arg [" type" ](value )
147+ if " action" in arg :
148+ if isinstance (arg [" action" ], str ):
137149 # HACK This accesses _pop_action_class from ArgumentParser
138150 # which is prefaced with an underscore indicating it not an API
139151 # we can rely on
140- arg [' action' ] = cls .__argp ._pop_action_class (arg )
152+ arg [" action" ] = cls .__argp ._pop_action_class (arg )
141153 namespace = ConfigurableParsingNamespace ()
142- action = arg [' action' ](dest = ' dest' , option_strings = '' )
154+ action = arg [" action" ](dest = " dest" , option_strings = "" )
143155 action (None , namespace , value )
144156 value = namespace .dest
145157 return value
146158
147159 @classmethod
148160 @abc .abstractmethod
149161 def args (cls , * above ) -> Dict [str , Any ]:
150- '''
162+ """
151163 Return a dict containing arguments required for this class
152- '''
164+ """
153165
154166 @classmethod
155167 @abc .abstractmethod
156168 def config (cls , config , * above ):
157- '''
169+ """
158170 Create the BaseConfig required to instantiate this class by parsing the
159171 config dict.
160- '''
172+ """
161173
162174 @classmethod
163175 def withconfig (cls , config , * above ):
164176 return cls (cls .config (config , * above ))
165177
178+
166179class BaseDataFlowFacilitatorObjectContext (LoggingLogger ):
167- '''
180+ """
168181 Base class for all Data Flow Facilitator object's contexts. These are
169182 classes which support async context management. Classes ending with
170183 ...Context are the most inner context's which are used in DFFML.
@@ -173,19 +186,19 @@ class BaseDataFlowFacilitatorObjectContext(LoggingLogger):
173186 >>> # BaseDataFlowFacilitatorObjectContext.
174187 >>> async with obj() as ctx:
175188 >>> await ctx.method()
176- '''
189+ """
177190
178- async def __aenter__ (self ) -> ' BaseDataFlowFacilitatorObjectContext' :
191+ async def __aenter__ (self ) -> " BaseDataFlowFacilitatorObjectContext" :
179192 return self
180193
181194 async def __aexit__ (self , exc_type , exc_value , traceback ):
182195 pass
183196
184- class BaseDataFlowFacilitatorObject ( BaseDataFlowFacilitatorObjectContext , \
185- BaseConfigurable , \
186- Entrypoint ,
187- abc . ABC ):
188- '''
197+
198+ class BaseDataFlowFacilitatorObject (
199+ BaseDataFlowFacilitatorObjectContext , BaseConfigurable , Entrypoint , abc . ABC
200+ ):
201+ """
189202 Base class for all Data Flow Facilitator objects conforming to the
190203 instantiate -> enter context -> return context via __call__ -> enter
191204 returned context's context pattern. Therefore they must contain a CONTEXT
@@ -204,25 +217,26 @@ class BaseDataFlowFacilitatorObject(BaseDataFlowFacilitatorObjectContext, \
204217 >>> async with BaseDataFlowObject() as obj:
205218 >>> async with obj() as ctx:
206219 >>> await ctx.method()
207- '''
220+ """
208221
209222 def __init__ (self , config : BaseConfig ) -> None :
210223 BaseConfigurable .__init__ (self , config )
211224 # TODO figure out how to call these in __new__
212- self .__ensure_property (' CONTEXT' )
213- self .__ensure_property (' ENTRY_POINT' )
225+ self .__ensure_property (" CONTEXT" )
226+ self .__ensure_property (" ENTRY_POINT" )
214227
215228 def __repr__ (self ):
216- return ' %s(%r)' % (self .__class__ .__qualname__ , self .config )
229+ return " %s(%r)" % (self .__class__ .__qualname__ , self .config )
217230
218231 @abc .abstractmethod
219- def __call__ (self ) -> ' BaseDataFlowFacilitatorObjectContext' :
232+ def __call__ (self ) -> " BaseDataFlowFacilitatorObjectContext" :
220233 pass
221234
222235 @classmethod
223236 def __ensure_property (cls , property_name ):
224237 if getattr (cls , property_name , None ) is None :
225238 raise MissingRequiredProperty (
226- 'BaseDataFlowFacilitatorObjects may not be '
227- 'created without a `%s`. Missing %s.%s' \
228- % (property_name , cls .__qualname__ , property_name ,))
239+ "BaseDataFlowFacilitatorObjects may not be "
240+ "created without a `%s`. Missing %s.%s"
241+ % (property_name , cls .__qualname__ , property_name )
242+ )
0 commit comments