Improve api_version decorator to avoid noqa

Our existing `api_version` decorator for microversions forces us to use
"# noqa" if we have multiple microversions of a method in the same
class, providing no way around this.

This patch adds a way to avoid using noqa directive.  Previously we
would have:

 @wsgi.Controller.api_version("3.3")
 def my_api_method(self, req, id):
     .... method_1 ...

 @wsgi.Controller.api_version("3.4")  # noqa
 def my_api_method(self, req, id):
     .... method_2 ...

With this patch the second method does not require noqa anymore:

 @my_api_method.api_version("3.4")
 def my_api_method(self, req, id):
     .... method_2 ...

Devref is updated to reflect this new change and to mention that it is
the recommended way to do it.

Change-Id: I46283b52cc6a347d5deb0f57a123eba4e01a3eb2
Closes-Bug: #1599806
This commit is contained in:
Gorka Eguileor 2016-07-07 13:14:40 +02:00
parent 0cd9b10c0a
commit a8edbd2e8d
4 changed files with 25 additions and 11 deletions

View File

@ -1220,6 +1220,12 @@ class Controller(object):
# ranges of valid versions as that is ambiguous
func_list.sort(reverse=True)
# NOTE(geguileo): To avoid PEP8 errors when defining multiple
# microversions of the same method in the same class we add the
# api_version decorator to the function so it can be used instead,
# thus preventing method redefinition errors.
f.api_version = cls.api_version
return f
return decorator

View File

@ -100,7 +100,7 @@ class VersionsController(wsgi.Controller):
known_versions.pop('v3.0')
return builder.build_versions(known_versions)
@wsgi.Controller.api_version('2.0') # noqa
@index.api_version('2.0')
def index(self, req): # pylint: disable=E0102
"""Return versions supported prior to the microversions epoch."""
builder = views_versions.get_view_builder(req)
@ -109,7 +109,7 @@ class VersionsController(wsgi.Controller):
known_versions.pop('v3.0')
return builder.build_versions(known_versions)
@wsgi.Controller.api_version('3.0') # noqa
@index.api_version('3.0')
def index(self, req): # pylint: disable=E0102
"""Return versions supported after the start of microversions."""
builder = views_versions.get_view_builder(req)

View File

@ -262,7 +262,8 @@ class VersionsControllerTestCase(test.TestCase):
('3.2', 'index', 'child 3.2', 'ControllerChild'),
('3.2', 'show', 404, 'ControllerChild'),
('3.3', 'index', 'child 3.3', 'ControllerChild'),
('3.3', 'show', 'show', 'ControllerChild'))
('3.3', 'show', 'show', 'ControllerChild'),
('3.4', 'index', 'child 3.4', 'ControllerChild'))
@ddt.unpack
def test_versions_inheritance_of_non_base_controller(self, version, call,
expected, controller):
@ -287,12 +288,14 @@ class VersionsControllerTestCase(test.TestCase):
def index(self, req):
return 'child 3.2'
# TODO(geguileo): Figure out a way to make microversions work in a
# way that doesn't raise complaints from duplicated method.
@wsgi.Controller.api_version('3.3') # noqa
@index.api_version('3.3')
def index(self, req):
return 'child 3.3'
@index.api_version('3.4')
def index(self, req):
return 'child 3.4'
@wsgi.Controller.api_version('3.3')
def show(self, req, *args, **kwargs):
return 'show'

View File

@ -186,7 +186,7 @@ In the controller class::
def my_api_method(self, req, id):
.... method_1 ...
@wsgi.Controller.api_version("3.4") # noqa
@my_api_method.api_version("3.4")
def my_api_method(self, req, id):
.... method_2 ...
@ -194,10 +194,15 @@ If a caller specified ``3.1``, ``3.2`` or ``3.3`` (or received the
default of ``3.1``) they would see the result from ``method_1``,
``3.4`` or later ``method_2``.
It is vital that the two methods have the same name, so the second of
them will need ``# noqa`` to avoid failing flake8's ``F811`` rule. The
two methods may be different in any kind of semantics (schema
validation, return values, response codes, etc)
We could use ``wsgi.Controller.api_version`` decorator on the second
``my_api_method`` as well, but then we would have to add ``# no qa`` to that
line to avoid failing flake8's ``F811`` rule. So the recommended approach is
to use the ``api_version`` decorator from the first method that is defined, as
illustrated by the example above, and then use ``my_api_method`` decorator for
subsequent api versions of the same method.
The two methods may be different in any kind of semantics (schema validation,
return values, response codes, etc.).
A method with only small changes between versions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~