diff options
Diffstat (limited to 'flup/resolver/objectpath.py')
-rw-r--r-- | flup/resolver/objectpath.py | 156 |
1 files changed, 0 insertions, 156 deletions
diff --git a/flup/resolver/objectpath.py b/flup/resolver/objectpath.py deleted file mode 100644 index 94e5558..0000000 --- a/flup/resolver/objectpath.py +++ /dev/null @@ -1,156 +0,0 @@ -# Copyright (c) 2005 Allan Saddi <allan@saddi.com> -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# $Id$ - -__author__ = 'Allan Saddi <allan@saddi.com>' -__version__ = '$Revision$' - -import re - -from flup.resolver.resolver import * - -__all__ = ['ObjectPathResolver', 'expose'] - -class NoDefault(object): - pass - -class ObjectPathResolver(Resolver): - """ - Inspired by CherryPy <http://www.cherrypy.org/>. :) For an explanation - of how this works, see the excellent tutorial at - <http://www.cherrypy.org/wiki/CherryPyTutorial>. We support the index and - default methods, though the calling convention for the default method - is different - we do not pass PATH_INFO as positional arguments. (It - is passed through the request/environ as normal.) - - Also, we explicitly block certain function names. See below. I don't - know if theres really any harm in letting those attributes be followed, - but I'd rather not take the chance. And unfortunately, this solution - is pretty half-baked as well (I'd rather only allow certain object - types to be traversed, rather than disallow based on names.) Better - than nothing though... - """ - index_page = 'index' - default_page = 'default' - - def __init__(self, root, index=NoDefault, default=NoDefault, - favorIndex=True): - """ - root is the root object of your URL hierarchy. In CherryPy, this - would be cpg.root. - - When the last component of a path has an index method and some - object along the path has a default method, favorIndex determines - which method is called when the URL has a trailing slash. If - True, the index method will be called. Otherwise, the default method. - """ - self.root = root - if index is not NoDefault: - self.index_page = index - if default is not NoDefault: - self.default_page = default - self._favorIndex = favorIndex - - # Certain names should be disallowed for safety. If one of your pages - # is showing up unexpectedly as a 404, make sure the function name doesn't - # begin with one of these prefixes. - _disallowed = re.compile(r'''(?:_|im_|func_|tb_|f_|co_).*''') - - def _exposed(self, obj, redirect): - # If redirecting, allow non-exposed objects as well. - return callable(obj) and (getattr(obj, 'exposed', False) or redirect) - - def resolve(self, request, redirect=False): - path_info = request.pathInfo.split(';')[0] - path_info = path_info.split('/') - - assert len(path_info) > 0 - assert not path_info[0] - - current = self.root - current_default = None - i = 0 - for i in range(1, len(path_info)): - component = path_info[i] - - # See if we have an index page (needed for index/default - # disambiguation, unfortunately). - current_index = None - if self.index_page: - current_index = getattr(current, self.index_page, None) - if not self._exposed(current_index, redirect): - current_index = None - - if self.default_page: - # Remember the last default page we've seen. - new_default = getattr(current, self.default_page, None) - if self._exposed(new_default, redirect): - current_default = (i - 1, new_default) - - # Test for trailing slash. - if not component and current_index is not None and \ - (self._favorIndex or current_default is None): - # Breaking out of the loop here favors index over default. - break - - # Respect __all__ attribute. (Ok to generalize to all objects?) - all = getattr(current, '__all__', None) - - current = getattr(current, component, None) - # Path doesn't exist - if current is None or self._disallowed.match(component) or \ - (all is not None and component not in all and not redirect): - # Use path up to latest default page. - if current_default is not None: - i, current = current_default - break - # No default at all, so we fail. - return None - - func = None - if self._exposed(current, redirect): # Exposed? - func = current - else: - # If not, see if it as an exposed index page - if self.index_page: - index = getattr(current, self.index_page, None) - if self._exposed(index, redirect): func = index - # How about a default page? - if func is None and self.default_page: - default = getattr(current, self.default_page, None) - if self._exposed(default, redirect): func = default - # Lastly, see if we have an ancestor's default page to fall back on. - if func is None and current_default is not None: - i, func = current_default - - if func is not None: - self._updatePath(request, i) - - return func - -def expose(func): - """Decorator to expose functions.""" - func.exposed = True - return func |