-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy path_sync.py
More file actions
73 lines (57 loc) · 2.34 KB
/
Copy path_sync.py
File metadata and controls
73 lines (57 loc) · 2.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# -*- test-case-name: effect.test_sync -*-
"""
Tools for dealing with Effects synchronously.
"""
from ._base import perform
from ._utils import wraps
class NotSynchronousError(Exception):
"""Performing an effect did not immediately return a value."""
def sync_perform(dispatcher, effect):
"""
Perform an effect, and return its ultimate result. If the final result is
an error, the exception will be raised.
This requires that the effect (and all effects returned from any of its
callbacks) be synchronous. If the result is not available immediately,
:class:`NotSynchronousError` will be raised.
"""
successes = []
errors = []
effect = effect.on(success=successes.append, error=errors.append)
perform(dispatcher, effect)
if successes:
return successes[0]
elif errors:
raise errors[0]
else:
raise NotSynchronousError("Performing %r was not synchronous!" % (effect,))
def sync_performer(f):
"""
A decorator for performers that return a value synchronously.
This decorator should be used if performing the intent will be synchronous,
i.e., it will block until the result is available and the result will be
simply returned. This is the common case unless you're using an
asynchronous framework like Twisted or asyncio.
Note that in addition to returning (or raising) values as normal, you can
also return another Effect, in which case that Effect will be immediately
performed with the same dispatcher. This is useful if you're implementing
one intent which is built on top of other effects, without having to
explicitly perform them.
The function being decorated is expected to take a dispatcher and an
intent, and should return or raise normally. The wrapper function that this
decorator returns will accept a dispatcher, an intent, and a box
(conforming to the performer interface). The wrapper deals with putting the
return value or exception into the box.
Example::
@sync_performer
def perform_foo(dispatcher, foo):
return do_side_effect(foo)
"""
@wraps(f)
def sync_wrapper(*args, **kwargs):
box = args[-1]
pass_args = args[:-1]
try:
box.succeed(f(*pass_args, **kwargs))
except Exception as e:
box.fail(e)
return sync_wrapper