Wie kann man die terminal-Ausgabe von ausführbaren Dateien ausführen von Python-Funktionen werden zum schweigen gebracht, in einer Allgemeinen Weise?

Will ich unterdrücken, die von der terminal-Ausgabe produziert, die durch eine Funktion läuft, dass ausführbare Dateien.

Habe ich versucht zu unterdrücken die Ausgabe der Python-Funktion mithilfe eines Kontext-manager, der vorübergehend neu definiert, stdout und stderr jedes mal, wenn die Funktion aufgerufen wird. Dies unterdrückt die Ausgabe im terminal produziert von print Aufrufe in der Funktion, aber es scheint nicht zu funktionieren, wenn die Funktion Aufrufe von ausführbaren Dateien produzieren, die terminal-Ausgabe.

So, wie könnte die Ausgabe von ausführbaren Dateien genannt, die von Python-Funktionen unterdrückt werden?

Mein code ist unten. Ich habe eine Beispiel-Funktion, die Anrufe ls um zu versuchen, um zu veranschaulichen die Art der Ausgabe im terminal, die ich unterdrücken wollen (obwohl die Funktion, die ich bin den Umgang mit anders ist).

#!/usr/bin/env python

import os
import subprocess
import sys

def main():

    print("hello")

    with silence():
        print("there")

    print("world")

    with silence():
        engage_command(command = "ls")

class silence(object):

    def __init__(
        self,
        stdout = None,
        stderr = None
        ):
        if stdout == None and stderr == None:
            devnull = open(os.devnull, "w")
            stdout = devnull
            stderr = devnull
        self._stdout = stdout or sys.stdout
        self._stderr = stderr or sys.stderr

    def __enter__(
        self
        ):
        self.old_stdout = sys.stdout
        self.old_stderr = sys.stderr
        self.old_stdout.flush()
        self.old_stderr.flush()
        sys.stdout = self._stdout
        sys.stderr = self._stderr

    def __exit__(
        self,
        exc_type,
        exc_value,
        traceback
        ):
        self._stdout.flush()
        self._stderr.flush()
        sys.stdout = self.old_stdout
        sys.stderr = self.old_stderr

def engage_command(
    command = None
    ):
    process = subprocess.Popen(
        [command],
        shell      = True,
        executable = "/bin/bash")
    process.wait()
    output, errors = process.communicate()
    return output

if __name__ == "__main__":
    main()

In meinem speziellen Fall, ich versuche, führen Sie die folgende Funktion (statt der ls Funktion oben):

with propyte.silence():
    stream = pyaudio.PyAudio().open(
        format   = pyaudio.PyAudio().get_format_from_width(1),
        channels = 1, 
        rate     = bitrate, 
        output   = True
    )

Beim ausführen, das erzeugt eine Ausgabe wie die folgende:

ALSA lib pcm_dsnoop.c:606:(snd_pcm_dsnoop_open) unable to open slave
ALSA lib pcm_dmix.c:1029:(snd_pcm_dmix_open) unable to open slave
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side
ALSA lib pcm_dmix.c:1029:(snd_pcm_dmix_open) unable to open slave
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for 4294967295, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for 4294967295, skipping unlock

Möchte ich unterdrücken die Ausgabe.


EDIT: testen eine Lösung zur Verfügung gestellt von @Matthias

#!/usr/bin/env python

import contextlib
import os
import subprocess
import sys

def main():

    print("hello")

    with silence():
        print("there")

    print("world")

    with silence():
        engage_command(command = "ls")

@contextlib.contextmanager
def silence():
    devnull = os.open(os.devnull, os.O_WRONLY)
    old_stderr = os.dup(2)
    sys.stderr.flush()
    os.dup2(devnull, 2)
    os.close(devnull)
    try:
        yield
    finally:
        os.dup2(old_stderr, 2)
        os.close(old_stderr)

def engage_command(
    command = None
    ):
    process = subprocess.Popen(
        [command],
        shell      = True,
        executable = "/bin/bash")
    process.wait()
    output, errors = process.communicate()
    return output

if __name__ == "__main__":
    main()

Ich habe nicht erfolgreich gewesen bei der Unterdrückung der terminal-Ausgabe von der print oder die ls und ich bin mir nicht sicher, warum.

InformationsquelleAutor d3pd | 2016-04-30



2 Replies
  1. 1

    Konnten Sie Umschalten von PyAudio der sounddevice – Modul, das bereits übernimmt-silencing die Ausgabe im terminal (siehe #12). Dies ist, wie es gemacht wird es (mit CFFI):

    from cffi import FFI
    import os
    
    ffi = FFI()
    ffi.cdef("""
    /* from stdio.h */
    FILE* fopen(const char* path, const char* mode);
    int fclose(FILE* fp);
    FILE* stderr;  /* GNU C library */
    FILE* __stderrp;  /* Mac OS X */
    """)
    try:
        stdio = ffi.dlopen(None)
        devnull = stdio.fopen(os.devnull.encode(), b'w')
    except OSError:
        return
    try:
        stdio.stderr = devnull
    except KeyError:
        try:
            stdio.__stderrp = devnull
        except KeyError:
            stdio.fclose(devnull)

    Wenn Sie möchten, eine Reine Python-Lösung, können Sie versuchen, diese context-manager:

    import contextlib
    import os
    import sys
    
    @contextlib.contextmanager
    def ignore_stderr():
        devnull = os.open(os.devnull, os.O_WRONLY)
        old_stderr = os.dup(2)
        sys.stderr.flush()
        os.dup2(devnull, 2)
        os.close(devnull)
        try:
            yield
        finally:
            os.dup2(old_stderr, 2)
            os.close(old_stderr)

    Dies ist ein sehr hilfreicher blog-post über das Thema: http://eli.thegreenplace.net/2015/redirecting-all-kinds-of-stdout-in-python/.


    UPDATE:

    Kontext-manager schweigen über die standard-Fehler-Ausgabe (stderr), die verwendet wird, für die lästigen Nachrichten von PortAudio erwähnt in der ursprünglichen Frage. Um loszuwerden, der standard-Ausgabe (stdout), wie in der aktualisierten Frage, haben Sie zu ersetzen sys.stderr mit sys.stdout und der file-Deskriptor 2 mit der Nummer 1:

    @contextlib.contextmanager
    def ignore_stdout():
        devnull = os.open(os.devnull, os.O_WRONLY)
        old_stdout = os.dup(1)
        sys.stdout.flush()
        os.dup2(devnull, 1)
        os.close(devnull)
        try:
            yield
        finally:
            os.dup2(old_stdout, 1)
            os.close(old_stdout)
    • Vielen Dank für deine ausführliche Lösung. Ich werde untersuchen, die sounddevice-Modul wie vorgeschlagen und wird prüfen, Ihre Lösung für silencing-PortAudio. Für die reinen, Allgemeinen Ansatz für die Stilllegung der terminal-vollständig (ob das für Python-output-oder EXE-Dateien gestartet, indem Python), die Sie vorgeschlagen haben, habe ich nicht erfolgreich zu unterdrücken, um die terminal-Ausgabe. Ich habe meinen code in ein edit zu der Frage. Würden Sie eine Idee haben über, wie man das so ändern, dass die terminal-Ausgabe der print und die ls unterdrückt wird?
    • Ah, das ist es. Es handle stdout. Nochmals vielen Dank für deine klare und ausführliche Lösung.
  2. 4

    Für die ALSA-Fehler, insbesondere, können Sie ALSA ‚ s snd_lib_error_set_handler Funktion, wie beschrieben, zum Beispiel in dieser Frage.

    Einem meiner Projekte, habe ich ein Modul namens mute_alsa, die wie folgt aussieht:

    import ctypes
    
    ERROR_HANDLER_FUNC = ctypes.CFUNCTYPE(None, ctypes.c_char_p, ctypes.c_int,
                                          ctypes.c_char_p, ctypes.c_int,
                                          ctypes.c_char_p)
    
    
    def py_error_handler(filename, line, function, err, fmt):
        pass
    
    c_error_handler = ERROR_HANDLER_FUNC(py_error_handler)
    
    try:
        asound = ctypes.cdll.LoadLibrary('libasound.so.2')
        asound.snd_lib_error_set_handler(c_error_handler)
    except OSError:
        pass

    Und verwenden Sie es ganz einfach, indem Sie Folgendes in Ihren code:

    import mute_alsa

    In einem Allgemeinen Sinn, Sie können verhindern, dass alles aus drucken
    stderr einfach durch schließen der zugehörigen Datei-Deskriptor. Für
    Beispiel, wenn wir versuchen, uns rm eine Datei, die nicht existiert, bekommen wir eine Fehlermeldung.
    Nachricht gedruckt auf stderr:

    >>> import sys
    >>> import os
    >>> os.system('rm /doesnotexist')
    rm: cannot remove ‘/doesnotexist’: Is a directory
    256

    Wenn wir in der Nähe der stderr Datei-Deskriptor:

    >>> os.close(sys.stderr.fileno())

    Wir nicht mehr sehen, keine Fehlermeldungen:

    >>> os.system('rm /doesnotexist')

    Der Nachteil dieses Ansatzes ist, dass es Stille alle Nachrichten
    stderr, was bedeutet, dass Sie nicht mehr zu sehen, legitime Fehler
    Nachrichten. Dies kann führen zu unerwarteten Ausfall-Modi (Programm
    verlassen, ohne Druck keine Fehler!).

    • Hey, vielen Dank für deine ausführliche Lösung (und für den präemptiven ALSA-mute-Vorschlag). Wenn ich os.close(sys.stdout.fileno()) und os.close(sys.stderr.fileno()) in die Eingabe-oder init-Funktionen der Kontext-manager vor, die terminal-Ausgabe nicht scheinen, um unterdrückt. Können Sie sehen, was ich bin fehlt?
    • Das ist großartig, vielen Dank!
    • Gibt es einen Weg, den varg args Teil auf der python-handler? Der handler erhält der ‚fmt‘ – string, aber nicht die params an die original-ALSA-Fehler-handler. Ich will nicht stumm, die Fehler, melden Sie sich einfach, Sie einmal für jedes vorkommen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.