Skip to content
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

Is it possible for a config variable to reference another one inside of a config class? #93

Open
OmarEjjeh opened this issue Jan 22, 2025 · 3 comments

Comments

@OmarEjjeh
Copy link

OmarEjjeh commented Jan 22, 2025

I'm trying to get something like the following pseudocode to work:

class AppConfig:
    root: str = environ.var(default="/data/", converter=str)
    folder: str = AppConfig.root + "subfolder/"


cfg = environ.to_config(AppConfig)

The expected behaviour being that I can type cfg.folder and get the string "/data/subfolder/" back. Basically, I want to be able to set values on the cfg object on the basis of other values that are populated by environment variables. I use this pattern all the time in my code - it's especially useful when you want to set a root folder using an environment variable and then specify a bunch of subfolders relative to that root.

Is there any way of accomplishing this?

@hynek
Copy link
Owner

hynek commented Jan 25, 2025

since it's a regular class, you can write:

@environ.config
class AppConfig:
    root: str = environ.var(default="/data/")

    @property
    def folder(self) -> str:
        return os.path.join(self.root, "subfolder")

No need for any special magic!

@OmarEjjeh
Copy link
Author

That's brilliant, thanks! But now I'm running into the following scenario. Say I have nested classes like in the following:

@environ.config
class AppConfig:
    root: str = environ.var(default="/data/", converter=str)

    @environ.config
    class DB:  # noqa: D106
        @property
        def path(self):
            return "/data/db.sqlite" ### what to do here?

    db: DB = environ.group(DB)

I would like to set the path of my database on the basis of the global root variable, but im not sure how to go about this. The instance of AppConfig is going to end up with a reference to an instance of DB, but the instance of DB would not have a reference to the parent instance of AppConfig, so at instantiation time, the instance of DB would not have access to the AppConfig.root attribute. I guess I would want to pass the root attribute into the init function of the DB class?

Ich steh auf dem Schlauch.

@hynek
Copy link
Owner

hynek commented Feb 22, 2025

Hm, yeah I'm afraid this is not something that can be done elegantly with the current design, but I also think it's fine to say, that data combination only happens at config root level (i.e., AppConfig), since only AppConfig has access to all sub-data without doing any traversal magic?

If you would like to have a structure like this and in fact don't want to have dedicated config within, you can of course do something like this too:

@environ.config
class AppConfig:
    root: str = environ.var(default="/data/", converter=str)

    @attrs.define
    class DB:
        root: str
        @property
        def path(self):
            return Path(self.root, "db.sqlite")

    @property
    def db(self):
        return DB(self.root)

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

No branches or pull requests

2 participants