Skip to content

Commit 4322626

Browse files
committed
Error.peek() raises a copy of the wrapped error
1 parent 28fecf4 commit 4322626

4 files changed

Lines changed: 16 additions & 9 deletions

File tree

newsfragments/47.feature.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
Remove reference to value/error when unwrapping outcome.
22
Provide a ``.peek()`` method to recieve wrapped
3-
value/error without invalidating the outcome.
3+
value or a copy of the wrapped error
4+
without invalidating the outcome.

src/outcome/_impl.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import abc
4+
import copy
45
from typing import (
56
TYPE_CHECKING,
67
AsyncGenerator,
@@ -125,10 +126,10 @@ class Outcome(abc.ABC, Generic[ValueT]):
125126

126127
@abc.abstractmethod
127128
def peek(self) -> ValueT:
128-
"""Return or raise the contained value or exception, without
129-
invalidating the outcome.
129+
"""Return the contained value or raise a copy of the contained
130+
exception, without invalidating the outcome.
130131
131-
These two lines of code are equivalent::
132+
These two lines of code are almost equivalent::
132133
133134
x = fn(*args)
134135
x = outcome.capture(fn, *args).peek()
@@ -245,7 +246,7 @@ def _unwrap_error(self) -> BaseException:
245246
def peek(self) -> NoReturn:
246247
# Tracebacks show the 'raise' line below out of context, so let's give
247248
# this variable a name that makes sense out of context.
248-
captured_error = self.error
249+
captured_error = copy.copy(self.error)
249250
try:
250251
raise captured_error
251252
finally:

tests/test_async.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ async def raise_ValueError(x):
2525
e = await outcome.acapture(raise_ValueError, 9)
2626
assert type(e.error) is ValueError
2727
assert e.error.args == (9,)
28-
with pytest.raises(ValueError):
28+
with pytest.raises(ValueError) as exc_info:
2929
e.peek()
30-
with pytest.raises(ValueError):
30+
with pytest.raises(ValueError) as exc_info2:
3131
e.unwrap()
3232

33+
assert exc_info.value is not exc_info2.value
34+
3335

3436
async def test_asend():
3537
async def my_agen_func():

tests/test_sync.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@ def test_Outcome():
2424
e = Error(exc)
2525
assert e.error is exc
2626
assert repr(e) == f"Error({exc!r})"
27-
with pytest.raises(RuntimeError):
27+
with pytest.raises(RuntimeError) as exc_info:
2828
e.peek()
29-
with pytest.raises(RuntimeError):
29+
with pytest.raises(RuntimeError) as exc_info2:
3030
e.unwrap()
31+
32+
assert exc_info.value is not exc_info2.value
33+
3134
with pytest.raises(AlreadyUsedError):
3235
e.unwrap()
3336
assert repr(e) == "Error(<AlreadyUsed>)"

0 commit comments

Comments
 (0)