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

Early return should not take return None form when it is not required #2151

Closed
sobolevn opened this issue Aug 21, 2021 · 21 comments · Fixed by #2171
Closed

Early return should not take return None form when it is not required #2151

sobolevn opened this issue Aug 21, 2021 · 21 comments · Fixed by #2171
Assignees
Labels
good first issue Entrypoint to the project help wanted Extra attention is needed level:starter Good for newcomers rule request Adding a new rule
Milestone

Comments

@sobolevn
Copy link
Member

Rule request

Thesis

Right now this code:

    def _check_parent(self, node: ast.If) -> None:
        parent = get_parent(node)

        if parent is None:
            return None

        if isinstance(parent, _ELSE_NODES):
            body = parent.body + parent.orelse
        else:
            body = getattr(parent, 'body', [node])

        next_index_in_parent = body.index(node) + 1
        if keywords.next_node_returns_bool(body, next_index_in_parent):
            self.add_violation(SimplifiableReturningIfViolation(node))

passes our style check. Note return None part there. It is the only return. And it means that None part is not required.
Moreover, it should not be allowed. Simple early returns must be just return`.

@sobolevn sobolevn added rule request Adding a new rule good first issue Entrypoint to the project help wanted Extra attention is needed level:starter Good for newcomers labels Aug 21, 2021
@sobolevn sobolevn added this to the Version 0.16 milestone Aug 21, 2021
@siddharth1704
Copy link

so we need just change that from return None to return

@sobolevn
Copy link
Member Author

@siddharth1704 yes!

I think that we can formulate this rule as:

If you have a single return None, it can only be the last item in a function's body.

@cdhiraj40
Copy link
Contributor

cdhiraj40 commented Aug 25, 2021

@sobolevn if we have returned none in a function, it means it's meant for later use, since we don't have the value to return, we do return none? please correct me if I'm wrong.

@cdhiraj40
Copy link
Contributor

cdhiraj40 commented Aug 25, 2021

@sobolevn if we have returned none in a function, it means it's meant for later use, since we don't have the value to return, we do return none? please correct me if I'm wrong.

i would like to contribute to this, please assign me.

@sobolevn
Copy link
Member Author

We allow:

def some():
   if condition:
       return None
   return other

We don't allow:

def some():
   if condition:
       return None
   print()

@cdhiraj40
Copy link
Contributor

@sobolevn can you tell me the process to contribute?
i am a beginner and i didn't understand much from contribute.md. thanks!

@sobolevn
Copy link
Member Author

You should probably start with learning what ast is. Then, look at

class ConsistentReturningVisitor(BaseNodeVisitor):
This change should leave somewhere there.

@cdhiraj40
Copy link
Contributor

cdhiraj40 commented Aug 29, 2021

hey @sobolevn I understood the concept(thesis) and I did comprehend how ast works but I'm still not able to get how to implement
can you provide me a sample code from some other issue that is easy to understand
will be really helpful for a beginner like me, Thanks!

@sobolevn
Copy link
Member Author

Ok, we also need to take a closer look at:

def some_funct():
    if first_cond:
        return None
    if second_cond:
        return None
    print('a')

I would re-formulate the rule as: if all function return nodes are return None -> than we must use plain return.

@DhirajChauhan40
Something like (untested):

is_all_none = (
            issubclass(returning_type, ast.Return) and
            has_values and
            all(
                ret_node.value.value is None
                for ret_node in return_nodes
                if isinstance(ret_node.value, (compat.nodes.Constant, ast.NameConstant))
            )
        )
        if is_all_none:
            self.add_violation(...)

You can put it here:

You would still have to:

  1. Add new violation type in violations/consistency.py
  2. Add tests
  3. Have fun 🙂

@cdhiraj40
Copy link
Contributor

@sobolevn
thank you so much!!

@cdhiraj40
Copy link
Contributor

@sobolevn so i was tryna run the file and I got this error in confest.py inside tests folder

ImportError while loading conftest '/home/thefunnyintrovert/wemake-python-styleguide/tests/conftest.py'.
  File "/home/thefunnyintrovert/wemake-python-styleguide/tests/conftest.py", line 20
    def factory(*files: str):
                      ^
SyntaxError: invalid syntax

@sobolevn
Copy link
Member Author

Are you running pythno3.9?

@cdhiraj40
Copy link
Contributor

Are you running pythno3.9?

yes after installing the 3.9 version, it was working thanks!
sorry for the late reply i had work, i have written the test cases and now im working on the post part.

@cdhiraj40
Copy link
Contributor

cdhiraj40 commented Sep 2, 2021

Hey @sobolevn i have added my violation to violations/consistency.py and have made other changes too

from wemake_python_styleguide.violations.consistency import (
    AllReturnsAreNoneViolation,

but In test_consistency_return.py I'm still getting module error

 from wemake_python_styleguide.violations.consistency import (
ImportError: cannot import name 'AllReturnsAreNoneViolation' from 'wemake_python_styleguide.violations.consistency'

@sobolevn
Copy link
Member Author

sobolevn commented Sep 2, 2021

Can you please open a PR?

@cdhiraj40
Copy link
Contributor

yes sure

@sathieu
Copy link
Contributor

sathieu commented Jan 7, 2022

How should I write the following code without noqa?

    def files_key(self, package_file: PackageFile) -> Optional[str]:  # noqa: WPS324
        """Get files key, to upload to. If None, uploaded as body.

        Args:
            package_file: Source package file.
        Returns:
            The files key, or None.
        """
        return None  # noqa: WPS324

This function is overriden in child classes.

NB: Using return (without None) fails with mypy:

mypy run-test: commands[0] | mypy gitlabracadabra
gitlabracadabra/packages/destination.py:160: error: Return value expected

See https://gitlab.com/gitlabracadabra/gitlabracadabra/-/merge_requests/233

@sobolevn
Copy link
Member Author

sobolevn commented Jan 7, 2022

def files_key(self, package_file: PackageFile) -> Optional[str]:  # noqa: WPS324
        """Get files key, to upload to. If None, uploaded as body.

        Args:
            package_file: Source package file.
        Returns:
            The files key, or None.
        """

🙂

@sathieu
Copy link
Contributor

sathieu commented Jan 7, 2022

@sobolevn Now I have:

  157:1    DAR202 Excess "Returns" in Docstring: + return
  """Get files key, to upload to. If None, uploaded as body.

        Args:
            package_file: Source package file.

        Returns:
            The files key, or None.
        """

@sobolevn
Copy link
Member Author

sobolevn commented Jan 7, 2022

Hm, can you please open a new bug? Looks like when we have Returns: spec, we have a false positive.

@sathieu
Copy link
Contributor

sathieu commented Jan 7, 2022

@sobolevn I created #2323.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Entrypoint to the project help wanted Extra attention is needed level:starter Good for newcomers rule request Adding a new rule
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants