Welches Python-Paket steckt hinter Import ...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Die site-packages Module sind aus Deiner eigenen Installation.
Wie ich sehe, hast Du Python 3.7 installiert, dort ist der Namen des Pfades wohl site-packages.
Bei mir mit Python 3.4 ist es dist-packages.
Vielleicht hat es auch evtl. damit zu tun, das wir beide unterschiedliche Betriebssysteme nutzen!?

Bei dem überwiegenden Teil, sind das ohl Module, die zu dem Paket python3 gehören.
Die mit dem Unterordner dist-packages, sind selbst installierte Pakete, wie z.B. reportlab aus dem Paket python3-reportlab.

Diese < atexit, sys, time > gehören wohl zur Standardbibliothek, konnte aber keine Anhaltspunkte in meiner Paketverwaltung finden.

Naja, zumindets lässt sich das mal recht gut eingrenzen, der Rest ist wohl Handarbeit ...

Mein ganzer Code zu dieser Geschichte, sieht so aus (lässt sich bestimmt noch optimieren, aber es funktioniert):

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# For Python3.x


import os
import sys

def search_import_names(modul, import_names):
    """
    Suche in Python-Dateien nach Import von Modulen.
    Gebe die die Namen der Module aus.
    """

    pool = set()
    with open(modul, 'r') as handler:
        for obj in handler:
            if not obj.startswith(('from ', 'import ')):
                continue
            if obj.startswith('from '):
                modul = obj.split('from ')[1].split(' ')[0]
            elif obj.startswith('import '):
                modul = obj.split('import ')[1].split(' ')[0].strip()
            modul = modul.replace(',', '')
            import_names.add(modul)
    return import_names


def search_py_files():
    """
    Suche in Python-Pfad nach Python-Dateien.
    Überprüfung untergeordnete Ordner in Python-Pfad (Erste Ebene).
    Übergabe der Python-Dateien an Funktion < search_import_names >,
    zum suchen der importierten Module.
    Erstellung aller importierten Modul-Namen in < import_names >
    als Set, sowie ein Dictionary mit eigen erstellten Modulen
    in < modul2privat >.
    Übergabe von < import_names > und < modul2privat > an Funktion
    < build_python_importnames >.
    """

    import_names = set()
    modul2privat = dict()
    for filename in os.listdir(os.getcwd()):
        check = '{}{}{}'.format(os.getcwd(), os.sep, filename)
        if os.path.isfile(check) and filename.endswith('.py'):
            modul = check
            import_names = search_import_names(modul, import_names)
            modul2privat[filename.replace('.py', '')] = True
        elif os.path.isdir(check):
            pathname = filename
            path = '{}{}{}'.format(os.getcwd(), os.sep, pathname)
            for file in os.listdir(path):
                modul = '{}{}{}'.format(path, os.sep, file)
                if os.path.isfile(modul) and modul.endswith('.py'):
                    import_names = search_import_names(modul, import_names)
                    modul2privat[file.replace('.py', '')] = True
    return build_python_importnames(import_names, modul2privat)


def build_python_importnames(import_names, modul2privat):
    """
    Entfernung der eigen erstellten Modulen aus < import_names >.
    Gebe die Namen der importierten Python-Module aus.
    Übergabe von < python_import_names > an Funktion < find_python_pachage_path >,
    zur Findung Python-Pfades der Python-Module.
    """

    python_import_names = set()
    for name in import_names:
        try:
            modul2privat[name]
        except KeyError:
            python_import_names.add(name)
    return find_python_pachage_path(python_import_names)


def find_python_pachage_path(python_import_names):
    """
    Import der Namen aus < python_import_names > mit Ausgabe
    der Python-Pfade < python_paths > und < AttributeError_names >, bei
    denen es kein Resultat gab.
    """

    python_paths = set()
    AttributeError_names = list()
    for name in sorted(python_import_names):
        try:
            python_paths.add(__import__(name).__file__)
        except AttributeError:
            AttributeError_names.append((name, __import__(name)))
    python_paths = sorted(python_paths)
    AttributeError_names = sorted(AttributeError_names)
    print('####### python_paths #######')
    print(python_paths)
    print('####### AttributeError_names #######')
    print(AttributeError_names)
    return python_paths, AttributeError_names


def main():
    search_py_files()

if __name__ == '__main__':
    main()
Benutzeravatar
pixewakb
User
Beiträge: 1408
Registriert: Sonntag 24. April 2011, 19:43

Ich habe noch keine requirements-Dateien geschrieben, aber den Schritt bei mir vorbereitet. Ich installiere unter Windows alles mit pip und kann mir mit pip freeze ausgeben lassen, was installiert ist und welche Version das hat. Damit lassen sich dann requirements-Dateien zügig erstellen. pip freeze liefert bei mir auch die Pakete mit, die als Abhängigkeiten irgendwo anders mitinstalliert wurden, erleichtert aber m. E. die Arbeit sehr!
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hier stelle mein überarbeiteter Code, für die zu installierenden Python-Pakete, um das Python-Programm lauffähig zu machen:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# For Python3.x


import os
import sys

def search_import_names(modul, import_names):
    """
    Suche in Python-Dateien nach Import von Modulen.
    Gebe die die Namen der Module aus.
    """

    pool = set()
    with open(modul, 'r') as handler:
        for obj in handler:
            if not obj.startswith(('from ', 'import ')):
                continue
            if obj.startswith('from '):
                modul = obj.split('from ')[1].split(' ')[0]
            elif obj.startswith('import '):
                modul = obj.split('import ')[1].split(' ')[0].strip()
            modul = modul.replace(',', '')
            import_names.add(modul)
    return import_names


def search_py_files():
    """
    Suche in Python-Pfad nach Python-Dateien.
    Überprüfung untergeordnete Ordner in Python-Pfad (Erste Ebene).
    Übergabe der Python-Dateien an Funktion < search_import_names >,
    zum suchen der importierten Module.
    Erstellung aller importierten Modul-Namen in < import_names >
    als Set, sowie ein Dictionary mit eigen erstellten Modulen
    in < modul2privat >.
    Übergabe von < import_names > und < modul2privat > an Funktion
    < build_python_importnames >.
    """

    import_names = set()
    modul2privat = dict()
    for filename in os.listdir(os.getcwd()):
        check = '{}{}{}'.format(os.getcwd(), os.sep, filename)
        if os.path.isfile(check) and filename.endswith('.py'):
            modul = check
            import_names = search_import_names(modul, import_names)
            modul2privat[filename.replace('.py', '')] = True
        elif os.path.isdir(check):
            pathname = filename
            path = '{}{}{}'.format(os.getcwd(), os.sep, pathname)
            for file in os.listdir(path):
                modul = '{}{}{}'.format(path, os.sep, file)
                if os.path.isfile(modul) and modul.endswith('.py'):
                    import_names = search_import_names(modul, import_names)
                    modul2privat[file.replace('.py', '')] = True
    return build_python_importnames(import_names, modul2privat)


def build_python_importnames(import_names, modul2privat):
    """
    Entfernung der eigen erstellten Modulen aus < import_names >.
    Gebe die Namen der importierten Python-Module aus.
    Übergabe von < python_import_names > an Funktion < find_python_pachage_path >,
    zur Findung Python-Pfades der Python-Module.
    """

    python_import_names = set()
    for name in import_names:
        try:
            modul2privat[name]
        except KeyError:
            python_import_names.add(name)
    return find_python_package_path(python_import_names)


def find_python_package_path(python_import_names):
    """
    Import der Namen aus < python_import_names >.
    Übergabe der Python-Pfade < python_paths > an Fuktion < build_python_package >,
    zur Erstellung der Python-Pakete.
    """

    python_paths = set()
    AttributeError_names = list()
    for name in sorted(python_import_names):
        try:
            python_paths.add(__import__(name).__file__)
        except AttributeError:
            AttributeError_names.append((name, __import__(name)))
    python_paths = sorted(python_paths)
    AttributeError_names = sorted(AttributeError_names)
    # print('####### python_paths #######')
    # print(python_paths)
    # print('####### AttributeError_names #######')
    # print(AttributeError_names)
    return build_python_package(python_paths)


def build_python_package(python_paths):
    """
    Erstellung der Python-Pakete aus < python_paths > in Liste.
    """

    python_packets = set()
    python_version = set()
    for path in python_paths:
        extra_packet = False
        for folder in path.split(os.sep):
            try:
                python
            except UnboundLocalError:
                if 'python' in folder:
                    python = folder
            if 'packages' in folder:
                extra_packet = True
                continue
            if extra_packet:
                extra_packet = folder.split('.')[0]
                break
        python_packet = python
        if extra_packet:
            python_packet = '{}-{}'.format(python_packet, extra_packet)
        python_packets.add(python_packet)
        python_version.add(python)
    print('Python-Version: ', ''.join(python_version))
    python_packets.add(('{}-minmal').format(''.join(python_version)))
    python_packets = sorted(python_packets)
    print('Zu installierende Python-Paket:')
    for packet in python_packets:
        print('\t{}'.format(packet))
    return python_packets



def main():
    search_py_files()

if __name__ == '__main__':
    main()
Bei meinem Python-Programm, erhalte ich folgende Ausgabe:

Code: Alles auswählen

Python-Version:  python3.4
Zu installierende Python-Paket:
        python3.4
        python3.4-cups
        python3.4-lxml
        python3.4-minmal
        python3.4-reportlab
        python3.4-requests
        python3.4-urllib3
        python3.4-xlrd
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@Nobuddy: Du hast also meinen shell-Einzeiler in 70 Zeilen Pythoncode umgewandelt. ›search_import_names‹ bekommt ein ›import_names‹, ändert es und gibt es wieder zurück. Das sollte nicht sein. Die Funktion sollte überhaupt nicht eine Datenstruktur bekommen, die gefüllt wird, sondern nur etwas zurückgeben.
›pool‹ wird nicht benutzt. Wenn man über ein Dateiobjekt (das ist kein ›handler‹) iteriert bekommt man Zeilen, keine Objekte; Variablennamen sind wichtig zum Verständnis. Die Funktion übersieht alle Importe, die aus welchen Gründen auch immer, eingerückt sind.
Statt `continue` solltest Du ein `else` benutzen, und das `elif` prüft den letzten möglichen Fall, ist also immer wahr.
`split` tut nicht das, was Du denkst. Sobald Du mehrere Leerzeichen (oder Tabs) benutzt, geht das schief. Das `replace` mußt Du mir erklären, denn da werden mehrere durch Komma getrennte Module zu einem zusammengepackt.

Weil schon mehrfach im Thread angesprochen, das ganze umgesetzt mit dem ast-Modul:

Code: Alles auswählen

def search_import_names(module):
    import_names = set()
    with open(module) as content:
        tree = ast.parse(content.read())
    for node in ast.walk(tree):
        if isinstance(node, ast.Import):
            for alias in node.names:
                import_names.add(alias.name)
        elif isinstance(node, ast.ImportFrom):
            import_names.add(node.module)
    return import_names
›search_py_files‹ tut zu viel. Es durchsucht nicht nur die Dateien, sondern ruft auch noch ›build_python_importnames‹ auf, das dann ›find_python_package_path‹ aufruft, was dann die eigentliche Hauptaufgabe des Programms macht. So tiefe Verschachtelungen sind schwer zu durchschauen. Rufe die Einzelnen Teile aus dem Hauptprogramm auf und schreibe Funktionen mit nur einer einfachen Aufgabe. Dann wird auch der Doc-String nicht so lang.

›search_by_files‹ soll also nur Dateiendurchsuchen, also ›search_in_files‹. ›modul2privat‹ ist eigentlich ein Set, weil das module2bool immer nur auf True mappt. Deine Suche geht exakt zwei Verzeichnisebenen tief, und das noch durch kopierten Code. Eigentlich will man beliebig tief suchen. Dafür gibt es walk von pathlib. Verzeichnisse setzt man auch nicht mit .format zusammen, dafür gibt es auch was aus pathlib.
Damit wird die Funktion zu:

Code: Alles auswählen

def search_in_files():
    import_names = set()
    for filename in pathlib.Path('.').walk('**/*.py'):
        import_names.update(search_import_names(filename))
    return import_names
›build_python_importnames‹ ist ein einfaches Filter, wobei man zum Prüfen, ob etwas in einem Wörterbuch ist, `in´ benutzt, und nicht einen KeyError.

Das mit dem `import` war nur als schnelle händlische Lösung gemeint, weil es bei 5 Modulen eigentlich nicht lohnt, ein ganzes Programm dafür zu schreiben. Will man tatsächlich nach den Dateien für ein Modul suchen, importiert man sie nicht, sondern benutzt importlib.

Code: Alles auswählen

def find_python_package_path(modules):
    python_paths = set()
    for module in modules:
        loader = importlib.find_loader(module)
        try:
            python_paths.add(loader.path)
        except AttributeError:
            # Module has no path, probably a builtin module
            # ignore it
            pass
    return sorted(python_paths)
In ›build_python_package‹ verstehe ich nicht, was da alles magisches passiert. Ein UnboundLocalError ist wirklich ein Fehler, und sollte in einer normalen Funktion nicht abgefangen werden. Für solche Fälle hat man den Wert `None`. `extra_packet` ist mal ein Wahrheitswert mal ein String. Eine Variable sollte nur einen Typ haben.

Zum Schluß, ich hatte angedeutet, dass Du Debian direkt nach dem Packetnamen fragen kannst, Du mußt also nicht raten, in welchem Paket das jeweilige Modul drin ist:

Code: Alles auswählen

dpkg -S /usr/lib/python3/dist-packages/reportlab/__init__.py
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo Sirius3,

Danke für Deinen Input, werde Deinen Code durcharbeiten, um zu verstehen!

Wie schon zu vor angedeutet, ist mein Code noch besser umsetzbar, wie Du selbst gezeigt hast.
Wie Du vielleicht auch erkennen kannst, ist mein Code sehr einfach gestrickt, weil ...... mir unter anderem auch die Englischkenntnisse fehlen.
Ich bin daher immer dankbar, für Input wie Deinen .....
Copy & Paste ist einfach, aber ohne Verständnis für den Code, kommt man nicht wirklich weiter.
Werde deshalb in Ruhe das Ganze durcharbeiten.

Grüße Nobuddy
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Fehlermeldung bei 'search_in_files':

Code: Alles auswählen

Traceback (most recent call last):
  File "start_python_packetcontrol_new.py", line 46, in <module>
    search_in_files()
  File "start_python_packetcontrol_new.py", line 26, in search_in_files
    for filename in pathlib.Path('.').walk('**/*.py'):
AttributeError: 'PosixPath' object has no attribute 'walk'
Wie lässt sich das beheben?
Finde 'walk' nur in Verbindung mit 'os', aber mit 'os.walk' komme ich auch nicht weiter.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Heißt ja auch `glob` statt `walk`.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo Sirius3,

habe Deinen Code-Vorschlag verwendet, musste aber noch ein paar kleine Änderungen vornehmen:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# For Python3.x

import os
import ast
import subprocess
import pathlib
import importlib


def search_import_names(module):
    import_names = set()
    with open(module) as content:
        tree = ast.parse(content.read())
    for node in ast.walk(tree):
        if isinstance(node, ast.Import):
            for alias in node.names:
                import_names.add(alias.name)
        elif isinstance(node, ast.ImportFrom):
            import_names.add(node.module)
    return import_names


def search_in_files():
    import_names = set()
    for filename in pathlib.Path('.').glob('**/*.py'):
        import_names.update(search_import_names(
            '{}{}{}'.format(os.getcwd(), os.sep, filename)))
    return find_python_paths(import_names)


def find_python_paths(modules):
    python_paths = set()
    for module in sorted(modules):
        try:
            loader = importlib.find_loader(module.split('.')[0])
            python_paths.add(loader.path)
        except (AttributeError, ImportError, KeyError):
            # Module has no path, probably a builtin module
            # ignore it
            pass
    return package_to_python_paths(sorted(python_paths))


def package_to_python_paths(python_paths):
    python_package = set()
    for path in python_paths:
        cmd = 'dpkg -S {}'.format(path)
        proc = subprocess.Popen(cmd, shell='true', stdout=subprocess.PIPE)
        bytes = proc.stdout.read()
        result = ''.join(map(chr, bytes))
        package = result.split(':')[0]
        if package != '':
            python_package.add(package)
    print(sorted(python_package))
    return sorted(python_package)


def main():
    search_in_files()

if __name__ == '__main__':
    main()
Funktioniert prima und erhalte alle erforderlichen Python-Pakete aufgelistet, die in meiner Firmware Einsatz finden.

Grüße Nobuddy
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Nobuddy:
Bytes haben eine decode()-Methode. Dann kann man sich das hier sparen:

Code: Alles auswählen

''.join(map(chr, bytes))
Außerdem sollte man Popen() mit einer Liste verwenden anstatt eine eigene Shell zu starten, weil letzteres potenziell unsicher ist. Und wie kamst du auf shell="true"? Dir ist bekannt, dass es True als Objekt in Python gibt?

Insgesamt ist der Programmfluss nach meinem Geschmack zu verschachtelt. Normalerweise hat man ein paar Lowlevel-Funktionen und dann eine höhere Schicht, die diese Funktionen sinnvoll aufruft und jeweils die Zwischenergebnisse übergibt. Sonst geht die Entkopplung und Wiederverwendbarkeit als ein wichtiges Merkmal von Funktionen verloren, wenn man am Ende doch wieder ein riesiges Knäuel von Abhängigkeiten hat.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@Nobuddy: wenn das Python3 ist, sollte die erste Zeile `python3` heißen, die zweite Zeile ist überflüssig, weil es utf8 defaultencoding ist und die dritte Zeile auch, weil das ja schon in der ersten Zeile steht.

Zeile 29: das man das nicht so macht, habe ich schon geschrieben. os.pah.join wäre eine richtige Möglichkeit, Da Du nur das aktuelle Verzeichnis anfügen willst, os.path.abspath noch besser, `filename.absolute()` noch viel besser, weil es sich ja um Path-Objekte handelt, ganz weglassen am allerbesten, weil sowieso alle Dateien relativ zum aktuellen Pfad referenziert wird.

Zeile 30/43: dass man Aufrufe nicht so tief verschachteln sollte, hab ich schon erwähnt.
Zeile 37: das Aufsplitten macht man am besten schon in `search_in_files`.
Zeile 39: wie soll da ein KeyError auftreten? Einfach irgendwelche Exceptions auf gut Glück abfangen macht man nicht. Es hat ja einen ganz expliziten Grund, warum hier AttributeError ignoriert wird, der auch kommentiert ist.
Zeile 50: shell=True benutzt man nicht, sondern übergibt das Commando als Liste, dann braucht man auch keine Argumente zusammenformatieren. Besser als Popen zu benutzen, wo auch noch ein wait fehlt ist es gleich check_output zu benutzen.
Zeile 56: statt der Ausgabe hier, solltest Du den Rückgabewert benutzen.

Code: Alles auswählen

#!/usr/bin/env python3
import os
import ast
import subprocess
import pathlib
import importlib


def search_import_names(module):
    import_names = set()
    with open(module) as content:
        tree = ast.parse(content.read())
    for node in ast.walk(tree):
        if isinstance(node, ast.Import):
            for alias in node.names:
                import_names.add(alias.name)
        elif isinstance(node, ast.ImportFrom):
            if node.level == 0:
                # ignore relative imports
                import_names.add(node.module)
    return import_names


def search_in_files():
    import_names = set()
    for filename in pathlib.Path('.').glob('**/*.py'):
        for module in search_import_names(filename):
            import_names.add(module.split('.')[0])
    return import_names


def find_python_path(module):
    try:
        print(module)
        loader = importlib.find_loader(module)
        return loader.path
    except (ImportError, AttributeError):
        # Module has no path, probably a builtin module
        print("No loader for", module)
        return None


def package_to_python_path(path):
    cmd = ['dpkg', '-S', path]
    try:
        result = subprocess.check_output(cmd)
        package = result.decode().split(':')[0]
        return package
    except subprocess.CalledProcessError:
        print("no packages for", path)


def main():
    modules = search_in_files()
    packages = []
    for module in modules:
        path = find_python_path(module)
        if path is not None:
            package = package_to_python_path(path)
            packages.append(package)
    packages.sort()
    print("Packages needed:")
    for package in packages:
        print(package)


if __name__ == '__main__':
    main()
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo snafu,

meinst Du etwa so:

Code: Alles auswählen

def package_to_python_paths(python_paths):
    """
    Erstellung der Python-Paketen aus den Python-Paden.
    """

    python_package = set()
    for path in python_paths:
        cmd = 'dpkg -S {} 2>nul'.format(path)
        proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
        result = proc.stdout.read().decode()
        package = result.split(':')[0]
        if package != '':
            python_package.add(package)
    return build_install_file(sorted(python_package))
Zu verschachtelt, wäre das die Lösung?:

Code: Alles auswählen

def main():
    python_paths = find_python_paths(search_in_files())
    python_package = package_to_python_paths(python_paths)
    build_install_file(python_package)

if __name__ == '__main__':
    main()
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo Sirius3,

das mit dem Verschachteln, habe ich jetzt anhand Deines Codes verstanden.

Das mit filename.absolute() und den anderen Vorschlägen dazu, bekomme ich Fehlermeldungen.
Bei filename.absolute():

Code: Alles auswählen

TypeError: invalid file: PosixPath('/media/daten/officeplanet/firmware/build_sock_control.py')
Mein Pfad, sieht hingegen so aus:

Code: Alles auswählen

/media/daten/officeplanet/firmware/build_sock_control.py
Ich werde mich mal weiter durcharbeiten und poste ggf. Fehlermeldungen dazu.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Ach, Du benutzt ja noch eine uralt-Pythonversion. Da braucht man noch eine explizite Konvertierung:

Code: Alles auswählen

search_import_names(str(filename))
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Sirius3 hat geschrieben: Mittwoch 22. August 2018, 15:59 Ach, Du benutzt ja noch eine uralt-Pythonversion. Da braucht man noch eine explizite Konvertierung:

Code: Alles auswählen

search_import_names(str(filename))
Ist Pythonversion 3.4 schon so alt, welche Version benutzt Du?

Poste nochmal Deinen Code, mit ein paar kleinen Abänderungen:

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import ast
import subprocess
import pathlib
import importlib


def search_import_names(module):
    """
    Suche aus Python-Dateien importierte Python-Module.
    """

    import_names = set()
    with open(module) as content:
        tree = ast.parse(content.read())
    for node in ast.walk(tree):
        if isinstance(node, ast.Import):
            for alias in node.names:
                import_names.add(alias.name)
        elif isinstance(node, ast.ImportFrom):
            if node.level == 0:
                # ignore relative imports
                import_names.add(node.module)
    return import_names


def search_in_files():
    """
    Suche Python-Dateien innerhalb des Firmware-Ordners.
    """
    import_names = set()
    for filename in pathlib.Path('.').glob('**/*.py'):
        for module in search_import_names(str(filename)):
            import_names.add(module.split('.')[0])
    return import_names


def find_python_path(module):
    """
    Suche Python-Pfad aus den in der Firmware installiertem Modul.
    """

    try:
        loader = importlib.find_loader(module)
        return loader.path
    except (ImportError, AttributeError):
        # Module has no path, probably a builtin module
        print("No loader for", module)
        return


def package_to_python_path(path):
    """
    Erstellung Python-Paket aus den Python-Pfad.
    """

    cmd = ['dpkg', '-S', path]
    try:
        result = subprocess.check_output(cmd)
        package = result.decode().split(':')[0]
        return package
    except subprocess.CalledProcessError:
        print("no packages for", path)
        return


def main():
    modules = search_in_files()
    packages = set()
    for module in modules:
        path = find_python_path(module)
        if path is not None:
            package = package_to_python_path(path)
            if package:
                packages.add(package)
    print("Packages needed:")
    f = open('package_install_list.txt', 'w')
    for package in sorted(packages):
        print(package)
        f.write('{}\n'.format(package))
    f.close()
    return


if __name__ == '__main__':
    main()
Funktioniert prima!

Danke und Grüße Nobuddy
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Python 3.7 ist aktuell und 3.4 inzwischen 4 Jahre alt.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Nobuddy hat geschrieben: Mittwoch 22. August 2018, 14:05 Zu verschachtelt, wäre das die Lösung?
Ich kann dir nicht DIE Lösung geben, einfach nur Erfahrungen weitergeben, da Programme schnell mal groß und unübersichtlich werden können. Manchmal kümmert man sich erst nach einem halben Jahr wieder um ein Modul. Und dann ist es gut, wenn man den Code wieder schnell versteht. Es ist ein Unterschied, ob man dann diese drölfzigfache Verschachtelung hat oder - wie von dir gezeigt - den Zusammenbau in einer main()-Funktion sehen kann.

Für die Maschine ist es am Ende egal, aber wir Menschen sollten uns das Leben nicht noch komplizierter machen... ;)
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo snafu,

auch wenn etwas verspätet, möchte ich mich dazu nochmals melden.

Das was Du beschreibst, habe ich eingesehen und werde zukünftig mich bemühen, meinen Code lesbarer zu machen.

Danke und Grüße
Nobuddy
Antworten