improve url_for to support multi values for one arg, add _anchor/_external/_scheme options
This commit is contained in:
parent
7401facc21
commit
cf2a363e5e
|
@ -230,6 +230,16 @@ class Sanic:
|
|||
matched_params = re.findall(
|
||||
self.router.parameter_pattern, uri)
|
||||
|
||||
# _method is only a placeholder now, don't know how to support it
|
||||
kwargs.pop('_method', None)
|
||||
anchor = kwargs.pop('_anchor', '')
|
||||
# _external need SERVER_NAME in config or pass _server arg
|
||||
external = kwargs.pop('_external', False)
|
||||
scheme = kwargs.pop('_scheme', '')
|
||||
if scheme and not external:
|
||||
raise ValueError('When specifying _scheme, _external must be True')
|
||||
|
||||
netloc = kwargs.pop('_server', self.config.get('SERVER_NAME', ''))
|
||||
for match in matched_params:
|
||||
name, _type, pattern = self.router.parse_parameter_string(
|
||||
match)
|
||||
|
@ -271,11 +281,9 @@ class Sanic:
|
|||
|
||||
# parse the remainder of the keyword arguments into a querystring
|
||||
if kwargs:
|
||||
query_string = urlencode(kwargs)
|
||||
out = urlunparse((
|
||||
'', '', out,
|
||||
'', query_string, ''
|
||||
))
|
||||
query_string = urlencode(kwargs, doseq=True)
|
||||
# scheme://netloc/path;parameters?query#fragment
|
||||
out = urlunparse((scheme, netloc, out, '', query_string, anchor))
|
||||
|
||||
return out
|
||||
|
||||
|
|
|
@ -6,7 +6,11 @@ PORT = 42101
|
|||
|
||||
|
||||
async def local_request(method, uri, cookies=None, *args, **kwargs):
|
||||
url = 'http://{host}:{port}{uri}'.format(host=HOST, port=PORT, uri=uri)
|
||||
if uri.startswith(('http:', 'https:', 'ftp:', 'ftps://' '//')):
|
||||
url = uri
|
||||
else:
|
||||
url = 'http://{host}:{port}{uri}'.format(host=HOST, port=PORT, uri=uri)
|
||||
|
||||
log.info(url)
|
||||
async with aiohttp.ClientSession(cookies=cookies) as session:
|
||||
async with getattr(
|
||||
|
|
|
@ -5,7 +5,7 @@ from sanic import Sanic
|
|||
from sanic.response import text
|
||||
from sanic.views import HTTPMethodView
|
||||
from sanic.blueprints import Blueprint
|
||||
from sanic.utils import sanic_endpoint_test
|
||||
from sanic.utils import sanic_endpoint_test, PORT as test_port
|
||||
from sanic.exceptions import URLBuildError
|
||||
|
||||
import string
|
||||
|
@ -39,6 +39,30 @@ def test_simple_url_for_getting(simple_app):
|
|||
assert response.text == letter
|
||||
|
||||
|
||||
def test_simple_url_for_getting_with_duplicate_params(simple_app):
|
||||
kw = dict(arg1=['value1', 'value2'], _anchor='anchor')
|
||||
for letter in string.ascii_letters:
|
||||
url = simple_app.url_for(letter, **kw)
|
||||
|
||||
assert url == '/{}?arg1=value1&arg1=value2#anchor'.format(letter)
|
||||
request, response = sanic_endpoint_test(simple_app, uri=url)
|
||||
assert response.status == 200
|
||||
assert response.text == letter
|
||||
|
||||
|
||||
def test_simple_url_for_getting_with_special_params(simple_app):
|
||||
kw = dict(arg1='value1', _anchor='anchor', _scheme='http',
|
||||
_server='localhost:{}'.format(test_port), _external=True)
|
||||
url_fmt = 'http://localhost:{}/{}?arg1=value1#anchor'
|
||||
for letter in string.ascii_letters:
|
||||
url = simple_app.url_for(letter, **kw)
|
||||
|
||||
assert url == url_fmt.format(test_port, letter)
|
||||
request, response = sanic_endpoint_test(simple_app, uri=url)
|
||||
assert response.status == 200
|
||||
assert response.text == letter
|
||||
|
||||
|
||||
def test_fails_if_endpoint_not_found():
|
||||
app = Sanic('fail_url_build')
|
||||
|
||||
|
@ -75,6 +99,19 @@ def test_fails_url_build_if_param_not_passed():
|
|||
assert 'Required parameter `Z` was not passed to url_for' in str(e.value)
|
||||
|
||||
|
||||
def test_fails_url_build_if_params_not_passed():
|
||||
app = Sanic('fail_url_build')
|
||||
|
||||
@app.route('/fail')
|
||||
def fail():
|
||||
return text('this should fail')
|
||||
|
||||
with pytest.raises(ValueError) as e:
|
||||
app.url_for('fail', _scheme='http')
|
||||
|
||||
assert str(e.value) == 'When specifying _scheme, _external must be True'
|
||||
|
||||
|
||||
COMPLEX_PARAM_URL = (
|
||||
'/<foo:int>/<four_letter_string:[A-z]{4}>/'
|
||||
'<two_letter_string:[A-z]{2}>/<normal_string>/<some_number:number>')
|
||||
|
@ -179,11 +216,11 @@ def blueprint_app():
|
|||
return text(
|
||||
'foo from first : {}'.format(param))
|
||||
|
||||
@second_print.route('/foo') # noqa
|
||||
@second_print.route('/foo') # noqa
|
||||
def foo():
|
||||
return text('foo from second')
|
||||
|
||||
@second_print.route('/foo/<param>') # noqa
|
||||
@second_print.route('/foo/<param>') # noqa
|
||||
def foo_with_param(request, param):
|
||||
return text(
|
||||
'foo from second : {}'.format(param))
|
||||
|
|
Loading…
Reference in New Issue
Block a user