Skip to content

Commit

Permalink
Merge branch 'master' into create_memory_object_stream-typing
Browse files Browse the repository at this point in the history
  • Loading branch information
agronholm committed May 9, 2023
2 parents 436c9f0 + 0414b4e commit 483bd3a
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 232 deletions.
2 changes: 2 additions & 0 deletions docs/versionhistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ This library adheres to `Semantic Versioning 2.0 <http://semver.org/>`_.
currently active cancel scope has been cancelled (PR by Ganden Schaffner)
- Fixed the ``OP_IGNORE_UNEXPECTED_EOF`` flag in an SSL context created by default in
``TLSStream.wrap()`` being inadvertently set on Python 3.11.3 and 3.10.11
- Fixed ``CancelScope`` to properly handle asyncio task uncancellation on Python 3.11
(PR by Nikolay Bryskin)

**3.6.1**

Expand Down
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ target-version = "py37"
src = ["src"]

[tool.mypy]
python_version = "3.10"
python_version = "3.11"
strict = true
ignore_missing_imports = true
disallow_any_generics = false
Expand All @@ -99,7 +99,6 @@ filterwarnings = [
"ignore:unclosed transport <_ProactorSocketTransport.*:ResourceWarning",
# Workaround for Python 3.9.7 (see https://bugs.python.org/issue45097)
"ignore:The loop argument is deprecated since Python 3\\.8, and scheduled for removal in Python 3\\.10\\.:DeprecationWarning:asyncio",
"ignore:Python 3.6 is no longer supported*"
]
markers = [
"network: marks tests as requiring Internet access",
Expand Down
187 changes: 60 additions & 127 deletions src/anyio/__init__.py
Original file line number Diff line number Diff line change
@@ -1,136 +1,69 @@
from __future__ import annotations

__all__ = (
"run",
"sleep",
"sleep_forever",
"sleep_until",
"current_time",
"get_all_backends",
"get_cancelled_exc_class",
"BrokenResourceError",
"BrokenWorkerProcess",
"BusyResourceError",
"ClosedResourceError",
"DelimiterNotFound",
"EndOfStream",
"IncompleteRead",
"TypedAttributeLookupError",
"WouldBlock",
"AsyncFile",
"Path",
"open_file",
"wrap_file",
"aclose_forcefully",
"open_signal_receiver",
"connect_tcp",
"connect_unix",
"create_tcp_listener",
"create_unix_listener",
"create_udp_socket",
"create_connected_udp_socket",
"create_unix_datagram_socket",
"create_connected_unix_datagram_socket",
"getaddrinfo",
"getnameinfo",
"wait_socket_readable",
"wait_socket_writable",
"create_memory_object_stream",
"run_process",
"open_process",
"CapacityLimiter",
"CapacityLimiterStatistics",
"Condition",
"ConditionStatistics",
"Event",
"EventStatistics",
"Lock",
"LockStatistics",
"Semaphore",
"SemaphoreStatistics",
"fail_after",
"move_on_after",
"current_effective_deadline",
"TASK_STATUS_IGNORED",
"CancelScope",
"create_task_group",
"TaskInfo",
"get_current_task",
"get_running_tasks",
"wait_all_tasks_blocked",
"typed_attribute",
"TypedAttributeSet",
"TypedAttributeProvider",
)

from typing import Any

from ._core._eventloop import (
current_time,
get_all_backends,
get_cancelled_exc_class,
run,
sleep,
sleep_forever,
sleep_until,
)
from ._core._exceptions import (
BrokenResourceError,
BrokenWorkerProcess,
BusyResourceError,
ClosedResourceError,
DelimiterNotFound,
EndOfStream,
IncompleteRead,
TypedAttributeLookupError,
WouldBlock,
)
from ._core._fileio import AsyncFile, Path, open_file, wrap_file
from ._core._resources import aclose_forcefully
from ._core._signals import open_signal_receiver
from ._core._eventloop import current_time as current_time
from ._core._eventloop import get_all_backends as get_all_backends
from ._core._eventloop import get_cancelled_exc_class as get_cancelled_exc_class
from ._core._eventloop import run as run
from ._core._eventloop import sleep as sleep
from ._core._eventloop import sleep_forever as sleep_forever
from ._core._eventloop import sleep_until as sleep_until
from ._core._exceptions import BrokenResourceError as BrokenResourceError
from ._core._exceptions import BrokenWorkerProcess as BrokenWorkerProcess
from ._core._exceptions import BusyResourceError as BusyResourceError
from ._core._exceptions import ClosedResourceError as ClosedResourceError
from ._core._exceptions import DelimiterNotFound as DelimiterNotFound
from ._core._exceptions import EndOfStream as EndOfStream
from ._core._exceptions import IncompleteRead as IncompleteRead
from ._core._exceptions import TypedAttributeLookupError as TypedAttributeLookupError
from ._core._exceptions import WouldBlock as WouldBlock
from ._core._fileio import AsyncFile as AsyncFile
from ._core._fileio import Path as Path
from ._core._fileio import open_file as open_file
from ._core._fileio import wrap_file as wrap_file
from ._core._resources import aclose_forcefully as aclose_forcefully
from ._core._signals import open_signal_receiver as open_signal_receiver
from ._core._sockets import connect_tcp as connect_tcp
from ._core._sockets import connect_unix as connect_unix
from ._core._sockets import create_connected_udp_socket as create_connected_udp_socket
from ._core._sockets import (
connect_tcp,
connect_unix,
create_connected_udp_socket,
create_connected_unix_datagram_socket,
create_tcp_listener,
create_udp_socket,
create_unix_datagram_socket,
create_unix_listener,
getaddrinfo,
getnameinfo,
wait_socket_readable,
wait_socket_writable,
create_connected_unix_datagram_socket as create_connected_unix_datagram_socket,
)
from ._core._streams import create_memory_object_stream
from ._core._subprocesses import open_process, run_process
from ._core._sockets import create_tcp_listener as create_tcp_listener
from ._core._sockets import create_udp_socket as create_udp_socket
from ._core._sockets import create_unix_datagram_socket as create_unix_datagram_socket
from ._core._sockets import create_unix_listener as create_unix_listener
from ._core._sockets import getaddrinfo as getaddrinfo
from ._core._sockets import getnameinfo as getnameinfo
from ._core._sockets import wait_socket_readable as wait_socket_readable
from ._core._sockets import wait_socket_writable as wait_socket_writable
from ._core._streams import create_memory_object_stream as create_memory_object_stream
from ._core._subprocesses import open_process as open_process
from ._core._subprocesses import run_process as run_process
from ._core._synchronization import CapacityLimiter as CapacityLimiter
from ._core._synchronization import (
CapacityLimiter,
CapacityLimiterStatistics,
Condition,
ConditionStatistics,
Event,
EventStatistics,
Lock,
LockStatistics,
Semaphore,
SemaphoreStatistics,
)
from ._core._tasks import (
TASK_STATUS_IGNORED,
CancelScope,
create_task_group,
current_effective_deadline,
fail_after,
move_on_after,
)
from ._core._testing import (
TaskInfo,
get_current_task,
get_running_tasks,
wait_all_tasks_blocked,
CapacityLimiterStatistics as CapacityLimiterStatistics,
)
from ._core._typedattr import TypedAttributeProvider, TypedAttributeSet, typed_attribute
from ._core._synchronization import Condition as Condition
from ._core._synchronization import ConditionStatistics as ConditionStatistics
from ._core._synchronization import Event as Event
from ._core._synchronization import EventStatistics as EventStatistics
from ._core._synchronization import Lock as Lock
from ._core._synchronization import LockStatistics as LockStatistics
from ._core._synchronization import Semaphore as Semaphore
from ._core._synchronization import SemaphoreStatistics as SemaphoreStatistics
from ._core._tasks import TASK_STATUS_IGNORED as TASK_STATUS_IGNORED
from ._core._tasks import CancelScope as CancelScope
from ._core._tasks import create_task_group as create_task_group
from ._core._tasks import current_effective_deadline as current_effective_deadline
from ._core._tasks import fail_after as fail_after
from ._core._tasks import move_on_after as move_on_after
from ._core._testing import TaskInfo as TaskInfo
from ._core._testing import get_current_task as get_current_task
from ._core._testing import get_running_tasks as get_running_tasks
from ._core._testing import wait_all_tasks_blocked as wait_all_tasks_blocked
from ._core._typedattr import TypedAttributeProvider as TypedAttributeProvider
from ._core._typedattr import TypedAttributeSet as TypedAttributeSet
from ._core._typedattr import typed_attribute as typed_attribute

# Re-export imports so they look like they live directly in this package
key: str
Expand Down
22 changes: 18 additions & 4 deletions src/anyio/_backends/_asyncio.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ def __init__(self, deadline: float = math.inf, shield: bool = False):
self._tasks: set[asyncio.Task] = set()
self._host_task: asyncio.Task | None = None
self._timeout_expired = False
self._cancel_calls: int = 0

def __enter__(self) -> CancelScope:
if self._active:
Expand Down Expand Up @@ -271,16 +272,28 @@ def __exit__(
)
if all(isinstance(exc, CancelledError) for exc in exceptions):
if self._timeout_expired:
return True
return self._uncancel()
elif not self._cancel_called:
# Task was cancelled natively
return None
elif not self._parent_cancelled():
# This scope was directly cancelled
return True
return self._uncancel()

return None

def _uncancel(self) -> bool:
if sys.version_info < (3, 11) or self._host_task is None:
self._cancel_calls = 0
return True

# Uncancel all AnyIO cancellations
for i in range(self._cancel_calls):
self._host_task.uncancel()

self._cancel_calls = 0
return not self._host_task.cancelling()

def _timeout(self) -> None:
if self._deadline != math.inf:
loop = get_running_loop()
Expand Down Expand Up @@ -316,6 +329,7 @@ def _deliver_cancellation(self) -> None:
if task is not current and (
task is self._host_task or _task_started(task)
):
self._cancel_calls += 1
task.cancel()

# Schedule another callback if there are still tasks left
Expand Down Expand Up @@ -582,7 +596,7 @@ def task_done(_task: asyncio.Task) -> None:
"This task group is not active; no new tasks can be started."
)

options = {}
options: dict[str, Any] = {}
name = get_callable_name(func) if name is None else str(name)
if _native_task_names:
options["name"] = name
Expand Down Expand Up @@ -2106,7 +2120,7 @@ async def open_process(

@classmethod
def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None:
kwargs = (
kwargs: dict[str, Any] = (
{"name": "AnyIO process pool shutdown task"} if _native_task_names else {}
)
create_task(_shutdown_process_pool_on_exit(workers), **kwargs)
Expand Down
Loading

0 comments on commit 483bd3a

Please sign in to comment.