Environment variables

Click’s environment-variable handling spreads across several internal methods on Parameter, Option, and Context. This module centralizes that logic into a small set of pure helpers that downstream code can call to introspect what Click would read for a given parameter, plus a couple of subprocess-friendly conveniences.

The helpers underpin click-extra’s show_envvar defaults on every option’s help screen, the --params table, and the auto-envvar reconciliation in TelemetryOption, ColorOption, and others, but they’re equally useful for any downstream code that needs to surface the env-var contract of its CLI.

See also

Environment variables are a legacy mess: Let’s dive deep into them is the best survey of the wider problem space these helpers paper over.

merge_envvar_ids(*envvar_ids)

Merge and deduplicate environment-variable names from any combination of strings and arbitrarily-nested iterables. None values are filtered out. Order is preserved (first occurrence wins), and on Windows every name is upper-cased to match the platform’s case-insensitive os.environ semantics: the same normalization the standard library applies internally.

('MYAPP_DEBUG',)
('MYAPP_DEBUG', 'MYAPP_VERBOSE')
('A', 'B', 'C')

The result is a tuple[str, ...] ready to feed Click’s envvar= parameter on options and arguments. Click Extra uses it internally to combine the envvar an option declares with the one Click derives from the CLI name: see param_envvar_ids below.

clean_envvar_id(name)

Normalize an arbitrary string into a canonical environment-variable name: split on non-alphanumeric runs, drop empties, join with underscores, uppercase the result.

MY_CLI
MY_CLI_DEBUG_MODE
V2_0_BETA

Attention

This helper does not exactly replicate Click’s own auto-envvar derivation: Click’s case-handling of environment variables is inconsistent across versions. Use clean_envvar_id when you control the naming, and param_auto_envvar_id (below) when you need to know exactly what Click itself would produce for a given parameter.

param_auto_envvar_id(param, ctx)

Compute the auto-generated environment variable Click would read for an option or argument, given a parameter instance and either an active click.Context or a plain settings dict (like context_settings). Returns None when the parameter has allow_from_autoenv=False, or when no auto_envvar_prefix is configured. The output exactly mirrors what click.core.Parameter.resolve_envvar_value() and click.core.Option.resolve_envvar_value() produce internally:

MYAPP_DEBUG
None

param_envvar_ids(param, ctx): the main entry point

Returns the deduplicated, ordered tuple of environment variables Click would consider for an option or argument: the user-declared envvar= value (single string or iterable) followed by the auto-generated one. Click reads them in this order and stops at the first one set, which means user-declared envvars take precedence over the auto-generated one: param_envvar_ids preserves that ordering.

        flowchart LR
    decl["param.envvar<br/>user-declared:<br/>string or nested iterable"] --> merge
    auto["param_auto_envvar_id()<br/>PREFIX_NAME,<br/>if auto-envvar enabled"] --> merge
    merge["merge_envvar_ids()<br/>flatten, drop empty,<br/>dedupe, upper-case on Windows"] --> tup["ordered tuple<br/>user-declared first,<br/>auto-generated last"]
    tup --> reader["Click reads in order,<br/>stops at first set<br/>so user-declared wins"]
    
--debug:   ('DEBUG', 'MYAPP_DEBUG')
--verbose: ('MYAPP_VERBOSE',)

This is what powers click-extra’s --params table: each row’s Env. vars. column comes from param_envvar_ids(param, ctx), joined with , and styled with the active theme’s envvar slot.

env_copy(extend=None)

Returns a shallow copy of os.environ with optional extra keys layered on top, or None when extend is empty. Mirrors Python’s own subprocess-handling pattern: subprocess.Popen(env=None) inherits the current environment, so returning None for the no-extension case is a useful contract:

None
None
False
1
False

Pair it with subprocess.run(..., env=env_copy({"MYAPP_TOKEN": secret})) when you need to add a few variables for a child process without leaking them into the parent’s os.environ.

click_extra.envvar API

Implements environment variable utilities.

click_extra.envvar.parse_envvar_flag(value)[source]

Read an environment flag’s value as a boolean, permissively.

The single interpretation shared by the flag-like variables Click Extra reads by hand as booleans (ACCESSIBLE, DO_NOT_TRACK): the value is read as one of the boolean spellings BOOLEAN_STATES lists, in any case and with surrounding whitespace ignored, and anything else counts as activation, the empty string included: the variable’s bare presence is the signal. The color variables are not read this way: each follows its own convention, see resolve_color_env().

Callers handle presence themselves: pass the value only when the variable is set, an unset variable being no vote at all.

Return type:

bool

click_extra.envvar.machine_envvars_apply(ctx, param)[source]

Whether the machine-wide environment variables may set the value of param.

A machine-wide variable speaks for every CLI on the machine, like ACCESSIBLE, CLICK_EXTRA_THEME or NO_COLOR. It fills in only where nothing more specific set the value: the command line, the variable of the option itself and a configuration file each outrank it. So it applies only while param holds its built-in default.

Call it from the callback of param, once Click recorded where the value came from.

Return type:

bool

click_extra.envvar.normalize_envvar_id(envvar_id)[source]

Spell an environment variable name the way the running platform reads it.

Windows looks variables up case-insensitively, and the standard library upper-cases every name it stores: see merge_envvar_ids(). Every other platform keeps the name as given.

Return type:

str

click_extra.envvar.merge_envvar_ids(*envvar_ids)[source]

Merge and deduplicate environment variables.

Multiple parameters are accepted and can be single strings or arbitrary-nested iterables of strings. None values are ignored.

Variable names are deduplicated while preserving their initial order.

Returns a tuple of strings. The result is ready to be used as the envvar parameter for Click’s options or arguments.

Return type:

tuple[str, ...]

click_extra.envvar.clean_envvar_id(envvar_id)[source]

Utility to produce a user-friendly environment variable name from a string.

Separates all contiguous alphanumeric string segments, eliminate empty strings, join them with an underscore and uppercase the result.

Return type:

str

click_extra.envvar.param_auto_envvar_id(param, ctx)[source]

Compute the auto-generated environment variable of an option or argument.

Returns the auto envvar exactly as computed within Click’s internals, by click.core.Parameter.resolve_envvar_value() and click.core.Option.resolve_envvar_value().

Return type:

str | None

click_extra.envvar.param_envvar_ids(param, ctx)[source]

Returns the deduplicated, ordered list of environment variables for an option or argument, including the auto-generated one.

The auto-generated environment variable is added at the end of the list, so that user-defined envvars takes precedence. This respects the current implementation of click.core.Option.resolve_envvar_value().

Names are normalized to uppercase on Windows by merge_envvar_ids().

Return type:

tuple[str, ...]

click_extra.envvar.temporary_env(set_vars=None, unset_vars=())[source]

Apply environment variable changes for the block’s duration, then restore.

set_vars are written into os.environ and unset_vars removed. On exit, every touched variable is restored to its pre-block state: recreated with its former value, or removed when it did not exist before.

The process environment is patched directly (not through test-framework fixtures) so the helper serves production code paths and test harnesses alike, with a single restore discipline.

Return type:

Generator[None, None, None]

click_extra.envvar.env_copy(extend=None)[source]

Returns a copy of the current environment variables, updated with extend.

Mimics Python’s original implementation by returning None when extend is empty or missing, so a child process inherits the environment unchanged.

A None value removes its variable from the copy instead of setting it, which is the only way to hide an inherited variable from a child process: assigning the empty string leaves it set, and a flag read by bare presence (see parse_envvar_flag()) counts that as activation. Same convention as click.testing.CliRunner.invoke()’s own env argument, and the reason TEnvVars values are typed optional.

Return type:

dict[str, str] | None