Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitcad68af

Browse files
committed
MEP32: matplotlibrc/mplstyle with Python syntax.
1 parent969de0a commitcad68af

File tree

1 file changed

+246
-0
lines changed

1 file changed

+246
-0
lines changed

‎doc/devel/MEP/MEP32.rst

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
MEP32: ``matplotlibrc``/``mplstyle`` with Python syntax
2+
=======================================================
3+
4+
..contents:::local:
5+
6+
Status
7+
------
8+
9+
Discussion
10+
11+
Branches and Pull Requests
12+
--------------------------
13+
14+
None
15+
16+
Abstract
17+
--------
18+
19+
I propose to replace ``matplotlibrc`` and ``mplstyle`` files (henceforth
20+
"old-style configs") by files using regular Python syntax (henceforth
21+
"new-style configs"). This will fix a number of issues that currently exist
22+
with parsing old-style configs.
23+
24+
Detailed description
25+
--------------------
26+
27+
The problem
28+
~~~~~~~~~~~
29+
30+
Current ("old-style") configuration files use a custom syntax, of the form
31+
32+
..code::conf
33+
34+
key: value # possible comment
35+
key: value
36+
37+
For each allowable key, a specific parser is defined in ``mpl.rcsetup``,
38+
possibly via some helper functions. Typical parsers parse booleans, numbers,
39+
strings (always unquoted), enumerated strings, comma-separated lists of the
40+
above-mentioned types, etc.
41+
42+
However, some desirable inputs are difficult to parse, or currently only
43+
partially parsed:
44+
45+
- Property cycles (e.g., ``axes.prop_cycle``), of the form ::
46+
47+
cycler("key", [value1, value2, ...])
48+
49+
are currently simply parsed via ``eval`` in a restricted environment
50+
(`#6274`_), which may (or may not) be a security hole (especially combined
51+
with the ability to load style files from an URL).
52+
53+
- Path effects (e.g., for implementing an XKCD style sheet, `#6157`_). They
54+
would have a form similar to ::
55+
56+
patheffects.withStroke(linewidth=4, foreground="w")
57+
58+
and would, like ``cycler``\s, require either a custom parser or being
59+
``eval``'d.
60+
61+
- Long inputs (e.g. property cycles) cannot be split over multiple lines, as
62+
the parser has no support for line continuations (`#9184`_).
63+
64+
- LaTeX and PGF preambles (multiple, comma separated strings) cannot contain
65+
commas, because commas are replaced by newlines by the parser (`#4371`_).
66+
Note that commas are in fact fairly common in "normal" LaTeX preambles (e.g.,
67+
``\usepackage[option1, option2]{package}``. Actually inputting the preamble
68+
over multiple lines is not possible due to the lack of multiline support (see
69+
above).
70+
71+
- Strings cannot contain the hash (``#``) symbol, as strings are unquoted and
72+
the hash is unconditionally interpreted as the start of a comment (`#7089`_).
73+
The hash symbol had been proposed to indicate a "plus" marker.
74+
75+
- Dash specs of the form ``(offset, (ink-on, ink-off, in-on, ...))`` are
76+
misparsed: while ::
77+
78+
plt.plot([1, 2], ls=(0, (5, 5)))
79+
80+
works just fine, ::
81+
82+
plt.rcParams["lines.linestyle"] = (0, (5, 5))
83+
84+
and ::
85+
86+
plt.rcParams["lines.linestyle"] = "(0, (5, 5))"
87+
88+
as well as setting this value in ``matplotlibrc`` all raise an exception
89+
(indirectly a cause of `#7219`_).
90+
91+
- Custom color palettes (redefining the meaning of ``"r"``, ``"g"``, ``"b"``,
92+
etc. as seaborn used to do) has been proposed (`#8430`_), but the
93+
hypothetical rcParam value would have a type of ``Dict[str, Dict[str, str]]``
94+
(mapping palettes to mappings of color names to color values), which was
95+
described by @tacaswell as "not too hard to parse" but "would further stress
96+
our current configuration system".
97+
98+
Overall, the syntax of the config file is defined as "whatever the parser
99+
accepts" (`#3670`_).
100+
101+
An additional feature that has been requested (but shoudl not be particularly
102+
difficult to implement using the current machinery) is "cascading" style
103+
sheets, either by adding a ``style`` key to style files (`#4240`_) or by
104+
loading all ``matplotlibrc``\s in order (`#6320`_).
105+
106+
Proposed solution
107+
~~~~~~~~~~~~~~~~~
108+
109+
Instead of playing whack-a-mole with parser bugs, I propose to replace the
110+
syntax of config files to simply use Python config. Two main possibilities are
111+
considered below. In all cases, it is necessary to encode, in a way or
112+
another, that the config file uses the new syntax, so that Matplotlib can tell
113+
which file-parser to use.
114+
115+
Maintain a matplotlibrc-like layout
116+
```````````````````````````````````
117+
118+
The config files would maintain the format
119+
120+
..code::conf
121+
122+
key: value # possible comment
123+
key: value
124+
125+
but all values would simply be parsed by passing to ``eval`` in the same
126+
restricted environment as for cyclers. Further validation of the inputs should
127+
try to reuse whatever validation code Matplotlib already uses to validate
128+
the same input when passed to an actual artist's property setter (e.g.,
129+
validating a linestyle should call the same helper validator function as
130+
``Line2D.set_linestyle``).
131+
132+
- The fact that a config file uses the nex syntax could be indicated by some
133+
"magic string" (e.g. ``# matplotlibrc-syntax-version: 2``), or a different
134+
naming convention.
135+
136+
- Parser handling for line-continuations would still need to be implemented. A
137+
relatively simple possibility would be to support backslash continuations
138+
(lack of support for implicit continuations based on parentheses could be
139+
somewhat surprising to a user inputting Python syntax, though).
140+
141+
- From a security point of view, this is exactly as secure as the current
142+
situation (whatever one can pass to ``eval`` with this syntax, one could
143+
already do it by passing it as value for the ``axes.prop_cycle`` key).
144+
145+
- Support for ``patheffects`` would require adding more entries into the
146+
restricted environment.
147+
148+
Full Python syntax
149+
``````````````````
150+
151+
The config files would simply be Python source files, of the form ::
152+
153+
from matplotlib import rcParams
154+
rcParams["key"] = value # possible comment
155+
rcParams["key"] = value
156+
157+
or ::
158+
159+
from matplotlib import rcParams
160+
rcParams.update(
161+
{"key": value, # possible comment
162+
"key": value}
163+
)
164+
165+
The files (with a ``.py`` extension, thus immediately distinguishable from
166+
old-style configs) would be either
167+
168+
- option 1: ``exec``'d in a completely standard context (empty globals, all
169+
builtins available). A few variables (``rcParams``, ``cycler``, etc.) could
170+
be preloaded into the globals, but I would prefer not (`#8235`_; see also
171+
`here<explicit-imports_>`_).
172+
173+
- option 2: Imported (operating by side-effect of the import), and then
174+
immediately removed from ``sys.modules`` so that reloading works; the config
175+
loader code would be in charge of locally patching ``sys.path`` to make the
176+
config files visible to the import system.
177+
178+
In either case, cascading style sheets can be implemented by having a config
179+
file ``exec`` or ``import`` (depending on the option chosen) itself another
180+
config file.
181+
182+
It would remain possible to disallow (accidental) modification of certain
183+
rcParams from style files by locally patching ``RcParams.__setitem__`` in
184+
``style.use``. However, the style files would be able to execute arbitrary
185+
code (this is a *feature* of this proposal).
186+
187+
As above, validation should share as much code as possible as the actual artist
188+
property setters.
189+
190+
No parser would need to be written at all -- it's done for us by Python!
191+
192+
Direct loading from an URL would be disabled, as it is inherently insecure.
193+
The documentation would encourage manual downloading (... or could even
194+
document how to do it using ``urllib`` if we really want to) of style sheets,
195+
which I believe is a good enough replacement (but I am happy to hear arguments
196+
that it is not).
197+
198+
Implementation
199+
--------------
200+
201+
The general implementation strategy is outlined in the proposed solutions.
202+
Neither strategy appears to present large technical difficulties. Actual work
203+
will be based on the agreed-upon syntax.
204+
205+
Backward compatibility
206+
----------------------
207+
208+
New-style configs use a different code path, so old-style config support can
209+
remain in order to maintain full backward compatibility. Deprecating support
210+
for old-style configs can be discussed and decided upon at a later time (or
211+
never done).
212+
213+
Alternatives
214+
------------
215+
216+
- Proposal: Fix the current issues with the parsers and implement custom
217+
parsers for the additional kinds of values we want to support.
218+
219+
Issues: Is it really worth maintaining a large corpus of custom parsers for
220+
a custom-designed language that is essentially used only by us?
221+
222+
- Proposal: Switch to another configuration language (JSON, YAML, etc.).
223+
224+
Issues: It remains necessary to be able to encode certain specific Python
225+
objects (certainly cyclers, possibly path effects), which means that they
226+
will need to be ``eval``'d (in which case I fail to see the advantage
227+
over using Python throughout), or that custom syntax (compatible with the
228+
underlying configuration language!) will need to be invented and custom
229+
parsers maintained. Additionally, JSON does not support comments, and YAML
230+
is an extremely (overly, in my opinion) complex language. See also the
231+
discussion that took place overPEP518_ (not that I particularly like the
232+
final choice of yet another obscure configuration language by that PEP).
233+
234+
.. _#3670:https://github.com/matplotlib/matplotlib/issues/3670
235+
.. _#4240:https://github.com/matplotlib/matplotlib/issues/4240
236+
.. _#4371:https://github.com/matplotlib/matplotlib/issues/4371
237+
.. _#6157:https://github.com/matplotlib/matplotlib/issues/6157
238+
.. _#6274:https://github.com/matplotlib/matplotlib/issues/6274
239+
.. _#6320:https://github.com/matplotlib/matplotlib/issues/6320
240+
.. _#7089:https://github.com/matplotlib/matplotlib/issues/7089
241+
.. _#7219:https://github.com/matplotlib/matplotlib/issues/7219
242+
.. _#8235:https://github.com/matplotlib/matplotlib/issues/8430
243+
.. _#8430:https://github.com/matplotlib/matplotlib/issues/8430
244+
.. _#9184:https://github.com/matplotlib/matplotlib/issues/9184
245+
.. _PEP518:https://www.python.org/dev/peps/pep-0518/#other-file-formats
246+
.. _explicit-imports:https://www.reddit.com/r/Python/comments/ex54j/seeking_clarification_on_pylonsturbogearspyramid/c1bo1v5/

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp