| | |
| | | IRequestFactory, |
| | | ITraverser, |
| | | VH_ROOT_KEY, |
| | | ) |
| | | ) |
| | | |
| | | from pyramid.compat import ( |
| | | PY2, |
| | |
| | | decode_path_info, |
| | | unquote_bytes_to_wsgi, |
| | | lru_cache, |
| | | ) |
| | | ) |
| | | |
| | | from pyramid.encode import url_quote |
| | | from pyramid.exceptions import URLDecodeError |
| | | from pyramid.location import lineage |
| | | from pyramid.threadlocal import get_current_registry |
| | | |
| | | PATH_SEGMENT_SAFE = "~!$&'()*+,;=:@" # from webob |
| | | PATH_SEGMENT_SAFE = "~!$&'()*+,;=:@" # from webob |
| | | PATH_SAFE = PATH_SEGMENT_SAFE + "/" |
| | | |
| | | empty = text_('') |
| | | |
| | | |
| | | def find_root(resource): |
| | | """ Find the root node in the resource tree to which ``resource`` |
| | |
| | | resource = location |
| | | break |
| | | return resource |
| | | |
| | | |
| | | def find_resource(resource, path): |
| | | """ Given a resource object and a string or tuple representing a path |
| | |
| | | raise KeyError('%r has no subelement %s' % (context, view_name)) |
| | | return context |
| | | |
| | | find_model = find_resource # b/w compat (forever) |
| | | |
| | | find_model = find_resource # b/w compat (forever) |
| | | |
| | | |
| | | def find_interface(resource, class_or_interface): |
| | | """ |
| | |
| | | for location in lineage(resource): |
| | | if test(location): |
| | | return location |
| | | |
| | | |
| | | def resource_path(resource, *elements): |
| | | """ Return a string object representing the absolute physical path of the |
| | |
| | | # which caches the joined result for us |
| | | return _join_path_tuple(resource_path_tuple(resource, *elements)) |
| | | |
| | | model_path = resource_path # b/w compat (forever) |
| | | |
| | | model_path = resource_path # b/w compat (forever) |
| | | |
| | | |
| | | def traverse(resource, path): |
| | | """Given a resource object as ``resource`` and a string or tuple |
| | |
| | | |
| | | request_factory = reg.queryUtility(IRequestFactory) |
| | | if request_factory is None: |
| | | from pyramid.request import Request # avoid circdep |
| | | from pyramid.request import Request # avoid circdep |
| | | |
| | | request_factory = Request |
| | | |
| | | request = request_factory.blank(path) |
| | |
| | | traverser = ResourceTreeTraverser(resource) |
| | | |
| | | return traverser(request) |
| | | |
| | | |
| | | def resource_path_tuple(resource, *elements): |
| | | """ |
| | |
| | | """ |
| | | return tuple(_resource_path_list(resource, *elements)) |
| | | |
| | | |
| | | model_path_tuple = resource_path_tuple # b/w compat (forever) |
| | | |
| | | |
| | | def _resource_path_list(resource, *elements): |
| | | """ Implementation detail shared by resource_path and resource_path_tuple""" |
| | |
| | | path.extend(elements) |
| | | return path |
| | | |
| | | _model_path_list = _resource_path_list # b/w compat, not an API |
| | | |
| | | _model_path_list = _resource_path_list # b/w compat, not an API |
| | | |
| | | |
| | | def virtual_root(resource, request): |
| | | """ |
| | |
| | | |
| | | vpath, rpath = url_adapter.virtual_path, url_adapter.physical_path |
| | | if rpath != vpath and rpath.endswith(vpath): |
| | | vroot_path = rpath[:-len(vpath)] |
| | | vroot_path = rpath[: -len(vpath)] |
| | | return find_resource(resource, vroot_path) |
| | | |
| | | try: |
| | | return request.root |
| | | except AttributeError: |
| | | return find_root(resource) |
| | | |
| | | |
| | | def traversal_path(path): |
| | | """ Variant of :func:`pyramid.traversal.traversal_path_info` suitable for |
| | |
| | | # must not possess characters outside ascii |
| | | path = path.encode('ascii') |
| | | # we unquote this path exactly like a PEP 3333 server would |
| | | path = unquote_bytes_to_wsgi(path) # result will be a native string |
| | | return traversal_path_info(path) # result will be a tuple of unicode |
| | | path = unquote_bytes_to_wsgi(path) # result will be a native string |
| | | return traversal_path_info(path) # result will be a tuple of unicode |
| | | |
| | | |
| | | @lru_cache(1000) |
| | | def traversal_path_info(path): |
| | |
| | | applications in :app:`Pyramid`. |
| | | """ |
| | | try: |
| | | path = decode_path_info(path) # result will be Unicode |
| | | path = decode_path_info(path) # result will be Unicode |
| | | except UnicodeDecodeError as e: |
| | | raise URLDecodeError(e.encoding, e.object, e.start, e.end, e.reason) |
| | | return split_path_info(path) # result will be tuple of Unicode |
| | | return split_path_info(path) # result will be tuple of Unicode |
| | | |
| | | |
| | | @lru_cache(1000) |
| | | def split_path_info(path): |
| | |
| | | else: |
| | | clean.append(segment) |
| | | return tuple(clean) |
| | | |
| | | |
| | | _segment_cache = {} |
| | | |
| | |
| | | try: |
| | | return _segment_cache[(segment, safe)] |
| | | except KeyError: |
| | | if segment.__class__ is text_type: #isinstance slighly slower (~15%) |
| | | if ( |
| | | segment.__class__ is text_type |
| | | ): # isinstance slighly slower (~15%) |
| | | result = url_quote(segment.encode('utf-8'), safe) |
| | | else: |
| | | result = url_quote(str(segment), safe) |
| | |
| | | # will generate exactly one Python bytecode (STORE_SUBSCR) |
| | | _segment_cache[(segment, safe)] = result |
| | | return result |
| | | |
| | | |
| | | else: |
| | | |
| | | def quote_path_segment(segment, safe=PATH_SEGMENT_SAFE): |
| | | """ %s """ % quote_path_segment_doc |
| | | # The bit of this code that deals with ``_segment_cache`` is an |
| | |
| | | _segment_cache[(segment, safe)] = result |
| | | return result |
| | | |
| | | |
| | | slash = text_('/') |
| | | |
| | | |
| | | @implementer(ITraverser) |
| | | class ResourceTreeTraverser(object): |
| | |
| | | every resource in the tree supplies a ``__name__`` and |
| | | ``__parent__`` attribute (ie. every resource in the tree is |
| | | :term:`location` aware) .""" |
| | | |
| | | |
| | | VH_ROOT_KEY = VH_ROOT_KEY |
| | | VIEW_SELECTOR = '@@' |
| | |
| | | # if environ['PATH_INFO'] is just not there |
| | | path = slash |
| | | except UnicodeDecodeError as e: |
| | | raise URLDecodeError(e.encoding, e.object, e.start, e.end, |
| | | e.reason) |
| | | raise URLDecodeError( |
| | | e.encoding, e.object, e.start, e.end, e.reason |
| | | ) |
| | | |
| | | if self.VH_ROOT_KEY in environ: |
| | | # HTTP_X_VHM_ROOT |
| | | vroot_path = decode_path_info(environ[self.VH_ROOT_KEY]) |
| | | vroot_tuple = split_path_info(vroot_path) |
| | | vpath = vroot_path + path # both will (must) be unicode or asciistr |
| | | vpath = ( |
| | | vroot_path + path |
| | | ) # both will (must) be unicode or asciistr |
| | | vroot_idx = len(vroot_tuple) - 1 |
| | | else: |
| | | vroot_tuple = () |
| | |
| | | root = self.root |
| | | ob = vroot = root |
| | | |
| | | if vpath == slash: # invariant: vpath must not be empty |
| | | if vpath == slash: # invariant: vpath must not be empty |
| | | # prevent a call to traversal_path if we know it's going |
| | | # to return the empty tuple |
| | | vpath_tuple = () |
| | |
| | | vpath_tuple = split_path_info(vpath) |
| | | for segment in vpath_tuple: |
| | | if segment[:2] == view_selector: |
| | | return {'context': ob, |
| | | 'view_name': segment[2:], |
| | | 'subpath': vpath_tuple[i + 1:], |
| | | 'traversed': vpath_tuple[:vroot_idx + i + 1], |
| | | 'virtual_root': vroot, |
| | | 'virtual_root_path': vroot_tuple, |
| | | 'root': root} |
| | | return { |
| | | 'context': ob, |
| | | 'view_name': segment[2:], |
| | | 'subpath': vpath_tuple[i + 1 :], |
| | | 'traversed': vpath_tuple[: vroot_idx + i + 1], |
| | | 'virtual_root': vroot, |
| | | 'virtual_root_path': vroot_tuple, |
| | | 'root': root, |
| | | } |
| | | try: |
| | | getitem = ob.__getitem__ |
| | | except AttributeError: |
| | | return {'context': ob, |
| | | 'view_name': segment, |
| | | 'subpath': vpath_tuple[i + 1:], |
| | | 'traversed': vpath_tuple[:vroot_idx + i + 1], |
| | | 'virtual_root': vroot, |
| | | 'virtual_root_path': vroot_tuple, |
| | | 'root': root} |
| | | return { |
| | | 'context': ob, |
| | | 'view_name': segment, |
| | | 'subpath': vpath_tuple[i + 1 :], |
| | | 'traversed': vpath_tuple[: vroot_idx + i + 1], |
| | | 'virtual_root': vroot, |
| | | 'virtual_root_path': vroot_tuple, |
| | | 'root': root, |
| | | } |
| | | |
| | | try: |
| | | next = getitem(segment) |
| | | except KeyError: |
| | | return {'context': ob, |
| | | 'view_name': segment, |
| | | 'subpath': vpath_tuple[i + 1:], |
| | | 'traversed': vpath_tuple[:vroot_idx + i + 1], |
| | | 'virtual_root': vroot, |
| | | 'virtual_root_path': vroot_tuple, |
| | | 'root': root} |
| | | return { |
| | | 'context': ob, |
| | | 'view_name': segment, |
| | | 'subpath': vpath_tuple[i + 1 :], |
| | | 'traversed': vpath_tuple[: vroot_idx + i + 1], |
| | | 'virtual_root': vroot, |
| | | 'virtual_root_path': vroot_tuple, |
| | | 'root': root, |
| | | } |
| | | if i == vroot_idx: |
| | | vroot = next |
| | | ob = next |
| | | i += 1 |
| | | |
| | | return {'context':ob, 'view_name':empty, 'subpath':subpath, |
| | | 'traversed':vpath_tuple, 'virtual_root':vroot, |
| | | 'virtual_root_path':vroot_tuple, 'root':root} |
| | | return { |
| | | 'context': ob, |
| | | 'view_name': empty, |
| | | 'subpath': subpath, |
| | | 'traversed': vpath_tuple, |
| | | 'virtual_root': vroot, |
| | | 'virtual_root_path': vroot_tuple, |
| | | 'root': root, |
| | | } |
| | | |
| | | ModelGraphTraverser = ResourceTreeTraverser # b/w compat, not API, used in wild |
| | | |
| | | ModelGraphTraverser = ( |
| | | ResourceTreeTraverser |
| | | ) # b/w compat, not API, used in wild |
| | | |
| | | |
| | | @implementer(IResourceURL) |
| | | class ResourceURL(object): |
| | |
| | | vroot_path_tuple = tuple(vroot_path.split('/')) |
| | | numels = len(vroot_path_tuple) |
| | | virtual_path_tuple = ('',) + physical_path_tuple[numels:] |
| | | virtual_path = physical_path[len(vroot_path):] |
| | | virtual_path = physical_path[len(vroot_path) :] |
| | | |
| | | self.virtual_path = virtual_path # IResourceURL attr |
| | | self.virtual_path = virtual_path # IResourceURL attr |
| | | self.physical_path = physical_path # IResourceURL attr |
| | | self.virtual_path_tuple = virtual_path_tuple # IResourceURL attr (1.5) |
| | | self.physical_path_tuple = physical_path_tuple # IResourceURL attr (1.5) |
| | | self.virtual_path_tuple = virtual_path_tuple # IResourceURL attr (1.5) |
| | | self.physical_path_tuple = ( |
| | | physical_path_tuple |
| | | ) # IResourceURL attr (1.5) |
| | | |
| | | |
| | | @lru_cache(1000) |
| | | def _join_path_tuple(tuple): |
| | | return tuple and '/'.join([quote_path_segment(x) for x in tuple]) or '/' |
| | | |
| | | |
| | | class DefaultRootFactory: |
| | | __parent__ = None |
| | | __name__ = None |
| | | |
| | | def __init__(self, request): |
| | | pass |