Skip to content

Commit 789daf4

Browse files
authored
Merge pull request #94 from dbcli/RW/json-format-followups
Followups for JSON output formats
2 parents 0edf14e + 49bfdb9 commit 789daf4

File tree

5 files changed

+58
-2
lines changed

5 files changed

+58
-2
lines changed

CHANGELOG

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
- Register the JSON formats so they are actually usable.
4+
- Make JSON formats able to encode Decimals and None/NULLs.
5+
36
## Version 2.5.0
47

58
- Added noheader CSV and TSV output formats.

cli_helpers/tabular_output/json_output_adapter.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
# -*- coding: utf-8 -*-
22
"""A JSON data output adapter"""
33

4+
from decimal import Decimal
45
from itertools import chain
56
import json
67

7-
from .preprocessors import bytes_to_string, override_missing_value, convert_to_string
8+
from .preprocessors import bytes_to_string
89

910
supported_formats = ("jsonl", "jsonl_escaped")
10-
preprocessors = (override_missing_value, bytes_to_string, convert_to_string)
11+
preprocessors = (bytes_to_string,)
12+
13+
14+
class CustomEncoder(json.JSONEncoder):
15+
def default(self, o):
16+
if isinstance(o, Decimal):
17+
return float(o)
18+
else:
19+
return super(CustomEncoder, self).default(o)
1120

1221

1322
def adapter(data, headers, table_format="jsonl", **_kwargs):
@@ -22,6 +31,7 @@ def adapter(data, headers, table_format="jsonl", **_kwargs):
2231
for row in chain(data):
2332
yield json.dumps(
2433
dict(zip(headers, row, strict=True)),
34+
cls=CustomEncoder,
2535
separators=(",", ":"),
2636
ensure_ascii=ensure_ascii,
2737
)

cli_helpers/tabular_output/output_formatter.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
vertical_table_adapter,
1818
tabulate_adapter,
1919
tsv_output_adapter,
20+
json_output_adapter,
2021
)
2122
from decimal import Decimal
2223

@@ -253,3 +254,14 @@ def format_output(data, headers, format_name, **kwargs):
253254
tsv_output_adapter.preprocessors,
254255
{"table_format": tsv_format, "missing_value": "", "max_field_width": None},
255256
)
257+
258+
for json_format in json_output_adapter.supported_formats:
259+
TabularOutputFormatter.register_new_formatter(
260+
json_format,
261+
json_output_adapter.adapter,
262+
json_output_adapter.preprocessors,
263+
{
264+
"table_format": json_format,
265+
"max_field_width": None,
266+
},
267+
)

tests/tabular_output/test_json_output_adapter.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
from __future__ import unicode_literals
55

6+
from decimal import Decimal
7+
68
from cli_helpers.tabular_output import json_output_adapter
79

810

@@ -29,6 +31,28 @@ def test_unicode_with_jsonl():
2931
)
3032

3133

34+
def test_decimal_with_jsonl():
35+
"""Test that the jsonl wrapper can pass through Decimal values."""
36+
data = [["ab\r\nc", 1], ["d", Decimal(4.56)]]
37+
headers = ["letters", "number"]
38+
output = json_output_adapter.adapter(iter(data), headers, table_format="jsonl")
39+
assert (
40+
"\n".join(output)
41+
== """{"letters":"ab\\r\\nc","number":1}\n{"letters":"d","number":4.56}"""
42+
)
43+
44+
45+
def test_null_with_jsonl():
46+
"""Test that the jsonl wrapper can pass through null values."""
47+
data = [["ab\r\nc", None], ["d", None]]
48+
headers = ["letters", "value"]
49+
output = json_output_adapter.adapter(iter(data), headers, table_format="jsonl")
50+
assert (
51+
"\n".join(output)
52+
== """{"letters":"ab\\r\\nc","value":null}\n{"letters":"d","value":null}"""
53+
)
54+
55+
3256
def test_unicode_with_jsonl_esc():
3357
"""Test that the jsonl_escaped wrapper JSON-escapes non-ascii characters."""
3458
data = [["观音", 1], ["Ποσειδῶν", 456]]

tests/tabular_output/test_output_formatter.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,13 @@ def test_unsupported_format():
177177
formatter.format_output((), (), format_name="foobar")
178178

179179

180+
def test_supported_json_formats():
181+
"""Test that the JSONl formats are known."""
182+
formatter = TabularOutputFormatter()
183+
assert "jsonl" in formatter.supported_formats
184+
assert "jsonl_escaped" in formatter.supported_formats
185+
186+
180187
def test_tabulate_ansi_escape_in_default_value():
181188
"""Test that ANSI escape codes work with tabulate."""
182189

0 commit comments

Comments
 (0)