diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c321860..b792c40 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,20 +35,16 @@ jobs: strategy: matrix: python: - - '3.7' - '3.8' - '3.9' - '3.10' - '3.11' - '3.12' - - 'pypy-3.7' - 'pypy-3.8' - 'pypy-3.9-v7.3.12' - 'pypy-3.10-v7.3.12' os: ['ubuntu-latest', 'macOS-latest', 'windows-latest'] exclude: - - python: 'pypy-3.7' - os: 'windows-latest' - python: 'pypy-3.8' os: 'windows-latest' - python: 'pypy-3.9-v7.3.12' diff --git a/aiuti/asyncio.py b/aiuti/asyncio.py index 1075b43..485dac8 100644 --- a/aiuti/asyncio.py +++ b/aiuti/asyncio.py @@ -41,12 +41,12 @@ from time import sleep from typing import ( Any, AsyncIterable, Awaitable, Callable, Coroutine, Dict, - MutableMapping, Generic, Iterable, Iterator, List, Optional, Set, - Tuple, Type, TypeVar, Union, + MutableMapping, Generic, Iterable, Iterator, List, Optional, Protocol, + Set, Tuple, Type, TypeVar, Union, overload, cast, ) -from .typing import T, Yields, AYields, Protocol +from .typing import T, Yields, AYields E = TypeVar('E', bound=BaseException) X = TypeVar('X') @@ -198,10 +198,7 @@ def _queue_elements() -> None: put = partial(loop.call_soon_threadsafe, q.put_nowait) with ThreadPoolExecutor(1) as pool: future = loop.run_in_executor(pool, _queue_elements) - while True: - i = await q.get() - if i is _DONE: - break + while (i := await q.get()) is not _DONE: yield i # type: ignore await future # Bubble any errors @@ -263,11 +260,8 @@ async def _queue_elements() -> None: with ThreadPoolExecutor(1) as pool: future = pool.submit(_set_loop_and_queue_elements, loop) try: - while True: - i = q.get() - if i is _DONE: - break - yield i + while (i := q.get()) is not _DONE: + yield i # type: ignore finally: future.result() @@ -668,6 +662,7 @@ async def wait(self, *, cancel: bool = True) -> None: # Process all queued tasks # Create a task because some unknown bug on 3.7 blocks # infinitely sometimes if we await join directly + # FIXME: Evaluate if the bug is possible on 3.8+? await self.loop.create_task(self.q.join()) if cancel and self._getting and not self._getting.done(): # Cancel the current q.get to avoid waiting for timeout diff --git a/aiuti/typing.py b/aiuti/typing.py index 7eb0fd8..83e838c 100644 --- a/aiuti/typing.py +++ b/aiuti/typing.py @@ -9,55 +9,32 @@ It also fallbacks for the following common new typing features to avoid import errors on older versions of Python: - - ``Literal`` - - ``Protocol`` - - ``TypedDict`` - - ``TypeAlias`` - - ``ParamSpec`` - - ``ParamSpecArgs`` - - ``ParamSpecKwargs`` - - ``Concatenate`` + - ``TypeAlias`` (added 3.10, deprecated 3.12) + - ``ParamSpec`` (added 3.10) + - ``ParamSpecArgs`` (added 3.10) + - ``ParamSpecKwargs`` (added 3.10) + - ``Concatenate`` (added 3.10) """ __all__ = [ - 'Literal', 'Protocol', 'TypedDict', 'TypeAlias', + 'TypeAlias', 'ParamSpec', 'ParamSpecArgs', 'ParamSpecKwargs', 'Concatenate', 'MaybeIter', 'MaybeAwaitable', 'Yields', 'AYields', 'T', 'T_co', 'T_contra', 'KT', 'VT', 'KT_co', 'VT_co', 'F', ] import logging +import typing from typing import ( - Any, AsyncGenerator, Awaitable, Callable, Dict, Generator, Iterable, + Any, AsyncGenerator, Awaitable, Callable, Generator, Iterable, TypeVar, Union, ) +from warnings import warn logger = logging.getLogger(__name__) -try: - from typing import Literal, Protocol, TypedDict -except ImportError: - try: - from typing_extensions import ( # type: ignore - Literal, Protocol, TypedDict, - ) - except ImportError: - # Shim implement common back ports to avoid requiring - # typing_extensions to be installed for regular execution. - - # Note that this is not a replacement for typing_extensions which - # should be made a normal dependency of any packages that use newer - # typing features and wish to support older Python versions. - logger.info("Creating shims for common typing features." - " Please install typing_extensions to avoid this.") - Literal = type('Literal', (type,), # type: ignore - {'__class_getitem__': lambda c, i: c}) - Protocol = type('Protocol', (type,), # type: ignore - {'__class_getitem__': lambda c, i: c}) - TypedDict = type('TypedDict', (Dict,), {}) - try: from typing import ParamSpec, ParamSpecArgs, ParamSpecKwargs, Concatenate except ImportError: @@ -126,3 +103,19 @@ def _any_init(*_: Any, **__: Any) -> None: return None #: Generic type for an ``AsyncGenerator`` which only yields AYields = AsyncGenerator[T, None] + + +def __getattr__(name: str) -> Any: + if name.startswith('_'): + raise AttributeError(name) + + if (res := getattr(typing, name, None)) is not None: + warn( + f"Typing shim for {name} is no longer necessary to support" + f" modern Python versions." + f" Please import {name} from the typing module directly.", + DeprecationWarning, + ) + return res + + raise AttributeError(name) diff --git a/setup.cfg b/setup.cfg index d4ff87c..ab8353c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -10,7 +10,6 @@ classifiers = Development Status :: 3 - Alpha Intended Audience :: Developers License :: OSI Approved :: MIT License - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 @@ -25,7 +24,7 @@ keywords = asyncio [options] -python_requires = >=3.7 +python_requires = >=3.8 include_package_data = True packages = find: tests_require = @@ -76,7 +75,7 @@ exclude = _version\.py follow_imports = silent [tox:tox] -envlist = py37, py38, py39, py310, py311, py312, pypy3 +envlist = py38, py39, py310, py311, py312, pypy3 [testenv] deps = -rrequirements.txt