Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TimeDelta #148

Merged
merged 7 commits into from Feb 20, 2015
Merged

TimeDelta #148

merged 7 commits into from Feb 20, 2015

Conversation

philtay
Copy link
Contributor

@philtay philtay commented Feb 15, 2015

@philtay
Copy link
Contributor Author

philtay commented Feb 15, 2015

The Travis failure is not caused by my code. Can I increase to 110 the line length? It's better.

except (TypeError, AttributeError, ValueError):
value = int(value)
except (TypeError, ValueError):
msg = '{0!r} cannot be interpreted as a valid period of time.'.format(value)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add a test that reaches this branch?

@sloria
Copy link
Member

sloria commented Feb 17, 2015

Looks good. Just a couple more tests, and this should be good to merge.

@philtay
Copy link
Contributor Author

philtay commented Feb 17, 2015

The test_invalid_timedelta_field_deserialization test already reaches the branches you indicated.

# ValueError
int('')

# TypeError
int([])

# OverflowError
field = fields.TimeDelta(fields.TimeDelta.DAYS)
field.deserialize(9999999999)

@sloria
Copy link
Member

sloria commented Feb 17, 2015

Right, those branches are reached; could you also make assertions about the error messages?

e.g.

        with pytest.raises(UnmarshallingError) as excinfo:
            field.deserialize(in_value)
        expected = ('{0!r} cannot be interpreted as '
                    'a valid period of time.').format(in_value)
        assert expected in str(excinfo)

@philtay
Copy link
Contributor Author

philtay commented Feb 17, 2015

Done

@sloria sloria added this to the 2.0-a milestone Feb 17, 2015
return total_seconds(value)
days = value.days
seconds = days * 86400 + value.seconds
microseconds = seconds * 10**6 + value.microseconds
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can save unneeded computation here by only computing to the requested precision. Something like:

    def _serialize(self, value, attr, obj):
        try:
            days = value.days
            if self.precision == self.DAYS:
                return days
            else:
                seconds = days * 86400 + value.seconds
                if self.precision == self.SECONDS:
                    return seconds
                else:  # microseconds
                    return seconds * 10**6 + value.microseconds
        except AttributeError:
            msg = '{0!r} cannot be formatted as a timedelta.'.format()
            raise MarshallingError(getattr(self, 'error', None) or msg)

Perhaps there is a more elegant way, but it would be good remove the extra computation.

@philtay
Copy link
Contributor Author

philtay commented Feb 17, 2015

I thought about it. The CPU cycles waste is really negligible (integer math). Saving them would mean uglier code, like the big try block or a lot of if-else. It doesn't worth it.

@philtay
Copy link
Contributor Author

philtay commented Feb 17, 2015

And I'd be curious to benchmark them: full C speed integer math vs big try and nested if-else. Who will win? :)

@sloria
Copy link
Member

sloria commented Feb 17, 2015

Here's a quick-and-dirty comparison of serializing a bunch of timedeltas to microsecond values: http://nbviewer.ipython.org/gist/sloria/5c1b845a6ec59c2404d0

@philtay
Copy link
Contributor Author

philtay commented Feb 17, 2015

LOL, you really have benchmarked them! However, this confirms that we don't have to worry about performance in this case and that we can avoid ugly code. The difference is negligible and probably within statistical error. Moreover, considering that you have tested with precision='microseconds', the math involved in both TimeDelta1 and TimeDelta2 is exactly the same. Thus the difference in performance can't be attributed to multiplications and additions.

@philtay
Copy link
Contributor Author

philtay commented Feb 17, 2015

You should use precision='days' to get the real difference and then subtract 0.64 sec (5.99 - 5.35). Anyway, if you really prefer the try-if-else approach, please feel free to uglify the code yourself after merge ;)

@sloria
Copy link
Member

sloria commented Feb 19, 2015

Here are comparisons with each level of precision: http://nbviewer.ipython.org/gist/sloria/6229107fa5cea79c80a2. The try-if-else implementation is consistently faster. As expected, the difference is the largest with days.

If you don't want to make the change, I'll go ahead and make it when I merge.

@philtay
Copy link
Contributor Author

philtay commented Feb 19, 2015

ok, make the change when you merge

@sloria sloria merged commit 3a9efaf into marshmallow-code:dev Feb 20, 2015
@sloria sloria mentioned this pull request Feb 20, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants