Skip to content

Commit

Permalink
👽️(project) replace deprecated parse_obj_as
Browse files Browse the repository at this point in the history
Replace soon-to-be-deprecated `parse_obj_as` with `TypeAdapter` after Pydantic
V2 migration.
  • Loading branch information
wilbrdt committed Apr 19, 2024
1 parent db52c78 commit 3c1b731
Show file tree
Hide file tree
Showing 9 changed files with 34 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to

- Upgrade `pydantic` to `2.7.0`
- Migrate model tests from hypothesis strategies to polyfactory
- Replace soon-to-be deprecated `parse_obj_as` with `TypeAdapter`

## [4.2.0] - 2024-04-08

Expand Down
4 changes: 2 additions & 2 deletions src/ralph/backends/data/async_lrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from urllib.parse import ParseResult, parse_qs, urljoin, urlparse

from httpx import AsyncClient, HTTPError, HTTPStatusError, RequestError
from pydantic import AnyHttpUrl, PositiveInt, parse_obj_as
from pydantic import AnyHttpUrl, PositiveInt, TypeAdapter

from ralph.backends.data.base import (
AsyncWritable,
Expand Down Expand Up @@ -44,7 +44,7 @@ def __init__(self, settings: Optional[LRSDataBackendSettings] = None) -> None:
If `settings` is `None`, a default settings instance is used instead.
"""
super().__init__(settings)
self.base_url = parse_obj_as(AnyHttpUrl, self.settings.BASE_URL)
self.base_url = TypeAdapter(AnyHttpUrl).validate_python(self.settings.BASE_URL)
self.auth = (self.settings.USERNAME, self.settings.PASSWORD)
self._client = None

Expand Down
10 changes: 8 additions & 2 deletions src/ralph/backends/data/lrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@
from urllib.parse import ParseResult, parse_qs, urljoin, urlparse

from httpx import Client, HTTPError, HTTPStatusError, RequestError
from pydantic import AnyHttpUrl, BaseModel, Field, PositiveInt, parse_obj_as
from pydantic import (
AnyHttpUrl,
BaseModel,
Field,
PositiveInt,
TypeAdapter,
)
from pydantic_settings import SettingsConfigDict
from typing_extensions import Annotated

Expand Down Expand Up @@ -90,7 +96,7 @@ def __init__(self, settings: Optional[LRSDataBackendSettings] = None) -> None:
If `settings` is `None`, a default settings instance is used instead.
"""
super().__init__(settings)
self.base_url = parse_obj_as(AnyHttpUrl, self.settings.BASE_URL)
self.base_url = TypeAdapter(AnyHttpUrl).validate_python(self.settings.BASE_URL)
self.auth = (self.settings.USERNAME, self.settings.PASSWORD)
self._client = None

Expand Down
6 changes: 4 additions & 2 deletions src/ralph/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
ConfigDict,
Field,
StringConstraints,
TypeAdapter,
model_validator,
parse_obj_as,
)
from pydantic_settings import BaseSettings, SettingsConfigDict
from typing_extensions import Annotated
Expand Down Expand Up @@ -198,7 +198,9 @@ class Settings(BaseSettings):
},
}
PARSERS: ParserSettings = ParserSettings()
RUNSERVER_AUTH_BACKENDS: AuthBackends = parse_obj_as(AuthBackends, "Basic")
RUNSERVER_AUTH_BACKENDS: AuthBackends = TypeAdapter(AuthBackends).validate_python(
"Basic"
)
RUNSERVER_AUTH_OIDC_AUDIENCE: Optional[str] = None
RUNSERVER_AUTH_OIDC_ISSUER_URI: Optional[AnyHttpUrl] = None
RUNSERVER_BACKEND: str = "es"
Expand Down
6 changes: 4 additions & 2 deletions tests/api/auth/test_oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest
import responses
from pydantic import parse_obj_as
from pydantic import TypeAdapter

from ralph.api.auth.oidc import discover_provider, get_public_keys
from ralph.conf import AuthBackend
Expand Down Expand Up @@ -40,7 +40,9 @@ async def test_api_auth_oidc_get_whoami_valid(
assert response.status_code == 200
assert len(response.json().keys()) == 2
assert response.json()["agent"] == {"openid": "https://iss.example.com/123|oidc"}
assert parse_obj_as(BaseXapiAgentWithOpenId, response.json()["agent"])
assert TypeAdapter(BaseXapiAgentWithOpenId).validate_python(
response.json()["agent"]
)
assert sorted(response.json()["scopes"]) == ["all", "profile/read"]
assert "target" not in response.json()

Expand Down
6 changes: 4 additions & 2 deletions tests/backends/data/test_async_lrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import httpx
import pytest
from httpx import HTTPStatusError, RequestError
from pydantic import AnyHttpUrl, AnyUrl, parse_obj_as
from pydantic import AnyHttpUrl, AnyUrl, TypeAdapter
from pytest_httpx import HTTPXMock

from ralph.backends.data.async_lrs import AsyncLRSDataBackend
Expand Down Expand Up @@ -46,7 +46,9 @@ def test_backends_data_async_lrs_default_instantiation(monkeypatch, fs, lrs_back
assert backend_class.settings_class == LRSDataBackendSettings
backend = backend_class()
assert backend.query_class == LRSStatementsQuery
assert backend.base_url == parse_obj_as(AnyHttpUrl, "http://0.0.0.0:8100")
assert backend.base_url == TypeAdapter(AnyHttpUrl).validate_python(
"http://0.0.0.0:8100"
)
assert backend.auth == ("ralph", "secret")
assert backend.settings.HEADERS == LRSHeaders()
assert backend.settings.LOCALE_ENCODING == "utf8"
Expand Down
8 changes: 4 additions & 4 deletions tests/backends/data/test_async_ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import pytest
import websockets
from pydantic import AnyUrl, parse_obj_as
from pydantic import AnyUrl, TypeAdapter

from ralph.backends.data.async_ws import AsyncWSDataBackend, WSDataBackendSettings
from ralph.backends.data.base import DataBackendStatus
Expand Down Expand Up @@ -49,7 +49,7 @@ def test_backends_data_async_ws_instantiation_with_settings(monkeypatch):
uri = f"ws://{WS_TEST_HOST}:{WS_TEST_PORT}"
settings = WSDataBackendSettings(URI=uri)
backend = AsyncWSDataBackend(settings)
assert backend.settings.URI == parse_obj_as(AnyUrl, uri)
assert backend.settings.URI == TypeAdapter(AnyUrl).validate_python(uri)
assert backend.settings.LOCALE_ENCODING == "utf8"
assert backend.settings.READ_CHUNK_SIZE == 500
assert backend.settings.WRITE_CHUNK_SIZE == 500
Expand All @@ -59,7 +59,7 @@ def test_backends_data_async_ws_instantiation_with_settings(monkeypatch):
monkeypatch.setenv("RALPH_BACKENDS__DATA__WS__URI", "ws://foo")
backend = AsyncWSDataBackend()
assert backend.settings.READ_CHUNK_SIZE == 1
assert backend.settings.URI == parse_obj_as(AnyUrl, "ws://foo")
assert backend.settings.URI == TypeAdapter(AnyUrl).validate_python("ws://foo")


@pytest.mark.anyio
Expand All @@ -79,7 +79,7 @@ async def test_backends_data_async_ws_status_with_error_status(ws, events, caplo
"[Errno 111] Connect call failed ('127.0.0.1', 1)",
) in caplog.record_tuples

uri = parse_obj_as(AnyUrl, f"ws://{WS_TEST_HOST}:{WS_TEST_PORT}")
uri = TypeAdapter(AnyUrl).validate_python(f"ws://{WS_TEST_HOST}:{WS_TEST_PORT}")
settings = WSDataBackendSettings(URI=uri)
backend = AsyncWSDataBackend(settings)
assert [_ async for _ in backend.read(raw_output=False)] == events
Expand Down
4 changes: 2 additions & 2 deletions tests/fixtures/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import websockets
from elasticsearch import BadRequestError, Elasticsearch
from httpx import AsyncClient, ConnectError
from pydantic import AnyHttpUrl, parse_obj_as
from pydantic import AnyHttpUrl, TypeAdapter
from pymongo import MongoClient
from pymongo.errors import CollectionInvalid

Expand Down Expand Up @@ -313,7 +313,7 @@ def _get_lrs_test_backend(
"CONTENT_TYPE": "application/json",
}
settings = backend_class.settings_class(
BASE_URL=parse_obj_as(AnyHttpUrl, base_url),
BASE_URL=TypeAdapter(AnyHttpUrl).validate_python(base_url),
USERNAME="user",
PASSWORD="pass",
HEADERS=LRSHeaders.model_validate(headers),
Expand Down
11 changes: 5 additions & 6 deletions tests/test_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from importlib import reload

import pytest
from pydantic import ValidationError
from pydantic import TypeAdapter, ValidationError

from ralph import conf
from ralph.backends.data.es import ESDataBackend
Expand All @@ -12,7 +12,6 @@
AuthBackends,
CommaSeparatedTuple,
Settings,
parse_obj_as,
settings,
)
from ralph.exceptions import ConfigurationException
Expand Down Expand Up @@ -54,7 +53,7 @@ def test_conf_settings_field_value_priority(fs, monkeypatch):
)
def test_conf_comma_separated_list_with_valid_values(value, expected, monkeypatch):
"""Test the CommaSeparatedTuple pydantic data type with valid values."""
assert parse_obj_as(CommaSeparatedTuple, value) == expected
assert TypeAdapter(CommaSeparatedTuple).validate_python(value) == expected
monkeypatch.setenv("RALPH_BACKENDS__DATA__ES__HOSTS", "".join(value))
assert ESDataBackend().settings.HOSTS == expected

Expand All @@ -63,7 +62,7 @@ def test_conf_comma_separated_list_with_valid_values(value, expected, monkeypatc
def test_conf_comma_separated_list_with_invalid_values(value):
"""Test the CommaSeparatedTuple pydantic data type with invalid values."""
with pytest.raises(ValidationError, match="2 validation errors for function-after"):
parse_obj_as(CommaSeparatedTuple, value)
TypeAdapter(CommaSeparatedTuple).validate_python(value)


@pytest.mark.parametrize(
Expand All @@ -80,13 +79,13 @@ def test_conf_comma_separated_list_with_invalid_values(value):
def test_conf_auth_backend(value, is_valid, expected, monkeypatch):
"""Test the AuthBackends data type with valid and invalid values."""
if is_valid:
assert parse_obj_as(AuthBackends, value) == expected
assert TypeAdapter(AuthBackends).validate_python(value) == expected
monkeypatch.setenv("RALPH_RUNSERVER_AUTH_BACKENDS", "".join(value))
reload(conf)
assert conf.settings.RUNSERVER_AUTH_BACKENDS == expected
else:
with pytest.raises(ValueError, match="'notvalid' is not a valid AuthBackend"):
parse_obj_as(AuthBackends, value)
TypeAdapter(AuthBackends).validate_python(value)


def test_conf_core_settings_should_impact_settings_defaults(monkeypatch):
Expand Down

0 comments on commit 3c1b731

Please sign in to comment.