diff --git a/pylint_odoo/checkers/no_modules.py b/pylint_odoo/checkers/no_modules.py index 79095621..692a3a81 100644 --- a/pylint_odoo/checkers/no_modules.py +++ b/pylint_odoo/checkers/no_modules.py @@ -196,6 +196,12 @@ 'eval-referenced', settings.DESC_DFLT ), + 'W%d13' % settings.BASE_NOMODULE_ID: ( + 'The attribute string is redundant. ' + 'String parameter equal to name of variable', + 'attribute-string-redundant', + settings.DESC_DFLT + ), } DFTL_MANIFEST_REQUIRED_KEYS = ['license'] @@ -231,6 +237,13 @@ DFTL_NO_MISSING_RETURN = [ '__init__', 'setUp', 'tearDown', ] +FIELDS_METHOD = { + 'Many2many': 4, + 'One2many': 2, + 'Many2one': 1, + 'Reference': 1, + 'Selection': 1, +} DFTL_DEPRECATED_FIELD_PARAMETERS = [ # From odoo/odoo 10.0: odoo/odoo/fields.py:29 'digits_compute:digits', 'select:index' @@ -358,13 +371,24 @@ def colon_list_to_dict(self, colon_list): @utils.check_messages('translation-field', 'invalid-commit', 'method-compute', 'method-search', 'method-inverse', 'sql-injection', + 'attribute-string-redundant', 'renamed-field-parameter' ) def visit_call(self, node): if node.as_string().lower().startswith('fields.'): args = misc.join_node_args_kwargs(node) + index = 0 for argument in args: argument_aux = argument + # Check this 'name = fields.Char("name")' + field_name = (argument.parent.parent.targets[0].name + .replace('_', ' ')) + if (isinstance(argument, astroid.Const) and + (index == + FIELDS_METHOD.get(argument.parent.func.attrname, 0)) and + (argument.value in + [field_name.capitalize(), field_name.title()])): + self.add_message('attribute-string-redundant', node=node) if isinstance(argument, astroid.Keyword): argument_aux = argument.value deprecated = self.config.deprecated_field_parameters @@ -375,6 +399,13 @@ def visit_call(self, node): '_' + argument.arg + '_'): self.add_message('method-' + argument.arg, node=argument_aux) + # Check if the param string is equal to the name + # of variable + elif argument.arg == 'string' and \ + (argument.value.value in + [field_name.capitalize(), field_name.title()]): + self.add_message( + 'attribute-string-redundant', node=node) elif (argument.arg in deprecated): self.add_message( 'renamed-field-parameter', node=node, @@ -384,6 +415,7 @@ def visit_call(self, node): isinstance(argument_aux.func, astroid.Name) and \ argument_aux.func.name == '_': self.add_message('translation-field', node=argument_aux) + index += 1 # Check cr.commit() if isinstance(node, astroid.CallFunc) and \ isinstance(node.func, astroid.Getattr) and \ diff --git a/pylint_odoo/test/main.py b/pylint_odoo/test/main.py index 39827893..a6ce4dc4 100644 --- a/pylint_odoo/test/main.py +++ b/pylint_odoo/test/main.py @@ -58,6 +58,7 @@ 'wrong-tabs-instead-of-spaces': 2, 'eval-referenced': 5, 'xml-syntax-error': 2, + 'attribute-string-redundant': 33, 'renamed-field-parameter': 2, 'xml-attribute-translatable': 1, } diff --git a/pylint_odoo/test_repo/broken_module/models/broken_model.py b/pylint_odoo/test_repo/broken_module/models/broken_model.py index bcab36f0..7af38545 100644 --- a/pylint_odoo/test_repo/broken_module/models/broken_model.py +++ b/pylint_odoo/test_repo/broken_module/models/broken_model.py @@ -47,6 +47,7 @@ class TestModel(models.Model): ) my_ok_field = fields.Float( + "My correctly named field", digits=(6, 6), # OK: Valid field parameter index=True, # OK: Valid field parameter help="My ok field", @@ -56,6 +57,108 @@ class TestModel(models.Model): digits_compute=lambda cr: (6, 6), # Deprecated field parameter select=True, # Deprecated field parameter help="My ko field", + string="My Ko Field", # String parameter equal to name of variable + ) + + """The name of the variable is equal to the string parameter + Tested all fields.*""" + + boolean_variable_1 = fields.Boolean(string='Boolean Variable 1', + help="Help") + boolean_variable_2 = fields.Boolean("Boolean Variable 2", help="Help") + + char_variable_1 = fields.Char(string='Char Variable 1', help="Help") + char_variable_2 = fields.Char("Char Variable 2", help="Help") + + text_variable_1 = fields.Text(string='Text Variable 1', help="Help") + text_variable_2 = fields.Text("Text Variable 2", help="Help") + + html_variable_1 = fields.Html(string='Html Variable 1', help="Help") + html_variable_2 = fields.Html("Html Variable 2", help="Help") + + integer_variable_1 = fields.Integer(string='Integer Variable 1', + help="Help") + integer_variable_2 = fields.Integer("Integer Variable 2", help="Help") + + float_variable_1 = fields.Float(string='Float Variable 1', help="Help") + float_variable_2 = fields.Float("Float Variable 2", help="Help") + + date_variable_1 = fields.Date(string='Date Variable 1', help="Help") + date_variable_2 = fields.Date("Date Variable 2", help="Help") + + date_time_variable_1 = fields.DateTime(string='Date Time Variable 1', + help="Help") + date_time_variable_2 = fields.DateTime("Date Time Variable 2", help="Help") + + binary_variable_1 = fields.Binary(string='Binary Variable 1', help="Help") + binary_variable_2 = fields.Binary("Binary Variable 2", help="Help") + + selection_variable_1 = fields.Selection(selection=[('a', 'A')], + string='Selection Variable 1', + help="Help") + selection_variable_2 = fields.Selection([('a', 'A')], + "Selection Variable 2", + help="Help") + + reference_variable_1 = fields.Reference(selection=[('res.user', 'User')], + string="Reference Variable 1", + help="Help") + reference_variable_2 = fields.Reference([('res.user', 'User')], + "Reference Variable 2", + help="Help") + + many_2_one_variable_1 = fields.Many2one(comodel_name='res.users', + string='Many 2 One Variable 1', + help="Help") + many_2_one_variable_2 = fields.Many2one('res.users', + "Many 2 One Variable 2", + help="Help") + + one_2_many_variable_1 = fields.One2many(comodel_name='res.users', + inverse_name='rel_id', + string='One 2 Many Variable 1', + help="Help") + one_2_many_variable_2 = fields.One2many('res.users', + 'rel_id', + "One 2 Many Variable 2", + help="Help") + + many_2_many_variable_1 = fields.Many2many(comodel_name='res.users', + relation='table_name', + column1='col_name', + column2='other_col_name', + string='Many 2 Many Variable 1', + help="Help") + many_2_many_variable_2 = fields.Many2many('res.users', + 'table_name', + 'col_name', + 'other_col_name', + "Many 2 Many Variable 2", + help="Help") + + field_case_sensitive = fields.Char( + 'Field Case SENSITIVE', + help="Field case sensitive" + ) + + name_equal_to_string = fields.Float( + "Name equal to string", + help="Name Equal To String" + ) + + many_2_one = fields.Many2one( + 'res.users', + "Many 2 One", + help="Many 2 one" + ) + + many_2_many = fields.Many2many( + 'res.users', + 'relation', + 'fk_column_from', + 'fk_column_to', + "Many 2 many", + help="Many 2 Many" ) def my_method1(self, variable1):