hatch icon indicating copy to clipboard operation
hatch copied to clipboard

Add feature to dynamically set environment variables in `envs.ENV.env-vars`

Open ketozhang opened this issue 1 year ago • 4 comments

Discussed in https://github.com/pypa/hatch/discussions/1554

Originally posted by ketozhang June 6, 2024 Is there any way to dynamically set environment variables?

In my use case, I want to set a secret variable dynamically using a command that takes in another env var for the secret key/name.

[tool.hatch.envs.default.env-vars]
SECRET_KEY="some-key-name"
SECRET="$(get-secret $SECRET_KEY)"  # get-secret is a placeholder command

The only way I can think of is to set it in scripts.

[tool.hatch.envs.default.scripts]
test="SECRET=$(get-secret $SECRET_KEY) printenv"

...which does not scale, unless you can use secret="export SECRET=..." then test=["secret", "printenv"], but I don't think hatch preserves export.

ketozhang avatar Jun 06 '24 19:06 ketozhang

Out of curiosity, does that workaround I mentioned in that discussion work for you (temporarily)?

ofek avatar Jun 06 '24 21:06 ofek

Yes it does–thank you!

ketozhang avatar Jun 07 '24 02:06 ketozhang

Just to note for other readers until a better solution is put in place, you can currently do this by creating an Environment Collector plugin which can arbitrarily edit the env vars of all environments.

johnpyp avatar Jun 09 '24 21:06 johnpyp

based on @johnpyp's suggestion I created a plugin to automatically collect variables from a .envfile and set it to all hatch environments:

from pathlib import Path
import re

from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface


class EnvVarSetter(EnvironmentCollectorInterface):
    def finalize_environments(self, config):
        env_file = Path(".env")
        if not env_file.exists():
            return config

        # collect new env vars in .env
        new_vars = dict()
        pattern = re.compile(r"""^([^\s=]+)=(?:[\s"']*)(.+?)(?:[\s"']*)$""")
        with env_file.open(encoding="utf-8") as infile:
            for line in infile:
                match = pattern.match(line)
                if match is not None:
                    new_vars[match.group(1)] = match.group(2)

        # add new env vars
        for env_name, env_entry in config.items():
            if not env_name.startswith("hatch"):
                if "env-vars" not in env_entry:
                    env_entry["env-vars"] = new_vars
                else:
                    env_entry["env-vars"].update(new_vars)

        return config

and then simply add this to your pyproject.toml:

[tool.hatch.env.collectors.custom]
path = "path/to/envvarsetter.py"

I guess the plugin can be easily modified to set other variables

sebag90 avatar Jun 18 '24 14:06 sebag90