[Python-modules-commits] [flask-script] 01/06: Import flask-script_2.0.5.orig.tar.gz
Orestis Ioannou
oorestisime-guest at moszumanska.debian.org
Tue Feb 23 09:25:56 UTC 2016
This is an automated email from the git hooks/post-receive script.
oorestisime-guest pushed a commit to branch master
in repository flask-script.
commit 2fc9654cc838e3dc3f527ab8b3aa3f9685e836d0
Author: Orestis Ioannou <orestis at oioannou.com>
Date: Thu Feb 18 05:09:23 2016 +0100
Import flask-script_2.0.5.orig.tar.gz
---
Flask_Script.egg-info/PKG-INFO | 12 +--
Flask_Script.egg-info/SOURCES.txt | 3 -
LICENSE | 1 +
PKG-INFO | 12 +--
README.rst | 8 +-
docs/.DS_Store | Bin 6148 -> 0 bytes
docs/_static/index.zip | Bin 435 -> 0 bytes
docs/conf.py | 2 +-
docs/index.rst | 198 ++++++++++++++++++++++++++++------
flask_script/__init__.py | 217 ++++++++++++++++++--------------------
flask_script/commands.py | 200 ++++++++++++++++++++++-------------
setup.cfg | 8 --
setup.py | 14 ++-
tests.py | 195 +++++++++++++++++++++++-----------
14 files changed, 555 insertions(+), 315 deletions(-)
diff --git a/Flask_Script.egg-info/PKG-INFO b/Flask_Script.egg-info/PKG-INFO
index ab82ad8..6dd2c95 100644
--- a/Flask_Script.egg-info/PKG-INFO
+++ b/Flask_Script.egg-info/PKG-INFO
@@ -1,11 +1,12 @@
Metadata-Version: 1.1
Name: Flask-Script
-Version: 0.6.7
+Version: 2.0.5
Summary: Scripting support for Flask
-Home-page: http://github.com/techniq/flask-script
-Author: Sean Lynch
-Author-email: techniq35 at gmail.com
+Home-page: http://github.com/smurfix/flask-script
+Author: Matthias Urlichs
+Author-email: matthias at urlichs.de
License: BSD
+Download-URL: https://github.com/smurfix/flask-script/tarball/v2.0.3
Description:
Flask-Script
--------------
@@ -20,14 +21,13 @@ Description:
Platform: any
-Classifier: Development Status :: 4 - Beta
+Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
diff --git a/Flask_Script.egg-info/SOURCES.txt b/Flask_Script.egg-info/SOURCES.txt
index 206ff39..2969b97 100644
--- a/Flask_Script.egg-info/SOURCES.txt
+++ b/Flask_Script.egg-info/SOURCES.txt
@@ -1,7 +1,6 @@
LICENSE
MANIFEST.in
README.rst
-setup.cfg
setup.py
tests.py
Flask_Script.egg-info/PKG-INFO
@@ -10,14 +9,12 @@ Flask_Script.egg-info/dependency_links.txt
Flask_Script.egg-info/not-zip-safe
Flask_Script.egg-info/requires.txt
Flask_Script.egg-info/top_level.txt
-docs/.DS_Store
docs/Makefile
docs/conf.py
docs/index.rst
docs/make.bat
docs/_static/flask-script.png
docs/_static/index.html
-docs/_static/index.zip
docs/_themes/README
docs/_themes/flask_theme_support.py
docs/_themes/flask/theme.conf
diff --git a/LICENSE b/LICENSE
index 00199ae..61b4357 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,5 @@
Copyright (c) 2010 by Dan Jacob.
+Copyright (c) 2014 by Matthias Urlichs.
Some rights reserved.
diff --git a/PKG-INFO b/PKG-INFO
index ab82ad8..6dd2c95 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,11 +1,12 @@
Metadata-Version: 1.1
Name: Flask-Script
-Version: 0.6.7
+Version: 2.0.5
Summary: Scripting support for Flask
-Home-page: http://github.com/techniq/flask-script
-Author: Sean Lynch
-Author-email: techniq35 at gmail.com
+Home-page: http://github.com/smurfix/flask-script
+Author: Matthias Urlichs
+Author-email: matthias at urlichs.de
License: BSD
+Download-URL: https://github.com/smurfix/flask-script/tarball/v2.0.3
Description:
Flask-Script
--------------
@@ -20,14 +21,13 @@ Description:
Platform: any
-Classifier: Development Status :: 4 - Beta
+Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
diff --git a/README.rst b/README.rst
index 0db245e..0fbcd2f 100644
--- a/README.rst
+++ b/README.rst
@@ -1,10 +1,10 @@
Flask-Script
==============
-.. image:: https://travis-ci.org/techniq/flask-script.png?branch=master
- :target: https://travis-ci.org/techniq/flask-script
+.. image:: https://travis-ci.org/smurfix/flask-script.png?branch=v2
+ :target: https://travis-ci.org/smurfix/flask-script
-A set of utilities for use with the Flask framework, which provide
+A set of utilities for use with the Flask framework which provide
decorators, classes and helpers for writing your own script commands.
Useful for creating command-line scripts, cronjobs etc outside your
@@ -15,4 +15,4 @@ Resources
---------
- `Documentation <http://flask-script.readthedocs.org>`_
-- `Issue Tracker <http://github.com/techniq/flask-script/issues>`_
+- `Issue Tracker <http://github.com/smurfix/flask-script/issues>`_
diff --git a/docs/.DS_Store b/docs/.DS_Store
deleted file mode 100644
index 2085b9d..0000000
Binary files a/docs/.DS_Store and /dev/null differ
diff --git a/docs/_static/index.zip b/docs/_static/index.zip
deleted file mode 100644
index 8280eab..0000000
Binary files a/docs/_static/index.zip and /dev/null differ
diff --git a/docs/conf.py b/docs/conf.py
index 9c2c161..f664e60 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -96,7 +96,7 @@ html_theme = 'flask_small'
html_theme_options = {
'index_logo': 'flask-script.png',
- 'github_fork': 'techniq/flask-script'
+ 'github_fork': 'smurfix/flask-script'
}
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
diff --git a/docs/index.rst b/docs/index.rst
index e5d7f12..3b47db7 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -38,7 +38,7 @@ Install with **pip** and **easy_install**::
or download the latest version from version control::
- git clone https://github.com/techniq/flask-script.git
+ git clone https://github.com/smurfix/flask-script.git
cd flask-script
python setup.py develop
@@ -49,12 +49,12 @@ Creating and running commands
-----------------------------
The first step is to create a Python module to run your script commands in. You can call it
-anything you like, for our examples we'll call it **manage.py**.
+anything you like, for our examples we'll call it ``manage.py``.
You don't have to place all your commands in the same file; for example, in a larger project
with lots of commands you might want to split them into a number of files with related commands.
-In your **manage.py** file you have to create a ``Manager`` instance. The ``Manager`` class
+In your ``manage.py`` file you have to create a ``Manager`` instance. The ``Manager`` class
keeps track of all the commands and handles how they are called from the command line::
from flask.ext.script import Manager
@@ -78,7 +78,7 @@ The next step is to create and add your commands. There are three methods for cr
* using the ``@command`` decorator
* using the ``@option`` decorator
-To take a very simple example, we want to create a **Hello** command that just prints out "hello world". It
+To take a very simple example, we want to create a ``hello`` command that just prints out "hello world". It
doesn't take any arguments so is very straightforward::
from flask.ext.script import Command
@@ -111,7 +111,7 @@ To get a list of available commands and their descriptions, just run with no com
To get help text for a particular command::
- python manage.py runserver -h
+ python manage.py runserver -?
This will print usage plus the docstring of the ``Command``.
@@ -128,9 +128,9 @@ Commands created this way are run in exactly the same way as those created with
python manage.py hello
> hello
-As with the ``Command`` class, the docstring you use for the function will appear when you run with the **-h** option::
+As with the ``Command`` class, the docstring you use for the function will appear when you run with the ``-?`` or ``--help`` option::
- python manage.py -h
+ python manage.py -?
> Just say hello
Finally, the ``@option`` decorator, again belonging to ``Manager`` can be used when you want more sophisticated
@@ -142,6 +142,32 @@ control over your commands::
The ``@option`` decorator is explained in more detail below.
+*New in version 2.0*
+
+Help was previously available with ``--help`` and ``-h``. This had a couple
+of less-than-ideal consequences, among them the inability to use ``-h`` as
+a shortcut for ``--host`` or similar options.
+
+*New in version 2.0.2*
+
+If you want to restore the original meaning of ``-h``, set your manager's
+``help_args`` attribute to a list of argument strings you want to be
+considered helpful.
+
+ manager = Manager()
+ manager.help_args = ('-h','-?','--help)
+
+You can override this list in sub-commands and -managers::
+
+ def talker(host='localhost'):
+ pass
+ ccmd = ConnectCmd(talker)
+ ccmd.help_args = ('-?','--help)
+ manager.add_command("connect", ccmd)
+ manager.run()
+
+so that ``manager -h`` prints help, while ``manager connect -h fubar.example.com``
+connects to a remote host.
Adding arguments to commands
----------------------------
@@ -204,7 +230,7 @@ Or you can do optional arguments::
@manager.command
def hello(name="Fred")
- print hello, name
+ print "hello", name
These can be called like so::
@@ -216,12 +242,10 @@ alternatively::
> python manage.py hello -n Joe
hello Joe
-There are a couple of important points to note here.
-
-The short-form **-n** is formed from the first letter of the argument, so "name" > "-n". Therefore it's a good idea that your
-optional argument variable names begin with different letters.
+The short form ``-n`` is formed from the first letter of the argument, so "name" > "-n". Therefore it's a good idea for your
+optional argument variable names to begin with different letters.
-The second issue is that the **-h** switch always runs the help text for that command, so avoid arguments starting with the letter "h".
+*New in version 2.0*
Note also that if your optional argument is a boolean, for example::
@@ -301,19 +325,56 @@ Suppose you have this command::
uppercase = app.config.get('USE_UPPERCASE', False)
if uppercase:
name = name.upper()
- print hello, name
+ print "hello", name
You can now run the following::
- > python manage.py hello joe -c dev.cfg
+ > python manage.py -c dev.cfg hello joe
hello JOE
Assuming the ``USE_UPPERCASE`` setting is **True** in your dev.cfg file.
-Notice also that the "config" option is **not** passed to the command.
+Notice also that the "config" option is **not** passed to the command. In
+fact, this usage
+
+ > python manage.py hello joe -c dev.cfg
+
+will show an error message because the ``-c`` option does not belong to the
+``hello`` command.
+
+You can attach same-named options to different levels; this allows you to
+add an option to your app setup code without checking whether it conflicts with
+a command:
+
+ @manager.option('-n', '--name', dest='name', default='joe')
+ @manager.option('-c', '--clue', dest='clue', default='clue')
+ def hello(name,clue):
+ uppercase = app.config.get('USE_UPPERCASE', False)
+ if uppercase:
+ name = name.upper()
+ clue = clue.upper()
+ print "hello {}, get a {}!".format(name,clue)
+
+ > python manage.py -c dev.cfg hello -c cookie -n frank
+ hello FRANK, get a COOKIE!
+
+Note that the destination variables (command arguments, corresponding to
+``dest`` values) must still be different; this is a limitation of Python's
+argument parser.
In order for manager options to work you must pass a factory function, rather than a Flask instance, to your
-``Manager`` constructor. A simple but complete example is available in `this gist <https://gist.github.com/3531881>`_.
+``Manager`` constructor. A simple but complete example is available in `this gist <https://gist.github.com/smurfix/9307618>`_.
+
+*New in version 2.0*
+
+Before version 2, options and command names could be interspersed freely.
+The author decided to discontinue this practice for a number of reasons;
+the problem with the most impact was that it was not possible to do
+
+ > python manage.py connect -d DEST
+ > python manage.py import -d DIR
+
+as these options collided.
Getting user input
------------------
@@ -335,17 +396,20 @@ Getting user input
It then runs like this::
- python manage.py dropdb
- > Are you sure you want to lose all your data ? [N]
+ > python manage.py dropdb
+ Are you sure you want to lose all your data ? [N]
See the :ref:`api` below for details on the various prompt functions.
Default commands
----------------
+runserver
++++++++++
+
**Flask-Script** has a couple of ready commands you can add and customise: ``Server`` and ``Shell``.
-The ``Server`` command runs the **Flask** development server. It takes an optional ``port`` argument (default **5000**)::
+The ``Server`` command runs the **Flask** development server.
from flask.ext.script import Server, Manager
from myapp import create_app
@@ -360,12 +424,32 @@ and then run the command::
python manage.py runserver
-The ``Server`` command has a number of command-line arguments - run ``python manage.py runserver -h`` for details on these. You can redefine the defaults in the constructor::
+The ``Server`` command has a number of command-line arguments - run ``python manage.py runserver -?`` for details on these. You can redefine the defaults in the constructor::
server = Server(host="0.0.0.0", port=9000)
Needless to say the development server is not intended for production use.
+*New in version 2.0.5*
+
+The most common use-case for ``runserver`` is to run a debug server for
+investigating problems. Therefore the default, if it is *not* set in the
+configuration file, is to enable debugging and auto-reloading.
+
+Unfortunately, Flask currently (as of May 2014) defaults to set the DEBUG
+configuration parameter to ``False``. Until this is changed, you can
+safely add ``DEFAULT=None`` to your Flask configuration. Flask-Script's
+``runserver`` will then turn on debugging, but everything else will treat
+it as being turned off.
+
+To prevent misunderstandings -- after all, debug mode is a serious security
+hole --, a warning is printed when Flask-Script treats a ``None`` default
+value as if it were set to ``True``. You can turn on debugging explicitly
+to get rid of this warning.
+
+shell
++++++
+
The ``Shell`` command starts a Python shell. You can pass in a ``make_context`` argument, which must be a ``callable`` returning a ``dict``. By default, this is just a dict returning the your Flask application instance::
from flask.ext.script import Shell, Manager
@@ -392,11 +476,11 @@ There is also a ``shell`` decorator which you can use with a context function::
def make_shell_context():
return dict(app=app, db=db, models=models)
-This enables a **shell** command with the defaults enabled::
+This enables a ``shell`` command with the defaults enabled::
> python manage.py shell
-The default commands **shell** and **runserver** are included by default, with the default options for these commands. If you wish to
+The default commands ``shell`` and ``runserver`` are included by default, with the default options for these commands. If you wish to
replace them with different commands simply override with ``add_command()`` or the decorators. If you pass ``with_default_commands=False``
to the ``Manager`` constructor these commands will not be loaded::
@@ -408,17 +492,39 @@ A Sub-Manager is an instance of ``Manager`` added as a command to another Manage
To create a submanager::
- sub_manager = Manager()
+ def sub_opts(app, **kwargs):
+ pass
+ sub_manager = Manager(sub_opts)
manager = Manager(self.app)
manager.add_command("sub_manager", sub_manager)
-Restrictions
- - A sub-manager does not provide an app instance/factory when created, it defers the calls to it's parent Manager's
- - A sub-manager inhert's the parent Manager's app options (used for the app instance/factory)
- - A sub-manager does not get default commands added to itself (by default)
- - A sub-manager must be added the primary/root ``Manager`` instance via ``add_command(sub_manager)``
- - A sub-manager can be added to another sub-manager as long as the parent sub-manager is added to the primary/root Manager
+If you attach options to the sub_manager, the ``sub_opts`` procedure will
+receive their values. Your application is passed in ``app`` for
+convenience.
+
+If ``sub_opts`` returns a value other than ``None``, this value will replace
+the ``app`` value that's passed on. This way, you can implement a
+sub-manager which replaces the whole app. One use case is to create a
+separate administrative application for improved security::
+
+ def gen_admin(app, **kwargs):
+ from myweb.admin import MyAdminApp
+ ## easiest but possibly incomplete way to copy your settings
+ return MyAdminApp(config=app.config, **kwargs)
+ sub_manager = Manager(gen_admin)
+
+ manager = Manager(MyApp)
+ manager.add_command("admin", sub_manager)
+
+ > python manage.py runserver
+ [ starts your normal server ]
+ > python manage.py admin runserver
+ [ starts an administrative server ]
+
+You can cascade sub-managers, i.e. add one sub-manager to another.
+
+A sub-manager does not get default commands added to itself (by default)
*New in version 0.5.0.*
@@ -486,6 +592,35 @@ The commands will then be available::
populate Populate database with default data
recreate Recreates database tables (same as issuing 'drop' and then 'create')
+Error handling
+--------------
+
+Users do not like to see stack traces, but developers want them for bug reports.
+
+Therefore, ``flask.ext.script.command`` provides an `InvalidCommand` error
+class which is not supposed to print a stack trace when reported.
+
+In your command handler:
+
+ from flask.ext.script.command import InvalidCommand
+
+ [… if some command verification fails …]
+ class MyCommand(Command):
+ def run(self, foo=None,bar=None):
+ if foo and bar:
+ raise InvalidCommand("Options foo and bar are incompatible")
+
+In your main loop:
+
+ try:
+ MyManager().run()
+ except InvalidCommand as err:
+ print(err, file=sys.stderr)
+ sys.exit(1)
+
+This way, you maintain interoperability if some plug-in code supplies
+Flask-Script hooks you'd like to use, or vice versa.
+
Accessing local proxies
-----------------------
@@ -521,5 +656,4 @@ API
.. autofunction:: prompt_choices
.. _Flask: http://flask.pocoo.org
-.. _GitHub: http://github.com/techniq/flask-script
-.. _argparse: http://pypi.python.org/pypi/argparse
+.. _GitHub: http://github.com/smurfix/flask-script
diff --git a/flask_script/__init__.py b/flask_script/__init__.py
index 5a08aea..a80133e 100644
--- a/flask_script/__init__.py
+++ b/flask_script/__init__.py
@@ -5,14 +5,14 @@ import os
import re
import sys
import types
-import inspect
import warnings
+from gettext import gettext as _
import argparse
from flask import Flask
-from ._compat import text_type, iteritems, izip
+from ._compat import iteritems
from .commands import Group, Option, Command, Server, Shell
from .cli import prompt, prompt_pass, prompt_bool, prompt_choices
@@ -34,6 +34,11 @@ try:
except ImportError:
ARGCOMPLETE_IMPORTED = False
+def add_help(parser, help_args):
+ if not help_args:
+ return
+ parser.add_argument(*help_args,
+ action='help', default=argparse.SUPPRESS, help=_('show this help message and exit'))
class Manager(object):
"""
@@ -59,12 +64,13 @@ class Manager(object):
python manage.py print
> hello
- :param app: Flask instance or callable returning a Flask instance.
+ :param app: Flask instance, or callable returning a Flask instance.
:param with_default_commands: load commands **runserver** and **shell**
by default.
:param disable_argcomplete: disable automatic loading of argcomplete.
"""
+ help_args = ('-?','--help')
def __init__(self, app=None, with_default_commands=None, usage=None,
help=None, description=None, disable_argcomplete=False):
@@ -74,54 +80,54 @@ class Manager(object):
self._commands = dict()
self._options = list()
- # Primary/root Manager instance adds default commands by default,
- # Sub-Managers do not
- if with_default_commands or (app and with_default_commands is None):
- self.add_default_commands()
-
self.usage = usage
self.help = help if help is not None else usage
self.description = description if description is not None else usage
self.disable_argcomplete = disable_argcomplete
+ self.with_default_commands = with_default_commands
self.parent = None
def add_default_commands(self):
"""
- Adds the shell and runserver default commands. To override these
+ Adds the shell and runserver default commands. To override these,
simply add your own equivalents using add_command or decorators.
"""
- self.add_command("shell", Shell())
- self.add_command("runserver", Server())
+ if "shell" not in self._commands:
+ self.add_command("shell", Shell())
+ if "runserver" not in self._commands:
+ self.add_command("runserver", Server())
def add_option(self, *args, **kwargs):
"""
- Adds an application-wide option. This is useful if you want to set
- variables applying to the application setup, rather than individual
- commands.
+ Adds a global option. This is useful if you want to set variables
+ applying to the application setup, rather than individual commands.
For this to work, the manager must be initialized with a factory
- function rather than an instance. Otherwise any options you set will
- be ignored.
+ function rather than a Flask instance. Otherwise any options you set
+ will be ignored.
The arguments are then passed to your function, e.g.::
- def create_app(config=None):
+ def create_my_app(config=None):
app = Flask(__name__)
if config:
app.config.from_pyfile(config)
return app
- manager = Manager(create_app)
+ manager = Manager(create_my_app)
manager.add_option("-c", "--config", dest="config", required=False)
+ @manager.command
+ def mycommand(app):
+ app.do_something()
- and are evoked like this::
+ and are invoked like this::
> python manage.py -c dev.cfg mycommand
- Any manager options passed in the command line will not be passed to
+ Any manager options passed on the command line will not be passed to
the command.
Arguments for this function are the same as for the Option class.
@@ -129,33 +135,49 @@ class Manager(object):
self._options.append(Option(*args, **kwargs))
- def create_app(self, **kwargs):
- if self.parent:
- # Sub-manager, defer to parent Manager
- return self.parent.create_app(**kwargs)
+ def __call__(self, app=None, **kwargs):
+ """
+ This procedure is called with the App instance (if this is a
+ sub-Manager) and any options.
- if isinstance(self.app, Flask):
- return self.app
+ If your sub-Manager does not override this, any values for options will get lost.
+ """
+ if app is None:
+ app = self.app
+ if app is None:
+ raise Exception("There is no app here. This is unlikely to work.")
+
+ if isinstance(app, Flask):
+ if kwargs:
+ import warnings
+ warnings.warn("Options will be ignored.")
+ return app
+
+ app = app(**kwargs)
+ self.app = app
+ return app
- return self.app(**kwargs)
+ def create_app(self, *args, **kwargs):
+ warnings.warn("create_app() is deprecated; use __call__().", warnings.DeprecationWarning)
+ return self(*args,**kwargs)
- def create_parser(self, prog, parents=None):
+ def create_parser(self, prog, func_stack=(), parent=None):
"""
Creates an ArgumentParser instance from options returned
- by get_options(), and a subparser for the given command.
+ by get_options(), and subparser for the given commands.
"""
prog = os.path.basename(prog)
+ func_stack=func_stack+(self,)
options_parser = argparse.ArgumentParser(add_help=False)
for option in self.get_options():
options_parser.add_argument(*option.args, **option.kwargs)
- # parser_parents = parents if parents else [option_parser]
- # parser_parents = [options_parser]
-
parser = argparse.ArgumentParser(prog=prog, usage=self.usage,
description=self.description,
- parents=[options_parser])
+ parents=[options_parser],
+ add_help=False)
+ add_help(parser, self.help_args)
self._patch_argparser(parser)
@@ -163,29 +185,28 @@ class Manager(object):
for name, command in self._commands.items():
usage = getattr(command, 'usage', None)
- help = getattr(command, 'help', command.__doc__)
- description = getattr(command, 'description', command.__doc__)
+ help = getattr(command, 'help', None)
+ if help is None: help = command.__doc__
+ description = getattr(command, 'description', None)
+ if description is None: description = command.__doc__
- # Only pass `parents` argument for commands that support it
- try:
- command_parser = command.create_parser(name, parents=[options_parser])
- except TypeError:
- warnings.warn("create_parser for {0} command should accept a `parents` argument".format(name), DeprecationWarning)
- command_parser = command.create_parser(name)
+ command_parser = command.create_parser(name, func_stack=func_stack, parent=self)
subparser = subparsers.add_parser(name, usage=usage, help=help,
description=description,
- parents=[command_parser], add_help=False)
+ parents=[command_parser],
+ add_help=False)
if isinstance(command, Manager):
self._patch_argparser(subparser)
## enable autocomplete only for parent parser when argcomplete is
## imported and it is NOT disabled in constructor
- if parents is None and ARGCOMPLETE_IMPORTED \
+ if parent is None and ARGCOMPLETE_IMPORTED \
and not self.disable_argcomplete:
argcomplete.autocomplete(parser, always_complete_options=True)
+ self.parser = parser
return parser
# def foo(self, app, *args, **kwargs):
@@ -207,9 +228,6 @@ class Manager(object):
parser._parse_known_args = types.MethodType(_parse_known_args, parser)
def get_options(self):
- if self.parent:
- return self.parent._options
-
return self._options
def add_command(self, *args, **kwargs):
@@ -264,44 +282,7 @@ class Manager(object):
"""
- args, varargs, keywords, defaults = inspect.getargspec(func)
-
- options = []
-
- # first arg is always "app" : ignore
-
- defaults = defaults or []
- kwargs = dict(izip(*[reversed(l) for l in (args, defaults)]))
-
- for arg in args:
-
- if arg in kwargs:
-
- default = kwargs[arg]
-
- if isinstance(default, bool):
- options.append(Option('-%s' % arg[0],
- '--%s' % arg,
- action="store_true",
- dest=arg,
- required=False,
- default=default))
- else:
- options.append(Option('-%s' % arg[0],
- '--%s' % arg,
- dest=arg,
- type=text_type,
- required=False,
- default=default))
-
- else:
- options.append(Option(arg, type=text_type))
-
- command = Command()
- command.run = func
- command.__doc__ = func.__doc__
- command.option_list = options
-
+ command = Command(func)
self.add_command(func.__name__, command)
return func
@@ -357,49 +338,57 @@ class Manager(object):
return func
- def handle(self, prog, args=None):
+ def set_defaults(self):
+ if self.with_default_commands is None:
+ self.with_default_commands = self.parent is None
+ if self.with_default_commands:
+ self.add_default_commands()
+ self.with_default_commands = False
+ def handle(self, prog, args=None):
+ self.set_defaults()
app_parser = self.create_parser(prog)
-
+
args = list(args or [])
app_namespace, remaining_args = app_parser.parse_known_args(args)
# get the handle function and remove it from parsed options
kwargs = app_namespace.__dict__
- handle = kwargs.pop('func_handle', None)
- if not handle:
+ func_stack = kwargs.pop('func_stack', None)
+ if not func_stack:
app_parser.error('too few arguments')
- # get only safe config options
- app_config_keys = [action.dest for action in app_parser._actions
- if action.__class__ in safe_actions]
+ last_func = func_stack[-1]
+ if remaining_args and not getattr(last_func, 'capture_all_args', False):
+ app_parser.error('too many arguments')
- # pass only safe app config keys
- app_config = dict((k, v) for k, v in iteritems(kwargs)
- if k in app_config_keys)
+ args = []
+ for handle in func_stack:
- # remove application config keys from handle kwargs
- kwargs = dict((k, v) for k, v in iteritems(kwargs)
- if k not in app_config_keys)
+ # get only safe config options
+ config_keys = [action.dest for action in handle.parser._actions
+ if handle is last_func or action.__class__ in safe_actions]
- # get command from bound handle function (py2.7+)
- command = handle.__self__
- if getattr(command, 'capture_all_args', False):
- positional_args = [remaining_args]
- else:
- if len(remaining_args):
- # raise correct exception
- # FIXME maybe change capture_all_args flag
- app_parser.parse_args(args)
- # sys.exit(2)
- pass
- positional_args = []
-
- app = self.create_app(**app_config)
- # for convience usage in a command
- self.app = app
+ # pass only safe app config keys
+ config = dict((k, v) for k, v in iteritems(kwargs)
+ if k in config_keys)
+
+ # remove application config keys from handle kwargs
+ kwargs = dict((k, v) for k, v in iteritems(kwargs)
+ if k not in config_keys)
+
+ if handle is last_func and getattr(last_func, 'capture_all_args', False):
+ args.append(remaining_args)
+ try:
+ res = handle(*args, **config)
+ except TypeError as err:
+ err.args = ("{}: {}".format(handle,str(err)),)
+ raise
+
+ args = [res]
- return handle(app, *positional_args, **kwargs)
+ assert not kwargs
+ return res
def run(self, commands=None, default_command=None):
"""
diff --git a/flask_script/commands.py b/flask_script/commands.py
index 8cdc538..62477bf 100644
--- a/flask_script/commands.py
+++ b/flask_script/commands.py
@@ -1,22 +1,34 @@
# -*- coding: utf-8 -*-
-from __future__ import absolute_import
+from __future__ import absolute_import,print_function
import os
+import sys
import code
import warnings
import string
+import inspect
import argparse
from flask import _request_ctx_stack
from .cli import prompt, prompt_pass, prompt_bool, prompt_choices
+from ._compat import izip, text_type
class InvalidCommand(Exception):
+ """\
+ This is a generic error for "bad" commands.
+ It is not used in Flask-Script itself, but you should throw
+ this error (or one derived from it) in your command handlers,
+ and your main code should display this error's message without
+ a stack trace.
+
+ This way, we maintain interoperability if some other plug-in code
+ supplies Flask-Script hooks.
+ """
pass
-
class Group(object):
"""
Stores argument groups and mutually exclusive groups for
@@ -90,9 +102,57 @@ class Option(object):
class Command(object):
"""
Base class for creating commands.
+
+ :param func: Initialize this command by introspecting the function.
"""
- option_list = []
+ option_list = ()
+ help_args = None
+
+ def __init__(self, func=None):
+ if func is None:
+ if not self.option_list:
+ self.option_list = []
+ return
+
+ args, varargs, keywords, defaults = inspect.getargspec(func)
+ if inspect.ismethod(func):
+ args = args[1:]
+
+ options = []
+
+ # first arg is always "app" : ignore
+
+ defaults = defaults or []
+ kwargs = dict(izip(*[reversed(l) for l in (args, defaults)]))
+
+ for arg in args:
+
+ if arg in kwargs:
+
+ default = kwargs[arg]
+
+ if isinstance(default, bool):
+ options.append(Option('-%s' % arg[0],
+ '--%s' % arg,
+ action="store_true",
+ dest=arg,
+ required=False,
+ default=default))
+ else:
+ options.append(Option('-%s' % arg[0],
+ '--%s' % arg,
+ dest=arg,
+ type=text_type,
+ required=False,
+ default=default))
+
+ else:
+ options.append(Option(arg, type=text_type))
+
+ self.run = func
+ self.__doc__ = func.__doc__
+ self.option_list = options
@property
def description(self):
@@ -113,8 +173,17 @@ class Command(object):
return self.option_list
def create_parser(self, *args, **kwargs):
-
- parser = argparse.ArgumentParser(*args, **kwargs)
+ func_stack = kwargs.pop('func_stack',())
+ parent = kwargs.pop('parent',None)
+ parser = argparse.ArgumentParser(*args, add_help=False, **kwargs)
+ help_args = self.help_args
+ while help_args is None and parent is not None:
+ help_args = parent.help_args
+ parent = getattr(parent,'parent',None)
+
+ if help_args:
+ from flask_script import add_help
+ add_help(parser,help_args)
... 773 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/flask-script.git
More information about the Python-modules-commits
mailing list