1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
|
# -*- coding: utf-8 -*-
import os
import six
import sys
import time
import traceback
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from django.db.backends import utils
from django.utils.six import PY3
from django_extensions.management.shells import import_objects
from django_extensions.management.utils import signalcommand
def use_vi_mode():
editor = os.environ.get('EDITOR')
if not editor:
return False
editor = os.path.basename(editor)
return editor.startswith('vi') or editor.endswith('vim')
class Command(BaseCommand):
help = "Like the 'shell' command but autoloads the models of all installed Django apps."
def add_arguments(self, parser):
super(Command, self).add_arguments(parser)
parser.add_argument(
'--plain', action='store_true', dest='plain',
help='Tells Django to use plain Python, not BPython nor IPython.')
parser.add_argument(
'--bpython', action='store_true', dest='bpython',
help='Tells Django to use BPython, not IPython.')
parser.add_argument(
'--ptpython', action='store_true', dest='ptpython',
help='Tells Django to use PTPython, not IPython.')
parser.add_argument(
'--ptipython', action='store_true', dest='ptipython',
help='Tells Django to use PT-IPython, not IPython.')
parser.add_argument(
'--ipython', action='store_true', dest='ipython',
help='Tells Django to use IPython, not BPython.')
parser.add_argument(
'--notebook', action='store_true', dest='notebook',
help='Tells Django to use IPython Notebook.')
parser.add_argument(
'--kernel', action='store_true', dest='kernel',
help='Tells Django to start an IPython Kernel.')
parser.add_argument('--connection-file', action='store', dest='connection_file',
help='Specifies the connection file to use if using the --kernel option'),
parser.add_argument(
'--use-pythonrc', action='store_true', dest='use_pythonrc',
help='Tells Django to execute PYTHONSTARTUP file '
'(BE CAREFULL WITH THIS!)')
parser.add_argument(
'--print-sql', action='store_true', default=False,
help="Print SQL queries as they're executed")
parser.add_argument(
'--dont-load', action='append', dest='dont_load', default=[],
help='Ignore autoloading of some apps/models. Can be used '
'several times.')
parser.add_argument(
'--quiet-load', action='store_true', default=False,
dest='quiet_load', help='Do not display loaded models messages')
parser.add_argument(
'--vi', action='store_true', default=use_vi_mode(), dest='vi_mode',
help='Load Vi key bindings (for --ptpython and --ptipython)')
parser.add_argument(
'--no-browser', action='store_true', default=False,
dest='no_browser',
help='Don\'t open the notebook in a browser after startup.')
def get_ipython_arguments(self, options):
return getattr(settings, 'IPYTHON_ARGUMENTS', [])
def get_notebook_arguments(self, options):
return getattr(settings, 'NOTEBOOK_ARGUMENTS', [])
@signalcommand
def handle(self, *args, **options):
use_kernel = options.get('kernel', False)
use_notebook = options.get('notebook', False)
use_ipython = options.get('ipython', False)
use_bpython = options.get('bpython', False)
use_plain = options.get('plain', False)
use_ptpython = options.get('ptpython', False)
use_ptipython = options.get('ptipython', False)
use_pythonrc = options.get('use_pythonrc', True)
no_browser = options.get('no_browser', False)
verbosity = int(options.get('verbosity', 1))
print_sql = getattr(settings, 'SHELL_PLUS_PRINT_SQL', False)
if options.get("print_sql", False) or print_sql:
# Code from http://gist.github.com/118990
sqlparse = None
try:
import sqlparse
except ImportError:
pass
class PrintQueryWrapper(utils.CursorDebugWrapper):
def execute(self, sql, params=()):
starttime = time.time()
try:
return self.cursor.execute(sql, params)
finally:
execution_time = time.time() - starttime
raw_sql = self.db.ops.last_executed_query(self.cursor, sql, params)
if sqlparse:
print(sqlparse.format(raw_sql, reindent=True))
else:
print(raw_sql)
print("")
print('Execution time: %.6fs [Database: %s]' % (execution_time, self.db.alias))
print("")
utils.CursorDebugWrapper = PrintQueryWrapper
def get_kernel():
try:
from IPython import release
if release.version_info[0] < 2:
print(self.style.ERROR("--kernel requires at least IPython version 2.0"))
return
from IPython import start_kernel
except ImportError:
return traceback.format_exc()
def run_kernel():
imported_objects = import_objects(options, self.style)
kwargs = dict(
argv=[],
user_ns=imported_objects,
)
connection_file = options.get('connection_file')
if connection_file:
kwargs['connection_file'] = connection_file
start_kernel(**kwargs)
return run_kernel
def get_notebook():
from IPython import release
try:
from notebook.notebookapp import NotebookApp
except ImportError:
try:
from IPython.html.notebookapp import NotebookApp
except ImportError:
if release.version_info[0] >= 3:
raise
try:
from IPython.frontend.html.notebook import notebookapp
NotebookApp = notebookapp.NotebookApp
except ImportError:
return traceback.format_exc()
def install_kernel_spec(app, display_name, ipython_arguments):
"""install an IPython >= 3.0 kernelspec that loads django extensions"""
ksm = app.kernel_spec_manager
try_spec_names = getattr(settings, 'NOTEBOOK_KERNEL_SPEC_NAMES', [
'python3' if PY3 else 'python2',
'python',
])
if isinstance(try_spec_names, six.string_types):
try_spec_names = [try_spec_names]
ks = None
for spec_name in try_spec_names:
try:
ks = ksm.get_kernel_spec(spec_name)
break
except:
continue
if not ks:
raise CommandError("No notebook (Python) kernel specs found")
ks.argv.extend(ipython_arguments)
ks.display_name = display_name
manage_py_dir, manage_py = os.path.split(os.path.realpath(sys.argv[0]))
if manage_py == 'manage.py' and os.path.isdir(manage_py_dir) and manage_py_dir != os.getcwd():
pythonpath = ks.env.get('PYTHONPATH', os.environ.get('PYTHONPATH', ''))
pythonpath = pythonpath.split(':')
if manage_py_dir not in pythonpath:
pythonpath.append(manage_py_dir)
ks.env['PYTHONPATH'] = ':'.join(filter(None, pythonpath))
kernel_dir = os.path.join(ksm.user_kernel_dir, 'django_extensions')
if not os.path.exists(kernel_dir):
os.makedirs(kernel_dir)
with open(os.path.join(kernel_dir, 'kernel.json'), 'w') as f:
f.write(ks.to_json())
def run_notebook():
app = NotebookApp.instance()
# Treat IPYTHON_ARGUMENTS from settings
ipython_arguments = self.get_ipython_arguments(options)
if 'django_extensions.management.notebook_extension' not in ipython_arguments:
ipython_arguments.extend(['--ext', 'django_extensions.management.notebook_extension'])
# Treat NOTEBOOK_ARGUMENTS from settings
notebook_arguments = self.get_notebook_arguments(options)
if no_browser and '--no-browser' not in notebook_arguments:
notebook_arguments.append('--no-browser')
if '--notebook-dir' not in notebook_arguments:
notebook_arguments.extend(['--notebook-dir', '.'])
# IPython < 3 passes through kernel args from notebook CLI
if release.version_info[0] < 3:
notebook_arguments.extend(ipython_arguments)
app.initialize(notebook_arguments)
# IPython >= 3 uses kernelspecs to specify kernel CLI args
if release.version_info[0] >= 3:
display_name = getattr(settings, 'IPYTHON_KERNEL_DISPLAY_NAME', "Django Shell-Plus")
install_kernel_spec(app, display_name, ipython_arguments)
app.start()
return run_notebook
def get_plain():
# Using normal Python shell
import code
imported_objects = import_objects(options, self.style)
try:
# Try activating rlcompleter, because it's handy.
import readline
except ImportError:
pass
else:
# We don't have to wrap the following import in a 'try', because
# we already know 'readline' was imported successfully.
import rlcompleter
readline.set_completer(rlcompleter.Completer(imported_objects).complete)
readline.parse_and_bind("tab:complete")
# We want to honor both $PYTHONSTARTUP and .pythonrc.py, so follow system
# conventions and get $PYTHONSTARTUP first then import user.
if use_pythonrc:
pythonrc = os.environ.get("PYTHONSTARTUP")
if pythonrc and os.path.isfile(pythonrc):
global_ns = {}
with open(pythonrc) as rcfile:
try:
six.exec_(compile(rcfile.read(), pythonrc, 'exec'), global_ns)
imported_objects.update(global_ns)
except NameError:
pass
# This will import .pythonrc.py as a side-effect
try:
import user # NOQA
except ImportError:
pass
def run_plain():
code.interact(local=imported_objects)
return run_plain
def get_bpython():
try:
from bpython import embed
except ImportError:
return traceback.format_exc()
def run_bpython():
imported_objects = import_objects(options, self.style)
embed(imported_objects)
return run_bpython
def get_ipython():
try:
from IPython import start_ipython
def run_ipython():
imported_objects = import_objects(options, self.style)
ipython_arguments = self.get_ipython_arguments(options)
start_ipython(argv=ipython_arguments, user_ns=imported_objects)
return run_ipython
except ImportError:
str_exc = traceback.format_exc()
# IPython < 0.11
# Explicitly pass an empty list as arguments, because otherwise
# IPython would use sys.argv from this script.
# Notebook not supported for IPython < 0.11.
try:
from IPython.Shell import IPShell
except ImportError:
return str_exc + "\n" + traceback.format_exc()
def run_ipython():
imported_objects = import_objects(options, self.style)
shell = IPShell(argv=[], user_ns=imported_objects)
shell.mainloop()
return run_ipython
def get_ptpython():
try:
from ptpython.repl import embed, run_config
except ImportError:
tb = traceback.format_exc()
try: # prompt_toolkit < v0.27
from prompt_toolkit.contrib.repl import embed, run_config
except ImportError:
return tb
def run_ptpython():
imported_objects = import_objects(options, self.style)
history_filename = os.path.expanduser('~/.ptpython_history')
embed(globals=imported_objects, history_filename=history_filename,
vi_mode=options.get('vi_mode', False), configure=run_config)
return run_ptpython
def get_ptipython():
try:
from ptpython.repl import run_config
from ptpython.ipython import embed
except ImportError:
tb = traceback.format_exc()
try: # prompt_toolkit < v0.27
from prompt_toolkit.contrib.repl import run_config
from prompt_toolkit.contrib.ipython import embed
except ImportError:
return tb
def run_ptipython():
imported_objects = import_objects(options, self.style)
history_filename = os.path.expanduser('~/.ptpython_history')
embed(user_ns=imported_objects, history_filename=history_filename,
vi_mode=options.get('vi_mode', False), configure=run_config)
return run_ptipython
def set_application_name():
"""Set the application_name on PostgreSQL connection
Use the fallback_application_name to let the user override
it with PGAPPNAME env variable
http://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-PARAMKEYWORDS # noqa
"""
supported_backends = ['django.db.backends.postgresql_psycopg2']
opt_name = 'fallback_application_name'
default_app_name = 'django_shell'
app_name = default_app_name
dbs = getattr(settings, 'DATABASES', [])
# lookup over all the databases entry
for db in dbs.keys():
if dbs[db]['ENGINE'] in supported_backends:
try:
options = dbs[db]['OPTIONS']
except KeyError:
options = {}
# dot not override a defined value
if opt_name in options.keys():
app_name = dbs[db]['OPTIONS'][opt_name]
else:
dbs[db].setdefault('OPTIONS', {}).update({opt_name: default_app_name})
app_name = default_app_name
return app_name
shells = (
('ptipython', get_ptipython),
('ptpython', get_ptpython),
('bpython', get_bpython),
('ipython', get_ipython),
('plain', get_plain),
)
SETTINGS_SHELL_PLUS = getattr(settings, 'SHELL_PLUS', None)
shell = None
shell_name = "any"
set_application_name()
if use_kernel:
shell = get_kernel()
shell_name = "IPython Kernel"
elif use_notebook:
shell = get_notebook()
shell_name = "IPython Notebook"
elif use_plain:
shell = get_plain()
shell_name = "plain"
elif use_ipython:
shell = get_ipython()
shell_name = "IPython"
elif use_bpython:
shell = get_bpython()
shell_name = "BPython"
elif use_ptpython:
shell = get_ptpython()
shell_name = "ptpython"
elif use_ptipython:
shell = get_ptipython()
shell_name = "ptipython"
elif SETTINGS_SHELL_PLUS:
shell_name = SETTINGS_SHELL_PLUS
shell = dict(shells)[shell_name]()
else:
for shell_name, func in shells:
shell = func()
if callable(shell):
if verbosity > 1:
print(self.style.NOTICE("Using shell %s." % shell_name))
break
if not callable(shell):
if shell:
print(shell)
print(self.style.ERROR("Could not load %s interactive Python environment." % shell_name))
return
shell()
|