Skip to content

Commit

Permalink
Documentation fixes and reformatting
Browse files Browse the repository at this point in the history
  • Loading branch information
agronholm committed Mar 20, 2024
1 parent 4fa6b5e commit ee98fd5
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 151 deletions.
6 changes: 5 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@
html_theme = "sphinx_rtd_theme"
htmlhelp_basename = "asphaltdoc"

intersphinx_mapping = {"python": ("https://docs.python.org/3/", None)}
intersphinx_mapping = {
"anyio": ("https://anyio.readthedocs.io/en/stable/", None),
"asphalt-mailer": ("https://asphalt-mailer.readthedocs.io/en/stable/", None),
"python": ("https://docs.python.org/3/", None),
}
22 changes: 12 additions & 10 deletions docs/tutorials/echo.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
Tutorial 1: Getting your feet wet – a simple echo server and client
===================================================================

.. py:currentmodule:: asphalt.core
This tutorial will get you started with Asphalt development from the ground up.
You will learn how to build a simple network server that echoes back messages sent to it, along
with a matching client application. It will however not yet touch more advanced concepts like
using the ``asphalt`` command to run an application with a configuration file.
You will learn how to build a simple network server that echoes back messages sent to
it, along with a matching client application. It will however not yet touch more
advanced concepts like using the ``asphalt`` command to run an application with a
configuration file.

Prerequisites
-------------
Expand Down Expand Up @@ -198,12 +201,10 @@ Create the file ``client.py`` file in the ``echo`` package directory as follows:
anyio.run(run_application, component)

You may have noticed that ``ClientComponent`` inherits from
:class:`~asphalt.core.component.CLIApplicationComponent` instead of
:class:`~asphalt.core.component.Component` and that instead of overriding the
:meth:`~asphalt.core.component.Component.start` method,
:meth:`~asphalt.core.component.CLIApplicationComponent.run` is overridden instead.
This is standard practice for Asphalt applications that just do one specific thing and
then exit.
:class:`CLIApplicationComponent` instead of :class:`Component` and that instead of
overriding the :meth:`Component.start` method, :meth:`CLIApplicationComponent.run` is
overridden instead. This is standard practice for Asphalt applications that just do one
specific thing and then exit.

The script instantiates ``ClientComponent`` using the first command line argument as the
``message`` argument to the component's constructor. Doing this instead of directly
Expand Down Expand Up @@ -241,4 +242,5 @@ This tutorial only scratches the surface of what's possible with Asphalt, howeve
teach you how to work with components, resources and configuration files to build more
useful applications.

.. _AnyIO socket streams: https://anyio.readthedocs.io/en/stable/networking.html#working-with-tcp-sockets
.. _AnyIO socket streams: https://anyio.readthedocs.io/en/stable/networking.html#\
working-with-tcp-sockets
217 changes: 115 additions & 102 deletions docs/tutorials/webnotifier.rst

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions docs/userguide/concurrency.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ Working with coroutines and threads

.. py:currentmodule:: asphalt.core
Asphalt was designed as a network oriented framework capable of high concurrency. This means that
it can efficiently work with hundreds or even thousands of connections at once. This is achieved by
utilizing `co-operative multitasking`_, using an *event loop* provided by the :mod:`asyncio`
Asphalt was designed as a network oriented framework capable of high concurrency. This
means that it can efficiently work with hundreds or even thousands of connections at
once. This is achieved by utilizing `co-operative multitasking`_, using an *event loop*
provided by the :mod:`asyncio`
module.

The event loop can only work on one task at a time, so whenever the currently running task needs to
Expand Down
51 changes: 27 additions & 24 deletions docs/userguide/testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,26 @@ Testing Asphalt components
Testing Asphalt components and component hierarchies is a relatively simple procedure:

#. Create an instance of your :class:`~asphalt.core.component.Component`
#. Create a :class:`~asphalt.core.context.Context` instance
#. Run the component's :meth:`~.component.Component.start` method with the context as the argument
#. Create an instance of your :class:`~Component`
#. Create a :class:`~Context` instance
#. Run the component's :meth:`~Component.start` method with the context as the argument
#. Run the tests
#. Close the context to release any resources

With Asphalt projects, it is recommended to use the pytest_ testing framework because it is
already being used with Asphalt core and it provides easy testing of asynchronous code
(via the pytest-asyncio_ plugin).
With Asphalt projects, it is recommended to use the pytest_ testing framework because it
is already being used with Asphalt core and it provides easy testing of asynchronous
code (via the pytest-asyncio_ plugin).

Example
-------

Let's build a test suite for the :doc:`Echo Tutorial <../tutorials/echo>`.

The client and server components could be tested separately, but to make things easier, we'll test
them against each other.
The client and server components could be tested separately, but to make things easier,
we'll test them against each other.

Create a ``tests`` directory at the root of the project directory and create a module named
``test_client_server`` there (the ``test_`` prefix is important)::
Create a ``tests`` directory at the root of the project directory and create a module
named ``test_client_server`` there (the ``test_`` prefix is important)::

import pytest
from asphalt.core import Context
Expand Down Expand Up @@ -57,31 +57,34 @@ The test module above contains one test function which uses one fixture (``capsy
This fixture is provided by ``pytest``, and it captures standard output and error,
letting us find out what message the components printed.

In the test function (``test_client_and_server()``), the server and client components are
instantiated and started. Since the client component's
:meth:`~.component.CLIApplicationComponent.start` function only kicks off a task that runs the
client's business logic (the :meth:`~.component.CLIApplicationComponent.run` method), we have to
In the test function (``test_client_and_server()``), the server and client components
are instantiated and started. Since the client component's
:meth:`~CLIApplicationComponent.start` function only kicks off a task that runs the
client's business logic (the :meth:`~CLIApplicationComponent.run` method), we have to
wait until the task is complete by running the event loop (using
:meth:`~asyncio.loop.run_forever`) until
:meth:`~.component.CLIApplicationComponent.run` finishes and its callback code attempts to
terminate the application. For that purpose, we catch the resulting :exc:`SystemExit` exception and
verify that the application indeed completed successfully, as indicated by the return code of 0.
:meth:`~CLIApplicationComponent.run` finishes and its callback code attempts to
terminate the application. For that purpose, we catch the resulting :exc:`SystemExit`
exception and verify that the application indeed completed successfully, as indicated by
the return code of 0.

Finally, we check that the server and the client printed the messages they were supposed to.
When the server receives a line from the client, it prints a message to standard output using
:func:`print`. Likewise, when the client gets a response from the server, it too prints out its
own message. By using pytest's built-in capsys_ fixture, we can capture the output and verify it
against the expected lines.
Finally, we check that the server and the client printed the messages they were supposed
to. When the server receives a line from the client, it prints a message to standard
output using :func:`print`. Likewise, when the client gets a response from the server,
it too prints out its own message. By using pytest's built-in capsys_ fixture, we can
capture the output and verify it against the expected lines.

To run the test suite, make sure you're in the project directory and then do:

.. code-block:: bash
PYTHONPATH=. pytest tests
For more elaborate examples, please see the test suites of various `Asphalt subprojects`_.
For more elaborate examples, please see the test suites of various
`Asphalt subprojects`_.

.. _pytest: http://pytest.org/
.. _pytest-asyncio: https://pypi.python.org/pypi/pytest-asyncio
.. _capsys: https://docs.pytest.org/en/6.2.x/capture.html#accessing-captured-output-from-a-test-function
.. _capsys: https://docs.pytest.org/en/6.2.x/capture.html#accessing-captured-output-\
from-a-test-function
.. _Asphalt subprojects: https://github.com/asphalt-framework
2 changes: 1 addition & 1 deletion src/asphalt/core/_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def add_component(
When configuration values are provided both as keyword arguments to this method
and component configuration through the ``components`` constructor argument, the
configurations are merged together using :func:`~asphalt.core.util.merge_config`
configurations are merged together using :func:`~asphalt.core.merge_config`
in a way that the configuration values from the ``components`` argument override
the keyword arguments to this method.
Expand Down
15 changes: 6 additions & 9 deletions src/asphalt/core/_concurrent.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
@dataclass
class TaskHandle:
"""
A representation of a task started from :meth:`Context.start_background_task`.
A representation of a task started from :class:`TaskFactory`.
:ivar name: the name of the task
:ivar start_value: the start value passed to ``task_status.started()`` if the target
Expand Down Expand Up @@ -115,7 +115,7 @@ async def start_task(
If ``func`` takes an argument named ``task_status``, then this method will only
return when the function has called ``task_status.started()``. See
:meth:`anyio.TaskGroup.start` for details. The value passed to
:meth:`anyio.abc.TaskGroup.start` for details. The value passed to
``task_status.started()`` will be available as the ``start_value`` property on
the :class:`TaskHandle`.
Expand Down Expand Up @@ -150,12 +150,9 @@ async def start_service_task(
Start a background task that gets shut down when the context shuts down.
This method is meant to be used by components to run their tasks like network
services that should be shut down with the application, while
:meth:`start_background_task` is meant to be used to run ad-hoc background tasks
that should be allowed to finish before the root context exits.
Behind the scenes, this method uses :meth:`start_background_task`, so its
semantics also apply here.
services that should be shut down with the application, because each call to this
functions registers a context teardown callback that waits for the service task to
finish before allowing the context teardown to continue..
If you supply a teardown callback, and it raises an exception, then the task
will be cancelled instead.
Expand Down Expand Up @@ -248,7 +245,7 @@ async def start_background_task_factory(
``True`` if it successfully handled the exception.
:return: the task factory
.. seealso:: :meth:`Context.start_service_task`
.. seealso:: :func:`start_service_task`
"""
factory = TaskFactory(exception_handler)
Expand Down
2 changes: 1 addition & 1 deletion src/asphalt/core/_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ def require_resource(
This is like :meth:`get_resource` except that instead of returning ``None`` when
a resource is not found, it will raise
:exc:`~asphalt.core.context.ResourceNotFound`.
:exc:`~asphalt.core.ResourceNotFound`.
:param type: type of the requested resource
:param name: name of the requested resource
Expand Down

0 comments on commit ee98fd5

Please sign in to comment.