Skip to content

Commit 3894394

Browse files
authored
Rely on canonical_json crate (#2)
1 parent ee7aa15 commit 3894394

File tree

5 files changed

+66
-26
lines changed

5 files changed

+66
-26
lines changed

Cargo.lock

Lines changed: 34 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ license = "Mozilla Public License 2.0"
88
repository = "https://github.com/leplatrem/python-canonicaljson-rs/"
99

1010
[lib]
11-
name = "canonicaljson"
11+
name = "canonicaljson" # python package name
1212
crate-type = ["cdylib"]
1313

1414
[dependencies]
1515
serde = "1.0"
1616
serde_json = "1.0"
17+
canonical_json = { version = "0.1.0", path = "../remote-settings-client/src/client/signatures/canonical_json" }
1718

1819
[dependencies.pyo3]
1920
version = "0.11"

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ Usage
1717
1818
>>> import canonicaljson
1919
>>>
20-
>>> canonicaljson.dumps({"foo": 42})
21-
'{"foo":42}'
20+
>>> canonicaljson.dumps({"héo": 42})
21+
'{"h\\u00e9o":42}'
2222
2323
2424
* ``canonicaljson.dumps(obj: Any) -> str``

src/lib.rs

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,54 @@
1+
use canonical_json::ser::{to_string, CanonicalJSONError};
12
use pyo3::exceptions::TypeError as PyTypeError;
23
use pyo3::prelude::*;
34
use pyo3::{
45
types::{PyAny, PyDict, PyFloat, PyList, PyTuple},
56
wrap_pyfunction,
67
};
78

8-
pub enum CanonicalJSONError {
9+
pub enum PyCanonicalJSONError {
910
InvalidConversion { error: String },
1011
PyErr { error: String },
1112
DictKeyNotSerializable { typename: String },
1213
InvalidFloat { value: PyObject },
1314
InvalidCast { typename: String },
1415
}
1516

16-
impl From<serde_json::Error> for CanonicalJSONError {
17-
fn from(error: serde_json::Error) -> CanonicalJSONError {
18-
CanonicalJSONError::InvalidConversion {
17+
impl From<CanonicalJSONError> for PyCanonicalJSONError {
18+
fn from(error: CanonicalJSONError) -> PyCanonicalJSONError {
19+
PyCanonicalJSONError::InvalidConversion {
1920
error: format!("{:?}", error),
2021
}
2122
}
2223
}
2324

24-
impl From<pyo3::PyErr> for CanonicalJSONError {
25-
fn from(error: pyo3::PyErr) -> CanonicalJSONError {
26-
CanonicalJSONError::PyErr {
25+
impl From<pyo3::PyErr> for PyCanonicalJSONError {
26+
fn from(error: pyo3::PyErr) -> PyCanonicalJSONError {
27+
PyCanonicalJSONError::PyErr {
2728
error: format!("{:?}", error),
2829
}
2930
}
3031
}
3132

32-
impl From<CanonicalJSONError> for pyo3::PyErr {
33-
fn from(e: CanonicalJSONError) -> pyo3::PyErr {
33+
impl From<PyCanonicalJSONError> for pyo3::PyErr {
34+
fn from(e: PyCanonicalJSONError) -> pyo3::PyErr {
3435
match e {
35-
CanonicalJSONError::InvalidConversion { error } => {
36-
PyErr::new::<PyTypeError, _>(format!("Conversion error: {}", error))
36+
PyCanonicalJSONError::InvalidConversion { error } => {
37+
PyErr::new::<PyTypeError, _>(format!("Conversion error: {:?}", error))
3738
}
38-
CanonicalJSONError::PyErr { error } => {
39+
PyCanonicalJSONError::PyErr { error } => {
3940
PyErr::new::<PyTypeError, _>(format!("Python Runtime exception: {}", error))
4041
}
41-
CanonicalJSONError::DictKeyNotSerializable { typename } => {
42+
PyCanonicalJSONError::DictKeyNotSerializable { typename } => {
4243
PyErr::new::<PyTypeError, _>(format!(
4344
"Dictionary key is not serializable: {}",
4445
typename
4546
))
4647
}
47-
CanonicalJSONError::InvalidFloat { value } => {
48+
PyCanonicalJSONError::InvalidFloat { value } => {
4849
PyErr::new::<PyTypeError, _>(format!("Invalid float: {:?}", value))
4950
}
50-
CanonicalJSONError::InvalidCast { typename } => {
51+
PyCanonicalJSONError::InvalidCast { typename } => {
5152
PyErr::new::<PyTypeError, _>(format!("Invalid type: {}", typename))
5253
}
5354
}
@@ -77,13 +78,13 @@ pub fn dump(py: Python, obj: PyObject, fp: PyObject) -> PyResult<PyObject> {
7778
#[pyfunction]
7879
pub fn dumps(py: Python, obj: PyObject) -> PyResult<PyObject> {
7980
let v = to_json(py, &obj)?;
80-
match serde_json::to_string(&v) {
81+
match to_string(&v) {
8182
Ok(s) => Ok(s.to_object(py)),
82-
Err(e) => Err(PyErr::new::<PyTypeError, _>(format!("{}", e))),
83+
Err(e) => Err(PyErr::new::<PyTypeError, _>(format!("{:?}", e))),
8384
}
8485
}
8586

86-
fn to_json(py: Python, obj: &PyObject) -> Result<serde_json::Value, CanonicalJSONError> {
87+
fn to_json(py: Python, obj: &PyObject) -> Result<serde_json::Value, PyCanonicalJSONError> {
8788
macro_rules! return_cast {
8889
($t:ty, $f:expr) => {
8990
if let Ok(val) = obj.cast_as::<$t>(py) {
@@ -96,7 +97,7 @@ fn to_json(py: Python, obj: &PyObject) -> Result<serde_json::Value, CanonicalJSO
9697
($t:ty) => {
9798
if let Ok(val) = obj.extract::<$t>(py) {
9899
return serde_json::value::to_value(val).map_err(|error| {
99-
CanonicalJSONError::InvalidConversion {
100+
PyCanonicalJSONError::InvalidConversion {
100101
error: format!("{}", error),
101102
}
102103
});
@@ -127,7 +128,7 @@ fn to_json(py: Python, obj: &PyObject) -> Result<serde_json::Value, CanonicalJSO
127128
} else if let Ok(val) = key_obj.str() {
128129
Ok(val.to_string()?.into_owned())
129130
} else {
130-
Err(CanonicalJSONError::DictKeyNotSerializable {
131+
Err(PyCanonicalJSONError::DictKeyNotSerializable {
131132
typename: key_obj
132133
.to_object(py)
133134
.as_ref(py)
@@ -153,14 +154,14 @@ fn to_json(py: Python, obj: &PyObject) -> Result<serde_json::Value, CanonicalJSO
153154
return_cast!(PyFloat, |x: &PyFloat| {
154155
match serde_json::Number::from_f64(x.value()) {
155156
Some(n) => Ok(serde_json::Value::Number(n)),
156-
None => Err(CanonicalJSONError::InvalidFloat {
157+
None => Err(PyCanonicalJSONError::InvalidFloat {
157158
value: x.to_object(py),
158159
}),
159160
}
160161
});
161162

162163
// At this point we can't cast it, set up the error object
163-
Err(CanonicalJSONError::InvalidCast {
164+
Err(PyCanonicalJSONError::InvalidCast {
164165
typename: obj.as_ref(py).get_type().name().into_owned(),
165166
})
166167
}

tests/test_dumps.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
(False, "false"),
1717
(True, "true"),
1818
("s", '"s"'),
19+
("é", '"\\u00e9"'),
20+
(10.0**21, '1e+21'),
21+
("1\n 2 \t \b\f", '"1\\n 2 \\t \\b\\f"'),
22+
("\xff I ❤ testing", r'"\u00ff I \u2764 testing"'),
23+
(r" \" ", r'" \\\" "'),
1924
]
2025

2126
@pytest.mark.parametrize("value,expected", FIXTURES)

0 commit comments

Comments
 (0)