|
9 | 9 |
|
10 | 10 | class ContextDecorator(object): |
11 | 11 | "A base class or mixin that enables context managers to work as decorators." |
| 12 | + |
| 13 | + def _recreate_cm(self): |
| 14 | + """Return a recreated instance of self. |
| 15 | + |
| 16 | + Allows otherwise one-shot context managers like |
| 17 | + _GeneratorContextManager to support use as |
| 18 | + decorators via implicit recreation. |
| 19 | + |
| 20 | + Note: this is a private interface just for _GCM in 3.2 but will be |
| 21 | + renamed and documented for third party use in 3.3 |
| 22 | + """ |
| 23 | + return self |
| 24 | + |
12 | 25 | def __call__(self, func): |
13 | 26 | @wraps(func) |
14 | 27 | def inner(*args, **kwds): |
15 | | - with self: |
| 28 | + with self._recreate_cm(): |
16 | 29 | return func(*args, **kwds) |
17 | 30 | return inner |
18 | 31 |
|
19 | 32 |
|
20 | 33 | class _GeneratorContextManager(ContextDecorator): |
21 | 34 | """Helper for @contextmanager decorator.""" |
22 | 35 |
|
23 | | - def __init__(self, gen): |
24 | | - self.gen = gen |
| 36 | + def __init__(self, func, *args, **kwds): |
| 37 | + self.gen = func(*args, **kwds) |
| 38 | + self.func, self.args, self.kwds = func, args, kwds |
| 39 | + |
| 40 | + def _recreate_cm(self): |
| 41 | + # _GCM instances are one-shot context managers, so the |
| 42 | + # CM must be recreated each time a decorated function is |
| 43 | + # called |
| 44 | + return self.__class__(self.func, *self.args, **self.kwds) |
25 | 45 |
|
26 | 46 | def __enter__(self): |
27 | 47 | try: |
@@ -92,7 +112,7 @@ def some_generator(<arguments>): |
92 | 112 | """ |
93 | 113 | @wraps(func) |
94 | 114 | def helper(*args, **kwds): |
95 | | - return _GeneratorContextManager(func(*args, **kwds)) |
| 115 | + return _GeneratorContextManager(func, *args, **kwds) |
96 | 116 | return helper |
97 | 117 |
|
98 | 118 |
|
|
0 commit comments