Skip to content

Commit

Permalink
feat: add support for [email protected] (#2396)
Browse files Browse the repository at this point in the history
* feat: add support for `[email protected]`

* chore: remove prerelease

- chore: apply suggestions

* fix(ci): fix weird thing

* Revert "chore: remove prerelease"

This reverts commit a6082f4

* feat: 3.12

* Compat for changes to QueueListener/QueueHandler config.

* Fix for test modifying global state.

* Fix test assertions.

* xfail for 3.12

* fix formatting

* fix xfail for parametrized test

* fixes for structlog logic.

Something seems to have changed in the way `isinstance()` proxies through from `BoundLoggerLazyProxy` to `BoundLogger`.

* Update pyproject.toml

Co-authored-by: Peter Schutt <[email protected]>

---------

Co-authored-by: Peter Schutt <[email protected]>
  • Loading branch information
JacobCoffee and peterschutt authored Oct 15, 2023
1 parent 999776a commit b6fc70c
Show file tree
Hide file tree
Showing 13 changed files with 57 additions and 42 deletions.
14 changes: 8 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ jobs:

- uses: actions/setup-python@v4
with:
python-version: "3.11"
python-version: "3.12"
allow-prereleases: true

- name: Install Pre-Commit
run: python -m pip install pre-commit && pre-commit install
Expand All @@ -35,11 +36,11 @@ jobs:
strategy:
fail-fast: true
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
pydantic-version: ["1", "2"]
uses: ./.github/workflows/test.yml
with:
coverage: ${{ matrix.python-version == '3.11' && matrix.pydantic-version == '2' }}
coverage: ${{ matrix.python-version == '3.12' && matrix.pydantic-version == '2' }}
pydantic-version: ${{ matrix.pydantic-version }}
python-version: ${{ matrix.python-version }}

Expand All @@ -51,7 +52,7 @@ jobs:
os: ["macos-latest", "windows-latest"]
uses: ./.github/workflows/test.yml
with:
python-version: "3.11"
python-version: "3.12"
pydantic-version: "2"
os: ${{ matrix.os }}

Expand Down Expand Up @@ -109,12 +110,13 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.11"
python-version: "3.12"
allow-prereleases: true

- uses: pdm-project/setup-pdm@v3
name: Set up PDM
with:
python-version: "3.11"
python-version: "3.12"
allow-python-prereleases: false
cache: true
cache-dependency-path: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:

- uses: actions/setup-python@v4
with:
python-version: "3.11"
python-version: "3.12"

- uses: pdm-project/setup-pdm@v3
name: Set up PDM
Expand Down
11 changes: 5 additions & 6 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ jobs:
name: Test Minimal Application with Base Dependencies
runs-on: ubuntu-latest
env:
python_version: "3.11"
python_version: "3.12"
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.11"
python-version: "3.12"

- uses: pdm-project/setup-pdm@v3
name: Set up PDM
with:
python-version: "3.11"
python-version: "3.12"
allow-python-prereleases: false
cache: true
cache-dependency-path: |
Expand All @@ -50,13 +50,12 @@ jobs:

- uses: actions/setup-python@v4
with:
python-version: "3.11"
python-version: "3.12"

- uses: pdm-project/setup-pdm@v3
name: Set up PDM
with:
python-version: "3.11"
allow-python-prereleases: false
python-version: "3.12"
cache: true

- name: Build package
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
default_language_version:
python: "3.11"
python: "3.12"
repos:
- repo: https://github.com/compilerla/conventional-pre-commit
rev: v2.4.0
Expand Down
2 changes: 1 addition & 1 deletion litestar/logging/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"class": "litestar.logging.standard.QueueListenerHandler",
"level": "DEBUG",
"formatter": "standard",
"handlers": ["console"],
},
}

Expand Down Expand Up @@ -327,7 +328,6 @@ def configure(self) -> GetLogger:

from structlog import configure, get_logger

# we now configure structlog
configure(
**{
k: v
Expand Down
30 changes: 18 additions & 12 deletions litestar/logging/standard.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import atexit
import sys
from logging import StreamHandler
from logging.handlers import QueueHandler, QueueListener
from queue import Queue
Expand All @@ -11,18 +12,23 @@
__all__ = ("QueueListenerHandler",)


class QueueListenerHandler(QueueHandler):
"""Configure queue listener and handler to support non-blocking logging configuration."""
if sys.version_info < (3, 12):

def __init__(self, handlers: list[Any] | None = None) -> None:
"""Initialize `?QueueListenerHandler`.
class QueueListenerHandler(QueueHandler):
"""Configure queue listener and handler to support non-blocking logging configuration."""

Args:
handlers: Optional 'ConvertingList'
"""
super().__init__(Queue(-1))
handlers = resolve_handlers(handlers) if handlers else [StreamHandler()]
self.listener = QueueListener(self.queue, *handlers)
self.listener.start()
def __init__(self, handlers: list[Any] | None = None) -> None:
"""Initialize `?QueueListenerHandler`.
atexit.register(self.listener.stop)
Args:
handlers: Optional 'ConvertingList'
"""
super().__init__(Queue(-1))
handlers = resolve_handlers(handlers) if handlers else [StreamHandler()]
self.listener = QueueListener(self.queue, *handlers)
self.listener.start()

atexit.register(self.listener.stop)

else:
QueueListenerHandler = QueueHandler
2 changes: 1 addition & 1 deletion litestar/middleware/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
"""
if not hasattr(self, "logger"):
self.logger = scope["app"].get_logger(self.config.logger_name)
self.is_struct_logger = structlog_installed and isinstance(self.logger, BindableLogger)
self.is_struct_logger = structlog_installed and repr(self.logger).startswith("<BoundLoggerLazyProxy")

if self.config.response_log_fields:
send = self.create_send_wrapper(scope=scope, send=send)
Expand Down
2 changes: 1 addition & 1 deletion pdm.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Software Development :: Libraries",
Expand Down Expand Up @@ -72,7 +73,7 @@ Twitter = "https://twitter.com/LitestarAPI"
annotated-types = ["annotated-types"]
attrs = ["attrs"]
brotli = ["brotli"]
cli = ["jsbeautifier", "uvicorn[standard]"]
cli = ["jsbeautifier", "uvicorn[standard]", "uvloop>=0.18.0"]
cryptography = ["cryptography"]
full = [
"litestar[annotated-types,attrs,brotli,cli,cryptography,jinja,jwt,mako,minijinja,opentelemetry,piccolo,picologging,prometheus,pydantic,redis,sqlalchemy,standard,structlog]",
Expand All @@ -88,7 +89,7 @@ prometheus = ["prometheus-client"]
pydantic = ["pydantic[email]", "pydantic-extra-types"]
redis = ["redis[hiredis]>=4.4.4"]
sqlalchemy = ["advanced-alchemy>=0.2.2,<0.4.0"]
standard = ["jinja2", "jsbeautifier", "uvicorn[standard]", "fast-query-parsers>=1.0.2"]
standard = ["jinja2", "jsbeautifier", "uvicorn[standard]", "uvloop>=0.18.0", "fast-query-parsers>=1.0.2"]
structlog = ["structlog"]

[tool.pdm.dev-dependencies]
Expand Down
2 changes: 1 addition & 1 deletion sonar-project.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
sonar.organization=litestar-api
sonar.projectKey=litestar-org_litestar
sonar.python.coverage.reportPaths=coverage.xml
sonar.python.version=3.8, 3.9, 3.10, 3.11
sonar.python.version=3.8, 3.9, 3.10, 3.11, 3.12
sonar.sourceEncoding=UTF-8
sonar.sources=litestar
sonar.tests=tests
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/test_cli/test_session_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def test_delete_session(

result = runner.invoke(cli_command, ["sessions", "delete", "foo"])

assert mock_confirm_ask.called_once_with("[red]Delete session 'foo'?")
mock_confirm_ask.assert_called_once_with("Delete session 'foo'?")
assert not result.exception
mock_delete.assert_called_once_with("foo")

Expand Down Expand Up @@ -78,6 +78,6 @@ def test_clear_sessions(

result = runner.invoke(cli_command, ["sessions", "clear"])

assert mock_confirm_ask.called_once_with("[red]Delete all sessions?")
mock_confirm_ask.assert_called_once_with("[red]Delete all sessions?")
assert not result.exception
mock_delete.assert_called_once()
13 changes: 10 additions & 3 deletions tests/unit/test_logging/test_logging_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import sys
from typing import TYPE_CHECKING, Any, Dict
from unittest.mock import Mock, patch

Expand Down Expand Up @@ -144,12 +145,18 @@ def test_root_logger(handlers: Any, listener: Any) -> None:
@pytest.mark.parametrize(
"handlers, listener",
[
[default_handlers, StandardQueueListenerHandler],
pytest.param(
default_handlers,
StandardQueueListenerHandler,
marks=pytest.mark.xfail(
condition=sys.version_info >= (3, 12), reason="change to QueueHandler/QueueListener config in 3.12"
),
),
[default_picologging_handlers, PicologgingQueueListenerHandler],
],
)
def test_customizing_handler(handlers: Any, listener: Any) -> None:
handlers["queue_listener"]["handlers"] = ["cfg://handlers.console"]
def test_customizing_handler(handlers: Any, listener: Any, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setitem(handlers["queue_listener"], "handlers", ["cfg://handlers.console"])

logging_config = LoggingConfig(handlers=handlers)
get_logger = logging_config.configure()
Expand Down
10 changes: 5 additions & 5 deletions tests/unit/test_logging/test_structlog_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
def test_structlog_config_default(capsys: CaptureFixture) -> None:
with create_test_client([], logging_config=StructLoggingConfig()) as client:
assert client.app.logger
assert isinstance(client.app.logger, BindableLogger)
client.app.logger.info("message", key="value") # type: ignore [attr-defined]
assert isinstance(client.app.logger.bind(), BindableLogger)
client.app.logger.info("message", key="value")

log_messages = [decode_json(value=x) for x in capsys.readouterr().out.splitlines()]
assert len(log_messages) == 1
Expand All @@ -29,11 +29,11 @@ def test_structlog_config_specify_processors(capsys: CaptureFixture) -> None:

with create_test_client([], logging_config=logging_config) as client:
assert client.app.logger
assert isinstance(client.app.logger, BindableLogger)
assert isinstance(client.app.logger.bind(), BindableLogger)

client.app.logger.info("message1", key="value1") # type: ignore [attr-defined]
client.app.logger.info("message1", key="value1")
# Log twice to make sure issue #882 doesn't appear again
client.app.logger.info("message2", key="value2") # type: ignore [attr-defined]
client.app.logger.info("message2", key="value2")

log_messages = [decode_json(value=x) for x in capsys.readouterr().out.splitlines()]

Expand Down

0 comments on commit b6fc70c

Please sign in to comment.