Idea: reduce the number of options through "configuration variables"
Some Kwant functions take options that are rarely set, and if so, they are often set for a whole session. The prime example is the show
argument to all plotting functions, but there's also dpi
, fig_size
, and perhaps also cmap
for example. Outside of plotter, there are parameters to the MUMPS solver like nrhs
that are very rarely set, because it's cumbersome to do so.
Another problem with these options is that API-functions that call other API-functions (like plotter.current
that calls plotter.streamplot
and plotter.interpolate_current
) need to re-expose options if the user is able to set them, or pass on kwargs. This leads to the kind of kwargs-hell known from matplotlib.
Now we could replace these options with global variables, and that could be done even in a backwards-compatible way (because the options would remain, and could even have precedence). Something like this:
old_value = kwant.plotter.show
kwant.plotter.show=False
# code that is executed with show set to False.
kwant.plotter.show=old_value
But this solution has several grave problems. Notably, there's no error when mistyping, and it's a mess when different configuration values are used throughout the same program. With async/multithreaded programs it becomes unmanageable.
Here is a possible solution that has been haunting me for some time: we could implement a special type of configuration variables that would emulate dynamic scope from Lisp. The syntax could be taken over verbatim from the contextvars stdlib module. In fact, contextvars could (and probably should) be used internally to make the configuration vars async-proof.
token = kwant.plotter.show.set(False)
# code that is executed with show set to False.
kwant.plotter.dpi.reset(token)
However, that's a bit on the heavy side. There could be also, additionally, a lighter context-manager-based syntax:
with kwant.plotter.show.set(False):
# code that is executed with show set to False.
(The stdlib context vars lack the context-manager syntax, but only because it was initially not deemed necessary for this low-level feature: https://mail.python.org/archives/list/python-ideas@python.org/thread/E4BB2WFMSC7D2GVOT4AFW3EBDY57HNQA.)
We could start slowly only using this for the likes of show
, but I believe that the above could be actually useful for most optional arguments to functions. The configuration variables could be even under the scope of the function that they belong to, e.g.:
with plotter.streamplot.cmap.set(something):
plotter.current(...)
Configuration options could be also made to inherit from each other when useful. For example, kwant.plotter.streamplot.cmap
could inherit from kwant.plotter.cmap
. This would allow to easily use one colormap for all streamplots, but another one for all other plots.
While this may seem a little bit technical and complicated, the usage is very simple, and this change would be fully backwards compatible.
This may deserve to be turned into a separate module on PyPI, but it's also small enough to be included into Kwant at least initially.