# Copyright Kevin Deldycke <kevin@deldycke.com> and contributors.## This program is Free Software; you can redistribute it and/or# modify it under the terms of the GNU General Public License# as published by the Free Software Foundation; either version 2# of the License, or (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program; if not, write to the Free Software# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA."""Implements environment variable utilities."""from__future__importannotationsimportosimportrefromtypingimportAny,Iterable,Mappingimportclickimportclick.testingfromboltons.iterutilsimportflatten_iterTEnvVarID=str|NoneTEnvVarIDs=Iterable[TEnvVarID]TNestedEnvVarIDs=Iterable[TEnvVarID|Iterable["TNestedEnvVarIDs"]]"""Types environment variable names."""TEnvVars=Mapping[str,str|None]"""Type for ``dict``-like environment variables."""
[docs]defmerge_envvar_ids(*envvar_ids:TEnvVarID|TNestedEnvVarIDs)->tuple[str,...]:"""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. .. caution:: `On Windows, environment variable names are case-insensitive <https://docs.python.org/3/library/os.html#os.environ>`_, so we `normalize them to uppercase as the standard library does <https://github.com/python/cpython/blob/ffef9b0/Lib/os.py#L777-L786>`_. Returns a tuple of strings. The result is ready to be used as the ``envvar`` parameter for Click's options or arguments. """ids=[]forenvvarinflatten_iter(envvar_ids):ifenvvar:ifos.name=="nt":envvar=envvar.upper()# Deduplicate names.ifenvvarnotinids:ids.append(envvar)returntuple(ids)
[docs]defclean_envvar_id(envvar_id:str)->str:"""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. .. attention:: We do not rely too much on this utility to try to reproduce the `current behavior of Click, which is is not consistent regarding case-handling of environment variable <https://github.com/pallets/click/issues/2483>`_. """return"_".join(pforpinre.split(r"[^a-zA-Z0-9]+",envvar_id)ifp).upper()
[docs]defparam_auto_envvar_id(param:click.Parameter,ctx:click.Context|dict[str,Any],)->str|None:"""Compute the auto-generated environment variable of an option or argument. Returns the auto envvar as it is exactly computed within Click's internals, i.e. ``click.core.Parameter.resolve_envvar_value()`` and ``click.core.Option.resolve_envvar_value()``. """# Skip parameters that have their auto-envvar explicitly disabled.ifnotgetattr(param,"allow_from_autoenv",None):returnNoneifisinstance(ctx,click.Context):prefix=ctx.auto_envvar_prefixelse:prefix=ctx.get("auto_envvar_prefix")ifnotprefixornotparam.name:returnNone# Mimics Click's internals.returnf"{prefix}_{param.name.upper()}"
[docs]defparam_envvar_ids(param:click.Parameter,ctx:click.Context|dict[str,Any],)->tuple[str,...]:"""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()``. .. caution:: `On Windows, environment variable names are case-insensitive <https://docs.python.org/3/library/os.html#os.environ>`_, so we `normalize them to uppercase as the standard library does <https://github.com/python/cpython/blob/ffef9b0/Lib/os.py#L777-L786>`_. """returnmerge_envvar_ids(param.envvar,param_auto_envvar_id(param,ctx))
[docs]defenv_copy(extend:TEnvVars|None=None)->TEnvVars|None:"""Returns a copy of the current environment variables and eventually ``extend`` it. Mimics `Python's original implementation <https://github.com/python/cpython/blob/7b5b429/Lib/subprocess.py#L1648-L1649>`_ by returning ``None`` if no ``extend`` content are provided. Environment variables are expected to be a ``dict`` of ``str:str``. """ifisinstance(extend,dict):fork,vinextend.items():assertisinstance(k,str)assertisinstance(v,str)else:assertnotextendenv_copy:TEnvVars|None=Noneifextend:# By casting to dict we make a copy and prevent the modification of the# global environment.env_copy=dict(os.environ)env_copy.update(extend)returnenv_copy