Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added .env support #2164

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.DS_Store
.env
*.pyc
*.pyo
env
Expand Down
3 changes: 3 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ Major release, unreleased
- Make `app.run()` into a noop if a Flask application is run from the
development server on the command line. This avoids some behavior that
was confusing to debug for newcomers.
- The `flask` command line tool now loads a `.env` file when it discovers
one. When it finds one it will change into that folder before starting

This comment was marked as off-topic.

This comment was marked as off-topic.

and load environment variables from it.

Version 0.12.1
--------------
Expand Down
11 changes: 10 additions & 1 deletion docs/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ register more commands there if they desire so.
For the :command:`flask` script to work, an application needs to be
discovered. This is achieved by exporting the ``FLASK_APP`` environment
variable. It can be either set to an import path or to a filename of a
Python module that contains a Flask application.
Python module that contains a Flask application. Additionally the
:command:`flask` command as of 0.13 will look for a ``.env`` file in the
current folder or any higher folder and automatically load all environment
variables from it.

In that imported file the name of the app needs to be called ``app`` or
optionally be specified after a colon. For instance
Expand All @@ -48,6 +51,12 @@ Or with a filename::
export FLASK_APP=/path/to/hello.py
flask run

If you use Flask 0.13 or later you can also set the environment variables
in a ``.env`` file. For instance like this::

FLASK_APP=/path/to/hello.py
FLASK_DEBUG=1

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

Virtualenv Integration
----------------------

Expand Down
3 changes: 2 additions & 1 deletion flask/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,8 @@ def run(self, host=None, port=None, debug=None, **options):
"""
# Change this into a no-op if the server is invoked from the
# command line. Have a look at cli.py for more information.
if os.environ.get('FLASK_RUN_FROM_CLI_SERVER') == '1':
# After the first call we unset the variable however.
if os.environ.pop('FLASK_RUN_FROM_CLI', None) == '1':
from .debughelpers import explain_ignored_app_run
explain_ignored_app_run()
return
Expand Down
72 changes: 63 additions & 9 deletions flask/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import click

from ._compat import iteritems, reraise
from ._compat import iteritems, reraise, text_type, PY2
from .helpers import get_debug_flag
from . import __version__

Expand Down Expand Up @@ -120,6 +120,57 @@ def find_default_import_path():
return app


def find_dotenv():
here = os.getcwd()
while 1:

This comment was marked as off-topic.

This comment was marked as off-topic.

path = os.path.join(here, '.env')
if os.path.isfile(path):
return path
there = os.path.dirname(here)
if there == here:
break
here = there


def _set_env(key, value):
if PY2:
if isinstance(value, text_type):
value = value.encode('utf-8')
else:
key = key.decode('utf-8', 'surrogateescape')
if isinstance(value, bytes):
value = value.decode('utf-8', 'surrogateescape')
os.environ[key] = value


def _unquote(s):
if len(s) >= 2 and s[0] == s[-1] and s[0] in '"\'':
return s[1:-1] \
.decode('utf-8', 'replace') \
.encode('utf-8', 'unicode-escape') \
.decode('unicode-escape')
return s


def load_dotenv():
"""Loads a dotenv file for flask."""
path = find_dotenv()
if path is None:
return
os.chdir(os.path.dirname(path))
with open(path, 'rb') as f:
for line in f:
line = line.strip()
if not line or line[:1] == b'#' or b'=' not in line:
continue
key, value = line.split(b'=', 1)
value = _unquote(value.strip())
_set_env(key.strip(), value)


_load_dotenv = load_dotenv


def get_version(ctx, param, value):
if not value or ctx.resilient_parsing:
return
Expand Down Expand Up @@ -199,7 +250,17 @@ class ScriptInfo(object):
onwards as click object.
"""

def __init__(self, app_import_path=None, create_app=None):
def __init__(self, app_import_path=None, create_app=None,
load_dotenv=True):
# Set a global flag that indicates that we were invoked from the
# command line interface. This is detected by Flask.run to make
# the call into a no-op. This is necessary to avoid ugly errors
# when the script that is loaded here also attempts to start a
# server.
os.environ['FLASK_RUN_FROM_CLI'] = '1'

if load_dotenv:
_load_dotenv()
if create_app is None:
if app_import_path is None:
app_import_path = find_default_import_path()
Expand Down Expand Up @@ -412,13 +473,6 @@ def run_command(info, host, port, reload, debugger, eager_loading,
"""
from werkzeug.serving import run_simple

# Set a global flag that indicates that we were invoked from the
# command line interface provided server command. This is detected
# by Flask.run to make the call into a no-op. This is necessary to
# avoid ugly errors when the script that is loaded here also attempts
# to start a server.
os.environ['FLASK_RUN_FROM_CLI_SERVER'] = '1'

debug = get_debug_flag()
if reload is None:
reload = bool(debug)
Expand Down