Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: agronholm/anyio
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 3.7.0
Choose a base ref
...
head repository: agronholm/anyio
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 3.7.1
Choose a head ref
  • 5 commits
  • 17 files changed
  • 1 contributor

Commits on Jul 5, 2023

  1. Updated pre-commit modules

    (cherry picked from commit 889209b)
    agronholm committed Jul 5, 2023
    Copy the full SHA
    052634c View commit details
  2. Fixed sending large buffers on UNIX stream sockets on asyncio

    Fixes #579.
    
    (cherry picked from commit fa011d2)
    agronholm committed Jul 5, 2023
    Copy the full SHA
    f1f9991 View commit details
  3. Copy the full SHA
    da94a29 View commit details
  4. Copy the full SHA
    d920654 View commit details
  5. Bumped up the version

    agronholm committed Jul 5, 2023
    Copy the full SHA
    3e182fa View commit details
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ jobs:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
cache: pip
cache-dependency-path: setup.cfg
cache-dependency-path: pyproject.toml
- name: Install dependencies
run: pip install -e .[test] coveralls
- name: Test with pytest
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ repos:
- id: trailing-whitespace

- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.270
rev: v0.0.277
hooks:
- id: ruff
args: [--fix, --show-fixes]
@@ -27,7 +27,7 @@ repos:
- id: black

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.3.0
rev: v1.4.1
hooks:
- id: mypy
additional_dependencies:
4 changes: 3 additions & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
@@ -65,7 +65,7 @@ Running asynchronous code from other threads
.. autofunction:: anyio.from_thread.create_blocking_portal
.. autofunction:: anyio.from_thread.start_blocking_portal

.. autoclass:: anyio.abc.BlockingPortal
.. autoclass:: anyio.from_thread.BlockingPortal

Async file I/O
--------------
@@ -135,6 +135,7 @@ Sockets and networking
.. autoclass:: anyio.abc.SocketListener()
.. autoclass:: anyio.abc.UDPSocket()
.. autoclass:: anyio.abc.ConnectedUDPSocket()
.. autoclass:: anyio.abc.UNIXSocketStream()

Subprocesses
------------
@@ -157,6 +158,7 @@ Synchronization
.. autoclass:: anyio.EventStatistics
.. autoclass:: anyio.ConditionStatistics
.. autoclass:: anyio.CapacityLimiterStatistics
.. autoclass:: anyio.SemaphoreStatistics

.. autofunction:: anyio.create_event
.. autofunction:: anyio.create_lock
6 changes: 3 additions & 3 deletions docs/cancellation.rst
Original file line number Diff line number Diff line change
@@ -28,9 +28,9 @@ context managers. The difference between these two is that the former simply exi
block prematurely on a timeout, while the other raises a :exc:`TimeoutError`.

Both methods create a new cancel scope, and you can check the deadline by accessing the
:attr:`~.abc.CancelScope.deadline` attribute. Note, however, that an outer cancel scope may
have an earlier deadline than your current cancel scope. To check the actual deadline, you can use
the :func:`~current_effective_deadline` function.
:attr:`~.CancelScope.deadline` attribute. Note, however, that an outer cancel scope
may have an earlier deadline than your current cancel scope. To check the actual
deadline, you can use the :func:`~current_effective_deadline` function.

Here's how you typically use timeouts::

2 changes: 1 addition & 1 deletion docs/fileio.rst
Original file line number Diff line number Diff line change
@@ -53,7 +53,7 @@ Asynchronous path operations
AnyIO provides an asynchronous version of the :class:`pathlib.Path` class. It differs with the
original in a number of ways:

* Operations that perform disk I/O (like :meth:`~pathlib.Path.read_bytes``) are run in a worker
* Operations that perform disk I/O (like :meth:`~pathlib.Path.read_bytes`) are run in a worker
thread and thus require an ``await``
* Methods like :meth:`~pathlib.Path.glob` return an asynchronous iterator that yields asynchronous
:class:`~.Path` objects
28 changes: 14 additions & 14 deletions docs/migration.rst
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ The following functions and methods were changed:

* :func:`current_time`
* :func:`current_effective_deadline`
* :meth:`CancelScope.cancel() <.abc.CancelScope.cancel>`
* :meth:`CancelScope.cancel() <.CancelScope.cancel>`
* :meth:`CapacityLimiter.acquire_nowait`
* :meth:`CapacityLimiter.acquire_on_behalf_of_nowait`
* :meth:`Condition.release`
@@ -40,14 +40,14 @@ When migrating to AnyIO 3, simply remove the ``await`` from each call to these.
awaitable versions of their original types (:class:`float` and :class:`list`,
respectively). These awaitable versions are subclasses of the original types so they
should behave as their originals, but if you absolutely need the pristine original types,
you can either use :func:`maybe_async` or ``float()`` / ``list()`` on the returned
you can either use ``maybe_async`` or ``float()`` / ``list()`` on the returned
value as appropriate.

The following async context managers changed to regular context managers:

* :func:`fail_after`
* :func:`move_on_after`
* :func:`open_cancel_scope` (now just ``CancelScope()``)
* ``open_cancel_scope()`` (now just ``CancelScope()``)

When migrating, just change ``async with`` into a plain ``with``.

@@ -57,8 +57,8 @@ all of them can still be used like before – they will raise :exc:`DeprecationW
this way on AnyIO 3, however.

If you're writing a library that needs to be compatible with both major releases, you will need
to use the compatibility functions added in AnyIO 2.2: :func:`maybe_async` and
:func:`maybe_async_cm`. These will let you safely use functions/methods and context managers
to use the compatibility functions added in AnyIO 2.2: ``maybe_async()`` and
``maybe_async_cm()``. These will let you safely use functions/methods and context managers
(respectively) regardless of which major release is currently installed.

Example 1 – setting an event::
@@ -84,11 +84,11 @@ Example 2 – opening a cancel scope::
Starting tasks
--------------

The :meth:`TaskGroup.spawn` coroutine method has been deprecated in favor of the synchronous
method :meth:`TaskGroup.start_soon` (which mirrors ``start_soon()`` in trio's nurseries). If you're
fully migrating to AnyIO 3, simply switch to calling the new method (and remove the ``await``).
The ``TaskGroup.spawn()`` coroutine method has been deprecated in favor of the synchronous
method :meth:`.TaskGroup.start_soon` (which mirrors ``start_soon()`` in trio's nurseries).
If you're fully migrating to AnyIO 3, simply switch to calling the new method (and remove the ``await``).

If your code needs to work with both AnyIO 2 and 3, you can keep using :meth:`~TaskGroup.spawn`
If your code needs to work with both AnyIO 2 and 3, you can keep using ``TaskGroup.spawn()``
(until AnyIO 4) and suppress the deprecation warning::

import warnings
@@ -109,18 +109,18 @@ AnyIO now **requires** :func:`.from_thread.start_blocking_portal` to be used as
with start_blocking_portal() as portal:
portal.call(sleep, 1)

As with :meth:`TaskGroup.spawn`, the :meth:`BlockingPortal.spawn_task` method has also been renamed
to :meth:`~BlockingPortal.start_task_soon`, so as to be consistent with task groups.
As with ``TaskGroup.spawn()``, the ``BlockingPortal.spawn_task()`` method has also been renamed
to :meth:`~from_thread.BlockingPortal.start_task_soon`, so as to be consistent with task groups.

The :func:`create_blocking_portal` factory function was also deprecated in favor of instantiating
:class:`BlockingPortal` directly.
The ``create_blocking_portal()`` factory function was also deprecated in favor of instantiating
:class:`~from_thread.BlockingPortal` directly.

For code requiring cross compatibility, catching the deprecation warning (as above) should work.

Synchronization primitives
--------------------------

Synchronization primitive factories (:func:`create_event` etc.) were deprecated in favor of
Synchronization primitive factories (``create_event()`` etc.) were deprecated in favor of
instantiating the classes directly. So convert code like this::

from anyio import create_event
2 changes: 1 addition & 1 deletion docs/networking.rst
Original file line number Diff line number Diff line change
@@ -108,7 +108,7 @@ Sending and receiving file descriptors
++++++++++++++++++++++++++++++++++++++

UNIX sockets can be used to pass open file descriptors (sockets and files) to another process.
The receiving end can then use either :func:`os.fdopen` or :func:`socket.socket` to get a usable
The receiving end can then use either :func:`os.fdopen` or :class:`socket.socket` to get a usable
file or socket object, respectively.

The following is an example where a client connects to a UNIX socket server and receives the
2 changes: 1 addition & 1 deletion docs/signals.rst
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@ AnyIO provides a simple mechanism for you to receive the signals you're interest
run(main)

.. note:: Signal handlers can only be installed in the main thread, so they will not work when the
event loop is being run through :func:`~start_blocking_portal`, for instance.
event loop is being run through :class:`~.from_thread.BlockingPortal`, for instance.

.. note:: Windows does not natively support signals so do not rely on this in a cross platform
application.
4 changes: 2 additions & 2 deletions docs/threads.rst
Original file line number Diff line number Diff line change
@@ -83,7 +83,7 @@ If you need to run async code from a thread that is not a worker thread spawned
you need a *blocking portal*. This needs to be obtained from within the event loop thread.

One way to do this is to start a new event loop with a portal, using
:func:`~start_blocking_portal` (which takes mostly the same arguments as :func:`~run`::
:class:`~from_thread.start_blocking_portal` (which takes mostly the same arguments as :func:`~run`::

from anyio.from_thread import start_blocking_portal

@@ -193,7 +193,7 @@ Adjusting the default maximum worker thread count
-------------------------------------------------

The default AnyIO worker thread limiter has a value of **40**, meaning that any calls
to :func:`.to_thread.run` without an explicit ``limiter`` argument will cause a maximum
to :func:`.to_thread.run_sync` without an explicit ``limiter`` argument will cause a maximum
of 40 threads to be spawned. You can adjust this limit like this::

from anyio import to_thread
6 changes: 6 additions & 0 deletions docs/versionhistory.rst
Original file line number Diff line number Diff line change
@@ -3,6 +3,12 @@ Version history

This library adheres to `Semantic Versioning 2.0 <http://semver.org/>`_.

**3.7.1**

- Fixed sending large buffers via UNIX stream sockets on asyncio
- Fixed several minor documentation issues (broken links to classes, missing classes or
attributes)

**3.7.0**

- Dropped support for Python 3.6
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -55,8 +55,8 @@ test = [
]
doc = [
"packaging",
"Sphinx >= 6.1.0",
"sphinx_rtd_theme",
"Sphinx",
"sphinx-rtd-theme >= 1.2.2",
"sphinxcontrib-jquery",
"sphinx-autodoc-typehints >= 1.2.0",
]
@@ -147,5 +147,5 @@ commands = pyright --verifytypes anyio
[testenv:docs]
depends =
extras = doc
commands = sphinx-build -W -n docs build/sphinx
commands = sphinx-build -W docs build/sphinx
"""
2 changes: 1 addition & 1 deletion src/anyio/_backends/_asyncio.py
Original file line number Diff line number Diff line change
@@ -1329,7 +1329,7 @@ async def send(self, item: bytes) -> None:
view = memoryview(item)
while view:
try:
bytes_sent = self.__raw_socket.send(item)
bytes_sent = self.__raw_socket.send(view)
except BlockingIOError:
await self._wait_until_writable(loop)
except OSError as exc:
6 changes: 3 additions & 3 deletions src/anyio/_core/_synchronization.py
Original file line number Diff line number Diff line change
@@ -149,7 +149,7 @@ def acquire_nowait(self) -> None:
"""
Acquire the lock, without blocking.
:raises ~WouldBlock: if the operation would block
:raises ~anyio.WouldBlock: if the operation would block
"""
task = get_current_task()
@@ -218,7 +218,7 @@ def acquire_nowait(self) -> None:
"""
Acquire the underlying lock, without blocking.
:raises ~WouldBlock: if the operation would block
:raises ~anyio.WouldBlock: if the operation would block
"""
self._lock.acquire_nowait()
@@ -336,7 +336,7 @@ def acquire_nowait(self) -> None:
"""
Acquire the underlying lock, without blocking.
:raises ~WouldBlock: if the operation would block
:raises ~anyio.WouldBlock: if the operation would block
"""
if self._value == 0:
2 changes: 1 addition & 1 deletion src/anyio/_core/_tasks.py
Original file line number Diff line number Diff line change
@@ -129,7 +129,7 @@ def fail_after(delay: float | None, shield: bool = False) -> FailAfterContextMan
disable the timeout
:param shield: ``True`` to shield the cancel scope from external cancellation
:return: a context manager that yields a cancel scope
:rtype: :class:`~typing.ContextManager`\\[:class:`~anyio.abc.CancelScope`\\]
:rtype: :class:`~typing.ContextManager`\\[:class:`~anyio.CancelScope`\\]
"""
deadline = (
17 changes: 10 additions & 7 deletions src/anyio/from_thread.py
Original file line number Diff line number Diff line change
@@ -350,10 +350,11 @@ def start_task_soon(
:param func: the target function
:param args: positional arguments passed to ``func``
:param name: name of the task (will be coerced to a string if not ``None``)
:return: a future that resolves with the return value of the callable if the task completes
successfully, or with the exception raised in the task
:raises RuntimeError: if the portal is not running or if this method is called from within
the event loop thread
:return: a future that resolves with the return value of the callable if the
task completes successfully, or with the exception raised in the task
:raises RuntimeError: if the portal is not running or if this method is called
from within the event loop thread
:rtype: concurrent.futures.Future[T_Retval]
.. versionadded:: 3.0
@@ -369,13 +370,15 @@ def start_task(
"""
Start a task in the portal's task group and wait until it signals for readiness.
This method works the same way as :meth:`TaskGroup.start`.
This method works the same way as :meth:`.abc.TaskGroup.start`.
:param func: the target function
:param args: positional arguments passed to ``func``
:param name: name of the task (will be coerced to a string if not ``None``)
:return: a tuple of (future, task_status_value) where the ``task_status_value`` is the
value passed to ``task_status.started()`` from within the target function
:return: a tuple of (future, task_status_value) where the ``task_status_value``
is the value passed to ``task_status.started()`` from within the target
function
:rtype: tuple[concurrent.futures.Future[Any], Any]
.. versionadded:: 3.0
26 changes: 13 additions & 13 deletions src/anyio/streams/tls.py
Original file line number Diff line number Diff line change
@@ -30,8 +30,8 @@ class TLSAttribute(TypedAttributeSet):
channel_binding_tls_unique: bytes = typed_attribute()
#: the selected cipher
cipher: tuple[str, str, int] = typed_attribute()
#: the peer certificate in dictionary form (see :meth:`ssl.SSLSocket.getpeercert` for more
#: information)
#: the peer certificate in dictionary form (see :meth:`ssl.SSLSocket.getpeercert`
#: for more information)
peer_certificate: dict[str, str | _PCTRTTT | _PCTRTT] | None = typed_attribute()
#: the peer certificate in binary form
peer_certificate_binary: bytes | None = typed_attribute()
@@ -42,8 +42,8 @@ class TLSAttribute(TypedAttributeSet):
shared_ciphers: list[tuple[str, str, int]] | None = typed_attribute()
#: the :class:`~ssl.SSLObject` used for encryption
ssl_object: ssl.SSLObject = typed_attribute()
#: ``True`` if this stream does (and expects) a closing TLS handshake when the stream is being
#: closed
#: ``True`` if this stream does (and expects) a closing TLS handshake when the
#: stream is being closed
standard_compatible: bool = typed_attribute()
#: the TLS protocol version (e.g. ``TLSv1.2``)
tls_version: str = typed_attribute()
@@ -83,13 +83,13 @@ async def wrap(
This performs a TLS handshake with the peer.
:param transport_stream: a bytes-transporting stream to wrap
:param server_side: ``True`` if this is the server side of the connection, ``False`` if
this is the client side (if omitted, will be set to ``False`` if ``hostname`` has been
provided, ``False`` otherwise). Used only to create a default context when an explicit
context has not been provided.
:param server_side: ``True`` if this is the server side of the connection,
``False`` if this is the client side (if omitted, will be set to ``False``
if ``hostname`` has been provided, ``False`` otherwise). Used only to create
a default context when an explicit context has not been provided.
:param hostname: host name of the peer (if host name checking is desired)
:param ssl_context: the SSLContext object to use (if not provided, a secure default will be
created)
:param ssl_context: the SSLContext object to use (if not provided, a secure
default will be created)
:param standard_compatible: if ``False``, skip the closing handshake when closing the
connection, and don't raise an exception if the peer does the same
:raises ~ssl.SSLError: if the TLS handshake fails
@@ -263,14 +263,14 @@ class TLSListener(Listener[TLSStream]):

@staticmethod
async def handle_handshake_error(exc: BaseException, stream: AnyByteStream) -> None:
f"""
"""
Handle an exception raised during the TLS handshake.
This method does 3 things:
#. Forcefully closes the original stream
#. Logs the exception (unless it was a cancellation exception) using the ``{__name__}``
logger
#. Logs the exception (unless it was a cancellation exception) using the
``anyio.streams.tls`` logger
#. Reraises the exception if it was a base exception or a cancellation exception
:param exc: the exception
Loading