move script directories for internal blender scripts.
ui/ --> startup/bl_ui op/ --> startup/bl_operators scripts/startup/ is now the only auto-loading script dir which gives some speedup for blender loading too. ~/.blender/2.56/scripts/startup works for auto-loading scripts too.
This commit is contained in:
306
release/scripts/modules/console_python.py
Normal file
306
release/scripts/modules/console_python.py
Normal file
@@ -0,0 +1,306 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
import sys
|
||||
import bpy
|
||||
|
||||
language_id = 'python'
|
||||
|
||||
# store our own __main__ module, not 100% needed
|
||||
# but python expects this in some places
|
||||
_BPY_MAIN_OWN = True
|
||||
|
||||
|
||||
def add_scrollback(text, text_type):
|
||||
for l in text.split('\n'):
|
||||
bpy.ops.console.scrollback_append(text=l.replace('\t', ' '),
|
||||
type=text_type)
|
||||
|
||||
|
||||
def replace_help(namespace):
|
||||
def _help(value):
|
||||
# because of how the console works. we need our own help() pager func.
|
||||
# replace the bold function because it adds crazy chars
|
||||
import pydoc
|
||||
pydoc.getpager = lambda: pydoc.plainpager
|
||||
pydoc.Helper.getline = lambda self, prompt: None
|
||||
pydoc.TextDoc.use_bold = lambda self, text: text
|
||||
|
||||
help(value)
|
||||
|
||||
namespace["help"] = _help
|
||||
|
||||
|
||||
def get_console(console_id):
|
||||
'''
|
||||
helper function for console operators
|
||||
currently each text datablock gets its own
|
||||
console - code.InteractiveConsole()
|
||||
...which is stored in this function.
|
||||
|
||||
console_id can be any hashable type
|
||||
'''
|
||||
from code import InteractiveConsole
|
||||
|
||||
consoles = getattr(get_console, "consoles", None)
|
||||
hash_next = hash(bpy.context.window_manager)
|
||||
|
||||
if consoles is None:
|
||||
consoles = get_console.consoles = {}
|
||||
get_console.consoles_namespace_hash = hash_next
|
||||
else:
|
||||
# check if clearning the namespace is needed to avoid a memory leak.
|
||||
# the window manager is normally loaded with new blend files
|
||||
# so this is a reasonable way to deal with namespace clearing.
|
||||
# bpy.data hashing is reset by undo so cant be used.
|
||||
hash_prev = getattr(get_console, "consoles_namespace_hash", 0)
|
||||
|
||||
if hash_prev != hash_next:
|
||||
get_console.consoles_namespace_hash = hash_next
|
||||
consoles.clear()
|
||||
|
||||
console_data = consoles.get(console_id)
|
||||
|
||||
if console_data:
|
||||
console, stdout, stderr = console_data
|
||||
|
||||
# XXX, bug in python 3.1.2 ? (worked in 3.1.1)
|
||||
# seems there is no way to clear StringIO objects for writing, have to make new ones each time.
|
||||
import io
|
||||
stdout = io.StringIO()
|
||||
stderr = io.StringIO()
|
||||
else:
|
||||
if _BPY_MAIN_OWN:
|
||||
import types
|
||||
bpy_main_mod = types.ModuleType("__main__")
|
||||
namespace = bpy_main_mod.__dict__
|
||||
else:
|
||||
namespace = {}
|
||||
|
||||
namespace["__builtins__"] = sys.modules["builtins"]
|
||||
namespace["bpy"] = bpy
|
||||
namespace["C"] = bpy.context
|
||||
|
||||
replace_help(namespace)
|
||||
|
||||
console = InteractiveConsole(locals=namespace, filename="<blender_console>")
|
||||
|
||||
console.push("from mathutils import *")
|
||||
console.push("from math import *")
|
||||
|
||||
if _BPY_MAIN_OWN:
|
||||
console._bpy_main_mod = bpy_main_mod
|
||||
|
||||
import io
|
||||
stdout = io.StringIO()
|
||||
stderr = io.StringIO()
|
||||
|
||||
consoles[console_id] = console, stdout, stderr
|
||||
|
||||
return console, stdout, stderr
|
||||
|
||||
|
||||
# Both prompts must be the same length
|
||||
PROMPT = '>>> '
|
||||
PROMPT_MULTI = '... '
|
||||
|
||||
|
||||
def execute(context):
|
||||
sc = context.space_data
|
||||
|
||||
try:
|
||||
line_object = sc.history[-1]
|
||||
except:
|
||||
return {'CANCELLED'}
|
||||
|
||||
console, stdout, stderr = get_console(hash(context.region))
|
||||
|
||||
# redirect output
|
||||
sys.stdout = stdout
|
||||
sys.stderr = stderr
|
||||
|
||||
# dont allow the stdin to be used, can lock blender.
|
||||
stdin_backup = sys.stdin
|
||||
sys.stdin = None
|
||||
|
||||
if _BPY_MAIN_OWN:
|
||||
main_mod_back = sys.modules["__main__"]
|
||||
sys.modules["__main__"] = console._bpy_main_mod
|
||||
|
||||
# incase exception happens
|
||||
line = "" # incase of encodingf error
|
||||
is_multiline = False
|
||||
|
||||
try:
|
||||
line = line_object.body
|
||||
|
||||
# run the console, "\n" executes a multiline statement
|
||||
line_exec = line if line.strip() else "\n"
|
||||
|
||||
is_multiline = console.push(line_exec)
|
||||
except:
|
||||
# unlikely, but this can happen with unicode errors for example.
|
||||
import traceback
|
||||
stderr.write(traceback.format_exc())
|
||||
|
||||
if _BPY_MAIN_OWN:
|
||||
sys.modules["__main__"] = main_mod_back
|
||||
|
||||
stdout.seek(0)
|
||||
stderr.seek(0)
|
||||
|
||||
output = stdout.read()
|
||||
output_err = stderr.read()
|
||||
|
||||
# cleanup
|
||||
sys.stdout = sys.__stdout__
|
||||
sys.stderr = sys.__stderr__
|
||||
sys.last_traceback = None
|
||||
|
||||
# So we can reuse, clear all data
|
||||
stdout.truncate(0)
|
||||
stderr.truncate(0)
|
||||
|
||||
# special exception. its possible the command loaded a new user interface
|
||||
if hash(sc) != hash(context.space_data):
|
||||
return
|
||||
|
||||
bpy.ops.console.scrollback_append(text=sc.prompt + line, type='INPUT')
|
||||
|
||||
if is_multiline:
|
||||
sc.prompt = PROMPT_MULTI
|
||||
else:
|
||||
sc.prompt = PROMPT
|
||||
|
||||
# insert a new blank line
|
||||
bpy.ops.console.history_append(text="", current_character=0,
|
||||
remove_duplicates=True)
|
||||
|
||||
# Insert the output into the editor
|
||||
# not quite correct because the order might have changed,
|
||||
# but ok 99% of the time.
|
||||
if output:
|
||||
add_scrollback(output, 'OUTPUT')
|
||||
if output_err:
|
||||
add_scrollback(output_err, 'ERROR')
|
||||
|
||||
# restore the stdin
|
||||
sys.stdin = stdin_backup
|
||||
|
||||
# execute any hooks
|
||||
for func, args in execute.hooks:
|
||||
func(*args)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
execute.hooks = []
|
||||
|
||||
|
||||
def autocomplete(context):
|
||||
from console import intellisense
|
||||
|
||||
sc = context.space_data
|
||||
|
||||
console = get_console(hash(context.region))[0]
|
||||
|
||||
if not console:
|
||||
return {'CANCELLED'}
|
||||
|
||||
# dont allow the stdin to be used, can lock blender.
|
||||
# note: unlikely stdin would be used for autocomp. but its possible.
|
||||
stdin_backup = sys.stdin
|
||||
sys.stdin = None
|
||||
|
||||
scrollback = ""
|
||||
scrollback_error = ""
|
||||
|
||||
if _BPY_MAIN_OWN:
|
||||
main_mod_back = sys.modules["__main__"]
|
||||
sys.modules["__main__"] = console._bpy_main_mod
|
||||
|
||||
try:
|
||||
current_line = sc.history[-1]
|
||||
line = current_line.body
|
||||
|
||||
# This function isnt aware of the text editor or being an operator
|
||||
# just does the autocomp then copy its results back
|
||||
result = intellisense.expand(
|
||||
line=line,
|
||||
cursor=current_line.current_character,
|
||||
namespace=console.locals,
|
||||
private=bpy.app.debug)
|
||||
|
||||
line_new = result[0]
|
||||
current_line.body, current_line.current_character, scrollback = result
|
||||
del result
|
||||
|
||||
# update sel. setting body should really do this!
|
||||
ofs = len(line_new) - len(line)
|
||||
sc.select_start += ofs
|
||||
sc.select_end += ofs
|
||||
except:
|
||||
# unlikely, but this can happen with unicode errors for example.
|
||||
# or if the api attribute access its self causes an error.
|
||||
import traceback
|
||||
scrollback_error = traceback.format_exc()
|
||||
|
||||
if _BPY_MAIN_OWN:
|
||||
sys.modules["__main__"] = main_mod_back
|
||||
|
||||
# Separate automplete output by command prompts
|
||||
if scrollback != '':
|
||||
bpy.ops.console.scrollback_append(text=sc.prompt + current_line.body, type='INPUT')
|
||||
|
||||
# Now we need to copy back the line from blender back into the
|
||||
# text editor. This will change when we dont use the text editor
|
||||
# anymore
|
||||
if scrollback:
|
||||
add_scrollback(scrollback, 'INFO')
|
||||
|
||||
if scrollback_error:
|
||||
add_scrollback(scrollback_error, 'ERROR')
|
||||
|
||||
# restore the stdin
|
||||
sys.stdin = stdin_backup
|
||||
|
||||
context.area.tag_redraw()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def banner(context):
|
||||
sc = context.space_data
|
||||
version_string = sys.version.strip().replace('\n', ' ')
|
||||
|
||||
add_scrollback("PYTHON INTERACTIVE CONSOLE %s" % version_string, 'OUTPUT')
|
||||
add_scrollback("", 'OUTPUT')
|
||||
add_scrollback("Command History: Up/Down Arrow", 'OUTPUT')
|
||||
add_scrollback("Cursor: Left/Right Home/End", 'OUTPUT')
|
||||
add_scrollback("Remove: Backspace/Delete", 'OUTPUT')
|
||||
add_scrollback("Execute: Enter", 'OUTPUT')
|
||||
add_scrollback("Autocomplete: Ctrl+Space", 'OUTPUT')
|
||||
add_scrollback("Ctrl +/- Wheel: Zoom", 'OUTPUT')
|
||||
add_scrollback("Builtin Modules: bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context, bgl, blf, mathutils", 'OUTPUT')
|
||||
add_scrollback("Convenience Imports: from mathutils import *; from math import *", 'OUTPUT')
|
||||
add_scrollback("", 'OUTPUT')
|
||||
add_scrollback(" WARNING!!! Blender 2.5 API is subject to change, see API reference for more info.", 'ERROR')
|
||||
add_scrollback("", 'OUTPUT')
|
||||
sc.prompt = PROMPT
|
||||
|
||||
return {'FINISHED'}
|
||||
Reference in New Issue
Block a user