Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-starlette for
openSUSE:Factory checked in at 2023-03-15 18:53:38
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-starlette (Old)
and /work/SRC/openSUSE:Factory/.python-starlette.new.31432 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-starlette"
Wed Mar 15 18:53:38 2023 rev:18 rq:1071792 version:0.26.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-starlette/python-starlette.changes
2023-02-25 19:55:05.843261288 +0100
+++
/work/SRC/openSUSE:Factory/.python-starlette.new.31432/python-starlette.changes
2023-03-15 18:53:47.100152746 +0100
@@ -1,0 +2,24 @@
+Tue Mar 14 09:11:16 UTC 2023 - David Anes <[email protected]>
+
+- Update to 0.26.1:
+ * Fixed
+ - Fix typing of Lifespan to allow subclasses of Starlette #2077.
+
+-------------------------------------------------------------------
+Fri Mar 10 11:36:42 UTC 2023 - David Anes <[email protected]>
+
+- Update to 0.26.0.post1:
+ * Fixed
+ - Replace reference from Events to Lifespan on the mkdocs.yml #2072.
+
+- Update to 0.26.0:
+ * Added
+ - Support lifespan state #2060, #2065 and #2064.
+ * Changed
+ - Change url_for signature to return a URL instance #1385.
+ * Fixed
+ - Allow "name" argument on url_for() and url_path_for() #2050.
+ * Deprecated
+ - Deprecate on_startup and on_shutdown events #2070.
+
+-------------------------------------------------------------------
Old:
----
starlette-0.25.0.tar.gz
New:
----
starlette-0.26.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-starlette.spec ++++++
--- /var/tmp/diff_new_pack.ksTc2u/_old 2023-03-15 18:53:47.880156896 +0100
+++ /var/tmp/diff_new_pack.ksTc2u/_new 2023-03-15 18:53:47.884156917 +0100
@@ -27,7 +27,7 @@
%define skip_python2 1
Name: python-starlette%{psuffix}
-Version: 0.25.0
+Version: 0.26.1
Release: 0
Summary: Lightweight ASGI framework/toolkit
License: BSD-3-Clause
++++++ starlette-0.25.0.tar.gz -> starlette-0.26.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/README.md
new/starlette-0.26.1/README.md
--- old/starlette-0.25.0/README.md 2023-02-14 10:06:03.000000000 +0100
+++ new/starlette-0.26.1/README.md 2023-03-13 19:08:31.000000000 +0100
@@ -135,7 +135,7 @@
[asgi]: https://asgi.readthedocs.io/en/latest/
[httpx]: https://www.python-httpx.org/
-[jinja2]: http://jinja.pocoo.org/
+[jinja2]: https://jinja.palletsprojects.com/
[python-multipart]: https://andrew-d.github.io/python-multipart/
[itsdangerous]: https://pythonhosted.org/itsdangerous/
[sqlalchemy]: https://www.sqlalchemy.org
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/docs/config.md
new/starlette-0.26.1/docs/config.md
--- old/starlette-0.25.0/docs/config.md 2023-02-14 10:06:03.000000000 +0100
+++ new/starlette-0.26.1/docs/config.md 2023-03-13 19:08:31.000000000 +0100
@@ -240,7 +240,7 @@
Make a 'client' fixture available to test cases.
"""
# Our fixture is created within a context manager. This ensures that
- # application startup and shutdown run for every test case.
+ # application lifespan runs for every test case.
with TestClient(app) as test_client:
yield test_client
```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/docs/database.md
new/starlette-0.26.1/docs/database.md
--- old/starlette-0.25.0/docs/database.md 2023-02-14 10:06:03.000000000
+0100
+++ new/starlette-0.26.1/docs/database.md 2023-03-13 19:08:31.000000000
+0100
@@ -18,6 +18,8 @@
**app.py**
```python
+import contextlib
+
import databases
import sqlalchemy
from starlette.applications import Starlette
@@ -44,6 +46,11 @@
database = databases.Database(DATABASE_URL)
[email protected]
+async def lifespan(app):
+ await database.connect()
+ yield
+ await database.disconnect()
# Main application code.
async def list_notes(request):
@@ -77,8 +84,7 @@
app = Starlette(
routes=routes,
- on_startup=[database.connect],
- on_shutdown=[database.disconnect]
+ lifespan=lifespan,
)
```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/docs/events.md
new/starlette-0.26.1/docs/events.md
--- old/starlette-0.25.0/docs/events.md 2023-02-14 10:06:03.000000000 +0100
+++ new/starlette-0.26.1/docs/events.md 1970-01-01 01:00:00.000000000 +0100
@@ -1,85 +0,0 @@
-
-Starlette applications can register multiple event handlers for dealing with
-code that needs to run before the application starts up, or when the
application
-is shutting down.
-
-## Registering events
-
-These event handlers can either be `async` coroutines, or regular synchronous
-functions.
-
-The event handlers should be included on the application like so:
-
-```python
-from starlette.applications import Starlette
-
-
-async def some_startup_task():
- pass
-
-async def some_shutdown_task():
- pass
-
-routes = [
- ...
-]
-
-app = Starlette(
- routes=routes,
- on_startup=[some_startup_task],
- on_shutdown=[some_shutdown_task]
-)
-```
-
-Starlette will not start serving any incoming requests until all of the
-registered startup handlers have completed.
-
-The shutdown handlers will run once all connections have been closed, and
-any in-process background tasks have completed.
-
-A single lifespan asynccontextmanager handler can be used instead of
-separate startup and shutdown handlers:
-
-```python
-import contextlib
-import anyio
-from starlette.applications import Starlette
-
-
[email protected]
-async def lifespan(app):
- async with some_async_resource():
- yield
-
-
-routes = [
- ...
-]
-
-app = Starlette(routes=routes, lifespan=lifespan)
-```
-
-Consider using
[`anyio.create_task_group()`](https://anyio.readthedocs.io/en/stable/tasks.html)
-for managing asynchronous tasks.
-
-## Running event handlers in tests
-
-You might want to explicitly call into your event handlers in any test setup
-or test teardown code.
-
-Alternatively, you can use `TestClient` as a context manager, to ensure that
-startup and shutdown events are called.
-
-```python
-from example import app
-from starlette.testclient import TestClient
-
-
-def test_homepage():
- with TestClient(app) as client:
- # Application 'on_startup' handlers are called on entering the block.
- response = client.get("/")
- assert response.status_code == 200
-
- # Application 'on_shutdown' handlers are called on exiting the block.
-```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/docs/index.md
new/starlette-0.26.1/docs/index.md
--- old/starlette-0.25.0/docs/index.md 2023-02-14 10:06:03.000000000 +0100
+++ new/starlette-0.26.1/docs/index.md 2023-03-13 19:08:31.000000000 +0100
@@ -131,7 +131,7 @@
[asgi]: https://asgi.readthedocs.io/en/latest/
[httpx]: https://www.python-httpx.org/
-[jinja2]: http://jinja.pocoo.org/
+[jinja2]: https://jinja.palletsprojects.com/
[python-multipart]: https://andrew-d.github.io/python-multipart/
[itsdangerous]: https://pythonhosted.org/itsdangerous/
[sqlalchemy]: https://www.sqlalchemy.org
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/docs/lifespan.md
new/starlette-0.26.1/docs/lifespan.md
--- old/starlette-0.25.0/docs/lifespan.md 1970-01-01 01:00:00.000000000
+0100
+++ new/starlette-0.26.1/docs/lifespan.md 2023-03-13 19:08:31.000000000
+0100
@@ -0,0 +1,91 @@
+
+Starlette applications can register a lifespan handler for dealing with
+code that needs to run before the application starts up, or when the
application
+is shutting down.
+
+```python
+import contextlib
+
+from starlette.applications import Starlette
+
+
[email protected]
+async def lifespan(app):
+ async with some_async_resource():
+ print("Run at startup!")
+ yield
+ print("Run on shutdown!")
+
+
+routes = [
+ ...
+]
+
+app = Starlette(routes=routes, lifespan=lifespan)
+```
+
+Starlette will not start serving any incoming requests until the lifespan has
been run.
+
+The lifespan teardown will run once all connections have been closed, and
+any in-process background tasks have completed.
+
+Consider using
[`anyio.create_task_group()`](https://anyio.readthedocs.io/en/stable/tasks.html)
+for managing asynchronous tasks.
+
+## Lifespan State
+
+The lifespan has the concept of `state`, which is a dictionary that
+can be used to share the objects between the lifespan, and the requests.
+
+```python
+import contextlib
+from typing import TypedDict
+
+import httpx
+from starlette.applications import Starlette
+from starlette.responses import PlainTextResponse
+from starlette.routing import Route
+
+
+class State(TypedDict):
+ http_client: httpx.AsyncClient
+
+
[email protected]
+async def lifespan(app: Starlette) -> State:
+ async with httpx.AsyncClient() as client:
+ yield {"http_client": client}
+
+
+async def homepage(request):
+ client = request.state.http_client
+ response = await client.get("https://www.example.com")
+ return PlainTextResponse(response.text)
+
+
+app = Starlette(
+ lifespan=lifespan,
+ routes=[Route("/", homepage)]
+)
+```
+
+The `state` received on the requests is a **shallow** copy of the state
received on the
+lifespan handler.
+
+## Running lifespan in tests
+
+You should use `TestClient` as a context manager, to ensure that the lifespan
is called.
+
+```python
+from example import app
+from starlette.testclient import TestClient
+
+
+def test_homepage():
+ with TestClient(app) as client:
+ # Application's lifespan is called on entering the block.
+ response = client.get("/")
+ assert response.status_code == 200
+
+ # And the lifespan's teardown is run when exiting the block.
+```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/docs/middleware.md
new/starlette-0.26.1/docs/middleware.md
--- old/starlette-0.25.0/docs/middleware.md 2023-02-14 10:06:03.000000000
+0100
+++ new/starlette-0.26.1/docs/middleware.md 2023-03-13 19:08:31.000000000
+0100
@@ -773,10 +773,6 @@
A middleware class for logging exceptions, errors, and log messages to
[Rollbar](https://www.rollbar.com).
-#### [SentryMiddleware](https://github.com/encode/sentry-asgi)
-
-A middleware class for logging exceptions to [Sentry](https://sentry.io/).
-
#### [StarletteOpentracing](https://github.com/acidjunk/starlette-opentracing)
A middleware class that emits tracing info to
[OpenTracing.io](https://opentracing.io/) compatible tracers and
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/docs/release-notes.md
new/starlette-0.26.1/docs/release-notes.md
--- old/starlette-0.25.0/docs/release-notes.md 2023-02-14 10:06:03.000000000
+0100
+++ new/starlette-0.26.1/docs/release-notes.md 2023-03-13 19:08:31.000000000
+0100
@@ -1,3 +1,34 @@
+## 0.26.1
+
+March 13, 2023
+
+### Fixed
+* Fix typing of Lifespan to allow subclasses of Starlette
[#2077](https://github.com/encode/starlette/pull/2077).
+
+## 0.26.0.post1
+
+March 9, 2023
+
+### Fixed
+* Replace reference from Events to Lifespan on the mkdocs.yml
[#2072](https://github.com/encode/starlette/pull/2072).
+
+## 0.26.0
+
+March 9, 2023
+
+### Added
+* Support [lifespan state](/lifespan/)
[#2060](https://github.com/encode/starlette/pull/2060),
+ [#2065](https://github.com/encode/starlette/pull/2065) and
[#2064](https://github.com/encode/starlette/pull/2064).
+
+### Changed
+* Change `url_for` signature to return a `URL` instance
[#1385](https://github.com/encode/starlette/pull/1385).
+
+### Fixed
+* Allow "name" argument on `url_for()` and `url_path_for()`
[#2050](https://github.com/encode/starlette/pull/2050).
+
+### Deprecated
+* Deprecate `on_startup` and `on_shutdown` events
[#2070](https://github.com/encode/starlette/pull/2070).
+
## 0.25.0
February 14, 2023
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/docs/routing.md
new/starlette-0.26.1/docs/routing.md
--- old/starlette-0.25.0/docs/routing.md 2023-02-14 10:06:03.000000000
+0100
+++ new/starlette-0.26.1/docs/routing.md 2023-03-13 19:08:31.000000000
+0100
@@ -151,6 +151,8 @@
You'll often want to be able to generate the URL for a particular route,
such as in cases where you need to return a redirect response.
+* Signature: `url_for(name, **path_params) -> URL`
+
```python
routes = [
Route("/", homepage, name="homepage")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/docs/testclient.md
new/starlette-0.26.1/docs/testclient.md
--- old/starlette-0.25.0/docs/testclient.md 2023-02-14 10:06:03.000000000
+0100
+++ new/starlette-0.26.1/docs/testclient.md 2023-03-13 19:08:31.000000000
+0100
@@ -64,10 +64,10 @@
!!! note
- If you want the `TestClient` to run `lifespan` events (`on_startup`,
`on_shutdown`, or `lifespan`),
- you will need to use the `TestClient` as a context manager. Otherwise, the
events
- will not be triggered when the `TestClient` is instantiated. You can learn
more about it
- [here](/events/#running-event-handlers-in-tests).
+ If you want the `TestClient` to run the `lifespan` handler,
+ you will need to use the `TestClient` as a context manager. It will
+ not be triggered when the `TestClient` is instantiated. You can learn more
about it
+ [here](/lifespan/#running-lifespan-in-tests).
### Selecting the Async backend
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/docs/third-party-packages.md
new/starlette-0.26.1/docs/third-party-packages.md
--- old/starlette-0.25.0/docs/third-party-packages.md 2023-02-14
10:06:03.000000000 +0100
+++ new/starlette-0.26.1/docs/third-party-packages.md 2023-03-13
19:08:31.000000000 +0100
@@ -170,12 +170,12 @@
### Flama
-<a href="https://github.com/perdy/flama/" target="_blank">GitHub</a> |
-<a href="https://flama.perdy.io/" target="_blank">Documentation</a>
+<a href="https://github.com/vortico/flama" target="_blank">GitHub</a> |
+<a href="https://flama.dev/" target="_blank">Documentation</a>
-Formerly Starlette API.
+Flama is a **data-science oriented framework** to rapidly build modern and
robust **machine learning** (ML) APIs. The main aim of the framework is to make
ridiculously simple the deployment of ML APIs. With Flama, data scientists can
now quickly turn their ML models into asynchronous, auto-documented APIs with
just a single line of code. All in just few seconds!
-Flama aims to bring a layer on top of Starlette to provide an **easy to
learn** and **fast to develop** approach for building **highly performant**
GraphQL and REST APIs. In the same way of Starlette is, Flama is a perfect
option for developing **asynchronous** and **production-ready** services.
+Flama comes with an intuitive CLI, and provides an easy-to-learn philosophy to
speed up the building of **highly performant** GraphQL, REST, and ML APIs.
Besides, it comprises an ideal solution for the development of asynchronous and
**production-ready** services, offering **automatic deployment** for ML models.
### Greppo
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/mkdocs.yml
new/starlette-0.26.1/mkdocs.yml
--- old/starlette-0.25.0/mkdocs.yml 2023-02-14 10:06:03.000000000 +0100
+++ new/starlette-0.26.1/mkdocs.yml 2023-03-13 19:08:31.000000000 +0100
@@ -39,7 +39,7 @@
- GraphQL: 'graphql.md'
- Authentication: 'authentication.md'
- API Schemas: 'schemas.md'
- - Events: 'events.md'
+ - Lifespan: 'lifespan.md'
- Background Tasks: 'background.md'
- Server Push: 'server-push.md'
- Exceptions: 'exceptions.md'
@@ -55,7 +55,7 @@
- pymdownx.highlight
- pymdownx.superfences
- pymdownx.tabbed:
- alternate_style: true
+ alternate_style: true
extra_javascript:
- 'js/chat.js'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/requirements.txt
new/starlette-0.26.1/requirements.txt
--- old/starlette-0.25.0/requirements.txt 2023-02-14 10:06:03.000000000
+0100
+++ new/starlette-0.26.1/requirements.txt 2023-03-13 19:08:31.000000000
+0100
@@ -8,19 +8,19 @@
flake8==3.9.2
importlib-metadata==4.13.0
isort==5.10.1
-mypy==0.991
+mypy==1.0.1
typing_extensions==4.4.0
-types-contextvars==2.4.7
+types-contextvars==2.4.7.1
types-PyYAML==6.0.12.3
types-dataclasses==0.6.6
-pytest==7.2.0
+pytest==7.2.1
trio==0.21.0
# Documentation
mkdocs==1.4.2
-mkdocs-material==8.5.7
+mkdocs-material==9.0.15
mkautodoc==0.2.0
# Packaging
-build==0.9.0
+build==0.10.0
twine==4.0.2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/starlette/__init__.py
new/starlette-0.26.1/starlette/__init__.py
--- old/starlette-0.25.0/starlette/__init__.py 2023-02-14 10:06:03.000000000
+0100
+++ new/starlette-0.26.1/starlette/__init__.py 2023-03-13 19:08:31.000000000
+0100
@@ -1 +1 @@
-__version__ = "0.25.0"
+__version__ = "0.26.1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/starlette/applications.py
new/starlette-0.26.1/starlette/applications.py
--- old/starlette-0.25.0/starlette/applications.py 2023-02-14
10:06:03.000000000 +0100
+++ new/starlette-0.26.1/starlette/applications.py 2023-03-13
19:08:31.000000000 +0100
@@ -9,7 +9,9 @@
from starlette.requests import Request
from starlette.responses import Response
from starlette.routing import BaseRoute, Router
-from starlette.types import ASGIApp, Receive, Scope, Send
+from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send
+
+AppType = typing.TypeVar("AppType", bound="Starlette")
class Starlette:
@@ -37,10 +39,13 @@
* **on_shutdown** - A list of callables to run on application shutdown.
Shutdown handler callables do not take any arguments, and may be be either
standard functions, or async functions.
+ * **lifespan** - A lifespan context function, which can be used to perform
+ startup and shutdown tasks. This is a newer style that replaces the
+ `on_startup` and `on_shutdown` handlers. Use one or the other, not both.
"""
def __init__(
- self,
+ self: "AppType",
debug: bool = False,
routes: typing.Optional[typing.Sequence[BaseRoute]] = None,
middleware: typing.Optional[typing.Sequence[Middleware]] = None,
@@ -55,9 +60,7 @@
] = None,
on_startup: typing.Optional[typing.Sequence[typing.Callable]] = None,
on_shutdown: typing.Optional[typing.Sequence[typing.Callable]] = None,
- lifespan: typing.Optional[
- typing.Callable[["Starlette"], typing.AsyncContextManager]
- ] = None,
+ lifespan: typing.Optional[Lifespan["AppType"]] = None,
) -> None:
# The lifespan context function is a newer style that replaces
# on_startup / on_shutdown handlers. Use one or the other, not both.
@@ -108,8 +111,9 @@
def routes(self) -> typing.List[BaseRoute]:
return self.router.routes
- def url_path_for(self, name: str, **path_params: typing.Any) -> URLPath:
- return self.router.url_path_for(name, **path_params)
+ # TODO: Make `__name` a positional-only argument when we drop Python 3.7
support.
+ def url_path_for(self, __name: str, **path_params: typing.Any) -> URLPath:
+ return self.router.url_path_for(__name, **path_params)
async def __call__(self, scope: Scope, receive: Receive, send: Send) ->
None:
scope["app"] = self
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/starlette/datastructures.py
new/starlette-0.26.1/starlette/datastructures.py
--- old/starlette-0.25.0/starlette/datastructures.py 2023-02-14
10:06:03.000000000 +0100
+++ new/starlette-0.26.1/starlette/datastructures.py 2023-03-13
19:08:31.000000000 +0100
@@ -187,7 +187,7 @@
self.protocol = protocol
self.host = host
- def make_absolute_url(self, base_url: typing.Union[str, URL]) -> str:
+ def make_absolute_url(self, base_url: typing.Union[str, URL]) -> URL:
if isinstance(base_url, str):
base_url = URL(base_url)
if self.protocol:
@@ -200,7 +200,7 @@
netloc = self.host or base_url.netloc
path = base_url.path.rstrip("/") + str(self)
- return str(URL(scheme=scheme, netloc=netloc, path=path))
+ return URL(scheme=scheme, netloc=netloc, path=path)
class Secret:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/starlette/requests.py
new/starlette-0.26.1/starlette/requests.py
--- old/starlette-0.25.0/starlette/requests.py 2023-02-14 10:06:03.000000000
+0100
+++ new/starlette-0.26.1/starlette/requests.py 2023-03-13 19:08:31.000000000
+0100
@@ -173,9 +173,9 @@
self._state = State(self.scope["state"])
return self._state
- def url_for(self, name: str, **path_params: typing.Any) -> str:
+ def url_for(self, __name: str, **path_params: typing.Any) -> URL:
router: Router = self.scope["router"]
- url_path = router.url_path_for(name, **path_params)
+ url_path = router.url_path_for(__name, **path_params)
return url_path.make_absolute_url(base_url=self.base_url)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/starlette/routing.py
new/starlette-0.26.1/starlette/routing.py
--- old/starlette-0.25.0/starlette/routing.py 2023-02-14 10:06:03.000000000
+0100
+++ new/starlette-0.26.1/starlette/routing.py 2023-03-13 19:08:31.000000000
+0100
@@ -17,7 +17,7 @@
from starlette.middleware import Middleware
from starlette.requests import Request
from starlette.responses import PlainTextResponse, RedirectResponse
-from starlette.types import ASGIApp, Receive, Scope, Send
+from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send
from starlette.websockets import WebSocket, WebSocketClose
@@ -170,7 +170,7 @@
def matches(self, scope: Scope) -> typing.Tuple[Match, Scope]:
raise NotImplementedError() # pragma: no cover
- def url_path_for(self, name: str, **path_params: typing.Any) -> URLPath:
+ def url_path_for(self, __name: str, **path_params: typing.Any) -> URLPath:
raise NotImplementedError() # pragma: no cover
async def handle(self, scope: Scope, receive: Receive, send: Send) -> None:
@@ -249,12 +249,12 @@
return Match.FULL, child_scope
return Match.NONE, {}
- def url_path_for(self, name: str, **path_params: typing.Any) -> URLPath:
+ def url_path_for(self, __name: str, **path_params: typing.Any) -> URLPath:
seen_params = set(path_params.keys())
expected_params = set(self.param_convertors.keys())
- if name != self.name or seen_params != expected_params:
- raise NoMatchFound(name, path_params)
+ if __name != self.name or seen_params != expected_params:
+ raise NoMatchFound(__name, path_params)
path, remaining_params = replace_params(
self.path_format, self.param_convertors, path_params
@@ -324,12 +324,12 @@
return Match.FULL, child_scope
return Match.NONE, {}
- def url_path_for(self, name: str, **path_params: typing.Any) -> URLPath:
+ def url_path_for(self, __name: str, **path_params: typing.Any) -> URLPath:
seen_params = set(path_params.keys())
expected_params = set(self.param_convertors.keys())
- if name != self.name or seen_params != expected_params:
- raise NoMatchFound(name, path_params)
+ if __name != self.name or seen_params != expected_params:
+ raise NoMatchFound(__name, path_params)
path, remaining_params = replace_params(
self.path_format, self.param_convertors, path_params
@@ -406,8 +406,8 @@
return Match.FULL, child_scope
return Match.NONE, {}
- def url_path_for(self, name: str, **path_params: typing.Any) -> URLPath:
- if self.name is not None and name == self.name and "path" in
path_params:
+ def url_path_for(self, __name: str, **path_params: typing.Any) -> URLPath:
+ if self.name is not None and __name == self.name and "path" in
path_params:
# 'name' matches "<mount_name>".
path_params["path"] = path_params["path"].lstrip("/")
path, remaining_params = replace_params(
@@ -415,13 +415,13 @@
)
if not remaining_params:
return URLPath(path=path)
- elif self.name is None or name.startswith(self.name + ":"):
+ elif self.name is None or __name.startswith(self.name + ":"):
if self.name is None:
# No mount name.
- remaining_name = name
+ remaining_name = __name
else:
# 'name' matches "<mount_name>:<child_name>".
- remaining_name = name[len(self.name) + 1 :]
+ remaining_name = __name[len(self.name) + 1 :]
path_kwarg = path_params.get("path")
path_params["path"] = ""
path_prefix, remaining_params = replace_params(
@@ -437,7 +437,7 @@
)
except NoMatchFound:
pass
- raise NoMatchFound(name, path_params)
+ raise NoMatchFound(__name, path_params)
async def handle(self, scope: Scope, receive: Receive, send: Send) -> None:
await self.app(scope, receive, send)
@@ -484,8 +484,8 @@
return Match.FULL, child_scope
return Match.NONE, {}
- def url_path_for(self, name: str, **path_params: typing.Any) -> URLPath:
- if self.name is not None and name == self.name and "path" in
path_params:
+ def url_path_for(self, __name: str, **path_params: typing.Any) -> URLPath:
+ if self.name is not None and __name == self.name and "path" in
path_params:
# 'name' matches "<mount_name>".
path = path_params.pop("path")
host, remaining_params = replace_params(
@@ -493,13 +493,13 @@
)
if not remaining_params:
return URLPath(path=path, host=host)
- elif self.name is None or name.startswith(self.name + ":"):
+ elif self.name is None or __name.startswith(self.name + ":"):
if self.name is None:
# No mount name.
- remaining_name = name
+ remaining_name = __name
else:
# 'name' matches "<mount_name>:<child_name>".
- remaining_name = name[len(self.name) + 1 :]
+ remaining_name = __name[len(self.name) + 1 :]
host, remaining_params = replace_params(
self.host_format, self.param_convertors, path_params
)
@@ -509,7 +509,7 @@
return URLPath(path=str(url), protocol=url.protocol,
host=host)
except NoMatchFound:
pass
- raise NoMatchFound(name, path_params)
+ raise NoMatchFound(__name, path_params)
async def handle(self, scope: Scope, receive: Receive, send: Send) -> None:
await self.app(scope, receive, send)
@@ -580,9 +580,9 @@
default: typing.Optional[ASGIApp] = None,
on_startup: typing.Optional[typing.Sequence[typing.Callable]] = None,
on_shutdown: typing.Optional[typing.Sequence[typing.Callable]] = None,
- lifespan: typing.Optional[
- typing.Callable[[typing.Any], typing.AsyncContextManager]
- ] = None,
+ # the generic to Lifespan[AppType] is the type of the top level
application
+ # which the router cannot know statically, so we use typing.Any
+ lifespan: typing.Optional[Lifespan[typing.Any]] = None,
) -> None:
self.routes = [] if routes is None else list(routes)
self.redirect_slashes = redirect_slashes
@@ -590,10 +590,16 @@
self.on_startup = [] if on_startup is None else list(on_startup)
self.on_shutdown = [] if on_shutdown is None else list(on_shutdown)
+ if on_startup or on_shutdown:
+ warnings.warn(
+ "The on_startup and on_shutdown parameters are deprecated, and
they "
+ "will be removed on version 1.0. Use the lifespan parameter
instead. "
+ "See more about it on https://www.starlette.io/lifespan/.",
+ DeprecationWarning,
+ )
+
if lifespan is None:
- self.lifespan_context: typing.Callable[
- [typing.Any], typing.AsyncContextManager
- ] = _DefaultLifespan(self)
+ self.lifespan_context: Lifespan = _DefaultLifespan(self)
elif inspect.isasyncgenfunction(lifespan):
warnings.warn(
@@ -631,13 +637,13 @@
response = PlainTextResponse("Not Found", status_code=404)
await response(scope, receive, send)
- def url_path_for(self, name: str, **path_params: typing.Any) -> URLPath:
+ def url_path_for(self, __name: str, **path_params: typing.Any) -> URLPath:
for route in self.routes:
try:
- return route.url_path_for(name, **path_params)
+ return route.url_path_for(__name, **path_params)
except NoMatchFound:
pass
- raise NoMatchFound(name, path_params)
+ raise NoMatchFound(__name, path_params)
async def startup(self) -> None:
"""
@@ -665,10 +671,16 @@
startup and shutdown events.
"""
started = False
- app = scope.get("app")
+ app: typing.Any = scope.get("app")
await receive()
try:
- async with self.lifespan_context(app):
+ async with self.lifespan_context(app) as maybe_state:
+ if maybe_state is not None:
+ if "state" not in scope:
+ raise RuntimeError(
+ 'The server does not support "state" in the
lifespan scope.'
+ )
+ scope["state"].update(maybe_state)
await send({"type": "lifespan.startup.complete"})
started = True
await receive()
@@ -839,7 +851,7 @@
def on_event(self, event_type: str) -> typing.Callable:
warnings.warn(
"The `on_event` decorator is deprecated, and will be removed in
version 1.0.0. " # noqa: E501
- "Refer to https://www.starlette.io/events/#registering-events for
recommended approach.", # noqa: E501
+ "Refer to https://www.starlette.io/lifespan/ for recommended
approach.",
DeprecationWarning,
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/starlette/templating.py
new/starlette-0.26.1/starlette/templating.py
--- old/starlette-0.25.0/starlette/templating.py 2023-02-14
10:06:03.000000000 +0100
+++ new/starlette-0.26.1/starlette/templating.py 2023-03-13
19:08:31.000000000 +0100
@@ -2,6 +2,7 @@
from os import PathLike
from starlette.background import BackgroundTask
+from starlette.datastructures import URL
from starlette.requests import Request
from starlette.responses import Response
from starlette.types import Receive, Scope, Send
@@ -77,7 +78,7 @@
self, directory: typing.Union[str, PathLike], **env_options: typing.Any
) -> "jinja2.Environment":
@pass_context
- def url_for(context: dict, name: str, **path_params: typing.Any) ->
str:
+ def url_for(context: dict, name: str, **path_params: typing.Any) ->
URL:
request = context["request"]
return request.url_for(name, **path_params)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/starlette/testclient.py
new/starlette-0.26.1/starlette/testclient.py
--- old/starlette-0.25.0/starlette/testclient.py 2023-02-14
10:06:03.000000000 +0100
+++ new/starlette-0.26.1/starlette/testclient.py 2023-03-13
19:08:31.000000000 +0100
@@ -188,11 +188,14 @@
portal_factory: _PortalFactoryType,
raise_server_exceptions: bool = True,
root_path: str = "",
+ *,
+ app_state: typing.Dict[str, typing.Any],
) -> None:
self.app = app
self.raise_server_exceptions = raise_server_exceptions
self.root_path = root_path
self.portal_factory = portal_factory
+ self.app_state = app_state
def handle_request(self, request: httpx.Request) -> httpx.Response:
scheme = request.url.scheme
@@ -243,6 +246,7 @@
"client": ["testclient", 50000],
"server": [host, port],
"subprotocols": subprotocols,
+ "state": self.app_state.copy(),
}
session = WebSocketTestSession(self.app, scope,
self.portal_factory)
raise _Upgrade(session)
@@ -260,6 +264,7 @@
"client": ["testclient", 50000],
"server": [host, port],
"extensions": {"http.response.debug": {}},
+ "state": self.app_state.copy(),
}
request_complete = False
@@ -380,11 +385,13 @@
app = typing.cast(ASGI2App, app) # type: ignore[assignment]
asgi_app = _WrapASGI2(app) # type: ignore[arg-type]
self.app = asgi_app
+ self.app_state: typing.Dict[str, typing.Any] = {}
transport = _TestClientTransport(
self.app,
portal_factory=self._portal_factory,
raise_server_exceptions=raise_server_exceptions,
root_path=root_path,
+ app_state=self.app_state,
)
if headers is None:
headers = {}
@@ -749,7 +756,7 @@
self.exit_stack.close()
async def lifespan(self) -> None:
- scope = {"type": "lifespan"}
+ scope = {"type": "lifespan", "state": self.app_state}
try:
await self.app(scope, self.stream_receive.receive,
self.stream_send.send)
finally:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/starlette/types.py
new/starlette-0.26.1/starlette/types.py
--- old/starlette-0.25.0/starlette/types.py 2023-02-14 10:06:03.000000000
+0100
+++ new/starlette-0.26.1/starlette/types.py 2023-03-13 19:08:31.000000000
+0100
@@ -1,5 +1,7 @@
import typing
+AppType = typing.TypeVar("AppType")
+
Scope = typing.MutableMapping[str, typing.Any]
Message = typing.MutableMapping[str, typing.Any]
@@ -7,3 +9,9 @@
Send = typing.Callable[[Message], typing.Awaitable[None]]
ASGIApp = typing.Callable[[Scope, Receive, Send], typing.Awaitable[None]]
+
+StatelessLifespan = typing.Callable[[AppType],
typing.AsyncContextManager[None]]
+StatefulLifespan = typing.Callable[
+ [AppType], typing.AsyncContextManager[typing.Mapping[str, typing.Any]]
+]
+Lifespan = typing.Union[StatelessLifespan[AppType], StatefulLifespan[AppType]]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/tests/test_applications.py
new/starlette-0.26.1/tests/test_applications.py
--- old/starlette-0.25.0/tests/test_applications.py 2023-02-14
10:06:03.000000000 +0100
+++ new/starlette-0.26.1/tests/test_applications.py 2023-03-13
19:08:31.000000000 +0100
@@ -1,6 +1,6 @@
import os
from contextlib import asynccontextmanager
-from typing import Any, Callable
+from typing import Any, AsyncIterator, Callable
import anyio
import httpx
@@ -345,10 +345,13 @@
nonlocal cleanup_complete
cleanup_complete = True
- app = Starlette(
- on_startup=[run_startup],
- on_shutdown=[run_cleanup],
- )
+ with pytest.deprecated_call(
+ match="The on_startup and on_shutdown parameters are deprecated"
+ ):
+ app = Starlette(
+ on_startup=[run_startup],
+ on_shutdown=[run_cleanup],
+ )
assert not startup_complete
assert not cleanup_complete
@@ -531,3 +534,17 @@
test_client_factory(app).get("/foo")
assert SimpleInitializableMiddleware.counter == 2
+
+
+def test_lifespan_app_subclass():
+ # This test exists to make sure that subclasses of Starlette
+ # (like FastAPI) are compatible with the types hints for Lifespan
+
+ class App(Starlette):
+ pass
+
+ @asynccontextmanager
+ async def lifespan(app: App) -> AsyncIterator[None]: # pragma: no cover
+ yield
+
+ App(lifespan=lifespan)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/tests/test_routing.py
new/starlette-0.26.1/tests/test_routing.py
--- old/starlette-0.25.0/tests/test_routing.py 2023-02-14 10:06:03.000000000
+0100
+++ new/starlette-0.26.1/tests/test_routing.py 2023-03-13 19:08:31.000000000
+0100
@@ -1,7 +1,14 @@
+import contextlib
import functools
+import sys
import typing
import uuid
+if sys.version_info < (3, 8):
+ from typing_extensions import TypedDict # pragma: no cover
+else:
+ from typing import TypedDict # pragma: no cover
+
import pytest
from starlette.applications import Starlette
@@ -521,8 +528,8 @@
async def echo_urls(request):
return JSONResponse(
{
- "index": request.url_for("index"),
- "submount": request.url_for("mount:submount"),
+ "index": str(request.url_for("index")),
+ "submount": str(request.url_for("mount:submount")),
}
)
@@ -622,11 +629,14 @@
nonlocal shutdown_complete
shutdown_complete = True
- app = Router(
- on_startup=[run_startup],
- on_shutdown=[run_shutdown],
- routes=[Route("/", hello_world)],
- )
+ with pytest.deprecated_call(
+ match="The on_startup and on_shutdown parameters are deprecated"
+ ):
+ app = Router(
+ on_startup=[run_startup],
+ on_shutdown=[run_shutdown],
+ routes=[Route("/", hello_world)],
+ )
assert not startup_complete
assert not shutdown_complete
@@ -653,9 +663,79 @@
nonlocal shutdown_complete
shutdown_complete = True
+ with pytest.deprecated_call(
+ match="The on_startup and on_shutdown parameters are deprecated"
+ ):
+ app = Router(
+ on_startup=[run_startup],
+ on_shutdown=[run_shutdown],
+ routes=[Route("/", hello_world)],
+ )
+
+ assert not startup_complete
+ assert not shutdown_complete
+ with test_client_factory(app) as client:
+ assert startup_complete
+ assert not shutdown_complete
+ client.get("/")
+ assert startup_complete
+ assert shutdown_complete
+
+
+def test_lifespan_state_unsupported(test_client_factory):
+ @contextlib.asynccontextmanager
+ async def lifespan(app):
+ yield {"foo": "bar"}
+
app = Router(
- on_startup=[run_startup],
- on_shutdown=[run_shutdown],
+ lifespan=lifespan,
+ routes=[Mount("/", PlainTextResponse("hello, world"))],
+ )
+
+ async def no_state_wrapper(scope, receive, send):
+ del scope["state"]
+ await app(scope, receive, send)
+
+ with pytest.raises(
+ RuntimeError, match='The server does not support "state" in the
lifespan scope'
+ ):
+ with test_client_factory(no_state_wrapper):
+ raise AssertionError("Should not be called") # pragma: no cover
+
+
+def test_lifespan_state_async_cm(test_client_factory):
+ startup_complete = False
+ shutdown_complete = False
+
+ class State(TypedDict):
+ count: int
+ items: typing.List[int]
+
+ async def hello_world(request: Request) -> Response:
+ # modifications to the state should not leak across requests
+ assert request.state.count == 0
+ # modify the state, this should not leak to the lifespan or other
requests
+ request.state.count += 1
+ # since state.items is a mutable object this modification _will_ leak
across
+ # requests and to the lifespan
+ request.state.items.append(1)
+ return PlainTextResponse("hello, world")
+
+ @contextlib.asynccontextmanager
+ async def lifespan(app: Starlette) -> typing.AsyncIterator[State]:
+ nonlocal startup_complete, shutdown_complete
+ startup_complete = True
+ state = State(count=0, items=[])
+ yield state
+ shutdown_complete = True
+ # modifications made to the state from a request do not leak to the
lifespan
+ assert state["count"] == 0
+ # unless of course the request mutates a mutable object that is
referenced
+ # via state
+ assert state["items"] == [1, 1]
+
+ app = Router(
+ lifespan=lifespan,
routes=[Route("/", hello_world)],
)
@@ -665,6 +745,8 @@
assert startup_complete
assert not shutdown_complete
client.get("/")
+ # Calling it a second time to ensure that the state is preserved.
+ client.get("/")
assert startup_complete
assert shutdown_complete
@@ -673,7 +755,10 @@
def run_startup():
raise RuntimeError()
- router = Router(on_startup=[run_startup])
+ with pytest.deprecated_call(
+ match="The on_startup and on_shutdown parameters are deprecated"
+ ):
+ router = Router(on_startup=[run_startup])
startup_failed = False
async def app(scope, receive, send):
@@ -695,7 +780,10 @@
def run_shutdown():
raise RuntimeError()
- app = Router(on_shutdown=[run_shutdown])
+ with pytest.deprecated_call(
+ match="The on_startup and on_shutdown parameters are deprecated"
+ ):
+ app = Router(on_shutdown=[run_shutdown])
with pytest.raises(RuntimeError):
with test_client_factory(app):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/starlette-0.25.0/tests/test_testclient.py
new/starlette-0.26.1/tests/test_testclient.py
--- old/starlette-0.25.0/tests/test_testclient.py 2023-02-14
10:06:03.000000000 +0100
+++ new/starlette-0.26.1/tests/test_testclient.py 2023-03-13
19:08:31.000000000 +0100
@@ -45,9 +45,6 @@
raise RuntimeError()
-startup_error_app = Starlette(on_startup=[startup])
-
-
def test_use_testclient_in_endpoint(test_client_factory):
"""
We should be able to use the test client within applications.
@@ -166,6 +163,11 @@
def test_error_on_startup(test_client_factory):
+ with pytest.deprecated_call(
+ match="The on_startup and on_shutdown parameters are deprecated"
+ ):
+ startup_error_app = Starlette(on_startup=[startup])
+
with pytest.raises(RuntimeError):
with test_client_factory(startup_error_app):
pass # pragma: no cover