【问题标题】:SQLAlchemy and pylintSQLAlchemy 和 pylint
【发布时间】:2015-07-26 11:11:44
【问题描述】:

SQLAlchemy 似乎在 pylint 上给了我很多我无法解决的错误。

第一个问题是每个表都必须定义为一个新的类。

例子:

class Person(BASE):
    """Person Table Definition"""
    __tablename__ = 'person'
    id = Column(Integer, primary_key=True)
    name = Column(String(30))

...导致这些错误对于我定义的每个表

W: 20, 0: Class has no __init__ method (no-init)
R: 20, 0: Too few public methods (0/2) (too-few-public-methods)

第二个问题是为 SQLAlchemy engineBASE 构造使用全局变量。我不确定如何重构此代码以使这些变量不是全局变量,因为必须将参数 BASE 传递到上面的表类定义中。

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')

我是 python 新手,但这看起来很难看。 pylint 也抱怨它:

C: 51, 0: Invalid constant name "engine" (invalid-name)

最后,pylint 认为我没有使用我在这段代码中明确使用的导入。

W: 15, 0: Unused declarative_base imported from sqlalchemy.ext.declarative (unused-import)
W: 16, 0: Unused sessionmaker imported from sqlalchemy.orm (unused-import)

...为什么? pylint 与 python3 不兼容吗?我应该在它们使用的方法中导入我需要的模块,而不是在文件的顶部?

【问题讨论】:

  • 虽然BASE 应该不会造成任何问题,但global engine 确实是代码异味。了解如何从方法中返回引擎实例。您只需要谨慎使用引擎;您应该主要向sessionmaker 请求会话,这很便宜。
  • WRT 'no init' 和 'too few public methods' 对于有元类的类,比如表,有an open bug

标签: python sqlalchemy pylint


【解决方案1】:

SQLAlchemy 对 pylint 不太友好。

您的问题中有几件事。

1。公共方法太少

这个错误经常出错,看这里:What does pylint's "Too few public methods" message mean

2。未使用的导入

Pylint 在这种情况下是对的!如果导入declarative_base,可以直接使用:declarative_base(...),而不是通过sqlalchemy.ext.declarative.declarative_base()

通常 - 如果导入未使用,请尝试将其删除并检查您的代码(和单元测试,注意 doctests!)是否仍然有效。如果是这样,则确实未使用导入。

TL;DR - 是的,您使用的是代码,但没有使用导入的names

3。无效的常量名

Pylint 在这种情况下是错误的,但原则上是正确的。

(我花了很多时间说服即使是体面的程序员也只需覆盖 Pylint 的 const-rgx 设置...)。

基本上,Pylint 相信每个全局变量都是常数。在你的情况下,它不是。因此,pylint 试图阻止您使用全局变量。

另外,你不应该在函数之外写global engine(在全局范围内)。它应该是这样的:

engine = None

Pylint 仍然会抱怨错误的常量名称。您可以明确将此警告静音。 (不建议重命名为ENGINE

4。 (额外)SQLAlchemy 查询构建

我发现了这个问题,因为我想看看 pylint 在 SQLAlchemy 条件下的建议。

与 Django 模型不同,SQLAlchemy 使用比较 == 来获得相等条件(Django 的 field_gt=5 实际上很笨拙,随着时间的推移我不得不喜欢 SQLAlchemy 的方式)。但皮林特会抱怨:

session.query(AlarmState).filter(AlarmState.is_default == True).one()

给予

C0121: comparison to True should be just 'expr' or 'expr is True'

一切都很好——在这种情况下,我们真的可以写:

session.query(AlarmState).filter(AlarmState.is_default).one()

没关系。

但是,怎么样:

session.query(AlarmState).filter(AlarmState.is_default == False).all()

好吧,我们得到:

C0121: comparison to False should be just 'not expr' or 'expr is False'

现在呢?这不起作用:session.query(AlarmState).filter(not AlarmState.is_default .all()!!! - 它似乎按False 条件过滤,并返回一个空集。同样在这里:sess.query(AlarmState).filter(AlarmState.is_default is False).all()

我找到了解决办法——你实际上可以写:

session.query(AlarmState).filter(AlarmState.is_default.__eq__(False)).all()

两者兼而有之:

  • 给出正确的结果
  • 不会引发 Pylint 通知

我只是对此感觉不太好。它正在用这个愚蠢的工具玩猫捉老鼠。 我想知道其他人对此做了什么,这就是我来到这里的原因。

编辑 - 好的,我找到了“正确”的方法......

如何将列与False 进行比较(无投诉)?

from sqlalchemy import not_
session.query(AlarmState).filter(not_(AlarmState.is_default)).all()

这可能是not_ 的用途...

【讨论】:

  • 有时这是not_ 的完美用法,尽管我更喜欢可读性更强的session.query(AlarmState).filter(AlarmState.is_default.is_(False)).all()。如果不对 True/False 值进行相等比较,它也能很好地工作。
猜你喜欢
  • 2015-03-27
  • 1970-01-01
  • 2017-10-25
  • 2018-09-15
  • 1970-01-01
  • 2015-03-25
  • 2020-12-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多