-
Notifications
You must be signed in to change notification settings - Fork 22
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
Session configuration #241
Comments
I'm more in favor of option 2, global variables are discouraged for a reason. While I know that you are in favor of just setting things once and not having to pass them around, I've been bitten too many times by having unexpected things happen and even in an option 2 scenario where I don't expect things to change, I will likely always pass around a config. Right now we're passing a chain of half a dozen arguments (that change from time to time) from initialization to source creation. Passing one variable that likely won't need to change seems like a pretty good compromise. |
I expected you would think that way. So let me ask, what were these cases where you got bitten? The problem I see is that we either have to pass configs around everywhere, or we have two classes of config parameters: those that a user can set and then the other ones. Not appealing to me. |
There have been a lot of instances over time. I can't think of anything recently because it's such an uncommon practice these days. Matplotlib does what I suggest, namely having a global set of "rc" parameters that can be updated by any given function on the fly. So I think that global constants are a good idea and should be used, but my implementation would be something like the following: config.py:
Scarlet code would look like the following (note: I don't think that we should parameterize init_source and init_all_sources this way with max_components, I'm just showing how it could be done if we did want to add some custom config options to nested functions as well as classes):
Then in code (like the quickstart guide) we would use
This leaves minimal boilerplate in classes and functions with config options, just a single line |
I'm following along because I have essentially the same problem and would appreciate someone else coming up with a solution before I have to. I would strongly suggest at least considering making the Config class a dataclass, as it's much easier to debug, document and introspect than a dynamic dict. You can always give it a dict attribute for dynamic configuration if you really need to, and also easily make it hierarchical and freeze parameters you don't want users to change. I think this would be preferable to the single global config dict. Consider how much nicer matplotlib's rcParams documentation would be to read and maintain if it was a single class with a type and docstring next to each parameter (though admittedly I'm not sure how you'd get the docstring to work like in pex.Config). |
@pmelchior feels strongly about having a global config, which is why I used the global dict. If not, I would make a config class that is the same as the one above without the
|
My comment wasn't so much about how you use the config classes and where you put them but how you define them. A Config dataclass could look like:
... etc, and where you can make ImmutableConfig Alternatively, you could use pex_config since it's a standalone pip-installable package designed for exactly this purpose (and probably what I'll use in non-Rubin projects now that I've thought about it). |
Having a ton of arguments for the init method of various function makes the code really ugly and requires a fair bit of work when we want to expose an aspect of some piece of code to the user. On the other hand, a global config module becomes problematic when multiple instances of, say, sources and blend should run with different settings.
I propose we use a mechanism similar to
Cache
, which is globally defined by empty, and dynamically filled by every instance. This way we could create a dictionary likeconfig['ExtendedSource.resizing'] = True
which can be set up with defaults programmatically or even hard-coded with defaults. In the
ExtendedSource
constructor, we can then do one of these:1. Session configs only
That's the version of ultimate simplicity because every config setting we make is available everywhere simply by importing
Config
. No need to pass anything around. I think this would serve most of our use cases, make the code API much lighter, and prevent drilling holes into the code to expose yet another config parameter to the user.A downside is for cases in which, say, sources are with different configs are run in the same blend. But I don't think the construction would be to bad:
2. Session configs with override
Has a cleaner API than we currently have and can be overridden by the user, e.g. for construction (in the same blend) sources with different config parameters:
But it still requires drilling holes to pass the
config
argument to wherever it is needed. The alternative is that some config parameters are settable by the user at init time and some others aren't. As compromises go, I'm not a fan of this option.Recommendation
We opt for option 1 with a twist:
This way we avoid the drilling holes thing and can persist any config setting in all classes that need that. I'm guessing only source classes will need that anyway.
The text was updated successfully, but these errors were encountered: