pylint 'unused_variable' warning on function definition - python

I have defined a function in __init__.py.
While running pylint on __init__.py, it gives a warning about unused_variable on the function_name.
I don't want to disable this warning in general (for actual unused variables, etc.) but obviously I don't want a warning for the function definition. Sample __init__.py:
import os
test_enabled = True
run_all_tests = False ## Raises 'unused_variable' warning, expected and want to keep such warnings
def is_test_enabled(): ## Raises 'unused_variable' warning, unexpected and want to disable
return <test_object> if test_enabled else None

Related

Disable mypy for test functions

Is it possible disable mypy checking for functions which for a testing? Such as starts from test_?
For me is redundant adding typing for tests
def test_dummy(): # <- mypy is raising "error: Function is missing a return type annotation"
# Empty test

warnings filter precedence

import warnings
def warn():
with warnings.catch_warnings():
warnings.simplefilter('always')
warnings.warn('warning')
with warnings.catch_warnings():
warnings.simplefilter('ignore')
warn()
warn.py:6: UserWarning: warning
warnings.warn('warning')
I was thinking that the 'ignore' filter would apply but it seems the 'always' filter within the function is taking priority. Is this the expected behavior? Is there any way to ignore a warning in this case? I am importing something with simplefilter('always'), so I do not have control, but I would like to ignore it.

Python: unused argument needed for compatibility. How to avoid Pylint complaining about it

For my code in Python, I would like to call many functions with a specific argument. However, for some functions, that argument does not do anything. Still, I would like to add the argument for compatibility reasons. For example, consider the following minimal working example:
def my_function(unused=False):
""" Function with unused argument. """
return True
Obviously, the argument unused is not used, so Pylint throws a warning:
W0613: Unused argument 'redundant' (unused-argument)
My point is that I do not want to remove the argument unused, because the function my_function will be called in a similar way as many other functions for which unused is used.
My question: How can I avoid the warning from Pylint without removing the optional argument?
Option 1: I can think of two options, but these options do not satisfy me. One option is to add some useless code, such that unused is used, e.g.,
def my_function(unused=False):
""" Function with unused argument. """
if unused:
dummy = 10
del dummy
return True
This feels as a waste of resources and it only clutters the code.
Option 2: The second option is to suppress the warning, e.g., like this:
def my_function(unused=False):
""" Function with unused argument. """
# pylint: disable=unused-argument
return True
I also do not really like this option, because usually Pylint warnings are a sign of bad style, so I am more looking to a different way of coding that avoids this warning.
What other options do I have?
I do not believe disabling some pylint warnings is bad style, as long as it is done carefully with clear intent and as specific as possible. For this purpose it is important to activate the useless-suppression check. When it is active pylint will warn you if some messages are locally disabled for no good reason. Add this to your .pylintrc:
[MESSAGES CONTROL]
enable=useless-suppression
For example I would recommend disabling the exact occurrence of the issue like in the following example:
def my_function(
used,
unused=False, # pylint: disable=unused-argument
):
""" Function with unused argument. """
return used
Adding a leading underscore should also keep pylint from triggering:
def my_function(used, _unused=False):
""" Function with unused argument. """
return used
Another commonly used pattern is the following:
def my_function(used, unused_a, unused_b=False):
""" Function with unused argument. """
_ = (unused_a, unused_b,)
return used
It would be possible to work out a solution by playing around with **kwargs. For example:
def _function_a(one, two=2):
return one + two
def _function_b(one, **kwargs):
return one + kwargs['two']
def _function_c(one, **_kwargs):
return one
def _main():
for _function in [_function_a, _function_b, _function_c]:
print(_function.__name__, _function(1, two=4))

How does #pytest.mark.filterwarnings work?

According to the docs you can ignore warnings like this:
#pytest.mark.filterwarnings("ignore:api v1")
def test_foo():
which gives:
But there doesn't seem to be any documentation on this mini-language (is it even a minilanguage?)
How is the match done?
I'm asking this because the following test doesn't ignore the DeprecationWarning raised by importing boto3:
#pytest.mark.filterwarnings("ignore:DeprecationWarning")
def test_ignore_warnings():
import boto3
Pytest outputs:
============================================================================================================================== warnings summary ===============================================================================================================================
/home/rob/dev/time-series/.venv/lib/python3.7/site-packages/botocore/awsrequest.py:624
/home/rob/dev/time-series/.venv/lib/python3.7/site-packages/botocore/awsrequest.py:624: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
class HeadersDict(collections.MutableMapping):
-- Docs: https://docs.pytest.org/en/latest/warnings.html
==================================================================================================================== 1 passed, 1 warnings in 0.36 seconds =====================================================================================================================
The filters work the same way as when you use -W argument with python command (see python --help). The format is described in the documentation of the warnings module. In short it's action:message:category:module:line where action is probably mandatory but the other parts can be omitted.
"ignore:api v1" would try to match the message by defining "a string containing a regular expression that the start of the warning message must match". Since you actually want to match category you can skip message. This means that you just seem to be missing one colon after ignore so this is the correct format:
#pytest.mark.filterwarnings("ignore::DeprecationWarning")
def test_ignore_warnings():
import boto3
However, you might apparently still get the warning if it happens during an import of a package outside of a test function. In this case you might need to specify the filter globally as a pytest's argument:
pytest -W "ignore::DeprecationWarning" ./tests/
...or add it to pytest.ini:
[pytest]
filterwarnings =
ignore::DeprecationWarning
If such a global exclusion is undesirable, you can try to limit it to a particular module:
ignore::DeprecationWarning:boto3
Testing
For testing purposes, you can use the following code:
import warnings
def something():
warnings.warn("Test", DeprecationWarning)
#pytest.mark.filterwarnings("ignore::DeprecationWarning")
def test_ignore_warnings():
something()

How Can I Suppress Warnings in Python Module CppHeaderParser

How Do I Change the Value of a Variable or Function in a Foreign Module?
I have a C++ header file that I need to parse. I'm using CppHeaderParser. Sadly, the header generates a lot of warnings that I'd like to suppress. The header in question is maintained by someone else, so I can't just fix it and be done.
CppHeaderParser doesn't include a configurable way to suppress warnings, but it is controlled by a variable and a function in the module
# Controls warning_print
print_warnings = 1
...
def warning_print(arg):
if print_warnings: print(("[%4d] %s"%(inspect.currentframe().f_back.f_lineno, arg)))
In my script, I tried changing the value of print_warnings:
import CppHeaderParser
CppHeaderParser.print_warnings = 0
cpp_info = CppHeaderParser.CppHeader(my_h_file)
But this had no effect.
How do I set a variable in a different module such that a class defined in that module will see it?
In my case, I might also like to redefine warning_print to examine the warnings and skip only the specific warnings I wish to ignore. I encountered the same problem as setting print_warnings. The assignment "worked" but had no effect, as if the code in CppHeaderParser wasn't looking at the values I set.
Note: I have worked around the problem by making a temp copy of the header file, correcting the problems, but I consider this a fragile solution.
Update: I was able to completely and unintelligently suppress all the warnings with:
CppHeaderParser.CppHeaderParser.print_warnings = 0
I've looked the source. The problem with your method is that in CppHeaderParser file there are import with *:
from .CppHeaderParser import *
So you need to change the way you import CppHeaderParser class:
from CppHeaderParser import CppHeaderParser
It should work.
Finally, just try this:
from CppHeaderParser import CppHeaderParser
CppHeaderParser.print_warnings = 0
cpp_info = CppHeaderParser.CppHeader(my_h_file)
The reason of such a behaviour is that from statement creates the copy of variable from imported module but not an alias. I will try to explain it on a simple example. Let's suppose we have some module named import_test with the following contents:
foo = "Init value"
def f():
print(foo)
Then execute the following code:
>> from import_test import *
>> f()
Init value
>> foo = "Updated value"
>> f()
Init value
The reason is that you change the copy of variable foo so the actual value of import_test.foo variable is not changed.
But we have a different behaviour when we import the module itself:
>> import import_test
>> import_test.f()
Init value
>> import_test.foo = "Updated value"
>> import_test.f()
Updated value
So in the case of CppHeaderParser package when you make import CppHeaderParser the code inside CppHeaderParser.__init__ is executed. And python interpreter creates a copy of warnings_print variable inside a CppHeaderParser. But to change the behaviour of a print_warning function you have to change the value of CppHeaderParser.CppHeaderParser.warnings_print.
Try monkey patching:
import CppHeaderParser
def my_silent_warning_print(arg):
pass
CppHeaderParser.warning_print = my_silent_warning_print

Categories