Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'release/scripts/modules/console_python.py')
-rw-r--r--release/scripts/modules/console_python.py306
1 files changed, 306 insertions, 0 deletions
diff --git a/release/scripts/modules/console_python.py b/release/scripts/modules/console_python.py
new file mode 100644
index 00000000000..c25103e740c
--- /dev/null
+++ b/release/scripts/modules/console_python.py
@@ -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'}