2

I have spent quite a while trying to figure out how to set .env and .flaskenv configuration values in my flask backend in Google Cloud Platform server. I am using apache2, mod_wsgi, Flask, Python 3.6 and SQLAlchemy. My backend works fine locally on my Mac using pure Flask.

Having python-dotenv installed, running the flask command will set environment variables defined in the files .env and .flaskenv. This, however, does not work with wsgi. The request from apache is redirected to execute my run.wsgi-file. There is no mechanism (that I have knowledge about) to set the environment variables defined in .env and .flaskenv.

The minimun requirement is to pass to the application information if test or development environment should be used. From there I could within init.py populate app.config values from an object. However, being somehow able to use config-values from .env and .flaskenv would be far better. I would really appreciate if somebody had any good ideas here - the best practice to set app.config values in wsgi environment.

There are two posts where this same problem has been presented - they really do not have a best practice how to tackle this challenge (and I am sure I am not the only one having a hard time with this):

Why can't Flask can't see my environment variables from Apache (mod_wsgi)?

Apache SetEnv not working as expected with mod_wsgi

My run.wsgi:

import sys
sys.path.append("/var/www/contacts-api/venv/lib/python3.6/site-packages")
sys.path.insert(0,"/var/www/contacts-api/")
from contacts import create_app
app = create_app('settings.py')
app.run()

[3]:Allows you to configure an application using pre-set methods.

from flask_appconfig import AppConfig
def create_app(configfile=None):
app = Flask('myapp')
AppConfig(app, configfile)
return app

The application returned by create_app will, in order:

Load default settings from a module called myapp.default_config, if it exists. (method described in http://flask.pocoo.org/docs/config/#configuring-from-files ) Load settings from a configuration file whose name is given in the environment variable MYAPP_CONFIG (see link from 1.). Load json or string values directly from environment variables that start with a prefix of MYAPP_, i.e. setting MYAPP_SQLALCHEMY_ECHO=true will cause the setting of SQLALCHEMY_ECHO to be True. Any of these behaviors can be altered or disabled by passing the appropriate options to the constructor or init_app().

[4]: Using “ENV-only” If you only want to use the environment-parsing functions of Flask-AppConfig, the appropriate functions are exposed:

from flask_appconfig.heroku import from_heroku_envvars
from flask_appconfig.env import from_envvars
# from environment variables. note that you need to set the prefix, as
# no auto-detection can be done without an app object
from_envvars(app.config, prefix=app.name.upper() + '_')
# also possible: parse heroku configuration values
# any dict-like object will do as the first parameter
from_heroku_envvars(app.config)
Rahul Kr Daman
  • 387
  • 3
  • 15
Janne
  • 21
  • 1
  • 4

3 Answers3

1

The easy to go will be using load_dotenv() and from_mapping

from flask import Flask
from dotenv import load_dotenv , dotenv_values

load_dotenv()

app = Flask(__name__)
config = dotenv_values()
app.config.from_mapping(config)
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 18 '23 at 11:09
0

After reading more about this and trying many different things. I reached to the conclusion that there is no reasonable way for configuring a Flask-application using .env- and .flaskenv -files. I ended up using a method presented in Configuration Handling which enables managing development/testing/production-environments in a reasonable manner:

app = Flask(__name__)
app.config.from_object('yourapplication.default_settings')
app.config.from_envvar('YOURAPPLICATION_SETTINGS')

My run.wsgi (being used in google cloud platform compute instance):

import sys
import os
from contacts import create_app
sys.path.append("/var/www/myapp/venv/lib/python3.6/site-packages")
sys.path.insert(0,"/var/www/myapp/")
os.environ['SETTINGS_PLATFORM_SPECIFIC'] = "/path/settings_platform_specific.py"
os.environ['CONFIG_ENVIRONMENT'] = 'DevelopmentConfig'

app = create_app(')
app.run()

Locally on my mac I use run.py (for flask run):

import os
from contacts import create_app
os.environ['SETTINGS_PLATFORM_SPECIFIC'] ="/path/settings_platform_specific.py"
os.environ['CONFIG_ENVIRONMENT'] = 'DevelopmentConfig'

if __name__ == '__main__':
    app = create_app()
    app.run()

For app creation init.py

def create_app():

    app = Flask(__name__, template_folder='templates')
    app.config.from_object(f'contacts.settings_common.{os.environ.get("CONFIG_ENVIRONMENT")}')
    app.config.from_envvar('SETTINGS_PLATFORM_SPECIFIC')

    db.init_app(app)
    babel.init_app(app)
    mail.init_app(app)
    bcrypt.init_app(app)
    app.register_blueprint(routes)
    create_db(app)

    return app

At this point it looks like this works out fine for my purposes. The most important thing is that I can easily manage different environments and deploy the backend service to google platform using git.

Janne
  • 21
  • 1
  • 4
0

I was wrestling with the same conundrum, wanting to use the same .env file I was using with docker-compose while developing with flask run. I ended up using python-dotenv, like so:

In .env:

DEBUG=True
APPLICATION_ROOT=${PWD}

In config.py:

import os

from dotenv import load_dotenv
load_dotenv()

class Config(object):
    SECRET_KEY = os.getenv('SECRET_KEY') or 'development-secret'
    DEBUG = os.getenv("DEBUG") or False
    APPLICATION_ROOT = os.getenv("APPLICATION_ROOT") or os.getcwd()

I haven't experimented with it yet, but I may also give flask-env a try in combination with this solution.

Joseph8th
  • 636
  • 5
  • 10
  • The best solution so far that I have come up with is using instance folder and reating app with this option app = Flask(__name__, instance_relative_config=True). In the instance folder I set up app.config value for config-environment which I then use to choose the configuration using an object with configurations for development, testing, staging and production. Also, I ditched mod_wsgi and now use gunicorn + nginx. – Janne Nov 19 '19 at 05:50