Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions pyodata/v2/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
from pyodata.exceptions import PyODataException, PyODataModelError, PyODataParserError

LOGGER_NAME = 'pyodata.model'
FIX_SCREWED_UP_MINIMAL_DATETIME_VALUE = False
FIX_SCREWED_UP_MAXIMUM_DATETIME_VALUE = False

IdentifierInfo = collections.namedtuple('IdentifierInfo', 'namespace name')
TypeInfo = collections.namedtuple('TypeInfo', 'namespace name is_collection')
Expand Down Expand Up @@ -414,8 +416,19 @@ def from_json(self, value):
try:
# https://stackoverflow.com/questions/36179914/timestamp-out-of-range-for-platform-localtime-gmtime-function
value = datetime.datetime(1970, 1, 1, tzinfo=current_timezone()) + datetime.timedelta(milliseconds=int(value))
except ValueError:
raise PyODataModelError(f'Cannot decode datetime from value {value}.')
except (ValueError, OverflowError):
if FIX_SCREWED_UP_MINIMAL_DATETIME_VALUE and int(value) < -62135596800000:
# Some service providers return false minimal date values.
# -62135596800000 is the lowest value PyOData could read.
# This workaroud fixes this issue and returns 0001-01-01 00:00:00+00:00 in such a case.
value = datetime.datetime(year=1, day=1, month=1, tzinfo=current_timezone())
elif FIX_SCREWED_UP_MAXIMUM_DATETIME_VALUE and int(value) > 253402300799999:
value = datetime.datetime(year=9999, day=31, month=12, tzinfo=current_timezone())
else:
raise PyODataModelError(f'Cannot decode datetime from value {value}. '
f'Possible value range: -62135596800000 to 253402300799999. '
f'You may fix this by setting `FIX_SCREWED_UP_MINIMAL_DATETIME_VALUE` '
f' or `FIX_SCREWED_UP_MAXIMUM_DATETIME_VALUE` as a workaround.')

return value

Expand Down
27 changes: 24 additions & 3 deletions tests/test_model_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
PolicyIgnore, Config, PolicyFatal, NullType, NullAssociation, current_timezone, StructType
from pyodata.exceptions import PyODataException, PyODataModelError, PyODataParserError
from tests.conftest import assert_logging_policy
import pyodata.v2.model


def test_edmx(schema):
Expand Down Expand Up @@ -537,10 +538,20 @@ def test_traits_datetime():
assert testdate.microsecond == 0
assert testdate.tzinfo == current_timezone()

# parsing below lowest value with workaround
pyodata.v2.model.FIX_SCREWED_UP_MINIMAL_DATETIME_VALUE = True
testdate = typ.traits.from_json("/Date(-62135596800001)/")
assert testdate.year == 1
assert testdate.month == 1
assert testdate.day == 1
assert testdate.tzinfo == current_timezone()

# parsing the lowest value
with pytest.raises(OverflowError):
pyodata.v2.model.FIX_SCREWED_UP_MINIMAL_DATETIME_VALUE = False
with pytest.raises(PyODataModelError) as e_info:
typ.traits.from_json("/Date(-62135596800001)/")

assert str(e_info.value).startswith('Cannot decode datetime from value -62135596800001.')

testdate = typ.traits.from_json("/Date(-62135596800000)/")
assert testdate.year == 1
assert testdate.month == 1
Expand All @@ -551,9 +562,19 @@ def test_traits_datetime():
assert testdate.microsecond == 0
assert testdate.tzinfo == current_timezone()

# parsing above highest value with workaround
pyodata.v2.model.FIX_SCREWED_UP_MAXIMUM_DATETIME_VALUE = True
testdate = typ.traits.from_json("/Date(253402300800000)/")
assert testdate.year == 9999
assert testdate.month == 12
assert testdate.day == 31
assert testdate.tzinfo == current_timezone()

# parsing the highest value
with pytest.raises(OverflowError):
pyodata.v2.model.FIX_SCREWED_UP_MAXIMUM_DATETIME_VALUE = False
with pytest.raises(PyODataModelError) as e_info:
typ.traits.from_json("/Date(253402300800000)/")
assert str(e_info.value).startswith('Cannot decode datetime from value 253402300800000.')

testdate = typ.traits.from_json("/Date(253402300799999)/")
assert testdate.year == 9999
Expand Down