Managing Configuration Namespaces
When you integrate third-party libraries like Celery or a custom storage engine into a Flask application, you often need to pass a specific subset of configuration settings to their constructors. Instead of manually picking keys from app.config, Flask provides tools to isolate and manage these settings using namespaces.
Extracting Configuration Subsets
If your configuration contains many keys with a common prefix, you can use get_namespace to extract them into a separate dictionary. This is particularly useful for passing keyword arguments to external classes or functions.
app.config["IMAGE_STORE_TYPE"] = "fs"
app.config["IMAGE_STORE_PATH"] = "/var/app/images"
app.config["IMAGE_STORE_BASE_URL"] = "http://img.website.com"
# Extract settings starting with 'IMAGE_STORE_'
image_store_config = app.config.get_namespace("IMAGE_STORE_")
The resulting image_store_config dictionary will look like this:
{
"type": "fs",
"path": "/var/app/images",
"base_url": "http://img.website.com"
}
How get_namespace Works Internally
The Config.get_namespace method in flask/config.py iterates through all configuration items and filters for keys that start with the provided string. By default, it performs two transformations:
- Trimming: It removes the namespace prefix from the keys (controlled by
trim_namespace=True). - Lowercasing: It converts the remaining key to lowercase (controlled by
lowercase=True).
This behavior is designed to match the common Python pattern where configuration constants are UPPERCASE but function arguments are lowercase.
Loading Prefixed Environment Variables
Modern applications often use environment variables for configuration. Flask supports loading these into specific namespaces using from_prefixed_env. This method allows you to group related settings and even create nested dictionary structures.
# In your shell:
# export FLASK_DATABASE__HOST=localhost
# export FLASK_DATABASE__PORT=5432
app.config.from_prefixed_env()
After calling this, app.config["DATABASE"] will contain {"HOST": "localhost", "PORT": "5432"}.
Handling Nested Structures
The from_prefixed_env method uses a double underscore (__) as a separator to indicate nesting. When it encounters a key like FLASK_DATABASE__HOST, it:
- Removes the
FLASK_prefix. - Splits the remaining string
DATABASE__HOSTby__. - Ensures
app.config["DATABASE"]is a dictionary. - Sets the
HOSTkey within that dictionary.
Type Conversion
By default, from_prefixed_env attempts to parse environment variable values as JSON using json.loads. This allows you to pass booleans, integers, or even full JSON objects/lists through environment variables. If parsing fails, the value remains a string.
# export FLASK_DEBUG=true
# export FLASK_RETRY_LIMIT=5
app.config.from_prefixed_env()
# app.config["DEBUG"] is True (bool)
# app.config["RETRY_LIMIT"] is 5 (int)
Practical Example: Celery Integration
A common pattern in Flask is to define default settings in a dictionary and allow environment variables to override specific nested values. This is frequently seen in Celery integrations within Flask.
from flask import Flask
def create_app() -> Flask:
app = Flask(__name__)
# Define default nested configuration
app.config.from_mapping(
CELERY=dict(
broker_url="redis://localhost",
result_backend="redis://localhost",
task_ignore_result=True,
),
)
# Allow overrides via environment variables
# e.g., FLASK_CELERY__BROKER_URL=redis://production-redis
app.config.from_prefixed_env()
return app
In this scenario, from_mapping ensures that the CELERY key exists as a dictionary. When from_prefixed_env runs, it traverses into that existing dictionary to update specific keys if the corresponding environment variables are set.
Important Constraints
When managing namespaces, keep the following Flask behaviors in mind:
- Uppercase Filtering: Methods like
from_object,from_pyfile, andfrom_mappingonly process keys that are entirely uppercase. This prevents internal attributes or temporary variables in config files from accidentally entering your application configuration. - Case Sensitivity: While
get_namespacedefaults to lowercasing keys for usage in Python code, the keys stored insideapp.configitself are case-sensitive. - Windows Environment Variables: On Windows, environment variable keys are always uppercase. This means
from_prefixed_envwill always result in uppercase keys (or nested keys) when running on Windows, regardless of how they were defined in the shell.