Package turbogears :: Module startup

Source Code for Module turbogears.startup

  1  "Things to do when TurboGears is imported." 
  2   
  3  import os 
  4  import errno 
  5  import logging 
  6  import sys 
  7  import time 
  8  import atexit 
  9  import signal 
 10   
 11  import pkg_resources 
 12  import cherrypy 
 13  from cherrypy import _cputil, request, server 
 14  from formencode.variabledecode import NestedVariables 
 15  from cherrypy._cpwsgi import wsgiApp, CPHTTPRequest 
 16  from cherrypy._cpwsgiserver import CherryPyWSGIServer 
 17   
 18  from turbogears import config, scheduler, database 
 19  from turbogears import view 
 20  from turbogears.database import hub_registry, EndTransactionsFilter 
 21   
 22  log = logging.getLogger("turbogears.startup") 
 23   
 24  pkg_resources.require("TurboGears") 
 25   
 26   
27 -def reloader_thread(freq):
28 """Monkeypatch for the reloader provided by CherryPy. 29 30 This reloader is designed to reload a single package. This is 31 more efficient and, more important, compatible with zipped 32 libraries that may not provide access to the individual files.""" 33 34 def archive_selector(module): 35 if hasattr(module, '__loader__'): 36 if hasattr(module.__loader__, 'archive'): 37 return module.__loader__.archive 38 return module
39 40 mtimes = {} 41 package = config.get("autoreload.package", None) 42 if package is None: 43 print \ 44 """TurboGears requires autoreload.package to be set. It can be an empty 45 value, which will use CherryPy's default behavior which is to check 46 every module. Setting an actual package makes the check much faster.""" 47 return 48 while cherrypy.lib.autoreload.RUN_RELOADER: 49 if package: 50 modnames = filter(lambda modname: modname.startswith(package), 51 sys.modules.keys()) 52 modlist = [sys.modules[modname] for modname in modnames] 53 else: 54 modlist = map(archive_selector, sys.modules.values()) 55 for filename in filter(lambda v: v, 56 map(lambda m: getattr(m, "__file__", None), modlist)): 57 if filename.endswith(".kid") or filename == "<string>": 58 continue 59 orig_filename = filename 60 if filename.endswith(".pyc"): 61 filename = filename[:-1] 62 try: 63 mtime = os.stat(filename).st_mtime 64 except OSError, e: 65 if orig_filename.endswith('.pyc') and e[0] == errno.ENOENT: 66 # This prevents us from endlessly restarting 67 # if there is an old .pyc lying around 68 # after a .py file has been deleted 69 try: os.unlink(orig_filename) 70 except: pass 71 sys.exit(3) # force reload 72 if filename not in mtimes: 73 mtimes[filename] = mtime 74 continue 75 if mtime > mtimes[filename]: 76 sys.exit(3) # force reload 77 time.sleep(freq) 78 79 cherrypy.lib.autoreload.reloader_thread = reloader_thread 80 81 webpath = '' 82 83 DNS_SD_PID = None 84 85
86 -def start_bonjour(package=None):
87 global DNS_SD_PID 88 if DNS_SD_PID: 89 return 90 if not getattr(cherrypy, 'root', None): 91 return 92 if not package: 93 package = cherrypy.root.__module__ 94 package = package[:package.find(".")] 95 96 host = config.get('server.socket_host', '') 97 port = str(config.get('server.socket_port')) 98 env = config.get('server.environment') 99 name = package + ": " + env 100 type = "_http._tcp" 101 102 cmds = [['/usr/bin/avahi-publish-service', ["-H", host, name, type, port]], 103 ['/usr/bin/dns-sd', ['-R', name, type, "."+host, port, "path=/"]]] 104 105 for cmd, args in cmds: 106 # TODO:. This check is flawed. If one has both services installed and 107 # avahi isn't the one running, then this won't work. We should either 108 # try registering with both or checking what service is running and use 109 # that. Program availability on the filesystem was never enough... 110 if os.path.exists(cmd): 111 DNS_SD_PID = os.spawnv(os.P_NOWAIT, cmd, [cmd]+args) 112 atexit.register(stop_bonjour) 113 break
114 115
116 -def stop_bonjour():
117 if not DNS_SD_PID: 118 return 119 try: 120 os.kill(DNS_SD_PID, signal.SIGTERM) 121 except OSError: 122 pass
123 124
125 -class VirtualPathFilter(object):
126 """Filter that makes CherryPy ignorant of a URL root path. 127 128 That is, you can mount your app so the URI "/users/~rdel/myapp/" 129 maps to the root object "/". 130 131 """ 132
133 - def __init__(self, webpath=''):
134 webpath = webpath.rstrip('/') 135 if webpath and not webpath.startswith('/'): 136 webpath = '/' + webpath 137 self.webpath = webpath
138
139 - def before_request_body(self):
140 """Determine the relevant path info by stripping of prefixes. 141 142 Strips webpath and SCRIPT_NAME from request.object_path and 143 sets request.path_info (since CherryPy 2 does not set it). 144 145 """ 146 webpath = self.webpath 147 try: 148 webpath += request.wsgi_environ['SCRIPT_NAME'].rstrip('/') 149 except (AttributeError, KeyError): 150 pass 151 if webpath: 152 if request.object_path.startswith(webpath): 153 request.object_path = request.object_path[len(webpath):] or '/' 154 if request.path.startswith(webpath): 155 request.path_info = request.path[len(webpath):] or '/' 156 else: 157 request.path_info = request.path 158 # check for webpath only if not forwarded 159 try: 160 if not request.wsgi_environ['HTTP_X_FORWARDED_SERVER']: 161 raise KeyError 162 except (AttributeError, KeyError): 163 raise cherrypy.NotFound(request.path) 164 else: 165 request.path_info = request.path
166 167
168 -class NestedVariablesFilter(object):
169
170 - def before_main(self):
171 if hasattr(request, 'params'): 172 request.params = NestedVariables.to_python(request.params or {})
173 174
175 -def startTurboGears():
176 """Handles TurboGears tasks when the CherryPy server starts. 177 178 This adds the "tg_js" configuration to make MochiKit accessible. 179 It also turns on stdlib logging when in development mode. 180 181 """ 182 config.update({"/tg_static": 183 { 184 "static_filter.on": True, 185 "static_filter.dir": 186 os.path.abspath(pkg_resources.resource_filename(__name__, "static")), 187 'log_debug_info_filter.on' : False, 188 } 189 }) 190 config.update({"/tg_js" : 191 { 192 "static_filter.on" : True, 193 "static_filter.dir" : 194 os.path.abspath(pkg_resources.resource_filename(__name__, "static/js")), 195 'log_debug_info_filter.on' : False, 196 } 197 }) 198 cherrypy.config.environments['development']['log_debug_info_filter.on'] = False 199 200 if config.get("decoding_filter.on", path="/") is None: 201 config.update({"/": { 202 "decoding_filter.on" : True, 203 "decoding_filter.encoding" : config.get( 204 "kid.encoding", "utf8") 205 }}) 206 207 view.load_engines() 208 view.loadBaseTemplates() 209 global webpath 210 webpath = config.get('server.webpath') or '' 211 212 if getattr(cherrypy, 'root', None): 213 if not hasattr(cherrypy.root, '_cp_filters'): 214 cherrypy.root._cp_filters = [] 215 cherrypy.root._cp_filters.extend([VirtualPathFilter(webpath), 216 EndTransactionsFilter(), NestedVariablesFilter()]) 217 218 webpath = webpath.lstrip('/') 219 if webpath and not webpath.endswith('/'): 220 webpath += '/' 221 222 isdev = config.get('server.environment') == 'development' 223 if not config.get("tg.new_style_logging"): 224 if config.get('server.log_to_screen'): 225 setuplog = logging.getLogger() 226 setuplog.setLevel(logging.DEBUG) 227 fmt = logging.Formatter("%(asctime)s %(name)s " 228 "%(levelname)s %(message)s") 229 handler = logging.StreamHandler(sys.stdout) 230 handler.setLevel(logging.DEBUG) 231 handler.setFormatter(fmt) 232 setuplog.addHandler(handler) 233 234 logfile = config.get("server.log_file") 235 if logfile: 236 setuplog = logging.getLogger("turbogears.access") 237 setuplog.propagate = 0 238 fmt = logging.Formatter("%(message)s") 239 handler = logging.FileHandler(logfile) 240 handler.setLevel(logging.INFO) 241 handler.setFormatter(fmt) 242 setuplog.addHandler(handler) 243 244 bonjoursetting = config.get("tg.bonjour", None) 245 if bonjoursetting or isdev: 246 start_bonjour(bonjoursetting) 247 248 if config.get("sqlalchemy.dburi"): 249 database.get_engine() 250 251 # Start all TurboGears extensions 252 extensions = pkg_resources.iter_entry_points("turbogears.extensions") 253 for entrypoint in extensions: 254 ext = entrypoint.load() 255 if hasattr(ext, "start_extension"): 256 ext.start_extension() 257 258 for item in call_on_startup: 259 item() 260 261 if config.get("tg.scheduler", False): 262 scheduler._start_scheduler() 263 log.info("Scheduler started")
264 265
266 -def stopTurboGears():
267 # end all transactions and clear out the hubs to 268 # help ensure proper reloading in autoreload situations 269 for hub in hub_registry: 270 hub.end() 271 hub_registry.clear() 272 273 stop_bonjour() 274 275 # Shut down all TurboGears extensions 276 extensions= pkg_resources.iter_entry_points( "turbogears.extensions" ) 277 for entrypoint in extensions: 278 ext= entrypoint.load() 279 if hasattr(ext, "shutdown_extension"): 280 ext.shutdown_extension() 281 282 for item in call_on_shutdown: 283 item() 284 285 if config.get("tg.scheduler", False): 286 scheduler._stop_scheduler() 287 log.info("Scheduler stopped")
288 289 290 old_object_trail = _cputil.get_object_trail 291 292 # hang on to object trail to use it to find an app root if need be
293 -def get_object_trail(object_path=None):
294 trail = old_object_trail(object_path) 295 try: 296 request.object_trail = trail 297 except AttributeError: 298 pass 299 return trail
300 301 _cputil.get_object_trail = get_object_trail 302 303
304 -class SimpleWSGIServer(CherryPyWSGIServer):
305 """A WSGI server that accepts a WSGI application as a parameter.""" 306 RequestHandlerClass = CPHTTPRequest 307
308 - def __init__(self):
309 conf = cherrypy.config.get 310 wsgi_app = wsgiApp 311 if conf('server.environment') == 'development': 312 try: 313 from paste.evalexception.middleware import EvalException 314 except ImportError: 315 pass 316 else: 317 wsgi_app = EvalException(wsgi_app, global_conf={}) 318 cherrypy.config.update({'server.throw_errors':True}) 319 bind_addr = (conf('server.socket_host'), conf('server.socket_port')) 320 CherryPyWSGIServer.