Skip to content

Commit 9569e8c

Browse files
authored
Merge pull request pallets#2249 from davidism/provide-automatic-options
Continue pallets#1489: Add kwarg to disable auto OPTIONS on add_url_rule
2 parents f4a1ca8 + 97e2cd0 commit 9569e8c

File tree

3 files changed

+61
-4
lines changed

3 files changed

+61
-4
lines changed

CHANGES

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ Major release, unreleased
2121
- ``send_file`` supports Unicode in ``attachment_filename``. (`#2223`_)
2222
- Pass ``_scheme`` argument from ``url_for`` to ``handle_build_error``.
2323
(`#2017`_)
24+
- Add support for ``provide_automatic_options`` in ``add_url_rule`` to disable
25+
adding OPTIONS method when the ``view_func`` argument is not a class.
26+
(`#1489`_).
2427

28+
.. _#1489: https://github.com/pallets/flask/pull/1489
2529
.. _#2017: https://github.com/pallets/flask/pull/2017
2630
.. _#2223: https://github.com/pallets/flask/pull/2223
2731

flask/app.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -980,7 +980,7 @@ def iter_blueprints(self):
980980
return iter(self._blueprint_order)
981981

982982
@setupmethod
983-
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
983+
def add_url_rule(self, rule, endpoint=None, view_func=None, provide_automatic_options=None, **options):
984984
"""Connects a URL rule. Works exactly like the :meth:`route`
985985
decorator. If a view_func is provided it will be registered with the
986986
endpoint.
@@ -1020,6 +1020,10 @@ def index():
10201020
endpoint
10211021
:param view_func: the function to call when serving a request to the
10221022
provided endpoint
1023+
:param provide_automatic_options: controls whether the ``OPTIONS``
1024+
method should be added automatically. This can also be controlled
1025+
by setting the ``view_func.provide_automatic_options = False``
1026+
before adding the rule.
10231027
:param options: the options to be forwarded to the underlying
10241028
:class:`~werkzeug.routing.Rule` object. A change
10251029
to Werkzeug is handling of method options. methods
@@ -1049,8 +1053,9 @@ def index():
10491053

10501054
# starting with Flask 0.8 the view_func object can disable and
10511055
# force-enable the automatic options handling.
1052-
provide_automatic_options = getattr(view_func,
1053-
'provide_automatic_options', None)
1056+
if provide_automatic_options is None:
1057+
provide_automatic_options = getattr(view_func,
1058+
'provide_automatic_options', None)
10541059

10551060
if provide_automatic_options is None:
10561061
if 'OPTIONS' not in methods:

tests/test_basic.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def index_put():
5050
assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']
5151

5252

53-
def test_options_handling_disabled():
53+
def test_provide_automatic_options_attr():
5454
app = flask.Flask(__name__)
5555

5656
def index():
@@ -70,6 +70,54 @@ def index2():
7070
assert sorted(rv.allow) == ['OPTIONS']
7171

7272

73+
def test_provide_automatic_options_kwarg():
74+
app = flask.Flask(__name__)
75+
76+
def index():
77+
return flask.request.method
78+
79+
def more():
80+
return flask.request.method
81+
82+
app.add_url_rule('/', view_func=index, provide_automatic_options=False)
83+
app.add_url_rule(
84+
'/more', view_func=more, methods=['GET', 'POST'],
85+
provide_automatic_options=False
86+
)
87+
88+
c = app.test_client()
89+
assert c.get('/').data == b'GET'
90+
91+
rv = c.post('/')
92+
assert rv.status_code == 405
93+
assert sorted(rv.allow) == ['GET', 'HEAD']
94+
95+
# Older versions of Werkzeug.test.Client don't have an options method
96+
if hasattr(c, 'options'):
97+
rv = c.options('/')
98+
else:
99+
rv = c.open('/', method='OPTIONS')
100+
101+
assert rv.status_code == 405
102+
103+
rv = c.head('/')
104+
assert rv.status_code == 200
105+
assert not rv.data # head truncates
106+
assert c.post('/more').data == b'POST'
107+
assert c.get('/more').data == b'GET'
108+
109+
rv = c.delete('/more')
110+
assert rv.status_code == 405
111+
assert sorted(rv.allow) == ['GET', 'HEAD', 'POST']
112+
113+
if hasattr(c, 'options'):
114+
rv = c.options('/more')
115+
else:
116+
rv = c.open('/more', method='OPTIONS')
117+
118+
assert rv.status_code == 405
119+
120+
73121
def test_request_dispatching():
74122
app = flask.Flask(__name__)
75123

0 commit comments

Comments
 (0)