Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 1.0.0 #1888

Closed
wants to merge 15 commits into from
61 changes: 61 additions & 0 deletions docs/deprecation.md
@@ -0,0 +1,61 @@
# Deprecation Policy

The goal of this policy is to reduce the impact of changes on users and developers of the project by providing
clear guidelines and a well-defined process for deprecating functionalities. This policy applies to both features
and API interfaces.

!!! info "Terminology"
**Deprecation** and **removal** of a feature have different meanings. **Deprecation** refers to the process of
communicating to users that a feature will be removed in the future. **Removal** refers to the actual
deletion of the feature from the codebase.

## Starlette Versions

Starlette follows [Semantic Versioning](https://semver.org/).

## Process to Remove a Feature

We'll consider two kinds of processes: **drop Python version support** and **feature removal**.

### Python Version

Starlette will aim to support a Python version until the [EOL date of that version](https://endoflife.date/python).
When a Python version reaches EOL, Starlette will drop support for that version in the next **minor** release.
Kludex marked this conversation as resolved.
Show resolved Hide resolved

The drop of Python version support will be documented in the release notes, but the user will **not** be warned it in code.
Kludex marked this conversation as resolved.
Show resolved Hide resolved

### Feature Removal

The first step to remove a feature is to **deprecate** it, which is done in **major** releases.

The deprecation of a feature needs to be followed by a warning message using `warnings.warn` in the code that
uses the deprecated feature. The warning message should include the version in which the feature will be removed.

The format of the message should follow:

> *`code` is deprecated and will be removed in version `version`.*

The `code` can be a *function*, *module* or *feature* name, and the `version` should be the next major release.

The deprecation warning may include an advice on how to replace the deprecated feature.

> *Use `alternative` instead.*

As a full example, imagine we are in version 1.0.0, and we want to deprecate the `potato` function.
We would add the follow warning:

```python
def potato():
warnings.warn(
"potato is deprecated and will be removed in version 2.0.0. "
"Use banana instead.",
DeprecationWarning,
)

def banana():
...
```

The deprecation of a feature will be documented in the release notes, and the user will be warned about it.

Also, in the above example, on version 2.0.0, the `potato` function will be removed from the codebase.
14 changes: 14 additions & 0 deletions docs/release-notes.md
@@ -1,3 +1,17 @@
## 1.0.0

Wow!!! 1.0.0 is here! 馃帀

### Removed

* Removed `WSGIMiddleware`, which is deprecated since `0.19.0`. Please use [`a2wsgi`](https://github.com/abersheeran/a2wsgi) instead.
* Removed `run_until_first_complete`, which is deprecated since `0.19.0`.
* Removed `iscoroutinefunction_or_partial`, which is deprecated since `0.20.1`.
It was an internal function, which we have replaced by `_utils.is_async_callable`.
* Removed `WS_1004_NO_STATUS_RCVD` and `WS_1005_ABNORMAL_CLOSURE` from the `status` module, which were deprecated since `0.19.1`.
* Removed `ExceptionMiddleware` from the `exceptions` module, which was deprecated since `0.19.1`.
The same middleware can be found in the `middleware.exceptions` module.

## 0.28.0

June 7, 2023
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Expand Up @@ -47,6 +47,7 @@ nav:
- Test Client: 'testclient.md'
- Third Party Packages: 'third-party-packages.md'
- Contributing: 'contributing.md'
- Deprecation Policy: 'deprecation.md'
- Release Notes: 'release-notes.md'

markdown_extensions:
Expand Down
3 changes: 0 additions & 3 deletions pyproject.toml
Expand Up @@ -78,12 +78,9 @@ xfail_strict = true
filterwarnings = [
# Turn warnings that aren't filtered into exceptions
"error",
"ignore: run_until_first_complete is deprecated and will be removed in a future version.:DeprecationWarning",
"ignore: starlette.middleware.wsgi is deprecated and will be removed in a future release.*:DeprecationWarning",
"ignore: Async generator 'starlette.requests.Request.stream' was garbage collected before it had been exhausted.*:ResourceWarning",
"ignore: path is deprecated.*:DeprecationWarning:certifi",
"ignore: Use 'content=<...>' to upload raw bytes/text content.:DeprecationWarning",
"ignore: The `allow_redirects` argument is deprecated. Use `follow_redirects` instead.:DeprecationWarning",
"ignore: 'cgi' is deprecated and slated for removal in Python 3.13:DeprecationWarning",
"ignore: You seem to already have a custom sys.excepthook handler installed. I'll skip installing Trio's custom handler, but this means MultiErrors will not show full tracebacks.:RuntimeWarning",
]
Expand Down
2 changes: 1 addition & 1 deletion starlette/__init__.py
@@ -1 +1 @@
__version__ = "0.28.0"
__version__ = "1.0.0"
129 changes: 0 additions & 129 deletions starlette/applications.py
@@ -1,9 +1,7 @@
import typing
import warnings

from starlette.datastructures import State, URLPath
from starlette.middleware import Middleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.middleware.errors import ServerErrorMiddleware
from starlette.middleware.exceptions import ExceptionMiddleware
from starlette.requests import Request
Expand Down Expand Up @@ -121,19 +119,6 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
self.middleware_stack = self.build_middleware_stack()
await self.middleware_stack(scope, receive, send)

def on_event(self, event_type: str) -> typing.Callable: # pragma: nocover
return self.router.on_event(event_type)

def mount(
self, path: str, app: ASGIApp, name: typing.Optional[str] = None
) -> None: # pragma: nocover
self.router.mount(path, app=app, name=name)

def host(
self, host: str, app: ASGIApp, name: typing.Optional[str] = None
) -> None: # pragma: no cover
self.router.host(host, app=app, name=name)

def add_middleware(self, middleware_class: type, **options: typing.Any) -> None:
if self.middleware_stack is not None: # pragma: no cover
raise RuntimeError("Cannot add middleware after an application has started")
Expand All @@ -145,117 +130,3 @@ def add_exception_handler(
handler: typing.Callable,
) -> None: # pragma: no cover
self.exception_handlers[exc_class_or_status_code] = handler

def add_event_handler(
self, event_type: str, func: typing.Callable
) -> None: # pragma: no cover
self.router.add_event_handler(event_type, func)

def add_route(
self,
path: str,
route: typing.Callable,
methods: typing.Optional[typing.List[str]] = None,
name: typing.Optional[str] = None,
include_in_schema: bool = True,
) -> None: # pragma: no cover
self.router.add_route(
path, route, methods=methods, name=name, include_in_schema=include_in_schema
)

def add_websocket_route(
self, path: str, route: typing.Callable, name: typing.Optional[str] = None
) -> None: # pragma: no cover
self.router.add_websocket_route(path, route, name=name)

def exception_handler(
self, exc_class_or_status_code: typing.Union[int, typing.Type[Exception]]
) -> typing.Callable:
warnings.warn(
"The `exception_handler` decorator is deprecated, and will be removed in version 1.0.0. " # noqa: E501
"Refer to https://www.starlette.io/exceptions/ for the recommended approach.", # noqa: E501
DeprecationWarning,
)

def decorator(func: typing.Callable) -> typing.Callable:
self.add_exception_handler(exc_class_or_status_code, func)
return func

return decorator

def route(
self,
path: str,
methods: typing.Optional[typing.List[str]] = None,
name: typing.Optional[str] = None,
include_in_schema: bool = True,
) -> typing.Callable:
"""
We no longer document this decorator style API, and its usage is discouraged.
Instead you should use the following approach:

>>> routes = [Route(path, endpoint=...), ...]
>>> app = Starlette(routes=routes)
"""
warnings.warn(
"The `route` decorator is deprecated, and will be removed in version 1.0.0. " # noqa: E501
"Refer to https://www.starlette.io/routing/ for the recommended approach.", # noqa: E501
DeprecationWarning,
)

def decorator(func: typing.Callable) -> typing.Callable:
self.router.add_route(
path,
func,
methods=methods,
name=name,
include_in_schema=include_in_schema,
)
return func

return decorator

def websocket_route(
self, path: str, name: typing.Optional[str] = None
) -> typing.Callable:
"""
We no longer document this decorator style API, and its usage is discouraged.
Instead you should use the following approach:

>>> routes = [WebSocketRoute(path, endpoint=...), ...]
>>> app = Starlette(routes=routes)
"""
warnings.warn(
"The `websocket_route` decorator is deprecated, and will be removed in version 1.0.0. " # noqa: E501
"Refer to https://www.starlette.io/routing/#websocket-routing for the recommended approach.", # noqa: E501
DeprecationWarning,
)

def decorator(func: typing.Callable) -> typing.Callable:
self.router.add_websocket_route(path, func, name=name)
return func

return decorator

def middleware(self, middleware_type: str) -> typing.Callable:
"""
We no longer document this decorator style API, and its usage is discouraged.
Instead you should use the following approach:

>>> middleware = [Middleware(...), ...]
>>> app = Starlette(middleware=middleware)
"""
warnings.warn(
"The `middleware` decorator is deprecated, and will be removed in version 1.0.0. " # noqa: E501
"Refer to https://www.starlette.io/middleware/#using-middleware for recommended approach.", # noqa: E501
DeprecationWarning,
)
assert (
middleware_type == "http"
), 'Currently only middleware("http") is supported.'

def decorator(func: typing.Callable) -> typing.Callable:
self.add_middleware(BaseHTTPMiddleware, dispatch=func)
return func

return decorator
18 changes: 0 additions & 18 deletions starlette/concurrency.py
@@ -1,7 +1,6 @@
import functools
import sys
import typing
import warnings

import anyio

Expand All @@ -15,23 +14,6 @@
P = ParamSpec("P")


async def run_until_first_complete(*args: typing.Tuple[typing.Callable, dict]) -> None:
warnings.warn(
"run_until_first_complete is deprecated "
"and will be removed in a future version.",
DeprecationWarning,
)

async with anyio.create_task_group() as task_group:

async def run(func: typing.Callable[[], typing.Coroutine]) -> None:
await func()
task_group.cancel_scope.cancel()

for func, kwargs in args:
task_group.start_soon(run, functools.partial(func, **kwargs))


async def run_in_threadpool(
func: typing.Callable[P, T], *args: P.args, **kwargs: P.kwargs
) -> T:
Expand Down
24 changes: 0 additions & 24 deletions starlette/exceptions.py
@@ -1,8 +1,5 @@
import http
import typing
import warnings

__all__ = ("HTTPException", "WebSocketException")


class HTTPException(Exception):
Expand Down Expand Up @@ -37,24 +34,3 @@ def __str__(self) -> str:
def __repr__(self) -> str:
class_name = self.__class__.__name__
return f"{class_name}(code={self.code!r}, reason={self.reason!r})"


__deprecated__ = "ExceptionMiddleware"


def __getattr__(name: str) -> typing.Any: # pragma: no cover
if name == __deprecated__:
from starlette.middleware.exceptions import ExceptionMiddleware

warnings.warn(
f"{__deprecated__} is deprecated on `starlette.exceptions`. "
f"Import it from `starlette.middleware.exceptions` instead.",
category=DeprecationWarning,
stacklevel=3,
)
return ExceptionMiddleware
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")


def __dir__() -> typing.List[str]:
return sorted(list(__all__) + [__deprecated__]) # pragma: no cover