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 dewith
.
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)