Skip to content

Commit

Permalink
Move base SerDe to _singerlib
Browse files Browse the repository at this point in the history
  • Loading branch information
edgarrmondragon committed Jul 12, 2024
1 parent 1182f38 commit 5cfa21e
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 85 deletions.
2 changes: 1 addition & 1 deletion singer_sdk/_singerlib/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from dataclasses import asdict, dataclass, field
from datetime import datetime, timezone

from singer_sdk.helpers._util import serialize_json
from singer_sdk._singerlib.serde import serialize_json

if sys.version_info < (3, 11):
from backports.datetime_fromisoformat import MonkeyPatch
Expand Down
66 changes: 66 additions & 0 deletions singer_sdk/_singerlib/serde.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from __future__ import annotations

import datetime
import decimal
import json
import logging
import typing as t

import simplejson

logger = logging.getLogger(__name__)


def _default_encoding(obj: t.Any) -> str: # noqa: ANN401
"""Default JSON encoder.
Args:
obj: The object to encode.
Returns:
The encoded object.
"""
return obj.isoformat(sep="T") if isinstance(obj, datetime.datetime) else str(obj)


def deserialize_json(json_str: str, **kwargs: t.Any) -> dict:
"""Deserialize a line of json.
Args:
json_str: A single line of json.
**kwargs: Optional key word arguments.
Returns:
A dictionary of the deserialized json.
Raises:
json.decoder.JSONDecodeError: raised if any lines are not valid json
"""
try:
return json.loads( # type: ignore[no-any-return]
json_str,
parse_float=decimal.Decimal,
**kwargs,
)
except json.decoder.JSONDecodeError as exc:
logger.exception("Unable to parse:\n%s", json_str, exc_info=exc)
raise


def serialize_json(obj: object, **kwargs: t.Any) -> str:
"""Serialize a dictionary into a line of json.
Args:
obj: A Python object usually a dict.
**kwargs: Optional key word arguments.
Returns:
A string of serialized json.
"""
return simplejson.dumps(
obj,
use_decimal=True,
default=_default_encoding,
separators=(",", ":"),
**kwargs,
)
12 changes: 3 additions & 9 deletions singer_sdk/connectors/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,8 @@
import sqlalchemy as sa

from singer_sdk import typing as th
from singer_sdk._singerlib import CatalogEntry, MetadataMapping, Schema
from singer_sdk._singerlib import CatalogEntry, MetadataMapping, Schema, serde
from singer_sdk.exceptions import ConfigValidationError
from singer_sdk.helpers._util import (
deserialize_json as util_deserialize_json,
)
from singer_sdk.helpers._util import (
serialize_json as util_serialize_json,
)
from singer_sdk.helpers.capabilities import TargetLoadMethods

if t.TYPE_CHECKING:
Expand Down Expand Up @@ -1170,7 +1164,7 @@ def serialize_json(self, obj: object) -> str: # noqa: PLR6301
.. versionadded:: 0.31.0
"""
return util_serialize_json(obj)
return serde.serialize_json(obj)

def deserialize_json(self, json_str: str) -> object: # noqa: PLR6301
"""Deserialize a JSON string to an object.
Expand All @@ -1186,7 +1180,7 @@ def deserialize_json(self, json_str: str) -> object: # noqa: PLR6301
.. versionadded:: 0.31.0
"""
return util_deserialize_json(json_str)
return serde.deserialize_json(json_str)

def delete_old_versions(
self,
Expand Down
2 changes: 1 addition & 1 deletion singer_sdk/contrib/batch_encoder_jsonl.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import typing as t
from uuid import uuid4

from singer_sdk._singerlib.serde import serialize_json
from singer_sdk.batch import BaseBatcher, lazy_chunked_generator
from singer_sdk.helpers._util import serialize_json

__all__ = ["JSONLinesBatcher"]

Expand Down
2 changes: 1 addition & 1 deletion singer_sdk/helpers/_flattening.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import inflection

from singer_sdk.helpers._util import serialize_json
from singer_sdk._singerlib.serde import serialize_json

DEFAULT_FLATTENING_SEPARATOR = "__"

Expand Down
70 changes: 1 addition & 69 deletions singer_sdk/helpers/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,78 +3,10 @@
from __future__ import annotations

import datetime
import decimal
import json
import logging
import sys
import typing as t
from pathlib import Path, PurePath

import simplejson

if sys.version_info < (3, 11):
from backports.datetime_fromisoformat import MonkeyPatch

MonkeyPatch.patch_fromisoformat()


logger = logging.getLogger(__name__)


def _default_encoding(obj: t.Any) -> str: # noqa: ANN401
"""Default JSON encoder.
Args:
obj: The object to encode.
Returns:
The encoded object.
"""
return obj.isoformat(sep="T") if isinstance(obj, datetime.datetime) else str(obj)


def deserialize_json(json_str: str, **kwargs: t.Any) -> dict:
"""Deserialize a line of json.
Args:
json_str: A single line of json.
**kwargs: Optional key word arguments.
Returns:
A dictionary of the deserialized json.
Raises:
json.decoder.JSONDecodeError: raised if any lines are not valid json
"""
try:
return json.loads( # type: ignore[no-any-return]
json_str,
parse_float=decimal.Decimal,
**kwargs,
)
except json.decoder.JSONDecodeError as exc:
logger.exception("Unable to parse:\n%s", json_str, exc_info=exc)
raise


def serialize_json(obj: object, **kwargs: t.Any) -> str:
"""Serialize a dictionary into a line of json.
Args:
obj: A Python object usually a dict.
**kwargs: Optional key word arguments.
Returns:
A string of serialized json.
"""
return simplejson.dumps(
obj,
use_decimal=True,
default=_default_encoding,
separators=(",", ":"),
**kwargs,
)


def read_json_file(path: PurePath | str) -> dict[str, t.Any]:
"""Read json file, throwing an error if missing."""
Expand All @@ -89,7 +21,7 @@ def read_json_file(path: PurePath | str) -> dict[str, t.Any]:
msg += f"\nFor more info, please see the sample template at: {template}"
raise FileExistsError(msg)

return deserialize_json(Path(path).read_text(encoding="utf-8"))
return t.cast(dict, json.loads(Path(path).read_text(encoding="utf-8")))


def utc_now() -> datetime.datetime:
Expand Down
2 changes: 1 addition & 1 deletion singer_sdk/io_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
from singer_sdk._singerlib.messages import Message, SingerMessageType
from singer_sdk._singerlib.messages import format_message as singer_format_message
from singer_sdk._singerlib.messages import write_message as singer_write_message
from singer_sdk._singerlib.serde import deserialize_json
from singer_sdk.exceptions import InvalidInputLine
from singer_sdk.helpers._util import deserialize_json

logger = logging.getLogger(__name__)

Expand Down
2 changes: 1 addition & 1 deletion singer_sdk/sinks/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import jsonschema
from typing_extensions import override

from singer_sdk._singerlib.serde import deserialize_json
from singer_sdk.exceptions import (
InvalidJSONSchema,
InvalidRecord,
Expand All @@ -37,7 +38,6 @@
get_datelike_property_type,
handle_invalid_timestamp_in_record,
)
from singer_sdk.helpers._util import deserialize_json

if t.TYPE_CHECKING:
from logging import Logger
Expand Down
3 changes: 2 additions & 1 deletion singer_sdk/tap_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import click

from singer_sdk._singerlib import Catalog, StateMessage
from singer_sdk._singerlib.serde import serialize_json
from singer_sdk.configuration._dict_config import merge_missing_config_jsonschema
from singer_sdk.exceptions import (
AbortedSyncFailedException,
Expand All @@ -19,7 +20,7 @@
from singer_sdk.helpers import _state
from singer_sdk.helpers._classproperty import classproperty
from singer_sdk.helpers._state import write_stream_state
from singer_sdk.helpers._util import read_json_file, serialize_json
from singer_sdk.helpers._util import read_json_file
from singer_sdk.helpers.capabilities import (
BATCH_CONFIG,
CapabilitiesEnum,
Expand Down
2 changes: 1 addition & 1 deletion tests/core/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import pytest

from singer_sdk._singerlib import RecordMessage
from singer_sdk.helpers._util import deserialize_json
from singer_sdk._singerlib.serde import deserialize_json
from singer_sdk.io_base import SingerReader, SingerWriter


Expand Down

0 comments on commit 5cfa21e

Please sign in to comment.