def redirect_to(*args, **kargs): """Issues a redirect based on the arguments. Redirect's *should* occur as a "302 Moved" header, however the web framework may utilize a different method. All arguments are passed to url_for to retrieve the appropriate URL, then the resulting URL it sent to the redirect function as the URL. """ target = url_for(*args, **kargs) config = request_config() return config.redirect(target)
def __init__(self, controller_scan=controller_scan, directory=None, always_scan=False, register=True, explicit=True): """Create a new Mapper instance All keyword arguments are optional. ``controller_scan`` Function reference that will be used to return a list of valid controllers used during URL matching. If ``directory`` keyword arg is present, it will be passed into the function during its call. This option defaults to a function that will scan a directory for controllers. Alternatively, a list of controllers or None can be passed in which are assumed to be the definitive list of controller names valid when matching 'controller'. ``directory`` Passed into controller_scan for the directory to scan. It should be an absolute path if using the default ``controller_scan`` function. ``always_scan`` Whether or not the ``controller_scan`` function should be run during every URL match. This is typically a good idea during development so the server won't need to be restarted anytime a controller is added. ``register`` Boolean used to determine if the Mapper should use ``request_config`` to register itself as the mapper. Since it's done on a thread-local basis, this is typically best used during testing though it won't hurt in other cases. ``explicit`` Boolean used to determine if routes should be connected with implicit defaults of:: {'controller':'content','action':'index','id':None} When set to True, these defaults will not be added to route connections and ``url_for`` will not use Route memory. Additional attributes that may be set after mapper initialization (ie, map.ATTRIBUTE = 'something'): ``encoding`` Used to indicate alternative encoding/decoding systems to use with both incoming URL's, and during Route generation when passed a Unicode string. Defaults to 'utf-8'. ``decode_errors`` How to handle errors in the encoding, generally ignoring any chars that don't convert should be sufficient. Defaults to 'ignore'. ``minimization`` Boolean used to indicate whether or not Routes should minimize URL's and the generated URL's, or require every part where it appears in the path. Defaults to True. ``hardcode_names`` Whether or not Named Routes result in the default options for the route being used *or* if they actually force url generation to use the route. Defaults to False. """ self.matchlist = [] self.maxkeys = {} self.minkeys = {} self.urlcache = LRUCache(1600) self._created_regs = False self._created_gens = False self._master_regexp = None self.prefix = None self.req_data = threading.local() self.directory = directory self.always_scan = always_scan self.controller_scan = controller_scan self._regprefix = None self._routenames = {} self.debug = False self.append_slash = False self.sub_domains = False self.sub_domains_ignore = [] self.domain_match = '[^\.\/]+?\.[^\.\/]+' self.explicit = explicit self.encoding = 'utf-8' self.decode_errors = 'ignore' self.hardcode_names = True self.minimization = False self.create_regs_lock = threading.Lock() if register: config = request_config() config.mapper = self
def url_for(*args, **kargs): """Generates a URL All keys given to url_for are sent to the Routes Mapper instance for generation except for:: anchor specified the anchor name to be appened to the path host overrides the default (current) host if provided protocol overrides the default (current) protocol if provided qualified creates the URL with the host/port information as needed The URL is generated based on the rest of the keys. When generating a new URL, values will be used from the current request's parameters (if present). The following rules are used to determine when and how to keep the current requests parameters: * If the controller is present and begins with '/', no defaults are used * If the controller is changed, action is set to 'index' unless otherwise specified For example, if the current request yielded a dict of {'controller': 'blog', 'action': 'view', 'id': 2}, with the standard ':controller/:action/:id' route, you'd get the following results:: url_for(id=4) => '/blog/view/4', url_for(controller='/admin') => '/admin', url_for(controller='admin') => '/admin/view/2' url_for(action='edit') => '/blog/edit/2', url_for(action='list', id=None) => '/blog/list' **Static and Named Routes** If there is a string present as the first argument, a lookup is done against the named routes table to see if there's any matching routes. The keyword defaults used with static routes will be sent in as GET query arg's if a route matches. If no route by that name is found, the string is assumed to be a raw URL. Should the raw URL begin with ``/`` then appropriate SCRIPT_NAME data will be added if present, otherwise the string will be used as the url with keyword args becoming GET query args. """ anchor = kargs.get('anchor') host = kargs.get('host') protocol = kargs.get('protocol') qualified = kargs.pop('qualified', None) # Remove special words from kargs, convert placeholders for key in ['anchor', 'host', 'protocol']: if kargs.get(key): del kargs[key] config = request_config() route = None static = False encoding = config.mapper.encoding url = '' if len(args) > 0: route = config.mapper._routenames.get(args[0]) # No named route found, assume the argument is a relative path if not route: static = True url = args[0] if url.startswith('/') and hasattr(config, 'environ') \ and config.environ.get('SCRIPT_NAME'): url = config.environ.get('SCRIPT_NAME') + url if static: if kargs: url += '?' query_args = [] for key, val in kargs.iteritems(): if isinstance(val, (list, tuple)): for value in val: query_args.append("%s=%s" % ( urllib.quote(unicode(key).encode(encoding)), urllib.quote(unicode(value).encode(encoding)))) else: query_args.append("%s=%s" % ( urllib.quote(unicode(key).encode(encoding)), urllib.quote(unicode(val).encode(encoding)))) url += '&'.join(query_args) environ = getattr(config, 'environ', {}) if 'wsgiorg.routing_args' not in environ: environ = environ.copy() mapper_dict = getattr(config, 'mapper_dict', None) if mapper_dict is not None: match_dict = mapper_dict.copy() else: match_dict = {} environ['wsgiorg.routing_args'] = ((), match_dict) if not static: route_args = [] if route: if config.mapper.hardcode_names: route_args.append(route) newargs = route.defaults.copy() newargs.update(kargs) # If this route has a filter, apply it if route.filter: newargs = route.filter(newargs) if not route.static: # Handle sub-domains newargs = _subdomain_check(newargs, config.mapper, environ) else: newargs = _screenargs(kargs, config.mapper, environ) anchor = newargs.pop('_anchor', None) or anchor host = newargs.pop('_host', None) or host protocol = newargs.pop('_protocol', None) or protocol url = config.mapper.generate(*route_args, **newargs) if anchor is not None: url += '#' + _url_quote(anchor, encoding) if host or protocol or qualified: if not host and not qualified: # Ensure we don't use a specific port, as changing the protocol # means that we most likely need a new port host = config.host.split(':')[0] elif not host: host = config.host if not protocol: protocol = config.protocol if url is not None: url = protocol + '://' + host + url if not isinstance(url, str) and url is not None: raise GenerationException("url_for can only return a string, got " "unicode instead: %s" % url) if url is None: raise GenerationException( "url_for could not generate URL. Called with args: %s %s" % \ (args, kargs)) return url