29 INSTANCE_ARGUMENT =
"instance" 32 """Inherit this class to give yourself a python class that wraps a set of 33 functions that together constitute the methods of the class. 35 The method functions must all have as a first argument an object 36 holding the instance data. There must also be a function that 37 returns a new instance of the class, the constructor. 39 Your subclass must define 40 _module - The module where the method functions, including the 41 constructor can be found 42 _new_instance - The name of a function that serves as a constructor, 43 returning the instance data. 45 To access the instance data, use the read-only property instance. 47 To add some functions from _module as methods, call classmethods like 48 add_method and add_methods_with_prefix. 50 def __new__(cls, *args, **kargs):
55 return super(ClassFromFunctions, cls).__new__(cls)
58 """Construct a new instance, using either the function 59 self._module[self._new_instance] or using existing instance 60 data. (specified with the keyword argument, instance) 62 if instance argument is None it will be ignored and the 63 constructor will be called to get a new instance 65 Pass the arguments that should be passed on to 66 self._module[self._new_instance]. Any arguments of that 67 are instances of ClassFromFunctions will be switched with the instance 68 data. (by calling the .instance property) 70 if INSTANCE_ARGUMENT
in kargs
and kargs[INSTANCE_ARGUMENT]
is not None:
71 inst = kargs[INSTANCE_ARGUMENT]
76 if isinstance(inst, ClassFromFunctions):
81 *process_list_convert_to_instance(args),
82 **process_dict_convert_to_instance(kargs))
85 """Get the instance data. 87 You can also call the instance property 91 instance = property(get_instance)
97 """! Add the function, method_name to this class as a method named name 100 @param cls Class: class to add methods to 101 @param function_name string: name of the function to add 102 @param method_name string: name of the method that function will be called 104 function will be wrapped by method_function""" 106 def method_function(self, *meth_func_args, **meth_func_kargs):
107 """! wrapper method for function 110 @param self: FunctionClass instance. Will be turned to its instance property. 111 @param *meth_func_args: arguments to be passed to function. All FunctionClass 112 objects will be turned to their respective instances. 113 @param **meth_func_kargs: keyword arguments to be passed to function. All 114 FunctionClass objects will be turned to their respective instances.""" 115 return getattr(self._module, function_name)(
117 *process_list_convert_to_instance(meth_func_args),
118 **process_dict_convert_to_instance(meth_func_kargs)
121 setattr(cls, method_name, method_function)
122 setattr(method_function,
"__name__", method_name)
123 return method_function
127 """! Add the function, method_name to this class as a classmethod named name 129 Taken from function_class and modified from add_method() to add classmethod 130 instead of method and not to turn self argument to self.instance. 133 @param cls Class: class to add methods to 134 @param function_name string: name of the function to add 135 @param method_name string: name of the classmethod that function will be called 137 function will be wrapped by method_function""" 139 def method_function(self, *meth_func_args, **meth_func_kargs):
140 """! wrapper method for function 143 @param self: FunctionClass instance. 144 @param *meth_func_args: arguments to be passed to function. All FunctionClass 145 objects will be turned to their respective instances. 146 @param **meth_func_kargs: keyword arguments to be passed to function. All 147 FunctionClass objects will be turned to their respective instances.""" 148 return getattr(self._module, function_name)(
150 *process_list_convert_to_instance(meth_func_args),
151 **process_dict_convert_to_instance(meth_func_kargs)
154 setattr(cls, method_name, classmethod(method_function))
155 setattr(method_function,
"__name__", method_name)
156 return method_function
160 """! Add the function, method_name to this class as a method named name 162 Taken from function_class. Modified to not turn self to self.instance 163 as add_method() does. 166 @param cls Class: class to add methods to 167 @param function_name string: name of the function to add 168 @param method_name string: name of the method that function will be called 170 function will be wrapped by method_function""" 172 def method_function(self, *meth_func_args, **meth_func_kargs):
173 """! wrapper method for function 176 @param self: FunctionClass instance. 177 @param *meth_func_args: arguments to be passed to function. All FunctionClass 178 objects will be turned to their respective instances. 179 @param **meth_func_kargs: keyword arguments to be passed to function. All 180 FunctionClass objects will be turned to their respective instances.""" 181 return getattr(self._module, function_name)(
183 *process_list_convert_to_instance(meth_func_args),
184 **process_dict_convert_to_instance(meth_func_kargs)
187 setattr(cls, method_name, method_function)
188 setattr(method_function,
"__name__", method_name)
189 return method_function
193 """Add a group of functions with the same prefix, exclude methods 196 for function_name, function_value, after_prefix
in \
197 extract_attributes_with_prefix(cls._module, prefix):
199 if not (function_name
in exclude):
204 """Add a group of functions with the same prefix, and set the 205 _new_instance attribute to prefix + constructor. Don't add methods 212 def decorate_functions(cls, decorator, *args):
213 for function_name
in args:
214 setattr( cls, function_name,
215 decorator( getattr(cls, function_name) ) )
219 """! decorate method method_name of class cls with decorator decorator 221 in difference to decorate_functions() this allows to provide additional 222 arguments for the decorator function. 226 @param decorator: function to decorate method 227 @param method_name: name of method to decorate (string) 228 @param *args: positional arguments for decorator 229 @param **kargs: keyword arguments for decorator""" 230 setattr(cls, method_name,
231 decorator(getattr(cls, method_name), *args, **kargs))
233 def method_function_returns_instance(method_function, cls):
234 """A function decorator that is used to decorate method functions that 235 return instance data, to return instances instead. 237 You can't use this decorator with @, because this function has a second 240 assert(
'instance' == INSTANCE_ARGUMENT )
241 def new_function(*args, **kargs):
242 kargs_cls = { INSTANCE_ARGUMENT : method_function(*args, **kargs) }
243 if kargs_cls[
'instance'] ==
None:
246 return cls( **kargs_cls )
250 def method_function_returns_instance_list(method_function, cls):
251 def new_function(*args, **kargs):
252 return [ cls( **{INSTANCE_ARGUMENT: item} )
253 for item
in method_function(*args, **kargs) ]
256 def methods_return_instance_lists(cls, function_dict):
257 for func_name, instance_name
in iter(function_dict.items()):
258 setattr(cls, func_name,
259 method_function_returns_instance_list(
260 getattr(cls, func_name), instance_name))
262 def default_arguments_decorator(function, *args, **kargs):
263 """! Decorates a function to give it default, positional and keyword arguments 265 mimics python behavior when setting defaults in function/method arguments. 266 arguments can be set for positional or keyword arguments. 268 kargs_pos contains positions of the keyword arguments. 269 @exception A TypeError will be raised if an argument is set as a positional and keyword argument 271 @note It might be possible to get keyword argument positional information using 272 introspection to avoid having to specify them manually 274 a keyword argument default will be overwritten by a positional argument at the 277 this function modifies the docstring of the wrapped function to reflect 280 You can't use this decorator with @, because this function has more 284 @param *args: optional positional defaults 285 @param kargs_pos: dict with keyword arguments as key and their position in the argument list as value 286 @param **kargs: optional keyword defaults 288 @return new_function wrapping original function 291 def new_function(*function_args, **function_kargs):
293 if "kargs_pos" in kargs:
294 kargs_pos = kargs.pop(
"kargs_pos")
295 new_argset = list(function_args)
296 new_argset.extend(args[len(function_args) :])
297 new_kargset = {**kargs, **function_kargs}
298 for karg_pos
in kargs_pos:
299 if karg_pos
in new_kargset:
300 pos_karg = kargs_pos[karg_pos]
301 if pos_karg < len(new_argset):
302 new_kargset.pop(karg_pos)
304 return function(*new_argset, **new_kargset)
306 kargs_pos = {}
if "kargs_pos" not in kargs
else kargs[
"kargs_pos"]
307 for karg_pos
in kargs_pos:
308 if karg_pos
in kargs:
309 pos_karg = kargs_pos[karg_pos]
310 if pos_karg < len(args):
312 "default_arguments_decorator() got multiple values for argument '%s'" 316 if new_function.__doc__
is None:
317 new_function.__doc__ =
"" 320 new_function.__doc__ +=
"positional argument defaults:\n" 323 new_function.__doc__ +=
", " 325 new_function.__doc__ +=
" " 327 new_function.__doc__ += str(arg)
328 new_function.__doc__ +=
"\n" 330 new_function.__doc__ +=
"keyword argument defaults:\n" 332 if karg !=
"kargs_pos":
333 new_function.__doc__ += (
334 " " + str(karg) +
" = " + str(kargs[karg]) +
"\n" 337 new_function.__doc__ +=
"keyword argument positions:\n" 338 for karg
in kargs_pos:
339 new_function.__doc__ += (
340 " " + str(karg) +
" is at pos " + str(kargs_pos[karg]) +
"\n" 342 if len(args)
or len(kargs):
343 new_function.__doc__ += (
344 "(defaults have been set by default_arguments_decorator method)" 349 def return_instance_if_value_has_it(value):
350 """Return value.instance if value is an instance of ClassFromFunctions, 353 if isinstance(value, ClassFromFunctions):
354 return value.instance
358 def process_list_convert_to_instance( value_list ):
359 """Return a list built from value_list, where if a value is in an instance 360 of ClassFromFunctions, we put value.instance in the list instead. 362 Things that are not instances of ClassFromFunctions are returned to 363 the new list unchanged. 365 return [ return_instance_if_value_has_it(value)
366 for value
in value_list ]
368 def process_dict_convert_to_instance(value_dict):
369 """Return a dict built from value_dict, where if a value is in an instance 370 of ClassFromFunctions, we put value.instance in the dict instead. 372 Things that are not instances of ClassFromFunctions are returned to 373 the new dict unchanged. 376 key: return_instance_if_value_has_it(value)
for key, value
in value_dict.items()
380 def extract_attributes_with_prefix(obj, prefix):
381 """Generator that iterates through the attributes of an object and 382 for any attribute that matches a prefix, this yields 383 the attribute name, the attribute value, and the text that appears 384 after the prefix in the name 386 for attr_name, attr_value
in iter(obj.__dict__.items()):
387 if attr_name.startswith(prefix):
388 after_prefix = attr_name[ len(prefix): ]
389 yield attr_name, attr_value, after_prefix
391 def methods_return_instance(cls, function_dict):
392 """Iterates through a dictionary of function name strings and instance names 393 and sets the function to return the associated instance 395 for func_name, instance_name
in iter(function_dict.items()):
396 setattr(cls, func_name,
397 method_function_returns_instance( getattr(cls, func_name), instance_name))
def ya_add_method(cls, function_name, method_name)
Add the function, method_name to this class as a method named name.
def add_method(cls, function_name, method_name)
Add the function, method_name to this class as a method named name.
def add_constructor_and_methods_with_prefix(cls, prefix, constructor, exclude=[])
def ya_add_classmethod(cls, function_name, method_name)
Add the function, method_name to this class as a classmethod named name.
def __init__(self, args, kargs)
def decorate_method(cls, decorator, method_name, args, kargs)
decorate method method_name of class cls with decorator decorator
def add_methods_with_prefix(cls, prefix, exclude=[])