ENH: Stricter validation of line style rcParams (and extended accepted types for `grid.linestyle`) #8040

Merged
merged 15 commits into from Feb 18, 2017

Conversation

Projects
None yet
6 participants
Contributor

afvincent commented Feb 7, 2017 edited

A possible “solution” to #7991 (suggested by @tacaswell on Gitter, February 7, 2017 12:09 PM) . The user could now use a sequence like [1.0, 3.0] for the rcParam grid.linestyle.

The validation is not extensive, partly because I was not sure it should be performed here. For example, one can perfectly pass a value like u'Hello world' without the new function validate_grid_linestyle raising an error. Should I set the only accepted strings to be in cbook.ls_mapper and cbook.ls_mapper_r?

Edit: typo + link to Gitter.

afvincent added some commits Feb 7, 2017

@afvincent afvincent extend 'grid.linestyle' valid types to on-off ink sequences 061061b
@afvincent afvincent extend 'add test for the new function 'validate_grid_linestyle'
5be29b5

afvincent added the rcparams label Feb 7, 2017

afvincent added this to the 2.0.1 (next bug fix release) milestone Feb 7, 2017

Owner

tacaswell commented Feb 7, 2017

It does not make the validation weaker at least.

Contributor

afvincent commented Feb 7, 2017

I could make the validation stronger in the case of strings if you think it is better.

afvincent referenced this pull request Feb 7, 2017

Merged

Api lw scale clipping #8032

lib/matplotlib/rcsetup.py
+ pass
+
+ raise ValueError("'grid.linestyle' must be a string or " +
+ "a even-length sequence of floats.")
@afvincent

afvincent Feb 7, 2017 edited

Contributor

Note to myself for tomorrow: “an even” (done)

@afvincent afvincent fix a small typo
25efd07
Contributor

dopplershift commented Feb 8, 2017

Shouldn't this be applied for all linestyles, not just grid?

Owner

tacaswell commented Feb 9, 2017

👍 to @dopplershift suggestion to add this to all of the rcparams that take linestyle.

Interestingly, for negative contours, there is a commit from 2007 (4682b0c) which deprecated passing in that linestyle as a on/off pattern.

Contributor

afvincent commented Feb 9, 2017

I am not sure it is exactly the same situation:

  • for “normal” line styles, the non solid patterns are defined through the ad-hoc rcParams (e.g. lines.dashed_pattern), and then the rcParam lines.linestyle is expected to be a named one, in {'solid', '-', 'dashed', '--', 'dashdot', '-.', 'dotted', ':'}. Introducing the possibility to pass directly a on-off sequence seems to be doing twice the job to me :/.
  • for the rcParam grid.linestyle, the idea was to relax the validation to also accept on-off sequences because we did not want to introduce the equivalent rcParams like grid.dashed_patterns to avoid excessive granularity, but still wanted to give the possibility to use a non solid line style that is different from the “normal” ones.

By the way, I have the feeling that the deprecated validation for the negative contour line style is a bit restrictive: it seems like only 2-element sequences are accepted (i.e. [3, 1, 1, 1] would be rejected for example, if I am correct…).

Contributor

dopplershift commented Feb 9, 2017

Counterpoint: why on earth, from a user standpoint, is configuring grid linestyle different from the other linestyles? I get the programmer concerns, but from a UX perspective, we're giving users a new thing to learn with no justification. Feels like a set of features that grew over time (which it is) rather than a cohesive design (which is what people want).

Contributor

afvincent commented Feb 9, 2017

Fair enough :), I am going to relax the validation of all the 'linestyle' rcParams, i.e.:

In [4]: [key for key in plt.rcParams if u'linestyle' in key]
Out[4]: 
[u'boxplot.boxprops.linestyle',
 u'boxplot.capprops.linestyle',
 u'boxplot.flierprops.linestyle',
 u'boxplot.meanprops.linestyle',
 u'boxplot.medianprops.linestyle',
 u'boxplot.whiskerprops.linestyle',
 u'contour.negative_linestyle',  # beware of the existing deprecation
 u'grid.linestyle',
 u'lines.linestyle']

to accept on-off sequences.

afvincent added some commits Feb 9, 2017

@afvincent afvincent Relax validation for all ls-related rcParams but contour.negative_lin…
…estyle
5cb183c
@afvincent afvincent Check that strings are valid line styles
d9ff6a8
Contributor

afvincent commented Feb 9, 2017

Now all the rcParams related to a line style (but contour.negative_linestyle) can be passed an on-off ink sequence. Besides, I added an early check that if a string is given, then it has to be one that will be accepted by Line2D.set_linestyle.

How should I handle the case of contour.negative_linestyle? It seems like a long time ago, one could pass an on-off ink sequence, but then is was deprecated to only accept a named line style (see validate_negative_linestyle_legacy in rcsetup.py). Should I deprecate the deprecation (\o/) to use the new validator validate_linestyle too? If it is, what has to be done: where can I find doc on the (current) deprecation process?

@afvincent afvincent fix PEP8
44c3fde
Contributor

afvincent commented Feb 9, 2017

Sorry, my current text editor does not yell at me when scripts are not PEP8-compliant… The other CI failure does not seem related (about “mathtext_dejavusans_21”).

Owner

efiring commented Feb 9, 2017

@afvincent afvincent use validate_linestyle even for rcParam 'contour.negative_linestyle'
e8032df
Contributor

afvincent commented Feb 10, 2017

I removed the former validatorsvalidate_negative_contour and validate_negative_contour_legacy, to now consistently rely on the new validator for all the line style-related rcParams.

There may be a (minor) break of behavior: in the new validator, I have chosen to be case-sensitive (to discourage users' jokes like “DaSHdOtTed”), while the former validator for contour.negative_linestyle was not (the ignorecase kwarg was set to True). Was this a mistake?

lib/matplotlib/rcsetup.py
+
+# A validator for all possible line styles, the named ones *and*
+# the on-off ink sequences.
+def validate_linestyle(ls):
@NelleV

NelleV Feb 13, 2017

Contributor

can we make this a private function? I don't think it should be added to our public API.

lib/matplotlib/rcsetup.py
@@ -888,6 +872,36 @@ def validate_animation_writer_path(p):
modules["matplotlib.animation"].writers.set_dirty()
return p
+# A validator dedicated to the named line styles, based on the items in
+# ls_mapper, and a list of possible strings read from Line2D.set_linestyle
+validate_named_linestyle = ValidateInStrings('linestyle',
@NelleV

NelleV Feb 13, 2017

Contributor

same here. this should not appear in our public API.

@afvincent

afvincent Feb 13, 2017

Contributor

Ok I'll do that! (I was hesitating because most of the other validators are public).

Speaking of public API, I think I've done something wrong (🐑) by genuinely getting rid off of validate_negative_linestyle and validate_negative_linestyle_legacy as they were both part of the public API. I should have used some deprecation warning instead, shouldn't I? Or at least just leave them (because if validate_linestyle is made private, there will be no alternative)?

Member

WeatherGod commented Feb 13, 2017

Contributor

dopplershift commented Feb 13, 2017 edited

I'm only in favor of limiting user choice to prevent dangerous behavior/common mistakes--not silly/poor choices.

Having said that, it's much more important to me for it to be consistent with the rest of the library (like @WeatherGod said).

Contributor

afvincent commented Feb 13, 2017

From what I understand, color validation is case insensitive. In _to_rgba_no_colorcycle, which is called during the process, one can read:

...
# Named color.
    try:
        # This may turn c into a non-string, so we check again below.
        c = _colors_full_map[c.lower()]
...

where c is the “color” under test. However on the 20+ instances of ValidateInStrings, more than half of them are case sensitive.

Anyway, I guess that making _validate_linestyle case insensitive will not be dangerous and it will avoid a deprecation process to warn people that would have been using named line styles not fully in lower case for negative contours.

afvincent added some commits Feb 13, 2017

@afvincent afvincent Reintroduce former public validators for negative contours (but they …
…are not used anymore)
2673585
@afvincent afvincent make validate_linestyle private and case insensitive (+ adapt relevan…
…t test)
7bd9bfe
@afvincent afvincent Remove deprecation warning in 'validate_negative_linestyle_legacy' ad21964
@afvincent afvincent Deprecate former validation schemes used by 'contour.negative_linestyle'
7ab75f5
Contributor

afvincent commented Feb 14, 2017

The new validation scheme is now private and case-insensitive :).

I have reintroduced the former validators related to the contour.negative_linestyle rcParam, because they were part of the public API. I have nonetheless added a (lazy) deprecation warning about them. Not totally sure I followed the canonical way to do this though :/.

@afvincent afvincent Fix typo (a forgotten 'return' statement...)
59328e6
Contributor

afvincent commented Feb 14, 2017

One last thing that bothers me a bit is that the (newly deprecated) former validators validate_negative_linestyle and validate_negative_linestyle_legacy do not seem bugfree (but even before this PR they were not tested, so it seems to have stayed under the radar…). See for example this traceback when (the current) validate_negative_linestyle_legacy is called with a simple 2-element list:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-2-667b565f2256> in <module>()
----> 1 validate_negative_linestyle_legacy([1, 2])

/home/adrien/matplotlib/lib/matplotlib/cbook/deprecation.pyc in wrapper(*args, **kwargs)
    204         def wrapper(*args, **kwargs):
    205             warnings.warn(message, mplDeprecation, stacklevel=2)
--> 206             return func(*args, **kwargs)
    207 
    208         old_doc = textwrap.dedent(old_doc or '').strip('\n')

/home/adrien/matplotlib/lib/matplotlib/rcsetup.pyc in validate_negative_linestyle_legacy(s)
    549 def validate_negative_linestyle_legacy(s):
    550     try:
--> 551         res = validate_negative_linestyle(s)
    552         return res
    553     except ValueError:

/home/adrien/matplotlib/lib/matplotlib/cbook/deprecation.pyc in wrapper(*args, **kwargs)
    204         def wrapper(*args, **kwargs):
    205             warnings.warn(message, mplDeprecation, stacklevel=2)
--> 206             return func(*args, **kwargs)
    207 
    208         old_doc = textwrap.dedent(old_doc or '').strip('\n')

/home/adrien/matplotlib/lib/matplotlib/rcsetup.pyc in validate_negative_linestyle(s)
    540                       "deprecation warning for more information."))
    541 def validate_negative_linestyle(s):
--> 542     return _validate_negative_linestyle(s)
    543 
    544 

/home/adrien/matplotlib/lib/matplotlib/rcsetup.pyc in __call__(self, s)
     64     def __call__(self, s):
     65         if self.ignorecase:
---> 66             s = s.lower()
     67         if s in self.valid:
     68             return self.valid[s]

AttributeError: 'list' object has no attribute 'lower'

I think it may be fixed by simply catching AttributeErrorexception in the same way as ValueError exceptions are caught in validate_negative_linestyle_legacy. Should I do this fix too, or is it not worth it due to the deprecation?

Contributor

afvincent commented Feb 14, 2017

The Travis failure seems unrelated to this PR. It is complaining about test_mixedsubplots in mplot3d, which has been rather flaky recently.

Member

WeatherGod commented Feb 14, 2017

lib/matplotlib/rcsetup.py
+@deprecated('3.0.0?', pending=True,
@NelleV

NelleV Feb 16, 2017

Contributor

Why can't we deprecate this "for sure"?

@afvincent

afvincent Feb 16, 2017

Contributor

So, something like

@deprecated(the version number you will kindly suggest,  # :)
            addendum=(" See 'validate_negative_linestyle_legacy' " +
                      "deprecation warning for more information.")
            )

would be better?

@NelleV

NelleV Feb 17, 2017

Contributor

Yes :D
I suggest deprecating this in 2.1, which means no backporting. Is that a problem?

@#{review_dismissed_event.actor.login} NelleV dismissed their review Feb 16, 2017

All comments have been addressed

NelleV changed the title from ENH: Extend accepted type for the rcParam `grid.linestyle` to [MRG+1] ENH: Extend accepted type for the rcParam `grid.linestyle` Feb 16, 2017

Contributor

NelleV commented Feb 16, 2017

I'd like to understand why the deprecations are pending, and why we are deprecating for 3.0.0 (and not for 2.3). Else it looks good (I'll approve one @afvincent clarifies this point).

Contributor

afvincent commented Feb 16, 2017

@NelleV Well… It simply reflects that I do not understand how the process of deprecation goes ^^…
Does “deprecated in 2.x” means
i) “This function should not be used anymore and might disappear in release 2.x + 0.2 and beyond”, or
ii) “This function might disappear at any moment since release 2.x”?
Then in case i) the deprecation should start at 2.0.1 (milestone of this PR), while in case ii) it should be 2.2 (or even later?).
For me, the current @deprecated decorators mean “We might remove this function after mpl 3 is released”, and the pending=True was used to avoid the message to be The ... function was deprecated in version 3.0.0. ..., which sounds weird. But apparently I am wrong and they are only meaning this to my eyes, so I will be happy to change the @deprecated decorators for the version number that you prefer ;) (and I will remove pending=True).

Contributor

afvincent commented Feb 16, 2017

Sidenote: I think a what's new entry might be a good thing. Unless anybody stand up against it, I will add one at the same time I will update the @deprecated decorators (likely tomorrow from this side of the Atlantic ocean).

Contributor

NelleV commented Feb 17, 2017

Deprecated in 2.1 means it will be removed in 2.3.
We should not deprecate for 2.0.1 as deprecation should not happen in micro releases (but integrating the code with the warning that it is deprecated in 2.1 and removed in 2.3 is totally fine with me).

👍 on the what's new entry.

Owner

tacaswell commented Feb 17, 2017

I think it is fine to push this to 2.1 (changed my mind).

afvincent added some commits Feb 17, 2017

@afvincent afvincent Fix the deprecation decorators 70e87c8
@afvincent afvincent Add a what's new entry
c060842
Contributor

afvincent commented Feb 17, 2017

Ok, the deprecations now start at 2.1. And I have added a what's new entry. Maybe it would be wise if an native English-speaker could have a look.

PS: I have changed the PR title because actually all line style rcParams are now affected by this PR ;).

afvincent changed the title from [MRG+1] ENH: Extend accepted type for the rcParam `grid.linestyle` to [MRG+1] ENH: Stricter validation of line style rcParams (and extended accepted types for `grid.linestyle`) Feb 17, 2017

@afvincent afvincent Fix a typo with the example in the what's new entry
aabf385

@NelleV NelleV merged commit 6450ce2 into matplotlib:master Feb 18, 2017

5 checks passed

codecov/patch 93.75% of diff hit (target 80%)
Details
codecov/project/library 62.29% (+0.01%) compared to c15694b
Details
codecov/project/tests 97.97% (target 97.7%)
Details
continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
Contributor

NelleV commented Feb 18, 2017

Thanks!

QuLogic changed the title from [MRG+1] ENH: Stricter validation of line style rcParams (and extended accepted types for `grid.linestyle`) to ENH: Stricter validation of line style rcParams (and extended accepted types for `grid.linestyle`) Feb 19, 2017

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