Skip to content

Commit e8f4025

Browse files
authored
Provide json.dumps an encoder for datetime (#15)
- add util wrapper for json.dumps - declares default encoder for datetime, datetime.date values - tests and fixes #14
1 parent 2b82f3e commit e8f4025

File tree

13 files changed

+217
-134
lines changed

13 files changed

+217
-134
lines changed

labkey/domain.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from __future__ import unicode_literals
1717
import json
1818

19-
from labkey.utils import ServerContext
19+
from labkey.utils import json_dumps, ServerContext
2020

2121

2222
def strip_none_values(data, do_strip=True):
@@ -326,7 +326,7 @@ def create(server_context, domain_definition, container_path=None):
326326

327327
domain = None
328328

329-
raw_domain = server_context.make_request(url, json.dumps(domain_definition), headers=headers)
329+
raw_domain = server_context.make_request(url, json_dumps(domain_definition), headers=headers)
330330

331331
if raw_domain is not None:
332332
domain = Domain.from_data(raw_domain)
@@ -355,7 +355,7 @@ def drop(server_context, schema_name, query_name, container_path=None):
355355
'queryName': query_name
356356
}
357357

358-
return server_context.make_request(url, json.dumps(payload), headers=headers)
358+
return server_context.make_request(url, json_dumps(payload), headers=headers)
359359

360360

361361
def get(server_context, schema_name, query_name, container_path=None):
@@ -431,4 +431,4 @@ def save(server_context, schema_name, query_name, domain, container_path=None):
431431
'schemaName': schema_name
432432
}
433433

434-
return server_context.make_request(url, json.dumps(payload), headers=headers)
434+
return server_context.make_request(url, json_dumps(payload), headers=headers)

labkey/experiment.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@
1414
# limitations under the License.
1515
#
1616
from __future__ import unicode_literals
17-
import json
1817

19-
from labkey.utils import ServerContext
18+
from labkey.utils import json_dumps, ServerContext
2019

2120

2221
# TODO Incorporate logging
@@ -42,7 +41,7 @@ def load_batch(server_context, assay_id, batch_id):
4241
'Accept': 'text/plain'
4342
}
4443

45-
json_body = server_context.make_request(load_batch_url, json.dumps(payload, sort_keys=True), headers=headers)
44+
json_body = server_context.make_request(load_batch_url, json_dumps(payload, sort_keys=True), headers=headers)
4645
if json_body is not None:
4746
loaded_batch = Batch.from_data(json_body['batch'])
4847

@@ -95,7 +94,7 @@ def save_batches(server_context, assay_id, batches):
9594
'Accept': 'text/plain'
9695
}
9796

98-
json_body = server_context.make_request(save_batch_url, json.dumps(payload, sort_keys=True), headers=headers)
97+
json_body = server_context.make_request(save_batch_url, json_dumps(payload, sort_keys=True), headers=headers)
9998
if json_body is not None:
10099
resp_batches = json_body['batches']
101100
return [Batch.from_data(resp_batch) for resp_batch in resp_batches]

labkey/query.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
############################################################################
4242
"""
4343
from __future__ import unicode_literals
44-
import json
44+
45+
from labkey.utils import json_dumps
4546

4647
_query_headers = {
4748
'Content-Type': 'application/json'
@@ -80,7 +81,7 @@ def delete_rows(server_context, schema_name, query_name, rows, container_path=No
8081
'rows': rows
8182
}
8283

83-
return server_context.make_request(url, json.dumps(payload, sort_keys=True), headers=_query_headers, timeout=timeout)
84+
return server_context.make_request(url, json_dumps(payload, sort_keys=True), headers=_query_headers, timeout=timeout)
8485

8586

8687
def execute_sql(server_context, schema_name, sql, container_path=None,
@@ -161,7 +162,7 @@ def insert_rows(server_context, schema_name, query_name, rows, container_path=No
161162
'rows': rows
162163
}
163164

164-
return server_context.make_request(url, json.dumps(payload, sort_keys=True), headers=_query_headers,
165+
return server_context.make_request(url, json_dumps(payload, sort_keys=True), headers=_query_headers,
165166
timeout=timeout)
166167

167168

@@ -281,7 +282,7 @@ def update_rows(server_context, schema_name, query_name, rows, container_path=No
281282
'rows': rows
282283
}
283284

284-
return server_context.make_request(url, json.dumps(payload, sort_keys=True), headers=_query_headers,
285+
return server_context.make_request(url, json_dumps(payload, sort_keys=True), headers=_query_headers,
285286
timeout=timeout)
286287

287288

labkey/unsupported/wiki.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323
"""
2424
from __future__ import unicode_literals
2525

26-
import json
2726
from requests.exceptions import SSLError
2827

28+
from labkey.utils import json_dumps
29+
2930

3031
def update_wiki(server_context, wiki_name, wiki_body, container_path=None):
3132
"""
@@ -100,7 +101,7 @@ def update_wiki(server_context, wiki_name, wiki_body, container_path=None):
100101
wiki_vars['body'] = wiki_body
101102

102103
try:
103-
data = server_context.make_request(update_wiki_url, payload=json.dumps(wiki_vars, sort_keys=True),
104+
data = server_context.make_request(update_wiki_url, payload=json_dumps(wiki_vars, sort_keys=True),
104105
headers=headers, non_json_response=True)
105106
except SSLError as e:
106107
print("There was a problem while attempting to submit the read for the wiki page '" + str(wiki_name) + "' via the URL " + str(e.geturl()) + ". The HTTP response code was " + str(e.getcode()))

labkey/utils.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
from __future__ import unicode_literals
1717

1818
import requests
19+
import json
20+
from functools import wraps
21+
from datetime import date, datetime
1922

2023
from requests.exceptions import RequestException
2124
from labkey.exceptions import RequestError, RequestAuthorizationError, QueryNotFoundError, ServerContextError, \
@@ -179,3 +182,18 @@ def handle_response(response, non_json_response=False):
179182
else:
180183
# consider response.raise_for_status()
181184
raise RequestError(response)
185+
186+
187+
# Issue #14: json.dumps on datetime throws TypeError
188+
class DateTimeEncoder(json.JSONEncoder):
189+
def default(self, o):
190+
if isinstance(o, (datetime, date)):
191+
return o.isoformat()
192+
193+
return super(DateTimeEncoder, self).default(o)
194+
195+
196+
@wraps(json.dumps)
197+
def json_dumps(*args, **kwargs):
198+
kwargs.setdefault('cls', DateTimeEncoder)
199+
return json.dumps(*args, **kwargs)

test/test_domain.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from labkey.domain import create, Domain, drop, get, infer_fields, save
2929
from labkey.exceptions import RequestAuthorizationError
3030

31-
from test_utils import MockLabKey, mock_server_context, success_test, success_test_get, throws_error_test, throws_error_test_get
31+
from utilities import MockLabKey, mock_server_context, success_test, success_test_get, throws_error_test, throws_error_test_get
3232

3333

3434
domain_controller = 'property'

test/test_experiment_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from labkey.experiment import load_batch, save_batch, Batch, Run
2626
from labkey.exceptions import RequestError, QueryNotFoundError, ServerNotFoundError, RequestAuthorizationError
2727

28-
from test_utils import MockLabKey, mock_server_context, success_test, throws_error_test
28+
from utilities import MockLabKey, mock_server_context, success_test, throws_error_test
2929

3030

3131
class MockLoadBatch(MockLabKey):

test/test_labkey.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from test_query_api import suite as query_suite
2323
from test_security import suite as security_suite
2424
from test_unsupported import suite as unsupported_suite
25+
from test_utils import suite as utils_suite
2526

2627
if __name__ == '__main__':
2728

@@ -35,6 +36,7 @@
3536
exp_suite(),
3637
query_suite(),
3738
security_suite(),
38-
unsupported_suite()
39+
unsupported_suite(),
40+
utils_suite()
3941
])
4042
unittest.TextTestRunner().run(all_tests)

test/test_query_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from labkey.query import delete_rows, update_rows, insert_rows, select_rows, execute_sql
2626
from labkey.exceptions import RequestError, QueryNotFoundError, ServerNotFoundError, RequestAuthorizationError
2727

28-
from test_utils import MockLabKey, mock_server_context, success_test, throws_error_test
28+
from utilities import MockLabKey, mock_server_context, success_test, throws_error_test
2929

3030

3131
class MockSelectRows(MockLabKey):

test/test_security.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
remove_from_group, remove_from_role, add_to_role, get_roles, list_groups
2828
from labkey.exceptions import RequestError, QueryNotFoundError, ServerNotFoundError, RequestAuthorizationError
2929

30-
from test_utils import MockLabKey, mock_server_context, success_test, throws_error_test
30+
from utilities import MockLabKey, mock_server_context, success_test, throws_error_test
3131

3232

3333
class MockSecurityController(MockLabKey):

0 commit comments

Comments
 (0)