Skip to content

Commit

Permalink
introduce Serializer class
Browse files Browse the repository at this point in the history
We have never handled the JSONDecodeError so consumers are assumed to
be catching that exception on their end. This means we cannot wrap all
the parser errors into a unified type (e.g. ValueError) without breaking
the API. Keep API compatibility on the loader functions by introducing a
Serializer class that the cli tool can utilize. This allows the cli to
avoid knowing which specific serializer errors to handle. The library
itself maintains its current API.

Signed-off-by: Cory Todd <cory.todd@canonical.com>
  • Loading branch information
Cory Todd committed Sep 5, 2023
1 parent 00e3dc8 commit 4c38815
Showing 1 changed file with 50 additions and 1 deletion.
51 changes: 50 additions & 1 deletion jsondiff/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import json
import yaml

from json import JSONDecodeError
from yaml import YAMLError

from .symbols import *
from .symbols import Symbol

Expand Down Expand Up @@ -55,6 +58,10 @@ def __init__(self, **kwargs):
self.kwargs = kwargs

def __call__(self, src):
"""Parse and return JSON data
:param src: str|file-like source
:return: dict parsed data
"""
if isinstance(src, string_types):
return json.loads(src, **self.kwargs)
else:
Expand All @@ -74,6 +81,47 @@ def __call__(self, src):
"""
return yaml.safe_load(src)

class Serializer:
"""Serializer helper loads and stores object data
:param file_format: str json or yaml
:param indent: int Output indentation in spaces
:raise ValueError: file_path does not contains valid file_format data
"""

def __init__(self, file_format, indent):
# pyyaml _can_ load json but is ~20 times slower and has known issues so use
# the json from stdlib when json is specified.
self.serializers = {
"json": (JsonLoader(), JsonDumper(indent=indent)),
"yaml": (YamlLoader(), YamlDumper(indent=indent)),
}
self.file_format = file_format
if file_format not in self.serializers:
raise ValueError(f"Unsupported serialization format {file_format}, expected one of {self.serializers.keys()}")

def deserialize_file(self, src):
"""Deserialize file from the specified format
:param file_path: str path to file
:param src: str|file-like source
:return dict
:raise ValueError: file_path does not contains valid file_format data
"""
loader, _ = self.serializers[self.file_format]
try:
parsed = loader(src)
except (JSONDecodeError, YAMLError) as ex:
raise ValueError(f"Invalid {self.file_format} file") from ex
return parsed

def serialize_data(self, obj, stream):
"""Serialize obj and write to stream
:param obj: dict to serialize
:param stream: Writeable stream
"""
_, dumper = self.serializers[self.file_format]
dumper(obj, stream)


class JsonDiffSyntax(object):
def emit_set_diff(self, a, b, s, added, removed):
raise NotImplementedError()
Expand Down Expand Up @@ -667,5 +715,6 @@ def similarity(a, b, cls=JsonDiffer, **kwargs):
"JsonDumper",
"JsonLoader",
"YamlDumper",
"YamlLoader"
"YamlLoader",
"Serializer",
]

0 comments on commit 4c38815

Please sign in to comment.