summaryrefslogtreecommitdiffstats
path: root/Doc/library/asyncio-extending.rst
blob: acbaa6f7faf745e2f59dfdcd72ee52bd91b17953 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
.. currentmodule:: asyncio


=========
Extending
=========

The main direction for :mod:`asyncio` extending is writing custom *event loop*
classes. Asyncio has helpers that could be used to simplify this task.

.. note::

   Third-parties should reuse existing asyncio code with caution,
   a new Python version is free to break backward compatibility
   in *internal* part of API.


Writing a Custom Event Loop
===========================

:class:`asyncio.AbstractEventLoop` declares very many methods.  Implementing all them
from scratch is a tedious job.

A loop can get many common methods implementation for free by inheriting from
:class:`asyncio.BaseEventLoop`.

In turn, the successor should implement a bunch of *private* methods declared but not
implemented in :class:`asyncio.BaseEventLoop`.

For example, ``loop.create_connection()`` checks arguments, resolves DNS addresses, and
calls ``loop._make_socket_transport()`` that should be implemented by inherited class.
The ``_make_socket_transport()`` method is not documented and is considered as an
*internal* API.



Future and Task private constructors
====================================

:class:`asyncio.Future` and :class:`asyncio.Task` should be never created directly,
please use corresponding :meth:`loop.create_future` and :meth:`loop.create_task`,
or :func:`asyncio.create_task` factories instead.

However, third-party *event loops* may *reuse* built-in future and task implementations
for the sake of getting a complex and highly optimized code for free.

For this purpose the following, *private* constructors are listed:

.. method:: Future.__init__(*, loop=None)

   Create a built-in future instance.

   *loop* is an optional event loop instance.

.. method:: Task.__init__(coro, *, loop=None, name=None, context=None)

   Create a built-in task instance.

   *loop* is an optional event loop instance. The rest of arguments are described in
   :meth:`loop.create_task` description.

   .. versionchanged:: 3.11

      *context* argument is added.

.. method:: Task._check_future(future)

   Return ``True`` if *future* is attached to the same loop as the task, ``False``
   otherwise.

   .. versionadded:: 3.11


Task lifetime support
=====================

A third party task implementation should call the following functions to keep a task
visible by :func:`asyncio.get_tasks` and :func:`asyncio.current_task`:

.. function:: _register_task(task)

   Register a new *task* as managed by *asyncio*.

   Call the function from a task constructor.

.. function:: _unregister_task(task)

   Unregister a *task* from *asyncio* internal structures.

   The function should be called when a task is about to finish.

.. function:: _enter_task(loop, task)

   Switch the current task to the *task* argument.

   Call the function just before executing a portion of embedded *coroutine*
   (:meth:`coroutine.send` or :meth:`coroutine.throw`).

.. function:: _leave_task(loop, task)

   Switch the current task back from *task* to ``None``.

   Call the function just after :meth:`coroutine.send` or :meth:`coroutine.throw`
   execution.