Skip to content

MNT: Move "backend" from a regular rcParams dict entry to a class attribute#31792

Open
timhoffm wants to merge 1 commit into
matplotlib:mainfrom
timhoffm:mnt-rcParams-backend-class-attribute
Open

MNT: Move "backend" from a regular rcParams dict entry to a class attribute#31792
timhoffm wants to merge 1 commit into
matplotlib:mainfrom
timhoffm:mnt-rcParams-backend-class-attribute

Conversation

@timhoffm
Copy link
Copy Markdown
Member

@timhoffm timhoffm commented May 31, 2026

PR summary

Working towards #31791.

rcParams should be only configuration, not state; i.e. wrt. backend, it
can hold the desired backend and backend priorities, but it should not
hold the currently active backend or trigger backend selection as a
side-effect. The latter causes a lot of complexity in rcParams.

This PR is the first step in the migration strategy outlined there:

Make the backend a RcParams class attribute and do not hold
"backend" as a regular dict entry. There can only be one backend,
so putting that value in a class attribute RcParams._backend makes
sense. This already reduces the complexity as we don't need special
handling to sync/copy the value when rcParams are bulk-replaced
(loading from file or rc_context). Instead add special logic to keep
behavioral backward compatibility with the dict API
(rcParams["backend"] / rcParams._get("backend") /
"rcParams._set("backend", val)).

Note on API compatibility: This PR limits itself to the known typical dict-API usages in the context of backend handling. I've refrained from trying to fully replicate dict behavior of a "virtual" "backend" parameter, i.e. len(rcParams) / rcParams.keys() / rcParams.values() / rcParams.items() do not contain "backend" anymore. I would be willing to accept this level of API breakage. If deemed critical, we could add compatibility shims for that too, but it's a bit more complicated as the style variants of RcParams must not claim to have "backend" as a key.

AI Disclosure

AI was used to analyze the code base and draft an implementation proposal. I've thoroughly reviewed and modified the result to the present form.

PR checklist

@timhoffm timhoffm added this to the v3.12.0 milestone May 31, 2026
@timhoffm timhoffm force-pushed the mnt-rcParams-backend-class-attribute branch 2 times, most recently from 1639484 to 85159ce Compare May 31, 2026 10:19
…ribute

Working towards matplotlib#31791.

> rcParams should be only configuration, not state; i.e. wrt. backend, it
> can hold the desired backend and backend priorities, but it should not
> hold the currently active backend or trigger backend selection as a
> side-effect. The latter causes a lot of complexity in rcParams.

This PR is the first step in the migration strategy outlined there:

> Make the backend a RcParams class attribute and do not hold
> "backend" as a regular dict entry. There can only be one backend,
> so putting that value in a class attribute `RcParams._backend` makes
> sense. This already reduces the complexity as we don't need special
> handling to sync/copy the value when rcParams are bulk-replaced
> (loading from file or rc_context). Instead add special logic to keep
> behavioral backward compatibility with the dict API
> (`rcParams["backend"]` / `rcParams._get("backend")` /
> `"rcParams._set("backend", val)`).

Note on API compatibility: This PR limits itself to the known typical
dict-API usages in the context of backend handling. I've refrained from
trying to fully replicate dict behavior of a "virtual" "backend" parameter,
i.e. `len(rcParams)` / `rcParams.keys()` / `rcParams.values()` /
`rcParams.items()` do not contain "backend" anymore. I would be willing to
accept this level of API breakage. If deemed critical, we could add
compatibility shims for that too.
@timhoffm timhoffm force-pushed the mnt-rcParams-backend-class-attribute branch from 85159ce to 8b8563d Compare May 31, 2026 11:56
Comment on lines -758 to -768
def _ensure_has_backend(self):
"""
Ensure that a "backend" entry exists.

Normally, the default matplotlibrc file contains *no* entry for "backend" (the
corresponding line starts with ##, not #; we fill in _auto_backend_sentinel
in that case. However, packagers can set a different default backend
(resulting in a normal `#backend: foo` line) in which case we should *not*
fill in _auto_backend_sentinel.
"""
dict.setdefault(self, "backend", rcsetup._auto_backend_sentinel)
Copy link
Copy Markdown
Member Author

@timhoffm timhoffm May 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: _ensure_has_backend() is not needed anymore, because the backend is stored in the class attribute RcParams._backend and thus always available.

Comment on lines -1204 to -1205
orig = dict(rcParams.copy())
del orig['backend']
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: The dict conversion was only needed to be able to drop the backend entry. Since that doesn't exist anymore, we don't need the dict conversion.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant