diff options
author | Victor Stinner <vstinner@redhat.com> | 2015-04-20 15:37:04 +0200 |
---|---|---|
committer | Victor Stinner <vstinner@redhat.com> | 2015-06-18 13:07:50 +0200 |
commit | 10400ba8a269cd3d000db4f47543b9238cc01d55 (patch) | |
tree | 79e897e1146006df707d67175f5a32fa86b42603 /routes | |
parent | f30dddcfebd782062b80fd78e32cfd6fd601dd86 (diff) | |
download | routes-10400ba8a269cd3d000db4f47543b9238cc01d55.tar.gz |
Port routes to Python 3
The code now works on Python 2 and Python 3 without modifications: 2to3
is no more needed. Changes:
* Drop 2to3 from setup.py: the code is now directly compatible with
Python 2 and Python 3
* Add dependency to six
* Drop support for Python 3.2: remove 3.2 from .travis.yml
* Replace "for key, value in dict.iteritems():" with "for key, value in
six.iteritems(dict):"
* Use six.moves.urllib to get urllib functions
* Replace unicode() with six.text_type()
* Replace dict.keys() with list(dict.keys())
* Replace "dict.has_key(key)" with "key in dict"
* Remove "py3where=build" from notests section of setup.cfg
* Add parenthesis to print()
* Replace dict.items() with list(dict.items())
Diffstat (limited to 'routes')
-rw-r--r-- | routes/mapper.py | 25 | ||||
-rw-r--r-- | routes/route.py | 40 | ||||
-rw-r--r-- | routes/util.py | 53 |
3 files changed, 62 insertions, 56 deletions
diff --git a/routes/mapper.py b/routes/mapper.py index ea55cda..583309e 100644 --- a/routes/mapper.py +++ b/routes/mapper.py @@ -3,6 +3,7 @@ import re import threading from repoze.lru import LRUCache +import six from routes import request_config from routes.util import ( @@ -153,7 +154,7 @@ class SubMapper(SubMapperParent): def connect(self, *args, **kwargs): newkargs = {} newargs = args - for key, value in self.kwargs.items(): + for key, value in six.iteritems(self.kwargs): if key == 'path_prefix': if len(args) > 1: newargs = (args[0], self.kwargs[key] + args[1]) @@ -547,8 +548,8 @@ class Mapper(SubMapperParent): # Setup the lists of all controllers/actions we'll add each route # to. We include the '*' in the case that a generate contains a # controller/action that has no hardcodes - controllerlist = controllerlist.keys() + ['*'] - actionlist = actionlist.keys() + ['*'] + controllerlist = list(controllerlist.keys()) + ['*'] + actionlist = list(actionlist.keys()) + ['*'] # Go through our list again, assemble the controllers/actions we'll # add each route to. If its hardcoded, we only add it to that dict key. @@ -562,7 +563,7 @@ class Mapper(SubMapperParent): if 'controller' in route.hardcoded: clist = [route.defaults['controller']] if 'action' in route.hardcoded: - alist = [unicode(route.defaults['action'])] + alist = [six.text_type(route.defaults['action'])] for controller in clist: for action in alist: actiondict = gendict.setdefault(controller, {}) @@ -592,7 +593,7 @@ class Mapper(SubMapperParent): else: clist = self.controller_scan - for key, val in self.maxkeys.iteritems(): + for key, val in six.iteritems(self.maxkeys): for route in val: route.makeregexp(clist) @@ -758,8 +759,8 @@ class Mapper(SubMapperParent): # If the URL didn't depend on the SCRIPT_NAME, we'll cache it # keyed by just by kargs; otherwise we need to cache it with # both SCRIPT_NAME and kargs: - cache_key = unicode(args).encode('utf8') + \ - unicode(kargs).encode('utf8') + cache_key = six.text_type(args).encode('utf8') + \ + six.text_type(kargs).encode('utf8') if self.urlcache is not None: cache_key_script_name = '%s:%s' % (script_name, cache_key) @@ -782,7 +783,7 @@ class Mapper(SubMapperParent): keys = frozenset(kargs.keys()) cacheset = False - cachekey = unicode(keys) + cachekey = six.text_type(keys) cachelist = sortcache.get(cachekey) if args: keylist = args @@ -1047,7 +1048,7 @@ class Mapper(SubMapperParent): def swap(dct, newdct): """Swap the keys and values in the dict, and uppercase the values from the dict during the swap.""" - for key, val in dct.iteritems(): + for key, val in six.iteritems(dct): newdct.setdefault(val.upper(), []).append(key) return newdct collection_methods = swap(collection, {}) @@ -1088,7 +1089,7 @@ class Mapper(SubMapperParent): return opts # Add the routes for handling collection methods - for method, lst in collection_methods.iteritems(): + for method, lst in six.iteritems(collection_methods): primary = (method != 'GET' and lst.pop(0)) or None route_options = requirements_for(method) for action in lst: @@ -1112,7 +1113,7 @@ class Mapper(SubMapperParent): action='index', conditions={'method': ['GET']}, **options) # Add the routes that deal with new resource methods - for method, lst in new_methods.iteritems(): + for method, lst in six.iteritems(new_methods): route_options = requirements_for(method) for action in lst: name = "new_" + member_name @@ -1131,7 +1132,7 @@ class Mapper(SubMapperParent): requirements_regexp = '[^\/]+(?<!\\\)' # Add the routes that deal with member methods of a resource - for method, lst in member_methods.iteritems(): + for method, lst in six.iteritems(member_methods): route_options = requirements_for(method) route_options['requirements'] = {'id': requirements_regexp} if method not in ['POST', 'GET', 'any']: diff --git a/routes/route.py b/routes/route.py index 901b4f6..ef8810c 100644 --- a/routes/route.py +++ b/routes/route.py @@ -1,10 +1,12 @@ import re import sys -import urllib - +from six.moves import urllib 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 @@ -87,18 +89,18 @@ class Route(object): 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'] == '.']) + 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 self.reqs.iteritems(): + 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 @@ -114,9 +116,9 @@ class Route(object): # 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]) + 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()) @@ -134,14 +136,14 @@ class Route(object): def make_unicode(self, s): """Transform the given argument into a unicode string.""" - if isinstance(s, unicode): + if isinstance(s, six.text_type): return s elif isinstance(s, bytes): return s.decode(self.encoding) elif callable(s): return s else: - return unicode(s) + return six.text_type(s) def _pathkeys(self, routepath): """Utility function to walk the route, and pull out the valid @@ -253,8 +255,8 @@ class Route(object): 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]) + 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]) @@ -266,8 +268,8 @@ class Route(object): 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]) + newdefaultkeys = frozenset(key for key in defaults.keys() + if key not in reserved_keys) return (defaults, newdefaultkeys) @@ -554,7 +556,7 @@ class Route(object): matchdict = match.groupdict() result = {} extras = self._default_keys - frozenset(matchdict.keys()) - for key, val in matchdict.iteritems(): + for key, val in six.iteritems(matchdict): if key != 'path_info' and self.encoding: # change back into python unicode objects from the URL # representation @@ -745,7 +747,7 @@ class Route(object): fragments.append((key, _str_encode(val, self.encoding))) if fragments: url += '?' - url += urllib.urlencode(fragments) + url += urlparse.urlencode(fragments) elif _append_slash and not url.endswith('/'): url += '/' return url diff --git a/routes/util.py b/routes/util.py index 9834ad5..baeeac7 100644 --- a/routes/util.py +++ b/routes/util.py @@ -7,7 +7,10 @@ framework. """ import os import re -import urllib + +import six +from six.moves import urllib + from routes import request_config @@ -31,8 +34,8 @@ def _screenargs(kargs, mapper, environ, force_explicit=False): """ # Coerce any unicode args with the encoding encoding = mapper.encoding - for key, val in kargs.iteritems(): - if isinstance(val, unicode): + for key, val in six.iteritems(kargs): + if isinstance(val, six.text_type): kargs[key] = val.encode(encoding) if mapper.explicit and mapper.sub_domains and not force_explicit: @@ -46,7 +49,7 @@ def _screenargs(kargs, mapper, environ, force_explicit=False): # If the controller name starts with '/', ignore route memory kargs['controller'] = kargs['controller'][1:] return kargs - elif controller_name and not kargs.has_key('action'): + elif controller_name and 'action' not in kargs: # Fill in an action if we don't have one, but have a controller kargs['action'] = 'index' @@ -57,10 +60,10 @@ def _screenargs(kargs, mapper, environ, force_explicit=False): memory_kargs = {} # Remove keys from memory and kargs if kargs has them as None - for key in [key for key in kargs.keys() if kargs[key] is None]: + empty_keys = [key for key, value in six.iteritems(kargs) if value is None] + for key in empty_keys: del kargs[key] - if memory_kargs.has_key(key): - del memory_kargs[key] + memory_kargs.pop(key, None) # Merge the new args on top of the memory args memory_kargs.update(kargs) @@ -76,7 +79,7 @@ def _subdomain_check(kargs, mapper, environ): on the current subdomain or lack therof.""" if mapper.sub_domains: subdomain = kargs.pop('sub_domain', None) - if isinstance(subdomain, unicode): + if isinstance(subdomain, six.text_type): subdomain = str(subdomain) fullhost = environ.get('HTTP_HOST') or environ.get('SERVER_NAME') @@ -107,27 +110,27 @@ def _subdomain_check(kargs, mapper, environ): def _url_quote(string, encoding): """A Unicode handling version of urllib.quote.""" if encoding: - if isinstance(string, unicode): + if isinstance(string, six.text_type): s = string.encode(encoding) - elif isinstance(string, str): + elif isinstance(string, six.text_type): # assume the encoding is already correct s = string else: - s = unicode(string).encode(encoding) + s = six.text_type(string).encode(encoding) else: s = str(string) - return urllib.quote(s, '/') + return urllib.parse.quote(s, '/') def _str_encode(string, encoding): if encoding: - if isinstance(string, unicode): + if isinstance(string, six.text_type): s = string.encode(encoding) - elif isinstance(string, str): + elif isinstance(string, six.text_type): # assume the encoding is already correct s = string else: - s = unicode(string).encode(encoding) + s = six.text_type(string).encode(encoding) return s @@ -207,16 +210,16 @@ def url_for(*args, **kargs): if kargs: url += '?' query_args = [] - for key, val in kargs.iteritems(): + for key, val in six.iteritems(kargs): 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)))) + urllib.parse.quote(six.text_type(key).encode(encoding)), + urllib.parse.quote(six.text_type(value).encode(encoding)))) else: query_args.append("%s=%s" % ( - urllib.quote(unicode(key).encode(encoding)), - urllib.quote(unicode(val).encode(encoding)))) + urllib.parse.quote(six.text_type(key).encode(encoding)), + urllib.parse.quote(six.text_type(val).encode(encoding)))) url += '&'.join(query_args) environ = getattr(config, 'environ', {}) if 'wsgiorg.routing_args' not in environ: @@ -352,16 +355,16 @@ class URLGenerator(object): if kargs: url += '?' query_args = [] - for key, val in kargs.iteritems(): + for key, val in six.iteritems(kargs): 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)))) + urllib.parse.quote(six.text_type(key).encode(encoding)), + urllib.parse.quote(six.text_type(value).encode(encoding)))) else: query_args.append("%s=%s" % ( - urllib.quote(unicode(key).encode(encoding)), - urllib.quote(unicode(val).encode(encoding)))) + urllib.parse.quote(six.text_type(key).encode(encoding)), + urllib.parse.quote(six.text_type(val).encode(encoding)))) url += '&'.join(query_args) if not static: route_args = [] |