Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 786

Show
Ignore:
Timestamp:
11/04/05 16:30:49
Author:
fumanchu
Message:

1. Refactored mapPathToObject to be cleaner and faster.
2. Reinstated positional params on any exposed callable (if we decide to keep denying that, there's a single line to uncomment).
3. Changed _cputil.getObjectTrail to get_object_trail, with a different return value.
4. Removed _cputil.getSpecialAttributePath (not used).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/cherrypy/_cphttptools.py

    r782 r786  
    287287         
    288288        The target method must have an ".exposed = True" attribute. 
    289          
    290289        """ 
    291290         
    292         # Remove leading and trailing slash 
    293         tpath = objectpath.strip("/") 
    294          
    295         if not tpath: 
    296             objectPathList = [] 
    297         else: 
    298             objectPathList = tpath.split('/') 
    299         if objectPathList == ['global']: 
    300             objectPathList = ['global_'] 
    301         objectPathList = ['root'] + objectPathList + ['index'] 
    302          
    303         if getattr(cherrypy, "debug", None): 
    304             cherrypy.log("  Attempting to map path: %s using %s" 
    305                          % (tpath, objectPathList), "DEBUG") 
    306          
    307         # Try successive objects... (and also keep the remaining object list) 
    308         isFirst = True 
    309         isSecond = False 
    310         foundIt = False 
    311         virtualPathList = [] 
    312         while objectPathList: 
    313             if isFirst or isSecond: 
    314                 # Only try this for a.b.index() or a.b() 
    315                 candidate = self.getObjFromPath(objectPathList) 
    316                 if callable(candidate) and getattr(candidate, 'exposed', False): 
    317                     foundIt = True 
    318                     break 
    319             # Couldn't find the object: pop one from the list and try "default" 
    320             lastObj = objectPathList.pop() 
    321             if (not isFirst) or (not tpath): 
    322                 virtualPathList.insert(0, lastObj) 
    323                 objectPathList.append('default') 
    324                 candidate = self.getObjFromPath(objectPathList) 
    325                 if callable(candidate) and getattr(candidate, 'exposed', False): 
    326                     foundIt = True 
    327                     break 
    328                 objectPathList.pop() # Remove "default" 
    329             if isSecond: 
    330                 isSecond = False 
    331             if isFirst: 
    332                 isFirst = False 
    333                 isSecond = True 
    334          
    335         # Check results of traversal 
    336         if not foundIt: 
    337             if tpath.endswith("favicon.ico"): 
    338                 # Use CherryPy's default favicon.ico. If developers really, 
    339                 # really want no favicon, they can make a dummy method 
    340                 # that raises NotFound. 
    341                 icofile = os.path.join(os.path.dirname(__file__), "favicon.ico") 
    342                 cptools.serveFile(icofile) 
    343                 applyFilters('beforeFinalize') 
    344                 cherrypy.response.finalize() 
    345                 raise cherrypy.RequestHandled() 
    346             else: 
    347                 # We didn't find anything 
    348                 if getattr(cherrypy, "debug", None): 
    349                     cherrypy.log("    NOT FOUND", "DEBUG") 
    350                 raise cherrypy.NotFound(objectpath) 
    351          
    352         if isFirst: 
    353             # We found the extra ".index". Check if the original path 
    354             # had a trailing slash (otherwise, do a redirect). 
    355             if not objectpath.endswith('/'): 
    356                 atoms = self.browserUrl.split("?", 1) 
    357                 newUrl = atoms.pop(0) + '/' 
    358                 if atoms: 
    359                     newUrl += "?" + atoms[0] 
    360                 if getattr(cherrypy, "debug", None): 
    361                     cherrypy.log("    Found: redirecting to %s" % newUrl, "DEBUG") 
    362                 raise cherrypy.HTTPRedirect(newUrl) 
    363          
    364         if getattr(cherrypy, "debug", None): 
    365             cherrypy.log("    Found: %s" % candidate, "DEBUG") 
    366         return candidate, objectPathList, virtualPathList 
    367      
    368     def getObjFromPath(self, objPathList): 
    369         """For a given objectPathList, return the object (or None). 
    370          
    371         objPathList should be a list of the form: ['root', 'a', 'b', 'index']. 
    372         """ 
    373          
    374         root = cherrypy 
    375         for objname in objPathList: 
    376             # maps virtual filenames to Python identifiers (substitutes '.' for '_') 
    377             objname = objname.replace('.', '_') 
    378             if getattr(cherrypy, "debug", None): 
    379                 cherrypy.log("    Trying: %s.%s" % (root, objname), "DEBUG") 
    380             root = getattr(root, objname, None) 
    381             if root is None: 
    382                 return None 
    383         return root 
     291        objectTrail = _cputil.get_object_trail(objectpath) 
     292        names = [name for name, candidate in objectTrail] 
     293         
     294        # Try successive objects 
     295        for i in xrange(len(objectTrail) - 1, -1, -1): 
     296             
     297            name, candidate = objectTrail[i] 
     298             
     299            # Try a "default" method on the current leaf. 
     300            defhandler = getattr(candidate, "default", None) 
     301            if callable(defhandler) and getattr(defhandler, 'exposed', False): 
     302                return defhandler, names[:i+1] + ["default"], names[i+1:-1] 
     303             
     304            # Uncomment the next line to restrict positional params to "default". 
     305            # if i < len(objectTrail) - 2: continue 
     306             
     307            # Try the current leaf. 
     308            if callable(candidate) and getattr(candidate, 'exposed', False): 
     309                if i == len(objectTrail) - 1: 
     310                    # We found the extra ".index". Check if the original path 
     311                    # had a trailing slash (otherwise, do a redirect). 
     312                    if not objectpath.endswith('/'): 
     313                        atoms = self.browserUrl.split("?", 1) 
     314                        newUrl = atoms.pop(0) + '/' 
     315                        if atoms: 
     316                            newUrl += "?" + atoms[0] 
     317                        raise cherrypy.HTTPRedirect(newUrl) 
     318                return candidate, names[:i+1], names[i+1:-1] 
     319         
     320        # Not found at any node 
     321        if objectpath.endswith("favicon.ico"): 
     322            # Use CherryPy's default favicon.ico. If developers really, 
     323            # really want no favicon, they can make a dummy method 
     324            # that raises NotFound. 
     325            icofile = os.path.join(os.path.dirname(__file__), "favicon.ico") 
     326            cptools.serveFile(icofile) 
     327            applyFilters('beforeFinalize') 
     328            cherrypy.response.finalize() 
     329            raise cherrypy.RequestHandled() 
     330        else: 
     331            # We didn't find anything 
     332            raise cherrypy.NotFound(objectpath) 
    384333 
    385334 
     
    432381        code, reason, _ = cptools.validStatus(self.status) 
    433382        self.status = "%s %s" % (code, reason) 
    434          
    435         if self.body is None: 
    436             self.body = [] 
    437383         
    438384        stream = cherrypy.config.get("streamResponse", False) 
  • trunk/cherrypy/_cputil.py

    r771 r786  
    1515 
    1616 
    17 def getObjectTrail(): 
    18     """ Return all objects from the currenct object to cherrypy """ 
    19     root = getattr(cherrypy, 'root', None) 
    20     if root: 
    21         objectTrail = [root] 
    22         # Try object path 
    23         try: 
    24             path = cherrypy.request.objectPath 
     17def get_object_trail(objectpath=None): 
     18    """ 
     19    List of (name, object) pairs, from cherrypy.root to the current object. 
     20     
     21    If any named objects are unreachable, (name, None) pairs are used. 
     22    """ 
     23     
     24    if objectpath is None: 
     25        try: 
     26            objectpath = cherrypy.request.objectPath 
    2527        except AttributeError: 
    26             path = '/' 
    27         if path: 
    28             pathList = path.split('/')[1:] 
    29              
    30             # Successively get objects from the path 
    31             for newObj in pathList: 
    32                 try: 
    33                     root = getattr(root, newObj) 
    34                     objectTrail.append(root) 
    35                 except AttributeError: 
    36                     break 
    37          
    38         return objectTrail 
    39     return None 
     28            pass 
     29     
     30    if objectpath is not None: 
     31        objectpath = objectpath.strip('/') 
     32     
     33    # Convert the objectpath into a list of names 
     34    if not objectpath: 
     35        nameList = [] 
     36    else: 
     37        nameList = objectpath.split('/') 
     38    if nameList == ['global']: 
     39        nameList = ['global_'] 
     40    nameList = ['root'] + nameList + ['index'] 
     41     
     42    # Convert the list of names into a list of objects 
     43    node = cherrypy 
     44    objectTrail = [] 
     45    for objname in nameList: 
     46        # maps virtual names to Python identifiers (replaces '.' with '_') 
     47        objname = objname.replace('.', '_') 
     48        node = getattr(node, objname, None) 
     49        objectTrail.append((objname, node)) 
     50     
     51    return objectTrail 
    4052 
    4153def getSpecialAttribute(name): 
     
    4456    _cpFilterList.""" 
    4557     
    46     # First, we look in the right-most object if this special attribute is implemented. 
    47     # If not, then we try the previous object and so on until we reach cherrypy.root 
    48     # If it's still not there, we use the implementation from this module. 
    49      
    50     objectList = getObjectTrail() 
    51     if objectList: 
    52          
    53         objectList.reverse() 
    54         for obj in objectList: 
    55             attr = getattr(obj, name, None) 
    56             if attr != None: 
    57                 return attr 
     58    # First, we look in the right-most object to see if this special 
     59    # attribute is implemented. If not, then we try the previous object, 
     60    # and so on until we reach cherrypy.root. If it's still not there, 
     61    # we use the implementation from this module. 
     62     
     63    objectList = get_object_trail() 
     64    objectList.reverse() 
     65    for objname, obj in objectList: 
     66        if hasattr(obj, name): 
     67            return getattr(obj, name) 
    5868     
    5969    try: 
     
    6272        msg = "Special attribute %s could not be found" % repr(name) 
    6373        raise cherrypy.HTTPError(500, msg) 
    64  
    65 def getSpecialAttributePath(name): 
    66     """ Return the path to the special attribute """ 
    67     objectList = getObjectTrail() 
    68     if objectList: 
    69         pathList = cherrypy.request.objectPath 
    70         pathList = pathList.split("/")[1:] 
    71         for i in xrange(len(objectList) - 1, -1, -1): 
    72             if hasattr(objectList[i], name): 
    73                 return "/" + "/".join(pathList[:i] + [name]) 
    74     msg = "Special attribute %s could not be found" % repr(name) 
    75     raise cherrypy.HTTPError(500, msg) 
    76  
    7774 
    7875def logtime(): 
  • trunk/cherrypy/test/test_objectmapping.py

    r778 r786  
    7373        return "method for dir2" 
    7474    method.exposed = True 
     75     
     76    def posparam(self, *vpath): 
     77        return "/".join(vpath) 
     78    posparam.exposed = True 
    7579 
    7680 
     
    112116         
    113117        self.getPage("/extra/too/much") 
    114         self.assertBody("default:('extra', 'too', 'much')") 
     118        self.assertBody("('too', 'much')") 
    115119         
    116120        self.getPage("/other") 
     
    130134        self.getPage("/dir1/dir2/dir3/dir4/index") 
    131135        self.assertBody("default for dir1, param is:('dir2', 'dir3', 'dir4', 'index')") 
     136         
     137        # Test positional parameters 
     138        self.getPage("/dir1/dir2/posparam/18/24/hut/hike") 
     139        self.assertBody("18/24/hut/hike") 
    132140         
    133141        self.getPage("/redirect") 

Hosted by WebFaction

Log in as guest/cpguest to create tickets