Skip to content

Commit

Permalink
♻️Fix settings library tests (#6605)
Browse files Browse the repository at this point in the history
  • Loading branch information
sanderegg authored Oct 28, 2024
1 parent 39aed6a commit e38cf4e
Show file tree
Hide file tree
Showing 79 changed files with 192 additions and 143 deletions.
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

0 comments on commit e38cf4e

Please sign in to comment.