/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/decorators.py

  • Committer: Jelmer Vernooij
  • Date: 2018-04-02 00:52:27 UTC
  • mfrom: (6939 work)
  • mto: This revision was merged to the branch mainline in revision 7274.
  • Revision ID: jelmer@jelmer.uk-20180402005227-pecflp1mvdjrjqd6
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
from __future__ import absolute_import
18
18
 
19
 
__all__ = ['needs_read_lock',
20
 
           'needs_write_lock',
21
 
           'use_fast_decorators',
22
 
           'use_pretty_decorators',
23
 
           ]
24
 
 
25
 
 
26
19
from . import trace
27
20
 
28
21
 
29
 
def _get_parameters(func):
30
 
    """Recreate the parameters for a function using introspection.
31
 
 
32
 
    :return: (function_params, calling_params, default_values)
33
 
        function_params: is a string representing the parameters of the
34
 
            function. (such as "a, b, c=None, d=1")
35
 
            This is used in the function declaration.
36
 
        calling_params: is another string representing how you would call the
37
 
            function with the correct parameters. (such as "a, b, c=c, d=d")
38
 
            Assuming you used function_params in the function declaration, this
39
 
            is the parameters to put in the function call.
40
 
        default_values_block: a dict with the default values to be passed as
41
 
            the scope for the 'exec' statement.
42
 
 
43
 
        For example:
44
 
 
45
 
        def wrapper(%(function_params)s):
46
 
            return original(%(calling_params)s)
47
 
    """
48
 
    # "import inspect" should stay in local scope. 'inspect' takes a long time
49
 
    # to import the first time. And since we don't always need it, don't import
50
 
    # it globally.
51
 
    import inspect
52
 
    args, varargs, varkw, defaults = inspect.getargspec(func)
53
 
    defaults_dict = {}
54
 
    def formatvalue(value):
55
 
        default_name = '__default_%d' % len(defaults_dict)
56
 
        defaults_dict[default_name] = value
57
 
        return '=' + default_name
58
 
    formatted = inspect.formatargspec(args, varargs=varargs,
59
 
                                      varkw=varkw,
60
 
                                      defaults=defaults,
61
 
                                      formatvalue=formatvalue)
62
 
    if defaults is None:
63
 
        args_passed = args
64
 
    else:
65
 
        first_default = len(args) - len(defaults)
66
 
        args_passed = args[:first_default]
67
 
        for arg in args[first_default:]:
68
 
            args_passed.append("%s=%s" % (arg, arg))
69
 
    if varargs is not None:
70
 
        args_passed.append('*' + varargs)
71
 
    if varkw is not None:
72
 
        args_passed.append('**' + varkw)
73
 
    args_passed = ', '.join(args_passed)
74
 
 
75
 
    return formatted[1:-1], args_passed, defaults_dict
76
 
 
77
 
 
78
 
def _pretty_needs_read_lock(unbound):
79
 
    """Decorate unbound to take out and release a read lock.
80
 
 
81
 
    This decorator can be applied to methods of any class with lock_read() and
82
 
    unlock() methods.
83
 
 
84
 
    Typical usage:
85
 
 
86
 
    class Branch(...):
87
 
        @needs_read_lock
88
 
        def branch_method(self, ...):
89
 
            stuff
90
 
    """
91
 
    # This compiles a function with a similar name, but wrapped with
92
 
    # lock_read/unlock calls. We use dynamic creation, because we need the
93
 
    # internal name of the function to be modified so that --lsprof will see
94
 
    # the correct name.
95
 
    # TODO: jam 20070111 Modify this template so that the generated function
96
 
    #       has the same argument signature as the original function, which
97
 
    #       will help commands like epydoc.
98
 
    #       This seems possible by introspecting foo.func_defaults, and
99
 
    #       foo.func_code.co_argcount and foo.func_code.co_varnames
100
 
    template = """\
101
 
def %(name)s_read_locked(%(params)s):
102
 
    self.lock_read()
103
 
    try:
104
 
        result = unbound(%(passed_params)s)
105
 
    except:
106
 
        try:
107
 
            self.unlock()
108
 
        finally:
109
 
            raise
110
 
    else:
111
 
        self.unlock()
112
 
        return result
113
 
read_locked = %(name)s_read_locked
114
 
"""
115
 
    params, passed_params, defaults_dict = _get_parameters(unbound)
116
 
    variables = {'name':unbound.__name__,
117
 
                 'params':params,
118
 
                 'passed_params':passed_params,
119
 
                }
120
 
    func_def = template % variables
121
 
 
122
 
    scope = dict(defaults_dict)
123
 
    scope['unbound'] = unbound
124
 
    exec(func_def, scope)
125
 
    read_locked = scope['read_locked']
126
 
 
127
 
    read_locked.__doc__ = unbound.__doc__
128
 
    read_locked.__name__ = unbound.__name__
129
 
    return read_locked
130
 
 
131
 
 
132
 
def _fast_needs_read_lock(unbound):
133
 
    """Decorate unbound to take out and release a read lock.
134
 
 
135
 
    This decorator can be applied to methods of any class with lock_read() and
136
 
    unlock() methods.
137
 
 
138
 
    Typical usage:
139
 
 
140
 
    class Branch(...):
141
 
        @needs_read_lock
142
 
        def branch_method(self, ...):
143
 
            stuff
144
 
    """
145
 
    def read_locked(self, *args, **kwargs):
146
 
        self.lock_read()
147
 
        try:
148
 
            result = unbound(self, *args, **kwargs)
149
 
        except:
150
 
            try:
151
 
                self.unlock()
152
 
            finally:
153
 
                raise
154
 
        else:
155
 
            self.unlock()
156
 
            return result
157
 
    read_locked.__doc__ = unbound.__doc__
158
 
    read_locked.__name__ = unbound.__name__
159
 
    return read_locked
160
 
 
161
 
 
162
 
def _pretty_needs_write_lock(unbound):
163
 
    """Decorate unbound to take out and release a write lock."""
164
 
    template = """\
165
 
def %(name)s_write_locked(%(params)s):
166
 
    self.lock_write()
167
 
    try:
168
 
        result = unbound(%(passed_params)s)
169
 
    except:
170
 
        try:
171
 
            self.unlock()
172
 
        finally:
173
 
            raise
174
 
    else:
175
 
        self.unlock()
176
 
        return result
177
 
write_locked = %(name)s_write_locked
178
 
"""
179
 
    params, passed_params, defaults_dict = _get_parameters(unbound)
180
 
    variables = {'name':unbound.__name__,
181
 
                 'params':params,
182
 
                 'passed_params':passed_params,
183
 
                }
184
 
    func_def = template % variables
185
 
 
186
 
    scope = dict(defaults_dict)
187
 
    scope['unbound'] = unbound
188
 
    exec(func_def, scope)
189
 
    write_locked = scope['write_locked']
190
 
 
191
 
    write_locked.__doc__ = unbound.__doc__
192
 
    write_locked.__name__ = unbound.__name__
193
 
    return write_locked
194
 
 
195
 
 
196
 
def _fast_needs_write_lock(unbound):
197
 
    """Decorate unbound to take out and release a write lock."""
198
 
    def write_locked(self, *args, **kwargs):
199
 
        self.lock_write()
200
 
        try:
201
 
            result = unbound(self, *args, **kwargs)
202
 
        except:
203
 
            try:
204
 
                self.unlock()
205
 
            finally:
206
 
                raise
207
 
        else:
208
 
            self.unlock()
209
 
            return result
210
 
    write_locked.__doc__ = unbound.__doc__
211
 
    write_locked.__name__ = unbound.__name__
212
 
    return write_locked
213
 
 
214
 
 
215
22
def only_raises(*errors):
216
23
    """Make a decorator that will only allow the given error classes to be
217
24
    raised.  All other errors will be logged and then discarded.
237
44
    return decorator
238
45
 
239
46
 
240
 
# Default is more functionality, 'bzr' the commandline will request fast
241
 
# versions.
242
 
needs_read_lock = _pretty_needs_read_lock
243
 
needs_write_lock = _pretty_needs_write_lock
244
 
 
245
 
 
246
 
def use_fast_decorators():
247
 
    """Change the default decorators to be fast loading ones.
248
 
 
249
 
    The alternative is to have decorators that do more work to produce
250
 
    nice-looking decorated functions, but this slows startup time.
251
 
    """
252
 
    global needs_read_lock, needs_write_lock
253
 
    needs_read_lock = _fast_needs_read_lock
254
 
    needs_write_lock = _fast_needs_write_lock
255
 
 
256
 
 
257
 
def use_pretty_decorators():
258
 
    """Change the default decorators to be pretty ones."""
259
 
    global needs_read_lock, needs_write_lock
260
 
    needs_read_lock = _pretty_needs_read_lock
261
 
    needs_write_lock = _pretty_needs_write_lock
262
 
 
263
 
 
264
47
# This implementation of cachedproperty is copied from Launchpad's
265
48
# canonical.launchpad.cachedproperty module (with permission from flacoste)
266
49
# -- spiv & vila 100120