Repository: PyCQA/pyflakes

Issue:
Ignore "_" vars in "Unused Variable" check

*Original report by [archardlias](https://launchpad.net/~archardlias) on [Launchpad](https://bugs.launchpad.net/bugs/1328169):*

------------------------------------

Would it be possible to ignore variables named "_" from "Unused Variable" checks?

I'm not really sure whether "_" is officially specified anywhere. But I do see it a lot and in a lot of languages including python to denote a variable to be ignored (place holder dummy). PyLint implements this pseudo(?)-convention (? second-hand knowledge).

Would be great, since I would love to be explicit about "things returned but not used" instead of just calling without assignment which looks tantamount to "this function does never return anything / does not contain a return statement". A great plus in signature visibility throughout the code, specially for first-time readers.

Best regards,
~arlias


Discussion:
krader1961: This is derived from PR #335. That PR prematurely expanded the scope to all vars with a leading underscore. This variant limits it to just the magic `_` var. It is a shame that @smontanaro couldn't set aside their belief that all vars with a leading underscore should be exempt from this check so that they would get credit for the improvement that resolves issue #202.
smontanaro: Note that I added a comment about the docstring in the new test function.
jayvdb: While not strictly relevant to your patch, it would be useful to add a test here to ensure that `_` import is not ignored.

```
    def test_unusedImport_underscore(self):
        self.flakes('import fu as _', m.UnusedImport)
```

With all the `_` special cases happening, I worry that one will become ignored also.
krader1961: I had forgotten I even opened this it's so old. I also see my unit test comment is bogus because I copied it from the flawed PR #334.

```
Don't warn when an unused variable starts with an underscore.
```

That should say something like "Don't warn when the unused variable is the magic underscore var."

@jayvdb Do you want to just merge this and fix the issues yourself or wait for me to muster the energy to address you comment and my observation about the added unit test?
jayvdb: Oh, I missed that :)

It needs to be rebased and docstring fixed before merging.
We can do that for you, if necessary.

Patch:
diff --git a/pyflakes/checker.py b/pyflakes/checker.py
index bd5eba5..648a224 100644
--- a/pyflakes/checker.py
+++ b/pyflakes/checker.py
@@ -425,7 +425,9 @@ class FunctionScope(Scope):
         Return a generator for the assignments which have not been used.
         """
         for name, binding in self.items():
-            if (not binding.used and name not in self.globals
+            if (not binding.used
+                    and name != '_'  # see issue #202
+                    and name not in self.globals
                     and not self.usesLocals
                     and isinstance(binding, Assignment)):
                 yield name, binding


Test patch:
diff --git a/pyflakes/test/test_imports.py b/pyflakes/test/test_imports.py
index 586a0a5..86e1d37 100644
--- a/pyflakes/test/test_imports.py
+++ b/pyflakes/test/test_imports.py
@@ -94,6 +94,13 @@ class TestImportationObject(TestCase):
         assert binding.source_statement == 'from __future__ import print_function'
         assert str(binding) == '__future__.print_function'
 
+    def test_unusedImport_underscore(self):
+        """
+        The magic underscore var should be reported as unused when used as an
+        import alias.
+        """
+        self.flakes('import fu as _', m.UnusedImport)
+
 
 class Test(TestCase):
 
diff --git a/pyflakes/test/test_other.py b/pyflakes/test/test_other.py
index 364b375..4dbaf23 100644
--- a/pyflakes/test/test_other.py
+++ b/pyflakes/test/test_other.py
@@ -1175,6 +1175,16 @@ class TestUnusedAssignment(TestCase):
             b = 1
         ''', m.UnusedVariable)
 
+    def test_unusedUnderscoreVariable(self):
+        """
+        Don't warn when the magic "_" (underscore) variable is unused.
+        See issue #202.
+        """
+        self.flakes('''
+        def a(unused_param):
+            _ = unused_param
+        ''')
+
     def test_unusedVariableAsLocals(self):
         """
         Using locals() it is perfectly valid to have unused variables