Skip to content

Commit

Permalink
Merge branch 'main' into replace-python-jose-by-pyjwt
Browse files Browse the repository at this point in the history
  • Loading branch information
cofin authored Jun 21, 2024
2 parents c52e57e + de8f4a7 commit 4e1a021
Show file tree
Hide file tree
Showing 24 changed files with 723 additions and 251 deletions.
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@
("py:exc", "HTTPExceptions"),
(PY_CLASS, "litestar.template.Template"),
(PY_CLASS, "litestar.middleware.compression.gzip_facade.GzipCompression"),
(PY_CLASS, "litestar.handlers.http_handlers.decorators._SubclassWarningMixin"),
(PY_CLASS, "litestar.handlers.http_handlers.decorators._subclass_warning"),
]

nitpick_ignore_regex = [
Expand Down Expand Up @@ -236,7 +236,7 @@
re.compile(r"litestar\.template\.(config|TemplateConfig).*"): re.compile(".*EngineType"),
"litestar.concurrency.set_asyncio_executor": {"ThreadPoolExecutor"},
"litestar.concurrency.get_asyncio_executor": {"ThreadPoolExecutor"},
re.compile(r"litestar\.channels\.backends\.asyncpg.*"): {"asyncpg.connection.Connection"},
re.compile(r"litestar\.channels\.backends\.asyncpg.*"): {"asyncpg.Connection"},
}

# Do not warn about broken links to the following:
Expand Down
80 changes: 80 additions & 0 deletions docs/release-notes/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,86 @@
2.x Changelog
=============

.. changelog:: 2.9.1
:date: 2024-06-21

.. change:: Add OPTIONS to the default safe methods for CSRFConfig
:type: bugfix
:pr: 3538

Add ``OPTIONS`` to the default safe methods for :class:`~litestar.config.csrf.CSRFConfig`


.. change:: Prometheus: Capture templated route name for metrics
:type: bugfix
:pr: 3533

Adding new extraction function for prometheus metrics to avoid high cardinality
issue in prometheus, eg having metrics ``GET /v1/users/{id}`` is preferable over
``GET /v1/users/1``, ``GET /v1/users/2,GET /v1/users/3``

More info about prometheus high cardinality
https://grafana.com/blog/2022/02/15/what-are-cardinality-spikes-and-why-do-they-matter/

.. change:: Respect ``base_url`` in ``.websocket_connect``
:type: bugfix
:pr: 3567

Fix a bug that caused :meth:`~litestar.testing.TestClient.websocket_connect` /
:meth:`~litestar.testing.AsyncTestClient.websocket_connect` to not respect the
``base_url`` set in the client's constructor, and instead would use the static
``ws://testerver`` URL as a base.

Also removes most of the test client code as it was unneeded and in the way of
this fix :)

Explanation for the last part: All the extra code we had was just proxying
method calls to the ``httpx.Client`` / ``httpx.AsyncClient``, while altering the
base URL. Since we already set the base URL on the httpx Client's superclass
instance, which in turn does this merging internally, this step isn't needed at
all.

.. change:: Fix deprecation warning for subclassing route handler decorators
:type: bugfix
:pr: 3569
:issue: 3552

Fix an issue where there was a deprecation warning emitted by all route handler
decorators. This warning was introduced in ``2.9.0`` to warn about the upcoming
deprecation, but should have only applied to user subclasses of the handler
classes, and not the built-in ones (``get``, ``post``, etc.)

.. change:: CLI: Don't call ``rich_click.patch`` if ``rich_click`` is installed
:type: bugfix
:pr: 3570
:issue: 3534

Don't call ``rich_click.patch`` if ``rich_click`` is installed. As this
monkey patches click globally, it can introduce unwanted side effects. Instead,
use conditional imports to refer to the correct library.

External libraries will still be able to make use of ``rich_click`` implicitly
when it's installed by inheriting from ``LitestarGroup`` /
``LitestarExtensionGroup``, which they will by default.


.. change:: Correctly handle ``typing.NewType``
:type: bugfix
:pr: 3580

When encountering a :class:`typing.NewType` during OpenAPI schema generation,
we currently treat it as an opaque type. This PR changes the behaviour such
that :class`typing.NewType`s are always unwrapped during schema generation.

.. change:: Encode response content object returned from an exception handler.
:type: bugfix
:pr: 3585

When an handler raises an exception and exception handler returns a Response
with a model (e.g. pydantic) object, ensure that object can be encoded as when
returning data from a regular handler.


.. changelog:: 2.9.0
:date: 2024-06-02

Expand Down
25 changes: 18 additions & 7 deletions docs/usage/logging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Application and request level loggers can be configured using the :class:`~lites
formatters={
"standard": {"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"}
},
log_exceptions="always",
)
app = Litestar(route_handlers=[my_router_handler], logging_config=logging_config)
Expand All @@ -32,12 +33,21 @@ Application and request level loggers can be configured using the :class:`~lites
is keyed as ``queue_listener`` in the logging configuration. The above example is using this handler,
which is optimal for async applications. Make sure to use it in your own loggers as in the above example.

.. attention::

Exceptions won't be logged by default, except in debug mode. Make sure to use ``log_exceptions="always"`` as in the
example above to log exceptions if you need it.


Using Python standard library
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Standard Library Logging (Manual Configuration)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`logging <https://docs.python.org/3/howto/logging.html>`_ is Python's builtin standard logging library and can be
configured through ``LoggingConfig``.

`logging <https://docs.python.org/3/howto/logging.html>`_ is Python's builtin standard logging library and can be integrated with `LoggingConfig` as the `root` logging. By using `logging_config()()` you can build a `logger` to be used around your project.
The ``LoggingConfig.configure()`` method returns a reference to ``logging.getLogger`` which can be used to access a
logger instance. Thus, the root logger can retrieved with ``logging_config.configure()()`` as shown in the example
below:

.. code-block:: python
Expand All @@ -47,10 +57,11 @@ Standard Library Logging (Manual Configuration)
from litestar.logging import LoggingConfig
logging_config = LoggingConfig(
root={"level": logging.getLevelName(logging.INFO), "handlers": ["console"]},
root={"level": "INFO", "handlers": ["queue_listener"]},
formatters={
"standard": {"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"}
},
log_exceptions="always",
)
logger = logging_config.configure()()
Expand All @@ -67,7 +78,7 @@ Standard Library Logging (Manual Configuration)
logging_config=logging_config,
)
The above example is the same as using logging without the litestar LoggingConfig.
The above example is the same as using logging without the litestar ``LoggingConfig``.

.. code-block:: python
Expand Down Expand Up @@ -112,8 +123,8 @@ the part of the user. That is, if ``picologging`` is present the previous exampl
Using StructLog
^^^^^^^^^^^^^^^

`StructLog <https://www.structlog.org/en/stable/>`_ is a powerful structured-logging library. Litestar ships with a dedicated
logging plugin and config for using it:
`StructLog <https://www.structlog.org/en/stable/>`_ is a powerful structured-logging library. Litestar ships with a
dedicated logging plugin and config for using it:

.. code-block:: python
Expand Down
14 changes: 13 additions & 1 deletion litestar/_openapi/schema_generation/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
from litestar.utils.typing import (
get_origin_or_inner_type,
make_non_optional_union,
unwrap_new_type,
)

if TYPE_CHECKING:
Expand Down Expand Up @@ -325,7 +326,9 @@ def for_field_definition(self, field_definition: FieldDefinition) -> Schema | Re

result: Schema | Reference

if plugin_for_annotation := self.get_plugin_for(field_definition):
if field_definition.is_new_type:
result = self.for_new_type(field_definition)
elif plugin_for_annotation := self.get_plugin_for(field_definition):
result = self.for_plugin(field_definition, plugin_for_annotation)
elif _should_create_enum_schema(field_definition):
annotation = _type_or_first_not_none_inner_type(field_definition)
Expand Down Expand Up @@ -354,6 +357,15 @@ def for_field_definition(self, field_definition: FieldDefinition) -> Schema | Re

return self.process_schema_result(field_definition, result) if isinstance(result, Schema) else result

def for_new_type(self, field_definition: FieldDefinition) -> Schema | Reference:
return self.for_field_definition(
FieldDefinition.from_kwarg(
annotation=unwrap_new_type(field_definition.raw),
name=field_definition.name,
default=field_definition.default,
)
)

@staticmethod
def for_upload_file(field_definition: FieldDefinition) -> Schema:
"""Create schema for UploadFile.
Expand Down
31 changes: 12 additions & 19 deletions litestar/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,19 @@

from importlib.util import find_spec

# Ensure `rich_click` patching occurs before we do any imports from `click`.
if find_spec("rich_click") is not None: # pragma: no cover
import rich_click as click

try:
from rich_click.patch import patch as rich_click_patch
except ImportError:
from rich_click.cli import patch as rich_click_patch

rich_click_patch()
click.rich_click.USE_RICH_MARKUP = True
click.rich_click.USE_MARKDOWN = False
click.rich_click.SHOW_ARGUMENTS = True
click.rich_click.GROUP_ARGUMENTS_OPTIONS = True
click.rich_click.STYLE_ERRORS_SUGGESTION = "magenta italic"
click.rich_click.ERRORS_SUGGESTION = ""
click.rich_click.ERRORS_EPILOGUE = ""
click.rich_click.MAX_WIDTH = 80
click.rich_click.SHOW_METAVARS_COLUMN = True
click.rich_click.APPEND_METAVARS_HELP = True
import rich_click

rich_click.rich_click.USE_RICH_MARKUP = True
rich_click.rich_click.USE_MARKDOWN = False
rich_click.rich_click.SHOW_ARGUMENTS = True
rich_click.rich_click.GROUP_ARGUMENTS_OPTIONS = True
rich_click.rich_click.STYLE_ERRORS_SUGGESTION = "magenta italic"
rich_click.rich_click.ERRORS_SUGGESTION = ""
rich_click.rich_click.ERRORS_EPILOGUE = ""
rich_click.rich_click.MAX_WIDTH = 80
rich_click.rich_click.SHOW_METAVARS_COLUMN = True
rich_click.rich_click.APPEND_METAVARS_HELP = True


from .main import litestar_group
Expand Down
14 changes: 10 additions & 4 deletions litestar/cli/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@
from pathlib import Path
from typing import TYPE_CHECKING, Any, Callable, Generator, Iterable, Sequence, TypeVar, cast

from click import ClickException, Command, Context, Group, pass_context
try:
from rich_click import RichCommand as Command
from rich_click import RichGroup as Group
except ImportError:
from click import Command, Group # type: ignore[assignment]

from click import ClickException, Context, pass_context
from rich import get_console
from rich.table import Table
from typing_extensions import ParamSpec, get_type_hints
Expand Down Expand Up @@ -128,7 +134,7 @@ class LoadedApp:
is_factory: bool


class LitestarGroup(Group):
class LitestarGroup(Group): # pyright: ignore
""":class:`click.Group` subclass that automatically injects ``app`` and ``env` kwargs into commands that request it.
Use this as the ``cls`` for :class:`click.Group` if you're extending the internal CLI with a group. For ``command``s
Expand All @@ -145,7 +151,7 @@ def __init__(
self.group_class = LitestarGroup
super().__init__(name=name, commands=commands, **attrs)

def add_command(self, cmd: Command, name: str | None = None) -> None:
def add_command(self, cmd: Command, name: str | None = None) -> None: # type: ignore[override]
"""Add command.
If necessary, inject ``app`` and ``env`` kwargs
Expand Down Expand Up @@ -207,7 +213,7 @@ def _prepare(self, ctx: Context) -> None:

self._prepare_done = True

def make_context(
def make_context( # type: ignore[override]
self,
info_name: str | None,
args: list[str],
Expand Down
Loading

0 comments on commit 4e1a021

Please sign in to comment.