Coverage for datasette/renderer.py : 94%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import json
2from datasette.utils import (
3 value_as_boolean,
4 remove_infinites,
5 CustomJSONEncoder,
6 path_from_row_pks,
7)
10def convert_specific_columns_to_json(rows, columns, json_cols):
11 json_cols = set(json_cols)
12 if not json_cols.intersection(columns):
13 return rows
14 new_rows = []
15 for row in rows:
16 new_row = []
17 for value, column in zip(row, columns):
18 if column in json_cols:
19 try:
20 value = json.loads(value)
21 except (TypeError, ValueError) as e:
22 print(e)
23 pass
24 new_row.append(value)
25 new_rows.append(new_row)
26 return new_rows
29def json_renderer(args, data, view_name):
30 """ Render a response as JSON """
31 status_code = 200
32 # Handle the _json= parameter which may modify data["rows"]
33 json_cols = []
34 if "_json" in args:
35 json_cols = args.getlist("_json")
36 if json_cols and "rows" in data and "columns" in data:
37 data["rows"] = convert_specific_columns_to_json(
38 data["rows"], data["columns"], json_cols
39 )
41 # unless _json_infinity=1 requested, replace infinity with None
42 if "rows" in data and not value_as_boolean(args.get("_json_infinity", "0")):
43 data["rows"] = [remove_infinites(row) for row in data["rows"]]
45 # Deal with the _shape option
46 shape = args.get("_shape", "arrays")
47 if shape == "arrayfirst":
48 data = [row[0] for row in data["rows"]]
49 elif shape in ("objects", "object", "array"):
50 columns = data.get("columns")
51 rows = data.get("rows")
52 if rows and columns:
53 data["rows"] = [dict(zip(columns, row)) for row in rows]
54 if shape == "object":
55 error = None
56 if "primary_keys" not in data:
57 error = "_shape=object is only available on tables"
58 else:
59 pks = data["primary_keys"]
60 if not pks:
61 error = (
62 "_shape=object not available for tables with no primary keys"
63 )
64 else:
65 object_rows = {}
66 for row in data["rows"]:
67 pk_string = path_from_row_pks(row, pks, not pks)
68 object_rows[pk_string] = row
69 data = object_rows
70 if error:
71 data = {"ok": False, "error": error}
72 elif shape == "array":
73 data = data["rows"]
74 elif shape == "arrays":
75 pass
76 else:
77 status_code = 400
78 data = {
79 "ok": False,
80 "error": "Invalid _shape: {}".format(shape),
81 "status": 400,
82 "title": None,
83 }
84 # Handle _nl option for _shape=array
85 nl = args.get("_nl", "")
86 if nl and shape == "array":
87 body = "\n".join(json.dumps(item) for item in data)
88 content_type = "text/plain"
89 else:
90 body = json.dumps(data, cls=CustomJSONEncoder)
91 content_type = "application/json; charset=utf-8"
92 return {"body": body, "status_code": status_code, "content_type": content_type}