Einlesen von Umgebungsvariablen aus einer Umgebungsdatei
Lesezeit: 10 Minuten
Kurt Peek
Ich möchte in einer lokalen Umgebung ein Python-Skript ausführen, das normalerweise in einem Docker-Container ausgeführt wird. Die docker-compose.yml spezifiziert ein env_file was (teilweise) wie folgt aussieht:
DB_ADDR=rethinkdb
DB_PORT=28015
DB_NAME=ipercron
Um dies lokal auszuführen, möchte ich, dass diese Zeilen konvertiert werden
Ich könnte meinen Parser schreiben, aber ich habe mich gefragt, ob es vorhandene Module/Tools zum Einlesen von Umgebungsvariablen aus Konfigurationsdateien gibt?
ParisNakitaKejser
ich benutze Python Dotenv-Bibliothek. Installieren Sie einfach die Bibliothek pip install python-dotenvein … kreieren .env Datei mit Ihren Umgebungsvariablen und importieren Sie die Umgebungsvariablen wie folgt in Ihren Code:
import os
from dotenv import load_dotenv
load_dotenv()
MY_ENV_VAR = os.getenv('MY_ENV_VAR')
Von dem .env Datei:
MY_ENV_VAR="This is my env var content."
Auf diese Weise mache ich es, wenn ich Code außerhalb meines Docker-Systems testen und ihn darauf vorbereiten muss, ihn wieder in Docker zurückzugeben.
benutze ich auch dotenv. Wenn Sie aus einer JS-Backend-Umgebung kommen, gibt es so schöne Ähnlichkeiten, dass die Lernkurve fast flach ist!
– sk
10. April 2020 um 11:54 Uhr
wenn ich habe MY_ENV_VAR="" in dem .bashrc Datei, für die dies nicht gilt, und gibt eine leere Zeichenfolge zurück; ist das ein normales verhalten?
– Alper
18. November 2020 um 21:59 Uhr
@alper ja ist es. Es überschreibt nur bereits gesetzte Umgebungsvariablen .bashrc wenn du benutzt load_dotenv(override=True)wie in ihrer beschrieben GitHub-Readme-Datei.
– Daniel Lavedonio de Lima
14. März 2021 um 2:46 Uhr
Im Allgemeinen sind in .env-Dateien keine Anführungszeichen für die Variablen erforderlich.
– Alex
18. Mai 2021 um 2:27 Uhr
Ich möchte das gemäß den Dokumenten hinzufügen Lines can start with the export directive, which has no effect on their interpretation. Sehr schön. Bedeutet, dass Sie tun können export MY_VAR="Env var" und kompatibel sein source .env von bash. Vielleicht ist es nützlich, diese Informationen zur Antwort hinzuzufügen. Ich würde eine Bearbeitung vorschlagen, aber die Warteschlange ist voll
– CervEd
21. November 2021 um 12:43 Uhr
Gino Mempin
Wenn Ihr System/Ihre Umgebung/Ihr Arbeitsablauf die Verwendung von Shell-Skripten unterstützt, können Sie ein Skript erstellen, das diese beiden Vorgänge umschließt:
Beschaffung der .env-Datei und Export als Umgebungsvariablen
Verwendung der set -a Option wo “Jede Variable oder Funktion, die erstellt oder geändert wird, erhält das Exportattribut und wird für den Export in die Umgebung nachfolgender Befehle markiert“.
Aufrufen Ihres Python-Skripts / Ihrer Python-App, die plain os.environ.get Code
Beispiel für eine .env-Datei (config.env):
TYPE=prod
PORT=5000
Beispiel-Python-Code (test.py):
import os
print(os.environ.get('TYPE'))
print(os.environ.get('PORT'))
Beispiel-Bash-Skript (run.sh):
#!/usr/bin/env bash
set -a
source config.env
set +a
python3 test.py
Wenn Sie das Python-Skript direkt ausführen (python3 test.py) ohne source-ing die .env-Datei, alle environ.get Anrufe zurück None.
Wenn Sie es jedoch in ein Shell-Skript einschließen, das zuerst die .env-Datei in Umgebungsvariablen lädt und anschließend das Python-Skript ausführt, sollte das Python-Skript jetzt in der Lage sein, die Umgebungsvariablen korrekt zu lesen. Es stellt auch sicher, dass die exportierten env-Variablen nur als Teil der Ausführung Ihrer Python-Anwendung/Ihres Python-Skripts existieren.
Im Vergleich zu der anderen beliebten Antwort benötigt dies keine externen Python-Bibliotheken.
Dies ist eine echte Linux-Lösung für dieses Problem, denke ich.
– Ehsan88
31. März 2021 um 12:17 Uhr
Das war genau das, was ich brauchte. Die set -a trick ist wirklich elegant und wird sich in einer Reihe anderer Szenarien als nützlich erweisen. Vielen Dank!
– András Aszodi
26. Mai 2021 um 14:53 Uhr
Beachten Sie, dass export MY_VAR="Hello!" ist kompatibel mit dotenv ebenso gut wie bash source. nett
– CervEd
21. November 2021 um 12:45 Uhr
…Sonderzeichen wie ! in der exportierten env ist der var-Wert kompatibel mit source solange es richtig zitiert wird. Siehe stackoverflow.com/q/55703950/2745495
– Gino Mempin
21. Februar 2022 um 10:44 Uhr
radtek
Das könnte auch für dich funktionieren:
env_vars = [] # or dict {}
with open(env_file) as f:
for line in f:
if line.startswith('#') or not line.strip():
continue
# if 'export' not in line:
# continue
# Remove leading `export `, if you have those
# then, split name / value pair
# key, value = line.replace('export ', '', 1).strip().split('=', 1)
key, value = line.strip().split('=', 1)
# os.environ[key] = value # Load to local environ
# env_vars[key] = value # Save to a dict, initialized env_vars = {}
env_vars.append({'name': key, 'value': value}) # Save to a list
print(env_vars)
In den Kommentaren finden Sie einige verschiedene Möglichkeiten, die env-Variablen zu speichern, und auch einige Parsing-Optionen, dh um die führenden zu entfernen export Stichwort. Eine andere Möglichkeit wäre die Verwendung von python-dotenv Bücherei. Beifall.
UPDATE: Ich habe meine eigene envvar_utils.py eingerichtet, um die Konvertierung von Zeichenfolgen usw.
"""Utility functions for dealing with env variables and reading variables from env file"""
import os
import logging
import json
BOOLEAN_TYPE = 'boolean'
INT_TYPE = 'int'
FLOAT_TYPE = 'float'
STRING_TYPE = 'str'
LIST_TYPE = 'list'
DICT_TYPE = 'dict'
def get_envvars(env_file=".env", set_environ=True, ignore_not_found_error=False, exclude_override=()):
"""
Set env vars from a file
:param env_file:
:param set_environ:
:param ignore_not_found_error: ignore not found error
:param exclude_override: if parameter found in this list, don't overwrite environment
:return: list of tuples, env vars
"""
env_vars = []
try:
with open(env_file) as f:
for line in f:
line = line.replace('\n', '')
if not line or line.startswith('#'):
continue
# Remove leading `export `
if line.lower().startswith('export '):
key, value = line.replace('export ', '', 1).strip().split('=', 1)
else:
try:
key, value = line.strip().split('=', 1)
except ValueError:
logging.error(f"envar_utils.get_envvars error parsing line: '{line}'")
raise
if set_environ and key not in exclude_override:
os.environ[key] = value
if key in exclude_override:
env_vars.append({'name': key, 'value': os.getenv(key)})
else:
env_vars.append({'name': key, 'value': value})
except FileNotFoundError:
if not ignore_not_found_error:
raise
return env_vars
def create_envvar_file(env_file_path, envvars):
"""
Writes envvar file using env var dict
:param env_file_path: str, path to file to write to
:param envvars: dict, env vars
:return:
"""
with open(env_file_path, "w+") as f:
for key, value in envvars.items():
f.write("{}={}\n".format(key, value))
return True
def convert_env_var_flag_to(env_var_name, required_type, default_value):
"""
Convert env variable string flag values to required_type
:param env_var_name: str, environment variable name
:param required_type: str, required type to cast the env var to
:param default_value: boolean, default value to use if the environment variable is not available
:return: environment variable value in required type
"""
env_var_orginal_value = os.getenv(env_var_name, default_value)
env_var_value = ""
try:
if required_type == INT_TYPE:
env_var_value = int(env_var_orginal_value)
elif required_type == FLOAT_TYPE:
env_var_value = float(env_var_orginal_value)
elif required_type == BOOLEAN_TYPE:
env_var_value = bool(int(env_var_orginal_value))
elif required_type == STRING_TYPE:
env_var_value = str(env_var_orginal_value)
elif required_type == LIST_TYPE:
env_var_value = env_var_orginal_value.split(',') if len(env_var_orginal_value) > 0 else default_value
elif required_type == DICT_TYPE:
try:
env_var_value = json.loads(env_var_orginal_value) if env_var_orginal_value else default_value
except Exception as e:
logging.error(f"convert_env_var_flag_to: failed loading {env_var_orginal_value} error {e}")
env_var_value = default_value
else:
logging.error("Unrecognized type {} for env var {}".format(required_type, env_var_name))
except ValueError:
env_var_value = default_value
logging.warning("{} is {}".format(env_var_name, env_var_orginal_value))
return env_var_value
Woud speichern sie nicht in a dict sein besserer Ansatz als in eine Liste? // +1, um den Zeilenvorsprung loszuwerden export Stichwort
– Alper
18. November 2020 um 22:21 Uhr
Das ist wirklich eine ziemlich schmutzige Methode und erfordert viel Reinigung, um tatsächlich zu funktionieren … Zeichenfolgen aus dem dotenv werden “wie sie sind” gelesen, dh sie behalten ihr ” “. Auch wenn das dotenv Leerzeichen um das = hat, sind diese Teil des Schlüssels
– KönigOtto
28. Dezember 2021 um 13:02 Uhr
Bei mir funktioniert es jetzt seit Jahren gut. env-Variablen sind Zeichenfolgen, also müssten Sie sie wie bei jeder env-Variablen nach Bedarf konvertieren.
– radtek
4. Januar 2022 um 20:54 Uhr
Moinuddin Quadri
Sie können verwenden ConfigParser. Musterbeispiel finden Sie hier.
Aber diese Bibliothek erwartet Ihre key=value Daten unter einigen vorhanden sein [heading]. Zum Beispiel wie:
[mysqld]
user = mysql # Key with values
pid-file = /var/run/mysqld/mysqld.pid
skip-external-locking
old_passwords = 1
skip-bdb # Key without value
skip-innodb
Martin Nowosad
Dewald Abrie hat eine gute Lösung gepostet.
Hier ist eine kleine Modifikation, die Bruchkanten ignoriert (\n)
def get_env_data_as_dict(path: str) -> dict:
with open(path, 'r') as f:
return dict(tuple(line.replace('\n', '').split('=')) for line
in f.readlines() if not line.startswith('#'))
print(get_env_data_as_dict('../db.env'))
Ich denke, das ist eine großartige Antwort, sauber, praktisch und ohne externe Abhängigkeiten. Ich habe die komplexen Anforderungen nicht überprüft, aber es ist sehr praktisch, wenn man ein lokales Repo hat und den gesamten Code, aber nicht den variablen Inhalt (z. B. ein Token) bereitstellen muss. Befolgen Sie einfach diese allgemeinen Schritte: 1) erstellte eine .env-Datei, 2) lege sie in deinen virtuellen Umgebungsordner, 3) füge den virtualenv-Ordner in .gitignore ein, 4) lese die Variable mit der bereitgestellten Funktion in einem beliebigen Skript und wird nicht im Repo öffentlich sein, sondern nur in deinem lokalen Maschine.
– IF.Francisco.ME
29. Mai 2021 um 0:24 Uhr
Das funktioniert bei mir nicht, ich bekomme diesen Fehler: ValueError: dictionary update sequence element #2 has length 1; 2 is required
– Chud37
19. September 2022 um 20:33 Uhr
Schöner Code, aber es funktioniert nicht mit Kommentaren am Ende einer Zeile (nach Daten), oder? (Dies gilt wahrscheinlich auch für andere Antworten.)
– jakob.j
19. Dezember 2022 um 21:15 Uhr
@jakob.j nein, aber Sie sollten die Kommentare trotzdem über dem Code hinzufügen. Wenn Sie möchten, dass Kommentare verschwinden, können Sie dies mit Regex handhaben
– Martin Nowosad
21. Dezember 2022 um 21:01 Uhr
Arash Hatami
Wie wäre es damit für eine kompaktere Lösung:
import os
with open('.docker-compose-env', 'r') as fh:
vars_dict = dict(
tuple(line.replace('\n', '').split('='))
for line in fh.readlines() if not line.startswith('#')
)
print(vars_dict)
os.environ.update(vars_dict)
Ich denke, das ist eine großartige Antwort, sauber, praktisch und ohne externe Abhängigkeiten. Ich habe die komplexen Anforderungen nicht überprüft, aber es ist sehr praktisch, wenn man ein lokales Repo hat und den gesamten Code, aber nicht den variablen Inhalt (z. B. ein Token) bereitstellen muss. Befolgen Sie einfach diese allgemeinen Schritte: 1) erstellte eine .env-Datei, 2) lege sie in deinen virtuellen Umgebungsordner, 3) füge den virtualenv-Ordner in .gitignore ein, 4) lese die Variable mit der bereitgestellten Funktion in einem beliebigen Skript und wird nicht im Repo öffentlich sein, sondern nur in deinem lokalen Maschine.
– IF.Francisco.ME
29. Mai 2021 um 0:24 Uhr
Das funktioniert bei mir nicht, ich bekomme diesen Fehler: ValueError: dictionary update sequence element #2 has length 1; 2 is required
– Chud37
19. September 2022 um 20:33 Uhr
Schöner Code, aber es funktioniert nicht mit Kommentaren am Ende einer Zeile (nach Daten), oder? (Dies gilt wahrscheinlich auch für andere Antworten.)
– jakob.j
19. Dezember 2022 um 21:15 Uhr
@jakob.j nein, aber Sie sollten die Kommentare trotzdem über dem Code hinzufügen. Wenn Sie möchten, dass Kommentare verschwinden, können Sie dies mit Regex handhaben
– Martin Nowosad
21. Dezember 2022 um 21:01 Uhr
Verwenden Sie nur Python Std
import re
envre = re.compile(r'''^([^=]+)\s+?=\s+?(?:[\s"']*)(.+?)(?:[\s"']*)$''')
result = {}
with open('/etc/os-release') as ins:
for line in ins:
match = envre.match(line)
if match is not None:
result[match.group(1)] = match.group(2)
14397400cookie-checkEinlesen von Umgebungsvariablen aus einer Umgebungsdateiyes