Browse Source

Add Blueprint level cli command registration

Implements #1357.
Adds ability to register click cli commands onto blueprint.
pull/2784/head
Anthony Plunkett 7 years ago
parent
commit
7f473e50c6
  1. 7
      flask/app.py
  2. 13
      flask/blueprints.py
  3. 9
      flask/helpers.py
  4. 46
      tests/test_cli.py

7
flask/app.py

@ -562,13 +562,14 @@ class Flask(_PackageBoundObject):
view_func=self.send_static_file
)
#: The click command line context for this application. Commands
#: Set the name of the cli context for this application. Commands
#: registered here show up in the :command:`flask` command once the
#: application has been discovered. The default commands are
#: provided by Flask itself and can be overridden.
#:
#: This is an instance of a :class:`click.Group` object.
self.cli = cli.AppGroup(self.name)
#: Set the name of the :class:``cli.AppGroup`` instance to allow
#: commands to be registered on the application.
self.cli.name = self.name
@locked_cached_property
def name(self):

13
flask/blueprints.py

@ -118,7 +118,7 @@ class Blueprint(_PackageBoundObject):
def __init__(self, name, import_name, static_folder=None,
static_url_path=None, template_folder=None,
url_prefix=None, subdomain=None, url_defaults=None,
root_path=None):
root_path=None, cli_group=-1):
_PackageBoundObject.__init__(self, import_name, template_folder,
root_path=root_path)
self.name = name
@ -130,6 +130,7 @@ class Blueprint(_PackageBoundObject):
if url_defaults is None:
url_defaults = {}
self.url_values_defaults = url_defaults
self.cli_group = cli_group
def record(self, func):
"""Registers a function that is called when the blueprint is
@ -186,6 +187,16 @@ class Blueprint(_PackageBoundObject):
for deferred in self.deferred_functions:
deferred(state)
cli_resolved_group = options.get('cli_group', self.cli_group)
if cli_resolved_group is None:
app.cli.commands.update(self.cli.commands)
elif cli_resolved_group == -1:
self.cli.name = self.name
app.cli.add_command(self.cli)
else:
self.cli.name = cli_resolved_group
app.cli.add_command(self.cli)
def route(self, rule, **options):
"""Like :meth:`Flask.route` but for a blueprint. The endpoint for the
:func:`url_for` function is prefixed with the name of the blueprint.

9
flask/helpers.py

@ -15,6 +15,7 @@ import sys
import pkgutil
import posixpath
import mimetypes
from . import cli
from time import time
from zlib import adler32
from threading import RLock
@ -887,6 +888,14 @@ class _PackageBoundObject(object):
self._static_folder = None
self._static_url_path = None
#: The click command line context for registration of cli commands
#: on the application and associated blueprints, accessible via the
#: :command:`flask` command once the application has been discovered
#: and blueprints optionally registered.
#:
#: This is an instance of a :class:`click.Group` object.
self.cli = cli.AppGroup()
def _get_static_folder(self):
if self._static_folder is not None:
return os.path.join(self.root_path, self._static_folder)

46
tests/test_cli.py

@ -23,7 +23,7 @@ import pytest
from _pytest.monkeypatch import notset
from click.testing import CliRunner
from flask import Flask, current_app
from flask import Flask, current_app, Blueprint
from flask.cli import (
AppGroup, FlaskGroup, NoAppException, ScriptInfo, dotenv, find_best_app,
get_version, load_dotenv, locate_app, prepare_import, run_command,
@ -539,3 +539,47 @@ def test_run_cert_import(monkeypatch):
with pytest.raises(click.BadParameter):
run_command.make_context(
'run', ['--cert', 'ssl_context', '--key', __file__])
def test_cli_blueprints(app):
"""Test blueprint commands register correctly to the application"""
custom = Blueprint('custom', __name__, cli_group='customized')
nested = Blueprint('nested', __name__)
merged = Blueprint('merged', __name__, cli_group=None)
late = Blueprint('late', __name__)
@custom.cli.command('custom')
def custom_command():
click.echo('custom_result')
@nested.cli.command('nested')
def nested_command():
click.echo('nested_result')
@merged.cli.command('merged')
def merged_command():
click.echo('merged_result')
@late.cli.command('late')
def late_command():
click.echo('late_result')
app.register_blueprint(custom)
app.register_blueprint(nested)
app.register_blueprint(merged)
app.register_blueprint(late, cli_group='late_registration')
app_runner = app.test_cli_runner()
result = app_runner.invoke(args=['customized', 'custom'])
assert 'custom_result' in result.output
result = app_runner.invoke(args=['nested', 'nested'])
assert 'nested_result' in result.output
result = app_runner.invoke(args=['merged'])
assert 'merged_result' in result.output
result = app_runner.invoke(args=['late_registration', 'late'])
assert 'late_result' in result.output

Loading…
Cancel
Save