I have a Flask (v0.10.1) application using Flask-SQLAlchemy (v2.0) and I\'m trying to configure Pylint to check it. Running with Python 3.4.2.
First error was:
The one that worked for me was switching to flake8 python linter. Below are the steps:
Ctrl+shift+P(For Windows Users)Python:Select Linter. You will see a list of all Linters and select flake8. Use pylint plugin pylint-flask-sqlalchemy
pip install pylint_flask_sqlalchemy
And in your settings.json of VisualCode
"python.linting.pylintArgs": ["--load-plugins", "pylint_flask_sqlalcheny"]
Here's a version of joeforker's answer that dynamically adds all public methods from the Session object back into a scoped_session's locals at lint-time, instead of hardcoding a few well-known method names.
Define {path}/{to}/pylintplugins.py:
import sys
from astroid import MANAGER, scoped_nodes
from astroid.builder import AstroidBuilder
from sqlalchemy.orm import Session
def register(_linter):
pass
def transform(cls):
if cls.name == 'scoped_session':
builder = AstroidBuilder(MANAGER)
module_node = builder.module_build(sys.modules[Session.__module__])
session_cls_node = [
c for c in module_node.get_children()
if getattr(c, "type", None) == "class" and c.name == Session.__name__
][0]
for prop in Session.public_methods:
cls.locals[prop] = [
c for c in session_cls_node.get_children()
if getattr(c, "type", None) == "method" and c.name == prop
]
MANAGER.register_transform(scoped_nodes.Class, transform)
And in your .pylintrc file:
load-plugins={path}.{to}.pylintplugins
This is how I'm dealing with the issue for scoped_session. Trivial to extend to check for more cls names with SQLAlchemy attributes.
from astroid import MANAGER
from astroid import scoped_nodes
def register(_linter):
pass
def transform(cls):
if cls.name == 'scoped_session':
for prop in ['add', 'delete', 'query', 'commit', 'rollback']:
cls.locals[prop] = [scoped_nodes.Function(prop, None)]
MANAGER.register_transform(scoped_nodes.Class, transform)
Adapted from https://docs.pylint.org/en/1.6.0/plugins.html . Then make sure pylint loads your plugin.
pylint -E --load-plugins warning_plugin Lib/warnings.py
(or load it in pylintrc)
In the first solution in this page, following needs to be updated. Its a typo issue,
Instead of "pylint_flask" in this settings.json parameter(in this line: "python.linting.pylintArgs": ["--load-plugins", "pylint_flask"]) it should be "python.linting.pylintArgs": ["--load-plugins", "pylint-flask"]).
Any class you declare as inheriting from db.Model won't have query member until the code runs so Pylint can't detect it.
The workaround for this besides ignoring no-member errors on every query call is to add query on the generated-members list in a Pylint config file since it is a member that will only be created at runtime.
When you run Pylint, it will search for a configuration file as stated in its documentation:
You can specify a configuration file on the command line using the --rcfile option. Otherwise, Pylint searches for a configuration file in the following order and uses the first one it finds:
pylintrcin the current working directory- If the current working directory is in a Python module, Pylint searches up the hierarchy of Python modules until it finds a pylintrc file. This allows you to specify coding standards on a module-by-module basis. Of course, a directory is judged to be a Python module if it contains an
__init__.pyfile- The file named by environment variable
PYLINTRC- if you have a home directory which isn’t
/root:
.pylintrcin your home directory.config/pylintrcin your home directory/etc/pylintrc
So if you don't have a config and you want a system wide default config for pylint you can use pylint --generate-rcfile > /etc/pylintrc. This will generate a commented configuration file according to the current configuration (or the default if you don't have one) that you can edit to your preferences.
p.s.: generated-members on a config file is the right way to deal with this warning, as it's said by the commented config
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed. Python regular
# expressions are accepted.