@TOC
flask中Manager源码如下所示:

class Manager(object): """ Controller class for handling a set of commands. Typical usage:: class Print(Command): def run(self): print "hello" app = Flask(__name__) manager = Manager(app) manager.add_command("print", Print()) if __name__ == "__main__": manager.run() On command line:: python manage.py print > hello

从上面我们我可以看到, 我们定义了一个类继承Command, 并且重写了run方法。就可以在命令行执行了, 也就是说Command为我们提供一个接口, run方法中内容都会被命令行所执行。
那么,现在看下Command又为我们做了什么, 源码如下所示:

class Command(object): """ Base class for creating commands. :param func: Initialize this command by introspecting the function. """ 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): description = self.__doc__ or '' return description.strip() def add_option(self, option): """ Adds Option to option list. """ self.option_list.append(option) def get_options(self): """ By default, returns self.option_list. Override if you need to do instance-specific configuration. """ return self.option_list def create_parser(self, *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) for option in self.get_options(): if isinstance(option, Group): if option.exclusive: group = parser.add_mutually_exclusive_group( required=option.required, ) else: group = parser.add_argument_group( title=option.title, description=option.description, ) for opt in option.get_options(): group.add_argument(*opt.args, **opt.kwargs) else: parser.add_argument(*option.args, **option.kwargs) parser.set_defaults(func_stack=func_stack+(self,)) self.parser = parser self.parent = parent return parser def __call__(self, app=None, *args, **kwargs): """ Handles the command with the given app. Default behaviour is to call ``self.run`` within a test request context. """ with app.test_request_context(): return self.run(*args, **kwargs) def run(self): """ Runs a command. This must be implemented by the subclass. Should take arguments as configured by the Command options. """ raise NotImplementedError

下面分析下执行过程:
1、其他函数是对options[列表]的内容进行增删查操作
2、create_parser函数创建了命令行解析对象parser = argparse.ArgumentParser(*args, add_help=False, **kwargs) ,获取options中获取并保存options中数据和help_args中数据,以及parser.set_defaults(func_stack=func_stack+(self,)) 将Command自己添加到parser中参数中。
3,在flask应用代码中我们添加例如manager.add_command("db", Print())的代码,传入了Command的实例对象, 而add_command创建了Command的实例对象并保存在slef._commands的namespace中或者key_value值中。

备注>>>在flask应用代码中我们添加例如manager.add_command("db", MigrateCommand)的代码,传入了Manager的实例对象MigrateCommand- - - -另外一个Manager对象(此对象,已经添加了添加了迁移等命令, 后面会和当前这个flask应用中manager对象建立关联self.parent)

4,call方法中显示,当Command的实例对象被调用的时候,就会被执行(此时, 引入app实例的上下文, 并执行了run方法)。那么此时,我们就只要去寻找Command实例是何时被调用的

此时Manage对象包装app,并执行了自己的run方法.如下所示.

run方法中通过sys.argv接收了命令行参数,并把参数提交给slef.handle执行。
而handle方法中创建app_parser = self.create_parser(prog)(此函数获取到Commad对象),获取了所有的app_parser的信息(func和 args和config)。

parser什么时候被执行?

此时而app_parser依然是argparse中ArgumentParser对象。
依然是在Manage的create_parser方法中,执行了app_namespace, remaining_args = app_parser.parse_known_args(args), 方法内又调用了_parse_known_args

此处是重点:_parse_known_args中,内部函数consume_optional先调用self._option_string_actions通过string映射action类,另一方面调用了内部函数take_action,创建action的实例对象(如上面Command的实例对象就是此时被创建)。

app_namespace.dict中可以获取到func_stack,
最后遍历for handle in func_stack:,并执行handle, handle可能是Command实例对象,调用后,执行call方法,执行run方法,也可能是func函数,直接被执行。

def run(self, commands=None, default_command=None): """ Prepares manager to receive command line input. Usually run inside "if __name__ == "__main__" block in a Python script. :param commands: optional dict of commands. Appended to any commands added using add_command(). :param default_command: name of default command to run if no arguments passed. """ if commands: self._commands.update(commands) # Make sure all of this is Unicode argv = list(text_type(arg) for arg in sys.argv) if default_command is not None and len(argv) == 1: argv.append(default_command) try: result = self.handle(argv[0], argv[1:]) except SystemExit as e: result = e.code sys.exit(result or 0)