Command Line Interface#
New in version 2.4.0.
Flask-Limiter adds a few subcommands to the Flask Command Line Interface for maintenance & diagnostic purposes. These can be accessed under the limiter sub-command as follows
Usage: flask limiter [OPTIONS] COMMAND [ARGS]...
Flask-Limiter maintenance & utility commmands
Options:
--help Show this message and exit.
Commands:
clear Clear limits for a specific key
config View the extension configuration
limits Enumerate details about all routes with rate limits
Example#
The examples below use the following example application:
import os
import jinja2
from flask import Blueprint, Flask, jsonify, request, render_template, make_response
from flask.views import View
import flask_limiter
from flask_limiter import ExemptionScope, Limiter
from flask_limiter.util import get_remote_address
def index_error_responder(request_limit):
error_template = jinja2.Environment().from_string(
"""
<h1>Breached rate limit of: {{request_limit.limit}}</h1>
<h2>Path: {{request.path}}</h2>
"""
)
return make_response(render_template(error_template, request_limit=request_limit))
def app():
def default_limit_extra():
if request.headers.get("X-Evil"):
return "100/minute"
return "200/minute"
def default_cost():
if request.headers.get("X-Evil"):
return 2
return 1
limiter = Limiter(
get_remote_address,
default_limits=["20/hour", "1000/hour", default_limit_extra],
default_limits_exempt_when=lambda: request.headers.get("X-Internal"),
default_limits_deduct_when=lambda response: response.status_code == 200,
default_limits_cost=default_cost,
application_limits=["5000/hour"],
headers_enabled=True,
storage_uri=os.environ.get("FLASK_RATELIMIT_STORAGE_URI", "memory://"),
)
app = Flask(__name__)
app.config.from_prefixed_env()
@app.errorhandler(429)
def handle_error(e):
return e.get_response() or make_response(
jsonify(error="ratelimit exceeded %s" % e.description)
)
@app.route("/")
@limiter.limit("10/minute", on_breach=index_error_responder)
def root():
"""
Custom rate limit of 10/minute which overrides the default limits.
The error page displayed on rate limit breached is also customized by using
an `on_breach` callback to render a template
"""
return "42"
@app.route("/version")
@limiter.exempt
def version():
"""
Exempt from all rate limits
"""
return flask_limiter.__version__
health_blueprint = Blueprint("health", __name__, url_prefix="/health")
@health_blueprint.route("/")
def health():
return "ok"
app.register_blueprint(health_blueprint)
#: Exempt from default, application and ancestor rate limits (effectively all)
limiter.exempt(
health_blueprint,
flags=ExemptionScope.DEFAULT
| ExemptionScope.APPLICATION
| ExemptionScope.ANCESTORS,
)
class ResourceView(View):
methods = ["GET", "POST"]
@staticmethod
def json_error_responder(request_limit):
return jsonify({"limit": str(request_limit.limit)})
#: Custom rate limit of 5/second by http method type for all routes under this
#: resource view. The error response is also customized by using the `on_breach`
#: callback to return a json error response
decorators = [
limiter.limit("5/second", per_method=True, on_breach=json_error_responder)
]
def dispatch_request(self):
return request.method.lower()
app.add_url_rule("/resource", view_func=ResourceView.as_view("resource"))
limiter.init_app(app)
return app
if __name__ == "__main__":
app().run()
Extension Config#
Use the subcommand config to display the active configuration
$ flask limiter config
$ FLASK_APP=../../examples/kitchensink.py:app flask limiter config
Traceback (most recent call last):
File "/usr/bin/flask", line 33, in <module>
sys.exit(load_entry_point('Flask==2.0.3', 'console_scripts', 'flask')())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 995, in main
cli.main(args=sys.argv[1:])
File "/usr/lib/python3/dist-packages/flask/cli.py", line 601, in main
return super().main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 760, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/decorators.py", line 26, in new_func
return f(get_current_context(), *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 444, in decorator
with __ctx.ensure_object(ScriptInfo).load_app().app_context():
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 407, in load_app
app = locate_app(self, import_name, name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 279, in locate_app
return find_app_by_string(script_info, module, app_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 205, in find_app_by_string
app = call_factory(script_info, attr, args, kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 123, in call_factory
return app_factory(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/build/flask-limiter-lPvBGK/flask-limiter-3.1.0/examples/kitchensink.py", line 44, in app
app.config.from_prefixed_env()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Config' object has no attribute 'from_prefixed_env'
List limits#
$ flask limiter limits
Use the subcommand limits to display all configured limits
$ FLASK_APP=../../examples/kitchensink.py:app flask limiter limits
Traceback (most recent call last):
File "/usr/bin/flask", line 33, in <module>
sys.exit(load_entry_point('Flask==2.0.3', 'console_scripts', 'flask')())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 995, in main
cli.main(args=sys.argv[1:])
File "/usr/lib/python3/dist-packages/flask/cli.py", line 601, in main
return super().main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 760, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/decorators.py", line 26, in new_func
return f(get_current_context(), *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 444, in decorator
with __ctx.ensure_object(ScriptInfo).load_app().app_context():
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 407, in load_app
app = locate_app(self, import_name, name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 279, in locate_app
return find_app_by_string(script_info, module, app_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 205, in find_app_by_string
app = call_factory(script_info, attr, args, kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 123, in call_factory
return app_factory(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/build/flask-limiter-lPvBGK/flask-limiter-3.1.0/examples/kitchensink.py", line 44, in app
app.config.from_prefixed_env()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Config' object has no attribute 'from_prefixed_env'
Filter by endpoint name#
$ FLASK_APP=../../examples/kitchensink.py:app flask limiter limits --endpoint=root
Traceback (most recent call last):
File "/usr/bin/flask", line 33, in <module>
sys.exit(load_entry_point('Flask==2.0.3', 'console_scripts', 'flask')())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 995, in main
cli.main(args=sys.argv[1:])
File "/usr/lib/python3/dist-packages/flask/cli.py", line 601, in main
return super().main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 760, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/decorators.py", line 26, in new_func
return f(get_current_context(), *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 444, in decorator
with __ctx.ensure_object(ScriptInfo).load_app().app_context():
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 407, in load_app
app = locate_app(self, import_name, name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 279, in locate_app
return find_app_by_string(script_info, module, app_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 205, in find_app_by_string
app = call_factory(script_info, attr, args, kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 123, in call_factory
return app_factory(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/build/flask-limiter-lPvBGK/flask-limiter-3.1.0/examples/kitchensink.py", line 44, in app
app.config.from_prefixed_env()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Config' object has no attribute 'from_prefixed_env'
Filter by path#
$ FLASK_APP=../../examples/kitchensink.py:app flask limiter limits --path=/health/
Traceback (most recent call last):
File "/usr/bin/flask", line 33, in <module>
sys.exit(load_entry_point('Flask==2.0.3', 'console_scripts', 'flask')())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 995, in main
cli.main(args=sys.argv[1:])
File "/usr/lib/python3/dist-packages/flask/cli.py", line 601, in main
return super().main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 760, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/decorators.py", line 26, in new_func
return f(get_current_context(), *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 444, in decorator
with __ctx.ensure_object(ScriptInfo).load_app().app_context():
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 407, in load_app
app = locate_app(self, import_name, name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 279, in locate_app
return find_app_by_string(script_info, module, app_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 205, in find_app_by_string
app = call_factory(script_info, attr, args, kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 123, in call_factory
return app_factory(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/build/flask-limiter-lPvBGK/flask-limiter-3.1.0/examples/kitchensink.py", line 44, in app
app.config.from_prefixed_env()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Config' object has no attribute 'from_prefixed_env'
Check limit status#
$ FLASK_APP=../../examples/kitchensink.py:app flask limiter limits --key=127.0.0.1
Traceback (most recent call last):
File "/usr/bin/flask", line 33, in <module>
sys.exit(load_entry_point('Flask==2.0.3', 'console_scripts', 'flask')())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 995, in main
cli.main(args=sys.argv[1:])
File "/usr/lib/python3/dist-packages/flask/cli.py", line 601, in main
return super().main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 760, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/decorators.py", line 26, in new_func
return f(get_current_context(), *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 444, in decorator
with __ctx.ensure_object(ScriptInfo).load_app().app_context():
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 407, in load_app
app = locate_app(self, import_name, name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 279, in locate_app
return find_app_by_string(script_info, module, app_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 205, in find_app_by_string
app = call_factory(script_info, attr, args, kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 123, in call_factory
return app_factory(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/build/flask-limiter-lPvBGK/flask-limiter-3.1.0/examples/kitchensink.py", line 44, in app
app.config.from_prefixed_env()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Config' object has no attribute 'from_prefixed_env'
Clear limits#
$ flask limiter clear
The CLI exposes a subcommand clear that can be used to clear either all limits or limits for specific endpoints or routes by a
key
which represents the value returned by the key_func
(i.e. a specific user)
callable configured for your application.
$ FLASK_APP=../../examples/kitchensink.py:app flask limiter clear --help
Usage: flask limiter clear [OPTIONS]
Clear limits for a specific key
Options:
--endpoint TEXT Endpoint to filter by
--path TEXT Path to filter by
--method TEXT HTTP Method to filter by
--key TEXT Key to reset the limits for [required]
-y Skip prompt for confirmation
--help Show this message and exit.
By default this is an interactive command which requires confirmation, however it can
also be used in automations by using the -y
flag to force confirmation.
$ FLASK_APP=../../examples/kitchensink.py:app flask limiter clear --key=127.0.0.1 -y
Traceback (most recent call last):
File "/usr/bin/flask", line 33, in <module>
sys.exit(load_entry_point('Flask==2.0.3', 'console_scripts', 'flask')())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 995, in main
cli.main(args=sys.argv[1:])
File "/usr/lib/python3/dist-packages/flask/cli.py", line 601, in main
return super().main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/core.py", line 760, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/click/decorators.py", line 26, in new_func
return f(get_current_context(), *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 444, in decorator
with __ctx.ensure_object(ScriptInfo).load_app().app_context():
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 407, in load_app
app = locate_app(self, import_name, name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 279, in locate_app
return find_app_by_string(script_info, module, app_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 205, in find_app_by_string
app = call_factory(script_info, attr, args, kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/flask/cli.py", line 123, in call_factory
return app_factory(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/build/flask-limiter-lPvBGK/flask-limiter-3.1.0/examples/kitchensink.py", line 44, in app
app.config.from_prefixed_env()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Config' object has no attribute 'from_prefixed_env'