Skip to content

Commit

Permalink
Avoid silent integer downcast in TimeDelta.deserialize
Browse files Browse the repository at this point in the history
  • Loading branch information
ddelange committed Dec 10, 2024
1 parent 6654eaf commit 1dcc544
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/marshmallow/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -1526,7 +1526,7 @@ def _serialize(self, value, attr, obj, **kwargs):

def _deserialize(self, value, attr, data, **kwargs):
try:
value = self.serialization_type(value)
value = float(value)
except (TypeError, ValueError) as error:
raise self.make_error("invalid") from error

Expand Down
25 changes: 16 additions & 9 deletions tests/test_deserialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,13 @@ def test_timedelta_field_deserialization(self):
assert result.seconds == 42
assert result.microseconds == 0

field = fields.TimeDelta()
result = field.deserialize("42.9")
assert isinstance(result, dt.timedelta)
assert result.days == 0
assert result.seconds == 42
assert result.microseconds == 900000

field = fields.TimeDelta(fields.TimeDelta.SECONDS)
result = field.deserialize(100000)
assert result.days == 1
Expand Down Expand Up @@ -741,7 +748,7 @@ def test_timedelta_field_deserialization(self):
assert isinstance(result, dt.timedelta)
assert result.days == 0
assert result.seconds == 12
assert result.microseconds == 0
assert result.microseconds == 900000

field = fields.TimeDelta(fields.TimeDelta.WEEKS)
result = field.deserialize(1)
Expand Down Expand Up @@ -772,7 +779,7 @@ def test_timedelta_field_deserialization(self):
assert result.microseconds == 456000

total_microseconds_value = 322.0
field = fields.TimeDelta(fields.TimeDelta.MICROSECONDS, float)
field = fields.TimeDelta(fields.TimeDelta.MICROSECONDS)
result = field.deserialize(total_microseconds_value)
assert isinstance(result, dt.timedelta)
unit_value = dt.timedelta(microseconds=1).total_seconds()
Expand All @@ -781,7 +788,7 @@ def test_timedelta_field_deserialization(self):
)

total_microseconds_value = 322.12345
field = fields.TimeDelta(fields.TimeDelta.MICROSECONDS, float)
field = fields.TimeDelta(fields.TimeDelta.MICROSECONDS)
result = field.deserialize(total_microseconds_value)
assert isinstance(result, dt.timedelta)
unit_value = dt.timedelta(microseconds=1).total_seconds()
Expand All @@ -790,7 +797,7 @@ def test_timedelta_field_deserialization(self):
)

total_milliseconds_value = 322.223
field = fields.TimeDelta(fields.TimeDelta.MILLISECONDS, float)
field = fields.TimeDelta(fields.TimeDelta.MILLISECONDS)
result = field.deserialize(total_milliseconds_value)
assert isinstance(result, dt.timedelta)
unit_value = dt.timedelta(milliseconds=1).total_seconds()
Expand All @@ -799,34 +806,34 @@ def test_timedelta_field_deserialization(self):
)

total_seconds_value = 322.223
field = fields.TimeDelta(fields.TimeDelta.SECONDS, float)
field = fields.TimeDelta(fields.TimeDelta.SECONDS)
result = field.deserialize(total_seconds_value)
assert isinstance(result, dt.timedelta)
assert math.isclose(result.total_seconds(), total_seconds_value)

total_minutes_value = 322.223
field = fields.TimeDelta(fields.TimeDelta.MINUTES, float)
field = fields.TimeDelta(fields.TimeDelta.MINUTES)
result = field.deserialize(total_minutes_value)
assert isinstance(result, dt.timedelta)
unit_value = dt.timedelta(minutes=1).total_seconds()
assert math.isclose(result.total_seconds() / unit_value, total_minutes_value)

total_hours_value = 322.223
field = fields.TimeDelta(fields.TimeDelta.HOURS, float)
field = fields.TimeDelta(fields.TimeDelta.HOURS)
result = field.deserialize(total_hours_value)
assert isinstance(result, dt.timedelta)
unit_value = dt.timedelta(hours=1).total_seconds()
assert math.isclose(result.total_seconds() / unit_value, total_hours_value)

total_days_value = 322.223
field = fields.TimeDelta(fields.TimeDelta.DAYS, float)
field = fields.TimeDelta(fields.TimeDelta.DAYS)
result = field.deserialize(total_days_value)
assert isinstance(result, dt.timedelta)
unit_value = dt.timedelta(days=1).total_seconds()
assert math.isclose(result.total_seconds() / unit_value, total_days_value)

total_weeks_value = 322.223
field = fields.TimeDelta(fields.TimeDelta.WEEKS, float)
field = fields.TimeDelta(fields.TimeDelta.WEEKS)
result = field.deserialize(total_weeks_value)
assert isinstance(result, dt.timedelta)
unit_value = dt.timedelta(weeks=1).total_seconds()
Expand Down

0 comments on commit 1dcc544

Please sign in to comment.