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

Added new rule for checking for infinite while loops. Added test call… #1066

Merged
merged 5 commits into from Oct 20, 2020

Conversation

ragohin
Copy link
Contributor

@ragohin ragohin commented Dec 9, 2019

…ed test_infinite_while_loops.py

I have made things!

Checklist

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

Related issues

Closes #1007

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! Great progress here. 👍

I have added some suggestions about your solution.

@@ -203,6 +206,25 @@ def _check_multiline_loop(self, node: _AnyLoop) -> None:
self.add_violation(MultilineLoopViolation(node))
break

def _has_break_raise_or_return(self, node: _AnyLoop) -> bool:
Copy link
Member

Choose a reason for hiding this comment

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

This can be moved to logic/ dir

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

return True
return False

def _check_infinite_while_loop(self, node: _AnyLoop) -> None:
Copy link
Member

Choose a reason for hiding this comment

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

This can be moved to a another or a new visitor, that is ast.While specific.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Shouldn't this be inside of this class though, since it says at line 129 "Checks ''for'' and ''while'' loops" ? It seems like _check_multiline_loop also is ast.While specific.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think what I have implemented as of now might work, but let me know!

@coveralls
Copy link

coveralls commented Dec 10, 2019

Pull Request Test Coverage Report for Build 2441

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

Totals Coverage Status
Change from base Build 2424: 0.0%
Covered Lines: 5041
Relevant Lines: 5041

💛 - Coveralls

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 a lot!

Now, let me show how integration test can be created:

def infinite_loop():
     while True:
          print('forever')

And put it into tests/fixtures/noqa.py with correct noqa comment.
Then adjust tests/test_checker/test_noqa.py to contain this violation.

That's it! Awesome job! 👍

from wemake_python_styleguide.compat.aliases import ForNodes
from wemake_python_styleguide.types import AnyFor, ContextNodes

_AnyLoop = Union[AnyFor, ast.While]
Copy link
Member

Choose a reason for hiding this comment

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

Should go to types.py

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

@@ -29,3 +32,36 @@ def get_parent(node: ast.AST) -> Optional[ast.AST]:
def get_context(node: ast.AST) -> Optional[ContextNodes]:
"""Returns the context or ``None`` if node has no context."""
return getattr(node, 'wps_context', None)


def does_loop_contain_node( # TODO: move, reuse in annotations.py
Copy link
Member

Choose a reason for hiding this comment

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

Please, remove TODO

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

loop: Optional[_AnyLoop],
to_check: ast.Break,
) -> bool:
"""Helper function for has_break method."""
Copy link
Member

Choose a reason for hiding this comment

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

Please, change the description to something more meaningful.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

@@ -29,3 +32,36 @@ def get_parent(node: ast.AST) -> Optional[ast.AST]:
def get_context(node: ast.AST) -> Optional[ContextNodes]:
"""Returns the context or ``None`` if node has no context."""
return getattr(node, 'wps_context', None)


def does_loop_contain_node( # TODO: move, reuse in annotations.py
Copy link
Member

Choose a reason for hiding this comment

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

Do we actually use this method from outside? If not, it should be protected. _does_loop_contain_node

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

@@ -208,22 +178,21 @@ def _check_multiline_loop(self, node: _AnyLoop) -> None:

def _has_break_raise_or_return(self, node: _AnyLoop) -> bool:
Copy link
Member

Choose a reason for hiding this comment

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

This method can still be moved into logic/

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, that function should not have been in this commit in that location. It has been moved to logic/.

@@ -338,6 +307,6 @@ def _check_implicit_items(self, node: ast.For) -> None:

def _is_assigned_target(self, node: ast.Subscript) -> bool:
parent = nodes.get_parent(node)
if not isinstance(parent, (*AssignNodes, ast.AugAssign)):
Copy link
Member

Choose a reason for hiding this comment

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

Are you sure about this change? Why do you have to remove ast.AugAssign?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, I don't remember changing that, I must've pulled an outdated version of the code. Fixed.

@ragohin
Copy link
Contributor Author

ragohin commented Dec 10, 2019

I added one more small change so that "while True:" loops are defined with print("forever") inside. Hopefully everything is correct now!

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.

Done! Only one little refactor remains.

Thanks a lot for your work!

from wemake_python_styleguide.visitors.ast.loops import WrongLoopVisitor

incorrect_loop1 = """
while True:
Copy link
Member

Choose a reason for hiding this comment

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

Looks like there are a lot of repetitive patterns in these samples.
Let's parametrize them!

Like so:

incorrect_loop_template = """
while True:
    {0}
"""

And later we can use this way of testing:

@pytest.mark.parametrize('keyword', [
    'break',
    'return',
    'return some',
    'raise Some',
    'raise Some()',
    'raise',
]
def test_whatever(keyword):
     code = template.format(keyword)

We also need to test a nested keyword:

while True:
    if some:
        {0}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alright I think I fixed everything! Let me know what you think!

incorrect_loop_template_nonfunction3 = """
while True:
if some:
print('forever')
Copy link
Member

Choose a reason for hiding this comment

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

This is not parametrized

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How can I parametrize this in a way where {0} accepts any command except for (raise, return, and break)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Basically my most recent pull request has (raise, return, break, etc) parametrized, but not "print('forever')" which should just be replaced by any command that is not (raise, return, break, etc).

@ragohin
Copy link
Contributor Author

ragohin commented Dec 10, 2019

I think there is an issue with the configuration on the laptop I pushed my code with most recently.

I originally was working on my Mac, which just crashed, so I switched to wsl on my Windows computer. I think the code will build properly if I submit on my Mac, but I can't use it right now :/

Is there any work around with this because I'm not sure I can satisfy the Travis CI build with my current laptop?

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.

At last! @ragohin now this is ready to be merged. I will include this feature into 0.15 version.

You PR was not polished, so I had to work on it for a bit more.
I hope that you will get your bonus credits for this work. Good luck!

Thanks a lot for taking the time to contribute to our project. I really appreciate that! 👍

@sobolevn sobolevn added this to the Version 0.15 milestone Jan 19, 2020
@codecov
Copy link

codecov bot commented Oct 20, 2020

Codecov Report

Merging #1066 into master will not change coverage.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff            @@
##            master     #1066   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          105       105           
  Lines         5512      5531   +19     
  Branches      1217      1224    +7     
=========================================
+ Hits          5512      5531   +19     
Impacted Files Coverage Δ
wemake_python_styleguide/logic/tree/loops.py 100.00% <100.00%> (ø)
...ake_python_styleguide/violations/best_practices.py 100.00% <100.00%> (ø)
wemake_python_styleguide/visitors/ast/loops.py 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 033048a...0683566. Read the comment docs.

@sobolevn sobolevn merged commit 34b9004 into wemake-services:master Oct 20, 2020
@sobolevn sobolevn modified the milestones: Version 0.16, Version 0.15 aka New runtime Oct 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Warn about possibly infinite while
3 participants