Voice et bot modif

This commit is contained in:
pi 2026-06-16 17:09:34 +00:00
parent 189d56026b
commit 7333a22bcd
10774 changed files with 634644 additions and 933308 deletions

View file

@ -53,7 +53,7 @@ from typing import (
IO,
TYPE_CHECKING,
Any,
Optional,
ParamSpec,
TypeVar,
cast,
)
@ -78,7 +78,6 @@ from .._core._exceptions import (
EndOfStream,
RunFinishedError,
WouldBlock,
iterate_exceptions,
)
from .._core._sockets import convert_ipv6_sockaddr
from .._core._streams import create_memory_object_stream
@ -109,11 +108,6 @@ if TYPE_CHECKING:
else:
FileDescriptorLike = object
if sys.version_info >= (3, 10):
from typing import ParamSpec
else:
from typing_extensions import ParamSpec
if sys.version_info >= (3, 11):
from asyncio import Runner
from typing import TypeVarTuple, Unpack
@ -498,17 +492,39 @@ class CancelScope(BaseCancelScope):
self._pending_uncancellations -= 1
# Update cancelled_caught and check for exceptions we must not swallow
cannot_swallow_exc_val = False
if exc_val is not None:
for exc in iterate_exceptions(exc_val):
if isinstance(exc, CancelledError) and is_anyio_cancellation(
exc
):
self._cancelled_caught = True
else:
cannot_swallow_exc_val = True
if isinstance(exc_val, BaseExceptionGroup):
cancelleds_caught, remaining = exc_val.split(
lambda exc: (
isinstance(exc, CancelledError)
and is_anyio_cancellation(exc)
)
)
return self._cancelled_caught and not cannot_swallow_exc_val
if cancelleds_caught is None:
return False
self._cancelled_caught = True
if remaining is None:
return True
context = remaining.__context__
try:
# Preserve __cause__ and __suppress_context__ by avoiding `raise
# ... from ...`
raise remaining
finally:
# Preserve __context__
remaining.__context__ = context
del context
else:
if isinstance(exc_val, CancelledError) and is_anyio_cancellation(
exc_val
):
self._cancelled_caught = True
return True
else:
return False
else:
if self._pending_uncancellations:
assert self._parent_scope is not None
@ -928,7 +944,7 @@ class TaskGroup(abc.TaskGroup):
# Threads
#
_Retval_Queue_Type = tuple[Optional[T_Retval], Optional[BaseException]]
_Retval_Queue_Type = tuple[T_Retval | None, BaseException | None]
class WorkerThread(Thread):
@ -1139,7 +1155,7 @@ def _forcibly_shutdown_process_pool_on_exit(
# Close as much as possible (w/o async/await) to avoid warnings
for process in workers.copy():
if process.returncode is None:
if process.returncode is not None:
continue
process._stdin._stream._transport.close() # type: ignore[union-attr]
@ -1192,8 +1208,7 @@ class StreamProtocol(asyncio.Protocol):
def connection_lost(self, exc: Exception | None) -> None:
if exc:
self.exception = BrokenResourceError()
self.exception.__cause__ = exc
self.exception = exc
self.read_event.set()
self.write_event.set()
@ -1277,7 +1292,7 @@ class SocketStream(abc.SocketStream):
if self._closed:
raise ClosedResourceError from None
elif self._protocol.exception:
raise self._protocol.exception from None
raise BrokenResourceError from self._protocol.exception
else:
raise EndOfStream from None
@ -1300,7 +1315,7 @@ class SocketStream(abc.SocketStream):
if self._closed:
raise ClosedResourceError
elif self._protocol.exception is not None:
raise self._protocol.exception
raise BrokenResourceError from self._protocol.exception
try:
self._transport.write(item)
@ -2243,6 +2258,7 @@ class TestRunner(abc.TestRunner):
async def _call_in_runner_task(
self,
func: Callable[P, Awaitable[T_Retval]],
/,
*args: P.args,
**kwargs: P.kwargs,
) -> T_Retval:

View file

@ -30,6 +30,7 @@ from typing import (
Any,
Generic,
NoReturn,
ParamSpec,
TypeVar,
cast,
overload,
@ -84,11 +85,6 @@ from ..streams.memory import MemoryObjectSendStream
if TYPE_CHECKING:
from _typeshed import FileDescriptorLike
if sys.version_info >= (3, 10):
from typing import ParamSpec
else:
from typing_extensions import ParamSpec
if sys.version_info >= (3, 11):
from typing import TypeVarTuple, Unpack
else:
@ -887,6 +883,7 @@ class TestRunner(abc.TestRunner):
def _call_in_runner_task(
self,
func: Callable[P, Awaitable[T_Retval]],
/,
*args: P.args,
**kwargs: P.kwargs,
) -> T_Retval:

View file

@ -301,6 +301,11 @@ class Path:
def __fspath__(self) -> str:
return self._path.__fspath__()
if sys.version_info >= (3, 15):
def __vfspath__(self) -> str:
return self._path.__vfspath__()
def __str__(self) -> str:
return self._path.__str__()
@ -561,8 +566,10 @@ class Path:
os.path.ismount, self._path, abandon_on_cancel=True
)
def is_reserved(self) -> bool:
return self._path.is_reserved()
if sys.version_info < (3, 15):
def is_reserved(self) -> bool:
return self._path.is_reserved()
async def is_socket(self) -> bool:
return await to_thread.run_sync(self._path.is_socket, abandon_on_cancel=True)
@ -784,14 +791,9 @@ class Path:
errors: str | None = None,
newline: str | None = None,
) -> int:
# Path.write_text() does not support the "newline" parameter before Python 3.10
def sync_write_text() -> int:
with self._path.open(
"w", encoding=encoding, errors=errors, newline=newline
) as fp:
return fp.write(data)
return await to_thread.run_sync(sync_write_text)
return await to_thread.run_sync(
self._path.write_text, data, encoding, errors, newline
)
PathLike.register(Path)

View file

@ -1,22 +1,16 @@
from __future__ import annotations
import sys
from collections.abc import AsyncIterable, Iterable, Mapping, Sequence
from io import BytesIO
from os import PathLike
from subprocess import PIPE, CalledProcessError, CompletedProcess
from typing import IO, Any, Union, cast
from typing import IO, Any, TypeAlias, cast
from ..abc import Process
from ._eventloop import get_async_backend
from ._tasks import create_task_group
if sys.version_info >= (3, 10):
from typing import TypeAlias
else:
from typing_extensions import TypeAlias
StrOrBytesPath: TypeAlias = Union[str, bytes, "PathLike[str]", "PathLike[bytes]"]
StrOrBytesPath: TypeAlias = str | bytes | PathLike[str] | PathLike[bytes]
async def run_process(

View file

@ -335,6 +335,10 @@ class Condition:
except BaseException:
if not event.is_set():
self._waiters.remove(event)
elif self._waiters:
# This task was notified by could not act on it, so pass
# it on to the next task
self._waiters.popleft().set()
raise
finally:

View file

@ -463,7 +463,6 @@ class TemporaryDirectory(Generic[AnyStr]):
:param prefix: Prefix to be added to the temporary directory name.
:param dir: The parent directory where the temporary directory is created.
:param ignore_cleanup_errors: Whether to ignore errors during cleanup
(Python 3.10+).
:param delete: Whether to delete the directory upon closing (Python 3.12+).
"""
@ -489,10 +488,8 @@ class TemporaryDirectory(Generic[AnyStr]):
"suffix": self.suffix,
"prefix": self.prefix,
"dir": self.dir,
"ignore_cleanup_errors": self.ignore_cleanup_errors,
}
if sys.version_info >= (3, 10):
params["ignore_cleanup_errors"] = self.ignore_cleanup_errors
if sys.version_info >= (3, 12):
params["delete"] = self.delete

View file

@ -12,8 +12,8 @@ from typing import (
IO,
TYPE_CHECKING,
Any,
TypeAlias,
TypeVar,
Union,
overload,
)
@ -22,11 +22,6 @@ if sys.version_info >= (3, 11):
else:
from typing_extensions import TypeVarTuple, Unpack
if sys.version_info >= (3, 10):
from typing import TypeAlias
else:
from typing_extensions import TypeAlias
if TYPE_CHECKING:
from _typeshed import FileDescriptorLike
@ -49,7 +44,7 @@ if TYPE_CHECKING:
T_Retval = TypeVar("T_Retval")
PosArgsT = TypeVarTuple("PosArgsT")
StrOrBytesPath: TypeAlias = Union[str, bytes, "PathLike[str]", "PathLike[bytes]"]
StrOrBytesPath: TypeAlias = str | bytes | PathLike[str] | PathLike[bytes]
class AsyncBackend(metaclass=ABCMeta):

View file

@ -2,14 +2,13 @@ from __future__ import annotations
import errno
import socket
import sys
from abc import abstractmethod
from collections.abc import Callable, Collection, Mapping
from contextlib import AsyncExitStack
from io import IOBase
from ipaddress import IPv4Address, IPv6Address
from socket import AddressFamily
from typing import Any, TypeVar, Union
from typing import Any, TypeAlias, TypeVar
from .._core._eventloop import get_async_backend
from .._core._typedattr import (
@ -20,14 +19,9 @@ from .._core._typedattr import (
from ._streams import ByteStream, Listener, UnreliableObjectStream
from ._tasks import TaskGroup
if sys.version_info >= (3, 10):
from typing import TypeAlias
else:
from typing_extensions import TypeAlias
IPAddressType: TypeAlias = Union[str, IPv4Address, IPv6Address]
IPAddressType: TypeAlias = str | IPv4Address | IPv6Address
IPSockAddrType: TypeAlias = tuple[str, int]
SockAddrType: TypeAlias = Union[IPSockAddrType, str]
SockAddrType: TypeAlias = IPSockAddrType | str
UDPPacketType: TypeAlias = tuple[bytes, IPSockAddrType]
UNIXDatagramPacketType: TypeAlias = tuple[bytes, str]
T_Retval = TypeVar("T_Retval")
@ -166,8 +160,8 @@ class _SocketProvider(TypedAttributeProvider):
# Provide local and remote ports for IP based sockets
if self._raw_socket.family in (AddressFamily.AF_INET, AddressFamily.AF_INET6):
attributes[SocketAttribute.local_port] = (
lambda: self._raw_socket.getsockname()[1]
attributes[SocketAttribute.local_port] = lambda: (
self._raw_socket.getsockname()[1]
)
if peername is not None:
remote_port = peername[1]

View file

@ -1,20 +1,14 @@
from __future__ import annotations
import sys
from abc import ABCMeta, abstractmethod
from collections.abc import Callable
from typing import Any, Generic, TypeVar, Union
from typing import Any, Generic, TypeAlias, TypeVar
from .._core._exceptions import EndOfStream
from .._core._typedattr import TypedAttributeProvider
from ._resources import AsyncResource
from ._tasks import TaskGroup
if sys.version_info >= (3, 10):
from typing import TypeAlias
else:
from typing_extensions import TypeAlias
T_Item = TypeVar("T_Item")
T_co = TypeVar("T_co", covariant=True)
T_contra = TypeVar("T_contra", contravariant=True)
@ -178,21 +172,21 @@ class ByteStream(ByteReceiveStream, ByteSendStream):
#: Type alias for all unreliable bytes-oriented receive streams.
AnyUnreliableByteReceiveStream: TypeAlias = Union[
UnreliableObjectReceiveStream[bytes], ByteReceiveStream
]
AnyUnreliableByteReceiveStream: TypeAlias = (
UnreliableObjectReceiveStream[bytes] | ByteReceiveStream
)
#: Type alias for all unreliable bytes-oriented send streams.
AnyUnreliableByteSendStream: TypeAlias = Union[
UnreliableObjectSendStream[bytes], ByteSendStream
]
AnyUnreliableByteSendStream: TypeAlias = (
UnreliableObjectSendStream[bytes] | ByteSendStream
)
#: Type alias for all unreliable bytes-oriented streams.
AnyUnreliableByteStream: TypeAlias = Union[UnreliableObjectStream[bytes], ByteStream]
AnyUnreliableByteStream: TypeAlias = UnreliableObjectStream[bytes] | ByteStream
#: Type alias for all bytes-oriented receive streams.
AnyByteReceiveStream: TypeAlias = Union[ObjectReceiveStream[bytes], ByteReceiveStream]
AnyByteReceiveStream: TypeAlias = ObjectReceiveStream[bytes] | ByteReceiveStream
#: Type alias for all bytes-oriented send streams.
AnyByteSendStream: TypeAlias = Union[ObjectSendStream[bytes], ByteSendStream]
AnyByteSendStream: TypeAlias = ObjectSendStream[bytes] | ByteSendStream
#: Type alias for all bytes-oriented streams.
AnyByteStream: TypeAlias = Union[ObjectStream[bytes], ByteStream]
AnyByteStream: TypeAlias = ObjectStream[bytes] | ByteStream
class Listener(Generic[T_co], AsyncResource, TypedAttributeProvider):
@ -234,6 +228,6 @@ class ByteStreamConnectable(metaclass=ABCMeta):
#: Type alias for all connectables returning bytestreams or bytes-oriented object streams
AnyByteStreamConnectable: TypeAlias = Union[
ObjectStreamConnectable[bytes], ByteStreamConnectable
]
AnyByteStreamConnectable: TypeAlias = (
ObjectStreamConnectable[bytes] | ByteStreamConnectable
)

View file

@ -34,6 +34,7 @@ from typing import (
)
from weakref import WeakKeyDictionary
from ._core._eventloop import current_time
from ._core._synchronization import Lock
from .lowlevel import RunVar, checkpoint
@ -48,7 +49,11 @@ P = ParamSpec("P")
lru_cache_items: RunVar[
WeakKeyDictionary[
AsyncLRUCacheWrapper[Any, Any],
OrderedDict[Hashable, tuple[_InitialMissingType, Lock] | tuple[Any, None]],
OrderedDict[
Hashable,
tuple[_InitialMissingType, Lock, float | None]
| tuple[Any, None, float | None],
],
]
] = RunVar("lru_cache_items")
@ -65,12 +70,14 @@ class AsyncCacheInfo(NamedTuple):
misses: int
maxsize: int | None
currsize: int
ttl: int | None
class AsyncCacheParameters(TypedDict):
maxsize: int | None
typed: bool
always_checkpoint: bool
ttl: int | None
class _LRUMethodWrapper(Generic[T]):
@ -102,6 +109,7 @@ class AsyncLRUCacheWrapper(Generic[P, T]):
maxsize: int | None,
typed: bool,
always_checkpoint: bool,
ttl: int | None,
):
self.__wrapped__ = func
self._hits: int = 0
@ -110,16 +118,20 @@ class AsyncLRUCacheWrapper(Generic[P, T]):
self._currsize: int = 0
self._typed = typed
self._always_checkpoint = always_checkpoint
self._ttl = ttl
update_wrapper(self, func)
def cache_info(self) -> AsyncCacheInfo:
return AsyncCacheInfo(self._hits, self._misses, self._maxsize, self._currsize)
return AsyncCacheInfo(
self._hits, self._misses, self._maxsize, self._currsize, self._ttl
)
def cache_parameters(self) -> AsyncCacheParameters:
return {
"maxsize": self._maxsize,
"typed": self._typed,
"always_checkpoint": self._always_checkpoint,
"ttl": self._ttl,
}
def cache_clear(self) -> None:
@ -158,23 +170,33 @@ class AsyncLRUCacheWrapper(Generic[P, T]):
cached_value: T | _InitialMissingType
try:
cached_value, lock = cache_entry[key]
cached_value, lock, expires_at = cache_entry[key]
except KeyError:
# We're the first task to call this function
cached_value, lock = (
cached_value, lock, expires_at = (
initial_missing,
Lock(fast_acquire=not self._always_checkpoint),
None,
)
cache_entry[key] = cached_value, lock
cache_entry[key] = cached_value, lock, expires_at
if lock is None:
# The value was already cached
self._hits += 1
cache_entry.move_to_end(key)
if self._always_checkpoint:
await checkpoint()
if expires_at is not None and current_time() >= expires_at:
self._currsize -= 1
cached_value, lock, expires_at = (
initial_missing,
Lock(fast_acquire=not self._always_checkpoint),
None,
)
cache_entry[key] = cached_value, lock, expires_at
else:
# The value was already cached
self._hits += 1
cache_entry.move_to_end(key)
if self._always_checkpoint:
await checkpoint()
return cast(T, cached_value)
return cast(T, cached_value)
async with lock:
# Check if another task filled the cache while we acquired the lock
@ -186,7 +208,10 @@ class AsyncLRUCacheWrapper(Generic[P, T]):
self._currsize += 1
value = await self.__wrapped__(*args, **kwargs)
cache_entry[key] = value, None
expires_at = (
current_time() + self._ttl if self._ttl is not None else None
)
cache_entry[key] = value, None, expires_at
else:
# Another task filled the cache while we were waiting for the lock
self._hits += 1
@ -204,10 +229,13 @@ class AsyncLRUCacheWrapper(Generic[P, T]):
class _LRUCacheWrapper(Generic[T]):
def __init__(self, maxsize: int | None, typed: bool, always_checkpoint: bool):
def __init__(
self, maxsize: int | None, typed: bool, always_checkpoint: bool, ttl: int | None
):
self._maxsize = maxsize
self._typed = typed
self._always_checkpoint = always_checkpoint
self._ttl = ttl
@overload
def __call__( # type: ignore[overload-overlap]
@ -224,7 +252,7 @@ class _LRUCacheWrapper(Generic[T]):
) -> AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T]:
if iscoroutinefunction(f):
return AsyncLRUCacheWrapper(
f, self._maxsize, self._typed, self._always_checkpoint
f, self._maxsize, self._typed, self._always_checkpoint, self._ttl
)
return functools.lru_cache(maxsize=self._maxsize, typed=self._typed)(f) # type: ignore[arg-type]
@ -254,7 +282,11 @@ def cache(
@overload
def lru_cache(
*, maxsize: int | None = ..., typed: bool = ..., always_checkpoint: bool = ...
*,
maxsize: int | None = ...,
typed: bool = ...,
always_checkpoint: bool = ...,
ttl: int | None = ...,
) -> _LRUCacheWrapper[Any]: ...
@ -275,6 +307,7 @@ def lru_cache(
maxsize: int | None = 128,
typed: bool = False,
always_checkpoint: bool = False,
ttl: int | None = None,
) -> (
AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T] | _LRUCacheWrapper[Any]
):
@ -286,17 +319,18 @@ def lru_cache(
:param always_checkpoint: if ``True``, every call to the cached function will be
guaranteed to yield control to the event loop at least once
:param ttl: time in seconds after which to invalidate cache entries
.. note:: Caches and locks are managed on a per-event loop basis.
"""
if func is None:
return _LRUCacheWrapper[Any](maxsize, typed, always_checkpoint)
return _LRUCacheWrapper[Any](maxsize, typed, always_checkpoint, ttl)
if not callable(func):
raise TypeError("the first argument must be callable")
return _LRUCacheWrapper[T](maxsize, typed, always_checkpoint)(func)
return _LRUCacheWrapper[T](maxsize, typed, always_checkpoint, ttl)(func)
@overload

View file

@ -1,5 +1,6 @@
from __future__ import annotations
import dataclasses
import socket
import sys
from collections.abc import Callable, Generator, Iterator
@ -8,8 +9,10 @@ from inspect import isasyncgenfunction, iscoroutinefunction, ismethod
from typing import Any, cast
import pytest
from _pytest.fixtures import SubRequest
from _pytest.fixtures import FuncFixtureInfo, SubRequest
from _pytest.outcomes import Exit
from _pytest.python import CallSpec2
from _pytest.scope import Scope
from . import get_available_backends
from ._core._eventloop import (
@ -163,6 +166,64 @@ def pytest_pycollect_makeitem(
pytest.mark.usefixtures("anyio_backend")(obj)
def pytest_collection_finish(session: pytest.Session) -> None:
for i, item in reversed(list(enumerate(session.items))):
if (
isinstance(item, pytest.Function)
and iscoroutinefunction(item.function)
and item.get_closest_marker("anyio") is not None
and "anyio_backend" not in item.fixturenames
):
new_items = []
try:
cs_fields = {f.name for f in dataclasses.fields(CallSpec2)}
except TypeError:
cs_fields = set()
for param_index, backend in enumerate(get_available_backends()):
if "_arg2scope" in cs_fields: # pytest >= 8
callspec = CallSpec2(
params={"anyio_backend": backend},
indices={"anyio_backend": param_index},
_arg2scope={"anyio_backend": Scope.Module},
_idlist=[backend],
marks=[],
)
else: # pytest 7.x
callspec = CallSpec2( # type: ignore[call-arg]
funcargs={},
params={"anyio_backend": backend},
indices={"anyio_backend": param_index},
arg2scope={"anyio_backend": Scope.Module},
idlist=[backend],
marks=[],
)
fi = item._fixtureinfo
new_names_closure = list(fi.names_closure)
if "anyio_backend" not in new_names_closure:
new_names_closure.append("anyio_backend")
new_fixtureinfo = FuncFixtureInfo(
argnames=fi.argnames,
initialnames=fi.initialnames,
names_closure=new_names_closure,
name2fixturedefs=fi.name2fixturedefs,
)
new_item = pytest.Function.from_parent(
item.parent,
name=f"{item.originalname}[{backend}]",
callspec=callspec,
callobj=item.obj,
fixtureinfo=new_fixtureinfo,
keywords=item.keywords,
originalname=item.originalname,
)
new_items.append(new_item)
session.items[i : i + 1] = new_items
@pytest.hookimpl(tryfirst=True)
def pytest_pyfunc_call(pyfuncitem: Any) -> bool | None:
def run_with_hypothesis(**kwargs: Any) -> None:

View file

@ -10,7 +10,7 @@ from collections.abc import Callable, Mapping
from io import SEEK_SET, UnsupportedOperation
from os import PathLike
from pathlib import Path
from typing import Any, BinaryIO, cast
from typing import IO, Any
from .. import (
BrokenResourceError,
@ -25,7 +25,7 @@ from ..abc import ByteReceiveStream, ByteSendStream
class FileStreamAttribute(TypedAttributeSet):
#: the open file descriptor
file: BinaryIO = typed_attribute()
file: IO[bytes] = typed_attribute()
#: the path of the file on the file system, if available (file must be a real file)
path: Path = typed_attribute()
#: the file number, if available (file must be a real file or a TTY)
@ -33,7 +33,7 @@ class FileStreamAttribute(TypedAttributeSet):
class _BaseFileStream:
def __init__(self, file: BinaryIO):
def __init__(self, file: IO[bytes]):
self._file = file
async def aclose(self) -> None:
@ -76,7 +76,7 @@ class FileReadStream(_BaseFileStream, ByteReceiveStream):
"""
file = await to_thread.run_sync(Path(path).open, "rb")
return cls(cast(BinaryIO, file))
return cls(file)
async def receive(self, max_bytes: int = 65536) -> bytes:
try:
@ -143,7 +143,7 @@ class FileWriteStream(_BaseFileStream, ByteSendStream):
"""
mode = "ab" if append else "wb"
file = await to_thread.run_sync(Path(path).open, mode)
return cls(cast(BinaryIO, file))
return cls(file)
async def send(self, item: bytes) -> None:
try:

View file

@ -15,7 +15,7 @@ from collections.abc import Callable, Mapping
from dataclasses import dataclass
from functools import wraps
from ssl import SSLContext
from typing import Any, TypeVar
from typing import Any, TypeAlias, TypeVar
from .. import (
BrokenResourceError,
@ -34,11 +34,6 @@ from ..abc import (
TaskGroup,
)
if sys.version_info >= (3, 10):
from typing import TypeAlias
else:
from typing_extensions import TypeAlias
if sys.version_info >= (3, 11):
from typing import TypeVarTuple, Unpack
else:
@ -279,9 +274,11 @@ class TLSStream(ByteStream):
True
),
TLSAttribute.server_side: lambda: self._ssl_object.server_side,
TLSAttribute.shared_ciphers: lambda: self._ssl_object.shared_ciphers()
if self._ssl_object.server_side
else None,
TLSAttribute.shared_ciphers: lambda: (
self._ssl_object.shared_ciphers()
if self._ssl_object.server_side
else None
),
TLSAttribute.standard_compatible: lambda: self.standard_compatible,
TLSAttribute.ssl_object: lambda: self._ssl_object,
TLSAttribute.tls_version: self._ssl_object.version,

View file

@ -32,9 +32,9 @@ async def run_sync(
"""
Call the given function with the given arguments in a worker thread.
If the ``cancellable`` option is enabled and the task waiting for its completion is
cancelled, the thread will still run its course but its return value (or any raised
exception) will be ignored.
If the ``abandon_on_cancel`` option is enabled and the task waiting for its
completion is cancelled, the thread will still run its course but its
return value (or any raised exception) will be ignored.
:param func: a callable
:param args: positional arguments for the callable