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 <david.a...@suse.com>
+
+- 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 <david.a...@suse.com>
+
+- 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)
 
+@contextlib.asynccontextmanager
+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
-
-
-@contextlib.asynccontextmanager
-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
+
+
+@contextlib.asynccontextmanager
+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
+
+
+@contextlib.asynccontextmanager
+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

Reply via email to