Python 3.6-Projektstruktur führt zu RuntimeWarning

12

Ich versuche mein Projekt für die Verteilung zu packen, aber ich treffe RuntimeWarning , wenn ich das Modul starte.

Ich habe einen Fehlerbericht in der Python-Mailingliste gefunden, der anzeigt, dass das RuntimeWarning neues Verhalten ist, das eingeführt wurde in Python 3.5.2.

Beim Lesen des Fehlerberichts scheint ein Doppelimport zu erfolgen, und dieser RuntimeWarning ist korrekt, um den Benutzer zu alarmieren. Ich sehe jedoch nicht, welche Änderungen ich an meiner eigenen Projektstruktur vornehmen muss, um dieses Problem zu vermeiden.

Dies ist das erste Projekt, das ich "richtig" strukturieren wollte. Ich hätte gerne ein ordentliches Layout, wenn ich den Code drücke, und eine Projektstruktur, die geklont und von anderen einfach ausgeführt werden kann.

Ich habe meine Struktur hauptsächlich auf Ссылка aufgebaut.

Ich habe Details eines Mindestarbeitsbeispiels unten hinzugefügt.

Um das Problem zu replizieren, führe ich die Hauptdatei mit python -m :

aus %Vor%

Das Ausführen meiner Tests ist in Ordnung:

%Vor%

Eine Projektstruktur zur Replizierung des Problems lautet wie folgt:

%Vor%

In der Datei proj/proj.py :

%Vor%

In proj/__init__.py :

%Vor%

In tests/context.py :

%Vor%

Schließlich in tests/test_proj.py :

%Vor%

Kann mir jemand helfen, meine Projektstruktur zu korrigieren, um dieses Doppelimport-Szenario zu vermeiden? Jede Hilfe mit diesem würde sehr geschätzt werden.

    
Matthew 13.04.2017, 13:34
quelle

4 Antworten

8

In diesem speziellen Fall liegt die doppelte Importwarnung an dieser Zeile in proj/__init__.py :

%Vor%

Was diese Zeile bedeutet ist, dass zu dem Zeitpunkt, zu dem die -m switch-Implementierung den import proj -Schritt beendet, proj.proj bereits bereits importiert wurde / ist als Nebeneffekt des Importierens des übergeordneten Pakets.

Vermeidung der Warnung

Um die Warnung zu vermeiden, müssen Sie eine Möglichkeit finden, sicherzustellen, dass das importierte Paket nicht implizit das Paket importiert, das mit dem Schalter -m ausgeführt wird.

Die beiden Hauptoptionen zum Lösen sind:

  1. Löschen Sie die Zeile from .proj import main (wie @John Moutafis vorgeschlagen), vorausgesetzt, dass dies ohne Verletzung der API-Kompatibilitätsgarantien erfolgen kann; oder
  2. Löschen Sie den if __name__ == "__main__": -Block aus dem proj Submodul und ersetzen Sie ihn durch eine separate proj/__main__.py -Datei, die einfach funktioniert:

    %Vor%

Wenn Sie mit Option 2 fortfahren, ändert sich auch der Aufruf der Befehlszeile so, dass er nur python -m proj lautet, anstatt auf ein Submodul zu verweisen.

Eine stärker abwärtskompatible Variante von Option 2 ist das Hinzufügen von __main__.py , ohne den CLI-Block aus dem aktuellen Submodul zu löschen. Dies kann besonders in Verbindung mit DeprecationWarning :

ein guter Ansatz sein %Vor%

Wenn proj/__main__.py bereits für einen anderen Zweck verwendet wird, können Sie auch python -m proj.proj durch python -m proj.proj_cli ersetzen, wobei proj/proj_cli.py folgendermaßen aussieht:

%Vor%

Warum existiert die Warnung?

Diese Warnung wird ausgegeben, wenn die -m -Schalterimplementierung im Begriff ist, den Code eines bereits importierten Moduls erneut zu laden im Modul __main__ , was bedeutet, dass Sie zwei verschiedene Kopien von allem haben werden Es definiert - Klassen, Funktionen, Container, etc.

Je nach den Besonderheiten der Anwendung kann dies gut funktionieren (weshalb es eher eine Warnung als ein Fehler ist), oder es kann zu bizarrem Verhalten führen, wie z. B. Statusänderungen auf Modulebene nicht wie erwartet oder sogar Ausnahmen nicht gefangen werden, weil der Ausnahmebehandler versucht hat, den Ausnahmetyp von einer Instanz des Moduls abzufangen, während die Ausnahme ausgelöst den Typ von der anderen Instanz verwendet hat.

Daher die vage this may cause unpredictable behaviour Warnung - wenn die Dinge schief laufen, weil der Code der obersten Ebene des Moduls zweimal ausgeführt wird, können die Symptome so ziemlich alles sein.

Wie können Sie komplexere Fälle debuggen?

Während in diesem speziellen Beispiel der Nebeneffekt-Import direkt in proj/__init__.py ist, gibt es eine viel subtilere und schwer zu debuggende Variante, wo das übergeordnete Paket stattdessen:

%Vor%

und dann ist some_other_module (oder ein importiertes Modul):

%Vor%

Unter der Annahme, dass das Fehlverhalten reproduzierbar ist, besteht der Hauptweg zum Debuggen dieser Art von Problemen darin, Python im ausführlichen Modus auszuführen und die Importsequenz zu überprüfen:

%Vor%

Dieses spezielle Beispiel zeigt nur die Basis von Importen, die Python 2.7 auf Fedora beim Start ausführt. Wenn Sie einen Doppelimport RuntimeWarning wie den in dieser Frage debuggen, würden Sie in der ausführlichen Ausgabe nach den Zeilen "import proj" und dann "import proj.proj" suchen und dann die unmittelbar vorhergehenden Importe genau betrachten die Zeile "import proj.proj".

    
ncoghlan 13.07.2017 02:43
quelle
0

python -m ist ein bisschen schwierig. @ncoghlan hat bereits detaillierte Informationen zur Verfügung gestellt. Wenn wir versuchen, mit python -m zu laufen, werden standardmäßig alle Pakete in sys.path / pythonpath importiert. Wenn Ihr Paket eine Anweisung import in die Verzeichnisse in den PATHs hat, tritt die obige Warnung auf.

Mein PYTHONPATH hat bereits das Projektverzeichnis. Also wenn ich das mache

%Vor%

System gibt die Warnung aus. Daher müssen keine expliziten Importe vorgenommen werden, wenn sich der Pfad im Python-Pfad befindet.

    
Doogle 02.09.2017 13:38
quelle
0

Wenn Sie sicher sind, dass die Warnung für Sie nicht relevant ist, können Sie RuntimeWarnings einfach durch das Modul runpy ignorieren, das die Logik hinter dem Schalter -m implementiert:

%Vor%

Dies kann natürlich auch relevante Warnungen verbergen, aber zumindest im Moment ist dies das einzige RuntimeWarning, das runpy verwendet. Alternativ könnte die Filterung strenger gemacht werden, indem ein Muster für die Nachrichten- oder Zeilennummer spezifiziert wird, wo eine Warnung auftreten muss, aber beide können unterbrochen werden, wenn runpy später bearbeitet wird.

    
Pekka Klärck 15.03.2018 17:41
quelle

Tags und Links