mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-01-05 04:34:10 +00:00
Move generator context state to a generator context manager
This commit is contained in:
parent
d902f7567f
commit
e55ee7d044
@ -5,6 +5,8 @@ Tools aimed at the interaction between Tahoe-LAFS implementation and Eliot.
|
|||||||
from sys import exc_info
|
from sys import exc_info
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
from weakref import WeakKeyDictionary
|
||||||
|
|
||||||
|
|
||||||
from eliot import (
|
from eliot import (
|
||||||
Message,
|
Message,
|
||||||
@ -14,25 +16,44 @@ from twisted.internet.defer import (
|
|||||||
inlineCallbacks,
|
inlineCallbacks,
|
||||||
)
|
)
|
||||||
|
|
||||||
@contextmanager
|
class _GeneratorContext(object):
|
||||||
def _substitute_stack(substitute, target):
|
def __init__(self, execution_context):
|
||||||
# Save whatever is there to begin with, making a copy ensures we don't get
|
self._execution_context = execution_context
|
||||||
# affected by any mutations that might happen while the substitute is in
|
self._contexts = WeakKeyDictionary()
|
||||||
# place.
|
self._current_generator = None
|
||||||
saved = list(target)
|
|
||||||
# Put the substitute in place. Preserve the identity of the target for no
|
def init_stack(self, generator):
|
||||||
# concrete reason but maybe it's a good idea.
|
stack = list(self._execution_context._get_stack())
|
||||||
target[:] = substitute
|
self._contexts[generator] = stack
|
||||||
try:
|
|
||||||
# Let some code run.
|
def get_stack(self):
|
||||||
yield
|
if self._current_generator is None:
|
||||||
finally:
|
# If there is no currently active generator then we have no
|
||||||
# Save whatever substitute state we ended up with back to the
|
# special stack to supply. Let the execution context figure out a
|
||||||
# substitute. Copying again, here.
|
# different answer on its own.
|
||||||
substitute[:] = list(target)
|
return None
|
||||||
# Restore the target to its original state. Again, preserving
|
# Otherwise, give back the action context stack we've been tracking
|
||||||
# identity.
|
# for the currently active generator. It must have been previously
|
||||||
target[:] = saved
|
# initialized (it's too late to do it now)!
|
||||||
|
return self._contexts[self._current_generator]
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def context(self, generator):
|
||||||
|
previous_generator = self._current_generator
|
||||||
|
try:
|
||||||
|
self._current_generator = generator
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
self._current_generator = previous_generator
|
||||||
|
|
||||||
|
|
||||||
|
from eliot._action import _context
|
||||||
|
_the_generator_context = _GeneratorContext(_context)
|
||||||
|
|
||||||
|
|
||||||
|
def use_generator_context():
|
||||||
|
_context.get_sub_context = _the_generator_context.get_stack
|
||||||
|
use_generator_context()
|
||||||
|
|
||||||
|
|
||||||
def eliot_friendly_generator_function(original):
|
def eliot_friendly_generator_function(original):
|
||||||
@ -49,16 +70,17 @@ def eliot_friendly_generator_function(original):
|
|||||||
# Keep track of the next value to deliver to the generator.
|
# Keep track of the next value to deliver to the generator.
|
||||||
value_in = None
|
value_in = None
|
||||||
|
|
||||||
# Start tracking our desired inward-facing action context stack. This
|
|
||||||
# really wants some more help from Eliot.
|
|
||||||
from eliot._action import _context
|
|
||||||
context_in = list(_context._get_stack())
|
|
||||||
|
|
||||||
# Create the generator with a call to the generator function. This
|
# Create the generator with a call to the generator function. This
|
||||||
# happens with whatever Eliot action context happens to be active,
|
# happens with whatever Eliot action context happens to be active,
|
||||||
# which is fine and correct and also irrelevant because no code in the
|
# which is fine and correct and also irrelevant because no code in the
|
||||||
# generator function can run until we call send or throw on it.
|
# generator function can run until we call send or throw on it.
|
||||||
gen = original(*a, **kw)
|
gen = original(*a, **kw)
|
||||||
|
|
||||||
|
# Initialize the per-generator Eliot action context stack to the
|
||||||
|
# current action stack. This might be the main stack or, if another
|
||||||
|
# decorated generator is running, it might be the stack for that
|
||||||
|
# generator. Not our business.
|
||||||
|
_the_generator_context.init_stack(gen)
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@ -66,7 +88,7 @@ def eliot_friendly_generator_function(original):
|
|||||||
# with the Eliot action context stack we've saved for it.
|
# with the Eliot action context stack we've saved for it.
|
||||||
# Then the context manager will re-save it and restore the
|
# Then the context manager will re-save it and restore the
|
||||||
# "outside" stack for us.
|
# "outside" stack for us.
|
||||||
with _substitute_stack(context_in, _context._get_stack()):
|
with _the_generator_context.context(gen):
|
||||||
if ok:
|
if ok:
|
||||||
value_out = gen.send(value_in)
|
value_out = gen.send(value_in)
|
||||||
else:
|
else:
|
||||||
@ -105,6 +127,7 @@ def eliot_friendly_generator_function(original):
|
|||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
def inline_callbacks(original):
|
def inline_callbacks(original):
|
||||||
"""
|
"""
|
||||||
Decorate a function like ``inlineCallbacks`` would but in a more
|
Decorate a function like ``inlineCallbacks`` would but in a more
|
||||||
|
Loading…
Reference in New Issue
Block a user