App Engine Python SDK version 1.7.4 (2)
[gae.git] / python / lib / django_1_4 / django / core / management / __init__.py
blob8e8330484d2fe3a1561bf24d808c54cf2e24d048
1 import collections
2 import os
3 import sys
4 from optparse import OptionParser, NO_DEFAULT
5 import imp
6 import warnings
8 from django.core.management.base import BaseCommand, CommandError, handle_default_options
9 from django.core.management.color import color_style
10 from django.utils.importlib import import_module
12 # For backwards compatibility: get_version() used to be in this module.
13 from django import get_version
15 # A cache of loaded commands, so that call_command
16 # doesn't have to reload every time it's called.
17 _commands = None
19 def find_commands(management_dir):
20 """
21 Given a path to a management directory, returns a list of all the command
22 names that are available.
24 Returns an empty list if no commands are defined.
25 """
26 command_dir = os.path.join(management_dir, 'commands')
27 try:
28 return [f[:-3] for f in os.listdir(command_dir)
29 if not f.startswith('_') and f.endswith('.py')]
30 except OSError:
31 return []
33 def find_management_module(app_name):
34 """
35 Determines the path to the management module for the given app_name,
36 without actually importing the application or the management module.
38 Raises ImportError if the management module cannot be found for any reason.
39 """
40 parts = app_name.split('.')
41 parts.append('management')
42 parts.reverse()
43 part = parts.pop()
44 path = None
46 # When using manage.py, the project module is added to the path,
47 # loaded, then removed from the path. This means that
48 # testproject.testapp.models can be loaded in future, even if
49 # testproject isn't in the path. When looking for the management
50 # module, we need look for the case where the project name is part
51 # of the app_name but the project directory itself isn't on the path.
52 try:
53 f, path, descr = imp.find_module(part,path)
54 except ImportError,e:
55 if os.path.basename(os.getcwd()) != part:
56 raise e
58 while parts:
59 part = parts.pop()
60 f, path, descr = imp.find_module(part, path and [path] or None)
61 return path
63 def load_command_class(app_name, name):
64 """
65 Given a command name and an application name, returns the Command
66 class instance. All errors raised by the import process
67 (ImportError, AttributeError) are allowed to propagate.
68 """
69 module = import_module('%s.management.commands.%s' % (app_name, name))
70 return module.Command()
72 def get_commands():
73 """
74 Returns a dictionary mapping command names to their callback applications.
76 This works by looking for a management.commands package in django.core, and
77 in each installed application -- if a commands package exists, all commands
78 in that package are registered.
80 Core commands are always included. If a settings module has been
81 specified, user-defined commands will also be included.
83 The dictionary is in the format {command_name: app_name}. Key-value
84 pairs from this dictionary can then be used in calls to
85 load_command_class(app_name, command_name)
87 If a specific version of a command must be loaded (e.g., with the
88 startapp command), the instantiated module can be placed in the
89 dictionary in place of the application name.
91 The dictionary is cached on the first call and reused on subsequent
92 calls.
93 """
94 global _commands
95 if _commands is None:
96 _commands = dict([(name, 'django.core') for name in find_commands(__path__[0])])
98 # Find the installed apps
99 try:
100 from django.conf import settings
101 apps = settings.INSTALLED_APPS
102 except (AttributeError, EnvironmentError, ImportError):
103 apps = []
105 # Find and load the management module for each installed app.
106 for app_name in apps:
107 try:
108 path = find_management_module(app_name)
109 _commands.update(dict([(name, app_name)
110 for name in find_commands(path)]))
111 except ImportError:
112 pass # No management module - ignore this app
114 return _commands
116 def call_command(name, *args, **options):
118 Calls the given command, with the given options and args/kwargs.
120 This is the primary API you should use for calling specific commands.
122 Some examples:
123 call_command('syncdb')
124 call_command('shell', plain=True)
125 call_command('sqlall', 'myapp')
127 # Load the command object.
128 try:
129 app_name = get_commands()[name]
130 if isinstance(app_name, BaseCommand):
131 # If the command is already loaded, use it directly.
132 klass = app_name
133 else:
134 klass = load_command_class(app_name, name)
135 except KeyError:
136 raise CommandError("Unknown command: %r" % name)
138 # Grab out a list of defaults from the options. optparse does this for us
139 # when the script runs from the command line, but since call_command can
140 # be called programatically, we need to simulate the loading and handling
141 # of defaults (see #10080 for details).
142 defaults = {}
143 for opt in klass.option_list:
144 if opt.default is NO_DEFAULT:
145 defaults[opt.dest] = None
146 else:
147 defaults[opt.dest] = opt.default
148 defaults.update(options)
150 return klass.execute(*args, **defaults)
152 class LaxOptionParser(OptionParser):
154 An option parser that doesn't raise any errors on unknown options.
156 This is needed because the --settings and --pythonpath options affect
157 the commands (and thus the options) that are available to the user.
159 def error(self, msg):
160 pass
162 def print_help(self):
163 """Output nothing.
165 The lax options are included in the normal option parser, so under
166 normal usage, we don't need to print the lax options.
168 pass
170 def print_lax_help(self):
171 """Output the basic options available to every command.
173 This just redirects to the default print_help() behavior.
175 OptionParser.print_help(self)
177 def _process_args(self, largs, rargs, values):
179 Overrides OptionParser._process_args to exclusively handle default
180 options and ignore args and other options.
182 This overrides the behavior of the super class, which stop parsing
183 at the first unrecognized option.
185 while rargs:
186 arg = rargs[0]
187 try:
188 if arg[0:2] == "--" and len(arg) > 2:
189 # process a single long option (possibly with value(s))
190 # the superclass code pops the arg off rargs
191 self._process_long_opt(rargs, values)
192 elif arg[:1] == "-" and len(arg) > 1:
193 # process a cluster of short options (possibly with
194 # value(s) for the last one only)
195 # the superclass code pops the arg off rargs
196 self._process_short_opts(rargs, values)
197 else:
198 # it's either a non-default option or an arg
199 # either way, add it to the args list so we can keep
200 # dealing with options
201 del rargs[0]
202 raise Exception
203 except:
204 largs.append(arg)
206 class ManagementUtility(object):
208 Encapsulates the logic of the django-admin.py and manage.py utilities.
210 A ManagementUtility has a number of commands, which can be manipulated
211 by editing the self.commands dictionary.
213 def __init__(self, argv=None):
214 self.argv = argv or sys.argv[:]
215 self.prog_name = os.path.basename(self.argv[0])
217 def main_help_text(self, commands_only=False):
219 Returns the script's main help text, as a string.
221 if commands_only:
222 usage = sorted(get_commands().keys())
223 else:
224 usage = [
226 "Type '%s help <subcommand>' for help on a specific subcommand." % self.prog_name,
228 "Available subcommands:",
230 commands_dict = collections.defaultdict(lambda: [])
231 for name, app in get_commands().iteritems():
232 if app == 'django.core':
233 app = 'django'
234 else:
235 app = app.rpartition('.')[-1]
236 commands_dict[app].append(name)
237 style = color_style()
238 for app in sorted(commands_dict.keys()):
239 usage.append("")
240 usage.append(style.NOTICE("[%s]" % app))
241 for name in sorted(commands_dict[app]):
242 usage.append(" %s" % name)
243 return '\n'.join(usage)
245 def fetch_command(self, subcommand):
247 Tries to fetch the given subcommand, printing a message with the
248 appropriate command called from the command line (usually
249 "django-admin.py" or "manage.py") if it can't be found.
251 try:
252 app_name = get_commands()[subcommand]
253 except KeyError:
254 sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" % \
255 (subcommand, self.prog_name))
256 sys.exit(1)
257 if isinstance(app_name, BaseCommand):
258 # If the command is already loaded, use it directly.
259 klass = app_name
260 else:
261 klass = load_command_class(app_name, subcommand)
262 return klass
264 def autocomplete(self):
266 Output completion suggestions for BASH.
268 The output of this function is passed to BASH's `COMREPLY` variable and
269 treated as completion suggestions. `COMREPLY` expects a space
270 separated string as the result.
272 The `COMP_WORDS` and `COMP_CWORD` BASH environment variables are used
273 to get information about the cli input. Please refer to the BASH
274 man-page for more information about this variables.
276 Subcommand options are saved as pairs. A pair consists of
277 the long option string (e.g. '--exclude') and a boolean
278 value indicating if the option requires arguments. When printing to
279 stdout, a equal sign is appended to options which require arguments.
281 Note: If debugging this function, it is recommended to write the debug
282 output in a separate file. Otherwise the debug output will be treated
283 and formatted as potential completion suggestions.
285 # Don't complete if user hasn't sourced bash_completion file.
286 if 'DJANGO_AUTO_COMPLETE' not in os.environ:
287 return
289 cwords = os.environ['COMP_WORDS'].split()[1:]
290 cword = int(os.environ['COMP_CWORD'])
292 try:
293 curr = cwords[cword-1]
294 except IndexError:
295 curr = ''
297 subcommands = get_commands().keys() + ['help']
298 options = [('--help', None)]
300 # subcommand
301 if cword == 1:
302 print ' '.join(sorted(filter(lambda x: x.startswith(curr), subcommands)))
303 # subcommand options
304 # special case: the 'help' subcommand has no options
305 elif cwords[0] in subcommands and cwords[0] != 'help':
306 subcommand_cls = self.fetch_command(cwords[0])
307 # special case: 'runfcgi' stores additional options as
308 # 'key=value' pairs
309 if cwords[0] == 'runfcgi':
310 from django.core.servers.fastcgi import FASTCGI_OPTIONS
311 options += [(k, 1) for k in FASTCGI_OPTIONS]
312 # special case: add the names of installed apps to options
313 elif cwords[0] in ('dumpdata', 'reset', 'sql', 'sqlall',
314 'sqlclear', 'sqlcustom', 'sqlindexes',
315 'sqlreset', 'sqlsequencereset', 'test'):
316 try:
317 from django.conf import settings
318 # Get the last part of the dotted path as the app name.
319 options += [(a.split('.')[-1], 0) for a in settings.INSTALLED_APPS]
320 except ImportError:
321 # Fail silently if DJANGO_SETTINGS_MODULE isn't set. The
322 # user will find out once they execute the command.
323 pass
324 options += [(s_opt.get_opt_string(), s_opt.nargs) for s_opt in
325 subcommand_cls.option_list]
326 # filter out previously specified options from available options
327 prev_opts = [x.split('=')[0] for x in cwords[1:cword-1]]
328 options = filter(lambda (x, v): x not in prev_opts, options)
330 # filter options by current input
331 options = sorted([(k, v) for k, v in options if k.startswith(curr)])
332 for option in options:
333 opt_label = option[0]
334 # append '=' to options which require args
335 if option[1]:
336 opt_label += '='
337 print opt_label
338 sys.exit(1)
340 def execute(self):
342 Given the command-line arguments, this figures out which subcommand is
343 being run, creates a parser appropriate to that command, and runs it.
345 # Preprocess options to extract --settings and --pythonpath.
346 # These options could affect the commands that are available, so they
347 # must be processed early.
348 parser = LaxOptionParser(usage="%prog subcommand [options] [args]",
349 version=get_version(),
350 option_list=BaseCommand.option_list)
351 self.autocomplete()
352 try:
353 options, args = parser.parse_args(self.argv)
354 handle_default_options(options)
355 except:
356 pass # Ignore any option errors at this point.
358 try:
359 subcommand = self.argv[1]
360 except IndexError:
361 subcommand = 'help' # Display help if no arguments were given.
363 if subcommand == 'help':
364 if len(args) <= 2:
365 parser.print_lax_help()
366 sys.stdout.write(self.main_help_text() + '\n')
367 elif args[2] == '--commands':
368 sys.stdout.write(self.main_help_text(commands_only=True) + '\n')
369 else:
370 self.fetch_command(args[2]).print_help(self.prog_name, args[2])
371 elif subcommand == 'version':
372 sys.stdout.write(parser.get_version() + '\n')
373 # Special-cases: We want 'django-admin.py --version' and
374 # 'django-admin.py --help' to work, for backwards compatibility.
375 elif self.argv[1:] == ['--version']:
376 # LaxOptionParser already takes care of printing the version.
377 pass
378 elif self.argv[1:] in (['--help'], ['-h']):
379 parser.print_lax_help()
380 sys.stdout.write(self.main_help_text() + '\n')
381 else:
382 self.fetch_command(subcommand).run_from_argv(self.argv)
384 def setup_environ(settings_mod, original_settings_path=None):
386 Configures the runtime environment. This can also be used by external
387 scripts wanting to set up a similar environment to manage.py.
388 Returns the project directory (assuming the passed settings module is
389 directly in the project directory).
391 The "original_settings_path" parameter is optional, but recommended, since
392 trying to work out the original path from the module can be problematic.
394 warnings.warn(
395 "The 'setup_environ' function is deprecated, "
396 "you likely need to update your 'manage.py'; "
397 "please see the Django 1.4 release notes "
398 "(https://docs.djangoproject.com/en/dev/releases/1.4/).",
399 PendingDeprecationWarning)
401 # Add this project to sys.path so that it's importable in the conventional
402 # way. For example, if this file (manage.py) lives in a directory
403 # "myproject", this code would add "/path/to/myproject" to sys.path.
404 if '__init__.py' in settings_mod.__file__:
405 p = os.path.dirname(settings_mod.__file__)
406 else:
407 p = settings_mod.__file__
408 project_directory, settings_filename = os.path.split(p)
409 if project_directory == os.curdir or not project_directory:
410 project_directory = os.getcwd()
411 project_name = os.path.basename(project_directory)
413 # Strip filename suffix to get the module name.
414 settings_name = os.path.splitext(settings_filename)[0]
416 # Strip $py for Jython compiled files (like settings$py.class)
417 if settings_name.endswith("$py"):
418 settings_name = settings_name[:-3]
420 # Set DJANGO_SETTINGS_MODULE appropriately.
421 if original_settings_path:
422 os.environ['DJANGO_SETTINGS_MODULE'] = original_settings_path
423 else:
424 # If DJANGO_SETTINGS_MODULE is already set, use it.
425 os.environ['DJANGO_SETTINGS_MODULE'] = os.environ.get(
426 'DJANGO_SETTINGS_MODULE',
427 '%s.%s' % (project_name, settings_name)
430 # Import the project module. We add the parent directory to PYTHONPATH to
431 # avoid some of the path errors new users can have.
432 sys.path.append(os.path.join(project_directory, os.pardir))
433 import_module(project_name)
434 sys.path.pop()
436 return project_directory
438 def execute_from_command_line(argv=None):
440 A simple method that runs a ManagementUtility.
442 utility = ManagementUtility(argv)
443 utility.execute()
445 def execute_manager(settings_mod, argv=None):
447 Like execute_from_command_line(), but for use by manage.py, a
448 project-specific django-admin.py utility.
450 warnings.warn(
451 "The 'execute_manager' function is deprecated, "
452 "you likely need to update your 'manage.py'; "
453 "please see the Django 1.4 release notes "
454 "(https://docs.djangoproject.com/en/dev/releases/1.4/).",
455 PendingDeprecationWarning)
457 setup_environ(settings_mod)
458 utility = ManagementUtility(argv)
459 utility.execute()