Wie "pip freeze > requirements.txt" OHNE das abschliessende "Drücke ENTER zum Schließen..." ausführen?

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.
Sirius3
User
Beiträge: 18216
Registriert: Sonntag 21. Oktober 2012, 17:20

Gerade mit einem frisch installierten System getestet, und wie erwartet, zeigt sich bei mir dein Verhalten nicht.
Ist das Verhalten ähnlich bei anderen Python-Programmen:

Code: Alles auswählen

python.exe -m profile --help
Was passiert bei:

Code: Alles auswählen

python.exe -I -m pip freeze
Und für den totalen Überblick:

Code: Alles auswählen

python.exe -v -m pip freeze
Benutzeravatar
ThomasL
User
Beiträge: 1377
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

pstein hat geschrieben: Montag 28. April 2025, 07:29 Nein, keine weiteren Tools oder IDEs installiert. Just pure Python. Nichts wissentlich modifiziert. Ich verwendet Windows 10 v22H2.
Alle anderen Python Scripte laufen übrigens normal.

Hier die gewünschten Ausgaben:

C:\Program Files\Python\Scripts>python.exe -m pip freeze
Python-Version : 3.13.3 (tags/v3.13.3:6280bb5, Apr 8 2025, 14:47:33) [MSC v.1943 64 bit (AMD64)]
Python-Pfad : C:\Program Files\Python

packaging==25.0
pillow==11.2.1
pytesseract==0.3.13
setuptools==65.5.0
Drücke ENTER zum Schließen...

- andere Beispiele -
Bei all deinen Ausgaben erscheint um die eigentliche "raw"-Ausgabe des Aufrufs dieser Textblock

Code: Alles auswählen

Python-Version : 3.13.3 (tags/v3.13.3:6280bb5, Apr 8 2025, 14:47:33) [MSC v.1943 64 bit (AMD64)]
Python-Pfad : C:\Program Files\Python

...
Drücke ENTER zum Schließen...
was imho darauf hindeutet das da etwas aufgerufen wird, was du nicht haben willst.
Bei mir ist dem nämlich nicht so und ich habe gerade Python 3.13 in einer jungfräulichen Windows VM installiert.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
snafu
User
Beiträge: 6830
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich würde Python deinstallieren, dann den Befehl pip freeze erneut aufrufen, um zu sehen, ob in dem Moment noch ein anderer Interpreter aktiv wird und anschließend das Python von python.org erneut installieren. Also eigentlich würde ich vorher noch ein paar andere Dinge ausprobieren, aber bei dem Grad der technischen Affinität des TE erscheint mir diese Variante am sinnvollsten.

@pstein:
Vielleicht hast du ja etwas in Zusammenhang mit dem Module nachladen Thread ausprobiert, was dir nun in die Quere kommt? Seit wann besteht dieses Verhalten denn? Also war die Ausgabe schon immer so oder erst seit kurzem?
Benutzeravatar
noisefloor
User
Beiträge: 4149
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

wenn möglich wäre auch meine Tendenz: deinstallieren, sicherstellen, dass alles _wirklich_ deinstalliert ist, und dann neu installieren. Ggf. dann via Microsoft Store. Was für das gegeben Problem keine Rolle spielen sollte, weil die Python-Version aus dem MS Store ebenfalls von der PSF bereit gestellt wird. Man hat "nur" den Vorteil, dass man automatisch Updates bekommt.

Gruß, noisefloor
Benutzeravatar
snafu
User
Beiträge: 6830
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@pstein:

Code: Alles auswählen

with open("requirements.txt", "w") as stream:
    print(*pip_freeze(), sep="\n", file=stream)

Ausgabe:

Python-Version : 3.13.3 (tags/v3.13.3:6280bb5, Apr 8 2025, 14:47:33) [MSC v.1943 64 bit (AMD64)]
Python-Pfad : C:\Program Files\Python

Traceback (most recent call last):
File "D:\tmp\pipfreeze.py", line 2, in <module>
print(*pip_freeze(), sep="\n", file=stream)
^^^^^^^^^^
NameError: name 'pip_freeze' is not defined
Drücke ENTER zum Schließen...
Hier fehlt übrigens der vorherige Import:

Code: Alles auswählen

from pip._internal.commands import freeze as pip_freeze
So solltest du dann das tatsächliche Ergebnis von pip in der requirements.txt stehen haben, ohne dieses "Blabla" drumherum.

Ich gehe nach jetzigem Stand aber davon aus, dass jegliche Ausgabe anderer Python-Programme bei dir betroffen sein wird. Also immer in dem Moment, wo der Interpreter gestartet wurde (Ausgabe von Version und Python-Pfad) und wenn er sich beendet (ENTER-Ausgabe). Damit kann man unter Windows vielleicht noch irgendwie leben und Workarounds finden (notfalls die ersten beiden Zeilen sowie die letzte Zeile skippen), aber unter LInux, wo Python viel tiefer integriert ist, fände ich dieses Verhalten katastrophal...
Zuletzt geändert von snafu am Montag 28. April 2025, 19:25, insgesamt 1-mal geändert.
Benutzeravatar
grubenfox
User
Beiträge: 593
Registriert: Freitag 2. Dezember 2022, 15:49

snafu hat geschrieben: Montag 28. April 2025, 17:29 Ich würde Python deinstallieren, dann den Befehl pip freeze erneut aufrufen, um zu sehen, ob in dem Moment noch ein anderer Interpreter aktiv wird
und vielleicht auch gut, wenn das 'pip freeze' ins Leere läuft, einfach auch mal den Befehl 'python -VV' und/oder den Befehl 'python.exe -VV' ausprobieren. Eigentlich sollte nach der Deinstallation da ja nichts mehr passieren (können), aber wer weiß? Mit dem -VV hat man dann auch gleich mal eine Versionsinfo ... falls da noch was kommt.
Ich erwarte da ja so eine Fehlermeldung:
Der Befehl "python" ist entweder falsch geschrieben oder konnte nicht gefunden werden.
Benutzeravatar
snafu
User
Beiträge: 6830
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Allerdings das -VV auf jeden Fall groß schreiben, sonst könnte man sich etwas erschrecken, weil man bei kleinem -vv eine umfangreiche Debugging-Ausgabe erhält. ;)
pstein
User
Beiträge: 10
Registriert: Montag 26. Juni 2017, 15:42

Ich denke ich habe die Ursache gefunden, aber damit ein anderes Problem:

Ich habe im Unterverzeichnis \Lib\site-packages\ eine Datei usercustomize.py. Dieses spezielle Script wird bekanntermassen
automatisch vor dem Start jedes (anderen) *.py Scriptes ausgeführt.

Bei mir sieht dieses wie folgt aus:

-----------

Code: Alles auswählen

import sys
import os
import atexit

print(f"Python-Version : {sys.version}")
print(f"Python-Pfad    : {os.path.dirname(sys.executable)}\n")


def pause_on_exit():
    if sys.stdin.isatty():
        input("Drücke ENTER zum Schließen...")

atexit.register(pause_on_exit)
----

Ok, damit wäre scheinbar (!) das Problem gelöst woher die zusätzlichen Ausgaben kommen. Aber:

1.) Ich habe bisher angenommen, dass usercustomize.py nur vor *.py Scripten ausgeführt wird.
pip.exe ist aber ein *.exe Binary und kein *.py Script

2.) NUR (!) mein "Pip" command soll seine Ausgaben in eine Datei schreiben und nicht das Wrapper Script drumrum.
Wieso werden dann trotzdem print-Ausgaben von ausserhalb von pip in die Datei geschrieben (die nur für pip geöffnet wurde)?

Hier ist mein backup/restore Script für die installierten Module im original:

Code: Alles auswählen

import os
import sys
import subprocess
import time

# Funktion, um die installierten Python-Pakete in eine Datei zu exportieren
def create_backup():
    # Zeitstempel für den Dateinamen generieren
    timestamp = time.strftime('%Y%m%d-%H%M%S')
    backup_filename = f"python_modules_backup_{timestamp}.txt"
    
    # 'pip freeze' ausführen und Ausgabe in die Datei schreiben
    with open(backup_filename, 'w') as f:
        subprocess.run(['pip', 'freeze'], stdout=f)
    
    print(f"Backup erfolgreich erstellt: {backup_filename}")
    return backup_filename

# Funktion, um ein Backup wiederherzustellen
def restore_backup(backup_filename):
    if not os.path.exists(backup_filename):
        print(f"Fehler: Backup-Datei {backup_filename} existiert nicht.")
        return
    
    # Installiere alle Pakete aus der Backup-Datei
    with open(backup_filename, 'r') as f:
        subprocess.run(['pip', 'install', '-r', backup_filename])
    
    print(f"Restore erfolgreich aus Datei: {backup_filename}")

def main():
    # Kommandozeilenparameter überprüfen
    if len(sys.argv) > 2:
        print("Fehler: Es dürfen maximal zwei Parameter angegeben werden.")
        sys.exit(1)
    
    # Prüfen, ob eine Datei übergeben wurde (Drag & Drop oder Kommandozeilenparameter)
    if len(sys.argv) == 2:
        backup_filename = sys.argv[1]
        restore_backup(backup_filename)
    else:
        # Wenn keine Datei übergeben wurde, nach einer Datei fragen
        backup_filename = input("Gib den Pfad zu einer Backup-Datei ein (oder drücke ENTER für ein neues Backup): ")
        
        if backup_filename.strip() == "":
            # Backup erstellen, wenn keine Datei angegeben wird
            create_backup()
        else:
            # Restore durchführen
            restore_backup(backup_filename)

if __name__ == "__main__":
    main()
Benutzeravatar
sparrow
User
Beiträge: 4501
Registriert: Freitag 17. April 2009, 10:28

1) Die .exe ruft nun mal den Interpreter auf. pip ist ein Python Modul.

2) Dann musst du lernen was das > tut. Nämlich stdout umleiten. Da du in deinem Wrapper dorthin schreibst, landet es in der Umleitung.

Einfachste Lösung: Solch Spielereien lassen.
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@pstein: Die pip.exe startet nur das Python-Modul `pip`, das ist letztlich also ein Python-Programm und damit kommt natürlich auch die usercustomize.py ins Spiel.

Ein Lösungsansatz diese Ausgaben zu behalten und einen Fehler dabei, sieht man dort im Grunde schon: Ausgaben nur machen wenn der entsprechende Kanal mit einem Terminal verbunden ist. Dazu muss man bei einer Ausgabeumlenkung aber nicht `sys.stdin` sondern eben die Ausgabe `sys.stdout` testen ob die mit einem Terminal verbunden ist. Das ist sie nicht wenn die Ausgabe in eine Datei umgeleitet wird. Und man müsste das dann für jede Ausgabe machen, und nicht nur für das ENTER am Ende. Wobei das IMHO ein ziemlich nerviger Hack ist, weil man ja auch in einem Terminal das dauerhaft geöffnet ist, dann bei jedem Python-Programm am Ende noch mal die Eingabetaste drücken muss.

Was auch Sinn machen würde, wäre solche Ausgaben nicht auf `sys.stdout` zu machen, sondern auf `sys.stderr`. Dann würde das weiterhin in das Terminal ausgegeben, auch wenn man die Ausgabe in eine Datei umleitet.

Ich persönlich würde die Datei löschen. So etwas ist vielleicht ganz nett zur Fehlersuche, aber ständig würde ich das nicht haben wollen.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
Benutzeravatar
Kebap
User
Beiträge: 760
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Unter Windows ist das ein regelmäßer Schmerz, dass Python-Terminals sich unmittelbar schließen, wenn das Programm durch ist. Man startet ein Skript bspw. per Doppelklick, da erscheinen spannende Ausgaben, und dann sind die weg, ohne dass man groß Zeit hatte, sie zu prüfen.

Unter Linux scheint das irgendwie selten ein Problem zu sein. Entweder werden die Skripte sowieso schon per Terminal gestartet. Dann bleibt das natürlich bestehen, auch wenn das Skript durchgelaufen ist. Oder vielleicht ist die Fensterverwaltung auch schlau genug, das Terminalfenster nicht sofort zu schließen, bzw. eben erst nach Tastendruck, ich weiß es nicht.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Benutzeravatar
noisefloor
User
Beiträge: 4149
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Linux bzw. der Linux Terminal verhält sich genau so. Ein nicht-interaktiver Terminal schließt sich, wenn das Programm / Skript, das diesen Terminal benötigt hat, fertig ist.

Gruß, noisefloor
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Und bei einem Start durch Mausklick öffnet sich unter Linux kein Terminal, denn unter Linux kann man keinen Unterschied zwischen GUI und Konsolenprogramm an der ausführbaren Datei erkennen wie bei Windows. Da erkennt Windows ja, dass python.exe ein Konsolenprogramm ist, und öffnet deswegen die Konsole in der das dann läuft.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
Benutzeravatar
snafu
User
Beiträge: 6830
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@pstein:
Hiermit erscheinen die zusätzlichen Infos nur bei direkter Anzeige in der Konsole, nicht aber bei Umleitungen in eine Datei bzw. in andere Programme:

Code: Alles auswählen

import atexit
from pathlib import Path
import sys

def print_python_info():
    print(f"Python-Version : {sys.version}")
    print(f"Python-Pfad    : {Path(sys.executable).parent}\n")

def maybe_pause():
    if sys.stdin.isatty() and sys.stdout.isatty():
        input("Drücke ENTER zum Schließen...")

if sys.stdout.isatty():
    print_python_info()
atexit.register(maybe_pause)
Warum du vorher die gaze Zeit behauptet hast, du hättest nichts verändert, bleibt wohl dein Geheimnis. Das hätte uns eine Menge Raterei erspart. Wobei ich mir am Ende schon ziemlich sicher war, dass so eine Customize-Datei bei dir existiert...

Übrigens wird die usercustomize.py auch beim Aufruf der Python-Shell (REPL) ausgeführt. Dann sieht man direkt zweimal seine Python-Version. Daran wird auch deutlich, dass diese Datei eher nicht für zusätzliche Ausgaben gedacht ist, sondern zum Laden bestimmter Module und Einstellungen beim Start. Also falls der Anwender sich zum Beispiel direkt in einer Umgebung mit wissenschaftlichen Standard-Modulen befinden soll. Oder wenn ich innerhalb meines Programms eine Python-Umgebung anbiete, mit der man Python-Skripte als Plugins laufen lassen kann.
Benutzeravatar
snafu
User
Beiträge: 6830
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Falls man die durchaus hilfreiche Betätigung beim Beenden von Python-Programmen zumindest unter Windows behalten möchte, könnte man einen entsprechenden "Schalter" einbauen:

Code: Alles auswählen

import atexit
import sys

PAUSE_ON_EXIT = sys.platform.lower().startswith("win")

PAUSE_PROMPT = "Drücke ENTER zum Schließen..."

def all_ttys(streams):
    try:
        return all(
            stream.isatty() for stream in streams
        )
    except ValueError:
        # Thrown by isatty() on closed streams
        # e.g. when Python REPL exits
        return False

def maybe_pause(prompt=PAUSE_PROMPT):
    if all_ttys([sys.stdin, sys.stdout]):
        input(prompt)

if PAUSE_ON_EXIT:
    atexit.register(maybe_pause)
Das ergibt natürlich wenig Sinn, wenn die Datei lediglich diese Funktion enthält, weil man dann ja auch die Datei weglassen könnte auf Systemen, wo man keine Bestätigung haben möchte. Im Rahmen einer komplexeren Nutzung könnte das aber hilfreich sein.

Die Versionsangabe und den Python-Pfad habe ich aus den bereits genannten Gründen weg gelassen. So etwas kann ein Skript auch selbst als Ein- bzw. Zweizeiler einbauen.
Antworten