-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21 from xoeye/feature/stack-context-and-oncall-de…
…faults
- Loading branch information
Showing
12 changed files
with
553 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from xoto3.utils.contextual_default import ContextualDefault | ||
|
||
IntDefault = ContextualDefault("i", 1) | ||
|
||
|
||
def test_that_the_name_is_used_and_everything_works(): | ||
@IntDefault.apply | ||
def f(a: str, i: int = 2): | ||
return i | ||
|
||
assert f("a") == 1 | ||
with IntDefault.set_default(4): | ||
assert f("b") == 4 | ||
with IntDefault.set_default(7): | ||
assert f("c") == 7 | ||
assert f("c", 8) == 8 | ||
assert f("d") == 4 | ||
assert f("e") == 1 | ||
assert f("f", i=3) == 3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
# pylint: disable=unused-argument,unused-variable | ||
from datetime import datetime | ||
|
||
import pytest | ||
|
||
from xoto3.utils.oncall_default import NotSafeToDefaultError, OnCallDefault | ||
|
||
utcnow = OnCallDefault(datetime.utcnow) | ||
|
||
|
||
def test_oncall_default_works_with_pos_or_kw(): | ||
@utcnow.apply_to("when") | ||
def final(a: str, when: datetime = utcnow(), f: float = 1.2): | ||
return when | ||
|
||
assert final("a") <= utcnow() | ||
|
||
val = datetime(1888, 8, 8, 8, 8, 8) | ||
assert val == final("a", when=val) | ||
assert val == final("c", f=4.2, when=val) | ||
|
||
|
||
def test_oncall_default_works_with_kw_only(): | ||
@utcnow.apply_to("when") | ||
def f(a: str, *, when: datetime = utcnow()): | ||
return when | ||
|
||
val = datetime(1900, 1, 1, 11, 11, 11) | ||
assert val == f("3", when=val) | ||
|
||
|
||
def test_deco_works_with_var_kwargs(): | ||
@utcnow.apply_to("when") | ||
def f(**kwargs): | ||
return kwargs["when"] | ||
|
||
assert datetime.utcnow() <= f() | ||
assert f() <= datetime.utcnow() | ||
|
||
direct = datetime(2012, 12, 12, 12, 12, 12) | ||
assert direct == f(when=direct) | ||
|
||
|
||
def test_disallow_positional_without_default(): | ||
"""A positional-possible argument without a default could have a | ||
positional argument provided after it and then we'd be unable to tell | ||
for sure whether it had been provided intentionally. | ||
""" | ||
|
||
with pytest.raises(NotSafeToDefaultError): | ||
|
||
@utcnow.apply_to("when") | ||
def nope(when: datetime, a: int): | ||
pass | ||
|
||
|
||
def test_disallow_not_found_without_var_kwargs(): | ||
|
||
with pytest.raises(NotSafeToDefaultError): | ||
|
||
@utcnow.apply_to("notthere") | ||
def steve(a: str, *args, b=1, c=2): | ||
pass | ||
|
||
|
||
def test_disallow_var_args_name_matches(): | ||
with pytest.raises(NotSafeToDefaultError): | ||
# *args itself has the default value 'new empty tuple', and if | ||
# you want to provide a positional default you should give it | ||
# a real name. | ||
@utcnow.apply_to("args") | ||
def felicity(a: str, *args): | ||
pass | ||
|
||
|
||
GeorgeKwargs = OnCallDefault(lambda: dict(b=2, c=3)) | ||
|
||
|
||
def test_allow_var_kwargs_merge(): | ||
# kwargs itself is a dict, | ||
# and we will perform top-level merging | ||
# for you if that's what you want | ||
|
||
@GeorgeKwargs.apply_to("kwargs") | ||
def george(a: str, **kwargs): | ||
return kwargs | ||
|
||
assert george("1") == dict(b=2, c=3) | ||
assert george("2", b=3) == dict(b=3, c=3) | ||
assert george("3", c=5, d=78) == dict(b=2, c=5, d=78) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
from contextvars import ContextVar | ||
from datetime import datetime | ||
|
||
from xoto3.utils.oncall_default import OnCallDefault | ||
from xoto3.utils.stack_context import StackContext, stack_context, unwrap | ||
|
||
NowContext = ContextVar("UtcNow", default=datetime.utcnow) | ||
|
||
|
||
def test_stack_context(): | ||
def final(): | ||
return NowContext.get()() | ||
|
||
def intermediate(): | ||
return final() | ||
|
||
outer_when = datetime(2018, 9, 9, 9, 9, 9) | ||
|
||
def outer(): | ||
with stack_context(NowContext, lambda: outer_when): | ||
return intermediate() | ||
|
||
way_outer_when = datetime(2019, 12, 12, 8, 0, 0) | ||
with stack_context(NowContext, lambda: way_outer_when): | ||
assert way_outer_when == intermediate() | ||
assert outer_when == outer() | ||
|
||
assert NowContext.get() != outer_when | ||
assert NowContext.get() != way_outer_when | ||
|
||
|
||
def test_composes_with_oncall_default(): | ||
|
||
when = OnCallDefault(unwrap(NowContext.get)) | ||
|
||
@when.apply_to("now") | ||
def f(now: datetime = when()): | ||
assert isinstance(now, datetime) | ||
return now | ||
|
||
val = datetime(1922, 8, 3, 1, 2, 1) | ||
assert f(now=val) == val | ||
|
||
with stack_context(NowContext, lambda: val): | ||
assert val == f() | ||
new_val = datetime(888, 8, 8, 8, 8, 8) | ||
with stack_context(NowContext, lambda: new_val): | ||
assert new_val == f() | ||
assert val == f() | ||
assert new_val == f(new_val) | ||
|
||
assert f(val) == val | ||
assert f(val) <= datetime.utcnow() | ||
|
||
|
||
ConsistentReadContext = StackContext("ConsistentRead", False) | ||
|
||
|
||
def test_StackContext_interface(): | ||
def f(): | ||
return ConsistentReadContext() | ||
|
||
def g(): | ||
return f() | ||
|
||
assert g() is False | ||
with ConsistentReadContext.set(True): | ||
assert g() is True | ||
assert g() is False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
"""xoto3""" | ||
__version__ = "1.13.1" | ||
__version__ = "1.14.0" | ||
__author__ = "Peter Gaultney" | ||
__author_email__ = "[email protected]" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.