Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Nathaniel Starkman (@nstarman) <nstarkman@protonmail.com>
- Loading branch information
Showing
7 changed files
with
399 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
# -*- coding: utf-8 -*- | ||
|
||
import ast | ||
import json | ||
import re | ||
|
||
import numpy as np | ||
import pytest | ||
|
||
import astropy.units as u | ||
import astropy.coordinates as coord | ||
from astropy.io.misc.json import JSONExtendedEncoder, JSONExtendedDecoder | ||
from astropy.io.misc.json.tests.test_core import JSONExtendedTestBase | ||
|
||
|
||
class TestJSONExtendedUnits(JSONExtendedTestBase): | ||
"""Tests for serializing builtins with extended JSON encoders and decoders.""" | ||
|
||
def test_longitude(self): | ||
"""Test round-tripping `astropy.coordinates.Longitude`.""" | ||
obj = coord.Longitude([3, 4], dtype=float, unit=u.deg, wrap_angle=180*u.deg) | ||
|
||
# Raises errors without extended encoder | ||
with pytest.raises(TypeError, match=re.escape("Object of type Longitude is not JSON serializable")): | ||
json.dumps(obj) | ||
|
||
# Works with the extended encoder | ||
serialized = json.dumps(obj, cls=JSONExtendedEncoder) | ||
assert isinstance(serialized, str) | ||
d = ast.literal_eval(serialized) | ||
assert d["__class__"] == "astropy.coordinates.angles.Longitude" | ||
assert d["value"] == [3.0, 4.0] | ||
assert d["unit"] == "deg" | ||
assert d["wrap_angle"]["value"] == 180.0 | ||
assert d["wrap_angle"]["unit"] == "deg" | ||
|
||
# Comes back partially processed without extended decoder | ||
out = json.loads(serialized) | ||
assert isinstance(out, dict) | ||
|
||
# Roundtrips | ||
out = json.loads(serialized, cls=JSONExtendedDecoder) | ||
assert isinstance(out, coord.Longitude) | ||
assert np.array_equal(out, obj) | ||
|
||
def test_latitude(self): | ||
"""Test round-tripping `astropy.coordinates.Latitude`.""" | ||
obj = coord.Latitude([3, 4], dtype=float, unit=u.deg) | ||
|
||
# Raises errors without extended encoder | ||
with pytest.raises(TypeError, match=re.escape("Object of type Latitude is not JSON serializable")): | ||
json.dumps(obj) | ||
|
||
# Works with the extended encoder | ||
serialized = json.dumps(obj, cls=JSONExtendedEncoder) | ||
assert isinstance(serialized, str) | ||
d = ast.literal_eval(serialized) | ||
assert d["__class__"] == "astropy.coordinates.angles.Latitude" | ||
assert d["value"] == [3.0, 4.0] | ||
assert d["unit"] == "deg" | ||
|
||
# Comes back partially processed without extended decoder | ||
out = json.loads(serialized) | ||
assert isinstance(out, dict) | ||
|
||
# Roundtrips | ||
out = json.loads(serialized, cls=JSONExtendedDecoder) | ||
assert isinstance(out, coord.Latitude) | ||
assert np.array_equal(out, obj) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
# -*- coding: utf-8 -*- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
# Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
# -*- coding: utf-8 -*- | ||
|
||
import ast | ||
import json | ||
|
||
import pytest | ||
|
||
from astropy.io.misc.json import JSONExtendedEncoder, JSONExtendedDecoder | ||
|
||
from .test_core import JSONExtendedTestBase | ||
|
||
|
||
class TestJSONExtendedBuiltins(JSONExtendedTestBase): | ||
"""Tests for serializing builtins with extended JSON encoders and decoders.""" | ||
|
||
def test_bytes(self): | ||
"""Test round-tripping `bytes`.""" | ||
obj = b"1234" | ||
|
||
# Raises errors without extended encoder | ||
with pytest.raises(TypeError, match="Object of type bytes is not JSON serializable"): | ||
json.dumps(obj) | ||
|
||
# Works with the extended encoder | ||
serialized = json.dumps(obj, cls=JSONExtendedEncoder) | ||
assert isinstance(serialized, str) | ||
d = ast.literal_eval(serialized) | ||
assert d["__class__"] == "builtins.bytes" | ||
assert d["value"] == "1234" | ||
|
||
# Comes back partially processed without extended decoder | ||
out = json.loads(serialized) | ||
assert isinstance(out, dict) | ||
|
||
# Roundtrips | ||
out = json.loads(serialized, cls=JSONExtendedDecoder) | ||
assert isinstance(out, bytes) | ||
assert out == obj | ||
|
||
def test_complex(self): | ||
"""Test round-tripping `complex`.""" | ||
obj = 1 + 2j | ||
|
||
# Raises errors without extended encoder | ||
with pytest.raises(TypeError, match="Object of type complex is not JSON serializable"): | ||
json.dumps(obj) | ||
|
||
# Works with the extended encoder | ||
serialized = json.dumps(obj, cls=JSONExtendedEncoder) | ||
assert isinstance(serialized, str) | ||
d = ast.literal_eval(serialized) | ||
assert d["__class__"] == "builtins.complex" | ||
assert d["value"] == [1, 2] | ||
|
||
# Comes back partially processed without extended decoder | ||
out = json.loads(serialized) | ||
assert isinstance(out, dict) | ||
|
||
# Roundtrips | ||
out = json.loads(serialized, cls=JSONExtendedDecoder) | ||
assert isinstance(out, complex) | ||
assert out == obj | ||
|
||
def test_set(self): | ||
"""Test round-tripping `set`.""" | ||
obj = {1, 2, 3} | ||
|
||
# Raises errors without extended encoder | ||
with pytest.raises(TypeError, match="Object of type set is not JSON serializable"): | ||
json.dumps(obj) | ||
|
||
# Works with the extended encoder | ||
serialized = json.dumps(obj, cls=JSONExtendedEncoder) | ||
assert isinstance(serialized, str) | ||
d = ast.literal_eval(serialized) | ||
assert d["__class__"] == "builtins.set" | ||
assert d["value"] == [1, 2, 3] | ||
|
||
# Comes back partially processed without extended decoder | ||
out = json.loads(serialized) | ||
assert isinstance(out, dict) | ||
|
||
# Roundtrips | ||
out = json.loads(serialized, cls=JSONExtendedDecoder) | ||
assert isinstance(out, set) | ||
assert out == obj | ||
|
||
def test_NotImplemented(self): | ||
"""Test round-tripping `NotImplemented`.""" | ||
obj = NotImplemented | ||
|
||
# Raises errors without extended encoder | ||
with pytest.raises(TypeError, match="Object of type NotImplementedType is not JSON serializable"): | ||
json.dumps(obj) | ||
|
||
# Works with the extended encoder | ||
serialized = json.dumps(obj, cls=JSONExtendedEncoder) | ||
assert isinstance(serialized, str) | ||
d = ast.literal_eval(serialized) | ||
assert d["__class__"] == "builtins.NotImplemented" | ||
assert d["value"] == "NotImplemented" | ||
|
||
# Comes back partially processed without extended decoder | ||
out = json.loads(serialized) | ||
assert isinstance(out, dict) | ||
|
||
# Roundtrips | ||
out = json.loads(serialized, cls=JSONExtendedDecoder) | ||
assert isinstance(out, type(NotImplemented)) | ||
assert out == obj | ||
|
||
def test_Ellipsis(self): | ||
"""Test round-tripping `Ellipsis`.""" | ||
obj = Ellipsis | ||
|
||
# Raises errors without extended encoder | ||
with pytest.raises(TypeError, match="Object of type ellipsis is not JSON serializable"): | ||
json.dumps(obj) | ||
|
||
# Works with the extended encoder | ||
serialized = json.dumps(obj, cls=JSONExtendedEncoder) | ||
assert isinstance(serialized, str) | ||
d = ast.literal_eval(serialized) | ||
assert d["__class__"] == "builtins.Ellipsis" | ||
assert d["value"] == "Ellipsis" | ||
|
||
# Comes back partially processed without extended decoder | ||
out = json.loads(serialized) | ||
assert isinstance(out, dict) | ||
|
||
# Roundtrips | ||
out = json.loads(serialized, cls=JSONExtendedDecoder) | ||
assert isinstance(out, type(Ellipsis)) | ||
assert out == obj |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
# -*- coding: utf-8 -*- | ||
|
||
|
||
class JSONExtendedTestBase: | ||
"""Base for testing JSON extended encoders and decoders""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
# -*- coding: utf-8 -*- | ||
|
||
import ast | ||
import json | ||
import re | ||
|
||
import numpy as np | ||
import pytest | ||
|
||
from astropy.io.misc.json import JSONExtendedEncoder, JSONExtendedDecoder | ||
|
||
from .test_core import JSONExtendedTestBase | ||
|
||
|
||
class TestJSONExtendedNumPy(JSONExtendedTestBase): | ||
"""Tests for serializing builtins with extended JSON encoders and decoders.""" | ||
|
||
def test_number(self): | ||
"""Test round-tripping `numpy.number`.""" | ||
obj = np.int64(10) | ||
|
||
# Raises errors without extended encoder | ||
with pytest.raises(TypeError, match="Object of type int64 is not JSON serializable"): | ||
json.dumps(obj) | ||
|
||
# Works with the extended encoder | ||
serialized = json.dumps(obj, cls=JSONExtendedEncoder) | ||
assert isinstance(serialized, str) | ||
d = ast.literal_eval(serialized) | ||
assert d["__class__"] == "numpy.int64" | ||
assert d["value"] == "10" | ||
|
||
# Comes back partially processed without extended decoder | ||
out = json.loads(serialized) | ||
assert isinstance(out, dict) | ||
|
||
# Roundtrips | ||
out = json.loads(serialized, cls=JSONExtendedDecoder) | ||
assert isinstance(out, np.int64) | ||
assert out == obj | ||
|
||
def test_dtype_simple(self): | ||
"""Test round-tripping `numpy.dtype`.""" | ||
obj = np.dtype("int64") | ||
|
||
# Raises errors without extended encoder | ||
# TODO! "Object of type dtype[int64] is not JSON serializable" when py3.9+ | ||
with pytest.raises(TypeError, match=re.escape("Object of type")): | ||
json.dumps(obj) | ||
|
||
# Works with the extended encoder | ||
serialized = json.dumps(obj, cls=JSONExtendedEncoder) | ||
assert isinstance(serialized, str) | ||
d = ast.literal_eval(serialized) | ||
assert d["__class__"] == "numpy.dtype" | ||
assert d["value"] == "int64" | ||
|
||
# Comes back partially processed without extended decoder | ||
out = json.loads(serialized) | ||
assert isinstance(out, dict) | ||
|
||
# Roundtrips | ||
out = json.loads(serialized, cls=JSONExtendedDecoder) | ||
assert isinstance(out, np.dtype) | ||
assert out == obj | ||
|
||
@pytest.mark.skip("TODO!") | ||
def test_dtype_structured(self): | ||
"""Test round-tripping structured `numpy.dtype`.""" | ||
obj = np.dtype([("f1", np.int64), ("f2", np.float16)]) | ||
|
||
def test_ndarray_simple(self): | ||
"""Test round-tripping `numpy.ndarray`.""" | ||
obj = np.array([3, 4], dtype=float) | ||
|
||
# Raises errors without extended encoder | ||
with pytest.raises(TypeError, match=re.escape("Object of type ndarray is not JSON serializable")): | ||
json.dumps(obj) | ||
|
||
# Works with the extended encoder | ||
serialized = json.dumps(obj, cls=JSONExtendedEncoder) | ||
assert isinstance(serialized, str) | ||
d = ast.literal_eval(serialized) | ||
assert d["__class__"] == "numpy.ndarray" | ||
assert d["value"] == [3.0, 4.0] | ||
|
||
# Comes back partially processed without extended decoder | ||
out = json.loads(serialized) | ||
assert isinstance(out, dict) | ||
|
||
# Roundtrips | ||
out = json.loads(serialized, cls=JSONExtendedDecoder) | ||
assert isinstance(out, np.ndarray) | ||
assert np.array_equal(out, obj) | ||
|
||
@pytest.mark.skip("TODO!") | ||
def test_ndarray_structured(self): | ||
"""Test round-tripping structured `numpy.ndarray`.""" | ||
dt = np.dtype([("f1", np.int64), ("f2", np.float16)]) | ||
obj = np.array((1, 3.0), dtype=dt) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.