Skip to content

Make date.{converter,interval_multiples} rcvalidators side-effect free. #21031

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

Merged
merged 1 commit into from
Sep 10, 2021
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
3 changes: 3 additions & 0 deletions doc/api/next_api_changes/behavior/21031-AL.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Setting invalid ``rcParams["date.converter"]`` now raises ValueError
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Previously, invalid values would be ignored with a UserWarning.
62 changes: 25 additions & 37 deletions lib/matplotlib/dates.py
Original file line number Diff line number Diff line change
Expand Up @@ -1890,44 +1890,32 @@ def axisinfo(self, unit, axis):
default_limits=(datemin, datemax))


class _rcParam_helper:
class _SwitchableDateConverter:
"""
This helper class is so that we can set the converter for dates
via the validator for the rcParams `date.converter` and
`date.interval_multiples`. Never instatiated.
Helper converter-like object that generates and dispatches to
temporary ConciseDateConverter or DateConverter instances based on
:rc:`date.converter` and :rc:`date.interval_multiples`.
"""

conv_st = 'auto'
int_mult = True

@classmethod
def set_converter(cls, s):
"""Called by validator for rcParams date.converter"""
if s not in ['concise', 'auto']:
raise ValueError('Converter must be one of "concise" or "auto"')
cls.conv_st = s
cls.register_converters()

@classmethod
def set_int_mult(cls, b):
"""Called by validator for rcParams date.interval_multiples"""
cls.int_mult = b
cls.register_converters()

@classmethod
def register_converters(cls):
"""
Helper to register the date converters when rcParams `date.converter`
and `date.interval_multiples` are changed. Called by the helpers
above.
"""
if cls.conv_st == 'concise':
converter = ConciseDateConverter
else:
converter = DateConverter
@staticmethod
def _get_converter():
converter_cls = {
"concise": ConciseDateConverter, "auto": DateConverter}[
mpl.rcParams["date.converter"]]
interval_multiples = mpl.rcParams["date.interval_multiples"]
return converter_cls(interval_multiples=interval_multiples)

def axisinfo(self, *args, **kwargs):
return self._get_converter().axisinfo(*args, **kwargs)

def default_units(self, *args, **kwargs):
return self._get_converter().default_units(*args, **kwargs)

def convert(self, *args, **kwargs):
return self._get_converter().convert(*args, **kwargs)


interval_multiples = cls.int_mult
convert = converter(interval_multiples=interval_multiples)
units.registry[np.datetime64] = convert
units.registry[datetime.date] = convert
units.registry[datetime.datetime] = convert
units.registry[np.datetime64] = \
units.registry[datetime.date] = \
units.registry[datetime.datetime] = \
_SwitchableDateConverter()
25 changes: 2 additions & 23 deletions lib/matplotlib/rcsetup.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,26 +149,6 @@ def validate_bool(b):
raise ValueError('Could not convert "%s" to bool' % b)


def _validate_date_converter(s):
if s is None:
return
s = validate_string(s)
if s not in ['auto', 'concise']:
_api.warn_external(f'date.converter string must be "auto" or '
f'"concise", not "{s}". Check your matplotlibrc')
return
import matplotlib.dates as mdates
mdates._rcParam_helper.set_converter(s)


def _validate_date_int_mult(s):
if s is None:
return
s = validate_bool(s)
import matplotlib.dates as mdates
mdates._rcParam_helper.set_int_mult(s)


def validate_axisbelow(s):
try:
return validate_bool(s)
Expand Down Expand Up @@ -1036,10 +1016,9 @@ def _convert_validator_spec(key, conv):
"date.autoformatter.second": validate_string,
"date.autoformatter.microsecond": validate_string,

# 'auto', 'concise', 'auto-noninterval'
'date.converter': _validate_date_converter,
'date.converter': ['auto', 'concise'],
# for auto date locator, choose interval_multiples
'date.interval_multiples': _validate_date_int_mult,
'date.interval_multiples': validate_bool,

# legend properties
"legend.fancybox": validate_bool,
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/tests/test_dates.py
Original file line number Diff line number Diff line change
Expand Up @@ -1152,7 +1152,7 @@ def test_change_converter():
fig.canvas.draw()
assert ax.get_xticklabels()[0].get_text() == 'Jan 01 2020'
assert ax.get_xticklabels()[1].get_text() == 'Jan 15 2020'
with pytest.warns(UserWarning) as rec:
with pytest.raises(ValueError):
plt.rcParams['date.converter'] = 'boo'


Expand Down