Skip to content

Commit 28f1a95

Browse files
committed
Use proper argparse subparsers
1 parent 5dc30c6 commit 28f1a95

File tree

2 files changed

+49
-34
lines changed

2 files changed

+49
-34
lines changed

flask_script/__init__.py

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def __init__(self, app=None, with_default_commands=None, usage=None):
5858
if with_default_commands or (app and with_default_commands is None):
5959
self.add_default_commands()
6060

61-
self.usage = usage
61+
self.usage = self.description = usage
6262

6363
self.parent = None
6464

@@ -115,18 +115,29 @@ def create_app(self, **kwargs):
115115

116116
return self.app(**kwargs)
117117

118-
def create_parser(self, prog):
118+
def create_parser(self, prog, parser=None):
119119

120120
"""
121121
Creates an ArgumentParser instance from options returned
122122
by get_options(), and a subparser for the given command.
123123
"""
124-
125124
prog = os.path.basename(prog)
126-
parser = argparse.ArgumentParser(prog=prog)
125+
126+
if parser is None:
127+
parser = argparse.ArgumentParser(prog=prog, usage=self.usage)
128+
129+
#parser.set_defaults(func_handle=self._handle)
130+
127131
for option in self.get_options():
128132
parser.add_argument(*option.args, **option.kwargs)
129133

134+
subparsers = parser.add_subparsers()
135+
for name, command in self._commands.iteritems():
136+
description = getattr(command, 'description',
137+
'Perform command ' + name)
138+
p = subparsers.add_parser(name, help=description, usage=description)
139+
command.create_parser(name, parser=p)
140+
130141
return parser
131142

132143
def get_options(self):
@@ -167,6 +178,7 @@ def command(self, func):
167178
kwargs = dict(zip(*[reversed(l) for l in (args, defaults)]))
168179

169180
for arg in args:
181+
170182
if arg in kwargs:
171183

172184
default = kwargs[arg]
@@ -285,6 +297,14 @@ def print_usage(self):
285297

286298
print self.get_usage()
287299

300+
def _handle(self, app, *args, **kwargs):
301+
"""
302+
Calling manager without command prints usage message.
303+
"""
304+
with app.test_request_context():
305+
self.print_usage()
306+
return 1
307+
288308
def handle(self, prog, name, args=None):
289309

290310
args = list(args or [])
@@ -294,34 +314,26 @@ def handle(self, prog, name, args=None):
294314
except KeyError:
295315
raise InvalidCommand("Command %s not found" % name)
296316

297-
if isinstance(command, Manager):
298-
# Run sub-manager, stripping first argument
299-
sys.argv = sys.argv[1:]
300-
command.run()
301-
else:
302-
help_args = ('-h', '--help')
303-
304-
# remove -h/--help from args if present, and add to remaining args
305-
app_args = [a for a in args if a not in help_args]
317+
app_parser = self.create_parser(prog)
318+
app_namespace, remaining_args = app_parser.parse_known_args([name] + args)
306319

307-
app_parser = self.create_parser(prog)
308-
app_namespace, remaining_args = app_parser.parse_known_args(app_args)
309-
app = self.create_app(**app_namespace.__dict__)
320+
kwargs = app_namespace.__dict__
321+
handle = kwargs['func_handle']
322+
del kwargs['func_handle']
323+
app = self.create_app(**app_namespace.__dict__)
310324

311-
for arg in help_args:
312-
if arg in args:
313-
remaining_args.append(arg)
314-
315-
command_parser = command.create_parser(prog + " " + name)
316-
if getattr(command, 'capture_all_args', False):
317-
command_namespace, unparsed_args = \
318-
command_parser.parse_known_args(remaining_args)
319-
positional_args = [unparsed_args]
320-
else:
321-
command_namespace = command_parser.parse_args(remaining_args)
322-
positional_args = []
323-
324-
return command.handle(app, *positional_args, **command_namespace.__dict__)
325+
# get command from bounded handle function (py2.7+)
326+
command = handle.__self__
327+
if getattr(command, 'capture_all_args', False):
328+
positional_args = [remaining_args]
329+
else:
330+
if len(remaining_args):
331+
# raise correct exception
332+
# FIXME maybe change capture_all_args flag
333+
app_parser.parse_args([name] + args)
334+
# sys.exit(2)
335+
positional_args = []
336+
return handle(app, *positional_args, **kwargs)
325337

326338
def run(self, commands=None, default_command=None):
327339

flask_script/commands.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def __init__(self, *options, **kwargs):
4848
if ((self.title or self.description) and
4949
(self.required or self.exclusive)):
5050
raise TypeError("title and/or description cannot be used with "
51-
"required and/or exclusive.")
51+
"required and/or exclusive.")
5252

5353
super(Group, self).__init__(**kwargs)
5454

@@ -113,9 +113,10 @@ def get_options(self):
113113
"""
114114
return self.option_list
115115

116-
def create_parser(self, prog):
117-
parser = argparse.ArgumentParser(prog=prog,
118-
description=self.description)
116+
def create_parser(self, prog, parser=None):
117+
if parser is None:
118+
parser = argparse.ArgumentParser(prog=prog,
119+
description=self.description)
119120

120121
for option in self.get_options():
121122
if isinstance(option, Group):
@@ -133,6 +134,8 @@ def create_parser(self, prog):
133134
else:
134135
parser.add_argument(*option.args, **option.kwargs)
135136

137+
parser.set_defaults(func_handle=self.handle)
138+
136139
return parser
137140

138141
def handle(self, app, *args, **kwargs):

0 commit comments

Comments
 (0)