From bd41eaac4ef9b8e154558cfa7993f0d46acdb434 Mon Sep 17 00:00:00 2001 From: Matthew Scragg Date: Wed, 22 Jul 2015 12:01:49 -0500 Subject: [PATCH] use app context aware cli, fixes #65 --- realms/__init__.py | 47 ++++++++++++++++++++++++++++++- realms/commands.py | 3 +- realms/modules/auth/commands.py | 4 +-- realms/modules/search/commands.py | 4 +-- 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/realms/__init__.py b/realms/__init__.py index 19160c9..6c6c51a 100644 --- a/realms/__init__.py +++ b/realms/__init__.py @@ -226,6 +226,51 @@ assets.register('main.css', 'css/style.css') -@click.group() +from functools import update_wrapper + +def with_appcontext(f): + """Wraps a callback so that it's guaranteed to be executed with the + script's application context. If callbacks are registered directly + to the ``app.cli`` object then they are wrapped with this function + by default unless it's disabled. + """ + @click.pass_context + def decorator(__ctx, *args, **kwargs): + with create_app().app_context(): + return __ctx.invoke(f, *args, **kwargs) + return update_wrapper(decorator, f) + + +class AppGroup(click.Group): + """This works similar to a regular click :class:`~click.Group` but it + changes the behavior of the :meth:`command` decorator so that it + automatically wraps the functions in :func:`with_appcontext`. + Not to be confused with :class:`FlaskGroup`. + """ + + def command(self, *args, **kwargs): + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it wraps callbacks in :func:`with_appcontext` + unless it's disabled by passing ``with_appcontext=False``. + """ + wrap_for_ctx = kwargs.pop('with_appcontext', True) + + def decorator(f): + if wrap_for_ctx: + f = with_appcontext(f) + return click.Group.command(self, *args, **kwargs)(f) + return decorator + + def group(self, *args, **kwargs): + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it defaults the group class to + :class:`AppGroup`. + """ + kwargs.setdefault('cls', AppGroup) + return click.Group.group(self, *args, **kwargs) + +flask_cli = AppGroup() + +@flask_cli.group() def cli(): pass diff --git a/realms/commands.py b/realms/commands.py index 9593bd0..2139ccd 100644 --- a/realms/commands.py +++ b/realms/commands.py @@ -1,4 +1,4 @@ -from realms import config, create_app, db, __version__, cli +from realms import config, create_app, db, __version__, flask_cli as cli from realms.lib.util import random_string, in_virtualenv, green, yellow, red from subprocess import call, Popen from multiprocessing import cpu_count @@ -13,7 +13,6 @@ import subprocess # called to discover commands in modules app = create_app() - def get_user(): for name in ('SUDO_USER', 'LOGNAME', 'USER', 'LNAME', 'USERNAME'): user = os.environ.get(name) diff --git a/realms/modules/auth/commands.py b/realms/modules/auth/commands.py index c99ce5f..01e7b23 100644 --- a/realms/modules/auth/commands.py +++ b/realms/modules/auth/commands.py @@ -2,9 +2,9 @@ import click from realms.lib.util import random_string from realms.modules.auth.models import User from realms.lib.util import green, red, yellow +from realms import flask_cli - -@click.group(short_help="Auth Module") +@flask_cli.group(short_help="Auth Module") def cli(): pass diff --git a/realms/modules/search/commands.py b/realms/modules/search/commands.py index 9a143f4..f17dd02 100644 --- a/realms/modules/search/commands.py +++ b/realms/modules/search/commands.py @@ -1,10 +1,10 @@ import click -from realms import create_app, search +from realms import create_app, search, flask_cli from realms.modules.wiki.models import Wiki from realms.lib.util import filename_to_cname -@click.group(short_help="Search Module") +@flask_cli.group(short_help="Search Module") def cli(): pass