Custom Flask Example¶
The Configuration
class can be extended and customized to cater to application-specific requirements. Developers can implement custom logic with getters and setters to handle unique settings or scenarios.
Folder contents¶
This example uses a custom Configuration class in the config.py module that inherits from Configuration
.
CustomConfiguration
class CustomConfiguration(Configuration):
def __init__(self):
super().__init__()
@property
def logging_debug(self):
return getattr(self, "_logging_debug")
@logging_debug.setter
def logging_debug(self, value: bool):
if not isinstance(value, bool):
raise ValueError(f"value must be of type bool not {type(value)}")
self._logging_debug = value
log_level = "DEBUG" if value else "INFO"
configure_logging(log_level)
The custom class uses a property with a setter that executes the configure_logging
function from utils.py
whenever the logging_debug attribute is updated. Thus setting the log level to "DEBUG" if the value is True.
This will change the log level on you Flask app without restarting it.
Code examples¶
extensions/config.py
config.py
import logging
import os
from binascii import hexlify
from simple_toml_configurator import Configuration
from utils import configure_logging
logger = logging.getLogger(__name__)
default_config = {
"app": {
"ip": "0.0.0.0",
"host": "",
"port": 5000,
"upload_folder": "uploads",
"flask_secret_key": "",
"proxy": "",
"site_url": "http://localhost:5000",
"debug": True,
},
"mysql": {
"host": "",
"port": "",
"user": "",
"password": "",
"databases": {"prod":"test", "dev":"test2"},
},
"scheduler": {
"disabled": True
},
"logging": {
"debug": True
},
"queue": {
"disabled": True
},
}
config_path = os.environ.get("CONFIG_PATH", os.path.join(os.getcwd(), "config"))
class CustomConfiguration(Configuration):
def __init__(self):
super().__init__()
@property
def logging_debug(self):
return getattr(self, "_logging_debug")
@logging_debug.setter
def logging_debug(self, value: bool):
if not isinstance(value, bool):
raise ValueError(f"value must be of type bool not {type(value)}")
self._logging_debug = value
log_level = "DEBUG" if value else "INFO"
configure_logging(log_level)
settings = CustomConfiguration()
settings.init_config(config_path, default_config)
# create random Flask secret_key if there's none in config.toml
if not settings.config.get("app", {}).get("flask_secret_key"):
key = os.environ.get("APP_FLASK_SECRET_KEY", hexlify(os.urandom(16)).decode())
settings.update_config({"app_flask_secret_key": key})
# Set default mysql host
if not settings.config.get("mysql",{}).get("host"):
mysql_host = os.environ.get("MYSQL_HOST", "localhost")
settings.update_config({"mysql_host": mysql_host})
# Set default mysql port
if not settings.config.get("mysql",{}).get("port"):
mysql_port = os.environ.get("MYSQL_PORT", "3306")
settings.update_config({"mysql_port": mysql_port})
# Set default mysql user
if not settings.config.get("mysql",{}).get("user"):
mysql_user = os.environ.get("MYSQL_USER", "root")
settings.update_config({"mysql_user": mysql_user})
# Set default mysql password
if not settings.config.get("mysql",{}).get("password"):
mysql_password = os.environ.get("MYSQL_PASSWORD", "root")
settings.update_config({"mysql_password": mysql_password})
if not settings.config.get("mysql",{}).get("database"):
mysql_database = os.environ.get("MYSQL_DATABASE", "some_database")
settings.update_config({"mysql_database": mysql_database})
utils.py
utils.py
import logging
# simple logger function that takes log_level as argument and sets the log level
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger()
def configure_logging(log_level: str) -> None:
"""Configure logging for the application
Args:
log_level (str): Log level to set
"""
if logger.getEffectiveLevel() == logging.getLevelName(log_level):
return
logger.setLevel(log_level)
if log_level=="DEBUG":
logger.debug(f"Debug logging enabled")
app.py
app.py
from flask import Flask, jsonify, request, url_for,redirect
from extensions.config import settings
import logging
logger = logging.getLogger(__name__)
def create_app():
app = Flask(__name__)
app.config["SECRET_KEY"] = settings.config.get("app").get("flask_secret_key")
app.config['APP_PORT'] = settings.config.get("app").get("port")
app.config['APP_IP'] = settings.config.get("app").get("ip")
app.config['APP_HOST'] = settings.config.get("app").get("host")
app.config["DEBUG"] = settings.config.get("app").get("debug")
return app
app = create_app()
# simple route that returns the config
@app.route("/")
def app_settings():
return jsonify(
{
"response": {
"data": {
"configuration": settings.get_settings(),
"toml_config": settings.config,
}
}
})
# Update settings route
@app.route("/update", methods=["POST"])
def update_settings():
"""Update settings route"""
data = request.get_json() # {"logging_debug": True, "app_debug": True}
settings.update_config(data)
return redirect(url_for("app_settings"))
# Get settings value route
@app.route("/logger", methods=["GET"])
def get_settings():
"""Sets logging_debug to True or False"""
value = False if settings.logging_debug else True
settings.update_config({"logging_debug": value})
return jsonify({"debug_logging": settings.logging_debug})
if __name__ == "__main__":
app.run(port=app.config.get("APP_PORT"), host=app.config.get("APP_IP"), debug=app.config.get("APP_DEBUG"))