Access\Read Flask Env Variable within app - flask

I can't seem to access my env variables' values inside my app. I'm loading my env variables into my app with a .env file and the dotenv package; I learned about it here.
My .env
FLASK_ENV=development
FLASK_APP=app.py
DEBUG=ON
TESTING=False
I want to use the value of the TESTING variable inside my app and run certain code based on whether it is True or False.
How can I get these values? The docs say
Certain configuration values are also forwarded to the Flask object so
you can read and write them from there: app.testing = True
But I get module 'app' has no attribute 'testing'
When I log app by itself I see a Flask object. When I log this out like app.Flask, I see the env variables, but these appear like this, with no refernce to the current value.
{'__name__': 'TESTING', 'get_converter': None}
I want to be able to do something like:
app.testing => False
app.FLASK_ENV => development
and then eventually:
if app.testing == True:
<do something>
PS - I know the app loads this .env file okay because if I remove the values the environment changes back to production, the default.
#settings.py
from pathlib import Path # python3 only
from dotenv import load_dotenv
load_dotenv(verbose=True)
env_path = Path('.') / '.env'
load_dotenv(dotenv_path=env_path)

import os
print(os.environ['TESTING'])
Equivalent in JS is process.env

Related

How do I store environment variables both locally and not to have to change code when deploying on Heroku in Django

I have a Django project I have been working on offline and now I have hosted it on Heroku and it works well on Heroku but fails on my local machine with this error.
File "/usr/lib/python3.9/os.py", line 679, in __getitem__
raise KeyError(key) from None
KeyError: 'DEBUG'
and I think it is because I used environment variables like this.
from boto.s3.connection import S3Connection
import os
DEBUG = S3Connection(os.environ['DEBUG'], os.environ['DEBUG'])
I also have a .env file in my root(project folder) with the environment variables like this.
export JWT_SECRET_KEY = "dfge..."
export DEBUG = 1
What is the right way to store the environment variables on my local machine?
I have local file secret.py added to .gitignore with all keys, env values needed:
#secret.py
DEBUG = 1
Then in settings.py:
# settings.py
try:
import secret
DEBUG = secret.DEBUG
except ModuleNotFoundError:
DEBUG = S3Connection(os.environ['DEBUG'], os.environ['DEBUG'])

Flask environment ignored in config.py

I'm trying to build a basic flask app for learning purposes. everything flows smoothly, but there's an issue I don't understand. in my run.py file, I have the following line:
app.config.from_object('config.prodConfig')
This loads config.py in the root, which contains the following code:
class Config:
SECRET_KEY = '1234567890'
STATIC_FOLDER = 'static'
TEMPLATES_FOLDER = 'templates'
class devConfig(Config):
FLASK_ENV = 'development'
DEBUG = True
TESTING = True
class prodConfig(Config):
FLASK_ENV = 'production'
DEBUG = False
TESTING = False
my understanding is that Config contains a few "default" settings. devConfig and prodConfig are based on Config, so will always contain those values, but each will have different env, debug and testing value. though I don't get any errors and debug seems to be activated, when I run my instance of Flask it tells me I'm running in production, regardless of what I do.
* Serving Flask app "run" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
I'm not interested in setting the env variable in the terminal/environment, I know how to do that. what I'm interested in is why this doesn't work. after all, the FLASK_ENV directive is a valid one and it should load when instructed to.
What am I doing wrong?
With Chase's comment in mind, about not setting the FLASK_ENV in the app. Pass a dict of your configurations from your config.py and select the appropriate config based on the FLASK_ENV set outside your app, e.g. with a .env file.
config.py
class BaseConfig:
...
class DevConfig(BaseConfig):
...
class ProdConfig(BaseConfig):
...
configs = {"development": DevConfig, "production": ProdConfig}
app.py
import os
from flask import FLask
from config import configs
...
app.config.from_object(configs[os.environ.get("FLASK_ENV", "development")])

Still getting KeyError: 'SECRET_KEY' in my Django Project having set up environment variables

I created environment variables for my django project within my pipenv virtual envronment bin/activate (linux) or scripts\activate(windows) file , i made necessary changes in settings file as well as exiting and re activating the virtual environment but im still getting a keyerror (I'm working on a windows machine)
variables in settings.py
SECRET_KEY = os.environ['SECRET_KEY']
EMAIL_HOST_PASSWORD = os.environ['EMAIL_HOST_PASSWORD']
evnvironment variables in virtualenv\scripts\activate file
export SECRET_KEY= "mysecretkey"
export EMAIL_HOST_PASSWORD= "mypassword"
error
File "C:\Users\Dell\.virtualenvs\team-272-SMES-Server-dSgdZ4Ig\lib\os.py", line 673, in __getitem__
raise KeyError(key) from None
KeyError: 'SECRET_KEY'
Make sure you have "SECRET_KEY" in your os.environ
Use this code to check if you have "SECRET_KEY" there:
import os
import pprint
# Get the list of user's
# environment variables
env_var = os.environ
# Print the list of user's
# environment variables
print("User's Environment variable:")
pprint.pprint(dict(env_var), width = 1)
You are probably missing "SECRET_KEY" in the environment variable list. You can add a variable:
# importing os module
import os
# Add a new environment variable
os.environ['GeeksForGeeks'] = 'www.geeksforgeeks.org'
source
On a Windows server, I recommend creating a JSON (or YAML) file with all your database and app secrets. I personally prefer JSON, so an example of one is
{
"SECRET_KEY": "...",
"MYSQL_DBUSER": "jon"
"MYSQL_PW": "..."
...
}
Then in your settings.py you should add something like
import json
with open("config.json") as config:
config = json.load(config)
Then to simply load in your project's secrets, index them by the variable name like
SECRET_KEY = config['SECRET_KEY']

Why do I get the error "A valid Flask application was not obtained from..." when I use the flask cli to run my app?

I try to use the flask cli to start my application, i.e. flask run. I use the FLASK_APP environment variable to point to my application, i.e. export FLASK_APP=package_name.wsgi:app
In my wsgi.py file, I create the app with a factory function, i.e. app = create_app(config) and my create_app method looks like this:
def create_app(config_object=LocalConfig):
app = connexion.App(config_object.API_NAME,
specification_dir=config_object.API_SWAGGER_DIR,
debug=config_object.DEBUG)
app.app.config.from_object(config_object)
app.app.json_encoder = JSONEncoder
app.add_api(config_object.API_SWAGGER_YAML,
strict_validation=config_object.API_SWAGGER_STRICT,
validate_responses=config_object.API_SWAGGER_VALIDATE)
app = register_extensions(app)
app = register_blueprints(app)
return app
However, the application doesn't start, I get the error:
A valid Flask application was not obtained from "package_name.wsgi:app".
Why is this?
I can start my app normally when I use gunicorn, i.e. gunicorn package_name.wsgi:app
My create_app function didn't return an object of class flask.app.Flask but an object of class connexion.apps.flask_app.FlaskApp, because I am using the connexion framework.
In my wsgi.py file, I could simply set:
application = create_app(config)
app = application.app
I didn't even have to do export FLASK_APP=package_name.wsgi:app anymore, autodescovery worked if the flask run command was executed in the folder where the wsgi.py file is.
application = create_app(config)
app = application.app
App = app.app
For me I just created another variable pointing to connexion.app.Flask type and I set the environ as below
export FLASK_APP= __main__:App
flask shell

Separate custom settings variable between development, staging and production

I'm following the project structure as laid out by Zachary Voase, but I'm struggling with one specific issue.
I'd very much like to have a custom settings boolean variable (let's call it SEND_LIVE_MAIL) that I would be using in the project. Basically, I'd like to use this settings variable in my code and if SEND_LIVE_MAIL is True actually send out a mail, whereas when it is set to False just print its contents out to the console. The latter would apply to the dev environment and when running unittests.
What would be a good way of implementing this? Currently, depending on the environment, the django server uses dev, staging or prd settings, but for custom settings variables I believe these need to be imported 'literally'. In other words, I'd be using in my views something like
from settings.development import SEND_LIVE_MAIL
which of course isn't what I want. I'd like to be able to do something like:
from settings import SEND_LIVE_MAIL
and depending on the environment, the correct value is assigned to the SEND_LIVE_MAIL variable.
Thanks in advance!
You shouldn't be importing directly from your settings files anyways. Use:
>>> from django.conf import settings
>>> settings.SEND_LIVE_MAIL
True
The simplest solution is to have this at the bottom of your settings file:
try:
from local_settings import *
except ImportError:
pass
And in local_settings.py specify all your environment-specific overrides. I generally don't commit this file to version control.
There are more advanced ways of doing it, where you end up with a default settings file and a per-environment override.
This article by David Cramer covers the various approaches, including both of the ones I've mentioned: http://justcramer.com/2011/01/13/settings-in-django/
import os
PROJECT_PATH = os.path.dirname(__file__)
try:
execfile(os.path.join(PROJECT_PATH, local_settings.py'))
except IOError:
pass
Then you can have your local_settings.py behave as if it was pasted directly into your settings.py:
$ cat local_settings.py
INSTALLED_APPS += ['foo']
You can do something like this for a wide variety of environment based settings, but here's an example for just SEND_LIVE_MAIL.
settings_config.py
import re
import socket
class Config:
def __init__(self):
fqdn = socket.getfqdn()
env = re.search(r'(devhost|stagehost|prodhost)', fqdn)
env = env and env.group(1)
env = env or 'devhost'
if env == 'devhost':
self.SEND_LIVE_MAIL = # whatever
elif env == 'stagehost':
self.SEND_LIVE_MAIL = # whatever
elif env == 'prodhost':
self.SEND_LIVE_MAIL = # whatever
config = Config()
settings.py
from settings_config import config
SEND_LIVE_MAIL = config.SEND_LIVE_MAIL