Skip to content

Commit 92129c5

Browse files
committed
#2447 Added exception forwarding to context tests
1 parent 555fa9b commit 92129c5

File tree

1 file changed

+93
-0
lines changed

1 file changed

+93
-0
lines changed

tests/test_context.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import logging
2+
from contextlib import AbstractContextManager
23
from contextlib import contextmanager
4+
from types import TracebackType
35

46
import pytest
57

@@ -423,6 +425,97 @@ def manager():
423425
assert rv == [0]
424426

425427

428+
def test_with_resource_exception() -> None:
429+
class TestContext(AbstractContextManager[list[int]]):
430+
_handle_exception: bool
431+
_base_val: int
432+
val: list[int]
433+
434+
def __init__(self, base_val: int = 1, *, handle_exception: bool = True) -> None:
435+
self._handle_exception = handle_exception
436+
self._base_val = base_val
437+
438+
def __enter__(self) -> list[int]:
439+
self.val = [self._base_val]
440+
return self.val
441+
442+
def __exit__(
443+
self,
444+
exc_type: type[BaseException] | None,
445+
exc_value: BaseException | None,
446+
traceback: TracebackType | None,
447+
) -> bool | None:
448+
if not exc_type:
449+
self.val[0] = self._base_val - 1
450+
return None
451+
452+
self.val[0] = self._base_val + 1
453+
return self._handle_exception
454+
455+
class TestException(Exception):
456+
pass
457+
458+
ctx = click.Context(click.Command("test"))
459+
460+
base_val = 1
461+
462+
with ctx.scope():
463+
rv = ctx.with_resource(TestContext(base_val=base_val))
464+
assert rv[0] == base_val
465+
466+
assert rv == [base_val - 1]
467+
468+
with ctx.scope():
469+
rv = ctx.with_resource(TestContext(base_val=base_val))
470+
raise TestException()
471+
472+
assert rv == [base_val + 1]
473+
474+
with pytest.raises(TestException):
475+
with ctx.scope():
476+
rv = ctx.with_resource(
477+
TestContext(base_val=base_val, handle_exception=False)
478+
)
479+
raise TestException()
480+
481+
base_val_nested = 11
482+
with ctx.scope():
483+
rv = ctx.with_resource(TestContext(base_val=base_val))
484+
rv_nested = ctx.with_resource(TestContext(base_val=base_val_nested))
485+
assert rv[0] == base_val
486+
assert rv_nested[0] == base_val_nested
487+
488+
assert rv == [base_val - 1]
489+
assert rv_nested == [base_val_nested - 1]
490+
491+
with ctx.scope():
492+
rv = ctx.with_resource(TestContext(base_val=base_val))
493+
rv_nested = ctx.with_resource(TestContext(base_val=base_val_nested))
494+
raise TestException()
495+
496+
# If one of the context "eats" the exceptions they will not be forwarded to other
497+
# parts. This is due to how ExitStack unwinding works
498+
assert rv_nested == [base_val_nested + 1]
499+
assert rv == [base_val - 1]
500+
501+
with ctx.scope():
502+
rv = ctx.with_resource(TestContext(base_val=base_val))
503+
rv_nested = ctx.with_resource(
504+
TestContext(base_val=base_val_nested, handle_exception=False)
505+
)
506+
raise TestException()
507+
508+
assert rv_nested == [base_val_nested + 1]
509+
assert rv == [base_val + 1]
510+
511+
with pytest.raises(TestException):
512+
rv = ctx.with_resource(TestContext(base_val=base_val, handle_exception=False))
513+
rv_nested = ctx.with_resource(
514+
TestContext(base_val=base_val_nested, handle_exception=False)
515+
)
516+
raise TestException()
517+
518+
426519
def test_make_pass_decorator_args(runner):
427520
"""
428521
Test to check that make_pass_decorator doesn't consume arguments based on

0 commit comments

Comments
 (0)