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