Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#212] Forbid variables self reassignment #262

Merged
merged 8 commits into from
Oct 18, 2018
Merged

[#212] Forbid variables self reassignment #262

merged 8 commits into from
Oct 18, 2018

Conversation

Roxe322
Copy link
Contributor

@Roxe322 Roxe322 commented Oct 15, 2018

I have made things!

  • [V] I have double checked that there are no unrelated changes in this pull request (old patches, accidental config files, etc)
  • [V] I have created at least one test case for the changes I have made
  • [V] I have updated the documentation for the changes I have made
  • [V] I have added my changes to the CHANGELOG.md

Related issues

Closes: #212

Copy link
Member

@sobolevn sobolevn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

WrongVariableAssignmentVisitor,
)

wrong_fragment = """
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please also test this example:

test_variable = 5
test_variable = test_variable = 5

and

test_variable = 5
test_variable = other = test_variable = 5

All these examples should raise a violation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@sobolevn
Copy link
Member

@Roxe322 please, also fix merge conflicts.

"""


def test_self_variable_reassignment(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, also check this example:

x, y = x, y

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@Roxe322
Copy link
Contributor Author

Roxe322 commented Oct 17, 2018

Ooops, some fails, I need to check it

@Roxe322
Copy link
Contributor Author

Roxe322 commented Oct 17, 2018

Can you please explain me what is going wrong there? In my local machine pytest passing successfully :(

Copy link
Member

@sobolevn sobolevn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Roxe322 thanks for your time and effort.

This code has a lot of major problems, that are hard to address in a single review. However, I will point some things that I find the most important:

  1. Some code looks pretty identical and can be moved to the function of its own, like:
    if getattr(node.value, 'id', None) in target_names or (
    len(target_names) != len(list(set(target_names)))):
    and
    if node_values in target_names or (len(target_names) !=
    len(list(set(target_names)))
    ):
  2. I am not sure what are you trying to do in these lines:
    target_names = [getattr(target, 'elts', None) for target
    in node.targets if isinstance(target, ast.Tuple)]
    for index in range(len(target_names)):
    target_names[index] = [name.id for name in target_names[index]]
    Seems like a wrong data structure / algorithm to me
  3. Try to adapt to the code style we have in a project. You won't find a single other example of neither of these things:
    if node_values in target_names or (len(target_names) !=
    len(list(set(target_names)))
    ):
    and
    target_names = [getattr(target, 'elts', None) for target
    in node.targets if isinstance(target, ast.Tuple)]
    We use different line break rules. And it is important.

I have asked @AlwxSin to help you with this PR.

Thanks again for your hard work! I would be happy to merge this PR as soon as it will be refactored.



@pytest.mark.parametrize('fragment', [wrong_fragment,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use different style for this kind of things: please, see

@pytest.mark.parametrize('code', [
calling_function,
called_function,
calling_method,
called_method,
accessing_attribute,
accessed_attribute,
raising_variable,
returning_variable,
awaiting_variable,
yielding_variable,
])

def test_self_variable_reassignment(
assert_errors, parse_ast_tree, default_options,
assert_errors, parse_ast_tree, fragment, default_options,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use code variable name for code samples, not fragment. Please, rename it.

"""

#: Error message shown to the user.
error_template = 'Found reassigning variable to itself'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please provide the name of the variable here? Currently you miss '{0}' in template string

target_names = [target.id for target in node.targets
if isinstance(target, ast.Name)]
if target_names:
if getattr(node.value, 'id', None) in target_names or (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each step in this if should be a separate variable:

taget_name = getattr(node.value, 'id', None)
PLEASE_FIND_CORRECT_NAME = len(target_names) != len(set(target_names))
if target_name in target_names or PLEASE_FIND_CORRECT_NAME: ...

Replace PLEASE_FIND_CORRECT_NAME with anything you find appropriate.

else:
target_names = [getattr(target, 'elts', None) for target
in node.targets if isinstance(target, ast.Tuple)]
for index in range(len(target_names)):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use enumerate instead. range(len()) is an anti-pattern.

node_values = []
if isinstance(node.value, ast.Tuple):
node_values = [getattr(node_value, 'id', None) for node_value
in node.value.elts]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, do not abuse line breaking like this. This linter currently unable to catch these things. But, I will be more than happy to create new rules to forbid this kind of line breaks.

node_values = [getattr(node_value, 'id', None) for node_value
in node.value.elts]
if node_values in target_names or (len(target_names) !=
len(list(set(target_names)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need to cast set to list.

@Roxe322
Copy link
Contributor Author

Roxe322 commented Oct 17, 2018

Thank you for your detailed review, I will try to fix all problems. About line breaking - it is very hard to fit into 80 symbols line length, and because of this such ugly line breakings are in my code :)

@sobolevn
Copy link
Member

@Roxe322 the general rule is: if it is hard to fit your logic into one line - you have too many logic.
Split this line into multiple variables, functions, etc.

@Roxe322
Copy link
Contributor Author

Roxe322 commented Oct 17, 2018

Your linter one time told me that I have too much local variables in one method, so I tried not to meet this warning again :)

@coveralls
Copy link

coveralls commented Oct 17, 2018

Pull Request Test Coverage Report for Build 520

  • 26 of 26 (100.0%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage remained the same at 100.0%

Totals Coverage Status
Change from base Build 490: 0.0%
Covered Lines: 1377
Relevant Lines: 1377

💛 - Coveralls

@Roxe322
Copy link
Contributor Author

Roxe322 commented Oct 17, 2018

@sobolevn Fixed all problems, I think :)

Copy link
Member

@sobolevn sobolevn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a single thing to fix before merging!

Awesome job!

@@ -171,26 +173,34 @@ def visit_Assign(self, node: ast.Assign) -> None:
class WrongVariableAssignmentVisitor(BaseNodeVisitor):
"""Finds wrong variables assignments."""

def create_target_names(self, target: AssignTarget) -> AssignTargetNameList:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should start with _, since it is a protected method.

wrong_fragment_tuple_assignment = """
x = 1
y = 2
x, y = x, y
Copy link
Member

@sobolevn sobolevn Oct 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more thing. Can you please test this case:

x = 1
y = 2
x, y = y, x

This should be a perfectly valid case. But, I am not sure if that is working right now.

@@ -23,6 +24,8 @@
from wemake_python_styleguide.visitors.decorators import alias

VariableDef = Union[ast.Name, ast.Attribute, ast.ExceptHandler]
AssignTarget = List[ast.expr]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
AssignTarget = List[ast.expr]
AssignTargets = List[ast.expr]

@@ -23,6 +24,8 @@
from wemake_python_styleguide.visitors.decorators import alias

VariableDef = Union[ast.Name, ast.Attribute, ast.ExceptHandler]
AssignTarget = List[ast.expr]
AssignTargetNameList = List[Union[str, Tuple[str]]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
AssignTargetNameList = List[Union[str, Tuple[str]]]
AssignTargetsNameList = List[Union[str, Tuple[str]]]

@Roxe322
Copy link
Contributor Author

Roxe322 commented Oct 18, 2018

@sobolevn I've added test case that you requested and also fixed naming mentioned by @AlwxSin

@sobolevn
Copy link
Member

@Roxe322 awesome job!

@sobolevn sobolevn merged commit ed3562d into wemake-services:master Oct 18, 2018
@Roxe322
Copy link
Contributor Author

Roxe322 commented Oct 18, 2018

Thank you! I'm glad to help you :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants