Skip to content

Commit

Permalink
Support loading configuration from text files
Browse files Browse the repository at this point in the history
TOML is a very popular format now, and is taking hold in the Python
ecosystem via pyproject.toml (among others). This allows toml config
files via,

    app.config.from_file("config.toml", toml.loads)

it also allows for any other file format whereby there is a loader
that takes a string and returns a mapping.
  • Loading branch information
pgjones committed Oct 15, 2019
1 parent 941bc9f commit 8557eb1
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 8 deletions.
33 changes: 25 additions & 8 deletions src/flask/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,31 +176,48 @@ class and has ``@property`` attributes, it needs to be
if key.isupper():
self[key] = getattr(obj, key)

def from_json(self, filename, silent=False):
"""Updates the values in the config from a JSON file. This function
behaves as if the JSON object was a dictionary and passed to the
:meth:`from_mapping` function.
def from_file(self, filename, loads, silent=False):
"""Update the values in the config from a file that is loaded using
the *loads* argument. This method passes the loaded Mapping
to the :meth:`from_mapping` function.
:param filename: the filename of the JSON file. This can either be an
absolute filename or a filename relative to the
root path.
:param loads: a callable that loads the file text and returned a
Mapping.
:type loads: Callable[[str], Mapping].
:param silent: set to ``True`` if you want silent failure for missing
files.
.. versionadded:: 0.11
.. versionadded:: 1.2
"""
filename = os.path.join(self.root_path, filename)

try:
with open(filename) as json_file:
obj = json.loads(json_file.read())
with open(filename) as file_:
obj = loads(file_.read())
except IOError as e:
if silent and e.errno in (errno.ENOENT, errno.EISDIR):
return False
e.strerror = "Unable to load configuration file (%s)" % e.strerror
raise
return self.from_mapping(obj)

def from_json(self, filename, silent=False):
"""Updates the values in the config from a JSON file. This function
behaves as if the JSON object was a dictionary and passed to the
:meth:`from_mapping` function.
:param filename: the filename of the JSON file. This can either be an
absolute filename or a filename relative to the
root path.
:param silent: set to ``True`` if you want silent failure for missing
files.
.. versionadded:: 0.11
"""
return self.from_file(filename, json.loads, silent=silent)

def from_mapping(self, *mapping, **kwargs):
"""Updates the config like :meth:`update` ignoring items with non-upper
keys.
Expand Down
2 changes: 2 additions & 0 deletions tests/static/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TEST_KEY = "foo"
SECRET_KEY = "config"
8 changes: 8 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from datetime import timedelta

import pytest
import toml

import flask
from flask._compat import PY2
Expand Down Expand Up @@ -46,6 +47,13 @@ def test_config_from_json():
common_object_test(app)


def test_config_from_file():
app = flask.Flask(__name__)
current_dir = os.path.dirname(os.path.abspath(__file__))
app.config.from_file(os.path.join(current_dir, "static", "config.toml"), toml.loads)
common_object_test(app)


def test_config_from_mapping():
app = flask.Flask(__name__)
app.config.from_mapping({"SECRET_KEY": "config", "TEST_KEY": "foo"})
Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ deps =
greenlet
blinker
python-dotenv
toml

lowest: Werkzeug==0.15
lowest: Jinja2==2.10
Expand Down

0 comments on commit 8557eb1

Please sign in to comment.