diff options
Diffstat (limited to 'flup/resolver')
-rw-r--r-- | flup/resolver/__init__.py | 2 | ||||
-rw-r--r-- | flup/resolver/complex.py | 112 | ||||
-rw-r--r-- | flup/resolver/function.py | 46 | ||||
-rw-r--r-- | flup/resolver/importingmodule.py | 129 | ||||
-rw-r--r-- | flup/resolver/module.py | 86 | ||||
-rw-r--r-- | flup/resolver/nopathinfo.py | 57 | ||||
-rw-r--r-- | flup/resolver/objectpath.py | 156 | ||||
-rw-r--r-- | flup/resolver/resolver.py | 81 |
8 files changed, 0 insertions, 669 deletions
diff --git a/flup/resolver/__init__.py b/flup/resolver/__init__.py deleted file mode 100644 index bc9c7bf..0000000 --- a/flup/resolver/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from resolver import * -del resolver diff --git a/flup/resolver/complex.py b/flup/resolver/complex.py deleted file mode 100644 index f5b3aa0..0000000 --- a/flup/resolver/complex.py +++ /dev/null @@ -1,112 +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__ = ['ComplexResolver'] - -class ComplexResolver(Resolver): - """ - A meta-Resolver that allows you to "graft" different resolvers at various - points in your URL space. - - It works as follows: given a PATH_INFO, it will try all matching - resolvers, starting with the most specific. The first function returned - by a resolver is returned as the result. - - If no matching resolvers return a function, then the search is - considered a failure. - - Assumes that none of the registered resolvers modify environ when - they fail to resolve. - - Upon successful resolution, SCRIPT_NAME will contain the path up to - and including the resolved function (as determined by the resolver) and - PATH_INFO will contain all remaining components. - """ - _slashRE = re.compile(r'''/{2,}''') - - def __init__(self): - self.resolverMap = {} - - def _canonicalUrl(self, url): - if not url: # Represents default - return url - - # Get rid of adjacent slashes - url = self._slashRE.sub('/', url) - - # No trailing slash - if url.endswith('/'): - url = url[:-1] - - # Make sure it starts with a slash - if not url.startswith('/'): - url = '/' + url - - return url - - def addResolver(self, url, resolver): - """ - Registers a resolver at a particular URL. The empty URL '' - represents the default resolver. It will be matched when no - other matching resolvers are found. - """ - url = self._canonicalUrl(url) - self.resolverMap[url] = resolver - - def removeResolver(self, url): - """Removes the resolver at a particular URL.""" - url = self._canonicalUrl(url) - del self.resolverMap[url] - - def resolve(self, request, redirect=False): - orig_script_name = request.scriptName - orig_path_info = path_info = request.pathInfo - path_info = path_info.split(';')[0] - path_info = path_info.split('/') - - assert len(path_info) > 0 - assert not path_info[0] - - while path_info: - try_path_info = '/'.join(path_info) - resolver = self.resolverMap.get(try_path_info) - if resolver is not None: - self._updatePath(request, len(path_info) - 1) - func = resolver.resolve(request, redirect) - if func is not None: - return func - request.environ['SCRIPT_NAME'] = orig_script_name - request.environ['PATH_INFO'] = orig_path_info - path_info.pop() - - return None diff --git a/flup/resolver/function.py b/flup/resolver/function.py deleted file mode 100644 index 15458be..0000000 --- a/flup/resolver/function.py +++ /dev/null @@ -1,46 +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$' - -from flup.resolver.resolver import * - -__all__ = ['FunctionResolver'] - -class FunctionResolver(Resolver): - """ - Very basic, almost brain-dead Resolver. Simply resolves to the passed - in function, no matter what. :) - - Can be used as a decorator and might actually have uses when used with - the ComplexResolver. - """ - def __init__(self, func): - self._func = func - - def resolve(self, request, redirect=False): - return self._func diff --git a/flup/resolver/importingmodule.py b/flup/resolver/importingmodule.py deleted file mode 100644 index 37fd83b..0000000 --- a/flup/resolver/importingmodule.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright (c) 2002, 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 sys -import os -import imp - -from flup.resolver.resolver import * - -__all__ = ['ImportingModuleResolver'] - -class NoDefault(object): - pass - -class ImportingModuleResolver(Resolver): - """ - Constructor takes a directory name or a list of directories. Interprets - the first two components of PATH_INFO as 'module/function'. Modules - are imported as needed and must reside in the directories specified. - Module and function names beginning with underscore are ignored. - - If the 'module' part of PATH_INFO is missing, it is assumed to be - self.default_module. - - If the 'function' part of PATH_INFO is missing, it is assumed to be - self.index_page. - - Upon successful resolution, appends the module and function names to - SCRIPT_NAME and updates PATH_INFO as the remaining components of the path. - - NB: I would recommend explicitly setting all modules' __all__ list. - Otherwise, be sure all the names of module-level callables that you - don't want exported begin with underscore. - """ - # No default module by default. - default_module = None - index_page = 'index' - - def __init__(self, path, defaultModule=NoDefault, index=NoDefault): - self.path = path - if defaultModule is not NoDefault: - self.default_module = defaultModule - if index is not NoDefault: - self.index_page = index - - 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] - - while len(path_info) < 3: - path_info.append('') - - module_name, func_name = path_info[1:3] - - if not module_name: - module_name = self.default_module - - if not func_name: - func_name = self.index_page - - module = None - if module_name and (module_name[0] != '_' or redirect) and \ - not module_name.count('.'): - module = _import_module(module_name, path=self.path) - - if module is not None: - if func_name and (func_name[0] != '_' or redirect): - module_all = getattr(module, '__all__', None) - if module_all is None or func_name in module_all or redirect: - func = getattr(module, func_name, None) - if callable(func): - self._updatePath(request, 2) - return func - - return None - -def _import_module(name, path=None): - """ - Imports a module. If path is None, module will be searched for in - sys.path. If path is given (which may be a single string or a list), - the module will only be searched for in those directories. - """ - if path is not None and type(path) is not list: - path = [path] - - module = sys.modules.get(name) - if module is not None: - module_file = getattr(module, '__file__') - if module_file is None or \ - (path is not None and os.path.dirname(module_file) not in path): - return None - - return module - - fp, pathname, description = imp.find_module(name, path) - try: - return imp.load_module(name, fp, pathname, description) - finally: - if fp: - fp.close() diff --git a/flup/resolver/module.py b/flup/resolver/module.py deleted file mode 100644 index 79171d6..0000000 --- a/flup/resolver/module.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (c) 2002, 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$' - -from flup.resolver.resolver import * - -__all__ = ['ModuleResolver'] - -class NoDefault(object): - pass - -class ModuleResolver(Resolver): - """ - Exposes all top-level callables within a module. The module's __all__ - attribute is respected, if it exists. Names beginning with underscore - are ignored. - - Uses the first component of PATH_INFO as the callable's name and if - empty, will instead use self.index_page. - - Upon successful resolution, appends the callable's name to SCRIPT_NAME - and updates PATH_INFO as the remaining components of the path. - - NB: I would recommend explicitly setting the module's __all__ list. - Otherwise, be sure all the names of module-level callables that you - don't want exported begin with underscore. - """ - index_page = 'index' - - def __init__(self, module, index=NoDefault): - self.module = module - if index is not NoDefault: - self.index_page = index - - 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] - - if len(path_info) < 2: - path_info.append('') - - func_name = path_info[1] - - if func_name: - if func_name[0] == '_' and not redirect: - func_name = None - else: - func_name = self.index_page - - if func_name: - module_all = getattr(self.module, '__all__', None) - if module_all is None or func_name in module_all or redirect: - func = getattr(self.module, func_name, None) - if callable(func): - self._updatePath(request, 1) - return func - - return None diff --git a/flup/resolver/nopathinfo.py b/flup/resolver/nopathinfo.py deleted file mode 100644 index db9bac0..0000000 --- a/flup/resolver/nopathinfo.py +++ /dev/null @@ -1,57 +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$' - -from flup.resolver.resolver import * - -__all__ = ['NoPathInfoResolver'] - -class NoPathInfoResolver(Resolver): - """ - Another meta-resolver. Disallows the existence of PATH_INFO (beyond - what's needed to resolve the function). Optionally allows a trailing - slash. - """ - def __init__(self, resolver, allowTrailingSlash=False): - self._resolver = resolver - self._allowTrailingSlash = allowTrailingSlash - - def resolve(self, request, redirect=False): - orig_script_name, orig_path_info = request.scriptName, request.pathInfo - func = self._resolver.resolve(request, redirect) - try: - if func is not None: - path_info = request.pathInfo.split(';')[0] - if path_info and \ - (not self._allowTrailingSlash or path_info != '/'): - func = None - return func - finally: - if func is None: - request.environ['SCRIPT_NAME'] = orig_script_name - request.environ['PATH_INFO'] = orig_path_info 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 diff --git a/flup/resolver/resolver.py b/flup/resolver/resolver.py deleted file mode 100644 index ce782c8..0000000 --- a/flup/resolver/resolver.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (c) 2002, 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$' - -__all__ = ['Resolver'] - -class Resolver(object): - """ - Abstract base class for 'Resolver' objects. (An instance of which is - passed to Publisher's constructor.) - - Given a Request, either return a callable (Publisher expects it to - be a function, method, class, or callable instance), or return None. - Typically Request.pathInfo is used to resolve the function. - Request.environ may be modified by the Resolver, for example, to re-adjust - SCRIPT_NAME/PATH_INFO after successful resolution. It is NOT recommended - that it be modified if resolution fails. - - When resolving an InternalRedirect, redirect will be True. - """ - def resolve(self, request, redirect=False): - raise NotImplementedError, self.__class__.__name__ + '.resolve' - - def _updatePath(self, request, num): - """ - Utility function to update SCRIPT_NAME and PATH_INFO in a sane - manner. Transfers num components from PATH_INFO to SCRIPT_NAME. - Keeps URL path parameters intact. - """ - assert num >= 0 - if not num: - return # Nothing to do - numScriptName = len(request.scriptName.split('/')) - totalPath = request.scriptName + request.pathInfo - if __debug__: - origTotalPath = totalPath - # Extract and save params - i = totalPath.find(';') - if i >= 0: - params = totalPath[i:] - totalPath = totalPath[:i] - else: - params = '' - totalPath = totalPath.split('/') - scriptName = '/'.join(totalPath[:numScriptName + num]) - pathInfo = '/'.join([''] + totalPath[numScriptName + num:]) - # SCRIPT_NAME shouldn't have trailing slash - if scriptName.endswith('/'): - scriptName = scriptName[:-1] - # Transfer to PATH_INFO (most likely empty, but just to be safe...) - pathInfo = '/' + pathInfo - request.environ['SCRIPT_NAME'] = scriptName - request.environ['PATH_INFO'] = pathInfo + params - if __debug__: - assert request.scriptName + request.pathInfo == origTotalPath - |