From 9c2cc72a29c45441dd3dff48df325f6d13f8fd0d Mon Sep 17 00:00:00 2001 From: Tom Kralidis Date: Wed, 4 Sep 2024 16:37:13 -0400 Subject: [PATCH] do not force ASCII on JSON dump, add json_dumps helper function --- pygeometa/core.py | 6 +++--- pygeometa/helpers.py | 20 +++++++++++++++++--- pygeometa/schemas/dcat/__init__.py | 7 +++---- pygeometa/schemas/ogcapi_records/__init__.py | 5 ++--- pygeometa/schemas/stac/__init__.py | 7 +++---- pygeometa/schemas/wmo_wcmp2/__init__.py | 5 ++--- tests/run_tests.py | 8 ++++---- 7 files changed, 34 insertions(+), 24 deletions(-) diff --git a/pygeometa/core.py b/pygeometa/core.py index de608f3..078820e 100644 --- a/pygeometa/core.py +++ b/pygeometa/core.py @@ -19,7 +19,7 @@ # referenced with those assets. # # Copyright (c) 2016 Government of Canada -# Copyright (c) 2022 Tom Kralidis +# Copyright (c) 2024 Tom Kralidis # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation @@ -63,7 +63,7 @@ import yaml from pygeometa import cli_options -from pygeometa.helpers import json_serial +from pygeometa.helpers import json_dumps from pygeometa.schemas import get_supported_schemas, load_schema LOGGER = logging.getLogger(__name__) @@ -573,7 +573,7 @@ def validate(ctx, mcf, verbosity): click.echo(f'Validating {mcf}') - instance = json.loads(json.dumps(read_mcf(mcf), default=json_serial)) + instance = json.loads(json_dumps(read_mcf(mcf))) validate_mcf(instance) click.echo('Valid MCF document') diff --git a/pygeometa/helpers.py b/pygeometa/helpers.py index fceacd3..916750e 100644 --- a/pygeometa/helpers.py +++ b/pygeometa/helpers.py @@ -18,7 +18,7 @@ # those files. Users are asked to read the 3rd Party Licenses # referenced with those assets. # -# Copyright (c) 2022 Tom Kralidis +# Copyright (c) 2024 Tom Kralidis # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation @@ -46,17 +46,31 @@ import base64 from datetime import date, datetime, time from decimal import Decimal +import json import logging from pathlib import Path +from typing import Any LOGGER = logging.getLogger(__name__) THISDIR = Path(__file__).resolve().parent -def json_serial(obj): +def json_dumps(obj) -> str: """ - helper function to convert to JSON non-default + Helper function to dump dict to JSON string + + :param obj: `dict` of JSON + + :returns: `str` of JSON + """ + + return json.dumps(obj, default=json_serial, indent=4, ensure_ascii=False) + + +def json_serial(obj) -> Any: + """ + Helper function to convert to JSON non-default types (source: https://stackoverflow.com/a/22238613) :param obj: `object` to be evaluated diff --git a/pygeometa/schemas/dcat/__init__.py b/pygeometa/schemas/dcat/__init__.py index 7791f73..009588f 100644 --- a/pygeometa/schemas/dcat/__init__.py +++ b/pygeometa/schemas/dcat/__init__.py @@ -18,7 +18,7 @@ # those files. Users are asked to read the 3rd Party Licenses # referenced with those assets. # -# Copyright (c) 2020 Tom Kralidis, Paul van Genuchten +# Copyright (c) 2024 Tom Kralidis, Paul van Genuchten # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation @@ -43,11 +43,10 @@ # # ================================================================= -import json import os from typing import Union -from pygeometa.helpers import json_serial +from pygeometa.helpers import json_dumps from pygeometa.schemas.base import BaseOutputSchema THISDIR = os.path.dirname(os.path.realpath(__file__)) @@ -208,6 +207,6 @@ def write(self, mcf: dict, stringify: str = True) -> Union[dict, str]: dcat[key] = value if stringify: - return json.dumps(dcat, default=json_serial, indent=4) + return json_dumps(dcat) return dcat diff --git a/pygeometa/schemas/ogcapi_records/__init__.py b/pygeometa/schemas/ogcapi_records/__init__.py index a7f54b3..dbe183d 100644 --- a/pygeometa/schemas/ogcapi_records/__init__.py +++ b/pygeometa/schemas/ogcapi_records/__init__.py @@ -44,13 +44,12 @@ # ================================================================= from datetime import date, datetime -import json import logging import os from typing import Union from pygeometa.core import get_charstring -from pygeometa.helpers import json_serial +from pygeometa.helpers import json_dumps from pygeometa.schemas.base import BaseOutputSchema THISDIR = os.path.dirname(os.path.realpath(__file__)) @@ -236,7 +235,7 @@ def write(self, mcf: dict, stringify: str = True) -> Union[dict, str]: record['links'].append(self.generate_link(value)) if stringify: - return json.dumps(record, default=json_serial, indent=4) + return json_dumps(record) return record diff --git a/pygeometa/schemas/stac/__init__.py b/pygeometa/schemas/stac/__init__.py index 7a8a6e3..4a593de 100644 --- a/pygeometa/schemas/stac/__init__.py +++ b/pygeometa/schemas/stac/__init__.py @@ -18,7 +18,7 @@ # those files. Users are asked to read the 3rd Party Licenses # referenced with those assets. # -# Copyright (c) 2020 Tom Kralidis +# Copyright (c) 2024 Tom Kralidis # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation @@ -43,12 +43,11 @@ # # ================================================================= -import json import os from typing import Union from pygeometa.core import get_charstring -from pygeometa.helpers import json_serial +from pygeometa.helpers import json_dumps from pygeometa.schemas.base import BaseOutputSchema THISDIR = os.path.dirname(os.path.realpath(__file__)) @@ -136,6 +135,6 @@ def write(self, mcf: dict, stringify: str = True) -> Union[dict, str]: stac_item['links'].append(link) if stringify: - return json.dumps(stac_item, default=json_serial, indent=4) + return json_dumps(stac_item) return stac_item diff --git a/pygeometa/schemas/wmo_wcmp2/__init__.py b/pygeometa/schemas/wmo_wcmp2/__init__.py index 2fa508e..7937460 100644 --- a/pygeometa/schemas/wmo_wcmp2/__init__.py +++ b/pygeometa/schemas/wmo_wcmp2/__init__.py @@ -44,12 +44,11 @@ # ================================================================= from datetime import datetime -import json import logging import os from typing import Union -from pygeometa.helpers import json_serial +from pygeometa.helpers import json_dumps from pygeometa.schemas.ogcapi_records import OGCAPIRecordOutputSchema THISDIR = os.path.dirname(os.path.realpath(__file__)) @@ -110,6 +109,6 @@ def write(self, mcf: dict, stringify: str = True) -> Union[dict, str]: record['properties']['created'] = datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ') # noqa if stringify: - return json.dumps(record, default=json_serial, indent=4) + return json_dumps(record) else: return record diff --git a/tests/run_tests.py b/tests/run_tests.py index 7234e2c..aa68591 100644 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -20,7 +20,7 @@ # # Copyright (c) 2015 Government of Canada # Copyright (c) 2016 ERT Inc. -# Copyright (c) 2022 Tom Kralidis +# Copyright (c) 2024 Tom Kralidis # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation @@ -58,7 +58,7 @@ prune_distribution_formats, prune_transfer_option, MCFReadError, MCFValidationError, SCHEMAS, validate_mcf) -from pygeometa.helpers import json_serial +from pygeometa.helpers import json_dumps, json_serial from pygeometa.schemas import (get_supported_schemas, InvalidSchemaError, load_schema) from pygeometa.schemas.iso19139 import ISO19139OutputSchema @@ -381,7 +381,7 @@ def test_validate_mcf(self): mcf = read_mcf(get_abspath('../sample.yml')) - instance = json.loads(json.dumps(mcf, default=json_serial)) + instance = json.loads(json_dumps(mcf) is_valid = validate_mcf(instance) assert is_valid @@ -389,7 +389,7 @@ def test_validate_mcf(self): # validated nested MCF mcf = read_mcf(get_abspath('./sample-child.yml')) - instance = json.loads(json.dumps(mcf, default=json_serial)) + instance = json.loads(json_dumps(mcf)) is_valid = validate_mcf(instance) assert is_valid