Prevent use filter(lambda obj: test(obj), data)

In Python3 [1], if we need filter on python3, replace
filter(lambda obj: test(obj), data) with:
[obj for obj in data if test(obj)]. This patch replaces
filter function and introduces a hacking rule to prevent
using filter in future.

[1] https://wiki.openstack.org/wiki/Python3

Change-Id: I83d22108c02f8da007a7233e71a4a7fb833170ec
This commit is contained in:
Nguyen Phuong An 2016-08-29 18:15:30 +07:00
parent 9a2e0b7669
commit 9afb9ca598
6 changed files with 31 additions and 7 deletions

View File

@ -29,6 +29,8 @@ Neutron Specific Commandments
- [N340] Check usage of <module>.i18n (and neutron.i18n) - [N340] Check usage of <module>.i18n (and neutron.i18n)
- [N341] Check usage of _ from python builtins - [N341] Check usage of _ from python builtins
- [N342] String interpolation should be delayed at logging calls. - [N342] String interpolation should be delayed at logging calls.
- [N344] Python 3: Do not use filter(lambda obj: test(obj), data). Replace it
with [obj for obj in data if test(obj)].
Creating Unit Tests Creating Unit Tests
------------------- -------------------

View File

@ -75,6 +75,7 @@ log_warn = re.compile(
r"(.)*LOG\.(warn)\(\s*('|\"|_)") r"(.)*LOG\.(warn)\(\s*('|\"|_)")
unittest_imports_dot = re.compile(r"\bimport[\s]+unittest\b") unittest_imports_dot = re.compile(r"\bimport[\s]+unittest\b")
unittest_imports_from = re.compile(r"\bfrom[\s]+unittest\b") unittest_imports_from = re.compile(r"\bfrom[\s]+unittest\b")
filter_match = re.compile(r".*filter\(lambda ")
@flake8ext @flake8ext
@ -381,6 +382,17 @@ def check_delayed_string_interpolation(logical_line, filename, noqa):
yield(0, msg) yield(0, msg)
@flake8ext
def check_python3_no_filter(logical_line):
"""N344 - Use list comprehension instead of filter(lambda)."""
msg = ("N343: Use list comprehension instead of "
"filter(lambda obj: test(obj), data) on python3.")
if filter_match.match(logical_line):
yield(0, msg)
def factory(register): def factory(register):
register(validate_log_translations) register(validate_log_translations)
register(use_jsonutils) register(use_jsonutils)
@ -400,3 +412,4 @@ def factory(register):
register(check_builtins_gettext) register(check_builtins_gettext)
register(check_unittest_imports) register(check_unittest_imports)
register(check_delayed_string_interpolation) register(check_delayed_string_interpolation)
register(check_python3_no_filter)

View File

@ -212,8 +212,8 @@ class QosPolicy(rbac_db.NeutronRbacObject):
def obj_make_compatible(self, primitive, target_version): def obj_make_compatible(self, primitive, target_version):
def filter_rules(obj_names, rules): def filter_rules(obj_names, rules):
return filter(lambda rule: return [rule for rule in rules if
(rule['versioned_object.name'] in obj_names), rules) rule['versioned_object.name'] in obj_names]
_target_version = versionutils.convert_version_to_tuple(target_version) _target_version = versionutils.convert_version_to_tuple(target_version)
names = [] names = []

View File

@ -112,7 +112,7 @@ def _build_subattr_match_rule(attr_name, attr, action, target):
# typing for API attributes # typing for API attributes
# Expect a dict as type descriptor # Expect a dict as type descriptor
validate = attr['validate'] validate = attr['validate']
key = list(filter(lambda k: k.startswith('type:dict'), validate.keys())) key = [k for k in validate.keys() if k.startswith('type:dict')]
if not key: if not key:
LOG.warning(_LW("Unable to find data type descriptor " LOG.warning(_LW("Unable to find data type descriptor "
"for attribute %s"), "for attribute %s"),

View File

@ -110,13 +110,15 @@ class SubnetPoolsTest(SubnetPoolsTestBase):
body = self._create_subnetpool(description='d1') body = self._create_subnetpool(description='d1')
self.assertEqual('d1', body['description']) self.assertEqual('d1', body['description'])
sub_id = body['id'] sub_id = body['id']
body = filter(lambda x: x['id'] == sub_id, subnet_pools = [x for x in
self.client.list_subnetpools()['subnetpools'])[0] self.client.list_subnetpools()['subnetpools'] if x['id'] == sub_id]
body = subnet_pools[0]
self.assertEqual('d1', body['description']) self.assertEqual('d1', body['description'])
body = self.client.update_subnetpool(sub_id, description='d2') body = self.client.update_subnetpool(sub_id, description='d2')
self.assertEqual('d2', body['subnetpool']['description']) self.assertEqual('d2', body['subnetpool']['description'])
body = filter(lambda x: x['id'] == sub_id, subnet_pools = [x for x in
self.client.list_subnetpools()['subnetpools'])[0] self.client.list_subnetpools()['subnetpools'] if x['id'] == sub_id]
body = subnet_pools[0]
self.assertEqual('d2', body['description']) self.assertEqual('d2', body['description'])
@test.idempotent_id('741d08c2-1e3f-42be-99c7-0ea93c5b728c') @test.idempotent_id('741d08c2-1e3f-42be-99c7-0ea93c5b728c')

View File

@ -339,6 +339,13 @@ class HackingTestCase(base.BaseTestCase):
self.assertEqual( self.assertEqual(
1, len(list(checks.check_log_warn_deprecated(bad, 'f')))) 1, len(list(checks.check_log_warn_deprecated(bad, 'f'))))
def test_check_python3_filter(self):
f = checks.check_python3_no_filter
self.assertLineFails(f, "filter(lambda obj: test(obj), data)")
self.assertLinePasses(f, "[obj for obj in data if test(obj)]")
self.assertLinePasses(f, "filter(function, range(0,10))")
self.assertLinePasses(f, "lambda x, y: x+y")
# The following is borrowed from hacking/tests/test_doctest.py. # The following is borrowed from hacking/tests/test_doctest.py.
# Tests defined in docstring is easier to understand # Tests defined in docstring is easier to understand
# in some cases, for example, hacking rules which take tokens as argument. # in some cases, for example, hacking rules which take tokens as argument.