Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-falcon for openSUSE:Factory checked in at 2024-04-02 16:43:47 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-falcon (Old) and /work/SRC/openSUSE:Factory/.python-falcon.new.1905 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-falcon" Tue Apr 2 16:43:47 2024 rev:23 rq:1163999 version:3.1.3 Changes: -------- --- /work/SRC/openSUSE:Factory/python-falcon/python-falcon.changes 2024-03-20 21:20:27.511521233 +0100 +++ /work/SRC/openSUSE:Factory/.python-falcon.new.1905/python-falcon.changes 2024-04-02 16:46:31.989873361 +0200 @@ -1,0 +2,7 @@ +Tue Apr 2 01:45:24 UTC 2024 - Steve Kowalik <steven.kowa...@suse.com> + +- Remove skipping asgi for Python 3.9. +- Add patch support-new-uvicorn.patch: + * Support new uvicorn, which now propagates its exit code. + +------------------------------------------------------------------- New: ---- support-new-uvicorn.patch BETA DEBUG BEGIN: New:- Remove skipping asgi for Python 3.9. - Add patch support-new-uvicorn.patch: * Support new uvicorn, which now propagates its exit code. BETA DEBUG END: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-falcon.spec ++++++ --- /var/tmp/diff_new_pack.PqT0tl/_old 2024-04-02 16:46:32.961906258 +0200 +++ /var/tmp/diff_new_pack.PqT0tl/_new 2024-04-02 16:46:32.961906258 +0200 @@ -22,11 +22,12 @@ Release: 0 Summary: A web framework for building APIs and app backends License: Apache-2.0 -Group: Development/Languages/Python URL: http://falconframework.org Source: https://files.pythonhosted.org/packages/source/f/falcon/falcon-%{version}.tar.gz # github pygments style is not available Patch0: python-falcon-sphinx-pygments-style.patch +# PATCH-FIX-UPSTREAM Based on gh#falconry/falcon#2216 +Patch1: support-new-uvicorn.patch BuildRequires: %{python_module PyYAML} BuildRequires: %{python_module Sphinx} BuildRequires: %{python_module ddt} @@ -63,7 +64,6 @@ %package -n %{name}-doc Summary: Documentation files for %{name} -Group: Documentation/HTML Provides: %{python_module falcon-doc = %{version}} %description @@ -103,13 +103,7 @@ %check export LANG=en_US.UTF8 -%{python_expand # -if [ %{$python_version_nodots} -lt 310 ]; then - $python_donttest=("--ignore" "tests/asgi") -fi -} - -%pytest "${$python_donttest[@]}" tests +%pytest tests %post %{python_install_alternative falcon-bench falcon-inspect-app falcon-print-routes} ++++++ support-new-uvicorn.patch ++++++ >From 13da50949751de6683b57221c2ab5f1fdce8eb50 Mon Sep 17 00:00:00 2001 From: Vytautas Liuolia <vytautas.liuo...@gmail.com> Date: Wed, 13 Mar 2024 16:31:00 +0100 Subject: [PATCH 1/7] chore(asyncio): replace `get_event_loop()` -> `get_running_loop()` where applicable --- tests/asgi/test_scope.py | 6 +++--- tests/dump_asgi.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) Index: falcon-3.1.3/tests/asgi/test_scope.py =================================================================== --- falcon-3.1.3.orig/tests/asgi/test_scope.py +++ falcon-3.1.3/tests/asgi/test_scope.py @@ -70,7 +70,7 @@ def test_supported_asgi_version(version, resp_event_collector = testing.ASGIResponseEventCollector() async def task(): - coro = asyncio.get_event_loop().create_task( + coro = asyncio.get_running_loop().create_task( app(scope, req_event_emitter, resp_event_collector) ) @@ -142,7 +142,7 @@ def test_lifespan_scope_default_version( scope = {'type': 'lifespan'} async def t(): - t = asyncio.get_event_loop().create_task( + t = asyncio.get_running_loop().create_task( app(scope, req_event_emitter, resp_event_collector) ) @@ -196,7 +196,7 @@ def test_lifespan_scope_version(spec_ver return async def t(): - t = asyncio.get_event_loop().create_task( + t = asyncio.get_running_loop().create_task( app(scope, req_event_emitter, resp_event_collector) ) Index: falcon-3.1.3/tests/dump_asgi.py =================================================================== --- falcon-3.1.3.orig/tests/dump_asgi.py +++ falcon-3.1.3/tests/dump_asgi.py @@ -23,5 +23,5 @@ async def app(scope, receive, send): } ) - loop = asyncio.get_event_loop() + loop = asyncio.get_running_loop() loop.create_task(_say_hi()) Index: falcon-3.1.3/falcon/util/sync.py =================================================================== --- falcon-3.1.3.orig/falcon/util/sync.py +++ falcon-3.1.3/falcon/util/sync.py @@ -4,7 +4,9 @@ from functools import partial from functools import wraps import inspect import os +from typing import Awaitable from typing import Callable +from typing import TypeVar __all__ = [ @@ -18,6 +20,42 @@ __all__ = [ ] +Result = TypeVar('Result') + + +class _DummyRunner: + def run(self, coro: Awaitable[Result]) -> Result: # pragma: nocover + # NOTE(vytas): Work around get_event_loop deprecation in 3.10 by going + # via get_event_loop_policy(). This should be equivalent for + # async_to_sync's use case as it is currently impossible to invoke + # run_until_complete() from a running loop anyway. + return self.get_loop().run_until_complete(coro) + + def get_loop(self) -> asyncio.AbstractEventLoop: # pragma: nocover + return asyncio.get_event_loop_policy().get_event_loop() + + def close(self) -> None: # pragma: nocover + pass + + +class _ActiveRunner: + def __init__(self, runner_cls: type): + self._runner_cls = runner_cls + self._runner = runner_cls() + + # TODO(vytas): This typing is wrong on py311+, but mypy accepts it. + # It doesn't, OTOH, accept any of my ostensibly valid attempts to + # describe it. + def __call__(self) -> _DummyRunner: + # NOTE(vytas): Sometimes our runner's loop can get picked and consumed + # by other utilities and test methods. If that happens, recreate the runner. + if self._runner.get_loop().is_closed(): + # NOTE(vytas): This condition is never hit on _DummyRunner. + self._runner = self._runner_cls() # pragma: nocover + return self._runner + + +_active_runner = _ActiveRunner(getattr(asyncio, 'Runner', _DummyRunner)) _one_thread_to_rule_them_all = ThreadPoolExecutor(max_workers=1) @@ -207,8 +245,13 @@ def async_to_sync(coroutine, *args, **kw one will be created. Warning: - This method is very inefficient and is intended primarily for testing - and prototyping. + Executing async code in this manner is inefficient since it involves + synchronization via threading primitives, and is intended primarily for + testing, prototyping or compatibility purposes. + + Note: + On Python 3.11+, this function leverages a module-wide + ``asyncio.Runner``. Args: coroutine: A coroutine function to invoke. @@ -217,17 +260,7 @@ def async_to_sync(coroutine, *args, **kw Keyword Args: **kwargs: Additional args are passed through to the coroutine function. """ - - # TODO(vytas): The canonical way of doing this for simple use cases is - # asyncio.run(), but that would be a breaking change wrt the above - # documented behaviour; breaking enough to break some of our own tests. - - # NOTE(vytas): Work around get_event_loop deprecation in 3.10 by going via - # get_event_loop_policy(). This should be equivalent for async_to_sync's - # use case as it is currently impossible to invoke run_until_complete() - # from a running loop anyway. - loop = asyncio.get_event_loop_policy().get_event_loop() - return loop.run_until_complete(coroutine(*args, **kwargs)) + return _active_runner().run(coroutine(*args, **kwargs)) def runs_sync(coroutine): Index: falcon-3.1.3/pyproject.toml =================================================================== --- falcon-3.1.3.orig/pyproject.toml +++ falcon-3.1.3/pyproject.toml @@ -63,7 +63,6 @@ filterwarnings = [ "ignore:.cgi. is deprecated and slated for removal:DeprecationWarning", "ignore:path is deprecated\\. Use files\\(\\) instead:DeprecationWarning", "ignore:This process \\(.+\\) is multi-threaded", - "ignore:There is no current event loop", ] testpaths = [ "tests" Index: falcon-3.1.3/tests/asgi/test_asgi_servers.py =================================================================== --- falcon-3.1.3.orig/tests/asgi/test_asgi_servers.py +++ falcon-3.1.3/tests/asgi/test_asgi_servers.py @@ -4,6 +4,7 @@ import hashlib import os import platform import random +import signal import subprocess import sys import time @@ -27,7 +28,9 @@ _WIN32 = sys.platform.startswith('win') _SERVER_HOST = '127.0.0.1' _SIZE_1_KB = 1024 _SIZE_1_MB = _SIZE_1_KB**2 - +# NOTE(vytas): Windows specific: {Application Exit by CTRL+C}. +# The application terminated as a result of a CTRL+C. +_STATUS_CONTROL_C_EXIT = 0xC000013A _REQUEST_TIMEOUT = 10 @@ -610,7 +613,10 @@ def server_base_url(request): yield base_url - assert server.returncode == 0 + # NOTE(vytas): Starting with 0.29.0, Uvicorn will propagate signal + # values into the return code (which is a good practice in Unix); + # see also https://github.com/encode/uvicorn/pull/1600 + assert server.returncode in (0, -signal.SIGTERM, _STATUS_CONTROL_C_EXIT) break