Package web2py :: Package gluon :: Module shell
[hide private]
[frames] | no frames]

Source Code for Module web2py.gluon.shell

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3   
  4  """ 
  5  This file is part of the web2py Web Framework 
  6  Developed by Massimo Di Pierro <mdipierro@cs.depaul.edu>, 
  7  limodou <limodou@gmail.com> and srackham <srackham@gmail.com>. 
  8  License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html) 
  9   
 10  """ 
 11   
 12  import os 
 13  import sys 
 14  import code 
 15  import logging 
 16  import types 
 17  import re 
 18  import optparse 
 19  import glob 
 20   
 21  import fileutils 
 22  import settings 
 23  from utils import web2py_uuid 
 24  from compileapp import build_environment, read_pyc, run_models_in 
 25  from restricted import RestrictedError 
 26  from globals import Request, Response, Session 
 27  from storage import Storage 
 28  from admin import w2p_unpack 
 29   
 30   
 31  logger = logging.getLogger("web2py") 
 32   
33 -def exec_environment( 34 pyfile='', 35 request=None, 36 response=None, 37 session=None, 38 ):
39 """ 40 .. function:: gluon.shell.exec_environment([pyfile=''[, request=Request() 41 [, response=Response[, session=Session()]]]]) 42 43 Environment builder and module loader. 44 45 46 Builds a web2py environment and optionally executes a Python 47 file into the environment. 48 A Storage dictionary containing the resulting environment is returned. 49 The working directory must be web2py root -- this is the web2py default. 50 51 """ 52 53 if request==None: request = Request() 54 if response==None: response = Response() 55 if session==None: session = Session() 56 57 if request.folder is None: 58 mo = re.match(r'(|.*/)applications/(?P<appname>[^/]+)', pyfile) 59 if mo: 60 appname = mo.group('appname') 61 request.folder = os.path.join('applications', appname) 62 else: 63 request.folder = '' 64 env = build_environment(request, response, session, store_current=False) 65 if pyfile: 66 pycfile = pyfile + 'c' 67 if os.path.isfile(pycfile): 68 exec read_pyc(pycfile) in env 69 else: 70 execfile(pyfile, env) 71 return Storage(env)
72 73
74 -def env( 75 a, 76 import_models=False, 77 c=None, 78 f=None, 79 dir='', 80 extra_request={}, 81 ):
82 """ 83 Return web2py execution environment for application (a), controller (c), 84 function (f). 85 If import_models is True the exec all application models into the 86 environment. 87 88 extra_request allows you to pass along any extra 89 variables to the request object before your models 90 get executed. This was mainly done to support 91 web2py_utils.test_runner, however you can use it 92 with any wrapper scripts that need access to the 93 web2py environment. 94 """ 95 96 request = Request() 97 response = Response() 98 session = Session() 99 request.application = a 100 101 # Populate the dummy environment with sensible defaults. 102 103 if not dir: 104 request.folder = os.path.join('applications', a) 105 else: 106 request.folder = dir 107 request.controller = c or 'default' 108 request.function = f or 'index' 109 response.view = '%s/%s.html' % (request.controller, 110 request.function) 111 request.env.path_info = '/%s/%s/%s' % (a, c, f) 112 request.env.http_host = '127.0.0.1:8000' 113 request.env.remote_addr = '127.0.0.1' 114 request.env.web2py_runtime_gae = settings.global_settings.web2py_runtime_gae 115 116 for k,v in extra_request.items(): 117 request[k] = v 118 119 # Monkey patch so credentials checks pass. 120 121 def check_credentials(request, other_application='admin'): 122 return True
123 124 fileutils.check_credentials = check_credentials 125 126 environment = build_environment(request, response, session) 127 128 if import_models: 129 try: 130 run_models_in(environment) 131 except RestrictedError, e: 132 sys.stderr.write(e.traceback+'\n') 133 sys.exit(1) 134 135 environment['__name__'] = '__main__' 136 return environment 137 138
139 -def exec_pythonrc():
140 pythonrc = os.environ.get('PYTHONSTARTUP') 141 if pythonrc and os.path.isfile(pythonrc): 142 try: 143 execfile(pythonrc) 144 except NameError: 145 pass
146 147
148 -def run( 149 appname, 150 plain=False, 151 import_models=False, 152 startfile=None, 153 bpython=False 154 ):
155 """ 156 Start interactive shell or run Python script (startfile) in web2py 157 controller environment. appname is formatted like: 158 159 a web2py application name 160 a/c exec the controller c into the application environment 161 """ 162 163 (a, c, f) = parse_path_info(appname) 164 errmsg = 'invalid application name: %s' % appname 165 if not a: 166 die(errmsg) 167 adir = os.path.join('applications', a) 168 if not os.path.exists(adir): 169 if raw_input('application %s does not exist, create (y/n)?' 170 % a).lower() in ['y', 'yes']: 171 os.mkdir(adir) 172 w2p_unpack('welcome.w2p', adir) 173 for subfolder in ['models','views','controllers', 'databases', 174 'modules','cron','errors','sessions', 175 'languages','static','private','uploads']: 176 subpath = os.path.join(adir,subfolder) 177 if not os.path.exists(subpath): 178 os.mkdir(subpath) 179 db = os.path.join(adir,'models/db.py') 180 if os.path.exists(db): 181 data = fileutils.read_file(db) 182 data = data.replace('<your secret key>','sha512:'+web2py_uuid()) 183 fileutils.write_file(db, data) 184 185 if c: 186 import_models = True 187 _env = env(a, c=c, import_models=import_models) 188 if c: 189 cfile = os.path.join('applications', a, 'controllers', c + '.py') 190 if not os.path.isfile(cfile): 191 cfile = os.path.join('applications', a, 'compiled', "controllers_%s_%s.pyc" % (c,f)) 192 if not os.path.isfile(cfile): 193 die(errmsg) 194 else: 195 exec read_pyc(cfile) in _env 196 else: 197 execfile(cfile, _env) 198 199 if f: 200 exec ('print %s()' % f, _env) 201 elif startfile: 202 exec_pythonrc() 203 try: 204 execfile(startfile, _env) 205 except RestrictedError, e: 206 print e.traceback 207 else: 208 if not plain: 209 if bpython: 210 try: 211 import bpython 212 bpython.embed(locals_=_env) 213 return 214 except: 215 logger.warning( 216 'import bpython error; trying ipython...') 217 else: 218 try: 219 import IPython 220 # following 2 lines fix a problem with IPython; thanks Michael Toomim 221 if '__builtins__' in _env: 222 del _env['__builtins__'] 223 shell = IPython.Shell.IPShell(argv=[], user_ns=_env) 224 shell.mainloop() 225 return 226 except: 227 logger.warning( 228 'import IPython error; use default python shell') 229 try: 230 import readline 231 import rlcompleter 232 except ImportError: 233 pass 234 else: 235 readline.set_completer(rlcompleter.Completer(_env).complete) 236 readline.parse_and_bind('tab:complete') 237 exec_pythonrc() 238 code.interact(local=_env)
239 240
241 -def parse_path_info(path_info):
242 """ 243 Parse path info formatted like a/c/f where c and f are optional 244 and a leading / accepted. 245 Return tuple (a, c, f). If invalid path_info a is set to None. 246 If c or f are omitted they are set to None. 247 """ 248 249 mo = re.match(r'^/?(?P<a>\w+)(/(?P<c>\w+)(/(?P<f>\w+))?)?$', 250 path_info) 251 if mo: 252 return (mo.group('a'), mo.group('c'), mo.group('f')) 253 else: 254 return (None, None, None)
255 256
257 -def die(msg):
258 print >> sys.stderr, msg 259 sys.exit(1)
260 261
262 -def test(testpath, import_models=True, verbose=False):
263 """ 264 Run doctests in web2py environment. testpath is formatted like: 265 266 a tests all controllers in application a 267 a/c tests controller c in application a 268 a/c/f test function f in controller c, application a 269 270 Where a, c and f are application, controller and function names 271 respectively. If the testpath is a file name the file is tested. 272 If a controller is specified models are executed by default. 273 """ 274 275 import doctest 276 if os.path.isfile(testpath): 277 mo = re.match(r'(|.*/)applications/(?P<a>[^/]+)', testpath) 278 if not mo: 279 die('test file is not in application directory: %s' 280 % testpath) 281 a = mo.group('a') 282 c = f = None 283 files = [testpath] 284 else: 285 (a, c, f) = parse_path_info(testpath) 286 errmsg = 'invalid test path: %s' % testpath 287 if not a: 288 die(errmsg) 289 cdir = os.path.join('applications', a, 'controllers') 290 if not os.path.isdir(cdir): 291 die(errmsg) 292 if c: 293 cfile = os.path.join(cdir, c + '.py') 294 if not os.path.isfile(cfile): 295 die(errmsg) 296 files = [cfile] 297 else: 298 files = glob.glob(os.path.join(cdir, '*.py')) 299 for testfile in files: 300 globs = env(a, import_models) 301 ignores = globs.keys() 302 execfile(testfile, globs) 303 304 def doctest_object(name, obj): 305 """doctest obj and enclosed methods and classes.""" 306 307 if type(obj) in (types.FunctionType, types.TypeType, 308 types.ClassType, types.MethodType, 309 types.UnboundMethodType): 310 311 # Reload environment before each test. 312 313 globs = env(a, c=c, f=f, import_models=import_models) 314 execfile(testfile, globs) 315 doctest.run_docstring_examples(obj, globs=globs, 316 name='%s: %s' % (os.path.basename(testfile), 317 name), verbose=verbose) 318 if type(obj) in (types.TypeType, types.ClassType): 319 for attr_name in dir(obj): 320 321 # Execute . operator so decorators are executed. 322 323 o = eval('%s.%s' % (name, attr_name), globs) 324 doctest_object(attr_name, o)
325 326 for (name, obj) in globs.items(): 327 if name not in ignores and (f is None or f == name): 328 doctest_object(name, obj) 329 330
331 -def get_usage():
332 usage = """ 333 %prog [options] pythonfile 334 """ 335 return usage
336 337
338 -def execute_from_command_line(argv=None):
339 if argv is None: 340 argv = sys.argv 341 342 parser = optparse.OptionParser(usage=get_usage()) 343 344 parser.add_option('-S', '--shell', dest='shell', metavar='APPNAME', 345 help='run web2py in interactive shell or IPython(if installed) ' + \ 346 'with specified appname') 347 msg = 'run web2py in interactive shell or bpython (if installed) with' 348 msg += ' specified appname (if app does not exist it will be created).' 349 msg += '\n Use combined with --shell' 350 parser.add_option( 351 '-B', 352 '--bpython', 353 action='store_true', 354 default=False, 355 dest='bpython', 356 help=msg, 357 ) 358 parser.add_option( 359 '-P', 360 '--plain', 361 action='store_true', 362 default=False, 363 dest='plain', 364 help='only use plain python shell, should be used with --shell option', 365 ) 366 parser.add_option( 367 '-M', 368 '--import_models', 369 action='store_true', 370 default=False, 371 dest='import_models', 372 help='auto import model files, default is False, ' + \ 373 ' should be used with --shell option', 374 ) 375 parser.add_option( 376 '-R', 377 '--run', 378 dest='run', 379 metavar='PYTHON_FILE', 380 default='', 381 help='run PYTHON_FILE in web2py environment, ' + \ 382 'should be used with --shell option', 383 ) 384 385 (options, args) = parser.parse_args(argv[1:]) 386 387 if len(sys.argv) == 1: 388 parser.print_help() 389 sys.exit(0) 390 391 if len(args) > 0: 392 startfile = args[0] 393 else: 394 startfile = '' 395 run(options.shell, options.plain, startfile=startfile, bpython=options.bpython)
396 397 398 if __name__ == '__main__': 399 execute_from_command_line() 400