Version history
This library adheres to Semantic Versioning 2.0.
UNRELEASED
As this is a major release with several backwards incompatible changes, see the Migration guide if you’re upgrading your existing application.
BACKWARD INCOMPATIBLE Changes in the application runner:
Asphalt now runs via AnyIO, rather than asyncio, although the asyncio backend is used by default
The runner now outputs an elaborate tree of component startup tasks if the application fails to start within the allotted time
Dropped the
--unsafe
switch forasphalt run
– configuration files are now always parsed in unsafe modeChanged configuration parsing to no longer treat dotted keys in configuration overrides to be interpreted as structural shortcuts (i.e.
foo.bar.baz
interpreted as a shortcut for a structure 3 levels deep:foo: {bar: {baz: ...}}
), as this prevented proper configuration for loggers that have dots in their namesAdded a shortcut for specify multiple components of the same type using a scheme like
mycomponenttype/name1
,mycomponenttype/name2
wheremycomponenttype
is used as the type for both componentsSwitched from ruamel.yaml to PyYAML as the backing YAML library
Changed how
CLIApplicationComponent
is run – theirrun()
method is now called directly by the runner after the component has started
BACKWARD INCOMPATIBLE Changes in concurrency handling:
Added the
start_service_task()
function for starting background service tasks, bound to the root context, fromComponent.start()
Added the
start_background_task_factory()
function for launching ad-hoc background tasks in a manner compatible with Structured ConcurrencyDropped the
@executor
decoratorDropped all context-bound methods of jumping to and from worker threads (
Context.call_async()
,Context.call_in_executor()
,Context.threadpool()
)
BACKWARD INCOMPATIBLE Changes in the component API:
Dropped the
ctx
parameter fromComponent.start()
andCLIApplicationComponent.run()
Changed how
CLIApplicationComponent
works: they no longer start a service task that call therun()
method, but instead the runner will call it directlyAdded the
start_component()
function which is now the preferred method for starting components directly (e.g. in test suites)
BACKWARD INCOMPATIBLE Changes in (Asphalt) context handling:
Dropped the
TeardownError
exception in favor of PEP 654 exception groupsDropped the
Context.loop
attributeDropped the
Context.context_chain
attributeDropped the
Context.close()
method (Context
objects are now required to be used as context managers)Dropped the deprecated ability to use a
Context
as a synchronous context managerDropped the deprecated
parent
argument toContext
Dropped support for context attributes
Dropped the
ctx
parameter from resource factory callbacksRefactored the
Context.get_resource()
,Context.require_resource()
andContext.request_resource()
methods (and their free-function counterparts) to just two:get_resource()
: a coroutine function, capable of triggering asynchronous resource factories, (and when called during component start-up, optionally waits for the resource to become available)get_resource_nowait()
the synchronous counterpart to the above, but incapable of waiting for resources or triggering asynchronous resource factories
Contexts now make a shallow copy of the non-generated resources, and resource factories, from their parents rather than allowing lookup from parents. This was done to prevent service tasks from using resources added later in the application startup cycle which would be torn down before the tasks.
BACKWARD INCOMPATIBLE Dropped the deprecated
Dependency()
markerBACKWARD INCOMPATIBLE Changes in the event system:
The
connect()
,disconnect()
anddispatch_raw()
methods were removedThe
dispatch()
method now accepts only anEvent
object and fills in the source, topic and time attributesThe
Event
class no longer has an initializer, so subclasses don’t have to callsuper().__init__()
anymore
BACKWARD INCOMPATIBLE Moved all exported functions and classes directly to
asphalt.core
and made submodules privateAdded support for Python 3.13
Dropped support for Python 3.7 and 3.8
4.12.0
Removed explicit run-time argument type checks and the
typeguard
dependency
4.11.1 (2023-03-23)
Worked around the presence of the
importlib_metadata
module on Python 3.10 and later causingPluginContainer.create_component()
to fail withAttributeError
4.11.0 (2022-12-03)
Added the
--set
option forasphalt run
for overriding specific values in configuration (PR by David Brochart)Made configuration files optional (PR by David Brochart)
4.10.1 (2022-06-10)
Fixed root context being unset as the current context before its
close()
method is run
4.10.0 (2022-05-27)
Changed
@executor
to propagate the PEP 567 context to the worker thread, just likeContext.call_in_executor()
4.9.1 (2022-05-22)
Fixed type annotation for
@context_teardown
Improved type annotations
4.9.0 (2022-05-22)
Added
asphalt.core.get_resources()
as a top-level shortcut forcurrent_context().get_resources(...)
Allowed resource retrieval and generation in teardown callbacks until the context has been completely closed (this would previously raise
RuntimeError("this context has already been closed")
)Allowed specifying optional dependencies with dependency injection, using either
Optional[SomeType]
(all Python versions) orSomeType | None
(Python 3.10+)Allowed omitting the
types
argument inContext.add_resource_factory()
if the factory callable has a return type annotationContext.call_in_executor()
now copies the current PEP 567 context to the worker thread, allowing operations that require the “current context” to be present (e.g. dependency injection)Raise better errors when the developer forgets to call
resource()
or forgets to add the@inject
decoratorRaise a
UserWarning
when@inject
is used on a function that has noresource()
declarationsFixed
@inject
not resolving forward references in type annotations in locally defined functionsImproved type annotations
4.8.0 (2022-04-28)
Context
now accepts parametrized generic classes as resource typesDeprecated context variables in favor of dependency injection
Replaced
asphalt.core.context.Dependency
withasphalt.core.context.resource
due to issues with strict type checking (the former is now deprecated and will be removed in v5.0)Added support for dependency injection on synchronous functions
Added shortcut functions for obtaining resources (
asphalt.core.get_resource()
,asphalt.core.require_resource()
)Fixed dependency injection not working with forward references (
from __future__ import annotations
)
4.7.0 (2022-04-08)
Removed all uses of Python 3.5 style
await yield_()
from core code and documentationAdded tracking of current Asphalt context in a PEP 555 context variable, available via
current_context()
Added dependency injection in coroutine functions via
Dependency()
andinject()
4.6.0 (2021-12-15)
Added support for Python 3.10
Dropped support for Python 3.5 and 3.6
Removed all uses of the
loop
argument (fixes Python 3.10 compatibility)Switched to v0.15+ API of
ruamel.yaml
Switched from
pkg_resources
toimportlib.metadata
for loading entry pointsFixed
DeprecationWarning
about passing coroutine objects toasyncio.wait()
Fixed
DeprecationWarning
about implicitly creating a new event loop usingget_event_loop()
Added the
py.typed
marker to enable type checking with dependent projectsDeprecated the use of
Context
as a synchronous context manager
4.5.0 (2019-03-26)
Added new custom YAML tags (
!Env
,!BinaryFile
and!TextFile
)
4.4.4 (2018-05-08)
Changed the
async_timeout
dependency to allow the 3.x and newer releases
4.4.3 (2018-02-05)
Fixed exception in
stream_events()
cleanup code introduced in the previous release
4.4.2 (2018-02-02)
Fixed memory leak when
stream_events()
is called but the returned generator is never used
4.4.1 (2018-01-21)
Fixed incompatibility with Python 3.5.2
4.4.0 (2017-11-25)
Removed the requirement for async generators to yield at least once when wrapped with
@context_teardown
Removed aiogevent support since it has been removed from PyPI
4.3.0 (2017-11-05)
The runner now calls
logging.shutdown()
after the event loop has been closedAdded the
Context.get_resources()
methodMade
stream_events()
connect to the signal when called instead of the first iteration of the async generator
4.2.0 (2017-08-24)
Allowed selecting the service to run with
asphalt run
using an environment variable (ASPHALT_SERVICE
)
4.1.0 (2017-08-18)
Added support for the Tokio event loop
Added a feature to the runner that lets one define multiple services in a configuration file and select which one to run
Increased the runner default start timeout to 10 seconds
4.0.0 (2017-06-04)
BACKWARD INCOMPATIBLE When a teardown callback raises an exception during
Context.close()
, aTeardownException
is raised at the end instead of the error being loggedRenamed the
asphalt.core.command
module toasphalt.core.cli
Fixed the inability to override the component type from external configuration (contributed by Devin Fee)
3.0.2 (2017-05-05)
Fixed
CLIApplicationComponent
running prematurely (during the application start phase) and skipping the proper shutdown sequenceFixed return code from
CLIApplicationComponent
being ignored
3.0.1 (2017-04-30)
Fixed
run_application()
not working on Windows due toNotImplementedError
when adding theSIGTERM
signal handler
3.0.0 (2017-04-10)
BACKWARD INCOMPATIBLE Upped the minimum Python version to 3.5.2 from 3.5.0
BACKWARD INCOMPATIBLE Renamed the
asphalt.core.util
module toasphalt.core.utils
The
asphalt.core.event
module was overhauled:BACKWARD INCOMPATIBLE Removed the
monotime
attribute from theEvent
classBACKWARD INCOMPATIBLE Dropped the
return_future
argument fromSignal.dispatch()
andSignal.dispatch_event()
– they now always return an awaitable that resolves to a boolean, indicating whether all callbacks were successful or notBACKWARD INCOMPATIBLE Made the
max_queue_size
argument inSignal.stream_events
andstream_events()
into a keyword-only argumentBACKWARD INCOMPATIBLE
Signal.dispatch_event()
was renamed toSignal.dispatch_raw()
Added the
filter
argument toSignal.stream_events()
andstream_events()
which can restrict the events that are yielded by themAdded the
time
constructor argument to theEvent
class
The
asphalt.core.context
module was overhauled:“lazy resources” are now called “resource factories”
Context.get_resources()
now returns a set ofResourceContainer
(instead of a list)BACKWARD INCOMPATIBLE The
default_timeout
parameter was removed from theContext
constructor- BACKWARD INCOMPATIBLE The
timeout
parameter of Context.request_resource()
was removed
- BACKWARD INCOMPATIBLE The
BACKWARD INCOMPATIBLE The
alias
parameter ofContext.request_resource()
was renamed toname
BACKWARD INCOMPATIBLE Removed the
Context.finished
signal in favor of the newadd_teardown_callback()
method which has different semantics (callbacks are called in LIFO order and awaited for one at a time)BACKWARD INCOMPATIBLE Removed the ability to remove resources from a
Context
Added several new methods to the
Context
class:close()
,get_resource()
,require_resource()
BACKWARD INCOMPATIBLE
Context.publish_resource()
was renamed toContext.add_resource()
BACKWARD INCOMPATIBLE
Context.publish_lazy_resource()
was renamed toContext.add_resource_factory()
BACKWARD INCOMPATIBLE The
Context.get_resources()
method was removed until it can be replaced with a better thought out APIBACKWARD INCOMPATIBLE The
Resource
class was removed from the public APIThree new methods were added to the
Context
class to bridgeasyncio_extras
andExecutor
resources:call_async()
,call_in_executor()
andthreadpool()
Added a new decorator,
@executor
to help run code in specificExecutor
resources
The application runner (
asphalt.core.runner
) got some changes too:BACKWARD INCOMPATIBLE The runner no longer cancels all active tasks on exit
BACKWARD INCOMPATIBLE There is now a (configurable, defaults to 5 seconds) timeout for waiting for the root component to start
Asynchronous generators are now closed after the context has been closed (on Python 3.6+)
The SIGTERM signal now cleanly shuts down the application
Switched from
asyncio_extras
toasync_generator
as the async generator compatibility libraryMade the current event loop accessible (from any thread) as the
loop
property from anyasphalt.core.context.Context
instance to make it easier to schedule execution of async code from worker threadsThe
asphalt.core.utils.merge_config()
function now acceptsNone
as either argument (or both)
2.1.1 (2017-02-01)
Fixed memory leak which prevented objects containing Signals from being garbage collected
Log a message on startup that indicates whether optimizations (
-O
orPYTHONOPTIMIZE
) are enabled
2.1.0 (2016-09-26)
Added the possibility to specify more than one configuration file on the command line
Added the possibility to use the command line interface via
python -m asphalt ...
Added the
CLIApplicationComponent
class to facilitate the creation of Asphalt based command line toolsRoot component construction is now done after installing any alternate event loop policy provider
Switched YAML library from PyYAML to ruamel.yaml
Fixed a corner case where in
wait_event()
the future’s result would be set twice, causing an exception in the listenerFixed coroutine-based lazy resource returning a CoroWrapper instead of a Future when asyncio’s debug mode has been enabled
Fixed a bug where a lazy resource would not be created separately for a context if a parent context contained an instance of the same resource
2.0.0 (2016-05-09)
BACKWARD INCOMPATIBLE Dropped Python 3.4 support in order to make the code fully rely on the new
async
/await
,async for
andasync with
language additionsBACKWARD INCOMPATIBLE De-emphasized the ability to implicitly run code in worker threads. As such, Asphalt components are no longer required to transparently work outside of the event loop thread. Instead, use
asyncio_extras.threads.call_async()` to call asynchronous code from worker threads if absolutely necessary. As a direct consequence of this policy shift, the ``asphalt.core.concurrency
module was dropped in favor of theasyncio_extras
library.BACKWARD INCOMPATIBLE The event system was completely rewritten:
instead of inheriting from
EventSource
, event source classes now simply assignSignal
instances to attributes and useobject.signalname.connect()
to listen to eventsall event listeners are now called independently of each other and coroutine listeners are run concurrently
added the ability to stream events
added the ability to wait for a single event to be dispatched
BACKWARD INCOMPATIBLE Removed the
asphalt.command
module from the public APIBACKWARD INCOMPATIBLE Removed the
asphalt quickstart
commandBACKWARD INCOMPATIBLE Removed the
asphalt.core.connectors
moduleBACKWARD INCOMPATIBLE Removed the
optional
argument ofContext.request_resource()
BACKWARD INCOMPATIBLE Removed the
asphalt.core.runners
entry point namespaceBACKWARD INCOMPATIBLE
Component.start()
is now required to be a coroutine methodBACKWARD INCOMPATIBLE Removed regular context manager support from the
Context
class (asynchronous context manager support still remains)BACKWARD INCOMPATIBLE The
Context.publish_resource()
,Context.publish_lazy_resource()
andContext.remove_resource()
methods are no longer coroutine methodsBACKWARD INCOMPATIBLE Restricted resource names to alphanumeric characters and underscores
Added the possibility to specify a custom event loop policy
Added support for uvloop
Added support for aiogevent
Added the ability to use coroutine functions as lazy resource creators (though that just makes them return a
Future
instead)Added the ability to get a list of all the resources in a Context
Changed the
asphalt.core.util.resolve_reference()
function to return invalid reference strings as-isSwitched from argparse to click for the command line interface
All of Asphalt core’s public API is now importable directly from
asphalt.core
1.2.0 (2016-01-02)
Moved the
@asynchronous
and@blocking
decorators to theasphalt.core.concurrency
package along with related code (they’re still importable fromasphalt.core.util
until v2.0)Added typeguard checks to fail early if arguments of wrong types are passed to functions
1.1.0 (2015-11-19)
Decorated
ContainerComponent.start
with@asynchronous
so that it can be called by a blocking subclass implementationAdded the
stop_event_loop
function to enable blocking callables to shut down Asphalt’s event loop
1.0.0 (2015-10-18)
Initial release