diff options
author | Robert Hofer <hofrob@protonmail.com> | 2022-10-30 16:26:07 +0100 |
---|---|---|
committer | Daniƫl van Noord <13665637+DanielNoord@users.noreply.github.com> | 2022-11-09 20:39:00 +0100 |
commit | 0507ee37f45cb3c9dcaf64036dd1b7f3c88ae690 (patch) | |
tree | 7ec3b2adc6e9841ec73d7f4aa5ac58ce36e24808 | |
parent | 5ae5842fa02021e086d66218d326c708e6433318 (diff) | |
download | pylint-git-0507ee37f45cb3c9dcaf64036dd1b7f3c88ae690.tar.gz |
Add R1737 use-dict-literal-without-kwargs
23 files changed, 286 insertions, 175 deletions
diff --git a/doc/data/messages/u/use-dict-literal/bad.py b/doc/data/messages/u/use-dict-literal/bad.py index 6c3056b6f..2d90a91e8 100644 --- a/doc/data/messages/u/use-dict-literal/bad.py +++ b/doc/data/messages/u/use-dict-literal/bad.py @@ -1 +1,3 @@ empty_dict = dict() # [use-dict-literal] +new_dict = dict(foo="bar") # [use-dict-literal] +new_dict = dict(**another_dict) # [use-dict-literal] diff --git a/doc/data/messages/u/use-dict-literal/details.rst b/doc/data/messages/u/use-dict-literal/details.rst new file mode 100644 index 000000000..f07532ead --- /dev/null +++ b/doc/data/messages/u/use-dict-literal/details.rst @@ -0,0 +1,4 @@ +https://gist.github.com/hofrob/ad143aaa84c096f42489c2520a3875f9
+
+This example script shows an 18% increase in performance when using a literal over the
+constructor in python version 3.10.6.
diff --git a/doc/data/messages/u/use-dict-literal/good.py b/doc/data/messages/u/use-dict-literal/good.py index 5f7d64deb..237d2c881 100644 --- a/doc/data/messages/u/use-dict-literal/good.py +++ b/doc/data/messages/u/use-dict-literal/good.py @@ -1 +1,7 @@ empty_dict = {} + +# create using a literal dict +new_dict = {"foo": "bar"} + +# shallow copy a dict +new_dict = {**another_dict} diff --git a/doc/user_guide/checkers/features.rst b/doc/user_guide/checkers/features.rst index 916f8c8f4..07d48d34f 100644 --- a/doc/user_guide/checkers/features.rst +++ b/doc/user_guide/checkers/features.rst @@ -781,9 +781,9 @@ Refactoring checker Messages :consider-swap-variables (R1712): *Consider using tuple unpacking for swapping variables* You do not have to use a temporary variable in order to swap variables. Using "tuple unpacking" to directly swap variables makes the intention more clear. -:use-dict-literal (R1735): *Consider using {} instead of dict()* - Emitted when using dict() to create an empty dictionary instead of the - literal {}. The literal is faster as it avoids an additional function call. +:use-dict-literal (R1735): *Consider using '%s' instead.* + Emitted when using dict() to create a dictionary instead of a literal '{ ... }'. + The literal is faster as it avoids an additional function call. :trailing-comma-tuple (R1707): *Disallow trailing comma tuple* In Python, a tuple is actually created by the comma symbol, not by the parentheses. Unfortunately, one can actually create a tuple by misplacing a diff --git a/doc/whatsnew/fragments/7690.new_check b/doc/whatsnew/fragments/7690.new_check new file mode 100644 index 000000000..2969428ed --- /dev/null +++ b/doc/whatsnew/fragments/7690.new_check @@ -0,0 +1,3 @@ +Extended ``use-dict-literal`` to also warn about call to ``dict()`` when passing keyword arguments. + +Closes #7690 diff --git a/pylint/checkers/refactoring/refactoring_checker.py b/pylint/checkers/refactoring/refactoring_checker.py index 34856749f..df3c3bccc 100644 --- a/pylint/checkers/refactoring/refactoring_checker.py +++ b/pylint/checkers/refactoring/refactoring_checker.py @@ -464,9 +464,9 @@ class RefactoringChecker(checkers.BaseTokenChecker): "The literal is faster as it avoids an additional function call.", ), "R1735": ( - "Consider using {} instead of dict()", + "Consider using '%s' instead of a call to 'dict'.", "use-dict-literal", - "Emitted when using dict() to create an empty dictionary instead of the literal {}. " + "Emitted when using dict() to create a dictionary instead of a literal '{ ... }'. " "The literal is faster as it avoids an additional function call.", ), "R1736": ( @@ -1074,7 +1074,8 @@ class RefactoringChecker(checkers.BaseTokenChecker): self._check_super_with_arguments(node) self._check_consider_using_generator(node) self._check_consider_using_with(node) - self._check_use_list_or_dict_literal(node) + self._check_use_list_literal(node) + self._check_use_dict_literal(node) @staticmethod def _has_exit_in_scope(scope: nodes.LocalsDictNodeNG) -> bool: @@ -1590,15 +1591,46 @@ class RefactoringChecker(checkers.BaseTokenChecker): if could_be_used_in_with and not _will_be_released_automatically(node): self.add_message("consider-using-with", node=node) - def _check_use_list_or_dict_literal(self, node: nodes.Call) -> None: - """Check if empty list or dict is created by using the literal [] or {}.""" - if node.as_string() in {"list()", "dict()"}: + def _check_use_list_literal(self, node: nodes.Call) -> None: + """Check if empty list is created by using the literal [].""" + if node.as_string() == "list()": inferred = utils.safe_infer(node.func) if isinstance(inferred, nodes.ClassDef) and not node.args: if inferred.qname() == "builtins.list": self.add_message("use-list-literal", node=node) - elif inferred.qname() == "builtins.dict" and not node.keywords: - self.add_message("use-dict-literal", node=node) + + def _check_use_dict_literal(self, node: nodes.Call) -> None: + """Check if dict is created by using the literal {}.""" + if not isinstance(node.func, astroid.Name) or node.func.name != "dict": + return + inferred = utils.safe_infer(node.func) + if ( + isinstance(inferred, nodes.ClassDef) + and inferred.qname() == "builtins.dict" + and not node.args + ): + self.add_message( + "use-dict-literal", + args=(self._dict_literal_suggestion(node),), + node=node, + confidence=INFERENCE, + ) + + @staticmethod + def _dict_literal_suggestion(node: nodes.Call) -> str: + """Return a suggestion of reasonable length.""" + elements: list[str] = [] + for keyword in node.keywords: + if len(", ".join(elements)) >= 64: + break + if keyword not in node.kwargs: + elements.append(f'"{keyword.arg}": {keyword.value.as_string()}') + for keyword in node.kwargs: + if len(", ".join(elements)) >= 64: + break + elements.append(f"**{keyword.value.as_string()}") + suggestion = ", ".join(elements) + return f"{{{suggestion}{', ... ' if len(suggestion) > 64 else ''}}}" def _check_consider_using_join(self, aug_assign: nodes.AugAssign) -> None: """We start with the augmented assignment and work our way upwards. diff --git a/pylint/pyreverse/dot_printer.py b/pylint/pyreverse/dot_printer.py index 5ec5858fc..7579d2877 100644 --- a/pylint/pyreverse/dot_printer.py +++ b/pylint/pyreverse/dot_printer.py @@ -29,13 +29,17 @@ SHAPES: dict[NodeType, str] = { NodeType.INTERFACE: "record", NodeType.CLASS: "record", } +# pylint: disable-next=consider-using-namedtuple-or-dataclass ARROWS: dict[EdgeType, dict[str, str]] = { - EdgeType.INHERITS: dict(arrowtail="none", arrowhead="empty"), - EdgeType.IMPLEMENTS: dict(arrowtail="node", arrowhead="empty", style="dashed"), - EdgeType.ASSOCIATION: dict( - fontcolor="green", arrowtail="none", arrowhead="diamond", style="solid" - ), - EdgeType.USES: dict(arrowtail="none", arrowhead="open"), + EdgeType.INHERITS: {"arrowtail": "none", "arrowhead": "empty"}, + EdgeType.IMPLEMENTS: {"arrowtail": "node", "arrowhead": "empty", "style": "dashed"}, + EdgeType.ASSOCIATION: { + "fontcolor": "green", + "arrowtail": "none", + "arrowhead": "diamond", + "style": "solid", + }, + EdgeType.USES: {"arrowtail": "none", "arrowhead": "open"}, } diff --git a/pylint/pyreverse/main.py b/pylint/pyreverse/main.py index 043e2a3f3..010ce47e9 100644 --- a/pylint/pyreverse/main.py +++ b/pylint/pyreverse/main.py @@ -36,14 +36,14 @@ DIRECTLY_SUPPORTED_FORMATS = ( OPTIONS: Options = ( ( "filter-mode", - dict( - short="f", - default="PUB_ONLY", - dest="mode", - type="string", - action="store", - metavar="<mode>", - help="""filter attributes and functions according to + { + "short": "f", + "default": "PUB_ONLY", + "dest": "mode", + "type": "string", + "action": "store", + "metavar": "<mode>", + "help": """filter attributes and functions according to <mode>. Correct modes are : 'PUB_ONLY' filter all non public attributes [DEFAULT], equivalent to PRIVATE+SPECIAL_A @@ -52,154 +52,154 @@ OPTIONS: Options = ( except constructor 'OTHER' filter protected and private attributes""", - ), + }, ), ( "class", - dict( - short="c", - action="extend", - metavar="<class>", - type="csv", - dest="classes", - default=None, - help="create a class diagram with all classes related to <class>;\ + { + "short": "c", + "action": "extend", + "metavar": "<class>", + "type": "csv", + "dest": "classes", + "default": None, + "help": "create a class diagram with all classes related to <class>;\ this uses by default the options -ASmy", - ), + }, ), ( "show-ancestors", - dict( - short="a", - action="store", - metavar="<ancestor>", - type="int", - default=None, - help="show <ancestor> generations of ancestor classes not in <projects>", - ), + { + "short": "a", + "action": "store", + "metavar": "<ancestor>", + "type": "int", + "default": None, + "help": "show <ancestor> generations of ancestor classes not in <projects>", + }, ), ( "all-ancestors", - dict( - short="A", - default=None, - action="store_true", - help="show all ancestors off all classes in <projects>", - ), + { + "short": "A", + "default": None, + "action": "store_true", + "help": "show all ancestors off all classes in <projects>", + }, ), ( "show-associated", - dict( - short="s", - action="store", - metavar="<association_level>", - type="int", - default=None, - help="show <association_level> levels of associated classes not in <projects>", - ), + { + "short": "s", + "action": "store", + "metavar": "<association_level>", + "type": "int", + "default": None, + "help": "show <association_level> levels of associated classes not in <projects>", + }, ), ( "all-associated", - dict( - short="S", - default=None, - action="store_true", - help="show recursively all associated off all associated classes", - ), + { + "short": "S", + "default": None, + "action": "store_true", + "help": "show recursively all associated off all associated classes", + }, ), ( "show-builtin", - dict( - short="b", - action="store_true", - default=False, - help="include builtin objects in representation of classes", - ), + { + "short": "b", + "action": "store_true", + "default": False, + "help": "include builtin objects in representation of classes", + }, ), ( "module-names", - dict( - short="m", - default=None, - type="yn", - metavar="<y or n>", - help="include module name in representation of classes", - ), + { + "short": "m", + "default": None, + "type": "yn", + "metavar": "<y or n>", + "help": "include module name in representation of classes", + }, ), ( "only-classnames", - dict( - short="k", - action="store_true", - default=False, - help="don't show attributes and methods in the class boxes; this disables -f values", - ), + { + "short": "k", + "action": "store_true", + "default": False, + "help": "don't show attributes and methods in the class boxes; this disables -f values", + }, ), ( "output", - dict( - short="o", - dest="output_format", - action="store", - default="dot", - metavar="<format>", - type="string", - help=( + { + "short": "o", + "dest": "output_format", + "action": "store", + "default": "dot", + "metavar": "<format>", + "type": "string", + "help": ( f"create a *.<format> output file if format is available. Available formats are: {', '.join(DIRECTLY_SUPPORTED_FORMATS)}. " f"Any other format will be tried to create by means of the 'dot' command line tool, which requires a graphviz installation." ), - ), + }, ), ( "colorized", - dict( - dest="colorized", - action="store_true", - default=False, - help="Use colored output. Classes/modules of the same package get the same color.", - ), + { + "dest": "colorized", + "action": "store_true", + "default": False, + "help": "Use colored output. Classes/modules of the same package get the same color.", + }, ), ( "max-color-depth", - dict( - dest="max_color_depth", - action="store", - default=2, - metavar="<depth>", - type="int", - help="Use separate colors up to package depth of <depth>", - ), + { + "dest": "max_color_depth", + "action": "store", + "default": 2, + "metavar": "<depth>", + "type": "int", + "help": "Use separate colors up to package depth of <depth>", + }, ), ( "ignore", - dict( - type="csv", - metavar="<file[,file...]>", - dest="ignore_list", - default=constants.DEFAULT_IGNORE_LIST, - help="Files or directories to be skipped. They should be base names, not paths.", - ), + { + "type": "csv", + "metavar": "<file[,file...]>", + "dest": "ignore_list", + "default": constants.DEFAULT_IGNORE_LIST, + "help": "Files or directories to be skipped. They should be base names, not paths.", + }, ), ( "project", - dict( - default="", - type="string", - short="p", - metavar="<project name>", - help="set the project name.", - ), + { + "default": "", + "type": "string", + "short": "p", + "metavar": "<project name>", + "help": "set the project name.", + }, ), ( "output-directory", - dict( - default="", - type="path", - short="d", - action="store", - metavar="<output_directory>", - help="set the output directory path.", - ), + { + "default": "", + "type": "path", + "short": "d", + "action": "store", + "metavar": "<output_directory>", + "help": "set the output directory path.", + }, ), ) diff --git a/pylint/pyreverse/vcg_printer.py b/pylint/pyreverse/vcg_printer.py index 7a1d2d02d..6f28a24e8 100644 --- a/pylint/pyreverse/vcg_printer.py +++ b/pylint/pyreverse/vcg_printer.py @@ -154,20 +154,29 @@ SHAPES: dict[NodeType, str] = { NodeType.CLASS: "box", NodeType.INTERFACE: "ellipse", } +# pylint: disable-next=consider-using-namedtuple-or-dataclass ARROWS: dict[EdgeType, dict[str, str | int]] = { - EdgeType.USES: dict(arrowstyle="solid", backarrowstyle="none", backarrowsize=0), - EdgeType.INHERITS: dict( - arrowstyle="solid", backarrowstyle="none", backarrowsize=10 - ), - EdgeType.IMPLEMENTS: dict( - arrowstyle="solid", - backarrowstyle="none", - linestyle="dotted", - backarrowsize=10, - ), - EdgeType.ASSOCIATION: dict( - arrowstyle="solid", backarrowstyle="none", textcolor="green" - ), + EdgeType.USES: { + "arrowstyle": "solid", + "backarrowstyle": "none", + "backarrowsize": 0, + }, + EdgeType.INHERITS: { + "arrowstyle": "solid", + "backarrowstyle": "none", + "backarrowsize": 10, + }, + EdgeType.IMPLEMENTS: { + "arrowstyle": "solid", + "backarrowstyle": "none", + "linestyle": "dotted", + "backarrowsize": 10, + }, + EdgeType.ASSOCIATION: { + "arrowstyle": "solid", + "backarrowstyle": "none", + "textcolor": "green", + }, } ORIENTATION: dict[Layout, str] = { Layout.LEFT_TO_RIGHT: "left_to_right", diff --git a/script/.contributors_aliases.json b/script/.contributors_aliases.json index 6563c71d4..44ca36e20 100644 --- a/script/.contributors_aliases.json +++ b/script/.contributors_aliases.json @@ -602,5 +602,9 @@ "yileiyang@google.com": { "mails": ["yileiyang@google.com"], "name": "Yilei \"Dolee\" Yang" + }, + "hofrob@protonmail.com": { + "mails": ["hofrob@protonmail.com"], + "name": "Robert Hofer" } } diff --git a/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_ex_returned.py b/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_ex_returned.py index 5614674c3..efe6ba25f 100644 --- a/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_ex_returned.py +++ b/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_ex_returned.py @@ -1,6 +1,6 @@ """Check invalid value returned by __getnewargs_ex__ """ -# pylint: disable=too-few-public-methods,missing-docstring,import-error,use-dict-literal,unnecessary-lambda-assignment +# pylint: disable=too-few-public-methods,missing-docstring,import-error,use-dict-literal,unnecessary-lambda-assignment,use-dict-literal import six from missing import Missing diff --git a/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_returned.py b/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_returned.py index 49fe7b602..06cd81dd0 100644 --- a/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_returned.py +++ b/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_returned.py @@ -1,6 +1,6 @@ """Check invalid value returned by __getnewargs__ """ -# pylint: disable=too-few-public-methods,missing-docstring,import-error,unnecessary-lambda-assignment +# pylint: disable=too-few-public-methods,missing-docstring,import-error,unnecessary-lambda-assignment,use-dict-literal import six from missing import Missing diff --git a/tests/functional/i/iterable_context.py b/tests/functional/i/iterable_context.py index bc77ade34..fb035c4df 100644 --- a/tests/functional/i/iterable_context.py +++ b/tests/functional/i/iterable_context.py @@ -4,6 +4,7 @@ iterating/mapping context. """ # pylint: disable=missing-docstring,invalid-name,too-few-public-methods,import-error,unused-argument,bad-mcs-method-argument, # pylint: disable=wrong-import-position,no-else-return, unnecessary-comprehension,redundant-u-string-prefix +# pylint: disable=use-dict-literal # primitives numbers = [1, 2, 3] diff --git a/tests/functional/i/iterable_context.txt b/tests/functional/i/iterable_context.txt index e0ca8c4fe..ef59b379c 100644 --- a/tests/functional/i/iterable_context.txt +++ b/tests/functional/i/iterable_context.txt @@ -1,10 +1,10 @@ -not-an-iterable:57:9:57:22::Non-iterable value powers_of_two is used in an iterating context:UNDEFINED -not-an-iterable:92:6:92:9::Non-iterable value A() is used in an iterating context:UNDEFINED -not-an-iterable:94:6:94:7::Non-iterable value B is used in an iterating context:UNDEFINED -not-an-iterable:95:9:95:12::Non-iterable value A() is used in an iterating context:UNDEFINED -not-an-iterable:99:9:99:10::Non-iterable value B is used in an iterating context:UNDEFINED -not-an-iterable:102:9:102:14::Non-iterable value range is used in an iterating context:UNDEFINED -not-an-iterable:106:9:106:13::Non-iterable value True is used in an iterating context:UNDEFINED -not-an-iterable:109:9:109:13::Non-iterable value None is used in an iterating context:UNDEFINED -not-an-iterable:112:9:112:12::Non-iterable value 8.5 is used in an iterating context:UNDEFINED -not-an-iterable:115:9:115:11::Non-iterable value 10 is used in an iterating context:UNDEFINED +not-an-iterable:58:9:58:22::Non-iterable value powers_of_two is used in an iterating context:UNDEFINED +not-an-iterable:93:6:93:9::Non-iterable value A() is used in an iterating context:UNDEFINED +not-an-iterable:95:6:95:7::Non-iterable value B is used in an iterating context:UNDEFINED +not-an-iterable:96:9:96:12::Non-iterable value A() is used in an iterating context:UNDEFINED +not-an-iterable:100:9:100:10::Non-iterable value B is used in an iterating context:UNDEFINED +not-an-iterable:103:9:103:14::Non-iterable value range is used in an iterating context:UNDEFINED +not-an-iterable:107:9:107:13::Non-iterable value True is used in an iterating context:UNDEFINED +not-an-iterable:110:9:110:13::Non-iterable value None is used in an iterating context:UNDEFINED +not-an-iterable:113:9:113:12::Non-iterable value 8.5 is used in an iterating context:UNDEFINED +not-an-iterable:116:9:116:11::Non-iterable value 10 is used in an iterating context:UNDEFINED diff --git a/tests/functional/m/mapping_context.py b/tests/functional/m/mapping_context.py index 1d8a46afc..8dc6b3b72 100644 --- a/tests/functional/m/mapping_context.py +++ b/tests/functional/m/mapping_context.py @@ -1,7 +1,7 @@ """ Checks that only valid values are used in a mapping context. """ -# pylint: disable=missing-docstring,invalid-name,too-few-public-methods,import-error,wrong-import-position +# pylint: disable=missing-docstring,invalid-name,too-few-public-methods,import-error,wrong-import-position,use-dict-literal def test(**kwargs): diff --git a/tests/functional/u/unidiomatic_typecheck.py b/tests/functional/u/unidiomatic_typecheck.py index 1e7642046..2a1957d75 100644 --- a/tests/functional/u/unidiomatic_typecheck.py +++ b/tests/functional/u/unidiomatic_typecheck.py @@ -1,5 +1,5 @@ """Warnings for using type(x) == Y or type(x) is Y instead of isinstance(x, Y).""" -# pylint: disable=missing-docstring,expression-not-assigned,redefined-builtin,invalid-name,unnecessary-lambda-assignment +# pylint: disable=missing-docstring,expression-not-assigned,redefined-builtin,invalid-name,unnecessary-lambda-assignment,use-dict-literal def simple_positives(): type(42) is int # [unidiomatic-typecheck] diff --git a/tests/functional/u/unnecessary/unnecessary_lambda.py b/tests/functional/u/unnecessary/unnecessary_lambda.py index c12e30bc7..3e5ece2b1 100644 --- a/tests/functional/u/unnecessary/unnecessary_lambda.py +++ b/tests/functional/u/unnecessary/unnecessary_lambda.py @@ -1,4 +1,4 @@ -# pylint: disable=undefined-variable, use-list-literal, unnecessary-lambda-assignment
+# pylint: disable=undefined-variable, use-list-literal, unnecessary-lambda-assignment, use-dict-literal
"""test suspicious lambda expressions
"""
diff --git a/tests/functional/u/unsubscriptable_value.py b/tests/functional/u/unsubscriptable_value.py index 2a40d647f..79e17903b 100644 --- a/tests/functional/u/unsubscriptable_value.py +++ b/tests/functional/u/unsubscriptable_value.py @@ -4,6 +4,7 @@ Checks that value used in a subscript supports subscription """ # pylint: disable=missing-docstring,pointless-statement,expression-not-assigned,wrong-import-position, unnecessary-comprehension # pylint: disable=too-few-public-methods,import-error,invalid-name,wrong-import-order, redundant-u-string-prefix +# pylint: disable=use-dict-literal # primitives numbers = [1, 2, 3] diff --git a/tests/functional/u/unsubscriptable_value.txt b/tests/functional/u/unsubscriptable_value.txt index 24209a64a..d0833b600 100644 --- a/tests/functional/u/unsubscriptable_value.txt +++ b/tests/functional/u/unsubscriptable_value.txt @@ -1,15 +1,15 @@ -unsubscriptable-object:31:0:31:18::Value 'NonSubscriptable()' is unsubscriptable:UNDEFINED -unsubscriptable-object:32:0:32:16::Value 'NonSubscriptable' is unsubscriptable:UNDEFINED -unsubscriptable-object:34:0:34:13::Value 'Subscriptable' is unsubscriptable:UNDEFINED -unsubscriptable-object:43:0:43:15::Value 'powers_of_two()' is unsubscriptable:UNDEFINED -unsubscriptable-object:44:0:44:13::Value 'powers_of_two' is unsubscriptable:UNDEFINED -unsubscriptable-object:48:0:48:4::Value 'True' is unsubscriptable:UNDEFINED -unsubscriptable-object:49:0:49:4::Value 'None' is unsubscriptable:UNDEFINED -unsubscriptable-object:50:0:50:3::Value '8.5' is unsubscriptable:UNDEFINED -unsubscriptable-object:51:0:51:2::Value '10' is unsubscriptable:UNDEFINED -unsubscriptable-object:54:0:54:27::Value '{x**2 for x in range(10)}' is unsubscriptable:UNDEFINED -unsubscriptable-object:55:0:55:12::Value 'set(numbers)' is unsubscriptable:UNDEFINED -unsubscriptable-object:56:0:56:18::Value 'frozenset(numbers)' is unsubscriptable:UNDEFINED -unsubscriptable-object:76:0:76:20::Value 'SubscriptableClass()' is unsubscriptable:UNDEFINED -unsubscriptable-object:83:0:83:4::Value 'test' is unsubscriptable:UNDEFINED -unsubscriptable-object:126:11:126:18:test_one:Value 'var_one' is unsubscriptable:UNDEFINED +unsubscriptable-object:32:0:32:18::Value 'NonSubscriptable()' is unsubscriptable:UNDEFINED +unsubscriptable-object:33:0:33:16::Value 'NonSubscriptable' is unsubscriptable:UNDEFINED +unsubscriptable-object:35:0:35:13::Value 'Subscriptable' is unsubscriptable:UNDEFINED +unsubscriptable-object:44:0:44:15::Value 'powers_of_two()' is unsubscriptable:UNDEFINED +unsubscriptable-object:45:0:45:13::Value 'powers_of_two' is unsubscriptable:UNDEFINED +unsubscriptable-object:49:0:49:4::Value 'True' is unsubscriptable:UNDEFINED +unsubscriptable-object:50:0:50:4::Value 'None' is unsubscriptable:UNDEFINED +unsubscriptable-object:51:0:51:3::Value '8.5' is unsubscriptable:UNDEFINED +unsubscriptable-object:52:0:52:2::Value '10' is unsubscriptable:UNDEFINED +unsubscriptable-object:55:0:55:27::Value '{x**2 for x in range(10)}' is unsubscriptable:UNDEFINED +unsubscriptable-object:56:0:56:12::Value 'set(numbers)' is unsubscriptable:UNDEFINED +unsubscriptable-object:57:0:57:18::Value 'frozenset(numbers)' is unsubscriptable:UNDEFINED +unsubscriptable-object:77:0:77:20::Value 'SubscriptableClass()' is unsubscriptable:UNDEFINED +unsubscriptable-object:84:0:84:4::Value 'test' is unsubscriptable:UNDEFINED +unsubscriptable-object:127:11:127:18:test_one:Value 'var_one' is unsubscriptable:UNDEFINED diff --git a/tests/functional/u/unsupported/unsupported_assignment_operation.py b/tests/functional/u/unsupported/unsupported_assignment_operation.py index 2cac693dd..93e84c020 100644 --- a/tests/functional/u/unsupported/unsupported_assignment_operation.py +++ b/tests/functional/u/unsupported/unsupported_assignment_operation.py @@ -3,7 +3,7 @@ Checks that value used in a subscript support assignments (i.e. defines __setitem__ method). """ # pylint: disable=missing-docstring,pointless-statement,expression-not-assigned,wrong-import-position,unnecessary-comprehension -# pylint: disable=too-few-public-methods,import-error,invalid-name,wrong-import-order +# pylint: disable=too-few-public-methods,import-error,invalid-name,wrong-import-order,use-dict-literal # primitives numbers = [1, 2, 3] diff --git a/tests/functional/u/unsupported/unsupported_delete_operation.py b/tests/functional/u/unsupported/unsupported_delete_operation.py index 56a457324..c33a6eb89 100644 --- a/tests/functional/u/unsupported/unsupported_delete_operation.py +++ b/tests/functional/u/unsupported/unsupported_delete_operation.py @@ -3,7 +3,7 @@ Checks that value used in a subscript support deletion (i.e. defines __delitem__ method). """ # pylint: disable=missing-docstring,pointless-statement,expression-not-assigned,wrong-import-position,unnecessary-comprehension -# pylint: disable=too-few-public-methods,import-error,invalid-name,wrong-import-order +# pylint: disable=too-few-public-methods,import-error,invalid-name,wrong-import-order,use-dict-literal # primitives numbers = [1, 2, 3] diff --git a/tests/functional/u/use/use_literal_dict.py b/tests/functional/u/use/use_literal_dict.py index 3377b4e63..598b382bd 100644 --- a/tests/functional/u/use/use_literal_dict.py +++ b/tests/functional/u/use/use_literal_dict.py @@ -1,7 +1,46 @@ -# pylint: disable=missing-docstring, invalid-name +# pylint: disable=missing-docstring, invalid-name, disallowed-name, unused-argument, too-few-public-methods x = dict() # [use-dict-literal] -x = dict(a="1", b=None, c=3) +x = dict(a="1", b=None, c=3) # [use-dict-literal] x = dict(zip(["a", "b", "c"], [1, 2, 3])) x = {} x = {"a": 1, "b": 2, "c": 3} +x = dict(**x) # [use-dict-literal] + +def bar(boo: bool = False): + return 1 + +x = dict(foo=bar()) # [use-dict-literal] + +baz = {"e": 9, "f": 1} + +dict( # [use-dict-literal] + **baz, + suggestions=list( + bar( + boo=True, + ) + ), +) + +class SomeClass: + prop: dict = {"a": 1} + +inst = SomeClass() + +dict( # [use-dict-literal] + url="/foo", + **inst.prop, +) + +dict( # [use-dict-literal] + Lorem="ipsum", + dolor="sit", + amet="consectetur", + adipiscing="elit", + sed="do", + eiusmod="tempor", + incididunt="ut", + labore="et", + dolore="magna", +) diff --git a/tests/functional/u/use/use_literal_dict.txt b/tests/functional/u/use/use_literal_dict.txt index cbcb83f24..145766479 100644 --- a/tests/functional/u/use/use_literal_dict.txt +++ b/tests/functional/u/use/use_literal_dict.txt @@ -1 +1,7 @@ -use-dict-literal:3:4:3:10::Consider using {} instead of dict():UNDEFINED +use-dict-literal:3:4:3:10::Consider using '{}' instead of a call to 'dict'.:INFERENCE +use-dict-literal:4:4:4:28::"Consider using '{""a"": '1', ""b"": None, ""c"": 3}' instead of a call to 'dict'.":INFERENCE +use-dict-literal:8:4:8:13::Consider using '{**x}' instead of a call to 'dict'.:INFERENCE +use-dict-literal:13:4:13:19::"Consider using '{""foo"": bar()}' instead of a call to 'dict'.":INFERENCE +use-dict-literal:17:0:24:1::"Consider using '{""suggestions"": list(bar(boo=True)), **baz}' instead of a call to 'dict'.":INFERENCE +use-dict-literal:31:0:34:1::"Consider using '{""url"": '/foo', **inst.prop}' instead of a call to 'dict'.":INFERENCE +use-dict-literal:36:0:46:1::"Consider using '{""Lorem"": 'ipsum', ""dolor"": 'sit', ""amet"": 'consectetur', ""adipiscing"": 'elit', ... }' instead of a call to 'dict'.":INFERENCE |