|
1
|
|
|
|
|
2
|
|
|
# :version: 0.1.0 |
|
3
|
|
|
# :copyright: Copyright (C) 2014 Universidad Carlos III de Madrid. |
|
4
|
|
|
# Todos los derechos reservados. |
|
5
|
|
|
# :license LASR_UC3M v1.0, ver LICENCIA.txt |
|
6
|
|
|
|
|
7
|
|
|
# Este programa es software libre: puede redistribuirlo y/o modificarlo |
|
8
|
|
|
# bajo los terminos de la Licencia Academica Social Robotics Lab - UC3M |
|
9
|
|
|
# publicada por la Universidad Carlos III de Madrid, tanto en su version 1.0 |
|
10
|
|
|
# como en una version posterior. |
|
11
|
|
|
|
|
12
|
|
|
# Este programa se distribuye con la intencion de que sea util, |
|
13
|
|
|
# pero SIN NINGUNA GARANTIA. Para mas detalles, consulte la |
|
14
|
|
|
# Licencia Academica Social Robotics Lab - UC3M version 1.0 o posterior. |
|
15
|
|
|
|
|
16
|
|
|
# Usted ha recibido una copia de la Licencia Academica Social |
|
17
|
|
|
# Robotics Lab - UC3M en el fichero LICENCIA.txt, que tambien se encuentra |
|
18
|
|
|
# disponible en <URL a la LASR_UC3Mv1.0>. |
|
19
|
|
|
|
|
20
|
|
|
|
|
21
|
|
|
""" |
|
22
|
|
|
Utils to ease the use of functions and methods in Python. |
|
23
|
|
|
|
|
24
|
|
|
:author: Victor Gonzalez Pacheco (victor.gonzalez.pacheco at gmail.com) |
|
25
|
|
|
:date: 2014-04 |
|
26
|
|
|
""" |
|
27
|
|
|
|
|
28
|
|
|
from functools import wraps |
|
29
|
|
|
from contextlib import contextmanager |
|
30
|
|
|
|
|
31
|
|
|
|
|
32
|
|
|
class PreconditionError(Exception): |
|
33
|
|
|
|
|
34
|
|
|
""" |
|
35
|
|
|
Exception that shuold be raised when the preconditions of a function |
|
36
|
|
|
are not met |
|
37
|
|
|
""" |
|
38
|
|
|
pass |
|
39
|
|
|
|
|
40
|
|
|
|
|
41
|
|
|
@contextmanager |
|
42
|
|
|
def error_handler(logger=None, log_msg='', |
|
43
|
|
|
action=None, action_args=None, action_kwargs=None, |
|
44
|
|
|
errors=Exception, reraise=False): |
|
45
|
|
|
""" |
|
46
|
|
|
Context Manager that logs errors and executes an action if error occurs. |
|
47
|
|
|
|
|
48
|
|
|
:param logger: logging function. Default: None |
|
49
|
|
|
:type logger: callable |
|
50
|
|
|
:param log_msg: message to add to the logger in case of fail |
|
51
|
|
|
(It will be preced to the exception message) |
|
52
|
|
|
:type log_msg: str |
|
53
|
|
|
:param action: function to call if an exception occurs. Default: None |
|
54
|
|
|
:type action: callable |
|
55
|
|
|
:param action_args: argument list to pass to action. Default:[] |
|
56
|
|
|
:param action_kwargs: argument keywords to pass to action. Default: {} |
|
57
|
|
|
:param errors: exceptions to catch. Default: Exception |
|
58
|
|
|
:type errors: Exception or a list of Exceptions |
|
59
|
|
|
:param reraise: (default: False) Wether to reraise precondition errors |
|
60
|
|
|
""" |
|
61
|
|
|
try: |
|
62
|
|
|
yield |
|
63
|
|
|
except errors as e: |
|
|
|
|
|
|
64
|
|
|
exception_msg = ''.join([log_msg, str(e)]) |
|
65
|
|
|
if logger: |
|
66
|
|
|
logger(str(exception_msg)) |
|
67
|
|
|
if action: |
|
68
|
|
|
action(*action_args, **action_kwargs) |
|
69
|
|
|
if reraise: |
|
70
|
|
|
raise e |
|
71
|
|
|
|
|
72
|
|
|
|
|
73
|
|
|
def preconditions(precons, logger=None, log_msg='', errors=PreconditionError, |
|
74
|
|
|
reraise=True): |
|
75
|
|
|
""" |
|
76
|
|
|
Decorator that binds precondition checking to a function. |
|
77
|
|
|
|
|
78
|
|
|
:param precons: Preconditions to check |
|
79
|
|
|
Must be a function with same attribs as decorated func |
|
80
|
|
|
:type precons: callable |
|
81
|
|
|
:param logger: Logger function executed in case of precons fail |
|
82
|
|
|
Default: None |
|
83
|
|
|
:param log_msg: Message to add to the logger in case of fail |
|
84
|
|
|
(It will be preced to the exception message) |
|
85
|
|
|
Default: '' |
|
86
|
|
|
:type log_msg: str |
|
87
|
|
|
:param errors: Exceptions to catch in preconditions. |
|
88
|
|
|
Default: L{PreconditionError} |
|
89
|
|
|
:type errors: Exception or a list of Exceptions |
|
90
|
|
|
:param reraise: (default: True) Wether to reraise precondition errors |
|
91
|
|
|
|
|
92
|
|
|
:return: None if reraise is false and preconditions do not pass |
|
93
|
|
|
""" |
|
94
|
|
|
def decor(f): |
|
95
|
|
|
@wraps(f) |
|
96
|
|
|
def wrapper(*args, **kwargs): |
|
97
|
|
|
with error_handler(logger=logger, log_msg=log_msg, |
|
98
|
|
|
errors=errors, reraise=reraise): |
|
99
|
|
|
precons(*args, **kwargs) |
|
100
|
|
|
return f(*args, **kwargs) |
|
101
|
|
|
return None # Arrives here only if reraises=False and precons fail |
|
102
|
|
|
return wrapper |
|
103
|
|
|
return decor |
|
104
|
|
|
|
|
105
|
|
|
|
|
106
|
|
|
def load_class(full_name): |
|
107
|
|
|
""" |
|
108
|
|
|
Returns an builder of a Python class from its qualified full name. |
|
109
|
|
|
To build the object of that class, simply call the returned object. |
|
110
|
|
|
|
|
111
|
|
|
Adapted from this SO Answer: http://stackoverflow.com/a/547867/630598 |
|
112
|
|
|
|
|
113
|
|
|
:type full_name: string |
|
114
|
|
|
:param full_name: Class full name: foo.bar.klass |
|
115
|
|
|
:return: an instance of foo.bar.Klass. It has to be called just |
|
116
|
|
|
|
|
117
|
|
|
Example: |
|
118
|
|
|
|
|
119
|
|
|
>>> # Assume Klass is declared in module foo.bar |
|
120
|
|
|
>>> class Klass(): |
|
121
|
|
|
>>> def __init__(self): |
|
122
|
|
|
>>> print('klass instantiated') |
|
123
|
|
|
|
|
124
|
|
|
>>> my_class = load_class('foo.bar.Klass') |
|
125
|
|
|
>>> my_class() |
|
126
|
|
|
... 'klass instantiated' |
|
127
|
|
|
""" |
|
128
|
|
|
module_name, klass_name = full_name.rsplit('.', 1) |
|
129
|
|
|
mod = __import__(module_name, fromlist=[klass_name]) |
|
130
|
|
|
klass = getattr(mod, klass_name) |
|
131
|
|
|
return klass |
|
132
|
|
|
|
Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.
So, unless you specifically plan to handle any error, consider adding a more specific exception.