Skip to content

Commit

Permalink
Removed the mandatory context parameter from all callbacks (#109)
Browse files Browse the repository at this point in the history
  • Loading branch information
agronholm authored Feb 5, 2024
1 parent 7bcd032 commit 2769793
Show file tree
Hide file tree
Showing 14 changed files with 187 additions and 166 deletions.
6 changes: 4 additions & 2 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ Concurrency
-----------

.. autofunction:: start_background_task
.. autofunction:: start_service_task

Contexts and resources
----------------------
Expand All @@ -24,6 +23,8 @@ Contexts and resources
.. autofunction:: current_context
.. autofunction:: context_teardown
.. autofunction:: add_resource
.. autofunction:: add_resource_factory
.. autofunction:: add_teardown_callback
.. autofunction:: get_resource
.. autofunction:: require_resource
.. autofunction:: inject
Expand All @@ -35,7 +36,7 @@ Contexts and resources
Events
------

.. autoclass:: ResourceEvent
.. autoclass:: Event
.. autoclass:: Signal
.. autofunction:: stream_events
.. autofunction:: wait_event
Expand All @@ -52,3 +53,4 @@ Utilities
.. autofunction:: callable_name
.. autofunction:: merge_config
.. autofunction:: qualified_name
.. autofunction:: resolve_reference
7 changes: 5 additions & 2 deletions docs/versionhistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ This library adheres to `Semantic Versioning 2.0 <http://semver.org/>`_.
- **BACKWARD INCOMPATIBLE** Dropped the deprecated ``parent`` argument to ``Context``
- **BACKWARD INCOMPATIBLE** Dropped the deprecated ``Dependency()`` marker
- **BACKWARD INCOMPATIBLE** Dropped support for context attributes
- **BACKWARD INCOMPATIBLE** Dropped the ``ctx`` parameter from
``CLIApplicationComponent.run()``
- **BACKWARD INCOMPATIBLE** Dropped the ``ctx`` parameter from all callbacks, including:

* ``Component.start()``
* ``CLIApplicationComponent.run()``
* resource factory callbacks
- **BACKWARD INCOMPATIBLE** Refactored the event system:

* The ``connect()``, ``disconnect()`` and ``dispatch_raw()`` methods were removed
Expand Down
3 changes: 1 addition & 2 deletions examples/tutorial1/echo/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

from asphalt.core import (
Component,
Context,
context_teardown,
run_application,
start_background_task,
Expand All @@ -23,7 +22,7 @@ async def handle(stream: SocketStream) -> None:

class ServerComponent(Component):
@context_teardown
async def start(self, ctx: Context) -> AsyncGenerator[None, Exception | None]:
async def start(self) -> AsyncGenerator[None, Exception | None]:
async with await anyio.create_tcp_listener(
local_host="localhost", local_port=64100
) as listener:
Expand Down
8 changes: 4 additions & 4 deletions examples/tutorial1/tests/test_client_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import pytest

from asphalt.core import Context
from _pytest.capture import CaptureFixture
from pytest import CaptureFixture

from echo.client import ClientComponent
from echo.server import ServerComponent
Expand All @@ -11,12 +11,12 @@


async def test_client_and_server(capsys: CaptureFixture[str]) -> None:
async with Context() as ctx:
async with Context():
server = ServerComponent()
await server.start(ctx)
await server.start()

client = ClientComponent("Hello!")
await client.start(ctx)
await client.start()

# Grab the captured output of sys.stdout and sys.stderr from the capsys fixture
out, err = capsys.readouterr()
Expand Down
6 changes: 3 additions & 3 deletions examples/tutorial2/webnotifier/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import logging
from difflib import HtmlDiff

from asphalt.core import CLIApplicationComponent, Context, inject, resource
from asphalt.core import CLIApplicationComponent, inject, resource
from asphalt.mailer.api import Mailer

from webnotifier.detector import ChangeDetectorComponent, Detector
Expand All @@ -12,10 +12,10 @@


class ApplicationComponent(CLIApplicationComponent):
async def start(self, ctx: Context) -> None:
async def start(self) -> None:
self.add_component("detector", ChangeDetectorComponent)
self.add_component("mailer", backend="smtp")
await super().start(ctx)
await super().start()

@inject
async def run(
Expand Down
6 changes: 3 additions & 3 deletions examples/tutorial2/webnotifier/detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
import httpx
from asphalt.core import (
Component,
Context,
Event,
Signal,
context_teardown,
start_background_task,
add_resource,
)

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -64,9 +64,9 @@ def __init__(self, url: str, delay: int = 10):
self.delay = delay

@context_teardown
async def start(self, ctx: Context) -> AsyncGenerator[None, Exception | None]:
async def start(self) -> AsyncGenerator[None, Exception | None]:
detector = Detector(self.url, self.delay)
await ctx.add_resource(detector)
await add_resource(detector)
await start_background_task(detector.run, "Web page change detector")
logging.info(
'Started web page change detector for url "%s" with a delay of %d seconds',
Expand Down
96 changes: 32 additions & 64 deletions src/asphalt/core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,37 @@
__all__ = (
"ApplicationExit",
"CLIApplicationComponent",
"Component",
"ContainerComponent",
"start_background_task",
"Context",
"GeneratedResource",
"ResourceConflict",
"ResourceEvent",
"ResourceNotFound",
"add_resource",
"context_teardown",
"current_context",
"get_resource",
"get_resources",
"require_resource",
"NoCurrentContext",
"inject",
"resource",
"Event",
"Signal",
"stream_events",
"wait_event",
"run_application",
"PluginContainer",
"callable_name",
"merge_config",
"qualified_name",
"resolve_reference",
)

from typing import Any

from ._component import (
CLIApplicationComponent,
Component,
ContainerComponent,
)
from ._context import (
Context,
GeneratedResource,
NoCurrentContext,
ResourceConflict,
ResourceEvent,
ResourceNotFound,
add_resource,
context_teardown,
current_context,
get_resource,
get_resources,
inject,
require_resource,
resource,
start_background_task,
)
from ._event import Event, Signal, stream_events, wait_event
from ._exceptions import ApplicationExit
from ._runner import run_application
from ._utils import (
PluginContainer,
callable_name,
merge_config,
qualified_name,
resolve_reference,
)
from ._component import CLIApplicationComponent as CLIApplicationComponent
from ._component import Component as Component
from ._component import ContainerComponent as ContainerComponent
from ._context import Context as Context
from ._context import GeneratedResource as GeneratedResource
from ._context import NoCurrentContext as NoCurrentContext
from ._context import ResourceConflict as ResourceConflict
from ._context import ResourceEvent as ResourceEvent
from ._context import ResourceNotFound as ResourceNotFound
from ._context import add_resource as add_resource
from ._context import add_resource_factory as add_resource_factory
from ._context import add_teardown_callback as add_teardown_callback
from ._context import context_teardown as context_teardown
from ._context import current_context as current_context
from ._context import get_resource as get_resource
from ._context import get_resources as get_resources
from ._context import inject as inject
from ._context import request_resource as request_resource
from ._context import require_resource as require_resource
from ._context import resource as resource
from ._context import start_background_task as start_background_task
from ._event import Event as Event
from ._event import Signal as Signal
from ._event import stream_events as stream_events
from ._event import wait_event as wait_event
from ._exceptions import ApplicationExit as ApplicationExit
from ._runner import run_application as run_application
from ._utils import PluginContainer as PluginContainer
from ._utils import callable_name as callable_name
from ._utils import merge_config as merge_config
from ._utils import qualified_name as qualified_name
from ._utils import resolve_reference as resolve_reference

# Re-export imports so they look like they live directly in this package
key: str
Expand Down
19 changes: 8 additions & 11 deletions src/asphalt/core/_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from anyio import create_task_group
from anyio.lowlevel import cancel_shielded_checkpoint

from ._context import Context, start_background_task
from ._context import start_background_task
from ._exceptions import ApplicationExit
from ._utils import PluginContainer, merge_config, qualified_name

Expand All @@ -19,22 +19,19 @@ class Component(metaclass=ABCMeta):
__slots__ = ()

@abstractmethod
async def start(self, ctx: Context) -> None:
async def start(self) -> None:
"""
Perform any necessary tasks to start the services provided by this component.
In this method, components typically use the context to:
* add resources and/or resource factories to it
(:meth:`~asphalt.core.context.Context.add_resource` and
:meth:`~asphalt.core.context.Context.add_resource_factory`)
(:func:`add_resource` and :func:`add_resource_factory`)
* get resources from it asynchronously
(:meth:`~asphalt.core.context.Context.get_resource`)
(:func:`get_resource`)
It is advisable for Components to first add all the resources they can to the
context before requesting any from it. This will speed up the dependency
resolution and prevent deadlocks.
:param ctx: the containing context for this component
"""


Expand Down Expand Up @@ -99,7 +96,7 @@ def add_component(
component = component_types.create_object(**config)
self.child_components[alias] = component

async def start(self, ctx: Context) -> None:
async def start(self) -> None:
"""
Create child components that have been configured but not yet created and then
calls their :meth:`~Component.start` methods in separate tasks and waits until
Expand All @@ -112,7 +109,7 @@ async def start(self, ctx: Context) -> None:

async with create_task_group() as tg:
for alias, component in self.child_components.items():
tg.start_soon(component.start, ctx)
tg.start_soon(component.start)


class CLIApplicationComponent(ContainerComponent):
Expand All @@ -131,7 +128,7 @@ class CLIApplicationComponent(ContainerComponent):
it is set to 1 and a warning is emitted.
"""

async def start(self, ctx: Context) -> None:
async def start(self) -> None:
async def run() -> None:
retval = await self.run()

Expand All @@ -154,7 +151,7 @@ async def run() -> None:
else:
raise ApplicationExit

await super().start(ctx)
await super().start()
await start_background_task(run, "Main task", teardown_action=None)

@abstractmethod
Expand Down
Loading

0 comments on commit 2769793

Please sign in to comment.