Add parameter checks to DayLocator initiator #6955

Merged
merged 4 commits into from Aug 22, 2016

Conversation

Projects
None yet
5 participants

Check that interval parameter is an integer greater than zero.

Delete unuseful 'optimization' meant to prevent exceeding the
MAXTICKS variable. During testing it seemed ineffective. The
following Locator.raise_if_exceeds exception was triggered first
anyways.

resolves #6935

mdboom added the needs_review label Aug 18, 2016

@story645 story645 and 1 other commented on an outdated diff Aug 18, 2016

lib/matplotlib/dates.py
@@ -1254,6 +1241,12 @@ def __init__(self, bymonthday=None, interval=1, tz=None):
Default is to tick every day of the month: ``bymonthday=range(1,32)``
"""
+ if interval < 1:
+ raise ValueError("The interval parameter must be an integer "
@story645

story645 Aug 18, 2016 edited

Member

since these are distinct errors, the messages should probabably be unique:
interval < 1 : The interval must be greater than 0
isinstance(interval, int): the interval must be an integer
(and also, this should then maybe be a TypeError?)
Otherwise you may as well do if interval <1 or not isinstance(interval, int)

@LindyBalboa

LindyBalboa Aug 18, 2016 edited

That makes sense. I thought of both cases. On the one hand, I feel since the parameter is being addressed anyways, it is worthwhile to flat out say both limitations. But on the other, if interval <1 or not isinstance(interval, int) started looking a little full. I figured it was best to just open the PR and get feedback.

I think it is still the better option. I will consolidate it to one check/one exception.

@story645 story645 and 2 others commented on an outdated diff Aug 18, 2016

lib/matplotlib/dates.py
@@ -1241,10 +1241,7 @@ def __init__(self, bymonthday=None, interval=1, tz=None):
Default is to tick every day of the month: ``bymonthday=range(1,32)``
"""
- if interval < 1:
- raise ValueError("The interval parameter must be an integer "
- "greater than or equal to one.")
- if not isinstance(interval, int):
+ if interval < 1 or not isinstance(interval, int):
raise ValueError("The interval parameter must be an integer "
"greater than or equal to one.")
@story645

story645 Aug 18, 2016

Member

I think this can be condensed to:

interval must be an integer greater than 0

And totally absurdly nitpicky, but I'd switch the error checks such that isinstance() check comes first so that the error checks match the order of the error message (which then in turn becomes the documentation of the error check)

@QuLogic

QuLogic Aug 18, 2016

Member

It's actually not that nitpicky. In Python 3, you can't compare two different types so checking the type first will prevent TypeErrors (due to short-circuiting).

@LindyBalboa

LindyBalboa Aug 19, 2016

@story645 Not nitpicky at all. Just keeping things clean!

@QuLogic Any chance you could expand upon that or point me in the right direction to read more? That is interesting and sounds good to know!

@story645

story645 Aug 19, 2016 edited

Member

Basically if for whatever reason interval was passed in as a string, like it was 'a', the comparison
'a'<=1 would throw a 'TypeError'. By checking that it's an integer first, that part of the conditional will fail and therefore the second check (interval<=1) won't ever happen.

@LindyBalboa

LindyBalboa Aug 20, 2016

I understood that part, the part that isn't so clear to me is

In Python 3, you can't compare two different types

@QuLogic

QuLogic Aug 20, 2016

Member
$ python2 
>>> 1 < '0'
True

$ python3
>>> 1 < '0'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < str()

Python 2 will compare incompatible types by the name of the type (which is completely arbitrary); Python 3 is not so forgiving and throws an error.

@LindyBalboa

LindyBalboa Aug 20, 2016

Ah I realize now that is what story645 was trying to explain. I just missed it. Code is clear as day. Thanks guys 👍

LindyBalboa commented Aug 19, 2016 edited

I'm confused as to what happened to the one Travis build. Someone mind taking a look?

I reran the mathtext test locally and it was no problem.

@tacaswell tacaswell and 1 other commented on an outdated diff Aug 20, 2016

lib/matplotlib/dates.py
@@ -1254,6 +1241,8 @@ def __init__(self, bymonthday=None, interval=1, tz=None):
Default is to tick every day of the month: ``bymonthday=range(1,32)``
"""
+ if not isinstance(interval, int) or interval < 1:
@tacaswell

tacaswell Aug 20, 2016

Owner

This will fail on internal == 1.0 which is surprising. I think if not interval == int(interval) is a better test here.

@LindyBalboa

LindyBalboa Aug 20, 2016

That is a fair point, but for a day locator, does that really make sense? I personally think it would be better to enforce the typing in this specific case.

Unless you think it would be a problem with existing code bases, then I suppose catering to compatibility would be preferred.

@tacaswell

tacaswell Aug 20, 2016

Owner

It has a chance of breaking user code. This also breaks in the case of non-python ints, ex

In [56]: d = np.uint8(5)

In [57]: isinstance(d, int)
Out[59]: False

In [60]: d == int(d)
Out[60]: True

isinstance should only be used when there is no other reasonable option.

@LindyBalboa

LindyBalboa Aug 20, 2016

Aha yes that makes sense, especially with the numpy example. I remember now having some nightmares with Qt qints in an old app. I will get that fixed up in the morning.

Owner

tacaswell commented Aug 20, 2016

For reasons un-known the math text tests are flaky, restarted the tests.

LindyBalboa Add parameter checks to DayLocator initiator
Check that interval parameter is an integer greater than zero.

Delete unuseful 'optimization' meant to prevent exceeding the
MAXTICKS variable. During testing it seemed ineffective. The
following Locator.raise_if_exceeds exception was triggered first
anyways.

resolves #6935
7f8c295

LindyBalboa deleted the LindyBalboa:issue_6935 branch Aug 21, 2016

mdboom removed the needs_revision label Aug 21, 2016

LindyBalboa restored the LindyBalboa:issue_6935 branch Aug 21, 2016

LindyBalboa reopened this Aug 21, 2016

mdboom added the needs_review label Aug 21, 2016

LindyBalboa Consolidate DayLocator interval checks
b5c9aa4
Owner

tacaswell commented Aug 21, 2016

Looks good. Can you add a test for that exception being raised on invalid input?

LindyBalboa added some commits Aug 22, 2016

LindyBalboa Add tests for dates.DayLocator
a2a8dc2
LindyBalboa PEP8 fixes
160c55d

@tacaswell tacaswell merged commit a53c4b3 into matplotlib:master Aug 22, 2016

3 checks passed

continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
coverage/coveralls Coverage increased (+0.0009%) to 70.223%
Details

tacaswell removed the needs_review label Aug 22, 2016

@tacaswell tacaswell added a commit that referenced this pull request Aug 22, 2016

@tacaswell tacaswell Merge pull request #6955 from LindyBalboa/issue_6935
MNT: Add parameter checks to DayLocator initiator
125a296
Owner

tacaswell commented Aug 22, 2016

backported to V2.x as 125a296

LindyBalboa deleted the LindyBalboa:issue_6935 branch Aug 22, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment