Can voluptuous code pass pylint? - python

I run pylint -E as part of the tests on my Python project to ensure that errors don't creep into untested code. Generally this works quite well. But recently I've been running into problems with voluptuous and pylint.
The problem is that pylint thinks that the values returned by voluptuous Schemas are lists, which is simply not the case. Here's a toy program:
import voluptuous
MyType = voluptuous.Schema({
'q': str
})
def foo(bar):
bar = MyType(bar)
q = bar.get('q')
print q
foo({'q': '1324'})
It runs just fine:
$ python toy.py
1234
pylint, however, flags the .get() call:
$ pylint -E toy.py
No config file found, using default configuration
************* Module toy
E: 11, 8: Instance of 'list' has no 'get' member (no-member)
How can I get this program to pass pylint -E?

One option is to ignore the voluptuous module entirely, e.g.
$ pylint -E --ignored-modules=voluptuous toy.py
(passes)
If would be nice if pylint understood voluptuous better, though.

Related

Using Pylint with PyModule generated using PyO3 and maturin

Pylint will not recognize any of the functions from a PyModule that I created using PyO3 and maturin. All of the functions import and run fine in the python code base, but for some reason Pylint is throwing E1011: no-member warnings.
Below is a (likely) incomplete dummy example, but is provided in order to show the way I am decorating using pymodule and pyfunction:
#[pyfunction]
fn add_nums(
_py: Python<'_>,
a: f32,
b: f32,
) -> PyResult<f32> {
let res:f32 = a+b;
Ok(res)
}
#[pymodule]
fn my_module(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(add_nums, m)?)?;
Ok(())
}
Then if I build that using maturin build --release and install the module, from the resulting wheelfile, into my python environment and import into a script:
import my_module
my_module.add_nums(5, 6) # ignore that these are not f32 - irrelevant this is a dummy example
If I then run pylint on that file (from terminal - VS Code pylint extension actually does not complain about this...), I end up with something like: E1101: Module 'my_module' has no 'add-nums' member (no-member) even though the code (not this code - but the real code which I cannot include here) runs just fine.
Has anyone successfully built wheelfiles using maturin, used them in another project, then had Pylint play nicely with that project and recognize that the methods do actually exist?
Pylint has a extension-pkg-allow-list setting which you can use to inspect non-python modules. It will need to load the extension into pylint's interpreter though, which is why it's not enabled by default.
There's also requests to support (and lint) pyi, but AFAIK that's not supported yet, cf #2873 and #4987.
Before Pylint 2.8, the setting is extension-pkg-whitelist.
Similar to the answer by #Masklinn except it looks like the term 'extension-pkg-whitelist' exists in older versions and later the 'extension-pkg-allow-list' does not (though it was introduced for obvious societal reasons).
add the following into the [MASTER] section of your .pylintrc:
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code.
extension-pkg-allow-list=
my_module
for versions where this is not supported (someone please update which version it changed here) use the extension-pkg-whitelist instead.

Pytest run a 'setup' method based on pytest command line argument

My issue is, how can I execute a setup method, that is based on a pytest argument when I run pytest? Basically I want this 'setup method' to run first before running any tests.
For simplicity lets say I have a file 'text_something.py'
import somemodule
def test_some(usefakemodule):
...
the 'somemodule' is either installed in the environment or not. If its installed already, then it will work no problem. If not, I need to add the path of the fake module by running a method that basically does sys.path.append(XXX).
In short, I want to run 'pytest -v --usefakemodule' if I want to use the fake module dir, or just 'pytest -v' to just use that library installed locally (assuming its installed there).
I tried adding a fixture (scope=session) in conftest.py, but it doesnt seem to run/execute it first before it executes 'test_something.py', which will then state no module named 'somemodule'
I can run a regular method in conftest, but I dont know how it can depend on the pytest command line argument 'usefakemodule'.
In your conftest.py you use pytest_addoption combined with pytest_cmdline_main,
pleas refer to the documentation for details.
import pytest
def pytest_addoption(parser):
parser.addoption(
"--usefakemodule", action="store_true", default=False, help="Use fake module "
)
def pytest_cmdline_main(config):
usefakemodule = config.getoption("--usefakemodule")
print(usefakemodule)
if usefakemodule:
print("OK fake module ")
else:
print("no fakes")
I don't know whether/how you can have pytest accept extra arguments, but here are a couple other ideas for accomplishing this:
Just try to import the real module, and update the load path if you get an ImportError:
try:
import somemodule
except ImportError:
sys.path.append(XXX)
import somemodule
Or, use an environment var, and run with USE_FAKE_MODULE=true pytest -v:
import os
if os.environ.get('USE_FAKE_MODULE'):
sys.path.append(XXX)

How to tell "where class definition of forward reference in type hints is" to Sphinx?

How to tell "where class definition of forward reference in type hints is" to Sphinx?
How to avoid lost parameter (in Sphinx documentation) whose type is defined by forward reference of type hints?
I use sphinx-apidoc to write the documentation of my Python program.
I'm using forward reference of type hints defined in PEP 484 like this:
# In file A/A.py
class A:
def a(self, param: 'MyClass') -> None:
"""docstring here"""
pass
MyClass is not imported to avoid circular imports. Of course, the program works fine because type hints are ignored at runtime.
When I run sphinx-apidoc and make html, the following warning (name 'MyClass' is not defined) appears.
$ sphinx-apidoc -f -o doc .
Creating file doc/A.rst
$ make html
...
reading sources... [100%] main
path/to/A/A.rst:XX: WARNING: error while formatting arguments for A.A.a: name 'MyClass' is not defined
looking for now-outdated files... none found
...
build succeeded, 1 warnings.
Build finished. The HTML pages are in _build/html.
In the generated html, the method 'a' has no parameter like this:
A module
class A
a() -> None
docstring here
In the context with import MyClass (without circular imports), generated html has the parameter like this:
A module
class A
a(param: MyClass) -> None
docstring here
My Environment:
$ python3 --version
Python 3.5.2
$ pip3 --version
pip 8.1.1 from /usr/lib/python3/dist-packages (python 3.5)
$ pip3 freeze | grep Sphinx
You are using pip version 8.1.1, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Sphinx==1.5.2
Accord to sphinx issues tracker, they fix this on sphinx 1.6. Maybe try with that version. I never try so this is just a suggestion.

nosetests: --nologcapture still captures INFO messages

With the code
import unittest
import logging
class LoggingTest(unittest.TestCase):
def test_that_logs(self):
logging.warning("Hello")
logging.info("World")
for a in xrange(100000000000000000):
pass
I get this unexpected output:
$ nosetests --version
nosetests version 1.3.7
$ nosetests log_from_nosetest.py --nocapture --nologcapture
WARNING:root:Hello
^C
----------------------------------------------------------------------
Ran 1 test in 105.376s
OK
As can be seen. The WARNING log level message is printed, but not the INFO level one.
I've tried using the --logging-level setting but without success.
It seems a missing feature. If --nologcapture is set, nose simply ignores all logging setup, e.g. --logging-level is not used at all. You can remedy that with a
logging.basicConfig(level=logging.INFO)
in your code - not sure if that's what you want, because this kind of setup shouldn't be in library-code at all. It would be fine within the test-setup though.
This is because the default log level is warning. Set it with
logging.getLogger('').setLevel(logging.INFO)

Turn off sqlalchemy warnings in nosetests

I'm trying to suppress all sqlalchemy warnings while running my test suite with nosetests. I read Turn off a warning in sqlalchemy
.............................../Users/ca/.pythonbrew/venvs/Python-2.7.3/api/lib/python2.7/site-packages/SQLAlchemy-0.7.5-py2.7-macosx-10.7-x86_64.egg/sqlalchemy/engine/default.py:330: Warning: Field 'random_id' doesn't have a default value
cursor.execute(statement, parameters)
I included this in my package's __init__.py file:
def setup_package():
"""Setup the test during the whole session.
Run by nosetests
"""
# Suppress all SQLAlchemy warnings
warnings.filterwarnings("ignore", category=sa_exc.SAWarning)
With the proper imports. I know it is run by nosetests because I tried some other stuff which raised error. The only thing is that it has no effect whatsoever. Warnings are still displayed.
Any idea?
Thanks!
It seems that nose overwrites whatever you set with:
warnings.filterwarnings("ignore")
However you can filter warnings during nose test with a command line option to nose. e.g.:
$ nosetests --logging-filter=SAWarning
I found that this still may not work under all circumstances. If this is the case you can try:
$ python -W ignore `which nosetests`

Categories

Resources