From 26f7064c3eb7535b9b1b946557a76d979c3659bc Mon Sep 17 00:00:00 2001 From: Moritz Ulmer Date: Sun, 6 Dec 2020 21:07:56 +0100 Subject: [PATCH 1/2] [refs #263] Add test for tuples in TextChoice Why: - Test that the fields label and value are not marked as missing This change addresses the need by: - Adding a test to ensure that pylint does not mark these as errors --- .../tests/input/func_noerror_model_enum.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 pylint_django/tests/input/func_noerror_model_enum.py diff --git a/pylint_django/tests/input/func_noerror_model_enum.py b/pylint_django/tests/input/func_noerror_model_enum.py new file mode 100644 index 00000000..91b38a74 --- /dev/null +++ b/pylint_django/tests/input/func_noerror_model_enum.py @@ -0,0 +1,23 @@ +""" +Test that django TextChoices does not raise a warning due to .label and .value methods +""" +# pylint: disable=missing-docstring,too-few-public-methods + +from django.db import models + + +class SomeTextChoices(models.TextChoices): + CHOICE_A = ("choice_a", "Choice A") + CHOICE_B = ("choice_b", "Choice B") + CHOICE_C = ("choice_c", "Choice C") + + +class SomeClass(): + choice_values = [ + SomeTextChoices.CHOICE_A.value, + SomeTextChoices.CHOICE_B.value, + ] + choice_labels = [ + SomeTextChoices.CHOICE_B.label, + SomeTextChoices.CHOICE_C.label, + ] From 2815db76071c8bde7153025af6a35e472b810988 Mon Sep 17 00:00:00 2001 From: Moritz Ulmer Date: Thu, 14 Jan 2021 16:27:55 +0100 Subject: [PATCH 2/2] [refs #263] Add initial transform code for text choices Why: - Transform tuples to include value and label properties This change addresses the need by: - Adding the text_choices transform file - Integrating in the transforms init file - Focusing on the predicate for the rule to trigger the transform --- pylint_django/transforms/__init__.py | 4 +- pylint_django/transforms/text_choices.py | 70 ++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 pylint_django/transforms/text_choices.py diff --git a/pylint_django/transforms/__init__.py b/pylint_django/transforms/__init__.py index 03930d3d..2154c47f 100644 --- a/pylint_django/transforms/__init__.py +++ b/pylint_django/transforms/__init__.py @@ -13,10 +13,10 @@ import astroid -from pylint_django.transforms import fields +from pylint_django.transforms import fields, text_choices fields.add_transforms(astroid.MANAGER) - +text_choices.add_transforms(astroid.MANAGER) def _add_transform(package_name): def fake_module_builder(): diff --git a/pylint_django/transforms/text_choices.py b/pylint_django/transforms/text_choices.py new file mode 100644 index 00000000..d923e656 --- /dev/null +++ b/pylint_django/transforms/text_choices.py @@ -0,0 +1,70 @@ +from astroid import MANAGER, scoped_nodes, nodes, inference_tip + +from pylint_django import utils + +class_names = set() + +def is_tuple_in_text_choices(node): + # file_name = node.root().file + # if file_name not in file_names: + # file_names.update({file_name}) + # import ipdb; ipdb.set_trace() + # else: + # return False + + if not (isinstance(node.parent, nodes.Assign) + or isinstance(node.parent, nodes.FunctionDef)) : + return False + if not isinstance(node.parent.parent, nodes.ClassDef): + return False + if "TextChoices" in [i.name for i in node.parent.parent.bases]: + import ipdb; ipdb.set_trace() + + class_name = node.parent.parent.name + if class_name not in class_names: + class_names.update({class_name}) + # import ipdb; ipdb.set_trace() + else: + return False + + # if node.parent.parent.name == "SomeTextChoices": + # import ipdb; ipdb.set_trace() + # else: + # return False + + # if node.parent.parent.parent.name in ["TextChoices", "SomeClass", "ChoicesMeta", "TextChoices"]: + # import ipdb; ipdb.set_trace() + # else: + # return False + + # if node.root().file.endswith("enums.py"): + # import ipdb; ipdb.set_trace() + # else: + # return False + + # try: + # if node.root().file.endswith("model_enum.py"): + # import ipdb; ipdb.set_trace() + # except: + # import ipdb; ipdb.set_trace() + # if (node.parent.parent.name != "LazyObject" + # and node.parent.parent.parent.name != "django.db.models.expressions" + # and node.parent.parent.parent.name != "django.db.models.fields"): + # import ipdb; ipdb.set_trace() + + if isinstance(node.func, nodes.Attribute): + attr = node.func.attrname + elif isinstance(node.func, nodes.Name): + attr = node.func.name + else: + return False + return True + + +def infer_key_classes(node, context=None): + pass + + +def add_transforms(manager): + manager.register_transform(nodes.Call, inference_tip(infer_key_classes), + is_tuple_in_text_choices)