How to suppress console output in Python?
Asked Answered
S

9

58

I'm using Pygame/SDL's joystick module to get input from a gamepad. Every time I call its get_hat() method it prints to the console. This is problematic since I use the console to help me debug and now it gets flooded with SDL_JoystickGetHat value:0: 60 times every second. Is there a way I can disable this? Either through an option in Pygame/SDL or suppress console output while the function calls? I saw no mention of this in the Pygame documentation.

edit: This turns out to be due to debugging being turned on when the SDL library was compiled.

Socratic answered 24/1, 2010 at 2:43 Comment(2)
Now I'm curious what platform you are using (Linux distro?), and what package you are using? Or did you compile it yourself?Credence
This was a long time ago, but I was using Windows, Python 2.6, and Pygame 1.9 (which includes SDL). I had just gone with their Windows installers and everything was already compiled.Socratic
C
5

Here's the relevant block of code from joystick.c (via SVN at http://svn.seul.org/viewcvs/viewvc.cgi/trunk/src/joystick.c?view=markup&revision=2652&root=PyGame)

    value = SDL_JoystickGetHat (joy, _index);
#ifdef DEBUG
    printf("SDL_JoystickGetHat value:%d:\n", value);
#endif
    if (value & SDL_HAT_UP) {

Looks like a problem with having debugging turned on.

Calibre answered 24/1, 2010 at 3:42 Comment(2)
How would I disable SDL debugging though Python? Google tells me the environment variable is SDL_DEBUG but inserting os.environ['SDL_DEBUG'] = '0' appears to have no effect.Socratic
@jackson that's a compile time debug option for SDL. The message is printing because when your SDL library was compiled, the DEBUG symbol was defined.Horne
H
71

Just for completeness, here's a nice solution from Dave Smith's blog:

from contextlib import contextmanager
import sys, os

@contextmanager
def suppress_stdout():
    with open(os.devnull, "w") as devnull:
        old_stdout = sys.stdout
        sys.stdout = devnull
        try:  
            yield
        finally:
            sys.stdout = old_stdout

With this, you can use context management wherever you want to suppress output:

print("Now you see it")
with suppress_stdout():
    print("Now you don't")
Heptastich answered 31/7, 2014 at 14:31 Comment(2)
Replace all out by err to suppress warnings and error messages, compare @telotortium's answer.Lizarraga
For python >3.4, contextlib offers redirect_stdout() with similar functionality.Clockwork
U
45

To complete charles's answer, there are two context managers built in to python, redirect_stdout and redirect_stderr which you can use to redirect and or suppress a commands output to a file or StringIO variable.

import contextlib

with contextlib.redirect_stdout(None):
    do_thing()

For a more complete explanation read the docs

A quick update: In some cases passing None might raise some reference errors (e.g. keras.models.Model.fit calls sys.stdout.write which will be problematic), in that case pass an io.StringIO() or os.devnull.

Undervalue answered 3/9, 2017 at 7:47 Comment(2)
Thanks for the tip. You can also add a print statement as the parameter in the redirect_stdout(). with redirect_stdout(print('Worked!')): do_thing()Rhoades
@myidealab Since the print statement will return None, isn't that the same as just adding one before the with?Blueberry
G
23

You can get around this by assigning the standard out/error (I don't know which one it's going to) to the null device. In Python, the standard out/error files are sys.stdout/sys.stderr, and the null device is os.devnull, so you do

sys.stdout = open(os.devnull, "w")
sys.stderr = open(os.devnull, "w")

This should disable these error messages completely. Unfortunately, this will also disable all console output. To get around this, disable output right before calling the get_hat() the method, and then restore it by doing

sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__

which restores standard out and error to their original value.

Gabrielson answered 24/1, 2010 at 3:16 Comment(6)
I wasn't aware of this technique before. It appears to be what I want, but when I try using it the get_hat() function continues to print to the console. Could this be an issue with SDL?Socratic
Using place holders for the original sys.stdout and sys.stderr to use when restoring the stdout will extend this solution to work in situations where a 'non standard' stdout is already in place and needs to be retained after suppression. eg for use in the QGIS python console.Eponymy
the first bit works, however even with the 'restoring' bit of code I still don't get any console output after it? I'm on Ubuntu 14.04 with 3.4.3Suborder
thanks for your solution, my problem is that output is slowing down my code, will this still lead to the same slowdown?Eger
os.devnull happens to be a string in python 3.6 on linuxNosing
Apparently, it throws error, AttributeError: 'module' object has no attribute '___stdout___' aChouinard
P
6

Building on @charleslparker's answer:

from contextlib import contextmanager
import sys, os

@contextmanager
def suppress_stdout():
    with open(os.devnull, "w") as devnull:
        old_stdout = sys.stdout
        sys.stdout = devnull
        try:  
            yield
        finally:
            sys.stdout = old_stdout

print("Now you see it")
with suppress_stdout():
    print("Now you don't")

Tests

>>> with suppress_stdout():
        os.system('play /mnt/Vancouver/programming/scripts/PHASER.WAV')

/mnt/Vancouver/programming/scripts/PHASER.WAV:

 File Size: 1.84k     Bit Rate: 90.4k
  Encoding: Unsigned PCM  
  Channels: 1 @ 8-bit    
Samplerate: 11025Hz      
Replaygain: off         
  Duration: 00:00:00.16  

In:100%  00:00:00.16 [00:00:00.00] Out:1.79k [!=====|=====!]        Clip:0    
Done.

Use this to completely suppress os.system() output:

>>> with suppress_stdout():
        os.system('play /mnt/Vancouver/programming/scripts/PHASER.WAV >/dev/null 2>&1')
>>> ## successfully executed

>>> import time
>>> with suppress_stdout():
        for i in range(3):
                os.system('play /mnt/Vancouver/programming/scripts/PHASER.WAV >/dev/null 2>&1')
                time.sleep(0.5) 
>>> ## successfully executed

Useful (e.g.) to signal completion of long-running scripts.

Pecksniffian answered 20/2, 2020 at 20:11 Comment(0)
C
5

Here's the relevant block of code from joystick.c (via SVN at http://svn.seul.org/viewcvs/viewvc.cgi/trunk/src/joystick.c?view=markup&revision=2652&root=PyGame)

    value = SDL_JoystickGetHat (joy, _index);
#ifdef DEBUG
    printf("SDL_JoystickGetHat value:%d:\n", value);
#endif
    if (value & SDL_HAT_UP) {

Looks like a problem with having debugging turned on.

Calibre answered 24/1, 2010 at 3:42 Comment(2)
How would I disable SDL debugging though Python? Google tells me the environment variable is SDL_DEBUG but inserting os.environ['SDL_DEBUG'] = '0' appears to have no effect.Socratic
@jackson that's a compile time debug option for SDL. The message is printing because when your SDL library was compiled, the DEBUG symbol was defined.Horne
V
2

I use pythonw.exe (on Windows) instead of python.exe. In other OSes, you could also redirect output to /dev/nul. And in order to still see my debug output, I am using the logging module.

Vehemence answered 21/2, 2011 at 9:0 Comment(0)
A
1

As Demolishun mentions in an answer to a closed duplicate question, there is a thread talking about this issue. The thread is from August of 2009 and one of the developers says the debug code was left in on accident. I had installed Pygame 1.9.1 from pip and the debug output is still present.

To get around it for now, I downloaded the source from pygame.org, removed the print statements from src/joystick.c and compiled the code.

I am on OS X 10.7.5 for what it's worth.

Abominate answered 25/11, 2012 at 4:54 Comment(0)
P
0

If you are on a Debian or Ubuntu machine you can just simply recompile pygame without the messages.

cd /tmp
sudo apt-get build-dep pygame
apt-get source pygame
vim pygame-1.9.1release+dfsg/src/joystick.c
# search for the printf("SDL.. messages and put a // in front
apt-get source --compile pygame
sudo dpkg -i python-pygame_1.9.1release+dfsg-9ubuntu1_amd64.deb

Greetings Max

Principality answered 15/4, 2016 at 13:18 Comment(0)
H
0

The solutions using os.devnull could cause synchronization issues with multi-processing - so multiple processes would wait on the same resource. At least this is what I encountered in windows.

Following solution might be better:


class DummyOutput(object):
    def __init__(self, *args, **kwargs):
        pass

    def write(self, *args, **kwargs):
        pass


class suppress_stdout_stderr(object):
    def __init__(self):
        self.stdout = sys.stdout
        self.stderr = sys.stderr

    def __enter__(self, *args, **kwargs):
        out = DummyOutput()
        sys.stdout = out
        sys.stderr = out

    def __exit__(self, *args, **kwargs):
        sys.stdout = self.stdout
        sys.stderr = self.stderr


with suppress_stdout_stderr():
    print(123, file=sys.stdout)
    print(123, file=sys.stderr)
Heater answered 1/2, 2023 at 15:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.