-
-
Save EugeneDudavkin/f4f0b05d31759384375f6942dd48ecc8 to your computer and use it in GitHub Desktop.
Route system output (stdout/stderr) of Blender to the app console (put in scripts/startup) (to work in 3.6+ as addon)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Add-on info | |
bl_info = { | |
"name": "Enhancing the console", | |
"author": "Tamask", | |
"version": (0, 0, 1), | |
"blender": (2, 83, 0), | |
"location": "Python Console", | |
"description": "Print logs in python console.", | |
"doc_url": "https://gist.github.com/tamask/0593436d044bfedb21081e3d2d802833#file-log-py", | |
"tracker_url": "", | |
"category": "Python Console" | |
} | |
import os | |
import sys | |
import bpy | |
output = None | |
input = None | |
info = None | |
error = None | |
write = None | |
def reset(): | |
global output | |
global input | |
global info | |
global error | |
global write | |
output = Stream('OUTPUT') | |
input = Stream('INPUT') | |
info = Stream('INFO') | |
error = Stream('ERROR') | |
write = output.write | |
class Stream: | |
def __init__(self, enum, context=None): | |
self.text = '' | |
self.enum = enum | |
self.line = None | |
self.newline = False | |
self.context = context | |
if not self.context: | |
self.context = get_console_context() | |
def write(self, text): | |
try: | |
if not self.context: | |
self.context = get_console_context() | |
if self.context: | |
self.console = getattr( | |
self.context, 'space_data', | |
self.context['space_data']) | |
self.scrollback = self.console.scrollback | |
else: | |
if self.enum == 'ERROR': | |
return sys.__stderr__.write(text) | |
else: | |
return sys.__stdout__.write(text) | |
line = self.line | |
sb = self.scrollback | |
if len(sb) == 0: | |
return | |
text = str(text) | |
lines = text.replace('\r\n', '\n').split('\n') | |
if ((line and not | |
line == sb[len(sb) - 1]) or self.newline): | |
self.newline = False | |
self.line = line = None | |
if line: | |
line.body += lines[0] | |
lines = lines[1:] | |
if lines and lines[len(lines) - 1] == '': | |
self.newline = True | |
lines = lines[:-1] | |
if bpy.app.version > (3, 6, 0): | |
with bpy.context.temp_override(**self.context): | |
for l in lines: | |
bpy.ops.console.scrollback_append(text=l, type=self.enum) | |
if bpy.app.version < (3, 6, 0): | |
for l in lines: | |
bpy.ops.console.scrollback_append( | |
self.context, text=l, type=self.enum) | |
self.line = sb[len(sb) - 1] | |
except: | |
import traceback | |
traceback.print_exc(file=sys.__stderr__) | |
# no-op interface | |
def flush(self): | |
pass | |
def tell(self): | |
return 0 | |
def read(self, size=-1): | |
return '' | |
def seek(self, offset, whence=0): | |
pass | |
def truncate(self, size=None): | |
pass | |
@property | |
def name(self): | |
return self.enum | |
def get_console_context(): | |
# do nothing while _RestrictContext | |
if not hasattr(bpy.context, 'window'): | |
return {} | |
context = { | |
'window': bpy.context.window, | |
} | |
for screen in bpy.data.screens: | |
for area in screen.areas: | |
if area.type == 'CONSOLE': | |
context['area'] = area | |
context['screen'] = screen | |
for space in area.spaces: | |
if space.type == 'CONSOLE': | |
context['space_data'] = space | |
for region in area.regions: | |
if region.type == 'WINDOW': | |
context['region'] = region | |
return context | |
return {} | |
def capture_streams(): | |
sys.stdout = info | |
sys.stderr = error | |
def release_streams(): | |
sys.stdout = sys.__stdout__ | |
sys.stderr = sys.__stderr__ | |
_console_draw_handle = None | |
@bpy.app.handlers.persistent | |
def install(*args, **kwargs): | |
global _console_draw_handle | |
wm = bpy.context.window_manager | |
if wm.capture_console_output: | |
reset() | |
context = get_console_context() | |
if context: | |
space = context['space_data'] | |
if _console_draw_handle: | |
space.draw_handler_remove(_console_draw_handle, 'WINDOW') | |
_console_draw_handle = space.draw_handler_add(capture_streams, tuple(), 'WINDOW', 'POST_PIXEL') | |
capture_streams() | |
def uninstall(*args, **kwargs): | |
global _console_draw_handle | |
context = get_console_context() | |
if context: | |
space = context['space_data'] | |
if _console_draw_handle: | |
space.draw_handler_remove(_console_draw_handle, 'WINDOW') | |
_console_draw_handle = None | |
release_streams() | |
def toggle_capture(self, context): | |
if self.capture_console_output: | |
install() | |
else: | |
uninstall() | |
bpy.types.WindowManager.capture_console_output = bpy.props.BoolProperty( | |
name='Capture System Output', default=False, update=toggle_capture, | |
description='Route system output (stdout/stderr) to this console',) | |
def console_header_draw(self, context): | |
layout = self.layout.row() | |
layout.operator("console.autocomplete", text="Autocomplete") | |
layout.prop(context.window_manager, 'capture_console_output') | |
def register(): | |
bpy.types.CONSOLE_HT_header.append(console_header_draw) | |
def unregister(): | |
bpy.types.CONSOLE_HT_header.remove(console_header_draw) | |
reset() | |
if __name__ == "__main__": | |
register() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment