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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️Fix settings library tests #6605

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/common-library/requirements/_base.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
#
--constraint ../../../requirements/constraints.txt

orjson
pydantic
pydantic-extra-types
7 changes: 7 additions & 0 deletions packages/common-library/requirements/_base.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
annotated-types==0.7.0
# via pydantic
orjson==3.10.10
# via
# -c requirements/../../../requirements/constraints.txt
# -r requirements/_base.in
pydantic==2.9.2
# via
# -c requirements/../../../requirements/constraints.txt
# -r requirements/_base.in
# pydantic-extra-types
pydantic-core==2.23.4
# via pydantic
pydantic-extra-types==2.9.0
# via -r requirements/_base.in
typing-extensions==4.12.2
# via
# pydantic
Expand Down
97 changes: 97 additions & 0 deletions packages/common-library/tests/test_json_serialization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# pylint: disable=redefined-outer-name
# pylint: disable=unused-argument
# pylint: disable=unused-variable

import json
from copy import deepcopy
from typing import Annotated, Any, TypeAlias
from uuid import uuid4

import pytest
from common_library.json_serialization import (
JsonNamespace,
SeparatorTuple,
json_dumps,
json_loads,
)
from faker import Faker
from pydantic import Field, TypeAdapter
from pydantic.json import pydantic_encoder


@pytest.fixture
def fake_data_dict(faker: Faker) -> dict[str, Any]:
data = {
"uuid_as_UUID": faker.uuid4(cast_to=None),
"uuid_as_str": faker.uuid4(),
"int": faker.pyint(),
"float": faker.pyfloat(),
"str": faker.pystr(),
"dict": faker.pydict(),
"list": faker.pylist(),
}
data["object"] = deepcopy(data)
return data


def test_json_dump_variants():

uuid_obj = uuid4()

with pytest.raises(TypeError) as exc_info:
json.dumps(uuid_obj)

assert str(exc_info.value) == "Object of type UUID is not JSON serializable"

assert json_dumps(uuid_obj) == json.dumps(str(uuid_obj))


def test_serialized_non_str_dict_keys():
# tests orjson.OPT_NON_STR_KEYS option

# if a dict has a key of a type other than str it will NOT raise
json_dumps({1: "foo"})


ConstrainedFloat: TypeAlias = Annotated[float, Field(ge=0.0, le=1.0)]


def test_serialized_constraint_floats():
# test extension of ENCODERS_BY_TYPE used in pydantic_encoder

json_dumps({"value": 1.0})

# TypeError: Type is not JSON serializable: ProgressPercent
json_dumps({"value": TypeAdapter(ConstrainedFloat).validate_python(1.0)})


def _expected_json_dumps(obj: Any, default=pydantic_encoder, **json_dumps_kwargs):
if "indent" not in json_dumps_kwargs:
json_dumps_kwargs.setdefault(
"separators",
SeparatorTuple(item_separator=",", key_separator=":"), # compact separators
)
return json.dumps(obj, default=default, **json_dumps_kwargs)


@pytest.mark.parametrize(
"kwargs",
[
pytest.param({}, id="no-kw"),
pytest.param({"sort_keys": True}, id="sort_keys-kw"),
pytest.param(
{"separators": (",", ":")}, id="default_separators-kw"
), # NOTE: e.g. engineio.packet has `self.json.dumps(self.data, separators=(',', ':'))`
pytest.param(
{"indent": 2}, id="indent-kw"
), # NOTE: only one-to-one with indent=2
],
)
def test_compatiblity_with_json_interface(
fake_data_dict: dict[str, Any], kwargs: dict[str, Any]
):
orjson_dump = JsonNamespace.dumps(fake_data_dict, **kwargs)
json_dump = _expected_json_dumps(fake_data_dict, **kwargs)

# NOTE: cannot compare dumps directly because orjson compacts it more
assert json_loads(orjson_dump) == json_loads(json_dump)
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from pathlib import Path
from typing import Any, Literal, TypeAlias

from common_library.json_serialization import json_dumps
from pydantic import (
BaseModel,
ByteSize,
Expand All @@ -23,7 +24,6 @@
from .generics import ListModel
from .service_settings_nat_rule import NATRule
from .services_resources import DEFAULT_SINGLE_SERVICE_NAME
from .utils.json_serialization import json_dumps

_BaseConfig = ConfigDict(
extra="forbid", arbitrary_types_allowed=True, ignored_types=(cached_property,)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from types import GeneratorType
from typing import Any, Callable, Union

from models_library.utils.json_serialization import ENCODERS_BY_TYPE
from common_library.json_serialization import ENCODERS_BY_TYPE
from pydantic import BaseModel
from pydantic_core import PydanticUndefined, PydanticUndefinedType
from typing_extensions import Annotated, Doc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from json.decoder import JSONDecodeError
from typing import Any, TypeAlias

from .json_serialization import json_dumps
from common_library.json_serialization import json_dumps

LabelsAnnotationsDict: TypeAlias = dict[str, str]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from typing import Any, NamedTuple, TypeAlias, cast

from common_library.errors_classes import OsparcErrorMixin

from common_library.json_serialization import json_dumps, json_loads
from pydantic import StrictBool, StrictFloat, StrictInt

from .json_serialization import json_dumps, json_loads
from .string_substitution import (
SubstitutionsDict,
TextTemplate,
Expand Down
70 changes: 1 addition & 69 deletions packages/models-library/tests/test_utils_json_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,14 @@
# pylint: disable=unused-variable


import json
from copy import deepcopy
from typing import Any
from uuid import uuid4

import pytest
from common_library.json_serialization import json_dumps, json_loads
from faker import Faker
from models_library.api_schemas_long_running_tasks.base import ProgressPercent
from models_library.utils.fastapi_encoders import jsonable_encoder
from models_library.utils.json_serialization import (
JsonNamespace,
SeparatorTuple,
json_dumps,
json_loads,
)
from pydantic.json import pydantic_encoder


def _expected_json_dumps(obj: Any, default=pydantic_encoder, **json_dumps_kwargs):
if "indent" not in json_dumps_kwargs:
json_dumps_kwargs.setdefault(
"separators",
SeparatorTuple(item_separator=",", key_separator=":"), # compact separators
)
return json.dumps(obj, default=default, **json_dumps_kwargs)


def test_json_dump_variants():

uuid_obj = uuid4()

with pytest.raises(TypeError) as exc_info:
json.dumps(uuid_obj)

assert str(exc_info.value) == "Object of type UUID is not JSON serializable"

assert json_dumps(uuid_obj) == json.dumps(str(uuid_obj))


@pytest.fixture
Expand Down Expand Up @@ -75,42 +46,3 @@ def test_serialization_of_nested_dicts(fake_data_dict: dict[str, Any]):

dump = json_dumps(obj)
assert json_loads(dump) == jsonable_encoder(obj)


@pytest.mark.parametrize(
"kwargs",
[
pytest.param({}, id="no-kw"),
pytest.param({"sort_keys": True}, id="sort_keys-kw"),
pytest.param(
{"separators": (",", ":")}, id="default_separators-kw"
), # NOTE: e.g. engineio.packet has `self.json.dumps(self.data, separators=(',', ':'))`
pytest.param(
{"indent": 2}, id="indent-kw"
), # NOTE: only one-to-one with indent=2
],
)
def test_compatiblity_with_json_interface(
fake_data_dict: dict[str, Any], kwargs: dict[str, Any]
):
orjson_dump = JsonNamespace.dumps(fake_data_dict, **kwargs)
json_dump = _expected_json_dumps(fake_data_dict, **kwargs)

# NOTE: cannot compare dumps directly because orjson compacts it more
assert json_loads(orjson_dump) == json_loads(json_dump)


def test_serialized_non_str_dict_keys():
# tests orjson.OPT_NON_STR_KEYS option

# if a dict has a key of a type other than str it will NOT raise
json_dumps({1: "foo"})


def test_serialized_constraint_floats():
# test extension of ENCODERS_BY_TYPE used in pydantic_encoder

json_dumps({"value": 1.0})

# TypeError: Type is not JSON serializable: ProgressPercent
json_dumps({"value": ProgressPercent(1.0)})
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import base64
from collections.abc import Sequence

from common_library.json_serialization import json_dumps
from models_library.docker import DockerGenericTag
from models_library.utils.json_serialization import json_dumps
from types_aiobotocore_ec2 import EC2Client
from types_aiobotocore_ec2.literals import InstanceStateNameType, InstanceTypeType
from types_aiobotocore_ec2.type_defs import FilterTypeDef, InstanceTypeDef, TagTypeDef
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import pytest
import yaml
from models_library.utils.json_serialization import json_loads
from common_library.json_serialization import json_loads
from service_integration import cli
from typer.testing import CliRunner, Result

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import cast

from aiohttp import ClientSession, ClientTimeout, web
from models_library.utils.json_serialization import json_dumps
from common_library.json_serialization import json_dumps

from ..utils import (
get_http_client_request_aiohttp_connect_timeout,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging

from aiohttp import web
from models_library.utils.json_serialization import json_dumps
from common_library.json_serialization import json_dumps

from ...long_running_tasks._errors import (
TaskCancelledError,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import Any

from aiohttp import web
from models_library.utils.json_serialization import json_dumps
from common_library.json_serialization import json_dumps
from pydantic import BaseModel
from servicelib.aiohttp import status

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from typing import Any

from aiohttp import web
from common_library.json_serialization import json_dumps
from common_library.pydantic_networks_extension import AnyHttpUrlLegacy
from models_library.utils.json_serialization import json_dumps
from pydantic import PositiveFloat, TypeAdapter

from ...aiohttp import status
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from typing import TypeAlias, TypeVar, Union

from aiohttp import web
from models_library.utils.json_serialization import json_dumps
from common_library.json_serialization import json_dumps
from pydantic import BaseModel, ConfigDict, TypeAdapter, ValidationError

from ..mimetype_constants import MIMETYPE_APPLICATION_JSON
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from aiohttp.web_request import Request
from aiohttp.web_response import StreamResponse
from common_library.error_codes import create_error_code
from models_library.utils.json_serialization import json_dumps
from common_library.json_serialization import json_dumps

from ..logging_errors import create_troubleshotting_log_kwargs
from ..mimetype_constants import MIMETYPE_APPLICATION_JSON
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
""" Utils to check, convert and compose server responses for the RESTApi

"""

import inspect
import json
from collections.abc import Mapping
Expand All @@ -9,7 +10,7 @@

from aiohttp import web, web_exceptions
from aiohttp.web_exceptions import HTTPError, HTTPException
from models_library.utils.json_serialization import json_dumps
from common_library.json_serialization import json_dumps
from servicelib.aiohttp.status import HTTP_200_OK

from ..mimetype_constants import MIMETYPE_APPLICATION_JSON
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from aiohttp import web
from aiohttp.web import RouteDef, RouteTableDef
from models_library.utils.json_serialization import json_dumps
from common_library.json_serialization import json_dumps


class EnvelopeFactory:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from contextlib import contextmanager
from typing import Final

from models_library.utils.json_serialization import json_dumps, json_loads
from common_library.json_serialization import json_dumps, json_loads
from pyinstrument import Profiler

from .mimetype_constants import MIMETYPE_APPLICATION_JSON, MIMETYPE_APPLICATION_ND_JSON
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from aiohttp import web
from aiohttp.client import ClientSession
from aiohttp.test_utils import TestServer
from models_library.utils.json_serialization import json_dumps
from common_library.json_serialization import json_dumps
from servicelib.aiohttp.application_keys import APP_CLIENT_SESSION_KEY
from servicelib.aiohttp.client_session import (
get_client_session,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import pytest
from aiohttp import web
from aiohttp.test_utils import TestClient
from common_library.json_serialization import json_dumps
from faker import Faker
from models_library.utils.json_serialization import json_dumps
from pydantic import BaseModel, ConfigDict, Field
from servicelib.aiohttp import status
from servicelib.aiohttp.requests_validation import (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from aiohttp import web
from aiohttp.test_utils import TestClient
from common_library.error_codes import parse_error_code
from models_library.utils.json_serialization import json_dumps
from common_library.json_serialization import json_dumps
from servicelib.aiohttp import status
from servicelib.aiohttp.rest_middlewares import (
_FMSG_INTERNAL_ERROR_USER_FRIENDLY_WITH_OEC,
Expand Down
Loading
Loading