Browse Source

url_for now supports no request context and no SERVER_NAME case

pull/1866/head
Jason Slay 9 years ago
parent
commit
e2daf87ab4
  1. 21
      flask/helpers.py
  2. 40
      tests/test_appctx.py

21
flask/helpers.py

@ -190,7 +190,24 @@ def make_response(*args):
return current_app.make_response(args) return current_app.make_response(args)
def url_for(endpoint, **values): def url_for(*args, **kwargs):
"""
wrapper based on https://github.com/miguelgrinberg/flack/blob/master/flack/utils.py
that also covers the case where application context exists with SERVER_NAME defined.
"""
reqctx = _request_ctx_stack.top
appctx = _app_ctx_stack.top
if reqctx is None and (appctx is None or appctx.url_adapter is None):
if kwargs.get('_external', False):
raise RuntimeError('Cannot generate external URLs without a '
'request context.')
with current_app.test_request_context():
return _url_for(*args, **kwargs)
return _url_for(*args, **kwargs)
def _url_for(endpoint, **values):
"""Generates a URL to the given endpoint with the method provided. """Generates a URL to the given endpoint with the method provided.
Variable arguments that are unknown to the target endpoint are appended Variable arguments that are unknown to the target endpoint are appended
@ -294,11 +311,13 @@ def url_for(endpoint, **values):
# the URLs external by default. # the URLs external by default.
else: else:
url_adapter = appctx.url_adapter url_adapter = appctx.url_adapter
# Due to the new url_for wrapper, url_adapter will never be None here
if url_adapter is None: if url_adapter is None:
raise RuntimeError('Application was not able to create a URL ' raise RuntimeError('Application was not able to create a URL '
'adapter for request independent URL generation. ' 'adapter for request independent URL generation. '
'You might be able to fix this by setting ' 'You might be able to fix this by setting '
'the SERVER_NAME config variable.') 'the SERVER_NAME config variable.')
external = values.pop('_external', True) external = values.pop('_external', True)
anchor = values.pop('_anchor', None) anchor = values.pop('_anchor', None)

40
tests/test_appctx.py

@ -16,7 +16,7 @@ import flask
def test_basic_url_generation(): def test_basic_url_generation():
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.config['SERVER_NAME'] = 'localhost' app.config['SERVER_NAME'] = 'somehost'
app.config['PREFERRED_URL_SCHEME'] = 'https' app.config['PREFERRED_URL_SCHEME'] = 'https'
@app.route('/') @app.route('/')
@ -25,13 +25,7 @@ def test_basic_url_generation():
with app.app_context(): with app.app_context():
rv = flask.url_for('index') rv = flask.url_for('index')
assert rv == 'https://localhost/' assert rv == 'https://somehost/'
def test_url_generation_requires_server_name():
app = flask.Flask(__name__)
with app.app_context():
with pytest.raises(RuntimeError):
flask.url_for('index')
def test_url_generation_without_context_fails(): def test_url_generation_without_context_fails():
with pytest.raises(RuntimeError): with pytest.raises(RuntimeError):
@ -49,6 +43,36 @@ def test_app_context_provides_current_app():
assert flask.current_app._get_current_object() == app assert flask.current_app._get_current_object() == app
assert flask._app_ctx_stack.top is None assert flask._app_ctx_stack.top is None
def test_url_for_without_server_name_or_app_context():
app = flask.Flask(__name__)
client = app.test_client()
@app.route('/endpoint')
def endpoint():
return 'Hello World!'
with app.app_context():
response = client.get(flask.url_for('endpoint', param='foo'))
assert response.status_code == 200
def test_get_with_arguments():
app = flask.Flask(__name__)
app.debug = True
@app.route('/echo')
def index():
assert 'key' in flask.request.args
return flask.jsonify( {'key': flask.request.args['key']} )
url = None
with app.test_request_context():
url = flask.url_for('index', key='test', _external=True)
assert url == 'http://localhost/echo?key=test'
rv = app.test_client().get(url)
assert b'"key": "test"' in rv.data
def test_app_tearing_down(): def test_app_tearing_down():
cleanup_stuff = [] cleanup_stuff = []
app = flask.Flask(__name__) app = flask.Flask(__name__)

Loading…
Cancel
Save