Skip to content

Commit c0e526b

Browse files
Closes #80: Revised default deserializer logic for datetime.timedelta and datetime.datetime values.
1 parent da7ea6b commit c0e526b

File tree

3 files changed

+93
-6
lines changed

3 files changed

+93
-6
lines changed

CHANGES.rst

+31
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,36 @@
11
-----------
22

3+
Release 0.5.1
4+
=========================================
5+
6+
.. image:: https://travis-ci.org/insightindustry/sqlathanor.svg?branch=v.0.5.1
7+
:target: https://travis-ci.org/insightindustry/sqlathanor
8+
:alt: Build Status (Travis CI)
9+
10+
.. image:: https://codecov.io/gh/insightindustry/sqlathanor/branch/v.0.5.1/graph/badge.svg
11+
:target: https://codecov.io/gh/insightindustry/sqlathanor
12+
:alt: Code Coverage Status (Codecov)
13+
14+
.. image:: https://readthedocs.org/projects/sqlathanor/badge/?version=v.0.5.1
15+
:target: http://sqlathanor.readthedocs.io/en/latest/?badge=v.0.5.1
16+
:alt: Documentation Status (ReadTheDocs)
17+
18+
Bug Fixes
19+
-----------------
20+
21+
* #80: Revised how the default deserializer functions for ``datetime.timedelta``
22+
and ``datetime.datetime`` objects functions. When deserializing either, the
23+
default deserializer now starts by attempting to coerce the value to a
24+
``datetime.timedelta`` using the Validator Collection ``timedelta()`` validator
25+
function, which supports the expression of amounts of time as both integers (e.g.
26+
``23 seconds``) and strings (e.g. ``00:00:23``). If the object cannot be
27+
converted to a ``timedelta`` (if it is a complete / proper datetime with both
28+
a time and date value), the default deserializer will then revert to returning
29+
a ``datetime.datetime`` object.
30+
31+
32+
-----------
33+
334
Release 0.5.0
435
=========================================
536

sqlathanor/default_deserializers.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,11 @@ def from_date(value):
8585
return validators.date(value, allow_empty = True)
8686

8787
def from_datetime(value):
88-
if checkers.is_numeric(value):
89-
return from_timedelta(value)
88+
try:
89+
value = validators.timedelta(value, allow_empty = True)
90+
return value
91+
except (ValueError, TypeError):
92+
pass
9093

9194
return validators.datetime(value, allow_empty = True)
9295

@@ -108,11 +111,9 @@ def from_iterable(value):
108111
return validators.iterable(value, allow_empty = True)
109112

110113
def from_timedelta(value):
111-
value = validators.integer(value, allow_empty = True)
112-
if value is None:
113-
return value
114+
value = validators.timedelta(value, allow_empty = True)
114115

115-
return datetime.timedelta(seconds = value)
116+
return value
116117

117118
def from_mac_address(value):
118119
return validators.mac_address(value, allow_empty = True)
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# -*- coding: utf-8 -*-
2+
3+
"""
4+
******************************************
5+
tests.test_interval_deserialization
6+
******************************************
7+
8+
Tests for how SQLAthanor deserializes Interval columns.
9+
10+
"""
11+
12+
import pytest
13+
import datetime
14+
15+
from tests.fixtures import db_engine, tables, base_model, db_session, \
16+
model_complex_postgresql, instance_postgresql
17+
18+
from sqlathanor.errors import InvalidFormatError, ValueDeserializationError, \
19+
UnsupportedDeserializationError
20+
21+
22+
23+
@pytest.mark.parametrize('attribute, format, input_value, expected_result, error', [
24+
('name', 'csv', 'serialized', 'deserialized', None),
25+
('id', 'csv', '1', 1, None),
26+
('hybrid', 'csv', 1, 1, None),
27+
('smallint_column', 'csv', '2', 2, None),
28+
('addresses', 'json', [], [], None),
29+
('time_delta', 'csv', 86400.0, datetime.timedelta(1), None),
30+
('time_delta', 'csv', '00:35:00', datetime.timedelta(minutes = 35), None),
31+
('time_delta', 'csv', '00:35:00.456', datetime.timedelta(minutes = 35, milliseconds = 456), None),
32+
('name', 'invalid', None, None, InvalidFormatError),
33+
('missing', 'csv', None, None, UnsupportedDeserializationError),
34+
('hidden', 'csv', None, None, UnsupportedDeserializationError),
35+
('id', 'csv', 'invalid', None, ValueDeserializationError),
36+
('time_delta', 'csv', 'not-numeric', None, ValueDeserializationError),
37+
('time_delta', 'json', 86400.0, None, UnsupportedDeserializationError),
38+
('time_delta', 'json', '00:35:00', None, UnsupportedDeserializationError),
39+
40+
])
41+
def test__get_deserialized_value(request,
42+
instance_postgresql,
43+
attribute,
44+
format,
45+
input_value,
46+
expected_result,
47+
error):
48+
target = instance_postgresql[0][0]
49+
50+
if not error:
51+
result = target._get_deserialized_value(input_value, format, attribute)
52+
assert result == expected_result
53+
else:
54+
with pytest.raises(error):
55+
result = target._get_deserialized_value(input_value, format, attribute)

0 commit comments

Comments
 (0)