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.
-
but inside blender - is too vauge, where exactly? – ideasman42 Apr 23 '17 at 09:10
-
@ideasman42 question updated as suggested. – Tak Apr 23 '17 at 10:24
4 Answers
- First redirect output from Python's
stdoutinto your own buffer,
see: How to redirect output from 'bpy.ops.*'? - Then run
bpy.ops.console.scrollback_appendwith the console space set using an override, see: https://blender.stackexchange.com/a/31398/55
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':
for region in area.regions:
if region.type == 'WINDOW':
return area, space, region
return None, None, None
def console_write(text):
area, space, region = console_get()
if space is None:
return
context_override = bpy.context.copy()
context_override.update({
"space": space,
"area": area,
"region": region,
})
with bpy.context.temp_override(**context_override):
for line in text.split("\n"):
bpy.ops.console.scrollback_append(text=line, type='OUTPUT')
console_write("Hello World")
- 47,387
- 10
- 141
- 223
-
Note that console_write() in the answer only allow string input.
def console_write(text=""):andtext = str(text)will make it better. – rint Dec 02 '23 at 11:17 -
@fmnijk I disagree that this is an obvious improvement, by this logic any function that accepts text could accept non text which is converted into text. By convention non of Blender's API's that accept text will coerce non-text into text, I rather make this an explicit action for the caller. – ideasman42 Dec 03 '23 at 10:15
-
This is not Blender API. This is a workaround to replace Python built-in print to print in python console by using Blender API. I haven't seen any Modern Language has print() or console.log() allow only string. – rint Dec 03 '23 at 13:46
-
If it is string input only. I think it should be something like
_console_write()or__console_write()which is simple and used to built another useful function. – rint Dec 03 '23 at 13:52 -
Is the fact that this is needed pretty strange? Why can't print() just work like every other DCC? – Mike Bourbeau Jan 26 '24 at 03:32
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.
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:
- 131
- 2
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.")
- 143
- 5
Thanks to @ideasman42's answer. I did a little modification so that it works more like the default print function in Python. Feel free to override the default print function. It will not affect other scripts in Text Editor.
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 print(*texts):
text = ' '.join(str(i) for i in texts)
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')
- 113
- 7
-
1take note that the way you override context is deprecated in favor of temp_override – Harry McKenzie Dec 02 '23 at 15:33


