8
$\begingroup$

I have a button created by my script. I wonder how I can display what the system console displays but inside blender's console. CoDEmanX did this by running a script inside it as shown here, but I want to display what happens in the system console inside blender's console.

My .blend file can be found here:

$\endgroup$
2
  • $\begingroup$ but inside blender - is too vauge, where exactly? $\endgroup$
    – ideasman42
    Apr 23, 2017 at 9:10
  • $\begingroup$ @ideasman42 question updated as suggested. $\endgroup$
    – Tak
    Apr 23, 2017 at 10:24

3 Answers 3

11
$\begingroup$

Hello world example that prints text into the first console found.

import bpy

def console_get():
    for area in bpy.context.screen.areas:
        if area.type == 'CONSOLE':
            for space in area.spaces:
                if space.type == 'CONSOLE':
                    return area, space
    return None, None


def console_write(text):
    area, space = console_get()
    if space is None:
        return

    context = bpy.context.copy()
    context.update(dict(
        space=space,
        area=area,
    ))
    for line in text.split("\n"):
        bpy.ops.console.scrollback_append(context, text=line, type='OUTPUT')

console_write("Hello World")
$\endgroup$
0
2
$\begingroup$

Step 1: Redirect the output to the python console.

You can use the following codes written by @batFINGER (https://blender.stackexchange.com/a/93746/101378):

import bpy
from bpy import context

import builtins as __builtin__

def console_print(*args, **kwargs):
    for a in context.screen.areas:
        if a.type == 'CONSOLE':
            c = {}
            c['area'] = a
            c['space_data'] = a.spaces.active
            c['region'] = a.regions[-1]
            c['window'] = context.window
            c['screen'] = context.screen
            s = " ".join([str(arg) for arg in args])
            for line in s.split("\n"):
                bpy.ops.console.scrollback_append(c, text=line)

def print(*args, **kwargs):
    console_print(*args, **kwargs)       # to Python Console
    __builtin__.print(*args, **kwargs)   # to System Console

The codes above will redirect the outputs in System Console to the Python Console.

Step 2: Add the script to the system path which your Blender can find it.

You can run sys.path in the python console and then it will output a list of system paths which python in Blender can find the imported scripts.

For example, %APPDATA%\Blender Foundation\Blender\2.92\scripts\addons.

enter image description here

Write the script in step 1 to a seperated file, such as pycl.py.

Then use from pycl import print to use the redirected print in your scripts:

enter image description here

$\endgroup$
1
$\begingroup$

If all you want is a block of code that you can paste at the start of a script, to have all print("...") calls within the script show up in Blender's visible Python-console panels, you can use this:

import sys
import bpy
class StdOutOverride:
    def write(self, text):
        sys.__stdout__.write(text) # also send to standard-output (can comment this out)
        if text != '\n': # ignore extra stdout.write('\n') call at end of each print()
            for line in text.replace('\t', '    ').split('\n'):
                for area in bpy.context.screen.areas:
                    if area.type == 'CONSOLE':
                        with bpy.context.temp_override(area=area):
                            bpy.ops.console.scrollback_append(text=line, type='OUTPUT')
sys.stdout = StdOutOverride()

print("Example text which will display within Blender's Python-console panels.")

The above is not 100% robust though (it can error in certain cases, eg. during rendering, and might mess up line-breaks for large text-blobs that require buffering), so this is the longer (but more robust) version: (I put this into a "prelude" script, which I execute prior to executing the target external script)

import sys
import bpy
class StdOutOverride:
    buffer = []
    def write(self, text):
        sys.__stdout__.write(text) # also send to standard-output (can comment this out)
        
        # at end of each call to print(), a basic write('\n') call gets added; when received, print buffer
        if text == '\n':
            self.print_to_console()
        # for actual-content calls, split text into lines, and print all but last (it'll be printed shortly)
        else:
            for line in text.replace('\t', '    ').split('\n'):
                if len(self.buffer) > 0:
                    self.print_to_console()
                self.buffer.append(line)
    def print_to_console(self):
        buffer_str = ''.join(map(str, self.buffer))
        if hasattr(bpy.context, 'screen') and bpy.context.screen:
            for area in bpy.context.screen.areas:
                if area.type == 'CONSOLE':
                    with bpy.context.temp_override(area=area):
                        # need try-catch, since scrollback_append can error in certain cases (eg. when rendering) 
                        try:
                            bpy.ops.console.scrollback_append(text=buffer_str, type='OUTPUT')
                        except Exception as ex:
                            pass
        self.buffer = []
sys.stdout = StdOutOverride()

print("Example text which will display within Blender's Python-console panels.")
$\endgroup$

You must log in to answer this question.

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