flake8 beschwert sich über den booleschen Vergleich "==" in der Filterklausel

73

Ich habe ein boolesches Feld in der MySQL-DB-Tabelle.

# table model
class TestCase(Base):
    __tablename__ = 'test_cases'
    ...
    obsoleted = Column('obsoleted',  Boolean)

Um die Anzahl aller nicht veralteten Testfälle zu ermitteln, gehen Sie einfach wie folgt vor:

caseNum = session.query(TestCase).filter(TestCase.obsoleted == False).count()
print(caseNum)

Das funktioniert gut, aber der flake8 meldet die folgende Warnung:

E712: Der Vergleich mit False sollte "wenn cond False:" oder "if not cond:" sein.

Okay, ich denke das macht Sinn. Ändern Sie also meinen Code wie folgt:

caseNum = session.query(TestCase).filter(TestCase.obsoleted is False).count()

oder

caseNum = session.query(TestCase).filter(not TestCase.obsoleted).count()

Aber keiner von ihnen kann arbeiten. Das Ergebnis ist immer 0. Ich denke, die Filterklausel unterstützt den Operator "ist" oder "ist nicht" nicht. Kann mir jemand sagen, wie ich mit dieser Situation umgehen soll? Ich möchte die Flocke nicht deaktivieren.

Jruv
quelle
8 PEP rät ausdrücklich gegen „wenn cond ist False“. Ich bin überrascht, dass das pep8-Tool das Gegenteil bewirkt.
Janne Karila

Antworten:

89

Das liegt daran, dass SQLAlchemy-Filter einer der wenigen Orte sind, an denen dies == Falsetatsächlich Sinn macht. Überall sonst sollten Sie es nicht verwenden.

Fügen Sie # noqader Zeile einen Kommentar hinzu und fertig.

Oder Sie können verwenden sqlalchemy.sql.expression.false:

from sqlalchemy.sql.expression import false

TestCase.obsoleted == false()

Dabei wird false()der richtige Wert für Ihren Sitzungs-SQL-Dialekt zurückgegeben. Es gibt eine Übereinstimmung sqlalchemy.expression.true.

Martijn Pieters
quelle
71

SQL Alchemy hat auch is_und isnotFunktionen, die Sie verwenden können. Ein Beispiel wäre

Model.filter(Model.deleted.is_(False))

Mehr dazu hier

Avoliva
quelle
1
In Python isund ==sind unterschiedlich, aber ich bin mir ziemlich sicher, dass das hier generierte SQL das gleiche sein wird.
Avoliva
1
isund ==unterscheiden sich in SQLAlchemy, da Sie den Identitätsoperator ( is) in Python nicht überschreiben können . Ein Ausdruck wie Model.column is Falsewird immer so ausgewertet, Falsedass der Vergleich immer sofort in Python und nicht in der Datenbank erfolgt. Das Ergebnis des Vergleichs der Identität eines Spaltenobjekts mit einem Booleschen Wert ist immer False. Dadurch werden Anweisungen wie WHERE FALSEoder AND FALSEin Ihre Abfrage eingefügt, was in den meisten Fällen dazu führt, dass 0 Zeilen zurückgegeben werden, unabhängig davon, was passiert.
Josh
9

Ich habe einen Blick darauf, welche genaue Abfrage generiert wird, SQLAlchemywenn ==und is_wann der DatenbankdialektPostgresql für ein boolesches Feld verwendet wird:

  • denn ==wir bekommen:

    1. field == False wird konvertiert zu field = false
    2. field == True wird konvertiert zu field = true
    3. field == None wird konvertiert zu field IS NULL
  • denn is_()wir bekommen:

    1. field.is_(False) wird konvertiert zu field IS false
    2. field.is_(True) wird konvertiert zu field IS true
    3. field.is_(None) wird konvertiert zu field IS NULL

HINWEIS: is_(not None) Wird dahingehend bewertet, is_(bool(not None)was is_(True)Geben gibt , field = truesodass Sie lieber isnot(None)produzieren field IS NOT NULL

Andilabs
quelle
2
Beachten Sie auch, dass Sie bei Verwendung von PostgreSQL isanstelle von =PostgreSQL niemals NULL als Antwort erhalten, selbst wenn ein Operand NULL ist. =gibt NULL zurück, wenn einer der Operanden NULL ist.
Jim Hunziker
0

@Jruv # noqaVor Anweisung verwenden, wird die Warnung ignoriert.

user3016020
quelle
3
# noqadeaktiviert flake8 / pep / other-linters für den gesamten String, sodass auch andere Flusenwarnungen ignoriert werden. Andere Antworten bieten bessere Lösungen, zum Beispiel die .is_Methode.
Maxkoryukov