Hilfe bei Modul

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.
Antworten
CyGro
User
Beiträge: 3
Registriert: Dienstag 11. Juli 2023, 10:49

HI kan mir jemand helfen bei sisen code ich ferstehe nicht warum er nicht funktioniert und dan würde ich gerne wissen welche code besser ist danke. :?:

# Module importieren
import os
import sys
import re
import subprocess

# Funktion zum Finden aller Python-Dateien in einem angegebenen Pfad definieren
def find_py_files(path):
# Leere Liste zum Speichern der Dateinamen initialisieren
py_files = []
# Durch alle Dateien und Verzeichnisse im Pfad iterieren
for root, dirs, files in os.walk(path):
# Durch alle Dateien iterieren
for file in files:
# Überprüfen, ob die Datei die Endung .py hat
if file.endswith(".py"):
# Den vollständigen Dateipfad zur Liste hinzufügen
py_files.append(os.path.join(root, file))
# Liste der Python-Dateien zurückgeben
return py_files

# Funktion zum Extrahieren aller importierten Module aus einer Python-Datei definieren
def extract_modules(file):
# Leere Menge zum Speichern der Modulnamen initialisieren
modules = set()
# Die Datei öffnen und den Inhalt lesen
with open(file, "r") as f:
content = f.read()
# Mit regulären Ausdrücken alle Import-Anweisungen finden
imports = re.findall(r"(?:from|import)\s+(\w+)", content)
# Durch alle Imports iterieren
for imp in imports:
# Den Modulnamen zur Menge hinzufügen
modules.add(imp)
# Menge der Module zurückgeben
return modules

# Funktion zum Überprüfen, ob ein Modul installiert ist oder nicht definieren
def is_installed(module):
# Versuchen, das Modul zu importieren
try:
__import__(module)
# Wenn keine Ausnahme ausgelöst wird, ist das Modul installiert
return True
except ImportError:
# Wenn eine Ausnahme ausgelöst wird, ist das Modul nicht installiert
return False

# Funktion zum Installieren eines Moduls mit pip definieren
def install_module(module):
# Subprozess verwenden, um den Befehl "pip install" auszuführen
subprocess.run([sys.executable, "-m", "pip", "install", module])

# Alle Laufwerke im System abrufen
drives = [f"{d}:\\" for d in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" if os.path.exists(f"{d}:\\")]

# Durch alle Laufwerke iterieren
for drive in drives:
# Alle Python-Dateien im Laufwerk finden
py_files = find_py_files(drive)
# Durch alle Python-Dateien iterieren
for py_file in py_files:
# Alle importierten Module aus der Datei extrahieren
modules = extract_modules(py_file)
# Durch alle Module iterieren
for module in modules:
# Überprüfen, ob das Modul installiert ist oder nicht
if not is_installed(module):
# Das Modul installieren, falls es nicht installiert ist
install_module(module)

Oder ?

# Import modules
import os
import sys
import re
import subprocess

# Define a function to find all Python files in a given path
def find_py_files(path):
# Initialize an empty list to store the file names
py_files = []
# Loop through all the files and directories in the path
for root, dirs, files in os.walk(path):
# Loop through all the files
for file in files:
# Check if the file has a .py extension
if file.endswith(".py"):
# Append the full file path to the list
py_files.append(os.path.join(root, file))
# Return the list of Python files
return py_files

# Define a function to extract all the modules imported in a Python file
def extract_modules(file):
# Initialize an empty set to store the module names
modules = set()
# Open the file and read its contents
with open(file, "r") as f:
content = f.read()
# Use a regular expression to find all the import statements
imports = re.findall(r"(?:from|import)\s+(\w+)", content)
# Loop through all the imports
for imp in imports:
# Add the module name to the set
modules.add(imp)
# Return the set of modules
return modules

# Define a function to check if a module is installed or not
def is_installed(module):
# Try to import the module
try:
__import__(module)
# If no exception is raised, the module is installed
return True
except ImportError:
# If an exception is raised, the module is not installed
return False

# Define a function to install a module using pip
def install_module(module):
# Use subprocess to run pip install command
subprocess.run([sys.executable, "-m", "pip", "install", module])

# Get all the drives in the system
drives = [f"{d}:\\" for d in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" if os.path.exists(f"{d}:\\")]

# Loop through all the drives
for drive in drives:
# Find all the Python files in the drive
py_files = find_py_files(drive)
# Loop through all the Python files
for py_file in py_files:
# Extract all the modules imported in the file
modules = extract_modules(py_file)
# Loop through all the modules
for module in modules:
# Check if the module is installed or not
if not is_installed(module):
# Install the module if not installed
install_module(module)
Zuletzt geändert von CyGro am Dienstag 11. Juli 2023, 11:10, insgesamt 1-mal geändert.
Benutzeravatar
/me
User
Beiträge: 3556
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Du möchtest den Code im Editor vielleicht auch als Code formatieren? So ist er unleserlich.

Und erkläre bitte genauer was "nicht funktioniert" heißt. Bekommst du eine Fehlermeldung? Tut der Code nicht was du erwartest? Was erwartest du eigentlich? Und was tut der Code stattdessen?
Zuletzt geändert von /me am Dienstag 11. Juli 2023, 14:21, insgesamt 1-mal geändert.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Wenn du den Code verstehen würdest, könntest du erkennen, dass er schlecht geschrieben und teilweise auch fehlerhaft ist.

Alle Python-Dateien auflisten geht bswp. mit der pathlib quasi als Einzeiler. Und reguläre Ausdrücke machen oft nicht das, was beabsichtigt ist. Im unterem Fall würde bei "extract_modules()" fälschlicherweise "path" als importiertes Modul mit gelistet werden.

Anbei ein kleines Beispiel, wie es ohne reguläre Ausdrücke gehen kann:

Code: Alles auswählen

s = """
# Module importieren
import os
import sys
import re
import subprocess
from pathlib import path

def silly():
    from pprint import pprint
    import sys
    pass
    
more code ...
""".split("\n")


def collect_imports(source):
    module_names = set()
    for line in source:
        line = line.strip()
        if line.startswith("import") or line.startswith("from"):
            keyword, module_name, *remainer = line.split()
            module_names.add(module_name)
    return module_names


collect_imports(s)
Du solltest versuchen, die Beispielfunktionen selbst zu lösen. Dann lernst Du am meisten. Die Sache mit dem "subprocess" lässt du am besten bleiben und das komische Zeug mit den Laufwerken funktioniert wenn, dann auch nur unter Windows.
Benutzeravatar
__blackjack__
User
Beiträge: 13121
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@CyGro: Das ist ja im Grunde zweimal der gleiche Code, nur das er einmal Deutsch und einmal Englisch kommentiert ist, und einmal korrekt mit vier Leerzeichen pro Ebene und einmal mit nur zwei Leerzeichen pro Ebene eingerückt ist. Es sei denn ich habe da Inhaltlich was übersehen. IMHO ist da zwischen den beiden Varianten ”Gleichstand”. Besser wäre es in Englisch zu kommentieren *und* vier Leerzeichen pro Ebene zu verwenden.

Es ist eindeutig zu viel kommentiert. Wirklich *jede* Zeile hat eine Kommentarzeile. Das macht man nicht. Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in aller Regel auch was in der Dokumentation von Python und den verwendeten Bibliotheken steht.

Maximal ein Teil von den Kommentaren über den Funktionsdefinitionen könnte als Docstring in die Funktion wandern. *Alle* anderen Kommentare sollten weg.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Das Laufwerksbuchstaben nicht portabel sind, wurde ja schon erwähnt, das sollte man also nur machen wenn man auf einem Windows-System ist, und ansonsten wäre das Äquivalent das Wurzelverzeichnis.

Namen sollten nicht kryptisch abgekürzt werden oder kryptische Abkürzungen enthalten. `f` ist zu kurz. `imp` hat selbst als Wort eine Bedeutung.

Bei Namen wie `module`/`modules`/`file`/`files` sollte man aufpassen ob man da wirklich Module und Dateien oder Modul*namen* und Datei*namen* meint. Denn es gibt ja beides als Werte.

Wenn man Textdateien öffnet, sollte man immer explizit die Kodierung angeben. Das ist hier schwierig bis unmöglich, denn Python-Quelltextdateien sind zwar meistens UTF-8 kodiert, aber das kann der Autor ja ändern. Das heisst man muss hier eigentlich nachprogrammieren wie Python selbst die Kodierung einer Quelltextdatei ermittelt, oder tatsächlich den Compiler für die gefundenen Dateien anwerfen.

Was man sowieso machen müsste um die Importe zu identifizieren, denn die Datei einfach als unstrukturierte Textdatei zu verarbeiten kann auf der einen Seite Importe übersehen, auf der anderen Seite werden falsche Importe erkannt, die beispielsweise nur in Kommentaren oder Docstrings stehen.

Es ist ineffizient die Importe für jeden gefundenen Python-Quelltext einzeln zu verarbeiten. Es wird ja viele Module geben, die die gleichen anderen Module importieren, und die werden dann immer wieder und wieder geprüft. Also erst *alle* Modulnamen suchen und über die Menge alle Doubletten raus filtern, bevor man die weiterverarbeitet.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import os
import re
import string
import subprocess
import sys
from itertools import chain
from pathlib import Path


def find_python_filepaths(base_path):
    return (path for path in base_path.rglob("*.py") if path.is_file())


def extract_imported_module_names(source_file_path):
    #
    # BUG Source file don't have to be encoded as UTF-8.
    #
    # BUG Using string operations is not robust.  A Python source file has a
    #     structure beyound some linear text.  The regular expression picks up
    #     ”imports” in Docstrings, or even regular strings, and comments too.
    #
    return set(
        re.findall(
            r"(?:from|import)\s+(\w+)",
            source_file_path.read_text(encoding="utf-8"),
        )
    )


def check_if_installed(module_name):
    #
    # BUG Actually importing might hang or have undesired side effects.  Even
    #     the Python standard library contains such modules.  So if the rest of
    #     the code works it isn't a hypothetical.
    #
    try:
        __import__(module_name)
        return True
    except ImportError:
        return False


def install_module(module):
    subprocess.run(
        [sys.executable, "-m", "pip", "install", module], check=True
    )


def main():
    root_paths = (
        (
            root_path
            for root_path in (
                Path(f"{drive_letter}:\\")
                for drive_letter in string.ascii_uppercase
            )
            if root_path.exists()
        )
        if os.name == "nt"
        else [Path().absolute().root]
    )

    python_file_paths = chain.from_iterable(
        map(find_python_filepaths, root_paths)
    )
    module_names = set(
        chain.from_iterable(
            map(extract_imported_module_names, python_file_paths)
        )
    )
    for module_name in module_names:
        if not check_if_installed(module_name):
            install_module(module_name)


if __name__ == "__main__":
    main()
Was nicht berücksichtigt wird: Es kann mehr als eine Python-Installation auf dem Rechner vorhanden sein und nicht alle Module/Packages gibt es für alle Python-Implementierungen. Wenn jemand Python 2.7, mindestens ein Python 3, PyPy, und MicroPython installiert hat, wird es beispielsweise zwangsläufig dieses Problem geben.

Packagenamen im Package Index haben öfter mal nicht den gleichen Namen wie das Modul, das man dann im Quelltext importieren muss. Es gibt auch Modulnamen im Package-Index mehrfach, da muss man dann hoffen, dass man das richtige installiert.

Man hat öfter mal optionale Abhängigkeiten oder bedingte Importe, wo man die Pakete entweder gar nicht braucht, oder wo es sogar unmöglich ist alle Importe sinnvoll zu erfüllen.

Die Suche ist nicht vollständig. Importe können nicht nur in Quelltextdateien mit der Endung *.py passieren und diese Dateien müssen nicht alle so ”offen” im Dateisystem existieren. Die Standardbibliothek kann beispielsweise schon aus ZIP-Archiven importieren, und der Importmechanismus ist da auch beliebig erweiterbar.

Selbst in *.py-Dateien gibt es noch mehrere Wege ohne die Schlüsselworte ``import`` oder ``from`` andere Module zu importieren. Einen Weg beschreitet das Programm ja selbst: die `__import__()`-Funktion.

Wenn man fröhlich einfach so alles installiert was man *irgendwo* auf dem Hintergrundspeicher findet, ist es auch nicht ausgeschlossen, dass man irgendwann Sachen nicht installieren kann, weil die Abhängigkeiten zu den anderen Paketen zu unauflösbaren Versionskonflikten führen. Je mehr unterschiedliche Python-Installationen und/oder venvs es gibt, um so grösser ist diese Gefahr.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
CyGro
User
Beiträge: 3
Registriert: Dienstag 11. Juli 2023, 10:49

Ich wollte einen code der alle Dateien mit der Endung .py auf dem gesamten Rechner auf benötigte nodule durchsucht und die fehlenden module installiert.
Benutzeravatar
__blackjack__
User
Beiträge: 13121
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@CyGro: Das geht halt nicht. Diverse Gründe wurden ja genannt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
CyGro
User
Beiträge: 3
Registriert: Dienstag 11. Juli 2023, 10:49

Bei diesen code bekomme ich aber auch Fehler
ich bin recht neu und wollte mir die Ärgernisse der ständig fehlenden module ersparen
dasss das nicht geht muss man mir nicht erzählen da es 3 Tastendrucks benötigt

Code: Alles auswählen

#!/usr/bin/env python3
import os
import re
import string
import subprocess
import sys
from itertools import chain
from pathlib import Path


def find_python_filepaths(base_path):
    return (path for path in base_path.rglob("*.py") if path.is_file())


def extract_imported_module_names(source_file_path):
    try:
        file_content = source_file_path.read_text(encoding="utf-8")
    except UnicodeDecodeError:
        file_content = source_file_path.read_text(encoding="latin-1")

    return set(re.findall(r"^(?:from|import)\s+(\w+)", file_content, flags=re.MULTILINE))


def check_if_installed(module_name):
    return module_name in sys.modules


def install_module(module):
    subprocess.run([sys.executable, "-m", "pip", "install", module], check=True)


def main():
    root_paths = (
        (
            root_path
            for root_path in (
                Path(f"{drive_letter}:\\")
                for drive_letter in string.ascii_uppercase
            )
            if root_path.exists()
        )
        if os.name == "nt"
        else [Path().absolute().root]
    )

    python_file_paths = chain.from_iterable(
        map(find_python_filepaths, root_paths)
    )
    module_names = set(
        chain.from_iterable(
            map(extract_imported_module_names, python_file_paths)
        )
    )
    for module_name in module_names:
        if not check_if_installed(module_name):
            install_module(module_name)


if __name__ == "__main__":
    main()
Fehlermeldungen

Code: Alles auswählen

Traceback (most recent call last):
  File "D:\Desktop\Test.py", line 60, in <module>
    main()
  File "D:\Desktop\Test.py", line 56, in main
    install_module(module_name)
  File "D:\Desktop\Test.py", line 29, in install_module
    subprocess.run([sys.executable, "-m", "pip", "install", module], check=True)
  File "C:\Users\Badboy\AppData\Local\Programs\Python\Python311\Lib\subprocess.py", line 571, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['C:\\Users\\Badboy\\AppData\\Local\\Programs\\Python\\Python311\\pythonw.exe', '-m', 'pip', 'install', 'win32transaction']' returned non-zero exit status 1.
Benutzeravatar
sparrow
User
Beiträge: 4196
Registriert: Freitag 17. April 2009, 10:28

Es geht nicht darum, dass das Script nicht geht - es geht darum, dass den Vorgehen nicht funktionieren kann.
Es kann sein, das ein Projekt ein Modul in einer anderen Version voraussetzt als ein anderes Projekt.
Lies dich mal ein, was das Modul "venv" macht und wie es funktioniert Das ist das übliche vorgehen um die Abhängigkeiten je Paket zu verwalten und eben nicht global zu installieren.
Sirius3
User
Beiträge: 17757
Registriert: Sonntag 21. Oktober 2012, 17:20

Das hat doch __blackjack__ schon geschrieben: man kann aus dem Modulnamen nicht den Paketnamen herausfinden, den man für PIP braucht. win32transaction ist z.B bei pywin32 dabei.
Benutzeravatar
__blackjack__
User
Beiträge: 13121
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@CyGro: Natürlich bekommst Du mit dem Code auch Fehler. Du wirst bei jedem Code Fehler bekommen, weil das *grundsätzlich* nicht funktionieren wird. Aus *mehreren* Gründen sogar. Die bereits genannt wurden.

"latin-1" ist naja, so semi-sicher. Ganz halt auch nicht wenn der Quelltext in etwas kodiert ist, was sich zwar als Latin-1 dekodieren lässt, dann aber verfälschte Modulnamen enthält wenn es nicht wirklich Latin-1 war. Dann lassen die sich nicht unter dem verfälschten Namen finden. Oder es könnte sogar eine Kodierung sein bei der nicht mal ``from`` oder ``import`` gefunden werden, auch wenn die in der Datei stehen. Den ersten BUG im Kommentar hast Du also nur so halb korrigiert. Den zweiten hast Du einfach ignoriert. Dabei würde eine Lösung *davon* auch den ersten *richtig* lösen. Zumindest für diese Funktion. Das Gesamtvorhaben wird dadurch nicht lösbarer.

`check_if_installed()` ist sinnlos. Was denkst Du denn was das macht? Wie kommen denn Module in `sys.modules`?

Das Installieren von `win32transaction` schlägt also fehlt. Woran liegt das denn? Kannst Du das manuell selbst installieren? Falls ja wie machst Du das? Von wo installierst Du das? (Übrigens auch noch so ein Punkt: nicht alles gibt auch im Python Package Index.)

Wenn das tatsächlich lösbar wäre, und das dann auch noch für einen Anfänger mit so wenigen Zeilen Quelltext, glaubst Du nicht das hätte dann irgendwer schon mal einfach gemacht in den letzten *15 Jahren*‽ Denn solange gibt es ``pip`` und den Package Index (damals noch Cheeseshop) bereits.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten