Mercurial > repos > shellac > guppy_basecaller
diff env/lib/python3.7/site-packages/routes/route.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author | shellac |
---|---|
date | Mon, 01 Jun 2020 08:59:25 -0400 |
parents | 79f47841a781 |
children |
line wrap: on
line diff
--- a/env/lib/python3.7/site-packages/routes/route.py Thu May 14 16:47:39 2020 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,752 +0,0 @@ -import re -import sys -if sys.version < '2.4': - from sets import ImmutableSet as frozenset - -import six -from six.moves.urllib import parse as urlparse - -from routes.util import _url_quote as url_quote, _str_encode, as_unicode - - -class Route(object): - """The Route object holds a route recognition and generation - routine. - - See Route.__init__ docs for usage. - - """ - # reserved keys that don't count - reserved_keys = ['requirements'] - - # special chars to indicate a natural split in the URL - done_chars = ('/', ',', ';', '.', '#') - - def __init__(self, name, routepath, **kargs): - """Initialize a route, with a given routepath for - matching/generation - - The set of keyword args will be used as defaults. - - Usage:: - - >>> from routes.base import Route - >>> newroute = Route(None, ':controller/:action/:id') - >>> sorted(newroute.defaults.items()) - [('action', 'index'), ('id', None)] - >>> newroute = Route(None, 'date/:year/:month/:day', - ... controller="blog", action="view") - >>> newroute = Route(None, 'archives/:page', controller="blog", - ... action="by_page", requirements = { 'page':'\d{1,2}' }) - >>> newroute.reqs - {'page': '\\\d{1,2}'} - - .. Note:: - Route is generally not called directly, a Mapper instance - connect method should be used to add routes. - - """ - self.routepath = routepath - self.sub_domains = False - self.prior = None - self.redirect = False - self.name = name - self._kargs = kargs - self.minimization = kargs.pop('_minimize', False) - self.encoding = kargs.pop('_encoding', 'utf-8') - self.reqs = kargs.get('requirements', {}) - self.decode_errors = 'replace' - - # Don't bother forming stuff we don't need if its a static route - self.static = kargs.pop('_static', False) - self.filter = kargs.pop('_filter', None) - self.absolute = kargs.pop('_absolute', False) - - # Pull out the member/collection name if present, this applies only to - # map.resource - self.member_name = kargs.pop('_member_name', None) - self.collection_name = kargs.pop('_collection_name', None) - self.parent_resource = kargs.pop('_parent_resource', None) - - # Pull out route conditions - self.conditions = kargs.pop('conditions', None) - - # Determine if explicit behavior should be used - self.explicit = kargs.pop('_explicit', False) - - # Since static need to be generated exactly, treat them as - # non-minimized - if self.static: - self.external = '://' in self.routepath - self.minimization = False - - # Strip preceding '/' if present, and not minimizing - if routepath.startswith('/') and self.minimization: - self.routepath = routepath[1:] - self._setup_route() - - def _setup_route(self): - # Build our routelist, and the keys used in the route - self.routelist = routelist = self._pathkeys(self.routepath) - routekeys = frozenset(key['name'] for key in routelist - if isinstance(key, dict)) - self.dotkeys = frozenset(key['name'] for key in routelist - if isinstance(key, dict) and - key['type'] == '.') - - if not self.minimization: - self.make_full_route() - - # Build a req list with all the regexp requirements for our args - self.req_regs = {} - for key, val in six.iteritems(self.reqs): - self.req_regs[key] = re.compile('^' + val + '$') - # Update our defaults and set new default keys if needed. defaults - # needs to be saved - (self.defaults, defaultkeys) = self._defaults(routekeys, - self.reserved_keys, - self._kargs.copy()) - # Save the maximum keys we could utilize - self.maxkeys = defaultkeys | routekeys - - # Populate our minimum keys, and save a copy of our backward keys for - # quicker generation later - (self.minkeys, self.routebackwards) = self._minkeys(routelist[:]) - - # Populate our hardcoded keys, these are ones that are set and don't - # exist in the route - self.hardcoded = frozenset(key for key in self.maxkeys - if key not in routekeys - and self.defaults[key] is not None) - - # Cache our default keys - self._default_keys = frozenset(self.defaults.keys()) - - def make_full_route(self): - """Make a full routelist string for use with non-minimized - generation""" - regpath = '' - for part in self.routelist: - if isinstance(part, dict): - regpath += '%(' + part['name'] + ')s' - else: - regpath += part - self.regpath = regpath - - def make_unicode(self, s): - """Transform the given argument into a unicode string.""" - if isinstance(s, six.text_type): - return s - elif isinstance(s, bytes): - return s.decode(self.encoding) - elif callable(s): - return s - else: - return six.text_type(s) - - def _pathkeys(self, routepath): - """Utility function to walk the route, and pull out the valid - dynamic/wildcard keys.""" - collecting = False - current = '' - done_on = '' - var_type = '' - just_started = False - routelist = [] - for char in routepath: - if char in [':', '*', '{'] and not collecting and not self.static \ - or char in ['{'] and not collecting: - just_started = True - collecting = True - var_type = char - if char == '{': - done_on = '}' - just_started = False - if len(current) > 0: - routelist.append(current) - current = '' - elif collecting and just_started: - just_started = False - if char == '(': - done_on = ')' - else: - current = char - done_on = self.done_chars + ('-',) - elif collecting and char not in done_on: - current += char - elif collecting: - collecting = False - if var_type == '{': - if current[0] == '.': - var_type = '.' - current = current[1:] - else: - var_type = ':' - opts = current.split(':') - if len(opts) > 1: - current = opts[0] - self.reqs[current] = opts[1] - routelist.append(dict(type=var_type, name=current)) - if char in self.done_chars: - routelist.append(char) - done_on = var_type = current = '' - else: - current += char - if collecting: - routelist.append(dict(type=var_type, name=current)) - elif current: - routelist.append(current) - return routelist - - def _minkeys(self, routelist): - """Utility function to walk the route backwards - - Will also determine the minimum keys we can handle to generate - a working route. - - routelist is a list of the '/' split route path - defaults is a dict of all the defaults provided for the route - - """ - minkeys = [] - backcheck = routelist[:] - - # If we don't honor minimization, we need all the keys in the - # route path - if not self.minimization: - for part in backcheck: - if isinstance(part, dict): - minkeys.append(part['name']) - return (frozenset(minkeys), backcheck) - - gaps = False - backcheck.reverse() - for part in backcheck: - if not isinstance(part, dict) and part not in self.done_chars: - gaps = True - continue - elif not isinstance(part, dict): - continue - key = part['name'] - if key in self.defaults and not gaps: - continue - minkeys.append(key) - gaps = True - return (frozenset(minkeys), backcheck) - - def _defaults(self, routekeys, reserved_keys, kargs): - """Creates default set with values stringified - - Put together our list of defaults, stringify non-None values - and add in our action/id default if they use it and didn't - specify it. - - defaultkeys is a list of the currently assumed default keys - routekeys is a list of the keys found in the route path - reserved_keys is a list of keys that are not - - """ - defaults = {} - # Add in a controller/action default if they don't exist - if 'controller' not in routekeys and 'controller' not in kargs \ - and not self.explicit: - kargs['controller'] = 'content' - if 'action' not in routekeys and 'action' not in kargs \ - and not self.explicit: - kargs['action'] = 'index' - defaultkeys = frozenset(key for key in kargs.keys() - if key not in reserved_keys) - for key in defaultkeys: - if kargs[key] is not None: - defaults[key] = self.make_unicode(kargs[key]) - else: - defaults[key] = None - if 'action' in routekeys and 'action' not in defaults \ - and not self.explicit: - defaults['action'] = 'index' - if 'id' in routekeys and 'id' not in defaults \ - and not self.explicit: - defaults['id'] = None - newdefaultkeys = frozenset(key for key in defaults.keys() - if key not in reserved_keys) - - return (defaults, newdefaultkeys) - - def makeregexp(self, clist, include_names=True): - """Create a regular expression for matching purposes - - Note: This MUST be called before match can function properly. - - clist should be a list of valid controller strings that can be - matched, for this reason makeregexp should be called by the web - framework after it knows all available controllers that can be - utilized. - - include_names indicates whether this should be a match regexp - assigned to itself using regexp grouping names, or if names - should be excluded for use in a single larger regexp to - determine if any routes match - - """ - if self.minimization: - reg = self.buildnextreg(self.routelist, clist, include_names)[0] - if not reg: - reg = '/' - reg = reg + '/?' + '$' - - if not reg.startswith('/'): - reg = '/' + reg - else: - reg = self.buildfullreg(clist, include_names) - - reg = '^' + reg - - if not include_names: - return reg - - self.regexp = reg - self.regmatch = re.compile(reg) - - def buildfullreg(self, clist, include_names=True): - """Build the regexp by iterating through the routelist and - replacing dicts with the appropriate regexp match""" - regparts = [] - for part in self.routelist: - if isinstance(part, dict): - var = part['name'] - if var == 'controller': - partmatch = '|'.join(map(re.escape, clist)) - elif part['type'] == ':': - partmatch = self.reqs.get(var) or '[^/]+?' - elif part['type'] == '.': - partmatch = self.reqs.get(var) or '[^/.]+?' - else: - partmatch = self.reqs.get(var) or '.+?' - if include_names: - regpart = '(?P<%s>%s)' % (var, partmatch) - else: - regpart = '(?:%s)' % partmatch - if part['type'] == '.': - regparts.append('(?:\.%s)??' % regpart) - else: - regparts.append(regpart) - else: - regparts.append(re.escape(part)) - regexp = ''.join(regparts) + '$' - return regexp - - def buildnextreg(self, path, clist, include_names=True): - """Recursively build our regexp given a path, and a controller - list. - - Returns the regular expression string, and two booleans that - can be ignored as they're only used internally by buildnextreg. - - """ - if path: - part = path[0] - else: - part = '' - reg = '' - - # noreqs will remember whether the remainder has either a string - # match, or a non-defaulted regexp match on a key, allblank remembers - # if the rest could possible be completely empty - (rest, noreqs, allblank) = ('', True, True) - if len(path[1:]) > 0: - self.prior = part - (rest, noreqs, allblank) = self.buildnextreg(path[1:], clist, - include_names) - - if isinstance(part, dict) and part['type'] in (':', '.'): - var = part['name'] - typ = part['type'] - partreg = '' - - # First we plug in the proper part matcher - if var in self.reqs: - if include_names: - partreg = '(?P<%s>%s)' % (var, self.reqs[var]) - else: - partreg = '(?:%s)' % self.reqs[var] - if typ == '.': - partreg = '(?:\.%s)??' % partreg - elif var == 'controller': - if include_names: - partreg = '(?P<%s>%s)' % (var, '|'.join(map(re.escape, - clist))) - else: - partreg = '(?:%s)' % '|'.join(map(re.escape, clist)) - elif self.prior in ['/', '#']: - if include_names: - partreg = '(?P<' + var + '>[^' + self.prior + ']+?)' - else: - partreg = '(?:[^' + self.prior + ']+?)' - else: - if not rest: - if typ == '.': - exclude_chars = '/.' - else: - exclude_chars = '/' - if include_names: - partreg = '(?P<%s>[^%s]+?)' % (var, exclude_chars) - else: - partreg = '(?:[^%s]+?)' % exclude_chars - if typ == '.': - partreg = '(?:\.%s)??' % partreg - else: - end = ''.join(self.done_chars) - rem = rest - if rem[0] == '\\' and len(rem) > 1: - rem = rem[1] - elif rem.startswith('(\\') and len(rem) > 2: - rem = rem[2] - else: - rem = end - rem = frozenset(rem) | frozenset(['/']) - if include_names: - partreg = '(?P<%s>[^%s]+?)' % (var, ''.join(rem)) - else: - partreg = '(?:[^%s]+?)' % ''.join(rem) - - if var in self.reqs: - noreqs = False - if var not in self.defaults: - allblank = False - noreqs = False - - # Now we determine if its optional, or required. This changes - # depending on what is in the rest of the match. If noreqs is - # true, then its possible the entire thing is optional as there's - # no reqs or string matches. - if noreqs: - # The rest is optional, but now we have an optional with a - # regexp. Wrap to ensure that if we match anything, we match - # our regexp first. It's still possible we could be completely - # blank as we have a default - if var in self.reqs and var in self.defaults: - reg = '(?:' + partreg + rest + ')?' - - # Or we have a regexp match with no default, so now being - # completely blank form here on out isn't possible - elif var in self.reqs: - allblank = False - reg = partreg + rest - - # If the character before this is a special char, it has to be - # followed by this - elif var in self.defaults and self.prior in (',', ';', '.'): - reg = partreg + rest - - # Or we have a default with no regexp, don't touch the allblank - elif var in self.defaults: - reg = partreg + '?' + rest - - # Or we have a key with no default, and no reqs. Not possible - # to be all blank from here - else: - allblank = False - reg = partreg + rest - # In this case, we have something dangling that might need to be - # matched - else: - # If they can all be blank, and we have a default here, we know - # its safe to make everything from here optional. Since - # something else in the chain does have req's though, we have - # to make the partreg here required to continue matching - if allblank and var in self.defaults: - reg = '(?:' + partreg + rest + ')?' - - # Same as before, but they can't all be blank, so we have to - # require it all to ensure our matches line up right - else: - reg = partreg + rest - elif isinstance(part, dict) and part['type'] == '*': - var = part['name'] - if noreqs: - if include_names: - reg = '(?P<%s>.*)' % var + rest - else: - reg = '(?:.*)' + rest - if var not in self.defaults: - allblank = False - noreqs = False - else: - if allblank and var in self.defaults: - if include_names: - reg = '(?P<%s>.*)' % var + rest - else: - reg = '(?:.*)' + rest - elif var in self.defaults: - if include_names: - reg = '(?P<%s>.*)' % var + rest - else: - reg = '(?:.*)' + rest - else: - if include_names: - reg = '(?P<%s>.*)' % var + rest - else: - reg = '(?:.*)' + rest - allblank = False - noreqs = False - elif part and part[-1] in self.done_chars: - if allblank: - reg = re.escape(part[:-1]) + '(?:' + re.escape(part[-1]) + rest - reg += ')?' - else: - allblank = False - reg = re.escape(part) + rest - - # We have a normal string here, this is a req, and it prevents us from - # being all blank - else: - noreqs = False - allblank = False - reg = re.escape(part) + rest - - return (reg, noreqs, allblank) - - def match(self, url, environ=None, sub_domains=False, - sub_domains_ignore=None, domain_match=''): - """Match a url to our regexp. - - While the regexp might match, this operation isn't - guaranteed as there's other factors that can cause a match to - fail even though the regexp succeeds (Default that was relied - on wasn't given, requirement regexp doesn't pass, etc.). - - Therefore the calling function shouldn't assume this will - return a valid dict, the other possible return is False if a - match doesn't work out. - - """ - # Static routes don't match, they generate only - if self.static: - return False - - match = self.regmatch.match(url) - - if not match: - return False - - sub_domain = None - - if sub_domains and environ and 'HTTP_HOST' in environ: - host = environ['HTTP_HOST'].split(':')[0] - sub_match = re.compile('^(.+?)\.%s$' % domain_match) - subdomain = re.sub(sub_match, r'\1', host) - if subdomain not in sub_domains_ignore and host != subdomain: - sub_domain = subdomain - - if self.conditions: - if 'method' in self.conditions and environ and \ - environ['REQUEST_METHOD'] not in self.conditions['method']: - return False - - # Check sub-domains? - use_sd = self.conditions.get('sub_domain') - if use_sd and not sub_domain: - return False - elif not use_sd and 'sub_domain' in self.conditions and sub_domain: - return False - if isinstance(use_sd, list) and sub_domain not in use_sd: - return False - - matchdict = match.groupdict() - result = {} - extras = self._default_keys - frozenset(matchdict.keys()) - for key, val in six.iteritems(matchdict): - if key != 'path_info' and self.encoding: - # change back into python unicode objects from the URL - # representation - try: - val = as_unicode(val, self.encoding, self.decode_errors) - except UnicodeDecodeError: - return False - - if not val and key in self.defaults and self.defaults[key]: - result[key] = self.defaults[key] - else: - result[key] = val - for key in extras: - result[key] = self.defaults[key] - - # Add the sub-domain if there is one - if sub_domains: - result['sub_domain'] = sub_domain - - # If there's a function, call it with environ and expire if it - # returns False - if self.conditions and 'function' in self.conditions and \ - not self.conditions['function'](environ, result): - return False - - return result - - def generate_non_minimized(self, kargs): - """Generate a non-minimal version of the URL""" - # Iterate through the keys that are defaults, and NOT in the route - # path. If its not in kargs, or doesn't match, or is None, this - # route won't work - for k in self.maxkeys - self.minkeys: - if k not in kargs: - return False - elif self.make_unicode(kargs[k]) != \ - self.make_unicode(self.defaults[k]): - return False - - # Ensure that all the args in the route path are present and not None - for arg in self.minkeys: - if arg not in kargs or kargs[arg] is None: - if arg in self.dotkeys: - kargs[arg] = '' - else: - return False - - # Encode all the argument that the regpath can use - for k in kargs: - if k in self.maxkeys: - if k in self.dotkeys: - if kargs[k]: - kargs[k] = url_quote('.' + as_unicode(kargs[k], - self.encoding), self.encoding) - else: - kargs[k] = url_quote(as_unicode(kargs[k], self.encoding), - self.encoding) - - return self.regpath % kargs - - def generate_minimized(self, kargs): - """Generate a minimized version of the URL""" - routelist = self.routebackwards - urllist = [] - gaps = False - for part in routelist: - if isinstance(part, dict) and part['type'] in (':', '.'): - arg = part['name'] - - # For efficiency, check these just once - has_arg = arg in kargs - has_default = arg in self.defaults - - # Determine if we can leave this part off - # First check if the default exists and wasn't provided in the - # call (also no gaps) - if has_default and not has_arg and not gaps: - continue - - # Now check to see if there's a default and it matches the - # incoming call arg - if (has_default and has_arg) and \ - self.make_unicode(kargs[arg]) == \ - self.make_unicode(self.defaults[arg]) and not gaps: - continue - - # We need to pull the value to append, if the arg is None and - # we have a default, use that - if has_arg and kargs[arg] is None and has_default and not gaps: - continue - - # Otherwise if we do have an arg, use that - elif has_arg: - val = kargs[arg] - - elif has_default and self.defaults[arg] is not None: - val = self.defaults[arg] - # Optional format parameter? - elif part['type'] == '.': - continue - # No arg at all? This won't work - else: - return False - - val = as_unicode(val, self.encoding) - urllist.append(url_quote(val, self.encoding)) - if part['type'] == '.': - urllist.append('.') - - if has_arg: - del kargs[arg] - gaps = True - elif isinstance(part, dict) and part['type'] == '*': - arg = part['name'] - kar = kargs.get(arg) - if kar is not None: - urllist.append(url_quote(kar, self.encoding)) - gaps = True - elif part and part[-1] in self.done_chars: - if not gaps and part in self.done_chars: - continue - elif not gaps: - urllist.append(part[:-1]) - gaps = True - else: - gaps = True - urllist.append(part) - else: - gaps = True - urllist.append(part) - urllist.reverse() - url = ''.join(urllist) - return url - - def generate(self, _ignore_req_list=False, _append_slash=False, **kargs): - """Generate a URL from ourself given a set of keyword arguments - - Toss an exception if this - set of keywords would cause a gap in the url. - - """ - # Verify that our args pass any regexp requirements - if not _ignore_req_list: - for key in self.reqs.keys(): - val = kargs.get(key) - if val and not self.req_regs[key].match(self.make_unicode(val)): - return False - - # Verify that if we have a method arg, its in the method accept list. - # Also, method will be changed to _method for route generation - meth = as_unicode(kargs.get('method'), self.encoding) - if meth: - if self.conditions and 'method' in self.conditions \ - and meth.upper() not in self.conditions['method']: - return False - kargs.pop('method') - - if self.minimization: - url = self.generate_minimized(kargs) - else: - url = self.generate_non_minimized(kargs) - - if url is False: - return url - - if not url.startswith('/') and not self.static: - url = '/' + url - extras = frozenset(kargs.keys()) - self.maxkeys - if extras: - if _append_slash and not url.endswith('/'): - url += '/' - fragments = [] - # don't assume the 'extras' set preserves order: iterate - # through the ordered kargs instead - for key in kargs: - if key not in extras: - continue - if key == 'action' or key == 'controller': - continue - val = kargs[key] - if isinstance(val, (tuple, list)): - for value in val: - value = as_unicode(value, self.encoding) - fragments.append((key, _str_encode(value, - self.encoding))) - else: - val = as_unicode(val, self.encoding) - fragments.append((key, _str_encode(val, self.encoding))) - if fragments: - url += '?' - url += urlparse.urlencode(fragments) - elif _append_slash and not url.endswith('/'): - url += '/' - return url