How to pass a list as an environment variable?
Question:
I use a list as part of a Python program, and wanted to convert that to an environment variable.
So, it’s like this:
list1 = ['a.1','b.2','c.3']
for items in list1:
alpha,number = items.split('.')
print(alpha,number)
which gives me, as expected:
a 1
b 2
c 3
But when I try to set it as an environment variable, as:
export LIST_ITEMS = 'a.1', 'b.2', 'c.3'
and do:
list1 = [os.environ.get("LIST_ITEMS")]
for items in list1:
alpha,number = items.split('.')
print(alpha,number)
I get an error: ValueError: too many values to unpack
How do I modify the way I pass the list, or get it so that I have the same output as without using env variables?
Answers:
I’m not sure why you’d do it through the environment variables, but you can do this:
export LIST_ITEMS ="a.1 b.2 c.3"
And in Python:
list1 = [i.split(".") for i in os.environ.get("LIST_ITEMS").split(" ")]
for k, v in list1:
print(k, v)
If you want to set the environment variable using that format — ['a.1','b.2','c.3']
— this would work:
from ast import literal_eval
list1 = [literal_eval(e.strip()) for e in os.environ["LIST_ITEMS"].split(',')]
for item in list1:
alpha,number = item.split('.')
print alpha, number
Output:
a 1
b 2
c 3
The rationale
I recommend using JSON if you want to have data structured in an environment variable. JSON is simple to write / read, can be written in a single line, parsers exist, developers know it.
The solution
To test, execute this in your shell:
$ export ENV_LIST_EXAMPLE='["Foo", "bar"]'
Python code to execute in the same shell:
import os
import json
env_list = json.loads(os.environ['ENV_LIST_EXAMPLE'])
print(env_list)
print(type(env_list))
gives
['Foo', 'bar']
<class 'list'>
Package
Chances are high that you are interested in cfg_load
Debugging
If you see
JSONDecodeError: Expecting value: line 1 column 2 (char 1)
You might have used single-quotes instead of double-quotes. While some JSON libraries accept that, the JSON standard clearly states that you need to use double-quotes:
Wrong: "['foo', 'bar']"
Right: '["foo", "bar"]'
The environs PyPI package handles my use case well: load a single setting from env var and coerce it to a list, int, etc:
from environs import Env
env = Env()
env.read_env() # read .env file, if it exists
# required variables
# env: GITHUB_USER=sloria
gh_user = env("GITHUB_USER") # => 'sloria'
# env: <unset>
secret = env("SECRET") # => raises error if not set
# casting
# env: MAX_CONNECTIONS=100
max_connections = env.int("MAX_CONNECTIONS") # => 100
# env: SHIP_DATE='1984-06-25'
ship_date = env.date("SHIP_DATE") # => datetime.date(1984, 6, 25)
# env: TTL=42
ttl = env.timedelta("TTL") # => datetime.timedelta(0, 42)
# providing a default value
# env: ENABLE_LOGIN=true
enable_login = env.bool("ENABLE_LOGIN", False) # => True
# env: <unset>
enable_feature_x = env.bool("ENABLE_FEATURE_X", False) # => False
# parsing lists
# env: GITHUB_REPOS=webargs,konch,ped
gh_repos = env.list("GITHUB_REPOS") # => ['webargs', 'konch', 'ped']
# env: COORDINATES=23.3,50.0
coords = env.list("COORDINATES", subcast=float) # => [23.3, 50.0]
YOUR_VARIABLE="val1, val2"
In your Python code, Just split them as a list
import os
os.environ.get('YOUR_VARIABLE').split(', ')
So no matter what I tried, i could not send emails to multiple recipients with smtplib. The only solution that worked out for me is to for loop the recipients
import smtplib
from email.mime.text import MIMEText
s = smtplib.SMTP('smtp.freesmtpservers.com')
# s.set_debuglevel(1)
recipients = ['[email protected]','[email protected]','[email protected]','[email protected]']
for x in recipients:
msg = MIMEText("""body""")
sender = '[email protected]'
msg['Subject'] = "subject line"
msg['From'] = sender
msg['To'] = str(x)
s.sendmail(sender, str(x), msg.as_string())
In .env:
VAR="val1,val2..."
In python code:
from dotenv import load_dotenv
load_dotenv('/path/to/your/file.env')
value = os.getenv('VAR').split(',')
It’s work for send for email’s list
I use a list as part of a Python program, and wanted to convert that to an environment variable.
So, it’s like this:
list1 = ['a.1','b.2','c.3']
for items in list1:
alpha,number = items.split('.')
print(alpha,number)
which gives me, as expected:
a 1
b 2
c 3
But when I try to set it as an environment variable, as:
export LIST_ITEMS = 'a.1', 'b.2', 'c.3'
and do:
list1 = [os.environ.get("LIST_ITEMS")]
for items in list1:
alpha,number = items.split('.')
print(alpha,number)
I get an error: ValueError: too many values to unpack
How do I modify the way I pass the list, or get it so that I have the same output as without using env variables?
I’m not sure why you’d do it through the environment variables, but you can do this:
export LIST_ITEMS ="a.1 b.2 c.3"
And in Python:
list1 = [i.split(".") for i in os.environ.get("LIST_ITEMS").split(" ")]
for k, v in list1:
print(k, v)
If you want to set the environment variable using that format — ['a.1','b.2','c.3']
— this would work:
from ast import literal_eval
list1 = [literal_eval(e.strip()) for e in os.environ["LIST_ITEMS"].split(',')]
for item in list1:
alpha,number = item.split('.')
print alpha, number
Output:
a 1
b 2
c 3
The rationale
I recommend using JSON if you want to have data structured in an environment variable. JSON is simple to write / read, can be written in a single line, parsers exist, developers know it.
The solution
To test, execute this in your shell:
$ export ENV_LIST_EXAMPLE='["Foo", "bar"]'
Python code to execute in the same shell:
import os
import json
env_list = json.loads(os.environ['ENV_LIST_EXAMPLE'])
print(env_list)
print(type(env_list))
gives
['Foo', 'bar']
<class 'list'>
Package
Chances are high that you are interested in cfg_load
Debugging
If you see
JSONDecodeError: Expecting value: line 1 column 2 (char 1)
You might have used single-quotes instead of double-quotes. While some JSON libraries accept that, the JSON standard clearly states that you need to use double-quotes:
Wrong: "['foo', 'bar']"
Right: '["foo", "bar"]'
The environs PyPI package handles my use case well: load a single setting from env var and coerce it to a list, int, etc:
from environs import Env
env = Env()
env.read_env() # read .env file, if it exists
# required variables
# env: GITHUB_USER=sloria
gh_user = env("GITHUB_USER") # => 'sloria'
# env: <unset>
secret = env("SECRET") # => raises error if not set
# casting
# env: MAX_CONNECTIONS=100
max_connections = env.int("MAX_CONNECTIONS") # => 100
# env: SHIP_DATE='1984-06-25'
ship_date = env.date("SHIP_DATE") # => datetime.date(1984, 6, 25)
# env: TTL=42
ttl = env.timedelta("TTL") # => datetime.timedelta(0, 42)
# providing a default value
# env: ENABLE_LOGIN=true
enable_login = env.bool("ENABLE_LOGIN", False) # => True
# env: <unset>
enable_feature_x = env.bool("ENABLE_FEATURE_X", False) # => False
# parsing lists
# env: GITHUB_REPOS=webargs,konch,ped
gh_repos = env.list("GITHUB_REPOS") # => ['webargs', 'konch', 'ped']
# env: COORDINATES=23.3,50.0
coords = env.list("COORDINATES", subcast=float) # => [23.3, 50.0]
YOUR_VARIABLE="val1, val2"
In your Python code, Just split them as a list
import os
os.environ.get('YOUR_VARIABLE').split(', ')
So no matter what I tried, i could not send emails to multiple recipients with smtplib. The only solution that worked out for me is to for loop the recipients
import smtplib
from email.mime.text import MIMEText
s = smtplib.SMTP('smtp.freesmtpservers.com')
# s.set_debuglevel(1)
recipients = ['[email protected]','[email protected]','[email protected]','[email protected]']
for x in recipients:
msg = MIMEText("""body""")
sender = '[email protected]'
msg['Subject'] = "subject line"
msg['From'] = sender
msg['To'] = str(x)
s.sendmail(sender, str(x), msg.as_string())
In .env:
VAR="val1,val2..."
In python code:
from dotenv import load_dotenv
load_dotenv('/path/to/your/file.env')
value = os.getenv('VAR').split(',')
It’s work for send for email’s list