ikalnytskyi / picobox Goto Github PK
View Code? Open in Web Editor NEWDependency injection framework designed with Python in mind.
Home Page: https://picobox.readthedocs.io
License: MIT License
Dependency injection framework designed with Python in mind.
Home Page: https://picobox.readthedocs.io
License: MIT License
============================= test session starts ==============================
platform linux -- Python 3.10.6, pytest-7.1.2, pluggy-1.0.0
rootdir: /build/source
collected 1266 items
tests/test_box.py ...................................................... [ 4%]
........................................................................ [ 9%]
........................................................................ [ 15%]
........FF............ [ 17%]
tests/test_scopes.py s.................................................. [ 21%]
........................................................................ [ 27%]
........................................................................ [ 32%]
........................................................................ [ 38%]
........................................................................ [ 44%]
................................ [ 46%]
tests/test_stack.py .................................................... [ 50%]
........................................................................ [ 56%]
........................................................................ [ 62%]
........................................................................ [ 67%]
........................................................................ [ 73%]
........................................................................ [ 79%]
..........................................................FFFF.......... [ 84%]
.............. [ 86%]
tests/contrib/test_flaskscopes.py ...................................... [ 89%]
........................................................................ [ 94%]
................................................................... [100%]
=================================== FAILURES ===================================
____________________ test_box_pass_unexpected_argument[Box] ____________________
boxclass = <class 'picobox._box.Box'>
def test_box_pass_unexpected_argument(boxclass):
testbox = boxclass()
testbox.put('d', 10)
@testbox.pass_('d')
def fn(a, b):
return a + b
with pytest.raises(TypeError) as excinfo:
fn(1, 2)
> assert str(excinfo.value) == "fn() got an unexpected keyword argument 'd'"
E assert "test_box_pas... argument 'd'" == "fn() got an ... argument 'd'"
E - fn() got an unexpected keyword argument 'd'
E + test_box_pass_unexpected_argument.<locals>.fn() got an unexpected keyword argument 'd'
tests/test_box.py:371: AssertionError
_________________ test_box_pass_unexpected_argument[ChainBox] __________________
boxclass = <class 'picobox._box.ChainBox'>
def test_box_pass_unexpected_argument(boxclass):
testbox = boxclass()
testbox.put('d', 10)
@testbox.pass_('d')
def fn(a, b):
return a + b
with pytest.raises(TypeError) as excinfo:
fn(1, 2)
> assert str(excinfo.value) == "fn() got an unexpected keyword argument 'd'"
E assert "test_box_pas... argument 'd'" == "fn() got an ... argument 'd'"
E - fn() got an unexpected keyword argument 'd'
E + test_box_pass_unexpected_argument.<locals>.fn() got an unexpected keyword argument 'd'
tests/test_box.py:371: AssertionError
______________ test_box_pass_unexpected_argument[Box-teststack0] _______________
boxclass = <class 'picobox._box.Box'>, teststack = <Stack (0x7ffff64c56f0)>
def test_box_pass_unexpected_argument(boxclass, teststack):
testbox = boxclass()
testbox.put('d', 10)
@teststack.pass_('d')
def fn(a, b):
return a + b
with teststack.push(testbox):
with pytest.raises(TypeError) as excinfo:
fn(1, 2)
> assert str(excinfo.value) == "fn() got an unexpected keyword argument 'd'"
E assert "test_box_pas... argument 'd'" == "fn() got an ... argument 'd'"
E - fn() got an unexpected keyword argument 'd'
E + test_box_pass_unexpected_argument.<locals>.fn() got an unexpected keyword argument 'd'
tests/test_stack.py:437: AssertionError
________________ test_box_pass_unexpected_argument[Box-picobox] ________________
boxclass = <class 'picobox._box.Box'>
teststack = <module 'picobox' from '/nix/store/322w5r8nncx3yhms0aaslyf72pv0632d-python3.10-picobox-2.2.0/lib/python3.10/site-packages/picobox/__init__.py'>
def test_box_pass_unexpected_argument(boxclass, teststack):
testbox = boxclass()
testbox.put('d', 10)
@teststack.pass_('d')
def fn(a, b):
return a + b
with teststack.push(testbox):
with pytest.raises(TypeError) as excinfo:
fn(1, 2)
> assert str(excinfo.value) == "fn() got an unexpected keyword argument 'd'"
E assert "test_box_pas... argument 'd'" == "fn() got an ... argument 'd'"
E - fn() got an unexpected keyword argument 'd'
E + test_box_pass_unexpected_argument.<locals>.fn() got an unexpected keyword argument 'd'
tests/test_stack.py:437: AssertionError
____________ test_box_pass_unexpected_argument[ChainBox-teststack0] ____________
boxclass = <class 'picobox._box.ChainBox'>, teststack = <Stack (0x7ffff64c56f0)>
def test_box_pass_unexpected_argument(boxclass, teststack):
testbox = boxclass()
testbox.put('d', 10)
@teststack.pass_('d')
def fn(a, b):
return a + b
with teststack.push(testbox):
with pytest.raises(TypeError) as excinfo:
fn(1, 2)
> assert str(excinfo.value) == "fn() got an unexpected keyword argument 'd'"
E assert "test_box_pas... argument 'd'" == "fn() got an ... argument 'd'"
E - fn() got an unexpected keyword argument 'd'
E + test_box_pass_unexpected_argument.<locals>.fn() got an unexpected keyword argument 'd'
tests/test_stack.py:437: AssertionError
_____________ test_box_pass_unexpected_argument[ChainBox-picobox] ______________
boxclass = <class 'picobox._box.ChainBox'>
teststack = <module 'picobox' from '/nix/store/322w5r8nncx3yhms0aaslyf72pv0632d-python3.10-picobox-2.2.0/lib/python3.10/site-packages/picobox/__init__.py'>
def test_box_pass_unexpected_argument(boxclass, teststack):
testbox = boxclass()
testbox.put('d', 10)
@teststack.pass_('d')
def fn(a, b):
return a + b
with teststack.push(testbox):
with pytest.raises(TypeError) as excinfo:
fn(1, 2)
> assert str(excinfo.value) == "fn() got an unexpected keyword argument 'd'"
E assert "test_box_pas... argument 'd'" == "fn() got an ... argument 'd'"
E - fn() got an unexpected keyword argument 'd'
E + test_box_pass_unexpected_argument.<locals>.fn() got an unexpected keyword argument 'd'
tests/test_stack.py:437: AssertionError
=============================== warnings summary ===============================
tests/test_scopes.py: 13 warnings
/build/source/tests/test_scopes.py:61: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
coroutine_function = asyncio.coroutine(coroutine_function)
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_box.py::test_box_pass_unexpected_argument[Box] - assert "te...
FAILED tests/test_box.py::test_box_pass_unexpected_argument[ChainBox] - asser...
FAILED tests/test_stack.py::test_box_pass_unexpected_argument[Box-teststack0]
FAILED tests/test_stack.py::test_box_pass_unexpected_argument[Box-picobox] - ...
FAILED tests/test_stack.py::test_box_pass_unexpected_argument[ChainBox-teststack0]
FAILED tests/test_stack.py::test_box_pass_unexpected_argument[ChainBox-picobox]
============ 6 failed, 1259 passed, 1 skipped, 13 warnings in 2.08s ============
The same tests pass with Python 3.9 without problems.
One thing I regret about picobox
is that it uses non-conventional names for methods (e.g. pass_()
, not inject
) and classes (e.g. Box
, not Container
). I'm afraid it might be a too late to change the names.
That's why it's worth considering introducing some picobox.ext.enterprise
extension that can expose better names.
How can it look like?
import picobox.ext.enterprise as di
import requests
@di.inject("conf")
@di.inject("requests", as_="session")
def get_resource(uri, session, conf):
return session.get(conf["base_uri"] + uri)
container = di.Container()
container.add("conf", {"base_uri": "http://example.com"})
container.add("requests", factory=requests.Session, scope=picobox.threadlocal)
with di.use(container):
get_resource("/resource", requests.Session(), {})
get_resource("/resource", requests.Session())
get_resource("/resource")
Starlette is a lightweight framework/toolkit for building web services in Python. Many Python frameworks are built on top of Starlette (e.g. FastAPI). It'd be nice if Picobox can come with application/request scopes for Starlette web applications, since this way we can cover many frameworks at once.
FastAPI is one of the popular (if not most popular) asynchronous web frameworks for Python. It'd be nice if Picobox can come with application/request scopes for FastAPI web applications.
With e92b001:
$ tox -e py311
py311: install_deps> python -I -m pip install flask pytest
.pkg: install_requires> python -I -m pip install 'setuptools>=40.8.0' wheel
.pkg: _optional_hooks> python /usr/lib/python3.11/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: get_requires_for_build_sdist> python /usr/lib/python3.11/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: install_requires_for_build_sdist> python -I -m pip install setuptools_scm
.pkg: prepare_metadata_for_build_wheel> python /usr/lib/python3.11/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: build_sdist> python /usr/lib/python3.11/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
py311: install_package> python -I -m pip install --force-reinstall --no-deps /tmp/picobox/.tox/.tmp/package/1/picobox-2.2.1.dev34+ge92b001.tar.gz
py311: commands[0]> .tox/py311/bin/python -m pytest --strict
========================================================= test session starts =========================================================
platform linux -- Python 3.11.2, pytest-7.2.1, pluggy-1.0.0
cachedir: .tox/py311/.pytest_cache
rootdir: /tmp/picobox
collected 1266 items
tests/test_box.py ............................................................................................................. [ 8%]
............................................................................................................... [ 17%]
tests/test_scopes.py s......................................................................................................... [ 25%]
............................................................................................................................... [ 35%]
...............................................................................................................F.F...F..F..F..F [ 45%]
..F..F...F. [ 46%]
tests/test_stack.py ........................................................................................................... [ 55%]
............................................................................................................................... [ 65%]
............................................................................................................................... [ 75%]
............................................................................................................................... [ 85%]
.......... [ 86%]
tests/contrib/test_flaskscopes.py ............................................................................................. [ 93%]
.................................................................................... [100%]
============================================================== FAILURES ===============================================================
__________________________________________ test_scope_value_shared[singleton-exec_coroutine] __________________________________________
request = <FixtureRequest for <Function test_scope_value_shared[singleton-exec_coroutine]>>, scopename = 'singleton'
executor = 'exec_coroutine'
@pytest.mark.parametrize(
"scopename, executor",
[
("singleton", "exec_thread"),
("singleton", "exec_coroutine"),
("singleton", "exec_context"),
("threadlocal", "exec_coroutine"),
("threadlocal", "exec_context"),
],
)
def test_scope_value_shared(request, scopename, executor):
scope = request.getfixturevalue(scopename)
value = object()
exec_ = request.getfixturevalue(executor)
> exec_(scope.set, "the-key", value)
tests/test_scopes.py:195:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
coroutine_function = <bound method singleton.set of <picobox._scopes.singleton object at 0x7fe02d2cdf90>>
args = ('the-key', <object object at 0x7fe02e2b18f0>), kwargs = {}
def executor(coroutine_function, *args, **kwargs):
if not asyncio.iscoroutinefunction(coroutine_function):
> coroutine_function = asyncio.coroutine(coroutine_function)
E AttributeError: module 'asyncio' has no attribute 'coroutine'
tests/test_scopes.py:63: AttributeError
_________________________________________ test_scope_value_shared[threadlocal-exec_coroutine] _________________________________________
request = <FixtureRequest for <Function test_scope_value_shared[threadlocal-exec_coroutine]>>, scopename = 'threadlocal'
executor = 'exec_coroutine'
@pytest.mark.parametrize(
"scopename, executor",
[
("singleton", "exec_thread"),
("singleton", "exec_coroutine"),
("singleton", "exec_context"),
("threadlocal", "exec_coroutine"),
("threadlocal", "exec_context"),
],
)
def test_scope_value_shared(request, scopename, executor):
scope = request.getfixturevalue(scopename)
value = object()
exec_ = request.getfixturevalue(executor)
> exec_(scope.set, "the-key", value)
tests/test_scopes.py:195:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
coroutine_function = <bound method threadlocal.set of <picobox._scopes.threadlocal object at 0x7fe02c9eb4d0>>
args = ('the-key', <object object at 0x7fe02e2b29a0>), kwargs = {}
def executor(coroutine_function, *args, **kwargs):
if not asyncio.iscoroutinefunction(coroutine_function):
> coroutine_function = asyncio.coroutine(coroutine_function)
E AttributeError: module 'asyncio' has no attribute 'coroutine'
tests/test_scopes.py:63: AttributeError
_______________________________________ test_scope_value_not_shared[contextvars-exec_coroutine] _______________________________________
request = <FixtureRequest for <Function test_scope_value_not_shared[contextvars-exec_coroutine]>>, scopename = 'contextvars'
executor = 'exec_coroutine'
@pytest.mark.parametrize(
"scopename, executor",
[
("threadlocal", "exec_thread"),
("contextvars", "exec_thread"),
("contextvars", "exec_coroutine"),
("contextvars", "exec_context"),
("noscope", "exec_thread"),
("noscope", "exec_coroutine"),
("noscope", "exec_context"),
],
)
def test_scope_value_not_shared(request, scopename, executor):
scope = request.getfixturevalue(scopename)
value = object()
exec_ = request.getfixturevalue(executor)
> exec_(scope.set, "the-key", value)
tests/test_scopes.py:216:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
coroutine_function = <bound method contextvars.set of <picobox._scopes.contextvars object at 0x7fe02ca3cf90>>
args = ('the-key', <object object at 0x7fe02e2b2200>), kwargs = {}
def executor(coroutine_function, *args, **kwargs):
if not asyncio.iscoroutinefunction(coroutine_function):
> coroutine_function = asyncio.coroutine(coroutine_function)
E AttributeError: module 'asyncio' has no attribute 'coroutine'
tests/test_scopes.py:63: AttributeError
_________________________________________ test_scope_value_not_shared[noscope-exec_coroutine] _________________________________________
request = <FixtureRequest for <Function test_scope_value_not_shared[noscope-exec_coroutine]>>, scopename = 'noscope'
executor = 'exec_coroutine'
@pytest.mark.parametrize(
"scopename, executor",
[
("threadlocal", "exec_thread"),
("contextvars", "exec_thread"),
("contextvars", "exec_coroutine"),
("contextvars", "exec_context"),
("noscope", "exec_thread"),
("noscope", "exec_coroutine"),
("noscope", "exec_context"),
],
)
def test_scope_value_not_shared(request, scopename, executor):
scope = request.getfixturevalue(scopename)
value = object()
exec_ = request.getfixturevalue(executor)
> exec_(scope.set, "the-key", value)
tests/test_scopes.py:216:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
coroutine_function = <bound method noscope.set of <picobox._scopes.noscope object at 0x7fe02c9e9410>>
args = ('the-key', <object object at 0x7fe02e2b1850>), kwargs = {}
def executor(coroutine_function, *args, **kwargs):
if not asyncio.iscoroutinefunction(coroutine_function):
> coroutine_function = asyncio.coroutine(coroutine_function)
E AttributeError: module 'asyncio' has no attribute 'coroutine'
tests/test_scopes.py:63: AttributeError
_____________________________________ test_scope_value_downstack_shared[singleton-exec_coroutine] _____________________________________
request = <FixtureRequest for <Function test_scope_value_downstack_shared[singleton-exec_coroutine]>>, scopename = 'singleton'
executor = 'exec_coroutine'
@pytest.mark.parametrize(
"scopename, executor",
[
("singleton", "exec_thread"),
("singleton", "exec_coroutine"),
("singleton", "exec_context"),
("threadlocal", "exec_thread"),
("threadlocal", "exec_coroutine"),
("threadlocal", "exec_context"),
("contextvars", "exec_thread"),
("contextvars", "exec_coroutine"),
("contextvars", "exec_context"),
],
)
def test_scope_value_downstack_shared(request, scopename, executor):
scope = request.getfixturevalue(scopename)
value = object()
exec_ = request.getfixturevalue(executor)
def caller():
scope.set("the-key", value)
return callee()
def callee():
return scope.get("the-key")
> assert exec_(caller) is value
tests/test_scopes.py:248:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
coroutine_function = <function test_scope_value_downstack_shared.<locals>.caller at 0x7fe02c9ce340>, args = (), kwargs = {}
def executor(coroutine_function, *args, **kwargs):
if not asyncio.iscoroutinefunction(coroutine_function):
> coroutine_function = asyncio.coroutine(coroutine_function)
E AttributeError: module 'asyncio' has no attribute 'coroutine'
tests/test_scopes.py:63: AttributeError
____________________________________ test_scope_value_downstack_shared[threadlocal-exec_coroutine] ____________________________________
request = <FixtureRequest for <Function test_scope_value_downstack_shared[threadlocal-exec_coroutine]>>, scopename = 'threadlocal'
executor = 'exec_coroutine'
@pytest.mark.parametrize(
"scopename, executor",
[
("singleton", "exec_thread"),
("singleton", "exec_coroutine"),
("singleton", "exec_context"),
("threadlocal", "exec_thread"),
("threadlocal", "exec_coroutine"),
("threadlocal", "exec_context"),
("contextvars", "exec_thread"),
("contextvars", "exec_coroutine"),
("contextvars", "exec_context"),
],
)
def test_scope_value_downstack_shared(request, scopename, executor):
scope = request.getfixturevalue(scopename)
value = object()
exec_ = request.getfixturevalue(executor)
def caller():
scope.set("the-key", value)
return callee()
def callee():
return scope.get("the-key")
> assert exec_(caller) is value
tests/test_scopes.py:248:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
coroutine_function = <function test_scope_value_downstack_shared.<locals>.caller at 0x7fe02c9cf4c0>, args = (), kwargs = {}
def executor(coroutine_function, *args, **kwargs):
if not asyncio.iscoroutinefunction(coroutine_function):
> coroutine_function = asyncio.coroutine(coroutine_function)
E AttributeError: module 'asyncio' has no attribute 'coroutine'
tests/test_scopes.py:63: AttributeError
____________________________________ test_scope_value_downstack_shared[contextvars-exec_coroutine] ____________________________________
request = <FixtureRequest for <Function test_scope_value_downstack_shared[contextvars-exec_coroutine]>>, scopename = 'contextvars'
executor = 'exec_coroutine'
@pytest.mark.parametrize(
"scopename, executor",
[
("singleton", "exec_thread"),
("singleton", "exec_coroutine"),
("singleton", "exec_context"),
("threadlocal", "exec_thread"),
("threadlocal", "exec_coroutine"),
("threadlocal", "exec_context"),
("contextvars", "exec_thread"),
("contextvars", "exec_coroutine"),
("contextvars", "exec_context"),
],
)
def test_scope_value_downstack_shared(request, scopename, executor):
scope = request.getfixturevalue(scopename)
value = object()
exec_ = request.getfixturevalue(executor)
def caller():
scope.set("the-key", value)
return callee()
def callee():
return scope.get("the-key")
> assert exec_(caller) is value
tests/test_scopes.py:248:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
coroutine_function = <function test_scope_value_downstack_shared.<locals>.caller at 0x7fe02c9ceb60>, args = (), kwargs = {}
def executor(coroutine_function, *args, **kwargs):
if not asyncio.iscoroutinefunction(coroutine_function):
> coroutine_function = asyncio.coroutine(coroutine_function)
E AttributeError: module 'asyncio' has no attribute 'coroutine'
tests/test_scopes.py:63: AttributeError
____________________________________ test_scope_value_downstack_not_shared[noscope-exec_coroutine] ____________________________________
request = <FixtureRequest for <Function test_scope_value_downstack_not_shared[noscope-exec_coroutine]>>, scopename = 'noscope'
executor = 'exec_coroutine'
@pytest.mark.parametrize(
"scopename, executor",
[
("noscope", "exec_thread"),
("noscope", "exec_coroutine"),
("noscope", "exec_context"),
],
)
def test_scope_value_downstack_not_shared(request, scopename, executor):
scope = request.getfixturevalue(scopename)
value = object()
exec_ = request.getfixturevalue(executor)
def caller():
scope.set("the-key", value)
return callee()
def callee():
return scope.get("the-key")
with pytest.raises(KeyError, match="the-key"):
> exec_(caller)
tests/test_scopes.py:272:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
coroutine_function = <function test_scope_value_downstack_not_shared.<locals>.caller at 0x7fe02ca147c0>, args = (), kwargs = {}
def executor(coroutine_function, *args, **kwargs):
if not asyncio.iscoroutinefunction(coroutine_function):
> coroutine_function = asyncio.coroutine(coroutine_function)
E AttributeError: module 'asyncio' has no attribute 'coroutine'
tests/test_scopes.py:63: AttributeError
__________________________________________ test_scope_not_leaked[contextvars-exec_coroutine] __________________________________________
request = <FixtureRequest for <Function test_scope_not_leaked[contextvars-exec_coroutine]>>, scopename = 'contextvars'
executor = 'exec_coroutine'
@pytest.mark.parametrize(
"scopename, executor",
[
("threadlocal", "exec_thread"),
("contextvars", "exec_thread"),
("contextvars", "exec_coroutine"),
("contextvars", "exec_context"),
],
)
def test_scope_not_leaked(request, scopename, executor):
scope = request.getfixturevalue(scopename)
exec_ = request.getfixturevalue(executor)
scope.set("a-key", "a-value")
> exec_(scope.set, "the-key", "the-value")
tests/test_scopes.py:289:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
coroutine_function = <bound method contextvars.set of <picobox._scopes.contextvars object at 0x7fe02ca48dd0>>
args = ('the-key', 'the-value'), kwargs = {}
def executor(coroutine_function, *args, **kwargs):
if not asyncio.iscoroutinefunction(coroutine_function):
> coroutine_function = asyncio.coroutine(coroutine_function)
E AttributeError: module 'asyncio' has no attribute 'coroutine'
tests/test_scopes.py:63: AttributeError
========================================================== warnings summary ===========================================================
.tox/py311/lib/python3.11/site-packages/_pytest/config/__init__.py:1240
/tmp/picobox/.tox/py311/lib/python3.11/site-packages/_pytest/config/__init__.py:1240: PytestRemovedIn8Warning: The --strict option is deprecated, use --strict-markers instead.
self.issue_config_time_warning(
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
======================================================= short test summary info =======================================================
FAILED tests/test_scopes.py::test_scope_value_shared[singleton-exec_coroutine] - AttributeError: module 'asyncio' has no attribute 'coroutine'
FAILED tests/test_scopes.py::test_scope_value_shared[threadlocal-exec_coroutine] - AttributeError: module 'asyncio' has no attribute 'coroutine'
FAILED tests/test_scopes.py::test_scope_value_not_shared[contextvars-exec_coroutine] - AttributeError: module 'asyncio' has no attribute 'coroutine'
FAILED tests/test_scopes.py::test_scope_value_not_shared[noscope-exec_coroutine] - AttributeError: module 'asyncio' has no attribute 'coroutine'
FAILED tests/test_scopes.py::test_scope_value_downstack_shared[singleton-exec_coroutine] - AttributeError: module 'asyncio' has no attribute 'coroutine'
FAILED tests/test_scopes.py::test_scope_value_downstack_shared[threadlocal-exec_coroutine] - AttributeError: module 'asyncio' has no attribute 'coroutine'
FAILED tests/test_scopes.py::test_scope_value_downstack_shared[contextvars-exec_coroutine] - AttributeError: module 'asyncio' has no attribute 'coroutine'
FAILED tests/test_scopes.py::test_scope_value_downstack_not_shared[noscope-exec_coroutine] - AttributeError: module 'asyncio' has no attribute 'coroutine'
FAILED tests/test_scopes.py::test_scope_not_leaked[contextvars-exec_coroutine] - AttributeError: module 'asyncio' has no attribute 'coroutine'
======================================== 9 failed, 1256 passed, 1 skipped, 1 warning in 2.01s =========================================
py311: exit 1 (2.29 seconds) /tmp/picobox> .tox/py311/bin/python -m pytest --strict pid=63011
.pkg: _exit> python /usr/lib/python3.11/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
py311: FAIL code 1 (12.79=setup[10.50]+cmd[2.29] seconds)
evaluation failed :( (12.87 seconds)
Since I don't like type hints specified in the code base, I need to check how to add them via *.pyi
stubs.
Ever since I started working on scopes for Starlette web framework (see #77), I realized that there's no Starlette specific facilities (like Flask provides) to access application or request states from any point of execution.
Thus, I'll need to go through a special ASGI middleware to define those scopes, and this approach will work for any ASGI framework.
At this point I'm thinking about three types of scopes: application and request scopes. The middleware must be recommended to be a top-level (or the most outer middleware), and it must save both the current ASGI application and current request context in a global contextvar
variable.
When I was working on ASGI scopes (see #80), I realized that the same approach (i.e. by using a middleware) can be applied to any WSGI-based web framework. In order to support as many WSGI web frameworks as possible, we have to provide these generic scopes.
At this point I'm thinking about two type of scopes: application and request scopes. The middleware must be recommended to be a top-level (or the most outer middleware), and it must save both the current WSGI application and current request context in a global threadlocal
variable.
Currently the picobox.pass_()
decorator can be successfully applied to coroutine functions, and such a coroutine function can be successfully used. For instance, the following code works as expected:
@picobox.pass_("database_session")
async def get_movies_by_name(name: str, database_conn: DatabaseSession) -> list[Movie]:
return await database_conn.query(...)
# ...
await get_movies_by_name("The Batman")
The get_movies_by_name
coroutine function, however, lose its coroutine function marker, which may lead to undesired consequences when used with frameworks or libraries that support both sync and async interface, and use inspect.iscoroutinefunction()
to properly dispatch its execution (e.g. Starlette
).
>>> inspect.iscoroutinefunction(get_movies_by_name)
False
Despite move pep517 backend from setuptools
to hatchling
documentation build still uses pkg_resources
which is part of the setuptools
and arendy is marked as deprecated.
https://importlib-resources.readthedocs.io/en/latest/migration.html
Autowiring is convenient functionality that allows to inject dependencies implicitly. Picobox core provides everything that is required to implement autowiring functionality as a third party decorator in picobox.contrib
pacakge.
The autowiring decorator must satisfy the following requirements:
There are engineers who prefer declarative over imperative, even when it comes to defining DI containers (i.e. picobox.Box
).
import picobox.ext.declarative as declarative
class MyBox(declarative.Box):
...
Is it possible next time on release new version make the github release to have entry on https://github.com/ikalnytskyi/picobox/releases? ๐ค
I'm asking because only on make gh release is spread notification about new release to those who have set watch->releases.
My automation process those notification trying make preliminary automated upgrade of building packages which allow save some time on maintaining packaging procedures.
More about gh releases is possible to find on
https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository
https://github.com/marketplace/actions/github-release
https://pgjones.dev/blog/trusted-plublishing-2023/
Like picobox.ext.asgi
or picobox.ext.wsgi
, picobox.ext.grpc
has to provide application and request scopes for dependencies.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.