fromcherrypy._cperrorimportformat_exc,bare_errorfromcherrypy._cpwsgiimportApplication,HostedWSGIfromcherrypyimportNotFoundfromcherrypy.libimporthttpclassTree:"""A dispatcher of WSGI applications, mounted at diverse points."""def__init__(self):self.apps={}defmount(self,app,script_name="",conf=None,wrap=True):"""Mount a new app at script_name using configuration in conf. An application can be one of: 1) A standard cherrypy.Application - left as is. 2) A "root" object - wrapped in an Application instance. 3) A WSGI callable - optionally wrapped in a HostedWSGI instance. If wrap == True, a WSGI callable will be wrapped in a cherrypy.Application instance, allowing the use of tools with the WSGI application. """# Next line both 1) strips trailing slash and 2) maps "/" -> "".script_name=script_name.rstrip("/")# Leave Application objects aloneifisinstance(app,Application):pass# Handle "root" objects...elifnotcallable(app):app=Application(app,script_name,conf)# Handle WSGI callableselifcallable(app)andwrap:app=Application(HostedWSGI(app),script_name,conf)# In all other cases leave the app intact (no wrapping)self.apps[script_name]=app# If mounted at "", add favicon.icoifscript_name==""andappandnothasattr(app,"favicon_ico"):importosfromcherrypyimporttoolsfavicon=os.path.join(os.getcwd(),os.path.dirname(__file__),"favicon.ico")app.favicon_ico=tools.staticfile.handler(favicon)returnappdefscript_name(self,path=None):"""The script_name of the app at the given path, or None. If path is None, cherrypy.request.path is used. """ifpathisNone:try:importcherrypypath=cherrypy.request.pathexceptAttributeError:returnNonewhileTrue:ifpathinself.apps:returnpathifpath=="":returnNone# Move one node up the tree and try again.path=path[:path.rfind("/")]defurl(self,path,script_name=None):"""Return 'path', prefixed with script_name. If script_name is None, cherrypy.request.path will be used to find a script_name. """ifscript_nameisNone:script_name=self.script_name()ifscript_nameisNone:returnpathfromcherrypy.libimporthttpreturnhttp.urljoin(script_name,path)defdispatch(self,environ,start_response):"""Dispatch to mounted WSGI applications."""script_name=environ.get("SCRIPT_NAME",'').rstrip('/')path_info=environ.get("PATH_INFO",'')mount_points=self.apps.keys()mount_points.sort()mount_points.reverse()formpinmount_points:ifpath_info.startswith(mp):environ['SCRIPT_NAME']=script_name+mpenviron['PATH_INFO']=path_info[len(mp):]app=self.apps[mp]returnapp(environ,start_response)raiseNotFound