Skip to content

Commit ca4e172

Browse files
committed
Capture contect from first call in eliot_friendly_generator_function.
1 parent d7e7071 commit ca4e172

File tree

2 files changed

+53
-13
lines changed

2 files changed

+53
-13
lines changed

eliot/_generators.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def eliot_friendly_generator_function(original):
4343
"""
4444

4545
@wraps(original)
46-
def wrapper(*a, **kw):
46+
def wrapper(context, *a, **kw):
4747
# Keep track of whether the next value to deliver to the generator is
4848
# a non-exception or an exception.
4949
ok = True
@@ -57,8 +57,6 @@ def wrapper(*a, **kw):
5757
# generator function can run until we call send or throw on it.
5858
gen = original(*a, **kw)
5959

60-
# Initialize the per-generator context to a copy of the current context.
61-
context = copy_context()
6260
while True:
6361
try:
6462
# Whichever way we invoke the generator, we will do it
@@ -97,7 +95,7 @@ def go():
9795
# indication of where the yield occurred.
9896
#
9997
# This is noisy, enable only for debugging:
100-
if wrapper.debug:
98+
if trampoline.debug:
10199
log_message(message_type="yielded")
102100
return value_out
103101

@@ -127,5 +125,12 @@ def go():
127125
else:
128126
ok = True
129127

130-
wrapper.debug = False
131-
return wrapper
128+
@wraps(original)
129+
def trampoline(*a, **kw):
130+
# Initialize the generator context to a copy of the current context at
131+
# the site where the generator is invoked.
132+
context = copy_context()
133+
return wrapper(context, *a, **kw)
134+
135+
trampoline.debug = False
136+
return trampoline

eliot/tests/test_generators.py

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -220,14 +220,14 @@ def g(which):
220220

221221
g.debug = True # output yielded messages
222222

223-
gens = [g("1"), g("2")]
224223
with start_action(action_type="the-action"):
225-
while gens:
226-
for g in gens[:]:
227-
try:
228-
next(g)
229-
except StopIteration:
230-
gens.remove(g)
224+
gens = [g("1"), g("2")]
225+
while gens:
226+
for g in gens[:]:
227+
try:
228+
next(g)
229+
except StopIteration:
230+
gens.remove(g)
231231

232232
assert_expected_action_tree(
233233
self,
@@ -292,3 +292,38 @@ def g(recurse):
292292
}
293293
],
294294
)
295+
296+
@capture_logging(None)
297+
def test_capture_context(self, logger):
298+
"""
299+
L{eliot_friendly_generator_function} decorated generators capture the
300+
context where they are created, not where L{.send} is first called on
301+
them.
302+
"""
303+
@eliot_friendly_generator_function
304+
def g():
305+
yield
306+
307+
g.debug = True # output yielded messages
308+
309+
with start_action(action_type="the-action"):
310+
with start_action(action_type="start"):
311+
gen = g()
312+
with start_action(action_type="run"):
313+
list(gen)
314+
315+
assert_expected_action_tree(
316+
self,
317+
logger,
318+
"the-action",
319+
[
320+
{
321+
"start": [
322+
"yielded",
323+
],
324+
},
325+
{
326+
"run": [],
327+
},
328+
],
329+
)

0 commit comments

Comments
 (0)