|
13 | 13 | parameter set listed here should also be visited to the |
14 | 14 | :file:`matplotlibrc.template` in matplotlib's root source directory. |
15 | 15 | """ |
| 16 | + |
16 | 17 | from collections.abc import Iterable, Mapping |
17 | | -from functools import reduce |
| 18 | +from functools import partial, reduce |
18 | 19 | import logging |
19 | 20 | import operator |
20 | 21 | import os |
@@ -67,7 +68,7 @@ def __call__(self, s): |
67 | 68 | % (self.key, s, list(self.valid.values()))) |
68 | 69 |
|
69 | 70 |
|
70 | | -def _listify_validator(scalar_validator, allow_stringlist=False): |
| 71 | +def _listify_validator(scalar_validator, allow_stringlist=False, *, doc=None): |
71 | 72 | def f(s): |
72 | 73 | if isinstance(s, str): |
73 | 74 | try: |
@@ -99,7 +100,7 @@ def f(s): |
99 | 100 | f.__name__ = "{}list".format(scalar_validator.__name__) |
100 | 101 | except AttributeError: # class instance. |
101 | 102 | f.__name__ = "{}List".format(type(scalar_validator).__name__) |
102 | | - f.__doc__ = scalar_validator.__doc__ |
| 103 | + f.__doc__ = doc if doc is not None else scalar_validator.__doc__ |
103 | 104 | return f |
104 | 105 |
|
105 | 106 |
|
@@ -144,40 +145,6 @@ def validate_bool_maybe_none(b): |
144 | 145 | raise ValueError('Could not convert "%s" to boolean' % b) |
145 | 146 |
|
146 | 147 |
|
147 | | -def validate_float(s): |
148 | | - """Convert s to float or raise.""" |
149 | | - try: |
150 | | - return float(s) |
151 | | - except ValueError: |
152 | | - raise ValueError('Could not convert "%s" to float' % s) |
153 | | -validate_floatlist = _listify_validator(validate_float) |
154 | | - |
155 | | - |
156 | | -def validate_float_or_None(s): |
157 | | - """Convert s to float, None or raise.""" |
158 | | - # values directly from the rc file can only be strings, |
159 | | - # so we need to recognize the string "None" and convert |
160 | | - # it into the object. We will be case-sensitive here to |
161 | | - # avoid confusion between string values of 'none', which |
162 | | - # can be a valid string value for some other parameters. |
163 | | - if s is None or s == 'None': |
164 | | - return None |
165 | | - try: |
166 | | - return float(s) |
167 | | - except ValueError: |
168 | | - raise ValueError('Could not convert "%s" to float or None' % s) |
169 | | - |
170 | | - |
171 | | -def validate_string_or_None(s): |
172 | | - """Convert s to string or raise.""" |
173 | | - if s is None: |
174 | | - return None |
175 | | - try: |
176 | | - return validate_string(s) |
177 | | - except ValueError: |
178 | | - raise ValueError('Could not convert "%s" to string' % s) |
179 | | - |
180 | | - |
181 | 148 | def _validate_tex_preamble(s): |
182 | 149 | if s is None or s == 'None': |
183 | 150 | return "" |
@@ -215,24 +182,34 @@ def validate_dpi(s): |
215 | 182 | ' could not convert "%s" to float' % (s, s)) |
216 | 183 |
|
217 | 184 |
|
218 | | -def validate_int(s): |
219 | | - """Convert s to int or raise.""" |
220 | | - try: |
221 | | - return int(s) |
222 | | - except ValueError: |
223 | | - raise ValueError('Could not convert "%s" to int' % s) |
| 185 | +def _make_type_validator(cls, *, allow_none=False): |
| 186 | + """ |
| 187 | + Return a validator that converts inputs to *cls* or raises (and possibly |
| 188 | + allows ``None`` as well). |
| 189 | + """ |
224 | 190 |
|
| 191 | + def validator(s): |
| 192 | + if (allow_none and |
| 193 | + (s is None or isinstance(s, str) and s.lower() == "none")): |
| 194 | + return None |
| 195 | + try: |
| 196 | + return cls(s) |
| 197 | + except ValueError: |
| 198 | + raise ValueError(f'Could not convert {s!r} to {cls.__name__}') |
| 199 | + |
| 200 | + return validator |
225 | 201 |
|
226 | | -def validate_int_or_None(s): |
227 | | - """Return None if s is None or return ``int(s)``, otherwise raise.""" |
228 | | - if s == 'None': |
229 | | - s = None |
230 | | - if s is None: |
231 | | - return None |
232 | | - try: |
233 | | - return int(s) |
234 | | - except ValueError: |
235 | | - raise ValueError('Could not convert "%s" to int' % s) |
| 202 | + |
| 203 | +validate_string = _make_type_validator(str) |
| 204 | +validate_string_or_None = _make_type_validator(str, allow_none=True) |
| 205 | +validate_stringlist = _listify_validator( |
| 206 | + validate_string, doc='return a list or strings') |
| 207 | +validate_int = _make_type_validator(int) |
| 208 | +validate_int_or_None = _make_type_validator(int, allow_none=True) |
| 209 | +validate_float = _make_type_validator(float) |
| 210 | +validate_float_or_None = _make_type_validator(float, allow_none=True) |
| 211 | +validate_floatlist = _listify_validator( |
| 212 | + validate_float, doc='return a list of floats') |
236 | 213 |
|
237 | 214 |
|
238 | 215 | def validate_fonttype(s): |
@@ -284,65 +261,37 @@ def validate_qt5(s): |
284 | 261 | return ValidateInStrings("backend.qt5", ['PyQt5', 'PySide2'])(s) |
285 | 262 |
|
286 | 263 |
|
287 | | -def validate_toolbar(s): |
288 | | - validator = ValidateInStrings( |
289 | | - 'toolbar', |
290 | | - ['None', 'toolbar2', 'toolmanager'], |
291 | | - ignorecase=True) |
292 | | - return validator(s) |
293 | | - |
294 | | - |
295 | | -_seq_err_msg = ('You must supply exactly {n} values, you provided {num} ' |
296 | | - 'values: {s}') |
297 | | - |
298 | | -_str_err_msg = ('You must supply exactly {n} comma-separated values, you ' |
299 | | - 'provided {num} comma-separated values: {s}') |
| 264 | +validate_toolbar = ValidateInStrings( |
| 265 | + 'toolbar', ['None', 'toolbar2', 'toolmanager'], ignorecase=True) |
300 | 266 |
|
301 | 267 |
|
302 | | -class validate_nseq_float: |
303 | | - def __init__(self, n=None, allow_none=False): |
304 | | - self.n = n |
305 | | - self.allow_none = allow_none |
| 268 | +def _make_nseq_validator(cls, n=None, allow_none=False): |
306 | 269 |
|
307 | | - def __call__(self, s): |
308 | | - """Return a list of *n* floats or raise.""" |
| 270 | + def validator(s): |
| 271 | + """Convert *n* objects using ``cls``, or raise.""" |
309 | 272 | if isinstance(s, str): |
310 | 273 | s = [x.strip() for x in s.split(',')] |
311 | | - err_msg = _str_err_msg |
| 274 | + if n is not None and len(s) != n: |
| 275 | + raise ValueError( |
| 276 | + f'Expected exactly {n} comma-separated values, ' |
| 277 | + f'but got {len(s)} comma-separated values: {s}') |
312 | 278 | else: |
313 | | - err_msg = _seq_err_msg |
314 | | - |
315 | | - if self.n is not None and len(s) != self.n: |
316 | | - raise ValueError(err_msg.format(n=self.n, num=len(s), s=s)) |
317 | | - |
| 279 | + if n is not None and len(s) != n: |
| 280 | + raise ValueError( |
| 281 | + f'Expected exactly {n} values, ' |
| 282 | + f'but got {len(s)} values: {s}') |
318 | 283 | try: |
319 | | - return [float(val) |
320 | | - if not self.allow_none or val is not None |
321 | | - else val |
| 284 | + return [cls(val) if not allow_none or val is not None else val |
322 | 285 | for val in s] |
323 | 286 | except ValueError: |
324 | | - raise ValueError('Could not convert all entries to floats') |
| 287 | + raise ValueError( |
| 288 | + f'Could not convert all entries to {cls.__name__}s') |
325 | 289 |
|
| 290 | + return validator |
326 | 291 |
|
327 | | -class validate_nseq_int: |
328 | | - def __init__(self, n=None): |
329 | | - self.n = n |
330 | 292 |
|
331 | | - def __call__(self, s): |
332 | | - """Return a list of *n* ints or raise.""" |
333 | | - if isinstance(s, str): |
334 | | - s = [x.strip() for x in s.split(',')] |
335 | | - err_msg = _str_err_msg |
336 | | - else: |
337 | | - err_msg = _seq_err_msg |
338 | | - |
339 | | - if self.n is not None and len(s) != self.n: |
340 | | - raise ValueError(err_msg.format(n=self.n, num=len(s), s=s)) |
341 | | - |
342 | | - try: |
343 | | - return [int(val) for val in s] |
344 | | - except ValueError: |
345 | | - raise ValueError('Could not convert all entries to ints') |
| 293 | +validate_nseq_float = partial(_make_nseq_validator, float) |
| 294 | +validate_nseq_int = partial(_make_nseq_validator, int) |
346 | 295 |
|
347 | 296 |
|
348 | 297 | def validate_color_or_inherit(s): |
@@ -412,21 +361,8 @@ def validate_color(s): |
412 | 361 | raise ValueError('%s does not look like a color arg%s' % (s, msg)) |
413 | 362 |
|
414 | 363 |
|
415 | | -validate_colorlist = _listify_validator(validate_color, allow_stringlist=True) |
416 | | -validate_colorlist.__doc__ = 'return a list of colorspecs' |
417 | | - |
418 | | - |
419 | | -def validate_string(s): |
420 | | - if isinstance(s, str): |
421 | | - # Always leave str as str and unicode as unicode |
422 | | - return s |
423 | | - else: |
424 | | - return str(s) |
425 | | - |
426 | | - |
427 | | -validate_stringlist = _listify_validator(str) |
428 | | -validate_stringlist.__doc__ = 'return a list' |
429 | | - |
| 364 | +validate_colorlist = _listify_validator( |
| 365 | + validate_color, allow_stringlist=True, doc='return a list of colorspecs') |
430 | 366 | validate_orientation = ValidateInStrings( |
431 | 367 | 'orientation', ['landscape', 'portrait']) |
432 | 368 |
|
@@ -578,10 +514,6 @@ def validate_ps_distiller(s): |
578 | 514 | 'top', 'none']) |
579 | 515 | validate_fillstylelist = _listify_validator(validate_fillstyle) |
580 | 516 |
|
581 | | -_validate_negative_linestyle = ValidateInStrings('negative_linestyle', |
582 | | - ['solid', 'dashed'], |
583 | | - ignorecase=True) |
584 | | - |
585 | 517 |
|
586 | 518 | def validate_markevery(s): |
587 | 519 | """ |
|
0 commit comments