diff options
author | Sviatoslav Sydorenko <wk.cvs.github@sydorenko.org.ua> | 2016-07-21 17:56:03 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-07-21 17:56:03 +0300 |
commit | 7c168b592ddfceb9e30b03aec0c9a60f5d600762 (patch) | |
tree | 1600a0928457d8bd3eab8a9ac8450f9ed021ec73 | |
parent | 2ffd3b57370d9591cc6edb9a4df28f70eaf7d20d (diff) | |
parent | 61a49ad4994e1a7f10767c61b5a9186996140606 (diff) | |
download | routes-7c168b592ddfceb9e30b03aec0c9a60f5d600762.tar.gz |
Merge pull request #3 from bbangert/master
Update from upstream #3
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | CHANGELOG.rst | 14 | ||||
-rw-r--r-- | LICENSE.txt | 2 | ||||
-rw-r--r-- | docs/conf.py | 6 | ||||
-rw-r--r-- | routes/mapper.py | 22 | ||||
-rw-r--r-- | routes/util.py | 44 | ||||
-rw-r--r-- | setup.py | 4 | ||||
-rw-r--r-- | tests/test_functional/test_explicit_use.py | 8 | ||||
-rw-r--r-- | tests/test_functional/test_submapper.py | 6 | ||||
-rw-r--r-- | tests/test_functional/test_utils.py | 2 |
10 files changed, 75 insertions, 35 deletions
diff --git a/.travis.yml b/.travis.yml index 65a02f6..484b853 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,3 +13,5 @@ matrix: - python: "nightly" install: pip install tox-travis script: tox +after_success: + - codecov diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2a8a322..bde71f9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,8 +1,16 @@ Routes Changelog %%%%%%%%%%%%%%%% -Release 2.3 (**dev**) -===================== +Release 2.3.1 (March 30, 2016) +============================== +* Backwards compatability fix - connect should work with mandatory + routename and optional path. Patch by Davanum Srinivas (PR #65). + +Release 2.3 (March 28, 2016) +============================ +* Fix sub_domain equivalence check. Patch by Nikita Uvarov +* Add support for protocol-relative URLs generation (i.e. starting with double + slash ``//``). PR #60. Patch by Sviatoslav Sydorenko. * Add support for the ``middleware`` extra requirement, making possible to depend on ``webob`` optionally. PR #59. Patch by Sviatoslav Sydorenko. * Fix matching of an empty string route, which led to exception in earlier @@ -431,7 +439,7 @@ Release 1.0 (Nov. 21st, 2005) Or:: - from routes import request_confg, Mapper + from routes import request_config, Mapper The following names are available for importing from routes:: diff --git a/LICENSE.txt b/LICENSE.txt index 493ea52..5a11de7 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2005-2015 Ben Bangert <ben@groovie.org> +Copyright (c) 2005-2016 Ben Bangert <ben@groovie.org> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/docs/conf.py b/docs/conf.py index 6673a37..467a6be 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -36,15 +36,15 @@ master_doc = 'index' # General substitutions. project = 'Routes' -copyright = '2005-2015, Ben Bangert, Mike Orr' +copyright = '2005-2016, Ben Bangert, Mike Orr, and numerous contributers' # The default replacements for |version| and |release|, also used in various # other places throughout the built documents. # # The short X.Y version. -version = '1.13' +version = '2.3' # The full version, including alpha/beta/rc tags. -release = '1.13' +release = '2.3.1' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: diff --git a/routes/mapper.py b/routes/mapper.py index 06f09f2..eb4060a 100644 --- a/routes/mapper.py +++ b/routes/mapper.py @@ -162,25 +162,25 @@ class SubMapper(SubMapperParent): self.formatted = True self.add_actions(actions or [], **kwargs) - def connect(self, *args, **kwargs): + def connect(self, routename, path=None, **kwargs): newkargs = {} - # newargs = args - routename, path = args + _routename = routename + _path = path for key, value in six.iteritems(self.kwargs): if key == 'path_prefix': - if len(args) > 1: + if path is not None: # if there's a name_prefix, add it to the route name # and if there's a path_prefix - path = ''.join((self.kwargs[key], args[1])) + _path = ''.join((self.kwargs[key], path)) else: - path = ''.join((self.kwargs[key], args[0])) + _path = ''.join((self.kwargs[key], routename)) elif key == 'name_prefix': - if len(args) > 1: + if path is not None: # if there's a name_prefix, add it to the route name # and if there's a path_prefix - routename = ''.join((self.kwargs[key], args[0])) + _routename = ''.join((self.kwargs[key], routename)) else: - routename = None + _routename = None elif key in kwargs: if isinstance(value, dict): newkargs[key] = dict(value, **kwargs[key]) # merge dicts @@ -197,7 +197,7 @@ class SubMapper(SubMapperParent): if key not in self.kwargs: newkargs[key] = kwargs[key] - newargs = (routename, path) + newargs = (_routename, _path) return self.obj.connect(*newargs, **newkargs) def link(self, rel=None, name=None, action=None, method='GET', @@ -1230,7 +1230,7 @@ class Mapper(SubMapperParent): Example:: map = Mapper() - map.redirect('/legacyapp/archives/{url:.*}, '/archives/{url}) + map.redirect('/legacyapp/archives/{url:.*}', '/archives/{url}') map.redirect('/home/index', '/', _redirect_code='301 Moved Permanently') diff --git a/routes/util.py b/routes/util.py index baeeac7..c48445f 100644 --- a/routes/util.py +++ b/routes/util.py @@ -93,10 +93,12 @@ def _subdomain_check(kargs, mapper, environ): port = '' if len(hostmatch) > 1: port += ':' + hostmatch[1] - sub_match = re.compile('^.+?\.(%s)$' % mapper.domain_match) - domain = re.sub(sub_match, r'\1', host) + + match = re.match('^(.+?)\.(%s)$' % mapper.domain_match, host) + host_subdomain, domain = match.groups() if match else (None, host) + subdomain = as_unicode(subdomain, mapper.encoding) - if subdomain and not host.startswith(subdomain) and \ + if subdomain and host_subdomain != subdomain and \ subdomain not in mapper.sub_domains_ignore: kargs['_host'] = subdomain + '.' + domain + port elif (subdomain in mapper.sub_domains_ignore or \ @@ -180,15 +182,19 @@ def url_for(*args, **kargs): """ anchor = kargs.get('anchor') host = kargs.get('host') - protocol = kargs.get('protocol') + protocol = kargs.pop('protocol', None) qualified = kargs.pop('qualified', None) # Remove special words from kargs, convert placeholders - for key in ['anchor', 'host', 'protocol']: + for key in ['anchor', 'host']: if kargs.get(key): del kargs[key] if key+'_' in kargs: kargs[key] = kargs.pop(key+'_') + + if 'protocol_' in kargs: + kargs['protocol_'] = protocol + config = request_config() route = None static = False @@ -250,21 +256,23 @@ def url_for(*args, **kargs): 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 + protocol = newargs.pop('_protocol', 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 host or (protocol is not None) 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: + if protocol is None: protocol = config.protocol + if protocol != '': + protocol += ':' if url is not None: - url = protocol + '://' + host + url + url = protocol + '//' + host + url if not ascii_characters(url) and url is not None: raise GenerationException("url_for can only return a string, got " @@ -324,16 +332,19 @@ class URLGenerator(object): """ anchor = kargs.get('anchor') host = kargs.get('host') - protocol = kargs.get('protocol') + protocol = kargs.pop('protocol', None) qualified = kargs.pop('qualified', None) # Remove special words from kargs, convert placeholders - for key in ['anchor', 'host', 'protocol']: + for key in ['anchor', 'host']: if kargs.get(key): del kargs[key] if key+'_' in kargs: kargs[key] = kargs.pop(key+'_') + if 'protocol_' in kargs: + kargs['protocol_'] = protocol + route = None use_current = '_use_current' in kargs and kargs.pop('_use_current') @@ -396,12 +407,13 @@ class URLGenerator(object): anchor = anchor or newargs.pop('_anchor', None) host = host or newargs.pop('_host', None) - protocol = protocol or newargs.pop('_protocol', None) + if protocol is None: + protocol = newargs.pop('_protocol', None) newargs['_environ'] = self.environ url = self.mapper.generate(*route_args, **newargs) if anchor is not None: url += '#' + _url_quote(anchor, encoding) - if host or protocol or qualified: + if host or (protocol is not None) or qualified: if 'routes.cached_hostinfo' not in self.environ: cache_hostinfo(self.environ) hostinfo = self.environ['routes.cached_hostinfo'] @@ -412,12 +424,14 @@ class URLGenerator(object): host = hostinfo['host'].split(':')[0] elif not host: host = hostinfo['host'] - if not protocol: + if protocol is None: protocol = hostinfo['protocol'] + if protocol != '': + protocol += ':' if url is not None: if host[-1] != '/': host += '/' - url = protocol + '://' + host + url.lstrip('/') + url = protocol + '//' + host + url.lstrip('/') if not ascii_characters(url) and url is not None: raise GenerationException("Can only return a string, got " @@ -1,4 +1,4 @@ -__version__ = '2.2' +__version__ = '2.3.1' import io import os @@ -47,7 +47,7 @@ setup(name="Routes", keywords='routes webob dispatch', author="Ben Bangert", author_email="ben@groovie.org", - url='http://routes.readthedocs.org/', + url='https://routes.readthedocs.io/', license="MIT", test_suite="nose.collector", include_package_data=True, diff --git a/tests/test_functional/test_explicit_use.py b/tests/test_functional/test_explicit_use.py index 32579d8..ccd3b7a 100644 --- a/tests/test_functional/test_explicit_use.py +++ b/tests/test_functional/test_explicit_use.py @@ -52,6 +52,14 @@ class TestUtils(unittest.TestCase): url = URLGenerator(m, environ.copy()) assert_raises(GenerationException, lambda: url.current(qualified=True)) + environ = {'HTTP_HOST': 'subdomain.localhost.com'} + url = URLGenerator(m, environ.copy()) + eq_('http://sub.localhost.com/hi/smith', url(fred='smith', sub_domain='sub', qualified=True)) + + environ = {'HTTP_HOST': 'sub.sub.localhost.com'} + url = URLGenerator(m, environ.copy()) + eq_('http://new.localhost.com/hi/smith', url(fred='smith', sub_domain='new', qualified=True)) + url = URLGenerator(m, {}) eq_('/hi/smith', url(fred='smith', sub_domain=u'home')) diff --git a/tests/test_functional/test_submapper.py b/tests/test_functional/test_submapper.py index 1516a58..8821de9 100644 --- a/tests/test_functional/test_submapper.py +++ b/tests/test_functional/test_submapper.py @@ -13,6 +13,12 @@ class TestSubmapper(unittest.TestCase): eq_('/entries/1', url_for('entry', id=1))
assert_raises(Exception, url_for, 'entry', id='foo')
+ def test_submapper_with_no_path(self):
+ m = Mapper()
+ c = m.submapper(path_prefix='/')
+ c.connect('entry')
+ eq_('/entry?id=1', url_for('entry', id=1))
+
def test_submapper_nesting(self):
m = Mapper()
c = m.submapper(path_prefix='/entries', controller='entry',
diff --git a/tests/test_functional/test_utils.py b/tests/test_functional/test_utils.py index 3f4dd47..e2a6a04 100644 --- a/tests/test_functional/test_utils.py +++ b/tests/test_functional/test_utils.py @@ -62,6 +62,8 @@ class TestUtils(unittest.TestCase): eq_('/content', urlobj()) eq_('https://www.test.com/viewpost', urlobj(controller='post', action='view', protocol='https')) eq_('http://www.test.org/content', urlobj(host='www.test.org')) + eq_('//www.test.com/viewpost', urlobj(controller='post', action='view', protocol='')) + eq_('//www.test.org/content', urlobj(host='www.test.org', protocol='')) def test_url_raises(self): con = self.con |