@@ -122,10 +122,23 @@ class Outcome(abc.ABC, Generic[ValueT]):
122122 hashable.
123123
124124 """
125+ @abc .abstractmethod
126+ def peek (self ) -> ValueT :
127+ """Return or raise the contained value or exception, without
128+ invalidating the outcome.
129+
130+ These two lines of code are equivalent::
131+
132+ x = fn(*args)
133+ x = outcome.capture(fn, *args).peek()
134+
135+ """
136+
125137
126138 @abc .abstractmethod
127139 def unwrap (self ) -> ValueT :
128- """Return or raise the contained value or exception.
140+ """Return or raise the contained value or exception, and invalidate
141+ the outcome.
129142
130143 These two lines of code are equivalent::
131144
@@ -173,6 +186,9 @@ def __repr__(self) -> str:
173186 except AttributeError :
174187 return 'Value(<AlreadyUsed>)'
175188
189+ def peek (self ) -> ValueT :
190+ return self .value
191+
176192 def unwrap (self ) -> ValueT :
177193 try :
178194 v = self ._value
@@ -226,6 +242,27 @@ def _unwrap_error(self) -> BaseException:
226242 return v
227243 raise AlreadyUsedError
228244
245+ def peek (self ) -> NoReturn :
246+ # Tracebacks show the 'raise' line below out of context, so let's give
247+ # this variable a name that makes sense out of context.
248+ captured_error = self .error
249+ try :
250+ raise captured_error
251+ finally :
252+ # We want to avoid creating a reference cycle here. Python does
253+ # collect cycles just fine, so it wouldn't be the end of the world
254+ # if we did create a cycle, but the cyclic garbage collector adds
255+ # latency to Python programs, and the more cycles you create, the
256+ # more often it runs, so it's nicer to avoid creating them in the
257+ # first place. For more details see:
258+ #
259+ # https://github.com/python-trio/trio/issues/1770
260+ #
261+ # In particuar, by deleting this local variables from the 'unwrap'
262+ # methods frame, we avoid the 'captured_error' object's
263+ # __traceback__ from indirectly referencing 'captured_error'.
264+ del captured_error , self
265+
229266 def unwrap (self ) -> NoReturn :
230267 # Tracebacks show the 'raise' line below out of context, so let's give
231268 # this variable a name that makes sense out of context.
0 commit comments