variable permanently mac environment-variables python

environment-variables - permanently - set environment variable ubuntu



Python-modifica temporalmente el entorno del proceso actual (5)

Estaba buscando hacer lo mismo, pero para la prueba de unidad, aquí está cómo lo he hecho usando la función unittest.mock.patch :

def test_function_with_different_env_variable(): with mock.patch.dict(''os.environ'', {''hello'': ''world''}, clear=True): self.assertEqual(os.environ.get(''hello''), ''world'') self.assertEqual(len(os.environ), 1)

Básicamente, usando unittest.mock.patch.dict con clear=True , estamos creando os.environ como un os.environ que contiene únicamente {''hello'': ''world''} .

  • La eliminación de clear=True permitirá al os.environ original y agregar / reemplazar el par clave / valor especificado dentro de {''hello'': ''world''} .

  • Al eliminar {''hello'': ''world''} solo se creará un diccionario vacío, os.envrion lo tanto, os.envrion estará vacío dentro de with .

Utilizo el siguiente código para modificar temporalmente las variables de entorno.

@contextmanager def _setenv(**mapping): """``with`` context to temporarily modify the environment variables""" backup_values = {} backup_remove = set() for key, value in mapping.items(): if key in os.environ: backup_values[key] = os.environ[key] else: backup_remove.add(key) os.environ[key] = value try: yield finally: # restore old environment for k, v in backup_values.items(): os.environ[k] = v for k in backup_remove: del os.environ[k]

Esto with contexto se utiliza principalmente en casos de prueba. Por ejemplo,

def test_myapp_respects_this_envvar(): with _setenv(MYAPP_PLUGINS_DIR=''testsandbox/plugins''): myapp.plugins.register() [...]

Mi pregunta: ¿hay una manera simple / elegante de escribir _setenv ? Pensé en hacer realmente backup = os.environ.copy() y luego os.environ = backup .. pero no estoy seguro si eso afectaría el comportamiento del programa (por ejemplo: si se hace referencia a os.environ en otra parte del intérprete de Python) .


Para pruebas unitarias prefiero usar una función de decorador con parámetros opcionales. De esta manera puedo usar los valores de entorno modificados para una función de prueba completa. El decorador a continuación también restaura los valores del entorno original en caso de que la función genere una excepción:

import os def patch_environ(new_environ=None, clear_orig=False): if not new_environ: new_environ = dict() def actual_decorator(func): from functools import wraps @wraps(func) def wrapper(*args, **kwargs): original_env = dict(os.environ) if clear_orig: os.environ.clear() os.environ.update(new_environ) try: result = func(*args, **kwargs) except: raise finally: # restore even if Exception was raised os.environ = original_env return result return wrapper return actual_decorator

Uso en pruebas unitarias:

class Something: @staticmethod def print_home(): home = os.environ.get(''HOME'', ''unknown'') print("HOME = {0}".format(home)) class SomethingTest(unittest.TestCase): @patch_environ({''HOME'': ''/tmp/test''}) def test_environ_based_something(self): Something.print_home() # prints: HOME = /tmp/test unittest.main()


Te sugiero la siguiente implementación:

import contextlib import os @contextlib.contextmanager def set_env(**environ): """ Temporarily set the process environment variables. >>> with set_env(PLUGINS_DIR=u''test/plugins''): ... "PLUGINS_DIR" in os.environ True >>> "PLUGINS_DIR" in os.environ False :type environ: dict[str, unicode] :param environ: Environment variables to set """ old_environ = dict(os.environ) os.environ.update(environ) try: yield finally: os.environ.clear() os.environ.update(old_environ)

EDIT: implementación más avanzada

El administrador de contexto a continuación se puede usar para agregar / eliminar / actualizar sus variables de entorno:

import contextlib import os @contextlib.contextmanager def modified_environ(*remove, **update): """ Temporarily updates the ``os.environ`` dictionary in-place. The ``os.environ`` dictionary is updated in-place so that the modification is sure to work in all situations. :param remove: Environment variables to remove. :param update: Dictionary of environment variables and values to add/update. """ env = os.environ update = update or {} remove = remove or [] # List of environment variables being updated or removed. stomped = (set(update.keys()) | set(remove)) & set(env.keys()) # Environment variables and values to restore on exit. update_after = {k: env[k] for k in stomped} # Environment variables and values to remove on exit. remove_after = frozenset(k for k in update if k not in env) try: env.update(update) [env.pop(k, None) for k in remove] yield finally: env.update(update_after) [env.pop(k) for k in remove_after]

Ejemplos de uso:

>>> with modified_environ(''HOME'', LD_LIBRARY_PATH=''/my/path/to/lib''): ... home = os.environ.get(''HOME'') ... path = os.environ.get("LD_LIBRARY_PATH") >>> home is None True >>> path ''/my/path/to/lib'' >>> home = os.environ.get(''HOME'') >>> path = os.environ.get("LD_LIBRARY_PATH") >>> home is None False >>> path is None True

EDIT2

Una demostración de este administrador de contexto está disponible en GitHub .


Usando el gist aquí, puede guardar / restaurar variables de entorno y local, alcance global: https://gist.github.com/earonesty/ac0617a5672ae1a41be1eaf316dd63e4

import os from varlib import vartemp, envtemp x = 3 y = 4 with vartemp({''x'':93,''y'':94}): print(x) print(y) print(x) print(y) with envtemp({''foo'':''bar''}): print(os.getenv(''foo'')) print(os.getenv(''foo''))

Esto produce:

93 94 3 4 bar None


_environ = dict(os.environ) # or os.environ.copy() try: ... finally: os.environ.clear() os.environ.update(_environ)