8

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

ideasman42
  • 47,387
  • 10
  • 141
  • 223
Garrett
  • 6,596
  • 6
  • 47
  • 75
  • 1
    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. – gandalf3 Jan 09 '14 at 08:06

4 Answers4

7

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()
ideasman42
  • 47,387
  • 10
  • 141
  • 223
3

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)
3

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
Maccesch
  • 2,149
  • 18
  • 30
  • 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. – Garrett Jan 10 '14 at 04:32
  • I updated my answer to account for realtime output (I hope). – Maccesch Jan 10 '14 at 11:21
  • 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'. – Garrett Jan 11 '14 at 01:22
  • 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. – Garrett Jan 11 '14 at 01:32
  • Hm, in that case try the other answer :( – Maccesch Jan 11 '14 at 16:58
  • 1
    blender 2>&1 | grep --line-buffered -v '^Info'

    Works like a charm. Thank you, @Maccesch!

    – mcgeo52 May 25 '20 at 22:37
2

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__

Matt
  • 11,126
  • 3
  • 32
  • 67
  • 1
    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. – Bakuriu Jan 10 '14 at 12:23
  • 1
    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." – Garrett Feb 09 '14 at 06:47
  • While this will work, it would be better to temporarily override stdout, see: http://blender.stackexchange.com/a/34218/55 – ideasman42 Jul 18 '15 at 20:43
  • This doesn't work for bpy.ops.wm. – Emadpres May 13 '22 at 07:41