diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cfa03687..c01b76a82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,13 @@ We used to have incremental versioning before `0.1.0`. - Adds `safety` and other dependency checks to CI process +## Version 0.6.3 + +### Bugfixes + +- Fixes a [crash](https://github.com/wemake-services/wemake-python-styleguide/issues/450) with `dict`s with just values and no keys + + ## Version 0.6.2 ### Bugfixes diff --git a/pyproject.toml b/pyproject.toml index f71124e79..857494a93 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "poetry.masonry.api" [tool.poetry] name = "wemake-python-styleguide" -version = "0.6.2" +version = "0.6.3" description = "The strictest and most opinionated python linter ever" license = "MIT" diff --git a/tests/test_visitors/test_ast/test_statements/test_parameters_indentation/test_collection_indentation.py b/tests/test_visitors/test_ast/test_statements/test_parameters_indentation/test_collection_indentation.py index 50dd6b9c1..e99a0b4f7 100644 --- a/tests/test_visitors/test_ast/test_statements/test_parameters_indentation/test_collection_indentation.py +++ b/tests/test_visitors/test_ast/test_statements/test_parameters_indentation/test_collection_indentation.py @@ -99,6 +99,18 @@ } """ +correct_simple_regression450 = """ +was_crashing = {**some_other_dict} +""" + +correct_multiline_regression450 = """ +was_crashing = { + **some_other_dict, + **some_very_other_dict, + **third_dict, +} +""" + # Wrong: @@ -198,6 +210,13 @@ } """ +wrong_regression450 = """ +some_dict = { + **one, + **two, **three, +} +""" + @pytest.mark.parametrize('code', [ correct_multiline_string, @@ -214,6 +233,10 @@ correct_next_line_set, correct_next_line_tuple, correct_nested_collections, + + # Regressions: + correct_simple_regression450, + correct_multiline_regression450, ]) def test_correct_collection_indentation( assert_errors, @@ -247,6 +270,9 @@ def test_correct_collection_indentation( wrong_dict_indentation2, wrong_dict_indentation3, wrong_dict_indentation4, + + # Regressions: + wrong_regression450, ]) def test_wrong_collection_indentation( assert_errors, diff --git a/wemake_python_styleguide/logics/collections.py b/wemake_python_styleguide/logics/collections.py new file mode 100644 index 000000000..f68136a58 --- /dev/null +++ b/wemake_python_styleguide/logics/collections.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +import ast +from typing import List, Sequence + + +def normalize_dict_elements(node: ast.Dict) -> Sequence[ast.AST]: + """ + Normalizes ``dict`` elements and enforces consistent order. + + We had a problem that some ``dict`` objects might not have some keys. + + Example:: + + some_dict = {**one, **two} + + This ``dict`` contains two values and zero keys. + This function will normalize this structure to use + values instead of missing keys. + + See also: + https://github.com/wemake-services/wemake-python-styleguide/issues/450 + + """ + elements: List[ast.AST] = [] + for dict_key, dict_value in zip(node.keys, node.values): + if dict_key is None: + elements.append(dict_value) + else: + elements.append(dict_key) + return elements diff --git a/wemake_python_styleguide/visitors/ast/statements.py b/wemake_python_styleguide/visitors/ast/statements.py index a9dab7aed..19850d9c0 100644 --- a/wemake_python_styleguide/visitors/ast/statements.py +++ b/wemake_python_styleguide/visitors/ast/statements.py @@ -3,6 +3,7 @@ import ast from typing import ClassVar, List, Optional, Sequence, Union +from wemake_python_styleguide.logics.collections import normalize_dict_elements from wemake_python_styleguide.logics.functions import get_all_arguments from wemake_python_styleguide.logics.nodes import is_doc_string from wemake_python_styleguide.types import AnyFunctionDef, AnyNodes, final @@ -215,7 +216,10 @@ def _check_indentation( def visit_collection(self, node: AnyCollection) -> None: """Checks how collection items indentation.""" - elements = node.keys if isinstance(node, ast.Dict) else node.elts + if isinstance(node, ast.Dict): + elements = normalize_dict_elements(node) + else: + elements = node.elts self._check_indentation(node, elements, extra_lines=1) self.generic_visit(node)