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:
74 *process_list_convert_to_instance(args),
75 **process_dict_convert_to_instance(kargs))
78 """Get the instance data. 80 You can also call the instance property 84 instance = property(get_instance)
90 """! Add the function, method_name to this class as a method named name 93 @param cls Class: class to add methods to 94 @param function_name string: name of the function to add 95 @param method_name string: name of the method that function will be called 97 function will be wrapped by method_function""" 99 def method_function(self, *meth_func_args, **meth_func_kargs):
100 """! wrapper method for function 103 @param self: FunctionClass instance. Will be turned to its instance property. 104 @param *meth_func_args: arguments to be passed to function. All FunctionClass 105 objects will be turned to their respective instances. 106 @param **meth_func_kargs: keyword arguments to be passed to function. All 107 FunctionClass objects will be turned to their respective instances.""" 108 return getattr(self._module, function_name)(
110 *process_list_convert_to_instance(meth_func_args),
111 **process_dict_convert_to_instance(meth_func_kargs)
114 setattr(cls, method_name, method_function)
115 setattr(method_function,
"__name__", method_name)
116 return method_function
120 """! Add the function, method_name to this class as a classmethod named name 122 Taken from function_class and modified from add_method() to add classmethod 123 instead of method and not to turn self argument to self.instance. 126 @param cls Class: class to add methods to 127 @param function_name string: name of the function to add 128 @param method_name string: name of the classmethod that function will be called 130 function will be wrapped by method_function""" 132 def method_function(self, *meth_func_args, **meth_func_kargs):
133 """! wrapper method for function 136 @param self: FunctionClass instance. 137 @param *meth_func_args: arguments to be passed to function. All FunctionClass 138 objects will be turned to their respective instances. 139 @param **meth_func_kargs: keyword arguments to be passed to function. All 140 FunctionClass objects will be turned to their respective instances.""" 141 return getattr(self._module, function_name)(
143 *process_list_convert_to_instance(meth_func_args),
144 **process_dict_convert_to_instance(meth_func_kargs)
147 setattr(cls, method_name, classmethod(method_function))
148 setattr(method_function,
"__name__", method_name)
149 return method_function
153 """! Add the function, method_name to this class as a method named name 155 Taken from function_class. Modified to not turn self to self.instance 156 as add_method() does. 159 @param cls Class: class to add methods to 160 @param function_name string: name of the function to add 161 @param method_name string: name of the method that function will be called 163 function will be wrapped by method_function""" 165 def method_function(self, *meth_func_args, **meth_func_kargs):
166 """! wrapper method for function 169 @param self: FunctionClass instance. 170 @param *meth_func_args: arguments to be passed to function. All FunctionClass 171 objects will be turned to their respective instances. 172 @param **meth_func_kargs: keyword arguments to be passed to function. All 173 FunctionClass objects will be turned to their respective instances.""" 174 return getattr(self._module, function_name)(
176 *process_list_convert_to_instance(meth_func_args),
177 **process_dict_convert_to_instance(meth_func_kargs)
180 setattr(cls, method_name, method_function)
181 setattr(method_function,
"__name__", method_name)
182 return method_function
186 """Add a group of functions with the same prefix, exclude methods 189 for function_name, function_value, after_prefix
in \
190 extract_attributes_with_prefix(cls._module, prefix):
192 if not (function_name
in exclude):
197 """Add a group of functions with the same prefix, and set the 198 _new_instance attribute to prefix + constructor. Don't add methods 205 def decorate_functions(cls, decorator, *args):
206 for function_name
in args:
207 setattr( cls, function_name,
208 decorator( getattr(cls, function_name) ) )
212 """! decorate method method_name of class cls with decorator decorator 214 in difference to decorate_functions() this allows to provide additional 215 arguments for the decorator function. 219 @param decorator: function to decorate method 220 @param method_name: name of method to decorate (string) 221 @param *args: positional arguments for decorator 222 @param **kargs: keyword arguments for decorator""" 223 setattr(cls, method_name,
224 decorator(getattr(cls, method_name), *args, **kargs))
226 def method_function_returns_instance(method_function, cls):
227 """A function decorator that is used to decorate method functions that 228 return instance data, to return instances instead. 230 You can't use this decorator with @, because this function has a second 233 assert(
'instance' == INSTANCE_ARGUMENT )
234 def new_function(*args, **kargs):
235 kargs_cls = { INSTANCE_ARGUMENT : method_function(*args, **kargs) }
236 if kargs_cls[
'instance'] ==
None:
239 return cls( **kargs_cls )
243 def method_function_returns_instance_list(method_function, cls):
244 def new_function(*args, **kargs):
245 return [ cls( **{INSTANCE_ARGUMENT: item} )
246 for item
in method_function(*args, **kargs) ]
249 def methods_return_instance_lists(cls, function_dict):
250 for func_name, instance_name
in iter(function_dict.items()):
251 setattr(cls, func_name,
252 method_function_returns_instance_list(
253 getattr(cls, func_name), instance_name))
255 def default_arguments_decorator(function, *args, **kargs):
256 """! Decorates a function to give it default, positional and keyword arguments 258 mimics python behavior when setting defaults in function/method arguments. 259 arguments can be set for positional or keyword arguments. 261 kargs_pos contains positions of the keyword arguments. 262 @exception A TypeError will be raised if an argument is set as a positional and keyword argument 264 @note It might be possible to get keyword argument positional information using 265 introspection to avoid having to specify them manually 267 a keyword argument default will be overwritten by a positional argument at the 270 this function modifies the docstring of the wrapped function to reflect 273 You can't use this decorator with @, because this function has more 277 @param *args: optional positional defaults 278 @param kargs_pos: dict with keyword arguments as key and their position in the argument list as value 279 @param **kargs: optional keyword defaults 281 @return new_function wrapping original function 284 def new_function(*function_args, **function_kargs):
286 if "kargs_pos" in kargs:
287 kargs_pos = kargs.pop(
"kargs_pos")
288 new_argset = list(function_args)
289 new_argset.extend(args[len(function_args) :])
290 new_kargset = {**kargs, **function_kargs}
291 for karg_pos
in kargs_pos:
292 if karg_pos
in new_kargset:
293 pos_karg = kargs_pos[karg_pos]
294 if pos_karg < len(new_argset):
295 new_kargset.pop(karg_pos)
297 return function(*new_argset, **new_kargset)
299 kargs_pos = {}
if "kargs_pos" not in kargs
else kargs[
"kargs_pos"]
300 for karg_pos
in kargs_pos:
301 if karg_pos
in kargs:
302 pos_karg = kargs_pos[karg_pos]
303 if pos_karg < len(args):
305 "default_arguments_decorator() got multiple values for argument '%s'" 309 if new_function.__doc__
is None:
310 new_function.__doc__ =
"" 313 new_function.__doc__ +=
"positional argument defaults:\n" 316 new_function.__doc__ +=
", " 318 new_function.__doc__ +=
" " 320 new_function.__doc__ += str(arg)
321 new_function.__doc__ +=
"\n" 323 new_function.__doc__ +=
"keyword argument defaults:\n" 325 if karg !=
"kargs_pos":
326 new_function.__doc__ += (
327 " " + str(karg) +
" = " + str(kargs[karg]) +
"\n" 330 new_function.__doc__ +=
"keyword argument positions:\n" 331 for karg
in kargs_pos:
332 new_function.__doc__ += (
333 " " + str(karg) +
" is at pos " + str(kargs_pos[karg]) +
"\n" 335 if len(args)
or len(kargs):
336 new_function.__doc__ += (
337 "(defaults have been set by default_arguments_decorator method)" 342 def return_instance_if_value_has_it(value):
343 """Return value.instance if value is an instance of ClassFromFunctions, 346 if isinstance(value, ClassFromFunctions):
347 return value.instance
351 def process_list_convert_to_instance( value_list ):
352 """Return a list built from value_list, where if a value is in an instance 353 of ClassFromFunctions, we put value.instance in the list instead. 355 Things that are not instances of ClassFromFunctions are returned to 356 the new list unchanged. 358 return [ return_instance_if_value_has_it(value)
359 for value
in value_list ]
361 def process_dict_convert_to_instance(value_dict):
362 """Return a dict built from value_dict, where if a value is in an instance 363 of ClassFromFunctions, we put value.instance in the dict instead. 365 Things that are not instances of ClassFromFunctions are returned to 366 the new dict unchanged. 369 key: return_instance_if_value_has_it(value)
for key, value
in value_dict.items()
373 def extract_attributes_with_prefix(obj, prefix):
374 """Generator that iterates through the attributes of an object and 375 for any attribute that matches a prefix, this yields 376 the attribute name, the attribute value, and the text that appears 377 after the prefix in the name 379 for attr_name, attr_value
in iter(obj.__dict__.items()):
380 if attr_name.startswith(prefix):
381 after_prefix = attr_name[ len(prefix): ]
382 yield attr_name, attr_value, after_prefix
384 def methods_return_instance(cls, function_dict):
385 """Iterates through a dictionary of function name strings and instance names 386 and sets the function to return the associated instance 388 for func_name, instance_name
in iter(function_dict.items()):
389 setattr(cls, func_name,
390 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=[])