""" Sub-module ``Environment`` ========================== """ import sys import UserDict import itertools #: Template to set a variable for shells of the *Bourne-shell* family. shTemplate = "export %(var)s=%(value)s" #: Template to set a variable for shells of the *C-shell* family. cshTemplate = "setenv %(var)s %(value)s;" #: Environment variable names to change from the unix default, e.g., for OS X replace = {} if sys.platform == "darwin": replace["LD_LIBRARY_PATH"] = "DYLD_LIBRARY_PATH" #: System path variables. The system default should not be disabled. An empty #: variable means that a single ":" has to be appended when updating the #: system environment sysPaths = ["MANPATH"] #: Path variables. Extending should create a ":" separated list. paths = sysPaths + ["PATH", "LD_LIBRARY_PATH", "PKG_CONFIG_PATH", "PYTHONPATH"] class Environment(UserDict.DictMixin): """Environment class. This is used to accumulate dictionaries that define environment variables. It provides two convenience functions to convert the dictionary into sh and csh code for setting the user's environment. Instances are mapping objects. :param env: Provides the initial environment stored in :attr:`_env`. :param read-only baseEnv: Set the base environment to extend. Typical use is to set it to :data:`os.environ`. """ def __init__(self, env={}, baseEnv={}): self._env = env.copy() self._baseEnv = baseEnv self._deleted = set() def __contains__(self, key): return (key in self._env or (key not in self._deleted and key in self._baseEnv)) def __getitem__(self, key): try: return self._env[key] except KeyError: if key not in self._deleted: return self._baseEnv[key] else: raise def __setitem__(self, key, value): self._env[key] = value def __delitem__(self, key): if key not in self: raise KeyError try: del self._env[key] except KeyError: pass if key in self._baseEnv: self._deleted.add(key) def __iter__(self): return itertools.chain(self._env, itertools.dropwhile(lambda x: (x in self._deleted or x in self._env), self._baseEnv)) def iteritems(self): return itertools.chain(self._env.iteritems(), itertools.dropwhile(lambda x: (x[0] in self._deleted or x[0] in self._env), self._baseEnv.iteritems())) def keys(self): return self._env.keys() + \ [k for k in self._baseEnv if (k not in self._deleted and k not in self._env)] def update(self, env={}, **kwargs): """Add the variables from one environment into 'self'. Path-like values are concatenated to form a ``:`` separated list. System paths, listed in :data:`sysPaths`, are terminated by ``:`` if previously empty. Other variables are copied, existing values get replaced. The additions to the environment can also be specified as keyword arguments. """ for d in (env, kwargs): for name, value in d.iteritems(): if name in paths: try: self[name] = value + ":" + self[name] except KeyError: if name in sysPaths: self._env[name] = value + ":" else: self._env[name] = value else: self._env[name] = value def toString(self, template): """Convert environment to a string of [c]sh commands. Handles substitutions of variables, e.g., LD_LIBRARY_PATH to DYLD_LIBRARY_PATH on OS X. The substitution is customized through templates. :param template: A template for setting variables. """ result = [] for name, value in self._env.iteritems(): try: name = replace[name] except KeyError: pass subst = {"var": name, "value": value} result.append(template % subst) return "\n".join(result) def csh(self): """Create the code to set the environment for a shell of the *C-shell* family. """ return self.toString(cshTemplate) def sh(self): """Create the code to set the environment for a shell of the *Bourne-shell* family. """ return self.toString(shTemplate)