Skip to content

Commit

Permalink
[ADD] prohibited-method-override: New check to avoid overriding metho…
Browse files Browse the repository at this point in the history
…ds (#485)

A new check that identifies methods that were marked as prohibited to override
via super() calls. This lint check does not raise any errors, only warnings.

Signed-off-by: Pexers <[email protected]>
  • Loading branch information
Pexers authored Mar 27, 2024
1 parent 24d53bc commit 35cc929
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 1 deletion.
31 changes: 30 additions & 1 deletion src/pylint_odoo/checkers/odoo_addons.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
"W8103": ('Translation method _("string") in fields is not necessary.', "translation-field", CHECK_DESCRIPTION),
"W8105": ('attribute "%s" deprecated', "attribute-deprecated", CHECK_DESCRIPTION),
"W8106": ('Missing `super` call in "%s" method.', "method-required-super", CHECK_DESCRIPTION),
"W8107": ('Prohibited override of "%s" method.', "prohibited-method-override", CHECK_DESCRIPTION),
"W8110": ("Missing `return` (`super` is used) in method %s.", "missing-return", CHECK_DESCRIPTION),
"W8111": (
'Field parameter "%s" is no longer supported. Use "%s" instead.',
Expand Down Expand Up @@ -303,6 +304,7 @@
"unlink",
"write",
]
DFTL_PROHIBITED_OVERRIDE_METHODS = []
DFTL_CURSOR_EXPR = [
"cr", # old api
"self._cr", # new api
Expand Down Expand Up @@ -495,6 +497,15 @@ class OdooAddons(OdooBaseChecker, BaseChecker):
"help": "List of methods where call to `super` is required.separated by a comma.",
},
),
(
"prohibited-method-override",
{
"type": "csv",
"metavar": "<comma separated values>",
"default": DFTL_PROHIBITED_OVERRIDE_METHODS,
"help": "List of methods that have been marked as prohibited to override.",
},
),
(
"no-missing-return",
{
Expand Down Expand Up @@ -1188,7 +1199,9 @@ def check_deprecated_odoo_method(self, node: NodeNG) -> bool:

return node.name in self._deprecated_odoo_methods

@utils.only_required_for_messages("method-required-super", "missing-return", "deprecated-odoo-model-method")
@utils.only_required_for_messages(
"method-required-super", "prohibited-method-override", "missing-return", "deprecated-odoo-model-method"
)
def visit_functiondef(self, node):
"""Check that `api.one` and `api.multi` decorators not exists together
Check that method `copy` exists `api.one` decorator
Expand Down Expand Up @@ -1216,6 +1229,22 @@ def visit_functiondef(self, node):
there_is_super = True
break

# Verify if super attributes are prohibited methods to override
if there_is_super and self.linter.config.prohibited_method_override or DFTL_PROHIBITED_OVERRIDE_METHODS:
for attr in node.nodes_of_class(nodes.Attribute):
if attr.attrname != node.name:
continue
func = attr.expr.func
if (
isinstance(func, nodes.Name)
and func.name == "super"
and (
attr.attrname in self.linter.config.prohibited_method_override
or attr.attrname in DFTL_PROHIBITED_OVERRIDE_METHODS
)
):
self.add_message("prohibited-method-override", node=node, args=(attr.attrname,))

there_is_return = any(node.nodes_of_class(nodes.Return, skip_klass=(nodes.FunctionDef, nodes.ClassDef)))
if (
there_is_super
Expand Down
22 changes: 22 additions & 0 deletions testing/resources/test_repo/broken_module/tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,25 @@ def method1(self, example_var):
def test_1(self):
self.partner.message_post(body="Test", subtype="mail.mt_comment")
self.partner.message_post("Test", subtype="mail.mt_comment")

def test_base_method_1(self):
# Override prohibited, should fail
super().test_base_method_1()
# No override applied, should not fail
super().test_base_method_2()
return super().test_base_method_3()

def test_base_method_2(self):
# No override applied, should not fail
super(TestModel, self).test_base_method_1()
# Override allowed, should not fail
super(TestModel, self).test_base_method_2()
# No override applied, should not fail
return super(TestModel, self).test_base_method_3()

def test_base_method_3(self):
# No override applied, should not fail
super(TestModel, self).test_base_method_1()
super(TestModel, self).test_base_method_2()
# Override prohibited, should fail
return super(TestModel, self).test_base_method_3()
14 changes: 14 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,20 @@ def test_option_odoo_deprecated_model_method(self):
pylint_res.linter.stats.by_msg["deprecated-odoo-model-method"],
)

def test_175_prohibited_method_override(self):
"""Test --prohibited_override_methods parameter"""
extra_params = [
"--disable=all",
"--enable=prohibited-method-override",
"--prohibited-method-override=test_base_method_1,test_base_method_3",
]
pylint_res = self.run_pylint(self.paths_modules, extra_params, verbose=True)
real_errors = pylint_res.linter.stats.by_msg
expected_errors = {
"prohibited-method-override": 2,
}
self.assertDictEqual(real_errors, expected_errors)

@staticmethod
def re_replace(sub_start, sub_end, substitution, content):
re_sub = re.compile(rf"^{re.escape(sub_start)}$.*^{re.escape(sub_end)}$", re.M | re.S)
Expand Down

0 comments on commit 35cc929

Please sign in to comment.