2016-04-10 7 views
2

TL; DRImport von übergeordnetem Verzeichnis für ein Testunterverzeichnis ohne Verpackung zu verwenden, Python 2.7

Für eine feste und unveränderliche Nicht-Paket Verzeichnisstruktur wie folgen aus:

some_dir/ 
    mod.py 
    test/ 
     test_mod.py 
     example_data.txt 

was eine nicht -Paket Möglichkeit, test_mod.py importieren von mod.py importieren?

Ich bin in diesem Fall auf die Verwendung von Python 2.7 beschränkt.

Ich möchte ein paar Tests für die Funktionen in mod.py schreiben. Ich möchte ein neues Verzeichnis erstellen test, das neben mod.py sitzt und darin gibt es eine Testdatei test/test_mod.py, die die Funktionen von mod.py importieren und sie testen sollte.

Aufgrund der bekannten Einschränkungen von relativen Importen, die auf paketbasierter Benennung beruhen, können Sie dies nicht auf einfache Weise tun. Alle Ratschläge zu diesem Thema schlagen jedoch vor, das Skript als Paket zu erstellen und dann relative Importe zu verwenden, was für meinen Anwendungsfall unmöglich ist.

In meinem Fall ist es nicht zulässig für mod.py als ein Paket gebaut werden und ich kann nicht verlangen, Benutzer von, um es zu installieren. Sie können stattdessen einfach die Datei aus der Versionskontrolle heraus überprüfen und sie einfach verwenden, wie sie wollen, und ich kann diesen Umstand nicht ändern.

Angesichts dieser, was ist eine Möglichkeit, eine einfache, unkomplizierte testVerzeichnis?

Hinweis: nicht nur eine Test-Datei, die neben mod.py sitzt, sondern ein tatsächliches Testverzeichnis, da es andere Vermögenswerte wie Testdaten sein, die mit ihm kommen, und das Unterverzeichnis Organisation ist von entscheidenden Bedeutung.

Ich entschuldige mich, wenn dies ein Duplikat ist, aber aus dem Dutzend oder so Permutationen dieser Frage, die ich in meiner Forschung vor dem Entsenden gesehen habe, habe ich keinen einzigen gesehen, der sich damit befasst. Sie alle sagen, Verpackungen zu verwenden, was für meinen Fall keine zulässige Option ist.

+0

Vielleicht nicht die eleganteste Lösung, aber Sie können 'PYTHONPATH' für Ihren Testläufer modifizieren. . . – mgilson

Antwort

1

Basierend auf dem Kommentar von @mgilson fügte ich dem Testverzeichnis eine Datei import_helper.py hinzu.

some_dir/ 
    mod.py 
    test/ 
     test_mod.py 
     import_helper.py 
     example_data.txt 

Hier ist der Inhalt von import_helper.py:

import sys as _sys 
import os.path as _ospath 
import inspect as _inspect 
from contextlib import contextmanager as _contextmanager 

@_contextmanager 
def enable_parent_import(): 
    path_appended = False 
    try: 
     current_file  = _inspect.getfile(_inspect.currentframe()) 
     current_directory = _ospath.dirname(_ospath.abspath(current_file)) 
     parent_directory = _ospath.dirname(current_directory) 
     _sys.path.insert(0, parent_directory) 
     path_appended = True 
     yield 
    finally: 
     if path_appended: 
      _sys.path.pop(0) 

und dann in dem Import Abschnitt test_mod.py, vor einem Versuch mod.py, ich habe zu importieren hinzugefügt:

import unittest 
from import_helper import enable_parent_import 

with enable_parent_import(): 
    from mod import some_mod_function_to_test 

Es ist bedauerlich, PYTHONPATH manuell zu mandrieren, aber es als ein Kontextmanager zu schreiben hilft ein wenig und stellt sys.path zurück zu seinem o. zur Verfügung Startzustand vor der Änderung des übergeordneten Verzeichnisses.

Damit diese Lösung über mehrere Instanzen dieses Problems skalieren kann (sagen wir morgen, dass ich ein widget.py Modul für einige nicht verwandte Aufgaben schreiben soll und es auch nicht als Paket verteilt werden kann), muss ich meine Hilfsfunktion replizieren und stellen Sie sicher, dass eine Kopie davon mit irgendwelchen Tests verteilt wird, oder ich muss dieses kleine Dienstprogramm als ein Paket schreiben, sicherstellen, dass es global in meiner Benutzerbasis installiert wird, und es dann weiterführen. Wenn Sie eine Menge internen Python-Code für ein Unternehmen verwalten, wird der Code-Verteilungsmodus häufig dadurch unterbrochen, dass das "Installieren" von Python-Code dem Auschecken der neuen Version aus der Versionskontrolle gleichkommt.

Da der Code oft extrem lokalisiert ist und für eine kleine Gruppe von Aufgaben für eine kleine Untergruppe eines größeren Teams spezifisch ist, wird der Overhead für die Freigabe von Code über die Verpackung (selbst wenn es im Allgemeinen eine bessere Idee ist) einfach nie geschehen.

Daher denke ich, dass der Anwendungsfall, den ich oben beschrieben habe, extrem häufig für Python in der realen Welt ist, und es wäre schön, wenn einige Import-Tools diese Funktionalität zum Ändern von PYTHONPATH hinzufügen würden Verzeichnis) ist sehr einfach.

Auf diese Weise können Sie sich darauf verlassen, dass dies mindestens Teil der Standardbibliothek ist und Sie nicht Ihren eigenen Code rollen müssen und sicherstellen müssen, dass er entweder mit Ihren Tests geliefert oder in Ihrer Benutzerbasis installiert wird.