8
$\begingroup$

Every time the bpy.ops.remove_doubles() operator is used, it outputs to my terminal (where I called Blender from). How can I suppress this output?

The code is:

bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='TOGGLE')
bpy.ops.mesh.remove_doubles()

and the undesired output is:

Info: Removed 48 vertices

$\endgroup$
1
  • 1
    $\begingroup$ I don't know how to suppress it or if it's even possible, but I believe that message is generated by the report method (stuff will appear in stdout every time something is displayed in the info panel) See this related post. $\endgroup$
    – gandalf3
    Commented Jan 9, 2014 at 8:06

4 Answers 4

7
$\begingroup$

Python can temporarily redirect the stdout, this is ideal since you may not want to suppress output for _all_ scripts, just selectively silence some operations.

eg:

import bpy

import io
from contextlib import redirect_stdout

stdout = io.StringIO()
with redirect_stdout(stdout):
    bpy.ops.mesh.remove_doubles()

If you want you can read the output back out or use it however you like.

stdout.seek(0)
output = stdout.read()
print("Report was %r" % output)

If you want to redirect both stdout and stderr.

import bpy

import io
from contextlib import redirect_stdout, redirect_stderr

output = io.StringIO()
with redirect_stdout(output), redirect_stderr(output):
    bpy.ops.some.operator_that_may_print_text()
$\endgroup$
2
  • 1
    $\begingroup$ This doesn't work for bpy.ops.wm Could you help me out with this? $\endgroup$
    – Školstvo
    Commented Apr 13, 2017 at 18:41
  • $\begingroup$ This does not work with bpy.os.render. See Marc Morcos' answer for that. $\endgroup$ Commented Jun 14, 2023 at 9:11
3
$\begingroup$

To filter the shell output of Blender you can start it via command line using a pipe with sed (Linux / OSX) or findstr (Windows). We can use sed or findstr to omit every line that starts with Info.

Linux / OSX:

blender 2>&1 | grep --line-buffered -v '^Info'

Windows:

blender.exe 2>&1 | findstr /v /b "Info"

findstr on Windows doesn't seem to have a similar option like --line-buffered. You could install grep for Windows though.

If you want to mute Blender all together preventing it from printing anything you can do this too.

Linux / OSX:

blender > /dev/null 2>&1

Windows:

blender 2>&1 > NUL
$\endgroup$
6
  • $\begingroup$ Cool! I wouldn't have thought of that. I guess the only disadvantage is the output (which I do care about) is not displayed until I quit Blender. $\endgroup$
    – Garrett
    Commented Jan 10, 2014 at 4:32
  • $\begingroup$ I updated my answer to account for realtime output (I hope). $\endgroup$
    – Maccesch
    Commented Jan 10, 2014 at 11:21
  • $\begingroup$ I tried the command above (blender 2>&1 | grep --line-buffered -v '^Info'), but again, it displayed no output at all until I closed Blender, at which point, it correctly suppressed all the lines starting with 'Info'. $\endgroup$
    – Garrett
    Commented Jan 11, 2014 at 1:22
  • $\begingroup$ You can verify this behavior by opening a new Blender file, then go to Text Editor, then entering: print("Info - don't display"); print("Hello - display this"), then running the script. $\endgroup$
    – Garrett
    Commented Jan 11, 2014 at 1:32
  • 1
    $\begingroup$ blender 2>&1 | grep --line-buffered -v '^Info' Works like a charm. Thank you, @Maccesch! $\endgroup$
    – mcgeo52
    Commented May 25, 2020 at 22:37
3
$\begingroup$

This worked for me (at least for bpy.ops.render) . https://stackoverflow.com/questions/5081657/how-do-i-prevent-a-c-shared-library-to-print-on-stdout-in-python It makes a context manager you can use to block the output of specific lines.

import os
import sys
from contextlib import contextmanager

@contextmanager
def stdout_redirected(to=os.devnull):
    '''
    import os

    with stdout_redirected(to=filename):
        print("from Python")
        os.system("echo non-Python applications are also supported")
    '''
    fd = sys.stdout.fileno()

    ##### assert that Python and C stdio write using the same file descriptor
    ####assert libc.fileno(ctypes.c_void_p.in_dll(libc, "stdout")) == fd == 1

    def _redirect_stdout(to):
        sys.stdout.close() # + implicit flush()
        os.dup2(to.fileno(), fd) # fd writes to 'to' file
        sys.stdout = os.fdopen(fd, 'w') # Python writes to fd

    with os.fdopen(os.dup(fd), 'w') as old_stdout:
        with open(to, 'w') as file:
            _redirect_stdout(to=file)
        try:
            yield # allow code to be run with the redirected stdout
        finally:
            _redirect_stdout(to=old_stdout) # restore stdout.
                                            # buffering and flags such as
                                            # CLOEXEC may be different

Then just use as follows:

with stdout_redirected():
     bpy.ops.render.render(write_still=True)
$\endgroup$
1
  • $\begingroup$ This should be the accepted answer! $\endgroup$ Commented Jun 14, 2023 at 9:10
2
$\begingroup$

This looks to be exactly what you need. This process would work well for redirecting stdout and/or stderr to /dev/null when you're about to display something that you don't want to see.

Essentially, point the current references to /dev/null, which will make output go away:

devnull = open(os.devnull, 'w')

sys.stdout, sys.stderr = devnull, devnull

...then point them back to stdout and stderr when you're done, which will restore normal output:

sys.stdout = self.__stdout__

sys.stderr = self.__stderr__

$\endgroup$
4
  • 1
    $\begingroup$ Note: sys already contains the original values for stdout and stderr. You do not have to save them. To restore: sys.stdout = sys.__stdout__. The same is true in many other cases. Also /dev/null is not valid python syntax. $\endgroup$
    – Bakuriu
    Commented Jan 10, 2014 at 12:23
  • 1
    $\begingroup$ I see, but in the Python docs udner sys.__stdout__, it says "the preferred way to do this is to explicitly save the previous stream before replacing it, and restore the saved object." $\endgroup$
    – Garrett
    Commented Feb 9, 2014 at 6:47
  • $\begingroup$ While this will work, it would be better to temporarily override stdout, see: blender.stackexchange.com/a/34218/55 $\endgroup$
    – ideasman42
    Commented Jul 18, 2015 at 20:43
  • $\begingroup$ This doesn't work for bpy.ops.wm. $\endgroup$
    – Emadpres
    Commented May 13, 2022 at 7:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .