53

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.

  • Now I'm curious what platform you are using (Linux distro?), and what package you are using? Or did you compile it yourself? – Keith Mar 12 '11 at 01:42
  • 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. –  Mar 12 '11 at 18:38

9 Answers9

69

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")
charleslparker
  • 1,904
  • 1
  • 21
  • 31
  • 2
    Replace all `out` by `err` to suppress warnings and error messages, compare @telotortium's answer. – bers Nov 15 '19 at 13:30
  • 1
    For python >3.4, contextlib offers [`redirect_stdout()`](https://docs.python.org/3/library/contextlib.html#contextlib.redirect_stdout) with similar functionality. – normanius Oct 22 '22 at 16:11
43

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.

Mohammad Jafar Mashhadi
  • 4,102
  • 3
  • 29
  • 49
  • 1
    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()` – datalifenyc Sep 27 '17 at 16:42
  • 1
    @myidealab Since the print statement will return None, isn't that the same as just adding one before the with? – Will Aug 08 '18 at 23:52
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.

telotortium
  • 3,383
  • 2
  • 23
  • 25
  • 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? –  Jan 24 '10 at 03:48
  • 1
    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. – Mr Purple Jul 21 '14 at 06:02
  • 2
    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.3 – m4p85r Mar 22 '16 at 02:53
  • thanks for your solution, my problem is that output is slowing down my code, will this still lead to the same slowdown? – jerpint Mar 01 '17 at 22:16
  • `os.devnull` happens to be a string in python 3.6 on linux – Mr Tsjolder from codidact Mar 27 '18 at 08:11
  • Apparently, it throws error, `AttributeError: 'module' object has no attribute '___stdout___' a` – hola Dec 30 '18 at 14:07
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.

Victoria Stuart
  • 4,610
  • 2
  • 44
  • 37
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.

fencepost
  • 1,758
  • 1
  • 12
  • 9
  • 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. –  Jan 24 '10 at 04:08
  • 4
    @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. – Geoff Reedy Jan 24 '10 at 04:16
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.

Henning
  • 31
  • 1
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.

Community
  • 1
  • 1
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

Max
  • 340
  • 2
  • 15
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)
Arthur
  • 11
  • 2