Python pytest: Dynamischer import einer Funktion

jb_alvarado

Lt. Junior Grade
Registriert
Sep. 2015
Beiträge
492
Hallo Allerseits,
bei einem Projekt habe ich in etwa diese Struktur:

Code:
Projekt/
    app/
        filters/
            __init__.py
            v_a.py
            v_b.py
            default.py
        __init__.py
        playlist.py
    tests/
        tests_playlist.py
    app.py

Die default.py importiert dabei Funktionen der Dateien aus dem filters Ordner automatisch:
Python:
def custom_filter(filter_type, node):
    """
    read custom filters from filters folder
    """
    filter_dir = os.path.dirname(os.path.abspath(__file__))
    filters = []

    for filter_file in glob(os.path.join(filter_dir, f'{filter_type}_*')):
        filter_ = os.path.splitext(os.path.basename(filter_file))[0]
        filter_function = locate(f'app.filters.{filter_}.filter_link')
        link = filter_function(node)

        if link is not None:
            filters.append(link)

    return filters

Wenn ich das Programm starte funktioniert auch alles wie es soll, nur wenn ich mit pytest das Programm teste, findet er nicht die dynamisch importierte Funktion.

Habe auch schon statt locate getattr(import_module(f'app.filters.{filter_}'), "filter_link") getestet, aber das geht auch nur, wenn ich das Programm normal startet. Die Fehlermeldung dabei wäre:

ModuleNotFoundError: No module named 'app'

Wenn ich die improt Zeile so ändern würde:
filter_function = locate(f'ffplayout_engine.ffplayout.filters.{filter_}.filter_link')
Würde pytest gehen, aber nicht der normale Programmstart.

Habt ihr einen Tipp, wie ich das lösen kann?
 
Zuletzt bearbeitet:
Vielleicht ein __init__.py auf toplevel? Oder den test in app verschieben? ;-)
Ergänzung ()

Achja nur so als Anregung und offtopic: Ich würde statt os.path lieber auf die neumodischere pathlib gehen. Hat meiner Meinung nach die deutlich angenehmere API
Ergänzung ()

Also ich glaube es fehlt einfach ein __init__.py in tests:

1622479636746.png


-> pytest läuft durch
 
Zuletzt bearbeitet:
Danke für deine Mühe! Klar so geht das auch, aber mein Problem ist der dynamische Import mittels locate.

Im Anhang mal ein Beispiel-Projekt.

Ich brauche diese Art des Imports weil der Ordner filters beliebig viele Dateien beinhalten kann, die im realen Projekt importiert werden müssen.

Danke auch für den Hinweis des pathlib Moduls. Schaue ich mir gerne genauer an.
 

Anhänge

  • import_test.zip
    2,8 KB · Aufrufe: 196
Also erstmal finde ich das locate seltsam. Dafür gibt es die importlib:

filter_function = importlib.import_module(f'app.filters.{filter_}').filter_link
Ergänzung ()

Änder aber erstmal nix am import error. Kann ich mir mal später anschauen ;)
 
Zuletzt bearbeitet:
Habe es jetzt herausgefunden... pytest verwendet nicht den aktuellen Pfad in der Systemumgebung. In der Testfunktion muss das hinzugefügt werden: sys.path.append('')
 
Ja an sowas dachte ich schon. Ist meiner Meinung nach etwas unschön die sys path manipulieren zu müssen.
Aber gut, was läuft das läuft ;)
 
  • Gefällt mir
Reaktionen: jb_alvarado
Zurück
Oben