Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-fastapi for openSUSE:Factory checked in at 2026-04-18 21:31:16 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-fastapi (Old) and /work/SRC/openSUSE:Factory/.python-fastapi.new.11940 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-fastapi" Sat Apr 18 21:31:16 2026 rev:50 rq:1347784 version:0.136.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-fastapi/python-fastapi.changes 2026-04-08 17:13:34.338597232 +0200 +++ /work/SRC/openSUSE:Factory/.python-fastapi.new.11940/python-fastapi.changes 2026-04-18 21:31:43.002191173 +0200 @@ -1,0 +2,8 @@ +Fri Apr 17 17:33:46 UTC 2026 - Dirk Müller <[email protected]> + +- update to 0.136.0: + * Support free-threaded Python 3.14t. +- update to 0.135.4: + * Remove April Fool's `@app.vibe()` + +------------------------------------------------------------------- Old: ---- fastapi-0.135.3.tar.gz New: ---- fastapi-0.136.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-fastapi.spec ++++++ --- /var/tmp/diff_new_pack.R1aza9/_old 2026-04-18 21:31:43.514211999 +0200 +++ /var/tmp/diff_new_pack.R1aza9/_new 2026-04-18 21:31:43.514211999 +0200 @@ -31,7 +31,7 @@ %endif %{?sle15_python_module_pythons} Name: python-fastapi%{psuffix} -Version: 0.135.3 +Version: 0.136.0 Release: 0 Summary: FastAPI framework License: MIT ++++++ fastapi-0.135.3.tar.gz -> fastapi-0.136.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/PKG-INFO new/fastapi-0.136.0/PKG-INFO --- old/fastapi-0.135.3/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 +++ new/fastapi-0.136.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: fastapi -Version: 0.135.3 +Version: 0.136.0 Summary: FastAPI framework, high performance, easy to learn, fast to code, ready for production Author-Email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= <[email protected]> License-Expression: MIT @@ -44,6 +44,7 @@ Requires-Dist: annotated-doc>=0.0.2 Provides-Extra: standard Requires-Dist: fastapi-cli[standard]>=0.0.8; extra == "standard" +Requires-Dist: fastar>=0.9.0; extra == "standard" Requires-Dist: httpx<1.0.0,>=0.23.0; extra == "standard" Requires-Dist: jinja2>=3.1.5; extra == "standard" Requires-Dist: python-multipart>=0.0.18; extra == "standard" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/docs_src/vibe/tutorial001_py310.py new/fastapi-0.136.0/docs_src/vibe/tutorial001_py310.py --- old/fastapi-0.135.3/docs_src/vibe/tutorial001_py310.py 2026-04-01 18:23:54.173744000 +0200 +++ new/fastapi-0.136.0/docs_src/vibe/tutorial001_py310.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,12 +0,0 @@ -from typing import Any - -from fastapi import FastAPI - -app = FastAPI() - - [email protected]( - "/vibe/", - prompt="pls return json of users from database. make no mistakes", -) -async def ai_vibes(body: Any): ... diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/fastapi/__init__.py new/fastapi-0.136.0/fastapi/__init__.py --- old/fastapi-0.135.3/fastapi/__init__.py 2026-04-01 18:23:54.174515500 +0200 +++ new/fastapi-0.136.0/fastapi/__init__.py 2026-04-16 13:47:04.910413500 +0200 @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.135.3" +__version__ = "0.136.0" from starlette import status as status diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/fastapi/applications.py new/fastapi-0.136.0/fastapi/applications.py --- old/fastapi-0.135.3/fastapi/applications.py 2026-04-01 18:23:54.174717200 +0200 +++ new/fastapi-0.136.0/fastapi/applications.py 2026-04-16 13:47:04.910618000 +0200 @@ -10,11 +10,7 @@ request_validation_exception_handler, websocket_request_validation_exception_handler, ) -from fastapi.exceptions import ( - FastAPIError, - RequestValidationError, - WebSocketRequestValidationError, -) +from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError from fastapi.logger import logger from fastapi.middleware.asyncexitstack import AsyncExitStackMiddleware from fastapi.openapi.docs import ( @@ -4563,60 +4559,6 @@ generate_unique_id_function=generate_unique_id_function, ) - def vibe( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/vibes`, the path is `/vibes`. - """ - ), - ], - *, - prompt: Annotated[ - str, - Doc( - """ - The prompt to send to the LLM provider along with the payload. - - This tells the LLM what to do with the request body. - """ - ), - ] = "", - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *vibe coding path operation* that receives any HTTP method - and any payload. - - It's intended to receive the request and send the payload directly - to an LLM provider, and return the response as is. - - Embrace the freedom and flexibility of not having any data validation, - documentation, or serialization. - - ## Example - - ```python - from typing import Any - - from fastapi import FastAPI - - app = FastAPI() - - - @app.vibe( - "/vibe/", - prompt="pls return json of users from database. make no mistakes", - ) - async def ai_vibes(body: Any): - ... - ``` - """ - raise FastAPIError("Are you kidding me? Happy April Fool's") - def websocket_route( self, path: str, name: str | None = None ) -> Callable[[DecoratedCallable], DecoratedCallable]: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/fastapi/responses.py new/fastapi-0.136.0/fastapi/responses.py --- old/fastapi-0.135.3/fastapi/responses.py 2026-04-01 18:23:54.176415400 +0200 +++ new/fastapi-0.136.0/fastapi/responses.py 2026-04-16 13:47:04.912054000 +0200 @@ -1,4 +1,5 @@ -from typing import Any +import importlib +from typing import Any, Protocol, cast from fastapi.exceptions import FastAPIDeprecationWarning from fastapi.sse import EventSourceResponse as EventSourceResponse # noqa @@ -11,16 +12,28 @@ from starlette.responses import StreamingResponse as StreamingResponse # noqa from typing_extensions import deprecated + +class _UjsonModule(Protocol): + def dumps(self, __obj: Any, *, ensure_ascii: bool = ...) -> str: ... + + +class _OrjsonModule(Protocol): + OPT_NON_STR_KEYS: int + OPT_SERIALIZE_NUMPY: int + + def dumps(self, __obj: Any, *, option: int = ...) -> bytes: ... + + try: - import ujson -except ImportError: # pragma: nocover - ujson = None # type: ignore + ujson = cast(_UjsonModule, importlib.import_module("ujson")) +except ModuleNotFoundError: # pragma: nocover + ujson = None # type: ignore # ty: ignore[unused-ignore-comment] try: - import orjson -except ImportError: # pragma: nocover - orjson = None # type: ignore + orjson = cast(_OrjsonModule, importlib.import_module("orjson")) +except ModuleNotFoundError: # pragma: nocover + orjson = None # type: ignore # ty: ignore[unused-ignore-comment] @deprecated( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/pyproject.toml new/fastapi-0.136.0/pyproject.toml --- old/fastapi-0.135.3/pyproject.toml 2026-04-01 18:23:56.667643000 +0200 +++ new/fastapi-0.136.0/pyproject.toml 2026-04-16 13:47:09.735903700 +0200 @@ -52,7 +52,7 @@ "typing-inspection>=0.4.2", "annotated-doc>=0.0.2", ] -version = "0.135.3" +version = "0.136.0" [project.urls] Homepage = "https://github.com/fastapi/fastapi" @@ -64,6 +64,7 @@ [project.optional-dependencies] standard = [ "fastapi-cli[standard] >=0.0.8", + "fastar >= 0.9.0", "httpx >=0.23.0,<1.0.0", "jinja2 >=3.1.5", "python-multipart >=0.0.18", @@ -128,8 +129,6 @@ docs-tests = [ "httpx >=0.23.0,<1.0.0", "ruff >=0.14.14", - "ujson >=5.8.0", - "orjson >=3.9.3", ] github-actions = [ "httpx >=0.27.0,<1.0.0", @@ -155,8 +154,6 @@ "sqlmodel >=0.0.31", "strawberry-graphql >=0.200.0,<1.0.0", "ty>=0.0.9", - "types-orjson >=3.6.2", - "types-ujson >=5.10.0.20240515", "a2wsgi >=1.9.0,<=2.0.0", "pytest-xdist[psutil]>=2.5.0", "pytest-cov>=4.0.0", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/scripts/add_latest_release_date.py new/fastapi-0.136.0/scripts/add_latest_release_date.py --- old/fastapi-0.135.3/scripts/add_latest_release_date.py 1970-01-01 01:00:00.000000000 +0100 +++ new/fastapi-0.136.0/scripts/add_latest_release_date.py 2026-04-16 13:47:04.913103000 +0200 @@ -0,0 +1,40 @@ +"""Check release-notes.md and add today's date to the latest release header if missing.""" + +import re +import sys +from datetime import date + +RELEASE_NOTES_FILE = "docs/en/docs/release-notes.md" +RELEASE_HEADER_PATTERN = re.compile(r"^## (\d+\.\d+\.\d+)\s*(\(.*\))?\s*$") + + +def main() -> None: + with open(RELEASE_NOTES_FILE) as f: + lines = f.readlines() + + for i, line in enumerate(lines): + match = RELEASE_HEADER_PATTERN.match(line) + if not match: + continue + + version = match.group(1) + date_part = match.group(2) + + if date_part: + print(f"Latest release {version} already has a date: {date_part}") + sys.exit(0) + + today = date.today().isoformat() + lines[i] = f"## {version} ({today})\n" + print(f"Added date: {version} ({today})") + + with open(RELEASE_NOTES_FILE, "w") as f: + f.writelines(lines) + sys.exit(0) + + print("No release header found") + sys.exit(1) + + +if __name__ == "__main__": + main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/tests/test_default_response_class.py new/fastapi-0.136.0/tests/test_default_response_class.py --- old/fastapi-0.135.3/tests/test_default_response_class.py 2026-04-01 18:23:54.183063000 +0200 +++ new/fastapi-0.136.0/tests/test_default_response_class.py 2026-04-16 13:47:04.917899100 +0200 @@ -1,15 +1,18 @@ from typing import Any -import orjson from fastapi import APIRouter, FastAPI from fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse from fastapi.testclient import TestClient +from tests.utils import needs_orjson + class ORJSONResponse(JSONResponse): media_type = "application/x-orjson" def render(self, content: Any) -> bytes: + import orjson + return orjson.dumps(content) @@ -118,6 +121,7 @@ override_type = "application/x-override" +@needs_orjson def test_app(): with client: response = client.get("/") @@ -132,6 +136,7 @@ assert response.headers["content-type"] == text_type +@needs_orjson def test_router_a(): with client: response = client.get("/a") @@ -146,6 +151,7 @@ assert response.headers["content-type"] == text_type +@needs_orjson def test_router_a_a(): with client: response = client.get("/a/a") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/tests/test_deprecated_responses.py new/fastapi-0.136.0/tests/test_deprecated_responses.py --- old/fastapi-0.135.3/tests/test_deprecated_responses.py 2026-04-01 18:23:54.184063000 +0200 +++ new/fastapi-0.136.0/tests/test_deprecated_responses.py 2026-04-16 13:47:04.918899000 +0200 @@ -7,6 +7,8 @@ from fastapi.testclient import TestClient from pydantic import BaseModel +from tests.utils import needs_orjson, needs_ujson + class Item(BaseModel): name: str @@ -28,6 +30,7 @@ return app +@needs_orjson def test_orjson_response_returns_correct_data(): app = _make_orjson_app() client = TestClient(app) @@ -38,6 +41,7 @@ assert response.json() == {"name": "widget", "price": 9.99} +@needs_orjson def test_orjson_response_emits_deprecation_warning(): with pytest.warns(FastAPIDeprecationWarning, match="ORJSONResponse is deprecated"): ORJSONResponse(content={"hello": "world"}) @@ -58,6 +62,7 @@ return app +@needs_ujson def test_ujson_response_returns_correct_data(): app = _make_ujson_app() client = TestClient(app) @@ -68,6 +73,7 @@ assert response.json() == {"name": "widget", "price": 9.99} +@needs_ujson def test_ujson_response_emits_deprecation_warning(): with pytest.warns(FastAPIDeprecationWarning, match="UJSONResponse is deprecated"): UJSONResponse(content={"hello": "world"}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/tests/test_orjson_response_class.py new/fastapi-0.136.0/tests/test_orjson_response_class.py --- old/fastapi-0.135.3/tests/test_orjson_response_class.py 2026-04-01 18:23:54.186331300 +0200 +++ new/fastapi-0.136.0/tests/test_orjson_response_class.py 2026-04-16 13:47:04.922150400 +0200 @@ -1,5 +1,9 @@ import warnings +import pytest + +pytest.importorskip("orjson") + from fastapi import FastAPI from fastapi.exceptions import FastAPIDeprecationWarning from fastapi.responses import ORJSONResponse diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/tests/test_tutorial/test_custom_response/test_tutorial001.py new/fastapi-0.136.0/tests/test_tutorial/test_custom_response/test_tutorial001.py --- old/fastapi-0.135.3/tests/test_tutorial/test_custom_response/test_tutorial001.py 2026-04-01 18:23:54.197140700 +0200 +++ new/fastapi-0.136.0/tests/test_tutorial/test_custom_response/test_tutorial001.py 2026-04-16 13:47:04.933370800 +0200 @@ -4,6 +4,8 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot +pytest.importorskip("orjson") + @pytest.fixture( name="client", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/tests/test_tutorial/test_custom_response/test_tutorial001b.py new/fastapi-0.136.0/tests/test_tutorial/test_custom_response/test_tutorial001b.py --- old/fastapi-0.135.3/tests/test_tutorial/test_custom_response/test_tutorial001b.py 2026-04-01 18:23:54.197140700 +0200 +++ new/fastapi-0.136.0/tests/test_tutorial/test_custom_response/test_tutorial001b.py 2026-04-16 13:47:04.933370800 +0200 @@ -11,6 +11,8 @@ client = TestClient(app) +pytest.importorskip("orjson") + @pytest.mark.filterwarnings("ignore::fastapi.exceptions.FastAPIDeprecationWarning") def test_get_custom_response(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/tests/test_tutorial/test_custom_response/test_tutorial009c.py new/fastapi-0.136.0/tests/test_tutorial/test_custom_response/test_tutorial009c.py --- old/fastapi-0.135.3/tests/test_tutorial/test_custom_response/test_tutorial009c.py 2026-04-01 18:23:54.197140700 +0200 +++ new/fastapi-0.136.0/tests/test_tutorial/test_custom_response/test_tutorial009c.py 2026-04-16 13:47:04.933370800 +0200 @@ -1,5 +1,8 @@ +import pytest from fastapi.testclient import TestClient +pytest.importorskip("orjson") + from docs_src.custom_response.tutorial009c_py310 import app client = TestClient(app) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/tests/test_vibe.py new/fastapi-0.136.0/tests/test_vibe.py --- old/fastapi-0.135.3/tests/test_vibe.py 2026-04-01 18:23:54.208743300 +0200 +++ new/fastapi-0.136.0/tests/test_vibe.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,17 +0,0 @@ -from typing import Any - -import pytest -from fastapi import FastAPI -from fastapi.exceptions import FastAPIError - - -def test_vibe_raises(): - with pytest.raises(FastAPIError, match="Are you kidding me"): - app = FastAPI() - - @app.vibe( - "/vibe/", - prompt="pls return json of users from database. make no mistakes", - ) - async def ai_vibes(body: Any): # pragma: nocover - pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fastapi-0.135.3/tests/utils.py new/fastapi-0.136.0/tests/utils.py --- old/fastapi-0.135.3/tests/utils.py 2026-04-01 18:23:54.208743300 +0200 +++ new/fastapi-0.136.0/tests/utils.py 2026-04-16 13:47:04.945173700 +0200 @@ -1,3 +1,4 @@ +import importlib import sys import pytest @@ -9,6 +10,16 @@ sys.version_info < (3, 14), reason="requires python3.14+" ) +needs_orjson = pytest.mark.skipif( + importlib.util.find_spec("orjson") is None, + reason="requires orjson", +) + +needs_ujson = pytest.mark.skipif( + importlib.util.find_spec("ujson") is None, + reason="requires ujson", +) + workdir_lock = pytest.mark.xdist_group("workdir_lock")
