Reputation: 1679
SQLAlchemy seems to give me a ton of errors on pylint that I can't resolve.
The first problem is that each table must be defined as a new class.
Example:
class Person(BASE):
"""Person Table Definition"""
__tablename__ = 'person'
id = Column(Integer, primary_key=True)
name = Column(String(30))
...causes these errors for each table I define:
W: 20, 0: Class has no __init__ method (no-init)
R: 20, 0: Too few public methods (0/2) (too-few-public-methods)
The second problem is using a global variable for the SQLAlchemy engine
and BASE
constructs. I'm not sure how I can refactor this code to make these variables not global, since the parameter BASE
must be passed into the table class definitions above.
BASE = sqlalchemy.ext.declarative.declarative_base()
global engine
...
def create_sqla_engine():
"""Create the SQLA engine"""
global engine
engine = create_engine('mysql+mysqlconnector://root:@127.0.0.1:3306/sqlalchemy_example')
I'm new to python but this seems ugly. pylint complains about it, too:
C: 51, 0: Invalid constant name "engine" (invalid-name)
Finally, pylint thinks I'm not using the imports that I am clearly using in this code.
W: 15, 0: Unused declarative_base imported from sqlalchemy.ext.declarative (unused-import)
W: 16, 0: Unused sessionmaker imported from sqlalchemy.orm (unused-import)
...why? Is pylint not compatible with python3? Should I be importing the modules I need within the methods they are used, instead of at the top of the file?
Upvotes: 4
Views: 4070
Reputation: 8823
SQLAlchemy is not very pylint-friendly.
There are a few things in your question.
This error is often wrong, see here: What does pylint's "Too few public methods" message mean
Pylint is right in this case! If you import declarative_base
, you can use it directly: declarative_base(...)
, and not via sqlalchemy.ext.declarative.declarative_base()
.
Generally - if an import is unused, try to remove it and check if your code (and unit tests, watch out for doctests!) still works. If so, the import was indeed unused.
TL;DR - yes, you're using the code, but not using the imported names.
Pylint is wrong in this instance, but somewhat right in principle.
(I spent many hours convincing even decent programmers to just override Pylint's const-rgx
setting...).
Basically, Pylint believes every global variable is a constant. In your case it's not. So, pylint tries to discourage you from using global variables.
Also, you shouldn't write global engine
outside of the functions (at global scope). It should be something like:
engine = None
Pylint will still complain about wrong constant name. You can silence this warning explicitly. (I don't recommend renaming it to ENGINE
)
I found this question, because I wanted to see something about pylint's suggestion in SQLAlchemy conditions.
Unlike Django models, SQLAlchemy uses comparisons ==
to have an equality condition (Django's field_gt=5
is actually clumsy, I've got to liking SQLAlchemy's way over time). But Pylint will complain:
session.query(AlarmState).filter(AlarmState.is_default == True).one()
gives
C0121: comparison to True should be just 'expr' or 'expr is True'
It's all good and well - in this case we can really write:
session.query(AlarmState).filter(AlarmState.is_default).one()
And it's fine.
But, what about:
session.query(AlarmState).filter(AlarmState.is_default == False).all()
well, we get:
C0121: comparison to False should be just 'not expr' or 'expr is False'
What now? This doesn't work: session.query(AlarmState).filter(not AlarmState.is_default .all()
!!! - it seems to filter by a False
condition, and returns an empty set. Same here: sess.query(AlarmState).filter(AlarmState.is_default is False).all()
.
I have found a way around it - you actually can write:
session.query(AlarmState).filter(AlarmState.is_default.__eq__(False)).all()
And it both:
I just don't feel great about this. It's playing cat and mouse with this stupid tool. I was wondering about what others do about it, and that's how I got here.
EDIT - ok, I found the "right" way to do it...
False
(without complaints)?from sqlalchemy import not_
session.query(AlarmState).filter(not_(AlarmState.is_default)).all()
This is what not_
is probably for...
Upvotes: 4