Ticket #5222: __init__.py

File __init__.py, 9.3 KB (added by dnordberg@…, 17 years ago)

The patched version of init.py

Line 
1import django
2from optparse import OptionParser
3import os
4import sys
5import textwrap
6
7# For backwards compatibility: get_version() used to be in this module.
8get_version = django.get_version
9
10def find_commands(path):
11 """
12 Given a path to a management directory, return a list of all the command names
13 that are available. Returns an empty list if no commands are defined.
14 """
15 command_dir = os.path.join(path, 'commands')
16 try:
17 return [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')]
18 except OSError:
19 return []
20
21def load_default_commands():
22 """
23 Returns a dictionary of instances of all available Command classes.
24
25 This works by looking for and loading all Python modules in the
26 django.core.management.commands package.
27
28 The dictionary is in the format {name: command_instance}.
29 """
30 return dict([(name, getattr(__import__('django.core.management.commands.%s' % (name), {}, {}, ['Command']), 'Command')()) for name in find_commands(__path__[0])])
31
32def load_project_commands():
33 """
34 Returns a dictionary of instances of all available Command classes.
35
36 It looks for a management.commands package in each installed application
37 -- if a commands package exists, it loads all commands in that
38 application and raises an AttributeError if a command doesn't contain a
39 Command instance.
40
41 The dictionary is in the format {name: command_instance}.
42 """
43
44 commands = {}
45
46 if 'DJANGO_SETTINGS_MODULE' in os.environ:
47 from django.db import models
48
49 # Get commands from all installed apps
50 for app in models.get_apps():
51 try:
52 app_name = '.'.join(app.__name__.split('.')[:-1])
53 path = os.path.join(os.path.dirname(app.__file__),'management')
54 commands.update(dict([(name, getattr(__import__('%s.management.commands.%s' % (app_name, name), {}, {}, ['Command']), 'Command')()) for name in find_commands(path)]))
55 except AttributeError:
56 sys.stderr.write("Management command '%s' in application '%s' doesn't contain a Command instance.\n" % (name, app_name))
57 sys.exit(1)
58
59 return commands
60
61def call_command(name, *args, **options):
62 """
63 Calls the given command, with the given options and args/kwargs.
64
65 This is the primary API you should use for calling specific commands.
66
67 Some examples:
68 call_command('syncdb')
69 call_command('shell', plain=True)
70 call_command('sqlall', 'myapp')
71 """
72 klass = getattr(__import__(_DJANGO_COMMANDS[name].__module__, {}, {}, ['Command']), 'Command')()
73 return klass.execute(*args, **options)
74
75class ManagementUtility(object):
76 """
77 Encapsulates the logic of the django-admin.py and manage.py utilities.
78
79 A ManagementUtility has a number of commands, which can be manipulated
80 by editing the self.commands dictionary.
81 """
82 def __init__(self):
83 self.commands = _DJANGO_COMMANDS
84
85 def usage(self):
86 """
87 Returns a usage string, for use with optparse.
88
89 The string doesn't include the options (e.g., "--verbose"), because
90 optparse puts those in automatically.
91 """
92 usage = ["%prog command [options]\nactions:"]
93 commands = self.commands.items()
94 commands.sort()
95 for name, cmd in commands:
96 usage.append(' %s %s' % (name, cmd.args))
97 usage.extend(textwrap.wrap(cmd.help, initial_indent=' ', subsequent_indent=' '))
98 usage.append('')
99 return '\n'.join(usage[:-1]) # Cut off the last list element, an empty space.
100
101 def execute(self, argv=None):
102 """
103 Parses the given argv from the command line, determines which command
104 to run and runs the command.
105 """
106 if argv is None:
107 argv = sys.argv
108
109 # Create the parser object and parse the command-line args.
110 # TODO: Ideally each Command class would register its own options for
111 # add_option(), but we'd need to figure out how to allow for multiple
112 # Commands using the same options. The optparse library gets in the way
113 # by checking for conflicts:
114 # http://docs.python.org/lib/optparse-conflicts-between-options.html
115 parser = OptionParser(usage=self.usage(), version=get_version())
116 parser.add_option('--settings',
117 help='The Python path to a settings module, e.g. "myproject.settings.main". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.')
118 parser.add_option('--pythonpath',
119 help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".')
120 parser.add_option('--plain', action='store_true', dest='plain',
121 help='When using "shell": Tells Django to use plain Python, not IPython.')
122 parser.add_option('--noinput', action='store_false', dest='interactive', default=True,
123 help='Tells Django to NOT prompt the user for input of any kind.')
124 parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True,
125 help='When using "runserver": Tells Django to NOT use the auto-reloader.')
126 parser.add_option('--format', default='json', dest='format',
127 help='Specifies the output serialization format for fixtures')
128 parser.add_option('--indent', default=None, dest='indent',
129 type='int', help='Specifies the indent level to use when pretty-printing output')
130 parser.add_option('--verbosity', action='store', dest='verbosity', default='1',
131 type='choice', choices=['0', '1', '2'],
132 help='Verbosity level; 0=minimal output, 1=normal output, 2=all output')
133 parser.add_option('--adminmedia', dest='admin_media_path', default='',
134 help='When using "runserver": Specifies the directory from which to serve admin media.')
135 options, args = parser.parse_args(argv[1:])
136
137 # If the 'settings' or 'pythonpath' options were submitted, activate those.
138 if options.settings:
139 os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
140 if options.pythonpath:
141 sys.path.insert(0, options.pythonpath)
142
143 # Run the appropriate command.
144 try:
145 command_name = args[0]
146 except IndexError:
147 sys.stderr.write("Type '%s --help' for usage.\n" % os.path.basename(argv[0]))
148 sys.exit(1)
149 try:
150 command = self.commands[command_name]
151 except KeyError:
152 sys.stderr.write("Unknown command: %r\nType '%s --help' for usage.\n" % (command_name, os.path.basename(argv[0])))
153 sys.exit(1)
154 command.execute(*args[1:], **options.__dict__)
155
156class ProjectManagementUtility(ManagementUtility):
157 """
158 A ManagementUtility that is specific to a particular Django project.
159 As such, its commands are slightly different than those of its parent
160 class.
161
162 In practice, this class represents manage.py, whereas ManagementUtility
163 represents django-admin.py.
164 """
165 def __init__(self, project_directory):
166 super(ProjectManagementUtility, self).__init__()
167
168 # Remove the "startproject" command from self.commands, because
169 # that's a django-admin.py command, not a manage.py command.
170 del self.commands['startproject']
171
172 # Override the startapp command so that it always uses the
173 # project_directory, not the current working directory (which is default).
174 from django.core.management.commands.startapp import ProjectCommand
175 self.commands['startapp'] = ProjectCommand(project_directory)
176
177def setup_environ(settings_mod):
178 """
179 Configure the runtime environment. This can also be used by external
180 scripts wanting to set up a similar environment to manage.py.
181 """
182 # Add this project to sys.path so that it's importable in the conventional
183 # way. For example, if this file (manage.py) lives in a directory
184 # "myproject", this code would add "/path/to/myproject" to sys.path.
185 project_directory, settings_filename = os.path.split(settings_mod.__file__)
186 project_name = os.path.basename(project_directory)
187 settings_name = os.path.splitext(settings_filename)[0]
188 sys.path.append(os.path.join(project_directory, '..'))
189 project_module = __import__(project_name, {}, {}, [''])
190 sys.path.pop()
191
192 # Set DJANGO_SETTINGS_MODULE appropriately.
193 os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name, settings_name)
194
195 # Update default commands with project commands for django internal
196 # webservers and the manage.py utility
197 _DJANGO_COMMANDS.update(load_project_commands())
198
199 return project_directory
200
201def execute_from_command_line(argv=None):
202 """
203 A simple method that runs a ManagementUtility.
204 """
205 utility = ManagementUtility()
206 utility.execute(argv)
207
208def execute_manager(settings_mod, argv=None):
209 """
210 Like execute_from_command_line(), but for use by manage.py, a
211 project-specific django-admin.py utility.
212 """
213 project_directory = setup_environ(settings_mod)
214 utility = ProjectManagementUtility(project_directory)
215 utility.execute(argv)
216
217# Add default commands to a dict
218_DJANGO_COMMANDS = load_default_commands()
219
220# Update default commands with project commands
221# when DJANGO_SETTINGS_MODULE is already set.
222_DJANGO_COMMANDS.update(load_project_commands())
223
Back to Top