1import json
2import os
3import textwrap
4from datetime import timedelta
5
6import pytest
7
8import flask
9
10
11# config keys used for the TestConfig
12TEST_KEY = "foo"
13SECRET_KEY = "config"
14
15
16def common_object_test(app):
17    assert app.secret_key == "config"
18    assert app.config["TEST_KEY"] == "foo"
19    assert "TestConfig" not in app.config
20
21
22def test_config_from_pyfile():
23    app = flask.Flask(__name__)
24    app.config.from_pyfile(f"{__file__.rsplit('.', 1)[0]}.py")
25    common_object_test(app)
26
27
28def test_config_from_object():
29    app = flask.Flask(__name__)
30    app.config.from_object(__name__)
31    common_object_test(app)
32
33
34def test_config_from_file():
35    app = flask.Flask(__name__)
36    current_dir = os.path.dirname(os.path.abspath(__file__))
37    app.config.from_file(os.path.join(current_dir, "static", "config.json"), json.load)
38    common_object_test(app)
39
40
41def test_config_from_mapping():
42    app = flask.Flask(__name__)
43    app.config.from_mapping({"SECRET_KEY": "config", "TEST_KEY": "foo"})
44    common_object_test(app)
45
46    app = flask.Flask(__name__)
47    app.config.from_mapping([("SECRET_KEY", "config"), ("TEST_KEY", "foo")])
48    common_object_test(app)
49
50    app = flask.Flask(__name__)
51    app.config.from_mapping(SECRET_KEY="config", TEST_KEY="foo")
52    common_object_test(app)
53
54    app = flask.Flask(__name__)
55    with pytest.raises(TypeError):
56        app.config.from_mapping({}, {})
57
58
59def test_config_from_class():
60    class Base:
61        TEST_KEY = "foo"
62
63    class Test(Base):
64        SECRET_KEY = "config"
65
66    app = flask.Flask(__name__)
67    app.config.from_object(Test)
68    common_object_test(app)
69
70
71def test_config_from_envvar(monkeypatch):
72    monkeypatch.setattr("os.environ", {})
73    app = flask.Flask(__name__)
74    with pytest.raises(RuntimeError) as e:
75        app.config.from_envvar("FOO_SETTINGS")
76        assert "'FOO_SETTINGS' is not set" in str(e.value)
77    assert not app.config.from_envvar("FOO_SETTINGS", silent=True)
78
79    monkeypatch.setattr(
80        "os.environ", {"FOO_SETTINGS": f"{__file__.rsplit('.', 1)[0]}.py"}
81    )
82    assert app.config.from_envvar("FOO_SETTINGS")
83    common_object_test(app)
84
85
86def test_config_from_envvar_missing(monkeypatch):
87    monkeypatch.setattr("os.environ", {"FOO_SETTINGS": "missing.cfg"})
88    with pytest.raises(IOError) as e:
89        app = flask.Flask(__name__)
90        app.config.from_envvar("FOO_SETTINGS")
91    msg = str(e.value)
92    assert msg.startswith(
93        "[Errno 2] Unable to load configuration file (No such file or directory):"
94    )
95    assert msg.endswith("missing.cfg'")
96    assert not app.config.from_envvar("FOO_SETTINGS", silent=True)
97
98
99def test_config_missing():
100    app = flask.Flask(__name__)
101    with pytest.raises(IOError) as e:
102        app.config.from_pyfile("missing.cfg")
103    msg = str(e.value)
104    assert msg.startswith(
105        "[Errno 2] Unable to load configuration file (No such file or directory):"
106    )
107    assert msg.endswith("missing.cfg'")
108    assert not app.config.from_pyfile("missing.cfg", silent=True)
109
110
111def test_config_missing_file():
112    app = flask.Flask(__name__)
113    with pytest.raises(IOError) as e:
114        app.config.from_file("missing.json", load=json.load)
115    msg = str(e.value)
116    assert msg.startswith(
117        "[Errno 2] Unable to load configuration file (No such file or directory):"
118    )
119    assert msg.endswith("missing.json'")
120    assert not app.config.from_file("missing.json", load=json.load, silent=True)
121
122
123def test_custom_config_class():
124    class Config(flask.Config):
125        pass
126
127    class Flask(flask.Flask):
128        config_class = Config
129
130    app = Flask(__name__)
131    assert isinstance(app.config, Config)
132    app.config.from_object(__name__)
133    common_object_test(app)
134
135
136def test_session_lifetime():
137    app = flask.Flask(__name__)
138    app.config["PERMANENT_SESSION_LIFETIME"] = 42
139    assert app.permanent_session_lifetime.seconds == 42
140
141
142def test_send_file_max_age():
143    app = flask.Flask(__name__)
144    app.config["SEND_FILE_MAX_AGE_DEFAULT"] = 3600
145    assert app.send_file_max_age_default.seconds == 3600
146    app.config["SEND_FILE_MAX_AGE_DEFAULT"] = timedelta(hours=2)
147    assert app.send_file_max_age_default.seconds == 7200
148
149
150def test_get_namespace():
151    app = flask.Flask(__name__)
152    app.config["FOO_OPTION_1"] = "foo option 1"
153    app.config["FOO_OPTION_2"] = "foo option 2"
154    app.config["BAR_STUFF_1"] = "bar stuff 1"
155    app.config["BAR_STUFF_2"] = "bar stuff 2"
156    foo_options = app.config.get_namespace("FOO_")
157    assert 2 == len(foo_options)
158    assert "foo option 1" == foo_options["option_1"]
159    assert "foo option 2" == foo_options["option_2"]
160    bar_options = app.config.get_namespace("BAR_", lowercase=False)
161    assert 2 == len(bar_options)
162    assert "bar stuff 1" == bar_options["STUFF_1"]
163    assert "bar stuff 2" == bar_options["STUFF_2"]
164    foo_options = app.config.get_namespace("FOO_", trim_namespace=False)
165    assert 2 == len(foo_options)
166    assert "foo option 1" == foo_options["foo_option_1"]
167    assert "foo option 2" == foo_options["foo_option_2"]
168    bar_options = app.config.get_namespace(
169        "BAR_", lowercase=False, trim_namespace=False
170    )
171    assert 2 == len(bar_options)
172    assert "bar stuff 1" == bar_options["BAR_STUFF_1"]
173    assert "bar stuff 2" == bar_options["BAR_STUFF_2"]
174
175
176@pytest.mark.parametrize("encoding", ["utf-8", "iso-8859-15", "latin-1"])
177def test_from_pyfile_weird_encoding(tmpdir, encoding):
178    f = tmpdir.join("my_config.py")
179    f.write_binary(
180        textwrap.dedent(
181            f"""
182            # -*- coding: {encoding} -*-
183            TEST_VALUE = "föö"
184            """
185        ).encode(encoding)
186    )
187    app = flask.Flask(__name__)
188    app.config.from_pyfile(str(f))
189    value = app.config["TEST_VALUE"]
190    assert value == "föö"
191