Skip to content

Commit

Permalink
chore: Fix warnings in test suite (#3440)
Browse files Browse the repository at this point in the history
* Replace utcfromtimestamp
* Fix DTO codegen feature flag warning
* Ignore piccolo max_length warning
* Fix monkeypatch env non-string
* Ignore warn_pdb_on_exception
* Ignore external DeprecationWarnings for datetime.datetime.utcnow:
* Fix sync_to_thread warning
  • Loading branch information
provinzkraut authored Apr 27, 2024
1 parent 4d29b16 commit 170bd06
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 93 deletions.
2 changes: 1 addition & 1 deletion docs/examples/request_data/custom_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def __init__(self, scope: Scope, receive: Receive = empty_receive, send: Send =
self.kitten_name = KITTEN_NAMES_MAP.get(scope["method"], "Mittens")


@get(path="/kitten-name")
@get(path="/kitten-name", sync_to_thread=False)
def get_kitten_name(request: CustomRequest) -> str:
"""Get kitten name based on the HTTP method."""
return request.kitten_name
Expand Down
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ exclude_lines = [
'if VERSION.startswith("1"):',
'if pydantic.VERSION.startswith("1"):',
]
fail_under = 96
fail_under = 50

[tool.pytest.ini_options]
addopts = "--strict-markers --strict-config --dist=loadgroup -m 'not server_integration'"
Expand All @@ -216,6 +216,10 @@ filterwarnings = [
"ignore::pydantic.PydanticDeprecatedSince20::",
"ignore:`general_plain_validator_function`:DeprecationWarning::",
"ignore: 'RichMultiCommand':DeprecationWarning::", # this is coming from rich_click itself, nothing we can do about # that for now
"ignore: Dropping max_length:litestar.exceptions.LitestarWarning:litestar.contrib.piccolo",
"ignore: Python Debugger on exception enabled:litestar.exceptions.LitestarWarning:",
"ignore: datetime.datetime.utcnow:DeprecationWarning:time_machine",
"ignore: datetime.datetime.utcnow:DeprecationWarning:jose",
]
markers = [
"sqlalchemy_integration: SQLAlchemy integration tests",
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_cli/test_core_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ def test_run_command_arguments_precedence(
if isinstance(env_value, list):
monkeypatch.setenv(env_name, "".join(env_value))
else:
monkeypatch.setenv(env_name, env_value) # type: ignore[arg-type] # pyright: ignore (reportGeneralTypeIssues)
monkeypatch.setenv(env_name, str(env_value))

if cli_name:
if cli_value is True:
Expand Down
10 changes: 10 additions & 0 deletions tests/unit/test_contrib/test_pydantic/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,19 @@
from pydantic import v1 as pydantic_v1
from pytest import FixtureRequest

from litestar.contrib.pydantic.pydantic_init_plugin import ( # type: ignore[attr-defined]
_KWARG_META_EXTRACTORS,
ConstrainedFieldMetaExtractor,
)

from . import PydanticVersion


@pytest.fixture(autouse=True, scope="session")
def ensure_metadata_extractor_is_added() -> None:
_KWARG_META_EXTRACTORS.add(ConstrainedFieldMetaExtractor)


@pytest.fixture(params=["v1", "v2"])
def pydantic_version(request: FixtureRequest) -> PydanticVersion:
return request.param # type: ignore[no-any-return]
Expand Down
62 changes: 45 additions & 17 deletions tests/unit/test_contrib/test_pydantic/test_openapi.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import date, datetime, timedelta
from datetime import date, datetime, timedelta, timezone
from decimal import Decimal
from types import ModuleType
from typing import Any, Callable, Pattern, Type, Union, cast
Expand Down Expand Up @@ -257,17 +257,29 @@ def test_create_date_constrained_field_schema_pydantic_v1(annotation: Any) -> No
schema = create_date_constrained_field_schema(field_definition.annotation, field_definition.kwarg_definition)
assert schema.type == OpenAPIType.STRING
assert schema.format == OpenAPIFormat.DATE
assert (datetime.utcfromtimestamp(schema.exclusive_minimum) if schema.exclusive_minimum else None) == (
datetime.fromordinal(annotation.gt.toordinal()) if annotation.gt is not None else None
assert (
datetime.fromtimestamp(schema.exclusive_minimum, tz=timezone.utc) if schema.exclusive_minimum else None
) == (
datetime.fromordinal(annotation.gt.toordinal()).replace(tzinfo=timezone.utc)
if annotation.gt is not None
else None
)
assert (datetime.utcfromtimestamp(schema.minimum) if schema.minimum else None) == (
datetime.fromordinal(annotation.ge.toordinal()) if annotation.ge is not None else None
assert (datetime.fromtimestamp(schema.minimum, tz=timezone.utc) if schema.minimum else None) == (
datetime.fromordinal(annotation.ge.toordinal()).replace(tzinfo=timezone.utc)
if annotation.ge is not None
else None
)
assert (datetime.utcfromtimestamp(schema.exclusive_maximum) if schema.exclusive_maximum else None) == (
datetime.fromordinal(annotation.lt.toordinal()) if annotation.lt is not None else None
assert (
datetime.fromtimestamp(schema.exclusive_maximum, tz=timezone.utc) if schema.exclusive_maximum else None
) == (
datetime.fromordinal(annotation.lt.toordinal()).replace(tzinfo=timezone.utc)
if annotation.lt is not None
else None
)
assert (datetime.utcfromtimestamp(schema.maximum) if schema.maximum else None) == (
datetime.fromordinal(annotation.le.toordinal()) if annotation.le is not None else None
assert (datetime.fromtimestamp(schema.maximum, tz=timezone.utc) if schema.maximum else None) == (
datetime.fromordinal(annotation.le.toordinal()).replace(tzinfo=timezone.utc)
if annotation.le is not None
else None
)


Expand All @@ -280,26 +292,42 @@ def test_create_date_constrained_field_schema_pydantic_v2(annotation: Any) -> No
assert schema.type == OpenAPIType.STRING
assert schema.format == OpenAPIFormat.DATE
assert any(
(datetime.fromordinal(getattr(m, "gt", None).toordinal()) if getattr(m, "gt", None) is not None else None) # type: ignore[union-attr]
== (datetime.utcfromtimestamp(schema.exclusive_minimum) if schema.exclusive_minimum else None)
(
datetime.fromordinal(getattr(m, "gt", None).toordinal()).replace(tzinfo=timezone.utc) # type: ignore[union-attr]
if getattr(m, "gt", None) is not None
else None
)
== (datetime.fromtimestamp(schema.exclusive_minimum, tz=timezone.utc) if schema.exclusive_minimum else None)
for m in field_definition.metadata
if m
)
assert any(
(datetime.fromordinal(getattr(m, "ge", None).toordinal()) if getattr(m, "ge", None) is not None else None) # type: ignore[union-attr]
== (datetime.utcfromtimestamp(schema.minimum) if schema.minimum else None)
(
datetime.fromordinal(getattr(m, "ge", None).toordinal()).replace(tzinfo=timezone.utc) # type: ignore[union-attr]
if getattr(m, "ge", None) is not None
else None
)
== (datetime.fromtimestamp(schema.minimum, tz=timezone.utc) if schema.minimum else None)
for m in field_definition.metadata
if m
)
assert any(
(datetime.fromordinal(getattr(m, "lt", None).toordinal()) if getattr(m, "lt", None) is not None else None) # type: ignore[union-attr]
== (datetime.utcfromtimestamp(schema.exclusive_maximum) if schema.exclusive_maximum else None)
(
datetime.fromordinal(getattr(m, "lt", None).toordinal()).replace(tzinfo=timezone.utc) # type: ignore[union-attr]
if getattr(m, "lt", None) is not None
else None
)
== (datetime.fromtimestamp(schema.exclusive_maximum, tz=timezone.utc) if schema.exclusive_maximum else None)
for m in field_definition.metadata
if m
)
assert any(
(datetime.fromordinal(getattr(m, "le", None).toordinal()) if getattr(m, "le", None) is not None else None) # type: ignore[union-attr]
== (datetime.utcfromtimestamp(schema.maximum) if schema.maximum else None)
(
datetime.fromordinal(getattr(m, "le", None).toordinal()).replace(tzinfo=timezone.utc) # type: ignore[union-attr]
if getattr(m, "le", None) is not None
else None
)
== (datetime.fromtimestamp(schema.maximum, tz=timezone.utc) if schema.maximum else None)
for m in field_definition.metadata
if m
)
Expand Down
6 changes: 4 additions & 2 deletions tests/unit/test_dto/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from litestar import Request, get
from litestar._openapi.schema_generation import SchemaCreator
from litestar.dto import AbstractDTO, DTOField, DTOFieldDefinition
from litestar.dto import AbstractDTO, DTOConfig, DTOField, DTOFieldDefinition
from litestar.enums import MediaType
from litestar.openapi.spec import Reference, Schema
from litestar.testing import RequestFactory
Expand All @@ -20,8 +20,10 @@


@pytest.fixture
def ModelDataDTO() -> type[AbstractDTO]:
def ModelDataDTO(use_experimental_dto_backend: bool) -> type[AbstractDTO]:
class DTOCls(AbstractDTO[Model]):
config = DTOConfig(experimental_codegen_backend=use_experimental_dto_backend)

def decode_builtins(self, value: Any) -> Model:
return Model(a=1, b="2")

Expand Down
77 changes: 13 additions & 64 deletions tests/unit/test_dto/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,27 @@
from typing import Dict
from unittest.mock import MagicMock

import pytest

from litestar import Controller, Litestar, Router, post
from litestar.config.app import ExperimentalFeatures
from litestar.dto import AbstractDTO, DTOConfig
from litestar.dto._backend import DTOBackend
from litestar.dto._codegen_backend import DTOCodegenBackend
from litestar.testing import create_test_client

from . import Model


@pytest.fixture()
def experimental_features(use_experimental_dto_backend: bool) -> list[ExperimentalFeatures] | None:
if use_experimental_dto_backend:
return [ExperimentalFeatures.DTO_CODEGEN]
return None


def test_dto_defined_on_handler(
ModelDataDTO: type[AbstractDTO], experimental_features: list[ExperimentalFeatures]
) -> None:
def test_dto_defined_on_handler(ModelDataDTO: type[AbstractDTO]) -> None:
@post(dto=ModelDataDTO, signature_types=[Model])
def handler(data: Model) -> Model:
assert data == Model(a=1, b="2")
return data

with create_test_client(route_handlers=handler, experimental_features=experimental_features) as client:
with create_test_client(route_handlers=handler) as client:
response = client.post("/", json={"what": "ever"})
assert response.status_code == 201
assert response.json() == {"a": 1, "b": "2"}


def test_dto_defined_on_controller(
ModelDataDTO: type[AbstractDTO], experimental_features: list[ExperimentalFeatures]
) -> None:
def test_dto_defined_on_controller(ModelDataDTO: type[AbstractDTO]) -> None:
class MyController(Controller):
dto = ModelDataDTO

Expand All @@ -47,109 +32,73 @@ def handler(self, data: Model) -> Model:
assert data == Model(a=1, b="2")
return data

with create_test_client(route_handlers=MyController, experimental_features=experimental_features) as client:
with create_test_client(route_handlers=MyController) as client:
response = client.post("/", json={"what": "ever"})
assert response.status_code == 201
assert response.json() == {"a": 1, "b": "2"}


def test_dto_defined_on_router(
ModelDataDTO: type[AbstractDTO], experimental_features: list[ExperimentalFeatures]
) -> None:
def test_dto_defined_on_router(ModelDataDTO: type[AbstractDTO]) -> None:
@post()
def handler(data: Model) -> Model:
assert data == Model(a=1, b="2")
return data

router = Router(path="/", route_handlers=[handler], dto=ModelDataDTO)

with create_test_client(route_handlers=router, experimental_features=experimental_features) as client:
with create_test_client(route_handlers=router) as client:
response = client.post("/", json={"what": "ever"})
assert response.status_code == 201
assert response.json() == {"a": 1, "b": "2"}


def test_dto_defined_on_app(ModelDataDTO: type[AbstractDTO], experimental_features: list[ExperimentalFeatures]) -> None:
def test_dto_defined_on_app(ModelDataDTO: type[AbstractDTO]) -> None:
@post()
def handler(data: Model) -> Model:
assert data == Model(a=1, b="2")
return data

with create_test_client(
route_handlers=handler, dto=ModelDataDTO, experimental_features=experimental_features
) as client:
with create_test_client(route_handlers=handler, dto=ModelDataDTO) as client:
response = client.post("/", json={"what": "ever"})
assert response.status_code == 201
assert response.json() == {"a": 1, "b": "2"}


def test_set_dto_none_disables_inherited_dto(
ModelDataDTO: type[AbstractDTO], experimental_features: list[ExperimentalFeatures]
) -> None:
def test_set_dto_none_disables_inherited_dto(ModelDataDTO: type[AbstractDTO]) -> None:
@post(dto=None, signature_namespace={"dict": Dict})
def handler(data: dict[str, str]) -> dict[str, str]:
assert data == {"hello": "world"}
return data

mock_dto = MagicMock(spec=ModelDataDTO)

with create_test_client(
route_handlers=handler,
dto=mock_dto, # pyright:ignore
experimental_features=experimental_features,
) as client:
with create_test_client(route_handlers=handler, dto=mock_dto) as client: # pyright:ignore
response = client.post("/", json={"hello": "world"})
assert response.status_code == 201
assert response.json() == {"hello": "world"}
mock_dto.assert_not_called()


def test_dto_and_return_dto(
ModelDataDTO: type[AbstractDTO],
ModelReturnDTO: type[AbstractDTO],
experimental_features: list[ExperimentalFeatures],
) -> None:
def test_dto_and_return_dto(ModelDataDTO: type[AbstractDTO], ModelReturnDTO: type[AbstractDTO]) -> None:
@post()
def handler(data: Model) -> Model:
assert data == Model(a=1, b="2")
return data

with create_test_client(
route_handlers=handler, dto=ModelDataDTO, return_dto=ModelReturnDTO, experimental_features=experimental_features
) as client:
with create_test_client(route_handlers=handler, dto=ModelDataDTO, return_dto=ModelReturnDTO) as client:
response = client.post("/", json={"what": "ever"})
assert response.status_code == 201
assert response.json() == {"a": 1, "b": "2"}


def test_enable_experimental_backend(ModelDataDTO: type[AbstractDTO], use_experimental_dto_backend: bool) -> None:
@post(dto=ModelDataDTO, signature_types=[Model])
def handler(data: Model) -> Model:
return data

Litestar(
route_handlers=[handler],
experimental_features=[ExperimentalFeatures.DTO_CODEGEN] if use_experimental_dto_backend else None,
)

backend = handler.resolve_data_dto()._dto_backends[handler.handler_id]["data_backend"] # type: ignore[union-attr]
if use_experimental_dto_backend:
assert isinstance(backend, DTOCodegenBackend)
else:
assert isinstance(backend, DTOBackend)


def test_enable_experimental_backend_override_in_dto_config(ModelDataDTO: type[AbstractDTO]) -> None:
ModelDataDTO.config = DTOConfig(experimental_codegen_backend=False)

@post(dto=ModelDataDTO, signature_types=[Model])
def handler(data: Model) -> Model:
return data

Litestar(
route_handlers=[handler],
experimental_features=[ExperimentalFeatures.DTO_CODEGEN],
)
Litestar(route_handlers=[handler])

backend = handler.resolve_data_dto()._dto_backends[handler.handler_id]["data_backend"] # type: ignore[union-attr]
assert isinstance(backend, DTOBackend)
Expand Down
16 changes: 9 additions & 7 deletions tests/unit/test_openapi/test_schema.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import sys
from dataclasses import dataclass
from datetime import date, datetime
from datetime import date, datetime, timezone
from enum import Enum, auto
from typing import ( # type: ignore[attr-defined]
TYPE_CHECKING,
Expand Down Expand Up @@ -317,12 +317,14 @@ class MyDataclass:
assert schema.properties["constrained_int"].exclusive_maximum == 10 # type: ignore[index, union-attr]
assert schema.properties["constrained_float"].minimum == 1 # type: ignore[index, union-attr]
assert schema.properties["constrained_float"].maximum == 10 # type: ignore[index, union-attr]
assert datetime.utcfromtimestamp(schema.properties["constrained_date"].exclusive_minimum) == datetime.fromordinal( # type: ignore[arg-type, index, union-attr]
historical_date.toordinal()
)
assert datetime.utcfromtimestamp(schema.properties["constrained_date"].exclusive_maximum) == datetime.fromordinal( # type: ignore[arg-type, index, union-attr]
today.toordinal()
)
assert datetime.fromtimestamp(
schema.properties["constrained_date"].exclusive_minimum, # type: ignore[arg-type, index, union-attr]
tz=timezone.utc,
) == datetime.fromordinal(historical_date.toordinal()).replace(tzinfo=timezone.utc)
assert datetime.fromtimestamp(
schema.properties["constrained_date"].exclusive_maximum, # type: ignore[arg-type, index, union-attr]
tz=timezone.utc,
) == datetime.fromordinal(today.toordinal()).replace(tzinfo=timezone.utc)
assert schema.properties["constrained_lower_case"].description == "must be in lower case" # type: ignore[index]
assert schema.properties["constrained_upper_case"].description == "must be in upper case" # type: ignore[index]
assert schema.properties["constrained_is_ascii"].pattern == "[[:ascii:]]" # type: ignore[index, union-attr]
Expand Down

0 comments on commit 170bd06

Please sign in to comment.