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 ):
148 """ 149 Start interactive shell or run Python script (startfile) in web2py 150 controller environment. appname is formatted like: 151 152 a web2py application name 153 a/c exec the controller c into the application environment 154 """ 155 156 (a, c, f) = parse_path_info(appname) 157 errmsg = 'invalid application name: %s' % appname 158 if not a: 159 die(errmsg) 160 adir = os.path.join('applications', a) 161 if not os.path.exists(adir): 162 if raw_input('application %s does not exist, create (y/n)?' 163 % a).lower() in ['y', 'yes']: 164 os.mkdir(adir) 165 w2p_unpack('welcome.w2p', adir) 166 for subfolder in ['models','views','controllers', 'databases', 167 'modules','cron','errors','sessions', 168 'languages','static','private','uploads']: 169 subpath = os.path.join(adir,subfolder) 170 if not os.path.exists(subpath): 171 os.mkdir(subpath) 172 db = os.path.join(adir,'models/db.py') 173 if os.path.exists(db): 174 fp = open(db,'r') 175 data = fp.read() 176 fp.close() 177 data = data.replace('<your secret key>','sha512:'+web2py_uuid()) 178 fp = open(db,'w') 179 fp.write(data) 180 fp.close() 181 182 if c: 183 import_models = True 184 _env = env(a, c=c, import_models=import_models) 185 if c: 186 cfile = os.path.join('applications', a, 'controllers', c + '.py') 187 if not os.path.isfile(cfile): 188 cfile = os.path.join('applications', a, 'compiled', "controllers_%s_%s.pyc" % (c,f)) 189 if not os.path.isfile(cfile): 190 die(errmsg) 191 else: 192 exec read_pyc(cfile) in _env 193 else: 194 execfile(cfile, _env) 195 196 if f: 197 exec ('print %s()' % f, _env) 198 elif startfile: 199 exec_pythonrc() 200 try: 201 execfile(startfile, _env) 202 except RestrictedError, e: 203 print e.traceback 204 else: 205 if not plain: 206 try: 207 import IPython 208 # following 2 lines fix a problem with IPython; thanks Michael Toomim 209 if '__builtins__' in _env: 210 del _env['__builtins__'] 211 shell = IPython.Shell.IPShell(argv=[], user_ns=_env) 212 shell.mainloop() 213 return 214 except: 215 logger.warning( 216 'import IPython error; use default python shell') 217 try: 218 import readline 219 import rlcompleter 220 except ImportError: 221 pass 222 else: 223 readline.set_completer(rlcompleter.Completer(_env).complete) 224 readline.parse_and_bind('tab:complete') 225 exec_pythonrc() 226 code.interact(local=_env)
227 228
229 -def parse_path_info(path_info):
230 """ 231 Parse path info formatted like a/c/f where c and f are optional 232 and a leading / accepted. 233 Return tuple (a, c, f). If invalid path_info a is set to None. 234 If c or f are omitted they are set to None. 235 """ 236 237 mo = re.match(r'^/?(?P<a>\w+)(/(?P<c>\w+)(/(?P<f>\w+))?)?$', 238 path_info) 239 if mo: 240 return (mo.group('a'), mo.group('c'), mo.group('f')) 241 else: 242 return (None, None, None)
243 244
245 -def die(msg):
246 print >> sys.stderr, msg 247 sys.exit(1)
248 249
250 -def test(testpath, import_models=True, verbose=False):
251 """ 252 Run doctests in web2py environment. testpath is formatted like: 253 254 a tests all controllers in application a 255 a/c tests controller c in application a 256 a/c/f test function f in controller c, application a 257 258 Where a, c and f are application, controller and function names 259 respectively. If the testpath is a file name the file is tested. 260 If a controller is specified models are executed by default. 261 """ 262 263 import doctest 264 if os.path.isfile(testpath): 265 mo = re.match(r'(|.*/)applications/(?P<a>[^/]+)', testpath) 266 if not mo: 267 die('test file is not in application directory: %s' 268 % testpath) 269 a = mo.group('a') 270 c = f = None 271 files = [testpath] 272 else: 273 (a, c, f) = parse_path_info(testpath) 274 errmsg = 'invalid test path: %s' % testpath 275 if not a: 276 die(errmsg) 277 cdir = os.path.join('applications', a, 'controllers') 278 if not os.path.isdir(cdir): 279 die(errmsg) 280 if c: 281 cfile = os.path.join(cdir, c + '.py') 282 if not os.path.isfile(cfile): 283 die(errmsg) 284 files = [cfile] 285 else: 286 files = glob.glob(os.path.join(cdir, '*.py')) 287 for testfile in files: 288 globs = env(a, import_models) 289 ignores = globs.keys() 290 execfile(testfile, globs) 291 292 def doctest_object(name, obj): 293 """doctest obj and enclosed methods and classes.""" 294 295 if type(obj) in (types.FunctionType, types.TypeType, 296 types.ClassType, types.MethodType, 297 types.UnboundMethodType): 298 299 # Reload environment before each test. 300 301 globs = env(a, c=c, f=f, import_models=import_models) 302 execfile(testfile, globs) 303 doctest.run_docstring_examples(obj, globs=globs, 304 name='%s: %s' % (os.path.basename(testfile), 305 name), verbose=verbose) 306 if type(obj) in (types.TypeType, types.ClassType): 307 for attr_name in dir(obj): 308 309 # Execute . operator so decorators are executed. 310 311 o = eval('%s.%s' % (name, attr_name), globs) 312 doctest_object(attr_name, o)
313 314 for (name, obj) in globs.items(): 315 if name not in ignores and (f is None or f == name): 316 doctest_object(name, obj) 317 318
319 -def get_usage():
320 usage = """ 321 %prog [options] pythonfile 322 """ 323 return usage
324 325
326 -def execute_from_command_line(argv=None):
327 if argv is None: 328 argv = sys.argv 329 330 parser = optparse.OptionParser(usage=get_usage()) 331 332 parser.add_option('-S', '--shell', dest='shell', metavar='APPNAME', 333 help='run web2py in interactive shell or IPython(if installed) ' + \ 334 'with specified appname') 335 parser.add_option( 336 '-P', 337 '--plain', 338 action='store_true', 339 default=False, 340 dest='plain', 341 help='only use plain python shell, should be used with --shell option', 342 ) 343 parser.add_option( 344 '-M', 345 '--import_models', 346 action='store_true', 347 default=False, 348 dest='import_models', 349 help='auto import model files, default is False, ' + \ 350 ' should be used with --shell option', 351 ) 352 parser.add_option( 353 '-R', 354 '--run', 355 dest='run', 356 metavar='PYTHON_FILE', 357 default='', 358 help='run PYTHON_FILE in web2py environment, ' + \ 359 'should be used with --shell option', 360 ) 361 362 (options, args) = parser.parse_args(argv[1:]) 363 364 if len(sys.argv) == 1: 365 parser.print_help() 366 sys.exit(0) 367 368 if len(args) > 0: 369 startfile = args[0] 370 else: 371 startfile = '' 372 run(options.shell, options.plain, startfile=startfile)
373 374 375 if __name__ == '__main__': 376 execute_from_command_line() 377