##// END OF EJS Templates
Merge pull request #3450 from ipython/flatten...
Fernando Perez -
r11042:0c0c1a16 merge
parent child Browse files
Show More
@@ -0,0 +1,79 b''
1 """
2 Shim to maintain backwards compatibility with old frontend imports.
3
4 We have moved all contents of the old `frontend` subpackage into top-level
5 subpackages (`html`, `qt` and `terminal`), and flattened the notebook into
6 just `IPython.html`, formerly `IPython.frontend.html.notebook`.
7
8 This will let code that was making `from IPython.frontend...` calls continue
9 working, though a warning will be printed.
10 """
11
12 #-----------------------------------------------------------------------------
13 # Copyright (c) 2013, IPython Development Team.
14 #
15 # Distributed under the terms of the Modified BSD License.
16 #
17 # The full license is in the file COPYING.txt, distributed with this software.
18 #-----------------------------------------------------------------------------
19
20 #-----------------------------------------------------------------------------
21 # Imports
22 #-----------------------------------------------------------------------------
23 from __future__ import print_function
24
25 # Stdlib
26 import sys
27 import types
28 from warnings import warn
29
30 warn("The top-level `frontend` package has been deprecated. "
31 "All its subpackages have been moved to the top `IPython` level.")
32
33 #-----------------------------------------------------------------------------
34 # Class declarations
35 #-----------------------------------------------------------------------------
36
37 class ShimModule(types.ModuleType):
38
39 def __init__(self, *args, **kwargs):
40 self._mirror = kwargs.pop("mirror")
41 super(ShimModule, self).__init__(*args, **kwargs)
42
43 def __getattr__(self, key):
44 # Use the equivalent of import_item(name), see below
45 name = "%s.%s" % (self._mirror, key)
46
47 # NOTE: the code below is copied *verbatim* from
48 # importstring.import_item. For some very strange reason that makes no
49 # sense to me, if we call it *as a function*, it doesn't work. This
50 # has something to do with the deep bowels of the import machinery and
51 # I couldn't find a way to make the code work as a standard function
52 # call. But at least since it's an unmodified copy of import_item,
53 # which is used extensively and has a test suite, we can be reasonably
54 # confident this is OK. If anyone finds how to call the function, all
55 # the below could be replaced simply with:
56 #
57 # from IPython.utils.importstring import import_item
58 # return import_item('MIRROR.' + key)
59
60 parts = name.rsplit('.', 1)
61 if len(parts) == 2:
62 # called with 'foo.bar....'
63 package, obj = parts
64 module = __import__(package, fromlist=[obj])
65 try:
66 pak = module.__dict__[obj]
67 except KeyError:
68 raise ImportError('No module named %s' % obj)
69 return pak
70 else:
71 # called with un-dotted string
72 return __import__(parts[0])
73
74
75 # Unconditionally insert the shim into sys.modules so that further import calls
76 # trigger the custom attribute access above
77
78 sys.modules['IPython.frontend.html.notebook'] = ShimModule('notebook', mirror='IPython.html')
79 sys.modules['IPython.frontend'] = ShimModule('frontend', mirror='IPython')
@@ -0,0 +1,1 b''
1 Subproject commit 2a98f498092682f11affe9b0b86bd7e642cf7b13
@@ -0,0 +1,39 b''
1 """Tests for IPython.utils.importstring."""
2
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2013 The IPython Development Team
5 #
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
14 import nose.tools as nt
15
16 from IPython.utils.importstring import import_item
17
18 #-----------------------------------------------------------------------------
19 # Tests
20 #-----------------------------------------------------------------------------
21
22 def test_import_plain():
23 "Test simple imports"
24 import os
25 os2 = import_item('os')
26 nt.assert_true(os is os2)
27
28
29 def test_import_nested():
30 "Test nested imports from the stdlib"
31 from os import path
32 path2 = import_item('os.path')
33 nt.assert_true(path is path2)
34
35
36 def test_import_raises():
37 "Test that failing imports raise the right exception"
38 nt.assert_raises(ImportError, import_item, 'IPython.foobar')
39
@@ -5,7 +5,7 b' _build'
5 docs/man/*.gz
5 docs/man/*.gz
6 docs/source/api/generated
6 docs/source/api/generated
7 docs/gh-pages
7 docs/gh-pages
8 IPython/frontend/html/notebook/static/mathjax
8 IPython/html/notebook/static/mathjax
9 *.py[co]
9 *.py[co]
10 __pycache__
10 __pycache__
11 build
11 build
@@ -1,3 +1,3 b''
1 [submodule "components"]
1 [submodule "components"]
2 path = IPython/frontend/html/notebook/static/components
2 path = IPython/html/static/components
3 url = https://github.com/ipython/ipython-components.git
3 url = https://github.com/ipython/ipython-components.git
@@ -44,7 +44,7 b' from .config.loader import Config'
44 from .core.getipython import get_ipython
44 from .core.getipython import get_ipython
45 from .core import release
45 from .core import release
46 from .core.application import Application
46 from .core.application import Application
47 from .frontend.terminal.embed import embed
47 from .terminal.embed import embed
48
48
49 from .core.error import TryNext
49 from .core.error import TryNext
50 from .core.interactiveshell import InteractiveShell
50 from .core.interactiveshell import InteractiveShell
@@ -9,6 +9,6 b''
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 from IPython.frontend.terminal.ipapp import launch_new_instance
12 from IPython.terminal.ipapp import launch_new_instance
13
13
14 launch_new_instance()
14 launch_new_instance()
@@ -2,7 +2,7 b''
2
2
3 This is not a complete console app, as subprocess will not be able to receive
3 This is not a complete console app, as subprocess will not be able to receive
4 input, there is no real readline support, among other limitations. This is a
4 input, there is no real readline support, among other limitations. This is a
5 refactoring of what used to be the IPython/frontend/qt/console/qtconsoleapp.py
5 refactoring of what used to be the IPython/qt/console/qtconsoleapp.py
6
6
7 Authors:
7 Authors:
8
8
@@ -238,10 +238,10 b' class ProfileCreate(BaseIPythonApplication):'
238 def init_config_files(self):
238 def init_config_files(self):
239 super(ProfileCreate, self).init_config_files()
239 super(ProfileCreate, self).init_config_files()
240 # use local imports, since these classes may import from here
240 # use local imports, since these classes may import from here
241 from IPython.frontend.terminal.ipapp import TerminalIPythonApp
241 from IPython.terminal.ipapp import TerminalIPythonApp
242 apps = [TerminalIPythonApp]
242 apps = [TerminalIPythonApp]
243 try:
243 try:
244 from IPython.frontend.qt.console.qtconsoleapp import IPythonQtConsoleApp
244 from IPython.qt.console.qtconsoleapp import IPythonQtConsoleApp
245 except Exception:
245 except Exception:
246 # this should be ImportError, but under weird circumstances
246 # this should be ImportError, but under weird circumstances
247 # this might be an AttributeError, or possibly others
247 # this might be an AttributeError, or possibly others
@@ -250,7 +250,7 b' class ProfileCreate(BaseIPythonApplication):'
250 else:
250 else:
251 apps.append(IPythonQtConsoleApp)
251 apps.append(IPythonQtConsoleApp)
252 try:
252 try:
253 from IPython.frontend.html.notebook.notebookapp import NotebookApp
253 from IPython.html.notebookapp import NotebookApp
254 except ImportError:
254 except ImportError:
255 pass
255 pass
256 except Exception:
256 except Exception:
@@ -29,7 +29,7 b' def test_image_filename_defaults():'
29 embed=True)
29 embed=True)
30 nt.assert_raises(ValueError, display.Image)
30 nt.assert_raises(ValueError, display.Image)
31 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
31 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
32 imgfile = os.path.join(tpath, 'frontend/html/notebook/static/base/images/ipynblogo.png')
32 imgfile = os.path.join(tpath, 'html/static/base/images/ipynblogo.png')
33 img = display.Image(filename=imgfile)
33 img = display.Image(filename=imgfile)
34 nt.assert_equal('png', img.format)
34 nt.assert_equal('png', img.format)
35 nt.assert_is_not_none(img._repr_png_())
35 nt.assert_is_not_none(img._repr_png_())
@@ -54,7 +54,7 b' wide install.'
54
54
55 First, cd into js directory :
55 First, cd into js directory :
56 ```bash
56 ```bash
57 cd IPython/frontend/html/notebook/static/js/
57 cd IPython/html/static/js/
58 # install yuidoc
58 # install yuidoc
59 npm install yuidocjs
59 npm install yuidocjs
60 ```
60 ```
@@ -62,7 +62,7 b' npm install yuidocjs'
62
62
63 ### Run YUIdoc server
63 ### Run YUIdoc server
64
64
65 From IPython/frontend/html/notebook/static/js/
65 From IPython/html/static/js/
66 ```bash
66 ```bash
67 # run yuidoc for install dir
67 # run yuidoc for install dir
68 ./node_modules/yuidocjs/lib/cli.js --server .
68 ./node_modules/yuidocjs/lib/cli.js --server .
@@ -70,4 +70,4 b' From IPython/frontend/html/notebook/static/js/'
70
70
71 Follow the instruction and the documentation should be available on localhost:3000
71 Follow the instruction and the documentation should be available on localhost:3000
72
72
73 Omitting `--server` will build a static version in the `out` folder by default. No newline at end of file
73 Omitting `--server` will build a static version in the `out` folder by default.
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/__init__.py to IPython/html/__init__.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/__init__.py to IPython/html/__init__.py
1 NO CONTENT: file renamed from IPython/deathrow/__init__.py to IPython/html/auth/__init__.py
NO CONTENT: file renamed from IPython/deathrow/__init__.py to IPython/html/auth/__init__.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/auth/login.py to IPython/html/auth/login.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/auth/login.py to IPython/html/auth/login.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/auth/logout.py to IPython/html/auth/logout.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/auth/logout.py to IPython/html/auth/logout.py
1 NO CONTENT: file renamed from IPython/deathrow/gui/__init__.py to IPython/html/base/__init__.py
NO CONTENT: file renamed from IPython/deathrow/gui/__init__.py to IPython/html/base/__init__.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/base/handlers.py to IPython/html/base/handlers.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/base/handlers.py to IPython/html/base/handlers.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/base/zmqhandlers.py to IPython/html/base/zmqhandlers.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/base/zmqhandlers.py to IPython/html/base/zmqhandlers.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/fabfile.py to IPython/html/fabfile.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/fabfile.py to IPython/html/fabfile.py
1 NO CONTENT: file renamed from IPython/deathrow/gui/wx/__init__.py to IPython/html/notebook/__init__.py
NO CONTENT: file renamed from IPython/deathrow/gui/wx/__init__.py to IPython/html/notebook/__init__.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/notebook/handlers.py to IPython/html/notebook/handlers.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/notebook/handlers.py to IPython/html/notebook/handlers.py
@@ -34,7 +34,7 b' import webbrowser'
34 # Third party
34 # Third party
35 # check for pyzmq 2.1.11
35 # check for pyzmq 2.1.11
36 from IPython.utils.zmqrelated import check_for_zmq
36 from IPython.utils.zmqrelated import check_for_zmq
37 check_for_zmq('2.1.11', 'IPython.frontend.html.notebook')
37 check_for_zmq('2.1.11', 'IPython.html')
38
38
39 import zmq
39 import zmq
40 from jinja2 import Environment, FileSystemLoader
40 from jinja2 import Environment, FileSystemLoader
@@ -61,7 +61,7 b' from tornado import httpserver'
61 from tornado import web
61 from tornado import web
62
62
63 # Our own libraries
63 # Our own libraries
64 from IPython.frontend.html.notebook import DEFAULT_STATIC_FILES_PATH
64 from IPython.html import DEFAULT_STATIC_FILES_PATH
65
65
66 from .services.kernels.kernelmanager import MappingKernelManager
66 from .services.kernels.kernelmanager import MappingKernelManager
67 from .services.notebooks.nbmanager import NotebookManager
67 from .services.notebooks.nbmanager import NotebookManager
@@ -72,7 +72,7 b' from .base.handlers import AuthenticatedFileHandler, FileFindHandler'
72
72
73 from IPython.config.application import catch_config_error, boolean_flag
73 from IPython.config.application import catch_config_error, boolean_flag
74 from IPython.core.application import BaseIPythonApplication
74 from IPython.core.application import BaseIPythonApplication
75 from IPython.frontend.consoleapp import IPythonConsoleApp
75 from IPython.consoleapp import IPythonConsoleApp
76 from IPython.kernel import swallow_argv
76 from IPython.kernel import swallow_argv
77 from IPython.kernel.zmq.session import default_secure
77 from IPython.kernel.zmq.session import default_secure
78 from IPython.kernel.zmq.kernelapp import (
78 from IPython.kernel.zmq.kernelapp import (
@@ -120,7 +120,7 b' def random_ports(port, n):'
120
120
121 def load_handlers(name):
121 def load_handlers(name):
122 """Load the (URL pattern, handler) tuples for each component."""
122 """Load the (URL pattern, handler) tuples for each component."""
123 name = 'IPython.frontend.html.notebook.' + name
123 name = 'IPython.html.' + name
124 mod = __import__(name, fromlist=['default_handlers'])
124 mod = __import__(name, fromlist=['default_handlers'])
125 return mod.default_handlers
125 return mod.default_handlers
126
126
@@ -490,7 +490,7 b' class NotebookApp(BaseIPythonApplication):'
490 else:
490 else:
491 self.log.info("Using MathJax: %s", new)
491 self.log.info("Using MathJax: %s", new)
492
492
493 notebook_manager_class = DottedObjectName('IPython.frontend.html.notebook.services.notebooks.filenbmanager.FileNotebookManager',
493 notebook_manager_class = DottedObjectName('IPython.html.services.notebooks.filenbmanager.FileNotebookManager',
494 config=True,
494 config=True,
495 help='The notebook manager class to use.')
495 help='The notebook manager class to use.')
496
496
1 NO CONTENT: file renamed from IPython/deathrow/oldfrontend/cocoa/__init__.py to IPython/html/services/__init__.py
NO CONTENT: file renamed from IPython/deathrow/oldfrontend/cocoa/__init__.py to IPython/html/services/__init__.py
1 NO CONTENT: file renamed from IPython/deathrow/oldfrontend/cocoa/tests/__init__.py to IPython/html/services/clusters/__init__.py
NO CONTENT: file renamed from IPython/deathrow/oldfrontend/cocoa/tests/__init__.py to IPython/html/services/clusters/__init__.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/services/clusters/clustermanager.py to IPython/html/services/clusters/clustermanager.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/services/clusters/clustermanager.py to IPython/html/services/clusters/clustermanager.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/services/clusters/handlers.py to IPython/html/services/clusters/handlers.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/services/clusters/handlers.py to IPython/html/services/clusters/handlers.py
1 NO CONTENT: file renamed from IPython/deathrow/oldfrontend/tests/__init__.py to IPython/html/services/kernels/__init__.py
NO CONTENT: file renamed from IPython/deathrow/oldfrontend/tests/__init__.py to IPython/html/services/kernels/__init__.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/services/kernels/handlers.py to IPython/html/services/kernels/handlers.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/services/kernels/handlers.py to IPython/html/services/kernels/handlers.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/services/kernels/kernelmanager.py to IPython/html/services/kernels/kernelmanager.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/services/kernels/kernelmanager.py to IPython/html/services/kernels/kernelmanager.py
1 NO CONTENT: file renamed from IPython/deathrow/oldfrontend/wx/__init__.py to IPython/html/services/notebooks/__init__.py
NO CONTENT: file renamed from IPython/deathrow/oldfrontend/wx/__init__.py to IPython/html/services/notebooks/__init__.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/services/notebooks/azurenbmanager.py to IPython/html/services/notebooks/azurenbmanager.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/services/notebooks/azurenbmanager.py to IPython/html/services/notebooks/azurenbmanager.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/services/notebooks/filenbmanager.py to IPython/html/services/notebooks/filenbmanager.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/services/notebooks/filenbmanager.py to IPython/html/services/notebooks/filenbmanager.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/services/notebooks/handlers.py to IPython/html/services/notebooks/handlers.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/services/notebooks/handlers.py to IPython/html/services/notebooks/handlers.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/services/notebooks/nbmanager.py to IPython/html/services/notebooks/nbmanager.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/services/notebooks/nbmanager.py to IPython/html/services/notebooks/nbmanager.py
1 NO CONTENT: file renamed from IPython/deathrow/tests/__init__.py to IPython/html/services/notebooks/tests/__init__.py
NO CONTENT: file renamed from IPython/deathrow/tests/__init__.py to IPython/html/services/notebooks/tests/__init__.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/services/notebooks/tests/test_nbmanager.py to IPython/html/services/notebooks/tests/test_nbmanager.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/services/notebooks/tests/test_nbmanager.py to IPython/html/services/notebooks/tests/test_nbmanager.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/auth/css/override.css to IPython/html/static/auth/css/override.css
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/auth/css/override.css to IPython/html/static/auth/css/override.css
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/auth/js/loginmain.js to IPython/html/static/auth/js/loginmain.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/auth/js/loginmain.js to IPython/html/static/auth/js/loginmain.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/auth/js/loginwidget.js to IPython/html/static/auth/js/loginwidget.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/auth/js/loginwidget.js to IPython/html/static/auth/js/loginwidget.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/auth/js/logoutmain.js to IPython/html/static/auth/js/logoutmain.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/auth/js/logoutmain.js to IPython/html/static/auth/js/logoutmain.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/auth/less/login.less to IPython/html/static/auth/less/login.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/auth/less/login.less to IPython/html/static/auth/less/login.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/auth/less/logout.less to IPython/html/static/auth/less/logout.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/auth/less/logout.less to IPython/html/static/auth/less/logout.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/auth/less/style.less to IPython/html/static/auth/less/style.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/auth/less/style.less to IPython/html/static/auth/less/style.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/css/boilerplate.css to IPython/html/static/base/css/boilerplate.css
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/css/boilerplate.css to IPython/html/static/base/css/boilerplate.css
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/images/favicon.ico to IPython/html/static/base/images/favicon.ico
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/images/favicon.ico to IPython/html/static/base/images/favicon.ico
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/images/ipynblogo.png to IPython/html/static/base/images/ipynblogo.png
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/images/ipynblogo.png to IPython/html/static/base/images/ipynblogo.png
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/images/ipynblogo.svg to IPython/html/static/base/images/ipynblogo.svg
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/images/ipynblogo.svg to IPython/html/static/base/images/ipynblogo.svg
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/js/dialog.js to IPython/html/static/base/js/dialog.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/js/dialog.js to IPython/html/static/base/js/dialog.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/js/events.js to IPython/html/static/base/js/events.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/js/events.js to IPython/html/static/base/js/events.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/js/namespace.js to IPython/html/static/base/js/namespace.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/js/namespace.js to IPython/html/static/base/js/namespace.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/js/page.js to IPython/html/static/base/js/page.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/js/page.js to IPython/html/static/base/js/page.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/js/pagemain.js to IPython/html/static/base/js/pagemain.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/js/pagemain.js to IPython/html/static/base/js/pagemain.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/js/utils.js to IPython/html/static/base/js/utils.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/js/utils.js to IPython/html/static/base/js/utils.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/less/flexbox.less to IPython/html/static/base/less/flexbox.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/less/flexbox.less to IPython/html/static/base/less/flexbox.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/less/mixins.less to IPython/html/static/base/less/mixins.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/less/mixins.less to IPython/html/static/base/less/mixins.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/less/page.less to IPython/html/static/base/less/page.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/less/page.less to IPython/html/static/base/less/page.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/less/style.less to IPython/html/static/base/less/style.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/less/style.less to IPython/html/static/base/less/style.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/less/variables.less to IPython/html/static/base/less/variables.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/base/less/variables.less to IPython/html/static/base/less/variables.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/custom/custom.css to IPython/html/static/custom/custom.css
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/custom/custom.css to IPython/html/static/custom/custom.css
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/custom/custom.js to IPython/html/static/custom/custom.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/custom/custom.js to IPython/html/static/custom/custom.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/dateformat/date.format.js to IPython/html/static/dateformat/date.format.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/dateformat/date.format.js to IPython/html/static/dateformat/date.format.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/css/override.css to IPython/html/static/notebook/css/override.css
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/css/override.css to IPython/html/static/notebook/css/override.css
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/cell.js to IPython/html/static/notebook/js/cell.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/cell.js to IPython/html/static/notebook/js/cell.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/celltoolbar.js to IPython/html/static/notebook/js/celltoolbar.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/celltoolbar.js to IPython/html/static/notebook/js/celltoolbar.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/celltoolbarpresets/default.js to IPython/html/static/notebook/js/celltoolbarpresets/default.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/celltoolbarpresets/default.js to IPython/html/static/notebook/js/celltoolbarpresets/default.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/celltoolbarpresets/example.js to IPython/html/static/notebook/js/celltoolbarpresets/example.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/celltoolbarpresets/example.js to IPython/html/static/notebook/js/celltoolbarpresets/example.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/celltoolbarpresets/slideshow.js to IPython/html/static/notebook/js/celltoolbarpresets/slideshow.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/celltoolbarpresets/slideshow.js to IPython/html/static/notebook/js/celltoolbarpresets/slideshow.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/codecell.js to IPython/html/static/notebook/js/codecell.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/codecell.js to IPython/html/static/notebook/js/codecell.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/codemirror-ipython.js to IPython/html/static/notebook/js/codemirror-ipython.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/codemirror-ipython.js to IPython/html/static/notebook/js/codemirror-ipython.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/completer.js to IPython/html/static/notebook/js/completer.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/completer.js to IPython/html/static/notebook/js/completer.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/config.js to IPython/html/static/notebook/js/config.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/config.js to IPython/html/static/notebook/js/config.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/contexthint.js to IPython/html/static/notebook/js/contexthint.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/contexthint.js to IPython/html/static/notebook/js/contexthint.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/layoutmanager.js to IPython/html/static/notebook/js/layoutmanager.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/layoutmanager.js to IPython/html/static/notebook/js/layoutmanager.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/main.js to IPython/html/static/notebook/js/main.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/main.js to IPython/html/static/notebook/js/main.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/maintoolbar.js to IPython/html/static/notebook/js/maintoolbar.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/maintoolbar.js to IPython/html/static/notebook/js/maintoolbar.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/mathjaxutils.js to IPython/html/static/notebook/js/mathjaxutils.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/mathjaxutils.js to IPython/html/static/notebook/js/mathjaxutils.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/menubar.js to IPython/html/static/notebook/js/menubar.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/menubar.js to IPython/html/static/notebook/js/menubar.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/notebook.js to IPython/html/static/notebook/js/notebook.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/notebook.js to IPython/html/static/notebook/js/notebook.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/notificationarea.js to IPython/html/static/notebook/js/notificationarea.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/notificationarea.js to IPython/html/static/notebook/js/notificationarea.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/notificationwidget.js to IPython/html/static/notebook/js/notificationwidget.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/notificationwidget.js to IPython/html/static/notebook/js/notificationwidget.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/outputarea.js to IPython/html/static/notebook/js/outputarea.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/outputarea.js to IPython/html/static/notebook/js/outputarea.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/pager.js to IPython/html/static/notebook/js/pager.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/pager.js to IPython/html/static/notebook/js/pager.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/quickhelp.js to IPython/html/static/notebook/js/quickhelp.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/quickhelp.js to IPython/html/static/notebook/js/quickhelp.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/savewidget.js to IPython/html/static/notebook/js/savewidget.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/savewidget.js to IPython/html/static/notebook/js/savewidget.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/textcell.js to IPython/html/static/notebook/js/textcell.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/textcell.js to IPython/html/static/notebook/js/textcell.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/toolbar.js to IPython/html/static/notebook/js/toolbar.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/toolbar.js to IPython/html/static/notebook/js/toolbar.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/tooltip.js to IPython/html/static/notebook/js/tooltip.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/js/tooltip.js to IPython/html/static/notebook/js/tooltip.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/ansicolors.less to IPython/html/static/notebook/less/ansicolors.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/ansicolors.less to IPython/html/static/notebook/less/ansicolors.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/cell.less to IPython/html/static/notebook/less/cell.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/cell.less to IPython/html/static/notebook/less/cell.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/celltoolbar.less to IPython/html/static/notebook/less/celltoolbar.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/celltoolbar.less to IPython/html/static/notebook/less/celltoolbar.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/codecell.less to IPython/html/static/notebook/less/codecell.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/codecell.less to IPython/html/static/notebook/less/codecell.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/codemirror.less to IPython/html/static/notebook/less/codemirror.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/codemirror.less to IPython/html/static/notebook/less/codemirror.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/completer.less to IPython/html/static/notebook/less/completer.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/completer.less to IPython/html/static/notebook/less/completer.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/highlight.less to IPython/html/static/notebook/less/highlight.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/highlight.less to IPython/html/static/notebook/less/highlight.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/menubar.less to IPython/html/static/notebook/less/menubar.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/menubar.less to IPython/html/static/notebook/less/menubar.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/notebook.less to IPython/html/static/notebook/less/notebook.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/notebook.less to IPython/html/static/notebook/less/notebook.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/notificationarea.less to IPython/html/static/notebook/less/notificationarea.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/notificationarea.less to IPython/html/static/notebook/less/notificationarea.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/notificationwidget.less to IPython/html/static/notebook/less/notificationwidget.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/notificationwidget.less to IPython/html/static/notebook/less/notificationwidget.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/outputarea.less to IPython/html/static/notebook/less/outputarea.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/outputarea.less to IPython/html/static/notebook/less/outputarea.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/pager.less to IPython/html/static/notebook/less/pager.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/pager.less to IPython/html/static/notebook/less/pager.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/quickhelp.less to IPython/html/static/notebook/less/quickhelp.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/quickhelp.less to IPython/html/static/notebook/less/quickhelp.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/renderedhtml.less to IPython/html/static/notebook/less/renderedhtml.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/renderedhtml.less to IPython/html/static/notebook/less/renderedhtml.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/savewidget.less to IPython/html/static/notebook/less/savewidget.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/savewidget.less to IPython/html/static/notebook/less/savewidget.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/style.less to IPython/html/static/notebook/less/style.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/style.less to IPython/html/static/notebook/less/style.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/textcell.less to IPython/html/static/notebook/less/textcell.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/textcell.less to IPython/html/static/notebook/less/textcell.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/toolbar.less to IPython/html/static/notebook/less/toolbar.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/toolbar.less to IPython/html/static/notebook/less/toolbar.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/tooltip.less to IPython/html/static/notebook/less/tooltip.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/tooltip.less to IPython/html/static/notebook/less/tooltip.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/variables.less to IPython/html/static/notebook/less/variables.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/notebook/less/variables.less to IPython/html/static/notebook/less/variables.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/services/kernels/js/kernel.js to IPython/html/static/services/kernels/js/kernel.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/services/kernels/js/kernel.js to IPython/html/static/services/kernels/js/kernel.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/style/style.less to IPython/html/static/style/style.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/style/style.less to IPython/html/static/style/style.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/style/style.min.css to IPython/html/static/style/style.min.css
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/style/style.min.css to IPython/html/static/style/style.min.css
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/tree/css/override.css to IPython/html/static/tree/css/override.css
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/tree/css/override.css to IPython/html/static/tree/css/override.css
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/tree/js/clusterlist.js to IPython/html/static/tree/js/clusterlist.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/tree/js/clusterlist.js to IPython/html/static/tree/js/clusterlist.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/tree/js/main.js to IPython/html/static/tree/js/main.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/tree/js/main.js to IPython/html/static/tree/js/main.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/tree/js/notebooklist.js to IPython/html/static/tree/js/notebooklist.js
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/tree/js/notebooklist.js to IPython/html/static/tree/js/notebooklist.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/tree/less/altuploadform.less to IPython/html/static/tree/less/altuploadform.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/tree/less/altuploadform.less to IPython/html/static/tree/less/altuploadform.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/tree/less/style.less to IPython/html/static/tree/less/style.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/tree/less/style.less to IPython/html/static/tree/less/style.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/tree/less/tree.less to IPython/html/static/tree/less/tree.less
NO CONTENT: file renamed from IPython/frontend/html/notebook/static/tree/less/tree.less to IPython/html/static/tree/less/tree.less
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/templates/login.html to IPython/html/templates/login.html
NO CONTENT: file renamed from IPython/frontend/html/notebook/templates/login.html to IPython/html/templates/login.html
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/templates/logout.html to IPython/html/templates/logout.html
NO CONTENT: file renamed from IPython/frontend/html/notebook/templates/logout.html to IPython/html/templates/logout.html
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/templates/notebook.html to IPython/html/templates/notebook.html
NO CONTENT: file renamed from IPython/frontend/html/notebook/templates/notebook.html to IPython/html/templates/notebook.html
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/templates/page.html to IPython/html/templates/page.html
NO CONTENT: file renamed from IPython/frontend/html/notebook/templates/page.html to IPython/html/templates/page.html
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/templates/tree.html to IPython/html/templates/tree.html
NO CONTENT: file renamed from IPython/frontend/html/notebook/templates/tree.html to IPython/html/templates/tree.html
1 NO CONTENT: file renamed from IPython/frontend/__init__.py to IPython/html/tests/__init__.py
NO CONTENT: file renamed from IPython/frontend/__init__.py to IPython/html/tests/__init__.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/tests/test_hist.sqlite to IPython/html/tests/test_hist.sqlite
NO CONTENT: file renamed from IPython/frontend/html/notebook/tests/test_hist.sqlite to IPython/html/tests/test_hist.sqlite
1 NO CONTENT: file renamed from IPython/frontend/html/__init__.py to IPython/html/tree/__init__.py
NO CONTENT: file renamed from IPython/frontend/html/__init__.py to IPython/html/tree/__init__.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/tree/handlers.py to IPython/html/tree/handlers.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/tree/handlers.py to IPython/html/tree/handlers.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/utils.py to IPython/html/utils.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/utils.py to IPython/html/utils.py
@@ -300,7 +300,7 b' def connect_qtconsole(connection_file=None, argv=None, profile=None):'
300 cf = find_connection_file(connection_file, profile=profile)
300 cf = find_connection_file(connection_file, profile=profile)
301
301
302 cmd = ';'.join([
302 cmd = ';'.join([
303 "from IPython.frontend.qt.console import qtconsoleapp",
303 "from IPython.qt.console import qtconsoleapp",
304 "qtconsoleapp.main()"
304 "qtconsoleapp.main()"
305 ])
305 ])
306
306
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/auth/__init__.py to IPython/qt/__init__.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/auth/__init__.py to IPython/qt/__init__.py
1 NO CONTENT: file renamed from IPython/frontend/qt/base_frontend_mixin.py to IPython/qt/base_frontend_mixin.py
NO CONTENT: file renamed from IPython/frontend/qt/base_frontend_mixin.py to IPython/qt/base_frontend_mixin.py
1 NO CONTENT: file renamed from IPython/frontend/qt/client.py to IPython/qt/client.py
NO CONTENT: file renamed from IPython/frontend/qt/client.py to IPython/qt/client.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/base/__init__.py to IPython/qt/console/__init__.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/base/__init__.py to IPython/qt/console/__init__.py
1 NO CONTENT: file renamed from IPython/frontend/qt/console/ansi_code_processor.py to IPython/qt/console/ansi_code_processor.py
NO CONTENT: file renamed from IPython/frontend/qt/console/ansi_code_processor.py to IPython/qt/console/ansi_code_processor.py
1 NO CONTENT: file renamed from IPython/frontend/qt/console/bracket_matcher.py to IPython/qt/console/bracket_matcher.py
NO CONTENT: file renamed from IPython/frontend/qt/console/bracket_matcher.py to IPython/qt/console/bracket_matcher.py
1 NO CONTENT: file renamed from IPython/frontend/qt/console/call_tip_widget.py to IPython/qt/console/call_tip_widget.py
NO CONTENT: file renamed from IPython/frontend/qt/console/call_tip_widget.py to IPython/qt/console/call_tip_widget.py
1 NO CONTENT: file renamed from IPython/frontend/qt/console/completion_html.py to IPython/qt/console/completion_html.py
NO CONTENT: file renamed from IPython/frontend/qt/console/completion_html.py to IPython/qt/console/completion_html.py
1 NO CONTENT: file renamed from IPython/frontend/qt/console/completion_lexer.py to IPython/qt/console/completion_lexer.py
NO CONTENT: file renamed from IPython/frontend/qt/console/completion_lexer.py to IPython/qt/console/completion_lexer.py
1 NO CONTENT: file renamed from IPython/frontend/qt/console/completion_plain.py to IPython/qt/console/completion_plain.py
NO CONTENT: file renamed from IPython/frontend/qt/console/completion_plain.py to IPython/qt/console/completion_plain.py
1 NO CONTENT: file renamed from IPython/frontend/qt/console/completion_widget.py to IPython/qt/console/completion_widget.py
NO CONTENT: file renamed from IPython/frontend/qt/console/completion_widget.py to IPython/qt/console/completion_widget.py
@@ -18,8 +18,8 b' from IPython.external.qt import QtCore, QtGui'
18 # Local imports
18 # Local imports
19 from IPython.config.configurable import LoggingConfigurable
19 from IPython.config.configurable import LoggingConfigurable
20 from IPython.core.inputsplitter import ESC_SEQUENCES
20 from IPython.core.inputsplitter import ESC_SEQUENCES
21 from IPython.frontend.qt.rich_text import HtmlExporter
21 from IPython.qt.rich_text import HtmlExporter
22 from IPython.frontend.qt.util import MetaQObjectHasTraits, get_font
22 from IPython.qt.util import MetaQObjectHasTraits, get_font
23 from IPython.utils.text import columnize
23 from IPython.utils.text import columnize
24 from IPython.utils.traitlets import Bool, Enum, Integer, Unicode
24 from IPython.utils.traitlets import Bool, Enum, Integer, Unicode
25 from ansi_code_processor import QtAnsiCodeProcessor
25 from ansi_code_processor import QtAnsiCodeProcessor
@@ -15,7 +15,7 b' from IPython.external.qt import QtCore, QtGui'
15 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
15 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
16 from IPython.core.inputtransformer import classic_prompt
16 from IPython.core.inputtransformer import classic_prompt
17 from IPython.core.oinspect import call_tip
17 from IPython.core.oinspect import call_tip
18 from IPython.frontend.qt.base_frontend_mixin import BaseFrontendMixin
18 from IPython.qt.base_frontend_mixin import BaseFrontendMixin
19 from IPython.utils.traitlets import Bool, Instance, Unicode
19 from IPython.utils.traitlets import Bool, Instance, Unicode
20 from bracket_matcher import BracketMatcher
20 from bracket_matcher import BracketMatcher
21 from call_tip_widget import CallTipWidget
21 from call_tip_widget import CallTipWidget
1 NO CONTENT: file renamed from IPython/frontend/qt/console/history_console_widget.py to IPython/qt/console/history_console_widget.py
NO CONTENT: file renamed from IPython/frontend/qt/console/history_console_widget.py to IPython/qt/console/history_console_widget.py
1 NO CONTENT: file renamed from IPython/frontend/qt/console/ipython_widget.py to IPython/qt/console/ipython_widget.py
NO CONTENT: file renamed from IPython/frontend/qt/console/ipython_widget.py to IPython/qt/console/ipython_widget.py
1 NO CONTENT: file renamed from IPython/frontend/qt/console/kill_ring.py to IPython/qt/console/kill_ring.py
NO CONTENT: file renamed from IPython/frontend/qt/console/kill_ring.py to IPython/qt/console/kill_ring.py
1 NO CONTENT: file renamed from IPython/frontend/qt/console/mainwindow.py to IPython/qt/console/mainwindow.py
NO CONTENT: file renamed from IPython/frontend/qt/console/mainwindow.py to IPython/qt/console/mainwindow.py
1 NO CONTENT: file renamed from IPython/frontend/qt/console/pygments_highlighter.py to IPython/qt/console/pygments_highlighter.py
NO CONTENT: file renamed from IPython/frontend/qt/console/pygments_highlighter.py to IPython/qt/console/pygments_highlighter.py
@@ -57,19 +57,19 b' from IPython.external.qt import QtCore, QtGui'
57 from IPython.config.application import boolean_flag, catch_config_error
57 from IPython.config.application import boolean_flag, catch_config_error
58 from IPython.core.application import BaseIPythonApplication
58 from IPython.core.application import BaseIPythonApplication
59 from IPython.core.profiledir import ProfileDir
59 from IPython.core.profiledir import ProfileDir
60 from IPython.frontend.qt.console.ipython_widget import IPythonWidget
60 from IPython.qt.console.ipython_widget import IPythonWidget
61 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
61 from IPython.qt.console.rich_ipython_widget import RichIPythonWidget
62 from IPython.frontend.qt.console import styles
62 from IPython.qt.console import styles
63 from IPython.frontend.qt.console.mainwindow import MainWindow
63 from IPython.qt.console.mainwindow import MainWindow
64 from IPython.frontend.qt.client import QtKernelClient
64 from IPython.qt.client import QtKernelClient
65 from IPython.frontend.qt.manager import QtKernelManager
65 from IPython.qt.manager import QtKernelManager
66 from IPython.kernel import tunnel_to_kernel, find_connection_file
66 from IPython.kernel import tunnel_to_kernel, find_connection_file
67 from IPython.utils.traitlets import (
67 from IPython.utils.traitlets import (
68 Dict, List, Unicode, CBool, Any
68 Dict, List, Unicode, CBool, Any
69 )
69 )
70 from IPython.kernel.zmq.session import default_secure
70 from IPython.kernel.zmq.session import default_secure
71
71
72 from IPython.frontend.consoleapp import (
72 from IPython.consoleapp import (
73 IPythonConsoleApp, app_aliases, app_flags, flags, aliases
73 IPythonConsoleApp, app_aliases, app_flags, flags, aliases
74 )
74 )
75
75
1 NO CONTENT: file renamed from IPython/frontend/qt/console/resources/icon/IPythonConsole.svg to IPython/qt/console/resources/icon/IPythonConsole.svg
NO CONTENT: file renamed from IPython/frontend/qt/console/resources/icon/IPythonConsole.svg to IPython/qt/console/resources/icon/IPythonConsole.svg
@@ -16,7 +16,7 b' from IPython.external.qt import QtCore, QtGui'
16
16
17 # Local imports
17 # Local imports
18 from IPython.utils.traitlets import Bool
18 from IPython.utils.traitlets import Bool
19 from IPython.frontend.qt.svg import save_svg, svg_to_clipboard, svg_to_image
19 from IPython.qt.svg import save_svg, svg_to_clipboard, svg_to_image
20 from ipython_widget import IPythonWidget
20 from ipython_widget import IPythonWidget
21
21
22
22
1 NO CONTENT: file renamed from IPython/frontend/qt/console/styles.py to IPython/qt/console/styles.py
NO CONTENT: file renamed from IPython/frontend/qt/console/styles.py to IPython/qt/console/styles.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/notebook/__init__.py to IPython/qt/console/tests/__init__.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/notebook/__init__.py to IPython/qt/console/tests/__init__.py
@@ -2,7 +2,7 b''
2 import unittest
2 import unittest
3
3
4 # Local imports
4 # Local imports
5 from IPython.frontend.qt.console.ansi_code_processor import AnsiCodeProcessor
5 from IPython.qt.console.ansi_code_processor import AnsiCodeProcessor
6
6
7
7
8 class TestAnsiCodeProcessor(unittest.TestCase):
8 class TestAnsiCodeProcessor(unittest.TestCase):
@@ -5,7 +5,7 b' import unittest'
5 from pygments.lexers import CLexer, CppLexer, PythonLexer
5 from pygments.lexers import CLexer, CppLexer, PythonLexer
6
6
7 # Local imports
7 # Local imports
8 from IPython.frontend.qt.console.completion_lexer import CompletionLexer
8 from IPython.qt.console.completion_lexer import CompletionLexer
9
9
10
10
11 class TestCompletionLexer(unittest.TestCase):
11 class TestCompletionLexer(unittest.TestCase):
@@ -5,7 +5,7 b' import unittest'
5 from IPython.external.qt import QtCore, QtGui
5 from IPython.external.qt import QtCore, QtGui
6
6
7 # Local imports
7 # Local imports
8 from IPython.frontend.qt.console.console_widget import ConsoleWidget
8 from IPython.qt.console.console_widget import ConsoleWidget
9
9
10
10
11 class TestConsoleWidget(unittest.TestCase):
11 class TestConsoleWidget(unittest.TestCase):
@@ -5,7 +5,7 b' import unittest'
5 from IPython.external.qt import QtCore, QtGui
5 from IPython.external.qt import QtCore, QtGui
6
6
7 # Local imports
7 # Local imports
8 from IPython.frontend.qt.console.kill_ring import KillRing, QtKillRing
8 from IPython.qt.console.kill_ring import KillRing, QtKillRing
9
9
10
10
11 class TestKillRing(unittest.TestCase):
11 class TestKillRing(unittest.TestCase):
1 NO CONTENT: file renamed from IPython/frontend/qt/inprocess.py to IPython/qt/inprocess.py
NO CONTENT: file renamed from IPython/frontend/qt/inprocess.py to IPython/qt/inprocess.py
1 NO CONTENT: file renamed from IPython/frontend/qt/kernel_mixins.py to IPython/qt/kernel_mixins.py
NO CONTENT: file renamed from IPython/frontend/qt/kernel_mixins.py to IPython/qt/kernel_mixins.py
1 NO CONTENT: file renamed from IPython/frontend/qt/manager.py to IPython/qt/manager.py
NO CONTENT: file renamed from IPython/frontend/qt/manager.py to IPython/qt/manager.py
1 NO CONTENT: file renamed from IPython/frontend/qt/rich_text.py to IPython/qt/rich_text.py
NO CONTENT: file renamed from IPython/frontend/qt/rich_text.py to IPython/qt/rich_text.py
1 NO CONTENT: file renamed from IPython/frontend/qt/svg.py to IPython/qt/svg.py
NO CONTENT: file renamed from IPython/frontend/qt/svg.py to IPython/qt/svg.py
1 NO CONTENT: file renamed from IPython/frontend/qt/util.py to IPython/qt/util.py
NO CONTENT: file renamed from IPython/frontend/qt/util.py to IPython/qt/util.py
@@ -2,6 +2,6 b''
2 """Terminal-based IPython entry point.
2 """Terminal-based IPython entry point.
3 """
3 """
4
4
5 from IPython.frontend.terminal.ipapp import launch_new_instance
5 from IPython.terminal.ipapp import launch_new_instance
6
6
7 launch_new_instance()
7 launch_new_instance()
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/services/__init__.py to IPython/terminal/__init__.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/services/__init__.py to IPython/terminal/__init__.py
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/services/clusters/__init__.py to IPython/terminal/console/__init__.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/services/clusters/__init__.py to IPython/terminal/console/__init__.py
@@ -17,7 +17,7 b' import signal'
17 import sys
17 import sys
18 import time
18 import time
19
19
20 from IPython.frontend.terminal.ipapp import TerminalIPythonApp, frontend_flags as term_flags
20 from IPython.terminal.ipapp import TerminalIPythonApp, frontend_flags as term_flags
21
21
22 from IPython.utils.traitlets import (
22 from IPython.utils.traitlets import (
23 Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any
23 Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any
@@ -27,11 +27,11 b' from IPython.utils.warn import warn,error'
27 from IPython.kernel.zmq.kernelapp import IPKernelApp
27 from IPython.kernel.zmq.kernelapp import IPKernelApp
28 from IPython.kernel.zmq.session import Session, default_secure
28 from IPython.kernel.zmq.session import Session, default_secure
29 from IPython.kernel.zmq.zmqshell import ZMQInteractiveShell
29 from IPython.kernel.zmq.zmqshell import ZMQInteractiveShell
30 from IPython.frontend.consoleapp import (
30 from IPython.consoleapp import (
31 IPythonConsoleApp, app_aliases, app_flags, aliases, app_aliases, flags
31 IPythonConsoleApp, app_aliases, app_flags, aliases, app_aliases, flags
32 )
32 )
33
33
34 from IPython.frontend.terminal.console.interactiveshell import ZMQTerminalInteractiveShell
34 from IPython.terminal.console.interactiveshell import ZMQTerminalInteractiveShell
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Globals
37 # Globals
1 NO CONTENT: file renamed from IPython/frontend/terminal/console/completer.py to IPython/terminal/console/completer.py
NO CONTENT: file renamed from IPython/frontend/terminal/console/completer.py to IPython/terminal/console/completer.py
@@ -37,8 +37,8 b' from IPython.utils import io'
37 from IPython.utils.traitlets import List, Enum, Any, Instance, Unicode
37 from IPython.utils.traitlets import List, Enum, Any, Instance, Unicode
38 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
38 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
39
39
40 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
40 from IPython.terminal.interactiveshell import TerminalInteractiveShell
41 from IPython.frontend.terminal.console.completer import ZMQCompleter
41 from IPython.terminal.console.completer import ZMQCompleter
42
42
43
43
44 class ZMQTerminalInteractiveShell(TerminalInteractiveShell):
44 class ZMQTerminalInteractiveShell(TerminalInteractiveShell):
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/services/kernels/__init__.py to IPython/terminal/console/tests/__init__.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/services/kernels/__init__.py to IPython/terminal/console/tests/__init__.py
1 NO CONTENT: file renamed from IPython/frontend/terminal/console/tests/test_console.py to IPython/terminal/console/tests/test_console.py
NO CONTENT: file renamed from IPython/frontend/terminal/console/tests/test_console.py to IPython/terminal/console/tests/test_console.py
@@ -11,8 +11,7 b' import unittest'
11 import base64
11 import base64
12
12
13 from IPython.kernel import KernelClient
13 from IPython.kernel import KernelClient
14 from IPython.frontend.terminal.console.interactiveshell \
14 from IPython.terminal.console.interactiveshell import ZMQTerminalInteractiveShell
15 import ZMQTerminalInteractiveShell
16 from IPython.utils.tempdir import TemporaryDirectory
15 from IPython.utils.tempdir import TemporaryDirectory
17 from IPython.testing.tools import monkeypatch
16 from IPython.testing.tools import monkeypatch
18 from IPython.testing.decorators import skip_without
17 from IPython.testing.decorators import skip_without
1 NO CONTENT: file renamed from IPython/frontend/terminal/console/tests/writetofile.py to IPython/terminal/console/tests/writetofile.py
NO CONTENT: file renamed from IPython/frontend/terminal/console/tests/writetofile.py to IPython/terminal/console/tests/writetofile.py
@@ -36,8 +36,8 b' except:'
36
36
37 from IPython.core import ultratb, compilerop
37 from IPython.core import ultratb, compilerop
38 from IPython.core.magic import Magics, magics_class, line_magic
38 from IPython.core.magic import Magics, magics_class, line_magic
39 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
39 from IPython.terminal.interactiveshell import TerminalInteractiveShell
40 from IPython.frontend.terminal.ipapp import load_default_config
40 from IPython.terminal.ipapp import load_default_config
41
41
42 from IPython.utils.traitlets import Bool, CBool, Unicode
42 from IPython.utils.traitlets import Bool, CBool, Unicode
43 from IPython.utils.io import ask_yes_no
43 from IPython.utils.io import ask_yes_no
1 NO CONTENT: file renamed from IPython/frontend/terminal/interactiveshell.py to IPython/terminal/interactiveshell.py
NO CONTENT: file renamed from IPython/frontend/terminal/interactiveshell.py to IPython/terminal/interactiveshell.py
@@ -47,7 +47,7 b' from IPython.core.magics import ScriptMagics'
47 from IPython.core.shellapp import (
47 from IPython.core.shellapp import (
48 InteractiveShellApp, shell_flags, shell_aliases
48 InteractiveShellApp, shell_flags, shell_aliases
49 )
49 )
50 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
50 from IPython.terminal.interactiveshell import TerminalInteractiveShell
51 from IPython.utils import warn
51 from IPython.utils import warn
52 from IPython.utils.path import get_ipython_dir, check_for_old_config
52 from IPython.utils.path import get_ipython_dir, check_for_old_config
53 from IPython.utils.traitlets import (
53 from IPython.utils.traitlets import (
@@ -223,10 +223,10 b' class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):'
223 ]
223 ]
224
224
225 subcommands = Dict(dict(
225 subcommands = Dict(dict(
226 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
226 qtconsole=('IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
227 """Launch the IPython Qt Console."""
227 """Launch the IPython Qt Console."""
228 ),
228 ),
229 notebook=('IPython.frontend.html.notebook.notebookapp.NotebookApp',
229 notebook=('IPython.html.notebookapp.NotebookApp',
230 """Launch the IPython HTML Notebook Server."""
230 """Launch the IPython HTML Notebook Server."""
231 ),
231 ),
232 profile = ("IPython.core.profileapp.ProfileApp",
232 profile = ("IPython.core.profileapp.ProfileApp",
@@ -235,10 +235,10 b' class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):'
235 kernel = ("IPython.kernel.zmq.kernelapp.IPKernelApp",
235 kernel = ("IPython.kernel.zmq.kernelapp.IPKernelApp",
236 "Start a kernel without an attached frontend."
236 "Start a kernel without an attached frontend."
237 ),
237 ),
238 console=('IPython.frontend.terminal.console.app.ZMQTerminalIPythonApp',
238 console=('IPython.terminal.console.app.ZMQTerminalIPythonApp',
239 """Launch the IPython terminal-based Console."""
239 """Launch the IPython terminal-based Console."""
240 ),
240 ),
241 locate=('IPython.frontend.terminal.ipapp.LocateIPythonApp',
241 locate=('IPython.terminal.ipapp.LocateIPythonApp',
242 LocateIPythonApp.description
242 LocateIPythonApp.description
243 ),
243 ),
244 history=('IPython.core.historyapp.HistoryApp',
244 history=('IPython.core.historyapp.HistoryApp',
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/services/notebooks/__init__.py to IPython/terminal/tests/__init__.py
NO CONTENT: file renamed from IPython/frontend/html/notebook/services/notebooks/__init__.py to IPython/terminal/tests/__init__.py
1 NO CONTENT: file renamed from IPython/frontend/terminal/tests/test_interactivshell.py to IPython/terminal/tests/test_interactivshell.py
NO CONTENT: file renamed from IPython/frontend/terminal/tests/test_interactivshell.py to IPython/terminal/tests/test_interactivshell.py
@@ -128,15 +128,17 b' def make_label_dec(label,ds=None):'
128 --------
128 --------
129
129
130 A simple labeling decorator:
130 A simple labeling decorator:
131 >>> slow = make_label_dec('slow')
132 >>> print slow.__doc__
133 Labels a test as 'slow'.
134
131
132 >>> slow = make_label_dec('slow')
133 >>> slow.__doc__
134 "Labels a test as 'slow'."
135
135 And one that uses multiple labels and a custom docstring:
136 And one that uses multiple labels and a custom docstring:
137
136 >>> rare = make_label_dec(['slow','hard'],
138 >>> rare = make_label_dec(['slow','hard'],
137 ... "Mix labels 'slow' and 'hard' for rare tests.")
139 ... "Mix labels 'slow' and 'hard' for rare tests.")
138 >>> print rare.__doc__
140 >>> rare.__doc__
139 Mix labels 'slow' and 'hard' for rare tests.
141 "Mix labels 'slow' and 'hard' for rare tests."
140
142
141 Now, let's test using this one:
143 Now, let's test using this one:
142 >>> @rare
144 >>> @rare
@@ -30,7 +30,7 b' from . import tools'
30 from IPython.core import page
30 from IPython.core import page
31 from IPython.utils import io
31 from IPython.utils import io
32 from IPython.utils import py3compat
32 from IPython.utils import py3compat
33 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
33 from IPython.terminal.interactiveshell import TerminalInteractiveShell
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Functions
36 # Functions
@@ -230,8 +230,8 b' def make_exclude():'
230 # files for web serving. Occasionally projects may put a .py
230 # files for web serving. Occasionally projects may put a .py
231 # file in there (MathJax ships a conf.py), so we might as
231 # file in there (MathJax ships a conf.py), so we might as
232 # well play it safe and skip the whole thing.
232 # well play it safe and skip the whole thing.
233 ipjoin('frontend', 'html', 'notebook', 'static'),
233 ipjoin('html', 'static'),
234 ipjoin('frontend', 'html', 'notebook', 'fabfile'),
234 ipjoin('html', 'fabfile'),
235 ]
235 ]
236 if not have['sqlite3']:
236 if not have['sqlite3']:
237 exclusions.append(ipjoin('core', 'tests', 'test_history'))
237 exclusions.append(ipjoin('core', 'tests', 'test_history'))
@@ -261,18 +261,18 b' def make_exclude():'
261 if not have['pexpect']:
261 if not have['pexpect']:
262 exclusions.extend([ipjoin('lib', 'irunner'),
262 exclusions.extend([ipjoin('lib', 'irunner'),
263 ipjoin('lib', 'tests', 'test_irunner'),
263 ipjoin('lib', 'tests', 'test_irunner'),
264 ipjoin('frontend', 'terminal', 'console'),
264 ipjoin('terminal', 'console'),
265 ])
265 ])
266
266
267 if not have['zmq']:
267 if not have['zmq']:
268 exclusions.append(ipjoin('kernel'))
268 exclusions.append(ipjoin('kernel'))
269 exclusions.append(ipjoin('frontend', 'qt'))
269 exclusions.append(ipjoin('qt'))
270 exclusions.append(ipjoin('frontend', 'html'))
270 exclusions.append(ipjoin('html'))
271 exclusions.append(ipjoin('frontend', 'consoleapp.py'))
271 exclusions.append(ipjoin('consoleapp.py'))
272 exclusions.append(ipjoin('frontend', 'terminal', 'console'))
272 exclusions.append(ipjoin('terminal', 'console'))
273 exclusions.append(ipjoin('parallel'))
273 exclusions.append(ipjoin('parallel'))
274 elif not have['qt'] or not have['pygments']:
274 elif not have['qt'] or not have['pygments']:
275 exclusions.append(ipjoin('frontend', 'qt'))
275 exclusions.append(ipjoin('qt'))
276
276
277 if not have['pymongo']:
277 if not have['pymongo']:
278 exclusions.append(ipjoin('parallel', 'controller', 'mongodb'))
278 exclusions.append(ipjoin('parallel', 'controller', 'mongodb'))
@@ -293,17 +293,17 b' def make_exclude():'
293 exclusions.extend([ipjoin('extensions', 'tests', 'test_octavemagic')])
293 exclusions.extend([ipjoin('extensions', 'tests', 'test_octavemagic')])
294
294
295 if not have['tornado']:
295 if not have['tornado']:
296 exclusions.append(ipjoin('frontend', 'html'))
296 exclusions.append(ipjoin('html'))
297
297
298 if not have['jinja2']:
298 if not have['jinja2']:
299 exclusions.append(ipjoin('frontend', 'html', 'notebook', 'notebookapp'))
299 exclusions.append(ipjoin('html', 'notebookapp'))
300
300
301 if not have['rpy2'] or not have['numpy']:
301 if not have['rpy2'] or not have['numpy']:
302 exclusions.append(ipjoin('extensions', 'rmagic'))
302 exclusions.append(ipjoin('extensions', 'rmagic'))
303 exclusions.append(ipjoin('extensions', 'tests', 'test_rmagic'))
303 exclusions.append(ipjoin('extensions', 'tests', 'test_rmagic'))
304
304
305 if not have['azure']:
305 if not have['azure']:
306 exclusions.append(ipjoin('frontend', 'html', 'notebook', 'services', 'notebooks', 'azurenbmanager'))
306 exclusions.append(ipjoin('html', 'services', 'notebooks', 'azurenbmanager'))
307
307
308 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
308 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
309 if sys.platform == 'win32':
309 if sys.platform == 'win32':
@@ -429,14 +429,21 b' class IPTester(object):'
429 # The process did not die...
429 # The process did not die...
430 print('... failed. Manual cleanup may be required.')
430 print('... failed. Manual cleanup may be required.')
431
431
432
432 def make_runners(inc_slow=False):
433 def make_runners(inc_slow=False):
433 """Define the top-level packages that need to be tested.
434 """Define the top-level packages that need to be tested.
434 """
435 """
435
436
436 # Packages to be tested via nose, that only depend on the stdlib
437 # Packages to be tested via nose, that only depend on the stdlib
437 nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib',
438 nose_pkg_names = ['config', 'core', 'extensions', 'lib', 'terminal',
438 'testing', 'utils', 'nbformat' ]
439 'testing', 'utils', 'nbformat' ]
439
440
441 if have['qt']:
442 nose_pkg_names.append('qt')
443
444 if have['tornado']:
445 nose_pkg_names.append('html')
446
440 if have['zmq']:
447 if have['zmq']:
441 nose_pkg_names.append('kernel')
448 nose_pkg_names.append('kernel')
442 nose_pkg_names.append('kernel.inprocess')
449 nose_pkg_names.append('kernel.inprocess')
@@ -19,29 +19,32 b' Authors:'
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 def import_item(name):
21 def import_item(name):
22 """Import and return bar given the string foo.bar."""
22 """Import and return ``bar`` given the string ``foo.bar``.
23 package = '.'.join(name.split('.')[0:-1])
23
24 obj = name.split('.')[-1]
24 Calling ``bar = import_item("foo.bar")`` is the functional equivalent of
25
25 executing the code ``from foo import bar``.
26 # Note: the original code for this was the following. We've left it
26
27 # visible for now in case the new implementation shows any problems down
27 Parameters
28 # the road, to make it easier on anyone looking for a problem. This code
28 ----------
29 # should be removed once we're comfortable we didn't break anything.
29 name : string
30 The fully qualified name of the module/package being imported.
31
32 Returns
33 -------
34 mod : module object
35 The module that was imported.
36 """
30
37
31 ## execString = 'from %s import %s' % (package, obj)
38 parts = name.rsplit('.', 1)
32 ## try:
39 if len(parts) == 2:
33 ## exec execString
40 # called with 'foo.bar....'
34 ## except SyntaxError:
41 package, obj = parts
35 ## raise ImportError("Invalid class specification: %s" % name)
42 module = __import__(package, fromlist=[obj])
36 ## exec 'temp = %s' % obj
37 ## return temp
38
39 if package:
40 module = __import__(package,fromlist=[obj])
41 try:
43 try:
42 pak = module.__dict__[obj]
44 pak = module.__dict__[obj]
43 except KeyError:
45 except KeyError:
44 raise ImportError('No module named %s' % obj)
46 raise ImportError('No module named %s' % obj)
45 return pak
47 return pak
46 else:
48 else:
47 return __import__(obj)
49 # called with un-dotted string
50 return __import__(parts[0])
@@ -51,7 +51,7 b' def find_cmd(cmd):'
51
51
52 from IPython.utils.path import get_ipython_module_path
52 from IPython.utils.path import get_ipython_module_path
53 from IPython.utils.process import pycmd2argv
53 from IPython.utils.process import pycmd2argv
54 argv = pycmd2argv(get_ipython_module_path('IPython.frontend.terminal.ipapp'))
54 argv = pycmd2argv(get_ipython_module_path('IPython.terminal.ipapp'))
55
55
56 Parameters
56 Parameters
57 ----------
57 ----------
@@ -33,7 +33,7 b' def ipython_parent():'
33 def ipython_submodules(root):
33 def ipython_submodules(root):
34 """return IPython submodules relative to root"""
34 """return IPython submodules relative to root"""
35 return [
35 return [
36 pjoin(root, 'IPython', 'frontend', 'html', 'notebook', 'static', 'components'),
36 pjoin(root, 'IPython', 'html', 'static', 'components'),
37 ]
37 ]
38
38
39 def is_repo(d):
39 def is_repo(d):
@@ -404,7 +404,7 b' def test_get_ipython_package_dir():'
404
404
405
405
406 def test_get_ipython_module_path():
406 def test_get_ipython_module_path():
407 ipapp_path = path.get_ipython_module_path('IPython.frontend.terminal.ipapp')
407 ipapp_path = path.get_ipython_module_path('IPython.terminal.ipapp')
408 nt.assert_true(os.path.isfile(ipapp_path))
408 nt.assert_true(os.path.isfile(ipapp_path))
409
409
410
410
@@ -11,11 +11,11 b' graft scripts'
11 graft IPython
11 graft IPython
12 prune IPython/deathrow
12 prune IPython/deathrow
13 prune IPython/external/js
13 prune IPython/external/js
14 prune IPython/frontend/html/notebook/static/mathjax
14 prune IPython/html/static/mathjax
15
15
16 # Include some specific files and data resources we need
16 # Include some specific files and data resources we need
17 include IPython/.git_commit_info.ini
17 include IPython/.git_commit_info.ini
18 include IPython/frontend/qt/console/resources/icon/IPythonConsole.svg
18 include IPython/qt/console/resources/icon/IPythonConsole.svg
19
19
20 # Documentation
20 # Documentation
21 graft docs
21 graft docs
@@ -413,7 +413,7 b' store the notebooks in a different format. Currently, we ship a'
413 storage. This can be used by adding the following lines to your
413 storage. This can be used by adding the following lines to your
414 ``ipython_notebook_config.py`` file::
414 ``ipython_notebook_config.py`` file::
415
415
416 c.NotebookApp.notebook_manager_class = 'IPython.frontend.html.notebook.azurenbmanager.AzureNotebookManager'
416 c.NotebookApp.notebook_manager_class = 'IPython.html.services.notebooks.azurenbmanager.AzureNotebookManager'
417 c.AzureNotebookManager.account_name = u'paste_your_account_name_here'
417 c.AzureNotebookManager.account_name = u'paste_your_account_name_here'
418 c.AzureNotebookManager.account_key = u'paste_your_account_key_here'
418 c.AzureNotebookManager.account_key = u'paste_your_account_key_here'
419 c.AzureNotebookManager.container = u'notebooks'
419 c.AzureNotebookManager.container = u'notebooks'
@@ -134,7 +134,7 b' def find_package_data():'
134
134
135 # walk notebook resources:
135 # walk notebook resources:
136 cwd = os.getcwd()
136 cwd = os.getcwd()
137 os.chdir(os.path.join('IPython', 'frontend', 'html', 'notebook'))
137 os.chdir(os.path.join('IPython', 'html'))
138 static_walk = list(os.walk('static'))
138 static_walk = list(os.walk('static'))
139 os.chdir(cwd)
139 os.chdir(cwd)
140 static_data = []
140 static_data = []
@@ -148,8 +148,8 b' def find_package_data():'
148 'IPython.config.profile' : ['README*', '*/*.py'],
148 'IPython.config.profile' : ['README*', '*/*.py'],
149 'IPython.testing' : ['*.txt'],
149 'IPython.testing' : ['*.txt'],
150 'IPython.testing.plugin' : ['*.txt'],
150 'IPython.testing.plugin' : ['*.txt'],
151 'IPython.frontend.html.notebook' : ['templates/*'] + static_data,
151 'IPython.html' : ['templates/*'] + static_data,
152 'IPython.frontend.qt.console' : ['resources/icon/*.svg'],
152 'IPython.qt.console' : ['resources/icon/*.svg'],
153 }
153 }
154 return package_data
154 return package_data
155
155
@@ -312,7 +312,7 b" def find_scripts(entry_points=False, suffix=''):"
312 """
312 """
313 if entry_points:
313 if entry_points:
314 console_scripts = [s % suffix for s in [
314 console_scripts = [s % suffix for s in [
315 'ipython%s = IPython.frontend.terminal.ipapp:launch_new_instance',
315 'ipython%s = IPython.terminal.ipapp:launch_new_instance',
316 'pycolor%s = IPython.utils.PyColorize:main',
316 'pycolor%s = IPython.utils.PyColorize:main',
317 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
317 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
318 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
318 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
This diff has been collapsed as it changes many lines, (665 lines changed) Show them Hide them
@@ -1,665 +0,0 b''
1 # -*- coding: utf-8 -*-
2 """Improved replacement for the Gnuplot.Gnuplot class.
3
4 This module imports Gnuplot and replaces some of its functionality with
5 improved versions. They add better handling of arrays for plotting and more
6 convenient PostScript generation, plus some fixes for hardcopy().
7
8 It also adds a convenient plot2 method for plotting dictionaries and
9 lists/tuples of arrays.
10
11 This module is meant to be used as a drop-in replacement to the original
12 Gnuplot, so it should be safe to do:
13
14 import IPython.Gnuplot2 as Gnuplot
15 """
16
17 import cStringIO
18 import os
19 import string
20 import sys
21 import tempfile
22 import time
23 import types
24
25 import Gnuplot as Gnuplot_ori
26 import Numeric
27
28 from IPython.utils.genutils import popkey,xsys
29
30 # needed by hardcopy():
31 gp = Gnuplot_ori.gp
32
33 # Patch for Gnuplot.py 1.6 compatibility.
34 # Thanks to Hayden Callow <h.callow@elec.canterbury.ac.nz>
35 try:
36 OptionException = Gnuplot_ori.PlotItems.OptionException
37 except AttributeError:
38 OptionException = Gnuplot_ori.Errors.OptionError
39
40 # exhibit a similar interface to Gnuplot so it can be somewhat drop-in
41 Data = Gnuplot_ori.Data
42 Func = Gnuplot_ori.Func
43 GridData = Gnuplot_ori.GridData
44 PlotItem = Gnuplot_ori.PlotItem
45 PlotItems = Gnuplot_ori.PlotItems
46
47 # Modify some of Gnuplot's functions with improved versions (or bugfixed, in
48 # hardcopy's case). In order to preserve the docstrings at runtime, I've
49 # copied them from the original code.
50
51 # After some significant changes in v 1.7 of Gnuplot.py, we need to do a bit
52 # of version checking.
53
54 if Gnuplot_ori.__version__ <= '1.6':
55 _BaseFileItem = PlotItems.File
56 _BaseTempFileItem = PlotItems.TempFile
57
58 # Fix the File class to add the 'index' option for Gnuplot versions < 1.7
59 class File(_BaseFileItem):
60
61 _option_list = _BaseFileItem._option_list.copy()
62 _option_list.update({
63 'index' : lambda self, index: self.set_option_index(index),
64 })
65
66 # A new initializer is needed b/c we want to add a modified
67 # _option_sequence list which includes 'index' in the right place.
68 def __init__(self,*args,**kw):
69 self._option_sequence = ['binary', 'index', 'using', 'smooth', 'axes',
70 'title', 'with']
71
72 _BaseFileItem.__init__(self,*args,**kw)
73
74 # Let's fix the constructor docstring
75 __newdoc = \
76 """Additional Keyword arguments added by IPython:
77
78 'index=<int>' -- similar to the `index` keyword in Gnuplot.
79 This allows only some of the datasets in a file to be
80 plotted. Datasets within a file are assumed to be separated
81 by _pairs_ of blank lines, and the first one is numbered as
82 0 (similar to C/Python usage)."""
83 __init__.__doc__ = PlotItems.File.__init__.__doc__ + __newdoc
84
85 def set_option_index(self, index):
86 if index is None:
87 self.clear_option('index')
88 elif type(index) in [type(''), type(1)]:
89 self._options['index'] = (index, 'index %s' % index)
90 elif type(index) is type(()):
91 self._options['index'] = (index,'index %s' %
92 string.join(map(repr, index), ':'))
93 else:
94 raise OptionException('index=%s' % (index,))
95
96 # We need a FileClass with a different name from 'File', which is a
97 # factory function in 1.7, so that our String class can subclass FileClass
98 # in any version.
99 _FileClass = File
100
101 elif Gnuplot_ori.__version__ =='1.7':
102 _FileClass = _BaseFileItem = PlotItems._FileItem
103 _BaseTempFileItem = PlotItems._TempFileItem
104 File = PlotItems.File
105
106 else: # changes in the newer version (svn as of March'06)
107 _FileClass = _BaseFileItem = PlotItems._FileItem
108 _BaseTempFileItem = PlotItems._NewFileItem
109 File = PlotItems.File
110
111
112 # Now, we can add our generic code which is version independent
113
114 # First some useful utilities
115 def eps_fix_bbox(fname):
116 """Fix the bounding box of an eps file by running ps2eps on it.
117
118 If its name ends in .eps, the original file is removed.
119
120 This is particularly useful for plots made by Gnuplot with square aspect
121 ratio: there is a bug in Gnuplot which makes it generate a bounding box
122 which is far wider than the actual plot.
123
124 This function assumes that ps2eps is installed in your system."""
125
126 # note: ps2ps and eps2eps do NOT work, ONLY ps2eps works correctly. The
127 # others make output with bitmapped fonts, which looks horrible.
128 print 'Fixing eps file: <%s>' % fname
129 xsys('ps2eps -f -q -l %s' % fname)
130 if fname.endswith('.eps'):
131 os.rename(fname+'.eps',fname)
132
133 def is_list1d(x,containers = [types.ListType,types.TupleType]):
134 """Returns true if x appears to be a 1d list/tuple/array.
135
136 The heuristics are: identify Numeric arrays, or lists/tuples whose first
137 element is not itself a list/tuple. This way zipped lists should work like
138 the original Gnuplot. There's no inexpensive way to know if a list doesn't
139 have a composite object after its first element, so that kind of input
140 will produce an error. But it should work well in most cases.
141 """
142 x_type = type(x)
143
144 return x_type == Numeric.ArrayType and len(x.shape)==1 or \
145 (x_type in containers and
146 type(x[0]) not in containers + [Numeric.ArrayType])
147
148 def zip_items(items,titles=None):
149 """zip together neighboring 1-d arrays, and zip standalone ones
150 with their index. Leave other plot items alone."""
151
152 class StandaloneItem(Exception): pass
153
154 def get_titles(titles):
155 """Return the next title and the input titles array.
156
157 The input array may be changed to None when no titles are left to
158 prevent extra unnecessary calls to this function."""
159
160 try:
161 title = titles[tit_ct[0]] # tit_ct[0] is in zip_items'scope
162 except IndexError:
163 titles = None # so we don't enter again
164 title = None
165 else:
166 tit_ct[0] += 1
167 return title,titles
168
169 new_items = []
170
171 if titles:
172 # Initialize counter. It was put in a list as a hack to allow the
173 # nested get_titles to modify it without raising a NameError.
174 tit_ct = [0]
175
176 n = 0 # this loop needs to be done by hand
177 while n < len(items):
178 item = items[n]
179 try:
180 if is_list1d(item):
181 if n==len(items)-1: # last in list
182 raise StandaloneItem
183 else: # check the next item and zip together if needed
184 next_item = items[n+1]
185 if next_item is None:
186 n += 1
187 raise StandaloneItem
188 elif is_list1d(next_item):
189 # this would be best done with an iterator
190 if titles:
191 title,titles = get_titles(titles)
192 else:
193 title = None
194 new_items.append(Data(zip(item,next_item),
195 title=title))
196 n += 1 # avoid double-inclusion of next item
197 else: # can't zip with next, zip with own index list
198 raise StandaloneItem
199 else: # not 1-d array
200 new_items.append(item)
201 except StandaloneItem:
202 if titles:
203 title,titles = get_titles(titles)
204 else:
205 title = None
206 new_items.append(Data(zip(range(len(item)),item),title=title))
207 except AttributeError:
208 new_items.append(item)
209 n+=1
210
211 return new_items
212
213 # And some classes with enhanced functionality.
214 class String(_FileClass):
215 """Make a PlotItem from data in a string with the same format as a File.
216
217 This allows writing data directly inside python scripts using the exact
218 same format and manipulation options which would be used for external
219 files."""
220
221 def __init__(self, data_str, **keyw):
222 """Construct a String object.
223
224 <data_str> is a string formatted exactly like a valid Gnuplot data
225 file would be. All options from the File constructor are valid here.
226
227 Warning: when used for interactive plotting in scripts which exit
228 immediately, you may get an error because the temporary file used to
229 hold the string data was deleted before Gnuplot had a chance to see
230 it. You can work around this problem by putting a raw_input() call at
231 the end of the script.
232
233 This problem does not appear when generating PostScript output, only
234 with Gnuplot windows."""
235
236 self.tmpfile = _BaseTempFileItem()
237 tmpfile = file(self.tmpfile.filename,'w')
238 tmpfile.write(data_str)
239 _BaseFileItem.__init__(self,self.tmpfile,**keyw)
240
241
242 class Gnuplot(Gnuplot_ori.Gnuplot):
243 """Improved Gnuplot class.
244
245 Enhancements: better plot,replot and hardcopy methods. New methods for
246 quick range setting.
247 """
248
249 def xrange(self,min='*',max='*'):
250 """Set xrange. If min/max is omitted, it is set to '*' (auto).
251
252 Note that this is different from the regular Gnuplot behavior, where
253 an unspecified limit means no change. Here any unspecified limit is
254 set to autoscaling, allowing these functions to be used for full
255 autoscaling when called with no arguments.
256
257 To preserve one limit's current value while changing the other, an
258 explicit '' argument must be given as the limit to be kept.
259
260 Similar functions exist for [y{2}z{2}rtuv]range."""
261
262 self('set xrange [%s:%s]' % (min,max))
263
264 def yrange(self,min='*',max='*'):
265 self('set yrange [%s:%s]' % (min,max))
266
267 def zrange(self,min='*',max='*'):
268 self('set zrange [%s:%s]' % (min,max))
269
270 def x2range(self,min='*',max='*'):
271 self('set xrange [%s:%s]' % (min,max))
272
273 def y2range(self,min='*',max='*'):
274 self('set yrange [%s:%s]' % (min,max))
275
276 def z2range(self,min='*',max='*'):
277 self('set zrange [%s:%s]' % (min,max))
278
279 def rrange(self,min='*',max='*'):
280 self('set rrange [%s:%s]' % (min,max))
281
282 def trange(self,min='*',max='*'):
283 self('set trange [%s:%s]' % (min,max))
284
285 def urange(self,min='*',max='*'):
286 self('set urange [%s:%s]' % (min,max))
287
288 def vrange(self,min='*',max='*'):
289 self('set vrange [%s:%s]' % (min,max))
290
291 def set_ps(self,option):
292 """Set an option for the PostScript terminal and reset default term."""
293
294 self('set terminal postscript %s ' % option)
295 self('set terminal %s' % gp.GnuplotOpts.default_term)
296
297 def __plot_ps(self, plot_method,*items, **keyw):
298 """Wrapper for plot/splot/replot, with processing of hardcopy options.
299
300 For internal use only."""
301
302 # Filter out PostScript options which will crash the normal plot/replot
303 psargs = {'filename':None,
304 'mode':None,
305 'eps':None,
306 'enhanced':None,
307 'color':None,
308 'solid':None,
309 'duplexing':None,
310 'fontname':None,
311 'fontsize':None,
312 'debug':0 }
313
314 for k in psargs.keys():
315 if keyw.has_key(k):
316 psargs[k] = keyw[k]
317 del keyw[k]
318
319 # Filter out other options the original plot doesn't know
320 hardcopy = popkey(keyw,'hardcopy',psargs['filename'] is not None)
321 titles = popkey(keyw,'titles',0)
322
323 # the filename keyword should control hardcopy generation, this is an
324 # override switch only which needs to be explicitly set to zero
325 if hardcopy:
326 if psargs['filename'] is None:
327 raise ValueError, \
328 'If you request hardcopy, you must give a filename.'
329
330 # set null output so nothing goes to screen. hardcopy() restores output
331 self('set term dumb')
332 # I don't know how to prevent screen output in Windows
333 if os.name == 'posix':
334 self('set output "/dev/null"')
335
336 new_items = zip_items(items,titles)
337 # plot_method is either plot or replot from the original Gnuplot class:
338 plot_method(self,*new_items,**keyw)
339
340 # Do hardcopy if requested
341 if hardcopy:
342 if psargs['filename'].endswith('.eps'):
343 psargs['eps'] = 1
344 self.hardcopy(**psargs)
345
346 def plot(self, *items, **keyw):
347 """Draw a new plot.
348
349 Clear the current plot and create a new 2-d plot containing
350 the specified items. Each arguments should be of the
351 following types:
352
353 'PlotItem' (e.g., 'Data', 'File', 'Func') -- This is the most
354 flexible way to call plot because the PlotItems can
355 contain suboptions. Moreover, PlotItems can be saved to
356 variables so that their lifetime is longer than one plot
357 command; thus they can be replotted with minimal overhead.
358
359 'string' (e.g., 'sin(x)') -- The string is interpreted as
360 'Func(string)' (a function that is computed by gnuplot).
361
362 Anything else -- The object, which should be convertible to an
363 array, is passed to the 'Data' constructor, and thus
364 plotted as data. If the conversion fails, an exception is
365 raised.
366
367
368 This is a modified version of plot(). Compared to the original in
369 Gnuplot.py, this version has several enhancements, listed below.
370
371
372 Modifications to the input arguments
373 ------------------------------------
374
375 (1-d array means Numeric array, list or tuple):
376
377 (i) Any 1-d array which is NOT followed by another 1-d array, is
378 automatically zipped with range(len(array_1d)). Typing g.plot(y) will
379 plot y against its indices.
380
381 (ii) If two 1-d arrays are contiguous in the argument list, they are
382 automatically zipped together. So g.plot(x,y) plots y vs. x, and
383 g.plot(x1,y1,x2,y2) plots y1 vs. x1 and y2 vs. x2.
384
385 (iii) Any 1-d array which is followed by None is automatically zipped
386 with range(len(array_1d)). In this form, typing g.plot(y1,None,y2)
387 will plot both y1 and y2 against their respective indices (and NOT
388 versus one another). The None prevents zipping y1 and y2 together, and
389 since y2 is unpaired it is automatically zipped to its indices by (i)
390
391 (iv) Any other arguments which don't match these cases are left alone and
392 passed to the code below.
393
394 For lists or tuples, the heuristics used to determine whether they are
395 in fact 1-d is fairly simplistic: their first element is checked, and
396 if it is not a list or tuple itself, it is assumed that the whole
397 object is one-dimensional.
398
399 An additional optional keyword 'titles' has been added: it must be a
400 list of strings to be used as labels for the individual plots which
401 are NOT PlotItem objects (since those objects carry their own labels
402 within).
403
404
405 PostScript generation
406 ---------------------
407
408 This version of plot() also handles automatically the production of
409 PostScript output. The main options are (given as keyword arguments):
410
411 - filename: a string, typically ending in .eps. If given, the plot is
412 sent to this file in PostScript format.
413
414 - hardcopy: this can be set to 0 to override 'filename'. It does not
415 need to be given to produce PostScript, its purpose is to allow
416 switching PostScript output off globally in scripts without having to
417 manually change 'filename' values in multiple calls.
418
419 All other keywords accepted by Gnuplot.hardcopy() are transparently
420 passed, and safely ignored if output is sent to the screen instead of
421 PostScript.
422
423 For example:
424
425 In [1]: x=frange(0,2*pi,npts=100)
426
427 Generate a plot in file 'sin.eps':
428
429 In [2]: plot(x,sin(x),filename = 'sin.eps')
430
431 Plot to screen instead, without having to change the filename:
432
433 In [3]: plot(x,sin(x),filename = 'sin.eps',hardcopy=0)
434
435 Pass the 'color=0' option to hardcopy for monochrome output:
436
437 In [4]: plot(x,sin(x),filename = 'sin.eps',color=0)
438
439 PostScript generation through plot() is useful mainly for scripting
440 uses where you are not interested in interactive plotting. For
441 interactive use, the hardcopy() function is typically more convenient:
442
443 In [5]: plot(x,sin(x))
444
445 In [6]: hardcopy('sin.eps') """
446
447 self.__plot_ps(Gnuplot_ori.Gnuplot.plot,*items,**keyw)
448
449 def plot2(self,arg,**kw):
450 """Plot the entries of a dictionary or a list/tuple of arrays.
451
452 This simple utility calls plot() with a list of Gnuplot.Data objects
453 constructed either from the values of the input dictionary, or the entries
454 in it if it is a tuple or list. Each item gets labeled with the key/index
455 in the Gnuplot legend.
456
457 Each item is plotted by zipping it with a list of its indices.
458
459 Any keywords are passed directly to plot()."""
460
461 if hasattr(arg,'keys'):
462 keys = arg.keys()
463 keys.sort()
464 else:
465 keys = range(len(arg))
466
467 pitems = [Data(zip(range(len(arg[k])),arg[k]),title=`k`) for k in keys]
468 self.plot(*pitems,**kw)
469
470 def splot(self, *items, **keyw):
471 """Draw a new three-dimensional plot.
472
473 Clear the current plot and create a new 3-d plot containing
474 the specified items. Arguments can be of the following types:
475
476 'PlotItem' (e.g., 'Data', 'File', 'Func', 'GridData' ) -- This
477 is the most flexible way to call plot because the
478 PlotItems can contain suboptions. Moreover, PlotItems can
479 be saved to variables so that their lifetime is longer
480 than one plot command--thus they can be replotted with
481 minimal overhead.
482
483 'string' (e.g., 'sin(x*y)') -- The string is interpreted as a
484 'Func()' (a function that is computed by gnuplot).
485
486 Anything else -- The object is converted to a Data() item, and
487 thus plotted as data. Note that each data point should
488 normally have at least three values associated with it
489 (i.e., x, y, and z). If the conversion fails, an
490 exception is raised.
491
492 This is a modified version of splot(). Compared to the original in
493 Gnuplot.py, this version has several enhancements, listed in the
494 plot() documentation.
495 """
496
497 self.__plot_ps(Gnuplot_ori.Gnuplot.splot,*items,**keyw)
498
499 def replot(self, *items, **keyw):
500 """Replot the data, possibly adding new 'PlotItem's.
501
502 Replot the existing graph, using the items in the current
503 itemlist. If arguments are specified, they are interpreted as
504 additional items to be plotted alongside the existing items on
505 the same graph. See 'plot' for details.
506
507 If you want to replot to a postscript file, you MUST give the
508 'filename' keyword argument in each call to replot. The Gnuplot python
509 interface has no way of knowing that your previous call to
510 Gnuplot.plot() was meant for PostScript output."""
511
512 self.__plot_ps(Gnuplot_ori.Gnuplot.replot,*items,**keyw)
513
514 # The original hardcopy has a bug. See fix at the end. The rest of the code
515 # was lifted verbatim from the original, so that people using IPython get the
516 # benefits without having to manually patch Gnuplot.py
517 def hardcopy(self, filename=None,
518 mode=None,
519 eps=None,
520 enhanced=None,
521 color=None,
522 solid=None,
523 duplexing=None,
524 fontname=None,
525 fontsize=None,
526 debug = 0,
527 ):
528 """Create a hardcopy of the current plot.
529
530 Create a postscript hardcopy of the current plot to the
531 default printer (if configured) or to the specified filename.
532
533 Note that gnuplot remembers the postscript suboptions across
534 terminal changes. Therefore if you set, for example, color=1
535 for one hardcopy then the next hardcopy will also be color
536 unless you explicitly choose color=0. Alternately you can
537 force all of the options to their defaults by setting
538 mode='default'. I consider this to be a bug in gnuplot.
539
540 Keyword arguments:
541
542 'filename=<string>' -- if a filename is specified, save the
543 output in that file; otherwise print it immediately
544 using the 'default_lpr' configuration option. If the
545 filename ends in '.eps', EPS mode is automatically
546 selected (like manually specifying eps=1 or mode='eps').
547
548 'mode=<string>' -- set the postscript submode ('landscape',
549 'portrait', 'eps', or 'default'). The default is
550 to leave this option unspecified.
551
552 'eps=<bool>' -- shorthand for 'mode="eps"'; asks gnuplot to
553 generate encapsulated postscript.
554
555 'enhanced=<bool>' -- if set (the default), then generate
556 enhanced postscript, which allows extra features like
557 font-switching, superscripts, and subscripts in axis
558 labels. (Some old gnuplot versions do not support
559 enhanced postscript; if this is the case set
560 gp.GnuplotOpts.prefer_enhanced_postscript=None.)
561
562 'color=<bool>' -- if set, create a plot with color. Default
563 is to leave this option unchanged.
564
565 'solid=<bool>' -- if set, force lines to be solid (i.e., not
566 dashed).
567
568 'duplexing=<string>' -- set duplexing option ('defaultplex',
569 'simplex', or 'duplex'). Only request double-sided
570 printing if your printer can handle it. Actually this
571 option is probably meaningless since hardcopy() can only
572 print a single plot at a time.
573
574 'fontname=<string>' -- set the default font to <string>,
575 which must be a valid postscript font. The default is
576 to leave this option unspecified.
577
578 'fontsize=<double>' -- set the default font size, in
579 postscript points.
580
581 'debug=<bool>' -- print extra debugging information (useful if
582 your PostScript files are misteriously not being created).
583 """
584
585 if filename is None:
586 assert gp.GnuplotOpts.default_lpr is not None, \
587 OptionException('default_lpr is not set, so you can only '
588 'print to a file.')
589 filename = gp.GnuplotOpts.default_lpr
590 lpr_output = 1
591 else:
592 if filename.endswith('.eps'):
593 eps = 1
594 lpr_output = 0
595
596 # Be careful processing the options. If the user didn't
597 # request an option explicitly, do not specify it on the 'set
598 # terminal' line (don't even specify the default value for the
599 # option). This is to avoid confusing older versions of
600 # gnuplot that do not support all of these options. The
601 # exception is 'enhanced', which is just too useful to have to
602 # specify each time!
603
604 setterm = ['set', 'terminal', 'postscript']
605 if eps:
606 assert mode is None or mode=='eps', \
607 OptionException('eps option and mode are incompatible')
608 setterm.append('eps')
609 else:
610 if mode is not None:
611 assert mode in ['landscape', 'portrait', 'eps', 'default'], \
612 OptionException('illegal mode "%s"' % mode)
613 setterm.append(mode)
614 if enhanced is None:
615 enhanced = gp.GnuplotOpts.prefer_enhanced_postscript
616 if enhanced is not None:
617 if enhanced: setterm.append('enhanced')
618 else: setterm.append('noenhanced')
619 if color is not None:
620 if color: setterm.append('color')
621 else: setterm.append('monochrome')
622 if solid is not None:
623 if solid: setterm.append('solid')
624 else: setterm.append('dashed')
625 if duplexing is not None:
626 assert duplexing in ['defaultplex', 'simplex', 'duplex'], \
627 OptionException('illegal duplexing mode "%s"' % duplexing)
628 setterm.append(duplexing)
629 if fontname is not None:
630 setterm.append('"%s"' % fontname)
631 if fontsize is not None:
632 setterm.append('%s' % fontsize)
633
634 self(string.join(setterm))
635 self.set_string('output', filename)
636 # replot the current figure (to the printer):
637 self.refresh()
638
639 # fperez. Ugly kludge: often for some reason the file is NOT created
640 # and we must reissue the creation commands. I have no idea why!
641 if not lpr_output:
642 #print 'Hardcopy <%s>' % filename # dbg
643 maxtries = 20
644 delay = 0.1 # delay (in seconds) between print attempts
645 for i in range(maxtries):
646 time.sleep(0.05) # safety, very small delay
647 if os.path.isfile(filename):
648 if debug:
649 print 'Hardcopy to file <%s> success at attempt #%s.' \
650 % (filename,i+1)
651 break
652 time.sleep(delay)
653 # try again, issue all commands just in case
654 self(string.join(setterm))
655 self.set_string('output', filename)
656 self.refresh()
657 if not os.path.isfile(filename):
658 print >> sys.stderr,'ERROR: Tried %s times and failed to '\
659 'create hardcopy file `%s`' % (maxtries,filename)
660
661 # reset the terminal to its `default' setting:
662 self('set terminal %s' % gp.GnuplotOpts.default_term)
663 self.set_string('output')
664
665 #********************** End of file <Gnuplot2.py> ************************
@@ -1,148 +0,0 b''
1 # -*- coding: utf-8 -*-
2 """Interactive functions and magic functions for Gnuplot usage.
3
4 This requires the Gnuplot.py module for interfacing python with Gnuplot, which
5 can be downloaded from:
6
7 http://gnuplot-py.sourceforge.net/
8
9 See gphelp() below for details on the services offered by this module.
10
11 Inspired by a suggestion/request from Arnd Baecker.
12 """
13
14 __all__ = ['Gnuplot','gp','gp_new','plot','plot2','splot','replot',
15 'hardcopy','gpdata','gpfile','gpstring','gpfunc','gpgrid',
16 'gphelp']
17
18 import IPython.GnuplotRuntime as GRun
19 from IPython.utils.genutils import warn
20 from IPython.core import page
21
22 # Set global names for interactive use
23 Gnuplot = GRun.Gnuplot
24 gp_new = GRun.gp_new
25 gp = GRun.gp
26 plot = gp.plot
27 plot2 = gp.plot2
28 splot = gp.splot
29 replot = gp.replot
30 hardcopy = gp.hardcopy
31
32 # Accessors for the main plot object constructors:
33 gpdata = Gnuplot.Data
34 gpfile = Gnuplot.File
35 gpstring = Gnuplot.String
36 gpfunc = Gnuplot.Func
37 gpgrid = Gnuplot.GridData
38
39 def gphelp():
40 """Print information about the Gnuplot facilities in IPython."""
41
42 page("""
43 IPython provides an interface to access the Gnuplot scientific plotting
44 system, in an environment similar to that of Mathematica or Matlab.
45
46 New top-level global objects
47 ----------------------------
48
49 Please see their respective docstrings for further details.
50
51 - gp: a running Gnuplot instance. You can access its methods as
52 gp.<method>. gp(`a string`) will execute the given string as if it had been
53 typed in an interactive gnuplot window.
54
55 - plot, splot, replot and hardcopy: aliases to the methods of the same name in
56 the global running Gnuplot instance gp. These allow you to simply type:
57
58 In [1]: plot(x,sin(x),title='Sin(x)') # assuming x is a Numeric array
59
60 and obtain a plot of sin(x) vs x with the title 'Sin(x)'.
61
62 - gp_new: a function which returns a new Gnuplot instance. This can be used to
63 have multiple Gnuplot instances running in your session to compare different
64 plots, each in a separate window.
65
66 - Gnuplot: alias to the Gnuplot2 module, an improved drop-in replacement for
67 the original Gnuplot.py. Gnuplot2 needs Gnuplot but redefines several of its
68 functions with improved versions (Gnuplot2 comes with IPython).
69
70 - gpdata, gpfile, gpstring, gpfunc, gpgrid: aliases to Gnuplot.Data,
71 Gnuplot.File, Gnuplot.String, Gnuplot.Func and Gnuplot.GridData
72 respectively. These functions create objects which can then be passed to the
73 plotting commands. See the Gnuplot.py documentation for details.
74
75 Keep in mind that all commands passed to a Gnuplot instance are executed in
76 the Gnuplot namespace, where no Python variables exist. For example, for
77 plotting sin(x) vs x as above, typing
78
79 In [2]: gp('plot x,sin(x)')
80
81 would not work. Instead, you would get the plot of BOTH the functions 'x' and
82 'sin(x)', since Gnuplot doesn't know about the 'x' Python array. The plot()
83 method lives in python and does know about these variables.
84
85
86 New magic functions
87 -------------------
88
89 %gpc: pass one command to Gnuplot and execute it or open a Gnuplot shell where
90 each line of input is executed.
91
92 %gp_set_default: reset the value of IPython's global Gnuplot instance.""")
93
94 # Code below is all for IPython use
95 # Define the magic functions for communicating with the above gnuplot instance.
96 def magic_gpc(self,parameter_s=''):
97 """Execute a gnuplot command or open a gnuplot shell.
98
99 Usage (omit the % if automagic is on). There are two ways to use it:
100
101 1) %gpc 'command' -> passes 'command' directly to the gnuplot instance.
102
103 2) %gpc -> will open up a prompt (gnuplot>>>) which takes input like the
104 standard gnuplot interactive prompt. If you need to type a multi-line
105 command, use \\ at the end of each intermediate line.
106
107 Upon exiting of the gnuplot sub-shell, you return to your IPython
108 session (the gnuplot sub-shell can be invoked as many times as needed).
109 """
110
111 if parameter_s.strip():
112 self.shell.gnuplot(parameter_s)
113 else:
114 self.shell.gnuplot.interact()
115
116 def magic_gp_set_default(self,parameter_s=''):
117 """Set the default gnuplot instance accessed by the %gp magic function.
118
119 %gp_set_default name
120
121 Call with the name of the new instance at the command line. If you want to
122 set this instance in your own code (using an embedded IPython, for
123 example), simply set the variable __IPYTHON__.gnuplot to your own gnuplot
124 instance object."""
125
126 gname = parameter_s.strip()
127 G = eval(gname,self.shell.user_ns)
128 self.shell.gnuplot = G
129 self.shell.user_ns.update({'plot':G.plot,'splot':G.splot,'plot2':G.plot2,
130 'replot':G.replot,'hardcopy':G.hardcopy})
131
132 try:
133 __IPYTHON__
134 except NameError:
135 pass
136 else:
137 # make the global Gnuplot instance known to IPython
138 __IPYTHON__.gnuplot = GRun.gp
139 __IPYTHON__.gnuplot.shell_first_time = 1
140
141 print """*** Type `gphelp` for help on the Gnuplot integration features."""
142
143 # Add the new magic functions to the class dict
144 from IPython.core.iplib import InteractiveShell
145 InteractiveShell.magic_gpc = magic_gpc
146 InteractiveShell.magic_gp_set_default = magic_gp_set_default
147
148 #********************** End of file <GnuplotInteractive.py> *******************
@@ -1,146 +0,0 b''
1 # -*- coding: utf-8 -*-
2 """Basic Gnuplot functionality for inclusion in other code.
3
4 This module creates a running Gnuplot instance called 'gp' and builds other
5 convenient globals for quick use in running scripts. It is intended to allow
6 you to script plotting tasks in Python with a minimum of effort. A typical
7 usage would be:
8
9 import IPython.GnuplotRuntime as GP # or some other short name
10 GP.gp.plot(GP.File('your_data.dat'))
11
12
13 This module exposes the following objects:
14
15 - gp: a running Gnuplot instance. You can access its methods as
16 gp.<method>. gp(`a string`) will execute the given string as if it had been
17 typed in an interactive gnuplot window.
18
19 - gp_new: a function which returns a new Gnuplot instance. This can be used to
20 have multiple Gnuplot instances running in your session to compare different
21 plots.
22
23 - Gnuplot: alias to the Gnuplot2 module, an improved drop-in replacement for
24 the original Gnuplot.py. Gnuplot2 needs Gnuplot but redefines several of its
25 functions with improved versions (Gnuplot2 comes with IPython).
26
27 - Data: alias to Gnuplot.Data, makes a PlotItem from array data.
28
29 - File: alias to Gnuplot.File, makes a PlotItem from a file.
30
31 - String: alias to Gnuplot.String, makes a PlotItem from a string formatted
32 exactly like a file for Gnuplot.File would be.
33
34 - Func: alias to Gnuplot.Func, makes a PlotItem from a function string.
35
36 - GridData: alias to Gnuplot.GridData, makes a PlotItem from grid data.
37
38 - pm3d_config: a string with Gnuplot commands to set up the pm3d mode for
39 surface plotting. You can activate it simply by calling gp(pm3d_config).
40
41 - eps_fix_bbox: A Unix-only function to fix eps files with bad bounding boxes
42 (which Gnuplot generates when the plot size is set to square).
43
44 This requires the Gnuplot.py module for interfacing Python with Gnuplot, which
45 can be downloaded from:
46
47 http://gnuplot-py.sourceforge.net/
48
49 Inspired by a suggestion/request from Arnd Baecker.
50 """
51
52 __all__ = ['Gnuplot','gp','gp_new','Data','File','Func','GridData',
53 'pm3d_config','eps_fix_bbox']
54
55 import os,tempfile,sys
56 from IPython.utils.process import getoutput
57
58 #---------------------------------------------------------------------------
59 # Notes on mouse support for Gnuplot.py
60
61 # If you do not have a mouse-enabled gnuplot, set gnuplot_mouse to 0. If you
62 # use gnuplot, you should really grab a recent, mouse enabled copy. It is an
63 # extremely useful feature. Mouse support is official as of gnuplot 4.0,
64 # released in April 2004.
65
66 # For the mouse features to work correctly, you MUST set your Gnuplot.py
67 # module to use temporary files instead of 'inline data' for data
68 # communication. Note that this is the default, so unless you've manually
69 # fiddled with it you should be ok. If you need to make changes, in the
70 # Gnuplot module directory, loook for the gp_unix.py file and make sure the
71 # prefer_inline_data variable is set to 0. If you set it to 1 Gnuplot.py will
72 # try to pass the data to gnuplot via standard input, which completely
73 # confuses the mouse control system (even though it may be a bit faster than
74 # using temp files).
75
76 # As of Gnuplot.py v1.7, a new option was added to use FIFOs (pipes). This
77 # mechanism, while fast, also breaks the mouse system. You must therefore set
78 # the variable prefer_fifo_data to 0 in gp_unix.py.
79
80 tmpname = tempfile.mktemp()
81 open(tmpname,'w').write('set mouse')
82 gnu_out = getoutput('gnuplot '+ tmpname)
83 os.unlink(tmpname)
84 if gnu_out: # Gnuplot won't print anything if it has mouse support
85 print "*** Your version of Gnuplot appears not to have mouse support."
86 gnuplot_mouse = 0
87 else:
88 gnuplot_mouse = 1
89 del tmpname,gnu_out
90
91 # Default state for persistence of new gnuplot instances
92 if os.name in ['nt','dos'] or sys.platform == 'cygwin':
93 gnuplot_persist = 0
94 else:
95 gnuplot_persist = 1
96
97 import IPython.Gnuplot2 as Gnuplot
98
99 class NotGiven: pass
100
101 def gp_new(mouse=NotGiven,persist=NotGiven):
102 """Return a new Gnuplot instance.
103
104 The instance returned uses the improved methods defined in Gnuplot2.
105
106 Options (boolean):
107
108 - mouse: if unspecified, the module global gnuplot_mouse is used.
109
110 - persist: if unspecified, the module global gnuplot_persist is used."""
111
112 if mouse is NotGiven:
113 mouse = gnuplot_mouse
114 if persist is NotGiven:
115 persist = gnuplot_persist
116 g = Gnuplot.Gnuplot(persist=persist)
117 if mouse:
118 g('set mouse')
119 return g
120
121 # Global-level names.
122
123 # A global Gnuplot instance for interactive use:
124 gp = gp_new()
125
126 # Accessors for the main plot object constructors:
127 Data = Gnuplot.Data
128 File = Gnuplot.File
129 Func = Gnuplot.Func
130 String = Gnuplot.String
131 GridData = Gnuplot.GridData
132
133 # A Unix-only function to fix eps files with bad bounding boxes (which Gnuplot
134 # generates when the plot size is set to square):
135 eps_fix_bbox = Gnuplot.eps_fix_bbox
136
137 # String for configuring pm3d. Simply call g(pm3d_config) to execute it. pm3d
138 # is a very nice mode for plotting colormaps on surfaces. Modify the defaults
139 # below to suit your taste.
140 pm3d_config = """
141 set pm3d solid
142 set hidden3d
143 unset surface
144 set isosamples 50
145 """
146 #******************** End of file <GnuplotRuntime.py> ******************
@@ -1,84 +0,0 b''
1 # -*- coding: utf-8 -*-
2 """Modified input prompt for entering quantities with units.
3
4 Modify the behavior of the interactive interpreter to allow direct input of
5 quantities with units without having to make a function call.
6
7 Now the following forms are accepted:
8
9 x = 4 m
10 y = -.45e3 m/s
11 g = 9.8 m/s**2
12 a = 2.3 m/s^2 # ^ -> ** automatically
13
14 All other input is processed normally.
15
16 Authors
17 -------
18 - Fernando Perez <Fernando.Perez@berkeley.edu>
19 """
20 #*****************************************************************************
21 # Copyright (C) 2008-2011 The IPython Development Team
22 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
23 #
24 # Distributed under the terms of the BSD License. The full license is in
25 # the file COPYING, distributed as part of this software.
26 #*****************************************************************************
27
28 # This file is an example of how to modify IPython's line-processing behavior
29 # without touching the internal code. We'll define an alternate pre-processing
30 # stage which allows a special form of input (which is invalid Python syntax)
31 # for certain quantities, rewrites a line of proper Python in those cases, and
32 # then passes it off to IPython's normal processor for further work.
33
34 # With this kind of customization, IPython can be adapted for many
35 # special-purpose scenarios providing alternate input syntaxes.
36
37 # This file can be imported like a regular module.
38
39 # IPython has a prefilter() function that analyzes each input line. We redefine
40 # it here to first pre-process certain forms of input
41
42 # The prototype of any alternate prefilter must be like this one (the name
43 # doesn't matter):
44 # - line is a string containing the user input line.
45 # - continuation is a parameter which tells us if we are processing a first line of
46 # user input or the second or higher of a multi-line statement.
47
48 def prefilter_PQ(self,line,continuation):
49 """Alternate prefilter for input of PhysicalQuantityInteractive objects.
50
51 This assumes that the function PhysicalQuantityInteractive() has been
52 imported."""
53
54 from re import match
55 from IPython.core.iplib import InteractiveShell
56
57 # This regexp is what does the real work
58 unit_split = match(r'\s*(\w+)\s*=\s*(-?\d*\.?\d*[eE]?-?\d*)\s+([a-zA-Z].*)',
59 line)
60
61 # If special input was ecnountered, process it:
62 if unit_split:
63 var,val,units = unit_split.groups()
64 if var and val and units:
65 units = units.replace('^','**')
66 # Now a valid line needs to be constructed for IPython to process:
67 line = var +" = PhysicalQuantityInteractive(" + val + ", '" + \
68 units + "')"
69 #print 'New line:',line # dbg
70
71 # In the end, always call the default IPython _prefilter() function. Note
72 # that self must be passed explicitly, b/c we're calling the unbound class
73 # method (since this method will overwrite the instance prefilter())
74 return InteractiveShell._prefilter(self,line,continuation)
75
76 # Rebind this to be the new IPython prefilter:
77 from IPython.core.iplib import InteractiveShell
78 InteractiveShell.prefilter = prefilter_PQ
79
80 # Clean up the namespace.
81 del InteractiveShell,prefilter_PQ
82
83 # Just a heads up at the console
84 print '*** Simplified input for physical quantities enabled.'
@@ -1,90 +0,0 b''
1 # -*- coding: utf-8 -*-
2 """Modify the PhysicalQuantities class for more convenient interactive use.
3
4 Also redefine some math functions to operate on PhysQties with no need for
5 special method syntax. This just means moving them out to the global
6 namespace.
7
8 This module should always be loaded *after* math or Numeric, so it can
9 overwrite math functions with the versions that handle units.
10
11 Authors
12 -------
13 - Fernando Perez <Fernando.Perez@berkeley.edu>
14 """
15
16 #*****************************************************************************
17 # Copyright (C) 2008-2011 The IPython Development Team
18 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
19 #
20 # Distributed under the terms of the BSD License. The full license is in
21 # the file COPYING, distributed as part of this software.
22 #*****************************************************************************
23
24 from Scientific.Physics.PhysicalQuantities import PhysicalQuantity
25
26 # This code can be set up to work with Numeric or with math for providing the
27 # mathematical functions. Uncomment the one you prefer to use below.
28
29 # If you use math, sin(x) won't work for x an array, only float or PhysQty
30 import math
31
32 # If you use Numeric, sin(x) works for x a float, PhysQty an array.
33 #import Numeric as math
34
35 class PhysicalQuantityFunction:
36 """Generic function wrapper for PhysicalQuantity instances.
37
38 Calls functions from either the math library or the instance's methods as
39 required. Allows using sin(theta) or sqrt(v**2) syntax irrespective of
40 whether theta is a pure number or a PhysicalQuantity.
41
42 This is *slow*. It's meant for convenient interactive use, not for
43 speed."""
44
45 def __init__(self,name):
46 self.name = name
47
48 def __call__(self,x):
49 if isinstance(x,PhysicalQuantity):
50 return PhysicalQuantity.__dict__[self.name](x)
51 else:
52 return math.__dict__[self.name](x)
53
54 class PhysicalQuantityInteractive(PhysicalQuantity):
55 """Physical quantity with units - modified for Interactive use.
56
57 Basically, the __str__ and __repr__ methods have been swapped for more
58 convenient interactive use. Powers are shown as ^ instead of ** and only 4
59 significant figures are shown.
60
61 Also adds the following aliases for commonly used methods:
62 b = PhysicalQuantity.inBaseUnits
63 u = PhysicalQuantity.inUnitsOf
64
65 These are useful when doing a lot of interactive calculations.
66 """
67
68 # shorthands for the most useful unit conversions
69 b = PhysicalQuantity.inBaseUnits # so you can just type x.b to get base units
70 u = PhysicalQuantity.inUnitsOf
71
72 # This can be done, but it can get dangerous when coupled with IPython's
73 # auto-calling. Everything ends up shown in baseunits and things like x*2
74 # get automatically converted to k(*2), which doesn't work.
75 # Probably not a good idea in general...
76 #__call__ = b
77
78 def __str__(self):
79 return PhysicalQuantity.__repr__(self)
80
81 def __repr__(self):
82 value = '%.4G' % self.value
83 units = self.unit.name().replace('**','^')
84 return value + ' ' + units
85
86 # implement the methods defined in PhysicalQuantity as PhysicalQuantityFunctions
87 sin = PhysicalQuantityFunction('sin')
88 cos = PhysicalQuantityFunction('cos')
89 tan = PhysicalQuantityFunction('tan')
90 sqrt = PhysicalQuantityFunction('sqrt')
@@ -1,42 +0,0 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3 """
4 A backwards compatibility layer for IPython.Shell.
5
6 Previously, IPython had an IPython.Shell module. IPython.Shell has been moved
7 to IPython.core.shell and is being refactored. This new module is provided
8 for backwards compatability. We strongly encourage everyone to start using
9 the new code in IPython.core.shell.
10 """
11
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2011 The IPython Development Team
14 #
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
18
19 from warnings import warn
20
21 msg = """
22 This module (IPython.Shell) is deprecated. The classes that were in this
23 module have been replaced by:
24
25 IPShell->IPython.core.iplib.InteractiveShell
26 IPShellEmbed->IPython.core.embed.InteractiveShellEmbed
27
28 Please migrate your code to use these classes instead.
29 """
30
31 warn(msg, category=DeprecationWarning, stacklevel=1)
32
33 from IPython.core.iplib import InteractiveShell as IPShell
34 from IPython.core.embed import InteractiveShellEmbed as IPShellEmbed
35
36 def start(user_ns=None, embedded=False):
37 """Return an instance of :class:`InteractiveShell`."""
38 if embedded:
39 return IPShellEmbed(user_ns=user_ns)
40 else:
41 return IPShell(user_ns=user_ns)
42
@@ -1,400 +0,0 b''
1 """
2 ``astyle`` provides classes for adding style (foreground and background color;
3 bold; blink; etc.) to terminal and curses output.
4 """
5
6
7 import sys, os
8
9 try:
10 import curses
11 except ImportError:
12 curses = None
13
14
15 COLOR_BLACK = 0
16 COLOR_RED = 1
17 COLOR_GREEN = 2
18 COLOR_YELLOW = 3
19 COLOR_BLUE = 4
20 COLOR_MAGENTA = 5
21 COLOR_CYAN = 6
22 COLOR_WHITE = 7
23
24 A_BLINK = 1<<0 # Blinking text
25 A_BOLD = 1<<1 # Extra bright or bold text
26 A_DIM = 1<<2 # Half bright text
27 A_REVERSE = 1<<3 # Reverse-video text
28 A_STANDOUT = 1<<4 # The best highlighting mode available
29 A_UNDERLINE = 1<<5 # Underlined text
30
31
32 class Style(object):
33 """
34 Store foreground color, background color and attribute (bold, underlined
35 etc.).
36 """
37 __slots__ = ("fg", "bg", "attrs")
38
39 COLORNAMES = {
40 "black": COLOR_BLACK,
41 "red": COLOR_RED,
42 "green": COLOR_GREEN,
43 "yellow": COLOR_YELLOW,
44 "blue": COLOR_BLUE,
45 "magenta": COLOR_MAGENTA,
46 "cyan": COLOR_CYAN,
47 "white": COLOR_WHITE,
48 }
49 ATTRNAMES = {
50 "blink": A_BLINK,
51 "bold": A_BOLD,
52 "dim": A_DIM,
53 "reverse": A_REVERSE,
54 "standout": A_STANDOUT,
55 "underline": A_UNDERLINE,
56 }
57
58 def __init__(self, fg, bg, attrs=0):
59 """
60 Create a ``Style`` object with ``fg`` as the foreground color,
61 ``bg`` as the background color and ``attrs`` as the attributes.
62
63 Examples:
64 >>> Style(COLOR_RED, COLOR_BLACK)
65 <Style fg=red bg=black attrs=0>
66
67 >>> Style(COLOR_YELLOW, COLOR_BLUE, A_BOLD|A_UNDERLINE)
68 <Style fg=yellow bg=blue attrs=bold|underline>
69 """
70 self.fg = fg
71 self.bg = bg
72 self.attrs = attrs
73
74 def __call__(self, *args):
75 text = Text()
76 for arg in args:
77 if isinstance(arg, Text):
78 text.extend(arg)
79 else:
80 text.append((self, arg))
81 return text
82
83 def __eq__(self, other):
84 return self.fg == other.fg and self.bg == other.bg and self.attrs == other.attrs
85
86 def __neq__(self, other):
87 return self.fg != other.fg or self.bg != other.bg or self.attrs != other.attrs
88
89 def __repr__(self):
90 color2name = ("black", "red", "green", "yellow", "blue", "magenta", "cyan", "white")
91 attrs2name = ("blink", "bold", "dim", "reverse", "standout", "underline")
92
93 return "<%s fg=%s bg=%s attrs=%s>" % (
94 self.__class__.__name__, color2name[self.fg], color2name[self.bg],
95 "|".join([attrs2name[b] for b in xrange(6) if self.attrs&(1<<b)]) or 0)
96
97 def fromstr(cls, value):
98 """
99 Create a ``Style`` object from a string. The format looks like this:
100 ``"red:black:bold|blink"``.
101 """
102 # defaults
103 fg = COLOR_WHITE
104 bg = COLOR_BLACK
105 attrs = 0
106
107 parts = value.split(":")
108 if len(parts) > 0:
109 fg = cls.COLORNAMES[parts[0].lower()]
110 if len(parts) > 1:
111 bg = cls.COLORNAMES[parts[1].lower()]
112 if len(parts) > 2:
113 for strattr in parts[2].split("|"):
114 attrs |= cls.ATTRNAMES[strattr.lower()]
115 return cls(fg, bg, attrs)
116 fromstr = classmethod(fromstr)
117
118 def fromenv(cls, name, default):
119 """
120 Create a ``Style`` from an environment variable named ``name``
121 (using ``default`` if the environment variable doesn't exist).
122 """
123 return cls.fromstr(os.environ.get(name, default))
124 fromenv = classmethod(fromenv)
125
126
127 def switchstyle(s1, s2):
128 """
129 Return the ANSI escape sequence needed to switch from style ``s1`` to
130 style ``s2``.
131 """
132 attrmask = (A_BLINK|A_BOLD|A_UNDERLINE|A_REVERSE)
133 a1 = s1.attrs & attrmask
134 a2 = s2.attrs & attrmask
135
136 args = []
137 if s1 != s2:
138 # do we have to get rid of the bold/underline/blink bit?
139 # (can only be done by a reset)
140 # use reset when our target color is the default color
141 # (this is shorter than 37;40)
142 if (a1 & ~a2 or s2==style_default):
143 args.append("0")
144 s1 = style_default
145 a1 = 0
146
147 # now we know that old and new color have the same boldness,
148 # or the new color is bold and the old isn't,
149 # i.e. we only might have to switch bold on, not off
150 if not (a1 & A_BOLD) and (a2 & A_BOLD):
151 args.append("1")
152
153 # Fix underline
154 if not (a1 & A_UNDERLINE) and (a2 & A_UNDERLINE):
155 args.append("4")
156
157 # Fix blink
158 if not (a1 & A_BLINK) and (a2 & A_BLINK):
159 args.append("5")
160
161 # Fix reverse
162 if not (a1 & A_REVERSE) and (a2 & A_REVERSE):
163 args.append("7")
164
165 # Fix foreground color
166 if s1.fg != s2.fg:
167 args.append("3%d" % s2.fg)
168
169 # Finally fix the background color
170 if s1.bg != s2.bg:
171 args.append("4%d" % s2.bg)
172
173 if args:
174 return "\033[%sm" % ";".join(args)
175 return ""
176
177
178 class Text(list):
179 """
180 A colored string. A ``Text`` object is a sequence, the sequence
181 items will be ``(style, string)`` tuples.
182 """
183
184 def __init__(self, *args):
185 list.__init__(self)
186 self.append(*args)
187
188 def __repr__(self):
189 return "%s.%s(%s)" % (
190 self.__class__.__module__, self.__class__.__name__,
191 list.__repr__(self)[1:-1])
192
193 def append(self, *args):
194 for arg in args:
195 if isinstance(arg, Text):
196 self.extend(arg)
197 elif isinstance(arg, tuple): # must be (style, string)
198 list.append(self, arg)
199 elif isinstance(arg, unicode):
200 list.append(self, (style_default, arg))
201 else:
202 list.append(self, (style_default, str(arg)))
203
204 def insert(self, index, *args):
205 self[index:index] = Text(*args)
206
207 def __add__(self, other):
208 new = Text()
209 new.append(self)
210 new.append(other)
211 return new
212
213 def __iadd__(self, other):
214 self.append(other)
215 return self
216
217 def format(self, styled=True):
218 """
219 This generator yields the strings that will make up the final
220 colorized string.
221 """
222 if styled:
223 oldstyle = style_default
224 for (style, string) in self:
225 if not isinstance(style, (int, long)):
226 switch = switchstyle(oldstyle, style)
227 if switch:
228 yield switch
229 if string:
230 yield string
231 oldstyle = style
232 switch = switchstyle(oldstyle, style_default)
233 if switch:
234 yield switch
235 else:
236 for (style, string) in self:
237 if not isinstance(style, (int, long)):
238 yield string
239
240 def string(self, styled=True):
241 """
242 Return the resulting string (with escape sequences, if ``styled``
243 is true).
244 """
245 return "".join(self.format(styled))
246
247 def __str__(self):
248 """
249 Return ``self`` as a string (without ANSI escape sequences).
250 """
251 return self.string(False)
252
253 def write(self, stream, styled=True):
254 """
255 Write ``self`` to the output stream ``stream`` (with escape sequences,
256 if ``styled`` is true).
257 """
258 for part in self.format(styled):
259 stream.write(part)
260
261
262 try:
263 import ipipe
264 except ImportError:
265 pass
266 else:
267 def xrepr_astyle_text(self, mode="default"):
268 yield (-1, True)
269 for info in self:
270 yield info
271 ipipe.xrepr.when_type(Text)(xrepr_astyle_text)
272
273
274 def streamstyle(stream, styled=None):
275 """
276 If ``styled`` is ``None``, return whether ``stream`` refers to a terminal.
277 If this can't be determined (either because ``stream`` doesn't refer to a
278 real OS file, or because you're on Windows) return ``False``. If ``styled``
279 is not ``None`` ``styled`` will be returned unchanged.
280 """
281 if styled is None:
282 try:
283 styled = os.isatty(stream.fileno())
284 except (KeyboardInterrupt, SystemExit):
285 raise
286 except Exception:
287 styled = False
288 return styled
289
290
291 def write(stream, styled, *texts):
292 """
293 Write ``texts`` to ``stream``.
294 """
295 text = Text(*texts)
296 text.write(stream, streamstyle(stream, styled))
297
298
299 def writeln(stream, styled, *texts):
300 """
301 Write ``texts`` to ``stream`` and finish with a line feed.
302 """
303 write(stream, styled, *texts)
304 stream.write("\n")
305
306
307 class Stream(object):
308 """
309 Stream wrapper that adds color output.
310 """
311 def __init__(self, stream, styled=None):
312 self.stream = stream
313 self.styled = streamstyle(stream, styled)
314
315 def write(self, *texts):
316 write(self.stream, self.styled, *texts)
317
318 def writeln(self, *texts):
319 writeln(self.stream, self.styled, *texts)
320
321 def __getattr__(self, name):
322 return getattr(self.stream, name)
323
324
325 class stdout(object):
326 """
327 Stream wrapper for ``sys.stdout`` that adds color output.
328 """
329 def write(self, *texts):
330 write(sys.stdout, None, *texts)
331
332 def writeln(self, *texts):
333 writeln(sys.stdout, None, *texts)
334
335 def __getattr__(self, name):
336 return getattr(sys.stdout, name)
337 stdout = stdout()
338
339
340 class stderr(object):
341 """
342 Stream wrapper for ``sys.stderr`` that adds color output.
343 """
344 def write(self, *texts):
345 write(sys.stderr, None, *texts)
346
347 def writeln(self, *texts):
348 writeln(sys.stderr, None, *texts)
349
350 def __getattr__(self, name):
351 return getattr(sys.stdout, name)
352 stderr = stderr()
353
354
355 if curses is not None:
356 # This is probably just range(8)
357 COLOR2CURSES = [
358 COLOR_BLACK,
359 COLOR_RED,
360 COLOR_GREEN,
361 COLOR_YELLOW,
362 COLOR_BLUE,
363 COLOR_MAGENTA,
364 COLOR_CYAN,
365 COLOR_WHITE,
366 ]
367
368 A2CURSES = {
369 A_BLINK: curses.A_BLINK,
370 A_BOLD: curses.A_BOLD,
371 A_DIM: curses.A_DIM,
372 A_REVERSE: curses.A_REVERSE,
373 A_STANDOUT: curses.A_STANDOUT,
374 A_UNDERLINE: curses.A_UNDERLINE,
375 }
376
377
378 # default style
379 style_default = Style.fromstr("white:black")
380
381 # Styles for datatypes
382 style_type_none = Style.fromstr("magenta:black")
383 style_type_bool = Style.fromstr("magenta:black")
384 style_type_number = Style.fromstr("yellow:black")
385 style_type_datetime = Style.fromstr("magenta:black")
386 style_type_type = Style.fromstr("cyan:black")
387
388 # Style for URLs and file/directory names
389 style_url = Style.fromstr("green:black")
390 style_dir = Style.fromstr("cyan:black")
391 style_file = Style.fromstr("green:black")
392
393 # Style for ellipsis (when an output has been shortened
394 style_ellisis = Style.fromstr("red:black")
395
396 # Style for displaying exceptions
397 style_error = Style.fromstr("red:black")
398
399 # Style for displaying non-existing attributes
400 style_nodata = Style.fromstr("red:black")
@@ -1,137 +0,0 b''
1 """Doctest-related utilities for IPython.
2
3 For most common uses, all you should need to run is::
4
5 from IPython.dtutils import idoctest
6
7 See the idoctest docstring below for usage details.
8 """
9
10 import doctest
11 import sys
12
13 from IPython.core import ipapi
14 ip = ipapi.get()
15
16 def rundoctest(text,ns=None,eraise=False):
17 """Run a the input source as a doctest, in the caller's namespace.
18
19 :Parameters:
20 text : str
21 Source to execute.
22
23 :Keywords:
24 ns : dict (None)
25 Namespace where the code should be executed. If not given, the
26 caller's locals and globals are used.
27 eraise : bool (False)
28 If true, immediately raise any exceptions instead of reporting them at
29 the end. This allows you to then do interactive debugging via
30 IPython's facilities (use %debug after the fact, or with %pdb for
31 automatic activation).
32 """
33
34 name = 'interactive doctest'
35 filename = '<IPython console>'
36
37 if eraise:
38 runner = doctest.DebugRunner()
39 else:
40 runner = doctest.DocTestRunner()
41
42 parser = doctest.DocTestParser()
43 if ns is None:
44 f = sys._getframe(1)
45 ns = f.f_globals.copy()
46 ns.update(f.f_locals)
47
48 test = parser.get_doctest(text,ns,name,filename,0)
49 runner.run(test)
50 runner.summarize(True)
51
52
53 def idoctest(ns=None,eraise=False):
54 """Interactively prompt for input and run it as a doctest.
55
56 To finish entering input, enter two blank lines or Ctrl-D (EOF). If you
57 use Ctrl-C, the example is aborted and all input discarded.
58
59 :Keywords:
60 ns : dict (None)
61 Namespace where the code should be executed. If not given, the IPython
62 interactive namespace is used.
63 eraise : bool (False)
64 If true, immediately raise any exceptions instead of reporting them at
65 the end. This allows you to then do interactive debugging via
66 IPython's facilities (use %debug after the fact, or with %pdb for
67 automatic activation).
68 end_mark : str ('--')
69 String to explicitly indicate the end of input.
70
71 """
72
73 inlines = []
74 empty_lines = 0 # count consecutive empty lines
75 run_test = True
76
77 if ns is None:
78 ns = ip.user_ns
79
80 ip.savehist()
81 try:
82 while True:
83 line = raw_input()
84 if not line or line.isspace():
85 empty_lines += 1
86 else:
87 empty_lines = 0
88
89 if empty_lines>=2:
90 break
91
92 inlines.append(line)
93 except EOFError:
94 pass
95 except KeyboardInterrupt:
96 print "KeyboardInterrupt - Discarding input."
97 run_test = False
98
99 ip.reloadhist()
100
101 if run_test:
102 # Extra blank line at the end to ensure that the final docstring has a
103 # closing newline
104 inlines.append('')
105 rundoctest('\n'.join(inlines),ns,eraise)
106
107
108 # For debugging of this module itself.
109 if __name__ == "__main__":
110 t = """
111 >>> for i in range(10):
112 ... print i,
113 ...
114 0 1 2 3 4 5 6 7 8 9
115 """
116
117 t2 = """
118 A simple example::
119
120 >>> for i in range(10):
121 ... print i,
122 ...
123 0 1 2 3 4 5 6 7 8 9
124
125 Some more details::
126
127 >>> print "hello"
128 hello
129 """
130
131 t3 = """
132 A failing example::
133
134 >>> x=1
135 >>> x+1
136 3
137 """
This diff has been collapsed as it changes many lines, (518 lines changed) Show them Hide them
@@ -1,518 +0,0 b''
1 #!/usr/bin/python
2 # -*- coding: iso-8859-15 -*-
3 '''
4 Provides IPython remote instance.
5
6 @author: Laurent Dufrechou
7 laurent.dufrechou _at_ gmail.com
8 @license: BSD
9
10 All rights reserved. This program and the accompanying materials are made
11 available under the terms of the BSD which accompanies this distribution, and
12 is available at U{http://www.opensource.org/licenses/bsd-license.php}
13 '''
14
15 __version__ = 0.9
16 __author__ = "Laurent Dufrechou"
17 __email__ = "laurent.dufrechou _at_ gmail.com"
18 __license__ = "BSD"
19
20 import re
21 import sys
22 import os
23 import locale
24 from thread_ex import ThreadEx
25
26 from IPython.core import iplib
27 import IPython.utils.io
28
29 ##############################################################################
30 class _Helper(object):
31 """Redefine the built-in 'help'.
32 This is a wrapper around pydoc.help (with a twist).
33 """
34
35 def __init__(self, pager):
36 self._pager = pager
37
38 def __repr__(self):
39 return "Type help() for interactive help, " \
40 "or help(object) for help about object."
41
42 def __call__(self, *args, **kwds):
43 class DummyWriter(object):
44 '''Dumy class to handle help output'''
45 def __init__(self, pager):
46 self._pager = pager
47
48 def write(self, data):
49 '''hook to fill self._pager'''
50 self._pager(data)
51
52 import pydoc
53 pydoc.help.output = DummyWriter(self._pager)
54 pydoc.help.interact = lambda :1
55
56 return pydoc.help(*args, **kwds)
57
58
59 ##############################################################################
60 class _CodeExecutor(ThreadEx):
61 ''' Thread that execute ipython code '''
62 def __init__(self, instance):
63 ThreadEx.__init__(self)
64 self.instance = instance
65
66 def run(self):
67 '''Thread main loop'''
68 try:
69 self.instance._doc_text = None
70 self.instance._help_text = None
71 self.instance._execute()
72 # used for uper class to generate event after execution
73 self.instance._after_execute()
74
75 except KeyboardInterrupt:
76 pass
77
78
79 ##############################################################################
80 class NonBlockingIPShell(object):
81 '''
82 Create an IPython instance, running the commands in a separate,
83 non-blocking thread.
84 This allows embedding in any GUI without blockage.
85
86 Note: The ThreadEx class supports asynchroneous function call
87 via raise_exc()
88 '''
89
90 def __init__(self, user_ns={}, user_global_ns=None,
91 cin=None, cout=None, cerr=None,
92 ask_exit_handler=None):
93 '''
94 @param user_ns: User namespace.
95 @type user_ns: dictionary
96 @param user_global_ns: User global namespace.
97 @type user_global_ns: dictionary.
98 @param cin: Console standard input.
99 @type cin: IO stream
100 @param cout: Console standard output.
101 @type cout: IO stream
102 @param cerr: Console standard error.
103 @type cerr: IO stream
104 @param exit_handler: Replacement for builtin exit() function
105 @type exit_handler: function
106 @param time_loop: Define the sleep time between two thread's loop
107 @type int
108 '''
109 #ipython0 initialisation
110 self._IP = None
111 self.init_ipython0(user_ns, user_global_ns,
112 cin, cout, cerr,
113 ask_exit_handler)
114
115 #vars used by _execute
116 self._iter_more = 0
117 self._history_level = 0
118 self._complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
119 self._prompt = str(self._IP.outputcache.prompt1).strip()
120
121 #thread working vars
122 self._line_to_execute = ''
123 self._threading = True
124
125 #vars that will be checked by GUI loop to handle thread states...
126 #will be replaced later by PostEvent GUI funtions...
127 self._doc_text = None
128 self._help_text = None
129 self._add_button = None
130
131 def init_ipython0(self, user_ns={}, user_global_ns=None,
132 cin=None, cout=None, cerr=None,
133 ask_exit_handler=None):
134 ''' Initialize an ipython0 instance '''
135
136 #first we redefine in/out/error functions of IPython
137 #BUG: we've got a limitation form ipython0 there
138 #only one instance can be instanciated else tehre will be
139 #cin/cout/cerr clash...
140 if cin:
141 Term.cin = cin
142 if cout:
143 Term.cout = cout
144 if cerr:
145 Term.cerr = cerr
146
147 excepthook = sys.excepthook
148
149 #Hack to save sys.displayhook, because ipython seems to overwrite it...
150 self.sys_displayhook_ori = sys.displayhook
151 ipython0 = iplib.InteractiveShell(
152 parent=None, config=None,
153 user_ns=user_ns,
154 user_global_ns=user_global_ns
155 )
156 self._IP = ipython0
157
158 #we save ipython0 displayhook and we restore sys.displayhook
159 self.displayhook = sys.displayhook
160 sys.displayhook = self.sys_displayhook_ori
161
162 #we replace IPython default encoding by wx locale encoding
163 loc = locale.getpreferredencoding()
164 if loc:
165 self._IP.stdin_encoding = loc
166 #we replace the ipython default pager by our pager
167 self._IP.set_hook('show_in_pager', self._pager)
168
169 #we replace the ipython default shell command caller
170 #by our shell handler
171 self._IP.set_hook('shell_hook', self._shell)
172
173 #we replace the ipython default input command caller by our method
174 iplib.raw_input_original = self._raw_input_original
175 #we replace the ipython default exit command by our method
176 self._IP.exit = ask_exit_handler
177 #we replace the help command
178 self._IP.user_ns['help'] = _Helper(self._pager_help)
179
180 #we disable cpaste magic... until we found a way to use it properly.
181 def bypass_magic(self, arg):
182 print '%this magic is currently disabled.'
183 ipython0.define_magic('cpaste', bypass_magic)
184
185 import __builtin__
186 __builtin__.raw_input = self._raw_input
187
188 sys.excepthook = excepthook
189
190 #----------------------- Thread management section ----------------------
191 def do_execute(self, line):
192 """
193 Tell the thread to process the 'line' command
194 """
195
196 self._line_to_execute = line
197
198 if self._threading:
199 #we launch the ipython line execution in a thread to make it
200 #interruptible with include it in self namespace to be able
201 #to call ce.raise_exc(KeyboardInterrupt)
202 self.ce = _CodeExecutor(self)
203 self.ce.start()
204 else:
205 try:
206 self._doc_text = None
207 self._help_text = None
208 self._execute()
209 # used for uper class to generate event after execution
210 self._after_execute()
211
212 except KeyboardInterrupt:
213 pass
214
215 #----------------------- IPython management section ----------------------
216 def get_threading(self):
217 """
218 Returns threading status, is set to True, then each command sent to
219 the interpreter will be executed in a separated thread allowing,
220 for example, breaking a long running commands.
221 Disallowing it, permits better compatibilty with instance that is embedding
222 IPython instance.
223
224 @return: Execution method
225 @rtype: bool
226 """
227 return self._threading
228
229 def set_threading(self, state):
230 """
231 Sets threading state, if set to True, then each command sent to
232 the interpreter will be executed in a separated thread allowing,
233 for example, breaking a long running commands.
234 Disallowing it, permits better compatibilty with instance that is embedding
235 IPython instance.
236
237 @param state: Sets threading state
238 @type bool
239 """
240 self._threading = state
241
242 def get_doc_text(self):
243 """
244 Returns the output of the processing that need to be paged (if any)
245
246 @return: The std output string.
247 @rtype: string
248 """
249 return self._doc_text
250
251 def get_help_text(self):
252 """
253 Returns the output of the processing that need to be paged via help pager(if any)
254
255 @return: The std output string.
256 @rtype: string
257 """
258 return self._help_text
259
260 def get_banner(self):
261 """
262 Returns the IPython banner for useful info on IPython instance
263
264 @return: The banner string.
265 @rtype: string
266 """
267 return self._IP.banner
268
269 def get_prompt_count(self):
270 """
271 Returns the prompt number.
272 Each time a user execute a line in the IPython shell the prompt count is increased
273
274 @return: The prompt number
275 @rtype: int
276 """
277 return self._IP.outputcache.prompt_count
278
279 def get_prompt(self):
280 """
281 Returns current prompt inside IPython instance
282 (Can be In [...]: ot ...:)
283
284 @return: The current prompt.
285 @rtype: string
286 """
287 return self._prompt
288
289 def get_indentation(self):
290 """
291 Returns the current indentation level
292 Usefull to put the caret at the good start position if we want to do autoindentation.
293
294 @return: The indentation level.
295 @rtype: int
296 """
297 return self._IP.indent_current_nsp
298
299 def update_namespace(self, ns_dict):
300 '''
301 Add the current dictionary to the shell namespace.
302
303 @param ns_dict: A dictionary of symbol-values.
304 @type ns_dict: dictionary
305 '''
306 self._IP.user_ns.update(ns_dict)
307
308 def complete(self, line):
309 '''
310 Returns an auto completed line and/or posibilities for completion.
311
312 @param line: Given line so far.
313 @type line: string
314
315 @return: Line completed as for as possible,
316 and possible further completions.
317 @rtype: tuple
318 '''
319 split_line = self._complete_sep.split(line)
320 possibilities = self._IP.complete(split_line[-1])
321 if possibilities:
322
323 def _common_prefix(str1, str2):
324 '''
325 Reduction function. returns common prefix of two given strings.
326
327 @param str1: First string.
328 @type str1: string
329 @param str2: Second string
330 @type str2: string
331
332 @return: Common prefix to both strings.
333 @rtype: string
334 '''
335 for i in range(len(str1)):
336 if not str2.startswith(str1[:i+1]):
337 return str1[:i]
338 return str1
339 common_prefix = reduce(_common_prefix, possibilities)
340 completed = line[:-len(split_line[-1])]+common_prefix
341 else:
342 completed = line
343 return completed, possibilities
344
345 def history_back(self):
346 '''
347 Provides one history command back.
348
349 @return: The command string.
350 @rtype: string
351 '''
352 history = ''
353 #the below while loop is used to suppress empty history lines
354 while((history == '' or history == '\n') and self._history_level >0):
355 if self._history_level >= 1:
356 self._history_level -= 1
357 history = self._get_history()
358 return history
359
360 def history_forward(self):
361 '''
362 Provides one history command forward.
363
364 @return: The command string.
365 @rtype: string
366 '''
367 history = ''
368 #the below while loop is used to suppress empty history lines
369 while((history == '' or history == '\n') \
370 and self._history_level <= self._get_history_max_index()):
371 if self._history_level < self._get_history_max_index():
372 self._history_level += 1
373 history = self._get_history()
374 else:
375 if self._history_level == self._get_history_max_index():
376 history = self._get_history()
377 self._history_level += 1
378 else:
379 history = ''
380 return history
381
382 def init_history_index(self):
383 '''
384 set history to last command entered
385 '''
386 self._history_level = self._get_history_max_index()+1
387
388 #----------------------- IPython PRIVATE management section --------------
389 def _after_execute(self):
390 '''
391 Can be redefined to generate post event after excution is done
392 '''
393 pass
394
395 def _ask_exit(self):
396 '''
397 Can be redefined to generate post event to exit the Ipython shell
398 '''
399 pass
400
401 def _get_history_max_index(self):
402 '''
403 returns the max length of the history buffer
404
405 @return: history length
406 @rtype: int
407 '''
408 return len(self._IP.input_hist_raw)-1
409
410 def _get_history(self):
411 '''
412 Get's the command string of the current history level.
413
414 @return: Historic command stri
415 @rtype: string
416 '''
417 rv = self._IP.input_hist_raw[self._history_level].strip('\n')
418 return rv
419
420 def _pager_help(self, text):
421 '''
422 This function is used as a callback replacment to IPython help pager function
423
424 It puts the 'text' value inside the self._help_text string that can be retrived via
425 get_help_text function.
426 '''
427 if self._help_text == None:
428 self._help_text = text
429 else:
430 self._help_text += text
431
432 def _pager(self, IP, text):
433 '''
434 This function is used as a callback replacment to IPython pager function
435
436 It puts the 'text' value inside the self._doc_text string that can be retrived via
437 get_doc_text function.
438 '''
439 self._doc_text = text
440
441 def _raw_input_original(self, prompt=''):
442 '''
443 Custom raw_input() replacement. Get's current line from console buffer.
444
445 @param prompt: Prompt to print. Here for compatability as replacement.
446 @type prompt: string
447
448 @return: The current command line text.
449 @rtype: string
450 '''
451 return self._line_to_execute
452
453 def _raw_input(self, prompt=''):
454 """ A replacement from python's raw_input.
455 """
456 raise NotImplementedError
457
458 def _execute(self):
459 '''
460 Executes the current line provided by the shell object.
461 '''
462
463 orig_stdout = sys.stdout
464 sys.stdout = Term.cout
465 #self.sys_displayhook_ori = sys.displayhook
466 #sys.displayhook = self.displayhook
467
468 try:
469 line = self._IP.raw_input(None, self._iter_more)
470 if self._IP.autoindent:
471 self._IP.readline_startup_hook(None)
472
473 except KeyboardInterrupt:
474 self._IP.write('\nKeyboardInterrupt\n')
475 self._IP.resetbuffer()
476 # keep cache in sync with the prompt counter:
477 self._IP.outputcache.prompt_count -= 1
478
479 if self._IP.autoindent:
480 self._IP.indent_current_nsp = 0
481 self._iter_more = 0
482 except:
483 self._IP.showtraceback()
484 else:
485 self._IP.write(str(self._IP.outputcache.prompt_out).strip())
486 self._iter_more = self._IP.push_line(line)
487 if (self._IP.SyntaxTB.last_syntax_error and \
488 self._IP.autoedit_syntax):
489 self._IP.edit_syntax_error()
490 if self._iter_more:
491 self._prompt = str(self._IP.outputcache.prompt2).strip()
492 if self._IP.autoindent:
493 self._IP.readline_startup_hook(self._IP.pre_readline)
494 else:
495 self._prompt = str(self._IP.outputcache.prompt1).strip()
496 self._IP.indent_current_nsp = 0 #we set indentation to 0
497
498 sys.stdout = orig_stdout
499 #sys.displayhook = self.sys_displayhook_ori
500
501 def _shell(self, ip, cmd):
502 '''
503 Replacement method to allow shell commands without them blocking.
504
505 @param ip: Ipython instance, same as self._IP
506 @type cmd: Ipython instance
507 @param cmd: Shell command to execute.
508 @type cmd: string
509 '''
510 stdin, stdout = os.popen4(cmd)
511 result = stdout.read().decode('cp437').\
512 encode(locale.getpreferredencoding())
513 #we use print command because the shell command is called
514 #inside IPython instance and thus is redirected to thread cout
515 #"\x01\x1b[1;36m\x02" <-- add colour to the text...
516 print "\x01\x1b[1;36m\x02"+result
517 stdout.close()
518 stdin.close()
This diff has been collapsed as it changes many lines, (510 lines changed) Show them Hide them
@@ -1,510 +0,0 b''
1 #!/usr/bin/python
2 # -*- coding: iso-8859-15 -*-
3 import wx
4 import wx.stc as stc
5 import keyword
6
7 #-----------------------------------------
8 # History widget for IPython
9 __version__ = 0.5
10 __author__ = "Laurent Dufrechou"
11 __email__ = "laurent.dufrechou _at_ gmail.com"
12 __license__ = "BSD"
13 #-----------------------------------------
14
15 class IPythonHistoryPanel(wx.Panel):
16
17 def __init__(self, parent,flt_empty=True,
18 flt_doc=True,flt_cmd=True,flt_magic=True):
19
20 wx.Panel.__init__(self,parent,-1)
21 #text_ctrl = wx.TextCtrl(self, -1, style=wx.TE_MULTILINE)
22 text_ctrl = PythonSTC(self, -1)
23
24
25 st_filt = wx.StaticText(self, -1, " Filter:")
26
27 self.filter_empty = wx.CheckBox(self, -1, "Empty commands")
28 self.filter_doc = wx.CheckBox(self, -1, "?: Doc commands")
29 self.filter_cmd = wx.CheckBox(self, -1, "!: Sys commands")
30 self.filter_magic = wx.CheckBox(self, -1, "%: Magic keys")
31
32 self.options={'filter_empty':{'value':'True',
33 'checkbox':self.filter_empty, \
34 'True':True,'False':False,
35 'setfunc':lambda x:None},
36 'filter_doc':{'value':'True',
37 'checkbox':self.filter_doc, \
38 'True':True,'False':False,
39 'setfunc':lambda x:None},
40 'filter_cmd':{'value':'True',
41 'checkbox':self.filter_cmd, \
42 'True':True,'False':False,
43 'setfunc':lambda x:None},
44 'filter_magic':{'value':'True',
45 'checkbox':self.filter_magic, \
46 'True':True,'False':False,
47 'setfunc':lambda x:None},
48 }
49 self.reloadOptions(self.options)
50
51 self.filter_empty.Bind(wx.EVT_CHECKBOX, self.evtCheckEmptyFilter)
52 self.filter_doc.Bind(wx.EVT_CHECKBOX, self.evtCheckDocFilter)
53 self.filter_cmd.Bind(wx.EVT_CHECKBOX, self.evtCheckCmdFilter)
54 self.filter_magic.Bind(wx.EVT_CHECKBOX, self.evtCheckMagicFilter)
55
56 #self.filter_empty.SetValue(flt_empty)
57 #self.filter_doc.SetValue(flt_doc)
58 #self.filter_cmd.SetValue(flt_cmd)
59 #self.filter_magic.SetValue(flt_magic)
60
61 sizer = wx.BoxSizer(wx.VERTICAL)
62
63 sizer.Add(text_ctrl, 1, wx.EXPAND)
64 sizer.AddMany( [(5,5),
65 st_filt,
66 (10,10),
67 self.filter_empty,
68 self.filter_doc,
69 self.filter_cmd,
70 self.filter_magic,
71 (10,10),
72 ])
73 self.SetAutoLayout(True)
74 sizer.Fit(self)
75 sizer.SetSizeHints(self)
76 self.SetSizer(sizer)
77 self.text_ctrl=text_ctrl
78 #text_ctrl.SetText(demoText + open('Main.py').read())
79 text_ctrl.EmptyUndoBuffer()
80 text_ctrl.Colourise(0, -1)
81
82 # line numbers in the margin
83 text_ctrl.SetMarginType(1, stc.STC_MARGIN_NUMBER)
84 text_ctrl.SetMarginWidth(1, 15)
85
86
87 def write(self,history_line):
88 add = True
89 if self.filter_empty.GetValue() == True and history_line == '':
90 add = False
91 if len(history_line)>0:
92 if self.filter_doc.GetValue() == True and history_line[-1:] == '?':
93 add = False
94 if self.filter_cmd.GetValue() == True and history_line[0] == '!':
95 add = False
96 if self.filter_magic.GetValue() == True and history_line[0] == '%':
97 add = False
98 if add:
99 self.text_ctrl.AppendText(history_line+'\n')
100
101 #------------------------ Option Section -----------------------------------
102 def processOptionCheckedEvt(self, event, name):
103 if event.IsChecked():
104 self.options[name]['value']='True'
105 else:
106 self.options[name]['value']='False'
107 self.updateOptionTracker(name,
108 self.options[name]['value'])
109
110 def evtCheckEmptyFilter(self, event):
111 self.processOptionCheckedEvt(event, 'filter_empty')
112
113 def evtCheckDocFilter(self, event):
114 self.processOptionCheckedEvt(event, 'filter_doc')
115
116 def evtCheckCmdFilter(self, event):
117 self.processOptionCheckedEvt(event, 'filter_cmd')
118
119 def evtCheckMagicFilter(self, event):
120 self.processOptionCheckedEvt(event, 'filter_magic')
121
122 def getOptions(self):
123 return self.options
124
125 def reloadOptions(self,options):
126 self.options = options
127 for key in self.options.keys():
128 value = self.options[key]['value']
129 self.options[key]['checkbox'].SetValue(self.options[key][value])
130 self.options[key]['setfunc'](value)
131
132 #------------------------ Hook Section -----------------------------------
133 def updateOptionTracker(self,name,value):
134 '''
135 Default history tracker (does nothing)
136 '''
137 pass
138
139 def setOptionTrackerHook(self,func):
140 '''
141 Define a new history tracker
142 '''
143 self.updateOptionTracker = func
144
145
146 #----------------------------------------------------------------------
147 # Font definition for Styled Text Control
148
149 if wx.Platform == '__WXMSW__':
150 faces = { 'times': 'Times New Roman',
151 'mono' : 'Courier New',
152 'helv' : 'Arial',
153 'other': 'Comic Sans MS',
154 'size' : 8,
155 'size2': 6,
156 }
157 elif wx.Platform == '__WXMAC__':
158 faces = { 'times': 'Times New Roman',
159 'mono' : 'Monaco',
160 'helv' : 'Arial',
161 'other': 'Comic Sans MS',
162 'size' : 8,
163 'size2': 6,
164 }
165 else:
166 faces = { 'times': 'Times',
167 'mono' : 'Courier',
168 'helv' : 'Helvetica',
169 'other': 'new century schoolbook',
170 'size' : 8,
171 'size2': 6,
172 }
173
174
175 #----------------------------------------------------------------------
176
177 class PythonSTC(stc.StyledTextCtrl):
178
179 fold_symbols = 3
180
181 def __init__(self, parent, ID,
182 pos=wx.DefaultPosition, size=wx.DefaultSize,
183 style=0):
184 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
185 #self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
186 #self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
187
188 self.SetLexer(stc.STC_LEX_PYTHON)
189 self.SetKeyWords(0, " ".join(keyword.kwlist))
190
191 #self.SetProperty("fold", "1")
192 #self.SetProperty("tab.timmy.whinge.level", "1")
193 #self.SetMargins(0,0)
194
195 #self.SetViewWhiteSpace(False)
196 #self.SetBufferedDraw(False)
197 #self.SetViewEOL(True)
198 self.SetEOLMode(stc.STC_EOL_CRLF)
199 #self.SetUseAntiAliasing(True)
200
201 self.SetEdgeMode(stc.STC_EDGE_LINE)
202 self.SetEdgeColumn(80)
203 self.SetEdgeColour(wx.LIGHT_GREY)
204 self.SetLayoutCache(stc.STC_CACHE_PAGE)
205
206 # Setup a margin to hold fold markers
207 #self.SetFoldFlags(16)
208 ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
209 self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
210 self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
211 self.SetMarginSensitive(2, True)
212 self.SetMarginWidth(2, 12)
213
214 if self.fold_symbols == 0:
215 # Arrow pointing right for contracted folders,
216 # arrow pointing down for expanded
217 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
218 stc.STC_MARK_ARROWDOWN, "black", "black")
219 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
220 stc.STC_MARK_ARROW, "black", "black")
221 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
222 stc.STC_MARK_EMPTY, "black", "black")
223 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
224 stc.STC_MARK_EMPTY, "black", "black")
225 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
226 stc.STC_MARK_EMPTY, "white", "black")
227 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
228 stc.STC_MARK_EMPTY, "white", "black")
229 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
230 stc.STC_MARK_EMPTY, "white", "black")
231
232 elif self.fold_symbols == 1:
233 # Plus for contracted folders, minus for expanded
234 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
235 stc.STC_MARK_MINUS, "white", "black")
236 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
237 stc.STC_MARK_PLUS, "white", "black")
238 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
239 stc.STC_MARK_EMPTY, "white", "black")
240 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
241 stc.STC_MARK_EMPTY, "white", "black")
242 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
243 stc.STC_MARK_EMPTY, "white", "black")
244 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
245 stc.STC_MARK_EMPTY, "white", "black")
246 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
247 stc.STC_MARK_EMPTY, "white", "black")
248
249 elif self.fold_symbols == 2:
250 # Like a flattened tree control using circular headers and curved joins
251 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
252 stc.STC_MARK_CIRCLEMINUS, "white", "#404040")
253 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
254 stc.STC_MARK_CIRCLEPLUS, "white", "#404040")
255 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
256 stc.STC_MARK_VLINE, "white", "#404040")
257 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
258 stc.STC_MARK_LCORNERCURVE, "white", "#404040")
259 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
260 stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040")
261 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
262 stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040")
263 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
264 stc.STC_MARK_TCORNERCURVE, "white", "#404040")
265
266 elif self.fold_symbols == 3:
267 # Like a flattened tree control using square headers
268 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
269 stc.STC_MARK_BOXMINUS, "white", "#808080")
270 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
271 stc.STC_MARK_BOXPLUS, "white", "#808080")
272 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
273 stc.STC_MARK_VLINE, "white", "#808080")
274 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
275 stc.STC_MARK_LCORNER, "white", "#808080")
276 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
277 stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080")
278 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
279 stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
280 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
281 stc.STC_MARK_TCORNER, "white", "#808080")
282
283
284 self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
285 self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
286 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
287
288 # Make some styles, The lexer defines what each style is used for, we
289 # just have to define what each style looks like. This set is adapted from
290 # Scintilla sample property files.
291
292 # Global default styles for all languages
293 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
294 self.StyleClearAll() # Reset all to be like the default
295
296 # Global default styles for all languages
297 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
298 self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces)
299 self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces)
300 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold")
301 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
302
303 # Python styles
304 # Default
305 self.StyleSetSpec(stc.STC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
306 # Comments
307 self.StyleSetSpec(stc.STC_P_COMMENTLINE, "fore:#007F00,face:%(other)s,size:%(size)d" % faces)
308 # Number
309 self.StyleSetSpec(stc.STC_P_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
310 # String
311 self.StyleSetSpec(stc.STC_P_STRING, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
312 # Single quoted string
313 self.StyleSetSpec(stc.STC_P_CHARACTER, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
314 # Keyword
315 self.StyleSetSpec(stc.STC_P_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
316 # Triple quotes
317 self.StyleSetSpec(stc.STC_P_TRIPLE, "fore:#7F0000,size:%(size)d" % faces)
318 # Triple double quotes
319 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, "fore:#7F0000,size:%(size)d" % faces)
320 # Class name definition
321 self.StyleSetSpec(stc.STC_P_CLASSNAME, "fore:#0000FF,bold,underline,size:%(size)d" % faces)
322 # Function or method name definition
323 self.StyleSetSpec(stc.STC_P_DEFNAME, "fore:#007F7F,bold,size:%(size)d" % faces)
324 # Operators
325 self.StyleSetSpec(stc.STC_P_OPERATOR, "bold,size:%(size)d" % faces)
326 # Identifiers
327 self.StyleSetSpec(stc.STC_P_IDENTIFIER, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
328 # Comment-blocks
329 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, "fore:#7F7F7F,size:%(size)d" % faces)
330 # End of line where string is not closed
331 self.StyleSetSpec(stc.STC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces)
332
333 self.SetCaretForeground("BLUE")
334
335
336 # register some images for use in the AutoComplete box.
337 #self.RegisterImage(1, images.getSmilesBitmap())
338 #self.RegisterImage(2,
339 # wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16)))
340 #self.RegisterImage(3,
341 # wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16)))
342
343
344 def OnKeyPressed(self, event):
345 if self.CallTipActive():
346 self.CallTipCancel()
347 key = event.GetKeyCode()
348
349 if key == 32 and event.ControlDown():
350 pos = self.GetCurrentPos()
351
352 # Tips
353 if event.ShiftDown():
354 self.CallTipSetBackground("yellow")
355 self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n'
356 'show some suff, maybe parameters..\n\n'
357 'fubar(param1, param2)')
358 # Code completion
359 else:
360 #lst = []
361 #for x in range(50000):
362 # lst.append('%05d' % x)
363 #st = " ".join(lst)
364 #print len(st)
365 #self.AutoCompShow(0, st)
366
367 kw = keyword.kwlist[:]
368
369 kw.sort() # Python sorts are case sensitive
370 self.AutoCompSetIgnoreCase(False) # so this needs to match
371
372 # Images are specified with a appended "?type"
373 for i in range(len(kw)):
374 if kw[i] in keyword.kwlist:
375 kw[i] = kw[i]# + "?1"
376
377 self.AutoCompShow(0, " ".join(kw))
378 else:
379 event.Skip()
380
381
382 def OnUpdateUI(self, evt):
383 # check for matching braces
384 braceAtCaret = -1
385 braceOpposite = -1
386 charBefore = None
387 caretPos = self.GetCurrentPos()
388
389 if caretPos > 0:
390 charBefore = self.GetCharAt(caretPos - 1)
391 styleBefore = self.GetStyleAt(caretPos - 1)
392
393 # check before
394 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
395 braceAtCaret = caretPos - 1
396
397 # check after
398 if braceAtCaret < 0:
399 charAfter = self.GetCharAt(caretPos)
400 styleAfter = self.GetStyleAt(caretPos)
401
402 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
403 braceAtCaret = caretPos
404
405 if braceAtCaret >= 0:
406 braceOpposite = self.BraceMatch(braceAtCaret)
407
408 if braceAtCaret != -1 and braceOpposite == -1:
409 self.BraceBadLight(braceAtCaret)
410 else:
411 self.BraceHighlight(braceAtCaret, braceOpposite)
412 #pt = self.PointFromPosition(braceOpposite)
413 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
414 #print pt
415 #self.Refresh(False)
416
417
418 def OnMarginClick(self, evt):
419 # fold and unfold as needed
420 if evt.GetMargin() == 2:
421 if evt.GetShift() and evt.GetControl():
422 self.FoldAll()
423 else:
424 lineClicked = self.LineFromPosition(evt.GetPosition())
425
426 if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
427 if evt.GetShift():
428 self.SetFoldExpanded(lineClicked, True)
429 self.Expand(lineClicked, True, True, 1)
430 elif evt.GetControl():
431 if self.GetFoldExpanded(lineClicked):
432 self.SetFoldExpanded(lineClicked, False)
433 self.Expand(lineClicked, False, True, 0)
434 else:
435 self.SetFoldExpanded(lineClicked, True)
436 self.Expand(lineClicked, True, True, 100)
437 else:
438 self.ToggleFold(lineClicked)
439
440
441 def FoldAll(self):
442 lineCount = self.GetLineCount()
443 expanding = True
444
445 # find out if we are folding or unfolding
446 for lineNum in range(lineCount):
447 if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
448 expanding = not self.GetFoldExpanded(lineNum)
449 break
450
451 lineNum = 0
452
453 while lineNum < lineCount:
454 level = self.GetFoldLevel(lineNum)
455 if level & stc.STC_FOLDLEVELHEADERFLAG and \
456 (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
457
458 if expanding:
459 self.SetFoldExpanded(lineNum, True)
460 lineNum = self.Expand(lineNum, True)
461 lineNum = lineNum - 1
462 else:
463 lastChild = self.GetLastChild(lineNum, -1)
464 self.SetFoldExpanded(lineNum, False)
465
466 if lastChild > lineNum:
467 self.HideLines(lineNum+1, lastChild)
468
469 lineNum = lineNum + 1
470
471
472
473 def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
474 lastChild = self.GetLastChild(line, level)
475 line = line + 1
476
477 while line <= lastChild:
478 if force:
479 if visLevels > 0:
480 self.ShowLines(line, line)
481 else:
482 self.HideLines(line, line)
483 else:
484 if doExpand:
485 self.ShowLines(line, line)
486
487 if level == -1:
488 level = self.GetFoldLevel(line)
489
490 if level & stc.STC_FOLDLEVELHEADERFLAG:
491 if force:
492 if visLevels > 1:
493 self.SetFoldExpanded(line, True)
494 else:
495 self.SetFoldExpanded(line, False)
496
497 line = self.Expand(line, doExpand, force, visLevels-1)
498
499 else:
500 if doExpand and self.GetFoldExpanded(line):
501 line = self.Expand(line, True, force, visLevels-1)
502 else:
503 line = self.Expand(line, False, force, visLevels-1)
504 else:
505 line = line + 1
506
507 return line
508
509
510 #----------------------------------------------------------------------
This diff has been collapsed as it changes many lines, (942 lines changed) Show them Hide them
@@ -1,942 +0,0 b''
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 '''
4 Provides IPython WX console widgets.
5
6 @author: Laurent Dufrechou
7 laurent.dufrechou _at_ gmail.com
8 This WX widget is based on the original work of Eitan Isaacson
9 that provided the console for the GTK toolkit.
10
11 Original work from:
12 @author: Eitan Isaacson
13 @organization: IBM Corporation
14 @copyright: Copyright (c) 2007 IBM Corporation
15 @license: BSD
16
17 All rights reserved. This program and the accompanying materials are made
18 available under the terms of the BSD which accompanies this distribution, and
19 is available at U{http://www.opensource.org/licenses/bsd-license.php}
20 '''
21
22 __version__ = 0.9
23 __author__ = "Laurent Dufrechou"
24 __email__ = "laurent.dufrechou _at_ gmail.com"
25 __license__ = "BSD"
26
27 import wx
28 import wx.stc as stc
29
30 import re
31 from StringIO import StringIO
32
33 import sys
34 import codecs
35 import locale
36 import time
37
38 for enc in (locale.getpreferredencoding(),
39 sys.getfilesystemencoding(),
40 sys.getdefaultencoding()):
41 try:
42 codecs.lookup(enc)
43 ENCODING = enc
44 break
45 except LookupError:
46 pass
47 else:
48 ENCODING = 'utf-8'
49
50 from ipshell_nonblocking import NonBlockingIPShell
51
52 class WxNonBlockingIPShell(NonBlockingIPShell):
53 '''
54 An NonBlockingIPShell Thread that is WX dependent.
55 '''
56 def __init__(self, parent,
57 argv=[],user_ns={},user_global_ns=None,
58 cin=None, cout=None, cerr=None,
59 ask_exit_handler=None):
60
61 NonBlockingIPShell.__init__(self, argv, user_ns, user_global_ns,
62 cin, cout, cerr,
63 ask_exit_handler)
64
65 self.parent = parent
66
67 self.ask_exit_callback = ask_exit_handler
68 self._IP.exit = self._ask_exit
69
70 def addGUIShortcut(self, text, func):
71 wx.CallAfter(self.parent.add_button_handler,
72 button_info={ 'text':text,
73 'func':self.parent.doExecuteLine(func)})
74
75 def _raw_input(self, prompt=''):
76 """ A replacement from python's raw_input.
77 """
78 self.answer = None
79 if(self._threading == True):
80 wx.CallAfter(self._yesNoBox, prompt)
81 while self.answer is None:
82 time.sleep(.1)
83 else:
84 self._yesNoBox(prompt)
85 return self.answer
86
87 def _yesNoBox(self, prompt):
88 """ yes/no box managed with wx.CallAfter jsut in case caler is executed in a thread"""
89 dlg = wx.TextEntryDialog(
90 self.parent, prompt,
91 'Input requested', 'Python')
92 dlg.SetValue("")
93
94 answer = ''
95 if dlg.ShowModal() == wx.ID_OK:
96 answer = dlg.GetValue()
97
98 dlg.Destroy()
99 self.answer = answer
100
101 def _ask_exit(self):
102 wx.CallAfter(self.ask_exit_callback, ())
103
104 def _after_execute(self):
105 wx.CallAfter(self.parent.evtStateExecuteDone, ())
106
107
108 class WxConsoleView(stc.StyledTextCtrl):
109 '''
110 Specialized styled text control view for console-like workflow.
111 We use here a scintilla frontend thus it can be reused in any GUI that
112 supports scintilla with less work.
113
114 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.
115 (with Black background)
116 @type ANSI_COLORS_BLACK: dictionary
117
118 @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.
119 (with White background)
120 @type ANSI_COLORS_WHITE: dictionary
121
122 @ivar color_pat: Regex of terminal color pattern
123 @type color_pat: _sre.SRE_Pattern
124 '''
125 ANSI_STYLES_BLACK = {'0;30': [0, 'WHITE'], '0;31': [1, 'RED'],
126 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
127 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
128 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
129 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
130 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
131 '1;34': [12, 'LIGHT BLUE'], '1;35':
132 [13, 'MEDIUM VIOLET RED'],
133 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
134
135 ANSI_STYLES_WHITE = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
136 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
137 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
138 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
139 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
140 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
141 '1;34': [12, 'LIGHT BLUE'], '1;35':
142 [13, 'MEDIUM VIOLET RED'],
143 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
144
145 def __init__(self, parent, prompt, intro="", background_color="BLACK",
146 pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
147 style=0, autocomplete_mode = 'IPYTHON'):
148 '''
149 Initialize console view.
150
151 @param parent: Parent widget
152 @param prompt: User specified prompt
153 @type intro: string
154 @param intro: User specified startup introduction string
155 @type intro: string
156 @param background_color: Can be BLACK or WHITE
157 @type background_color: string
158 @param other: init param of styledTextControl (can be used as-is)
159 @param autocomplete_mode: Can be 'IPYTHON' or 'STC'
160 'IPYTHON' show autocompletion the ipython way
161 'STC" show it scintilla text control way
162 '''
163 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
164
165 ####### Scintilla configuration ###################################
166
167 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
168 # the widget
169 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
170 self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
171
172 #We draw a line at position 80
173 self.SetEdgeMode(stc.STC_EDGE_LINE)
174 self.SetEdgeColumn(80)
175 self.SetEdgeColour(wx.LIGHT_GREY)
176
177 #self.SetViewWhiteSpace(True)
178 #self.SetViewEOL(True)
179 self.SetEOLMode(stc.STC_EOL_CRLF)
180 #self.SetWrapMode(stc.STC_WRAP_CHAR)
181 #self.SetWrapMode(stc.STC_WRAP_WORD)
182 self.SetBufferedDraw(True)
183 #self.SetUseAntiAliasing(True)
184 self.SetLayoutCache(stc.STC_CACHE_PAGE)
185 self.SetUndoCollection(False)
186 self.SetUseTabs(True)
187 self.SetIndent(4)
188 self.SetTabWidth(4)
189
190 self.EnsureCaretVisible()
191
192 self.SetMargins(3, 3) #text is moved away from border with 3px
193 # Suppressing Scintilla margins
194 self.SetMarginWidth(0, 0)
195 self.SetMarginWidth(1, 0)
196 self.SetMarginWidth(2, 0)
197
198 self.background_color = background_color
199 self.buildStyles()
200
201 self.indent = 0
202 self.prompt_count = 0
203 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
204
205 self.write(intro)
206 self.setPrompt(prompt)
207 self.showPrompt()
208
209 self.autocomplete_mode = autocomplete_mode
210
211 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress)
212
213 def buildStyles(self):
214 #we define platform specific fonts
215 if wx.Platform == '__WXMSW__':
216 faces = { 'times': 'Times New Roman',
217 'mono' : 'Courier New',
218 'helv' : 'Arial',
219 'other': 'Comic Sans MS',
220 'size' : 10,
221 'size2': 8,
222 }
223 elif wx.Platform == '__WXMAC__':
224 faces = { 'times': 'Times New Roman',
225 'mono' : 'Monaco',
226 'helv' : 'Arial',
227 'other': 'Comic Sans MS',
228 'size' : 10,
229 'size2': 8,
230 }
231 else:
232 faces = { 'times': 'Times',
233 'mono' : 'Courier',
234 'helv' : 'Helvetica',
235 'other': 'new century schoolbook',
236 'size' : 10,
237 'size2': 8,
238 }
239
240 # make some styles
241 if self.background_color != "BLACK":
242 self.background_color = "WHITE"
243 self.SetCaretForeground("BLACK")
244 self.ANSI_STYLES = self.ANSI_STYLES_WHITE
245 else:
246 self.SetCaretForeground("WHITE")
247 self.ANSI_STYLES = self.ANSI_STYLES_BLACK
248
249 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
250 "fore:%s,back:%s,size:%d,face:%s"
251 % (self.ANSI_STYLES['0;30'][1],
252 self.background_color,
253 faces['size'], faces['mono']))
254 self.StyleClearAll()
255 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
256 "fore:#FF0000,back:#0000FF,bold")
257 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
258 "fore:#000000,back:#FF0000,bold")
259
260 for style in self.ANSI_STYLES.values():
261 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
262
263 #######################################################################
264
265 def setBackgroundColor(self, color):
266 self.background_color = color
267 self.buildStyles()
268
269 def getBackgroundColor(self, color):
270 return self.background_color
271
272 def asyncWrite(self, text):
273 '''
274 Write given text to buffer in an asynchroneous way.
275 It is used from another thread to be able to acces the GUI.
276 @param text: Text to append
277 @type text: string
278 '''
279 try:
280 wx.MutexGuiEnter()
281
282 #be sure not to be interrutpted before the MutexGuiLeave!
283 self.write(text)
284
285 except KeyboardInterrupt:
286 wx.MutexGuiLeave()
287 raise KeyboardInterrupt
288 wx.MutexGuiLeave()
289
290
291 def write(self, text):
292 '''
293 Write given text to buffer.
294
295 @param text: Text to append.
296 @type text: string
297 '''
298 segments = self.color_pat.split(text)
299 segment = segments.pop(0)
300 self.StartStyling(self.getCurrentLineEnd(), 0xFF)
301 self.AppendText(segment)
302
303 if segments:
304 ansi_tags = self.color_pat.findall(text)
305
306 for tag in ansi_tags:
307 i = segments.index(tag)
308 self.StartStyling(self.getCurrentLineEnd(), 0xFF)
309 self.AppendText(segments[i+1])
310
311 if tag != '0':
312 self.SetStyling(len(segments[i+1]), self.ANSI_STYLES[tag][0])
313
314 segments.pop(i)
315
316 self.moveCursor(self.getCurrentLineEnd())
317
318 def getPromptLen(self):
319 '''
320 Return the length of current prompt
321 '''
322 return len(str(self.prompt_count)) + 7
323
324 def setPrompt(self, prompt):
325 self.prompt = prompt
326
327 def setIndentation(self, indentation):
328 self.indent = indentation
329
330 def setPromptCount(self, count):
331 self.prompt_count = count
332
333 def showPrompt(self):
334 '''
335 Prints prompt at start of line.
336
337 @param prompt: Prompt to print.
338 @type prompt: string
339 '''
340 self.write(self.prompt)
341 #now we update the position of end of prompt
342 self.current_start = self.getCurrentLineEnd()
343
344 autoindent = self.indent*' '
345 autoindent = autoindent.replace(' ','\t')
346 self.write(autoindent)
347
348 def changeLine(self, text):
349 '''
350 Replace currently entered command line with given text.
351
352 @param text: Text to use as replacement.
353 @type text: string
354 '''
355 self.SetSelection(self.getCurrentPromptStart(), self.getCurrentLineEnd())
356 self.ReplaceSelection(text)
357 self.moveCursor(self.getCurrentLineEnd())
358
359 def getCurrentPromptStart(self):
360 return self.current_start
361
362 def getCurrentLineStart(self):
363 return self.GotoLine(self.LineFromPosition(self.GetCurrentPos()))
364
365 def getCurrentLineEnd(self):
366 return self.GetLength()
367
368 def getCurrentLine(self):
369 '''
370 Get text in current command line.
371
372 @return: Text of current command line.
373 @rtype: string
374 '''
375 return self.GetTextRange(self.getCurrentPromptStart(),
376 self.getCurrentLineEnd())
377
378 def moveCursorOnNewValidKey(self):
379 #If cursor is at wrong position put it at last line...
380 if self.GetCurrentPos() < self.getCurrentPromptStart():
381 self.GotoPos(self.getCurrentPromptStart())
382
383 def removeFromTo(self, from_pos, to_pos):
384 if from_pos < to_pos:
385 self.SetSelection(from_pos, to_pos)
386 self.DeleteBack()
387
388 def removeCurrentLine(self):
389 self.LineDelete()
390
391 def moveCursor(self, position):
392 self.GotoPos(position)
393
394 def getCursorPos(self):
395 return self.GetCurrentPos()
396
397 def selectFromTo(self, from_pos, to_pos):
398 self.SetSelectionStart(from_pos)
399 self.SetSelectionEnd(to_pos)
400
401 def writeHistory(self, history):
402 self.removeFromTo(self.getCurrentPromptStart(), self.getCurrentLineEnd())
403 self.changeLine(history)
404
405 def setCompletionMethod(self, completion):
406 if completion in ['IPYTHON', 'STC']:
407 self.autocomplete_mode = completion
408 else:
409 raise AttributeError
410
411 def getCompletionMethod(self, completion):
412 return self.autocomplete_mode
413
414 def writeCompletion(self, possibilities):
415 if self.autocomplete_mode == 'IPYTHON':
416 max_len = len(max(possibilities, key=len))
417 max_symbol = ' '*max_len
418
419 #now we check how much symbol we can put on a line...
420 test_buffer = max_symbol + ' '*4
421
422 allowed_symbols = 80/len(test_buffer)
423 if allowed_symbols == 0:
424 allowed_symbols = 1
425
426 pos = 1
427 buf = ''
428 for symbol in possibilities:
429 #buf += symbol+'\n'#*spaces)
430 if pos < allowed_symbols:
431 spaces = max_len - len(symbol) + 4
432 buf += symbol+' '*spaces
433 pos += 1
434 else:
435 buf += symbol+'\n'
436 pos = 1
437 self.write(buf)
438 else:
439 possibilities.sort() # Python sorts are case sensitive
440 self.AutoCompSetIgnoreCase(False)
441 self.AutoCompSetAutoHide(False)
442 #let compute the length ot last word
443 splitter = [' ', '(', '[', '{','=']
444 last_word = self.getCurrentLine()
445 for breaker in splitter:
446 last_word = last_word.split(breaker)[-1]
447 self.AutoCompShow(len(last_word), " ".join(possibilities))
448
449 def _onKeypress(self, event, skip=True):
450 '''
451 Key press callback used for correcting behavior for console-like
452 interfaces. For example 'home' should go to prompt, not to begining of
453 line.
454
455 @param widget: Widget that key press accored in.
456 @type widget: gtk.Widget
457 @param event: Event object
458 @type event: gtk.gdk.Event
459
460 @return: Return True if event as been catched.
461 @rtype: boolean
462 '''
463 if not self.AutoCompActive():
464 if event.GetKeyCode() == wx.WXK_HOME:
465 if event.Modifiers == wx.MOD_NONE:
466 self.moveCursorOnNewValidKey()
467 self.moveCursor(self.getCurrentPromptStart())
468 return True
469 elif event.Modifiers == wx.MOD_SHIFT:
470 self.moveCursorOnNewValidKey()
471 self.selectFromTo(self.getCurrentPromptStart(), self.getCursorPos())
472 return True
473 else:
474 return False
475
476 elif event.GetKeyCode() == wx.WXK_LEFT:
477 if event.Modifiers == wx.MOD_NONE:
478 self.moveCursorOnNewValidKey()
479
480 self.moveCursor(self.getCursorPos()-1)
481 if self.getCursorPos() < self.getCurrentPromptStart():
482 self.moveCursor(self.getCurrentPromptStart())
483 return True
484
485 elif event.GetKeyCode() == wx.WXK_BACK:
486 self.moveCursorOnNewValidKey()
487 if self.getCursorPos() > self.getCurrentPromptStart():
488 event.Skip()
489 return True
490
491 if skip:
492 if event.GetKeyCode() not in [wx.WXK_PAGEUP, wx.WXK_PAGEDOWN]\
493 and event.Modifiers == wx.MOD_NONE:
494 self.moveCursorOnNewValidKey()
495
496 event.Skip()
497 return True
498 return False
499 else:
500 event.Skip()
501
502 def OnUpdateUI(self, evt):
503 # check for matching braces
504 braceAtCaret = -1
505 braceOpposite = -1
506 charBefore = None
507 caretPos = self.GetCurrentPos()
508
509 if caretPos > 0:
510 charBefore = self.GetCharAt(caretPos - 1)
511 styleBefore = self.GetStyleAt(caretPos - 1)
512
513 # check before
514 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
515 braceAtCaret = caretPos - 1
516
517 # check after
518 if braceAtCaret < 0:
519 charAfter = self.GetCharAt(caretPos)
520 styleAfter = self.GetStyleAt(caretPos)
521
522 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
523 braceAtCaret = caretPos
524
525 if braceAtCaret >= 0:
526 braceOpposite = self.BraceMatch(braceAtCaret)
527
528 if braceAtCaret != -1 and braceOpposite == -1:
529 self.BraceBadLight(braceAtCaret)
530 else:
531 self.BraceHighlight(braceAtCaret, braceOpposite)
532 #pt = self.PointFromPosition(braceOpposite)
533 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
534 #print pt
535 #self.Refresh(False)
536
537 class IPShellWidget(wx.Panel):
538 '''
539 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
540 If you want to port this to any other GUI toolkit, just replace the
541 WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
542 from whatever container you want. I've choosed to derivate from a wx.Panel
543 because it seems to be more useful
544 Any idea to make it more 'generic' welcomed.
545 '''
546
547 def __init__(self, parent, intro=None,
548 background_color="BLACK", add_button_handler=None,
549 wx_ip_shell=None, user_ns={},user_global_ns=None,
550 ):
551 '''
552 Initialize.
553 Instanciate an IPython thread.
554 Instanciate a WxConsoleView.
555 Redirect I/O to console.
556 '''
557 wx.Panel.__init__(self,parent,wx.ID_ANY)
558
559 self.parent = parent
560 ### IPython non blocking shell instanciation ###
561 self.cout = StringIO()
562 self.add_button_handler = add_button_handler
563
564 if wx_ip_shell is not None:
565 self.IP = wx_ip_shell
566 else:
567 self.IP = WxNonBlockingIPShell(self,
568 cout = self.cout, cerr = self.cout,
569 ask_exit_handler = self.askExitCallback)
570
571 ### IPython wx console view instanciation ###
572 #If user didn't defined an intro text, we create one for him
573 #If you really wnat an empty intro just call wxIPythonViewPanel
574 #with intro=''
575 if intro is None:
576 welcome_text = "Welcome to WxIPython Shell.\n\n"
577 welcome_text+= self.IP.get_banner()
578 welcome_text+= "!command -> Execute command in shell\n"
579 welcome_text+= "TAB -> Autocompletion\n"
580 else:
581 welcome_text = intro
582
583 self.text_ctrl = WxConsoleView(self,
584 self.IP.get_prompt(),
585 intro=welcome_text,
586 background_color=background_color)
587
588 option_text = wx.StaticText(self, -1, "Options:")
589 self.completion_option = wx.CheckBox(self, -1, "Scintilla Completion")
590 self.completion_option.SetToolTip(wx.ToolTip(
591 "Selects the completion type:\nEither Ipython default style or Scintilla one"))
592 #self.completion_option.SetValue(False)
593 self.background_option = wx.CheckBox(self, -1, "White Background")
594 self.background_option.SetToolTip(wx.ToolTip(
595 "Selects the back ground color: BLACK or WHITE"))
596 #self.background_option.SetValue(False)
597 self.threading_option = wx.CheckBox(self, -1, "Execute in thread")
598 self.threading_option.SetToolTip(wx.ToolTip(
599 "Use threading: infinite loop don't freeze the GUI and commands can be breaked\nNo threading: maximum compatibility"))
600 #self.threading_option.SetValue(False)
601
602 self.options={'completion':{'value':'IPYTHON',
603 'checkbox':self.completion_option,'STC':True,'IPYTHON':False,
604 'setfunc':self.text_ctrl.setCompletionMethod},
605 'background_color':{'value':'BLACK',
606 'checkbox':self.background_option,'WHITE':True,'BLACK':False,
607 'setfunc':self.text_ctrl.setBackgroundColor},
608 'threading':{'value':'True',
609 'checkbox':self.threading_option,'True':True,'False':False,
610 'setfunc':self.IP.set_threading},
611 }
612
613 #self.cout.write dEfault option is asynchroneous because default sate is threading ON
614 self.cout.write = self.text_ctrl.asyncWrite
615 #we reloard options
616 self.reloadOptions(self.options)
617
618 self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress)
619 self.completion_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionCompletion)
620 self.background_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionBackgroundColor)
621 self.threading_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionThreading)
622
623 ### making the layout of the panel ###
624 sizer = wx.BoxSizer(wx.VERTICAL)
625 sizer.Add(self.text_ctrl, 1, wx.EXPAND)
626 option_sizer = wx.BoxSizer(wx.HORIZONTAL)
627 sizer.Add(option_sizer, 0)
628 option_sizer.AddMany([(10, 20),
629 (option_text, 0, wx.ALIGN_CENTER_VERTICAL),
630 (5, 5),
631 (self.completion_option, 0, wx.ALIGN_CENTER_VERTICAL),
632 (8, 8),
633 (self.background_option, 0, wx.ALIGN_CENTER_VERTICAL),
634 (8, 8),
635 (self.threading_option, 0, wx.ALIGN_CENTER_VERTICAL)
636 ])
637 self.SetAutoLayout(True)
638 sizer.Fit(self)
639 sizer.SetSizeHints(self)
640 self.SetSizer(sizer)
641 #and we focus on the widget :)
642 self.SetFocus()
643
644 #widget state management (for key handling different cases)
645 self.setCurrentState('IDLE')
646 self.pager_state = 'DONE'
647 self.raw_input_current_line = 0
648
649 def askExitCallback(self, event):
650 self.askExitHandler(event)
651
652 #---------------------- IPython Thread Management ------------------------
653 def stateDoExecuteLine(self):
654 lines=self.text_ctrl.getCurrentLine()
655 self.text_ctrl.write('\n')
656 lines_to_execute = lines.replace('\t',' '*4)
657 lines_to_execute = lines_to_execute.replace('\r','')
658 self.IP.do_execute(lines_to_execute.encode(ENCODING))
659 self.updateHistoryTracker(lines)
660 if(self.text_ctrl.getCursorPos()!=0):
661 self.text_ctrl.removeCurrentLine()
662 self.setCurrentState('WAIT_END_OF_EXECUTION')
663
664 def evtStateExecuteDone(self,evt):
665 self.doc = self.IP.get_doc_text()
666 self.help = self.IP.get_help_text()
667 if self.doc:
668 self.pager_lines = self.doc[7:].split('\n')
669 self.pager_state = 'INIT'
670 self.setCurrentState('SHOW_DOC')
671 self.pager(self.doc)
672 elif self.help:
673 self.pager_lines = self.help.split('\n')
674 self.pager_state = 'INIT'
675 self.setCurrentState('SHOW_DOC')
676 self.pager(self.help)
677 else:
678 if(self.text_ctrl.getCursorPos()!=0):
679 self.text_ctrl.removeCurrentLine()
680 self.stateShowPrompt()
681
682 def stateShowPrompt(self):
683 self.setCurrentState('SHOW_PROMPT')
684 self.text_ctrl.setPrompt(self.IP.get_prompt())
685 self.text_ctrl.setIndentation(self.IP.get_indentation())
686 self.text_ctrl.setPromptCount(self.IP.get_prompt_count())
687 self.text_ctrl.showPrompt()
688 self.IP.init_history_index()
689 self.setCurrentState('IDLE')
690
691 def setCurrentState(self, state):
692 self.cur_state = state
693 self.updateStatusTracker(self.cur_state)
694
695 def pager(self,text):
696
697 if self.pager_state == 'INIT':
698 #print >>sys.__stdout__,"PAGER state:",self.pager_state
699 self.pager_nb_lines = len(self.pager_lines)
700 self.pager_index = 0
701 self.pager_do_remove = False
702 self.text_ctrl.write('\n')
703 self.pager_state = 'PROCESS_LINES'
704
705 if self.pager_state == 'PROCESS_LINES':
706 #print >>sys.__stdout__,"PAGER state:",self.pager_state
707 if self.pager_do_remove == True:
708 self.text_ctrl.removeCurrentLine()
709 self.pager_do_remove = False
710
711 if self.pager_nb_lines > 10:
712 #print >>sys.__stdout__,"PAGER processing 10 lines"
713 if self.pager_index > 0:
714 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
715 else:
716 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
717
718 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
719 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
720 self.pager_index += 10
721 self.pager_nb_lines -= 10
722 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
723 self.pager_do_remove = True
724 self.pager_state = 'WAITING'
725 return
726 else:
727 #print >>sys.__stdout__,"PAGER processing last lines"
728 if self.pager_nb_lines > 0:
729 if self.pager_index > 0:
730 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
731 else:
732 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
733
734 self.pager_index += 1
735 self.pager_nb_lines -= 1
736 if self.pager_nb_lines > 0:
737 for line in self.pager_lines[self.pager_index:]:
738 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
739 self.pager_nb_lines = 0
740 self.pager_state = 'DONE'
741 self.stateShowPrompt()
742
743 #------------------------ Key Handler ------------------------------------
744 def keyPress(self, event):
745 '''
746 Key press callback with plenty of shell goodness, like history,
747 autocompletions, etc.
748 '''
749 if event.GetKeyCode() == ord('C'):
750 if event.Modifiers == wx.MOD_CONTROL or event.Modifiers == wx.MOD_ALT:
751 if self.cur_state == 'WAIT_END_OF_EXECUTION':
752 #we raise an exception inside the IPython thread container
753 self.IP.ce.raise_exc(KeyboardInterrupt)
754 return
755
756 #let this before 'wx.WXK_RETURN' because we have to put 'IDLE'
757 #mode if AutoComp has been set as inactive
758 if self.cur_state == 'COMPLETING':
759 if not self.text_ctrl.AutoCompActive():
760 self.cur_state = 'IDLE'
761 else:
762 event.Skip()
763
764 if event.KeyCode == wx.WXK_RETURN:
765 if self.cur_state == 'IDLE':
766 #we change the state ot the state machine
767 self.setCurrentState('DO_EXECUTE_LINE')
768 self.stateDoExecuteLine()
769 return
770
771 if self.pager_state == 'WAITING':
772 self.pager_state = 'PROCESS_LINES'
773 self.pager(self.doc)
774 return
775
776 if self.cur_state == 'WAITING_USER_INPUT':
777 line=self.text_ctrl.getCurrentLine()
778 self.text_ctrl.write('\n')
779 self.setCurrentState('WAIT_END_OF_EXECUTION')
780 return
781
782 if event.GetKeyCode() in [ord('q'),ord('Q')]:
783 if self.pager_state == 'WAITING':
784 self.pager_state = 'DONE'
785 self.text_ctrl.write('\n')
786 self.stateShowPrompt()
787 return
788
789 if self.cur_state == 'WAITING_USER_INPUT':
790 event.Skip()
791
792 if self.cur_state == 'IDLE':
793 if event.KeyCode == wx.WXK_UP:
794 history = self.IP.history_back()
795 self.text_ctrl.writeHistory(history)
796 return
797 if event.KeyCode == wx.WXK_DOWN:
798 history = self.IP.history_forward()
799 self.text_ctrl.writeHistory(history)
800 return
801 if event.KeyCode == wx.WXK_TAB:
802 #if line empty we disable tab completion
803 if not self.text_ctrl.getCurrentLine().strip():
804 self.text_ctrl.write('\t')
805 return
806 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
807 if len(possibilities) > 1:
808 if self.text_ctrl.autocomplete_mode == 'IPYTHON':
809 cur_slice = self.text_ctrl.getCurrentLine()
810 self.text_ctrl.write('\n')
811 self.text_ctrl.writeCompletion(possibilities)
812 self.text_ctrl.write('\n')
813
814 self.text_ctrl.showPrompt()
815 self.text_ctrl.write(cur_slice)
816 self.text_ctrl.changeLine(completed or cur_slice)
817 else:
818 self.cur_state = 'COMPLETING'
819 self.text_ctrl.writeCompletion(possibilities)
820 else:
821 self.text_ctrl.changeLine(completed or cur_slice)
822 return
823 event.Skip()
824
825 #------------------------ Option Section ---------------------------------
826 def evtCheckOptionCompletion(self, event):
827 if event.IsChecked():
828 self.options['completion']['value']='STC'
829 else:
830 self.options['completion']['value']='IPYTHON'
831 self.text_ctrl.setCompletionMethod(self.options['completion']['value'])
832 self.updateOptionTracker('completion',
833 self.options['completion']['value'])
834 self.text_ctrl.SetFocus()
835
836 def evtCheckOptionBackgroundColor(self, event):
837 if event.IsChecked():
838 self.options['background_color']['value']='WHITE'
839 else:
840 self.options['background_color']['value']='BLACK'
841 self.text_ctrl.setBackgroundColor(self.options['background_color']['value'])
842 self.updateOptionTracker('background_color',
843 self.options['background_color']['value'])
844 self.text_ctrl.SetFocus()
845
846 def evtCheckOptionThreading(self, event):
847 if event.IsChecked():
848 self.options['threading']['value']='True'
849 self.IP.set_threading(True)
850 self.cout.write = self.text_ctrl.asyncWrite
851 else:
852 self.options['threading']['value']='False'
853 self.IP.set_threading(False)
854 self.cout.write = self.text_ctrl.write
855 self.updateOptionTracker('threading',
856 self.options['threading']['value'])
857 self.text_ctrl.SetFocus()
858
859 def getOptions(self):
860 return self.options
861
862 def reloadOptions(self,options):
863 self.options = options
864 for key in self.options.keys():
865 value = self.options[key]['value']
866 self.options[key]['checkbox'].SetValue(self.options[key][value])
867 self.options[key]['setfunc'](value)
868
869 if self.options['threading']['value']=='True':
870 self.IP.set_threading(True)
871 self.cout.write = self.text_ctrl.asyncWrite
872 else:
873 self.IP.set_threading(False)
874 self.cout.write = self.text_ctrl.write
875
876 #------------------------ Hook Section -----------------------------------
877 def updateOptionTracker(self,name,value):
878 '''
879 Default history tracker (does nothing)
880 '''
881 pass
882
883 def setOptionTrackerHook(self,func):
884 '''
885 Define a new history tracker
886 '''
887 self.updateOptionTracker = func
888
889 def updateHistoryTracker(self,command_line):
890 '''
891 Default history tracker (does nothing)
892 '''
893 pass
894
895 def setHistoryTrackerHook(self,func):
896 '''
897 Define a new history tracker
898 '''
899 self.updateHistoryTracker = func
900
901 def updateStatusTracker(self,status):
902 '''
903 Default status tracker (does nothing)
904 '''
905 pass
906
907 def setStatusTrackerHook(self,func):
908 '''
909 Define a new status tracker
910 '''
911 self.updateStatusTracker = func
912
913 def askExitHandler(self, event):
914 '''
915 Default exit handler
916 '''
917 self.text_ctrl.write('\nExit callback has not been set.')
918
919 def setAskExitHandler(self, func):
920 '''
921 Define an exit handler
922 '''
923 self.askExitHandler = func
924
925 if __name__ == '__main__':
926 # Some simple code to test the shell widget.
927 class MainWindow(wx.Frame):
928 def __init__(self, parent, id, title):
929 wx.Frame.__init__(self, parent, id, title, size=(300,250))
930 self._sizer = wx.BoxSizer(wx.VERTICAL)
931 self.shell = IPShellWidget(self)
932 self._sizer.Add(self.shell, 1, wx.EXPAND)
933 self.SetSizer(self._sizer)
934 self.SetAutoLayout(1)
935 self.Show(True)
936
937 app = wx.PySimpleApp()
938 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
939 frame.SetSize((780, 460))
940 shell = frame.shell
941
942 app.MainLoop()
@@ -1,50 +0,0 b''
1 """
2 Thread subclass that can deal with asynchronously function calls via
3 raise_exc.
4 """
5
6 import threading
7 import inspect
8 import ctypes
9
10
11 def _async_raise(tid, exctype):
12 """raises the exception, performs cleanup if needed"""
13 if not inspect.isclass(exctype):
14 raise TypeError("Only types can be raised (not instances)")
15 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
16 if res == 0:
17 raise ValueError("invalid thread id")
18 elif res != 1:
19 # """if it returns a number greater than one, you're in trouble,
20 # and you should call it again with exc=NULL to revert the effect"""
21 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
22 raise SystemError("PyThreadState_SetAsyncExc failed")
23
24
25 class ThreadEx(threading.Thread):
26 def _get_my_tid(self):
27 """determines this (self's) thread id"""
28 if not self.isAlive():
29 raise threading.ThreadError("the thread is not active")
30
31 # do we have it cached?
32 if hasattr(self, "_thread_id"):
33 return self._thread_id
34
35 # no, look for it in the _active dict
36 for tid, tobj in threading._active.items():
37 if tobj is self:
38 self._thread_id = tid
39 return tid
40
41 raise AssertionError("could not determine the thread's id")
42
43 def raise_exc(self, exctype):
44 """raises the given exception type in the context of this thread"""
45 _async_raise(self._get_my_tid(), exctype)
46
47 def kill(self):
48 """raises SystemExit in the context of the given thread, which should
49 cause the thread to exit silently (unless caught)"""
50 self.raise_exc(SystemExit)
@@ -1,266 +0,0 b''
1 #!/usr/bin/python
2 # -*- coding: iso-8859-15 -*-
3
4 import wx.aui
5 import sys
6 #used for about dialog
7 from wx.lib.wordwrap import wordwrap
8
9 #used for ipython GUI objects
10 from IPython.gui.wx.ipython_view import IPShellWidget
11 from IPython.gui.wx.ipython_history import IPythonHistoryPanel
12
13 #used to invoke ipython1 wx implementation
14 ### FIXME ### temporary disabled due to interference with 'show_in_pager' hook
15 is_sync_frontend_ok = False
16 try:
17 from IPython.frontend.wx.ipythonx import IPythonXController
18 except ImportError:
19 is_sync_frontend_ok = False
20
21 #used to create options.conf file in user directory
22 from IPython.core.ipapi import get
23
24 __version__ = 0.91
25 __author__ = "Laurent Dufrechou"
26 __email__ = "laurent.dufrechou _at_ gmail.com"
27 __license__ = "BSD"
28
29 #-----------------------------------------
30 # Creating one main frame for our
31 # application with movables windows
32 #-----------------------------------------
33 class MyFrame(wx.Frame):
34 """Creating one main frame for our
35 application with movables windows"""
36 def __init__(self, parent=None, id=-1, title="WxIPython",
37 pos=wx.DefaultPosition,
38 size=(800, 600), style=wx.DEFAULT_FRAME_STYLE, sync_ok=False):
39 wx.Frame.__init__(self, parent, id, title, pos, size, style)
40 self._mgr = wx.aui.AuiManager()
41
42 # notify PyAUI which frame to use
43 self._mgr.SetManagedWindow(self)
44
45 #create differents panels and make them persistant
46 self.history_panel = IPythonHistoryPanel(self)
47
48 self.history_panel.setOptionTrackerHook(self.optionSave)
49
50 self.ipython_panel = IPShellWidget(self,background_color = "BLACK")
51 #self.ipython_panel = IPShellWidget(self,background_color = "WHITE")
52 if(sync_ok):
53 self.ipython_panel2 = IPythonXController(self)
54 else:
55 self.ipython_panel2 = None
56 self.ipython_panel.setHistoryTrackerHook(self.history_panel.write)
57 self.ipython_panel.setStatusTrackerHook(self.updateStatus)
58 self.ipython_panel.setAskExitHandler(self.OnExitDlg)
59 self.ipython_panel.setOptionTrackerHook(self.optionSave)
60
61 #Create a notebook to display different IPython shell implementations
62 self.nb = wx.aui.AuiNotebook(self)
63
64 self.optionLoad()
65
66 self.statusbar = self.createStatus()
67 self.createMenu()
68
69 ########################################################################
70 ### add the panes to the manager
71 # main panels
72 self._mgr.AddPane(self.nb , wx.CENTER, "IPython Shells")
73 self.nb.AddPage(self.ipython_panel , "IPython0 Shell")
74 if(sync_ok):
75 self.nb.AddPage(self.ipython_panel2, "IPython1 Synchroneous Shell")
76
77 self._mgr.AddPane(self.history_panel , wx.RIGHT, "IPython history")
78
79 # now we specify some panel characteristics
80 self._mgr.GetPane(self.ipython_panel).CaptionVisible(True);
81 self._mgr.GetPane(self.history_panel).CaptionVisible(True);
82 self._mgr.GetPane(self.history_panel).MinSize((200,400));
83
84 # tell the manager to "commit" all the changes just made
85 self._mgr.Update()
86
87 #global event handling
88 self.Bind(wx.EVT_CLOSE, self.OnClose)
89 self.Bind(wx.EVT_MENU, self.OnClose,id=wx.ID_EXIT)
90 self.Bind(wx.EVT_MENU, self.OnShowIPythonPanel,id=wx.ID_HIGHEST+1)
91 self.Bind(wx.EVT_MENU, self.OnShowHistoryPanel,id=wx.ID_HIGHEST+2)
92 self.Bind(wx.EVT_MENU, self.OnShowAbout, id=wx.ID_HIGHEST+3)
93 self.Bind(wx.EVT_MENU, self.OnShowAllPanel,id=wx.ID_HIGHEST+6)
94
95 warn_text = 'Hello from IPython and wxPython.\n'
96 warn_text +='Please Note that this work is still EXPERIMENTAL\n'
97 warn_text +='It does NOT emulate currently all the IPython functions.\n'
98 warn_text +="\nIf you use MATPLOTLIB with show() you'll need to deactivate the THREADING option.\n"
99 if(not sync_ok):
100 warn_text +="\n->No twisted package detected, IPython1 example deactivated."
101
102 dlg = wx.MessageDialog(self,
103 warn_text,
104 'Warning Box',
105 wx.OK | wx.ICON_INFORMATION
106 )
107 dlg.ShowModal()
108 dlg.Destroy()
109
110 def optionSave(self, name, value):
111 ip = get()
112 path = ip.ipython_dir
113 opt = open(path + '/options.conf','w')
114
115 try:
116 options_ipython_panel = self.ipython_panel.getOptions()
117 options_history_panel = self.history_panel.getOptions()
118
119 for key in options_ipython_panel.keys():
120 opt.write(key + '=' + options_ipython_panel[key]['value']+'\n')
121 for key in options_history_panel.keys():
122 opt.write(key + '=' + options_history_panel[key]['value']+'\n')
123 finally:
124 opt.close()
125
126 def optionLoad(self):
127 try:
128 ip = get()
129 path = ip.ipython_dir
130 opt = open(path + '/options.conf','r')
131 lines = opt.readlines()
132 opt.close()
133
134 options_ipython_panel = self.ipython_panel.getOptions()
135 options_history_panel = self.history_panel.getOptions()
136
137 for line in lines:
138 key = line.split('=')[0]
139 value = line.split('=')[1].replace('\n','').replace('\r','')
140 if key in options_ipython_panel.keys():
141 options_ipython_panel[key]['value'] = value
142 elif key in options_history_panel.keys():
143 options_history_panel[key]['value'] = value
144 else:
145 print >>sys.__stdout__,"Warning: key ",key,"not found in widget options. Check Options.conf"
146 self.ipython_panel.reloadOptions(options_ipython_panel)
147 self.history_panel.reloadOptions(options_history_panel)
148
149 except IOError:
150 print >>sys.__stdout__,"Could not open Options.conf, defaulting to default values."
151
152
153 def createMenu(self):
154 """local method used to create one menu bar"""
155
156 mb = wx.MenuBar()
157
158 file_menu = wx.Menu()
159 file_menu.Append(wx.ID_EXIT, "Exit")
160
161 view_menu = wx.Menu()
162 view_menu.Append(wx.ID_HIGHEST+1, "Show IPython Panel")
163 view_menu.Append(wx.ID_HIGHEST+2, "Show History Panel")
164 view_menu.AppendSeparator()
165 view_menu.Append(wx.ID_HIGHEST+6, "Show All")
166
167 about_menu = wx.Menu()
168 about_menu.Append(wx.ID_HIGHEST+3, "About")
169
170 mb.Append(file_menu, "File")
171 mb.Append(view_menu, "View")
172 mb.Append(about_menu, "About")
173 #mb.Append(options_menu, "Options")
174
175 self.SetMenuBar(mb)
176
177 def createStatus(self):
178 statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP)
179 statusbar.SetStatusWidths([-2, -3])
180 statusbar.SetStatusText("Ready", 0)
181 statusbar.SetStatusText("WxIPython "+str(__version__), 1)
182 return statusbar
183
184 def updateStatus(self,text):
185 states = {'IDLE':'Idle',
186 'DO_EXECUTE_LINE':'Send command',
187 'WAIT_END_OF_EXECUTION':'Running command',
188 'WAITING_USER_INPUT':'Waiting user input',
189 'SHOW_DOC':'Showing doc',
190 'SHOW_PROMPT':'Showing prompt'}
191 self.statusbar.SetStatusText(states[text], 0)
192
193 def OnClose(self, event):
194 """#event used to close program """
195 # deinitialize the frame manager
196 self._mgr.UnInit()
197 self.Destroy()
198 event.Skip()
199
200 def OnExitDlg(self, event):
201 dlg = wx.MessageDialog(self, 'Are you sure you want to quit WxIPython',
202 'WxIPython exit',
203 wx.ICON_QUESTION |
204 wx.YES_NO | wx.NO_DEFAULT
205 )
206 if dlg.ShowModal() == wx.ID_YES:
207 dlg.Destroy()
208 self._mgr.UnInit()
209 self.Destroy()
210 dlg.Destroy()
211
212 #event to display IPython pannel
213 def OnShowIPythonPanel(self,event):
214 """ #event to display Boxpannel """
215 self._mgr.GetPane(self.ipython_panel).Show(True)
216 self._mgr.Update()
217 #event to display History pannel
218 def OnShowHistoryPanel(self,event):
219 self._mgr.GetPane(self.history_panel).Show(True)
220 self._mgr.Update()
221
222 def OnShowAllPanel(self,event):
223 """#event to display all Pannels"""
224 self._mgr.GetPane(self.ipython_panel).Show(True)
225 self._mgr.GetPane(self.history_panel).Show(True)
226 self._mgr.Update()
227
228 def OnShowAbout(self, event):
229 # First we create and fill the info object
230 info = wx.AboutDialogInfo()
231 info.Name = "WxIPython"
232 info.Version = str(__version__)
233 info.Copyright = "(C) 2007 Laurent Dufrechou"
234 info.Description = wordwrap(
235 "A Gui that embbed a multithreaded IPython Shell",
236 350, wx.ClientDC(self))
237 info.WebSite = ("http://ipython.scipy.org/", "IPython home page")
238 info.Developers = [ "Laurent Dufrechou" ]
239 licenseText="BSD License.\nAll rights reserved. This program and the accompanying materials are made available under the terms of the BSD which accompanies this distribution, and is available at http://www.opensource.org/licenses/bsd-license.php"
240 info.License = wordwrap(licenseText, 500, wx.ClientDC(self))
241
242 # Then we call wx.AboutBox giving it that info object
243 wx.AboutBox(info)
244
245 #-----------------------------------------
246 #Creating our application
247 #-----------------------------------------
248 class MyApp(wx.PySimpleApp):
249 """Creating our application"""
250 def __init__(self, sync_ok=False):
251 wx.PySimpleApp.__init__(self)
252
253 self.frame = MyFrame(sync_ok=sync_ok)
254 self.frame.Show()
255
256 #-----------------------------------------
257 #Main loop
258 #-----------------------------------------
259 def main():
260 app = MyApp(is_sync_frontend_ok)
261 app.SetTopWindow(app.frame)
262 app.MainLoop()
263
264 #if launched as main program run this
265 if __name__ == '__main__':
266 main()
This diff has been collapsed as it changes many lines, (1767 lines changed) Show them Hide them
@@ -1,1767 +0,0 b''
1 # -*- coding: iso-8859-1 -*-
2
3 import curses, fcntl, signal, struct, tty, textwrap, inspect
4
5 from IPython.core import ipapi
6
7 import astyle, ipipe
8
9
10 # Python 2.3 compatibility
11 try:
12 set
13 except NameError:
14 import sets
15 set = sets.Set
16
17 # Python 2.3 compatibility
18 try:
19 sorted
20 except NameError:
21 from ipipe import sorted
22
23
24 class UnassignedKeyError(Exception):
25 """
26 Exception that is used for reporting unassigned keys.
27 """
28
29
30 class UnknownCommandError(Exception):
31 """
32 Exception that is used for reporting unknown commands (this should never
33 happen).
34 """
35
36
37 class CommandError(Exception):
38 """
39 Exception that is used for reporting that a command can't be executed.
40 """
41
42
43 class Keymap(dict):
44 """
45 Stores mapping of keys to commands.
46 """
47 def __init__(self):
48 self._keymap = {}
49
50 def __setitem__(self, key, command):
51 if isinstance(key, str):
52 for c in key:
53 dict.__setitem__(self, ord(c), command)
54 else:
55 dict.__setitem__(self, key, command)
56
57 def __getitem__(self, key):
58 if isinstance(key, str):
59 key = ord(key)
60 return dict.__getitem__(self, key)
61
62 def __detitem__(self, key):
63 if isinstance(key, str):
64 key = ord(key)
65 dict.__detitem__(self, key)
66
67 def register(self, command, *keys):
68 for key in keys:
69 self[key] = command
70
71 def get(self, key, default=None):
72 if isinstance(key, str):
73 key = ord(key)
74 return dict.get(self, key, default)
75
76 def findkey(self, command, default=ipipe.noitem):
77 for (key, commandcandidate) in self.iteritems():
78 if commandcandidate == command:
79 return key
80 if default is ipipe.noitem:
81 raise KeyError(command)
82 return default
83
84
85 class _BrowserCachedItem(object):
86 # This is used internally by ``ibrowse`` to store a item together with its
87 # marked status.
88 __slots__ = ("item", "marked")
89
90 def __init__(self, item):
91 self.item = item
92 self.marked = False
93
94
95 class _BrowserHelp(object):
96 style_header = astyle.Style.fromstr("yellow:black:bold")
97 # This is used internally by ``ibrowse`` for displaying the help screen.
98 def __init__(self, browser):
99 self.browser = browser
100
101 def __xrepr__(self, mode):
102 yield (-1, True)
103 if mode == "header" or mode == "footer":
104 yield (astyle.style_default, "ibrowse help screen")
105 else:
106 yield (astyle.style_default, repr(self))
107
108 def __iter__(self):
109 # Get reverse key mapping
110 allkeys = {}
111 for (key, cmd) in self.browser.keymap.iteritems():
112 allkeys.setdefault(cmd, []).append(key)
113
114 fields = ("key", "description")
115
116 commands = []
117 for name in dir(self.browser):
118 if name.startswith("cmd_"):
119 command = getattr(self.browser, name)
120 commands.append((inspect.getsourcelines(command)[-1], name[4:], command))
121 commands.sort()
122 commands = [(c[1], c[2]) for c in commands]
123 for (i, (name, command)) in enumerate(commands):
124 if i:
125 yield ipipe.Fields(fields, key="", description="")
126
127 description = command.__doc__
128 if description is None:
129 lines = []
130 else:
131 lines = [l.strip() for l in description.splitlines() if l.strip()]
132 description = "\n".join(lines)
133 lines = textwrap.wrap(description, 60)
134 keys = allkeys.get(name, [])
135
136 yield ipipe.Fields(fields, key="", description=astyle.Text((self.style_header, name)))
137 for i in xrange(max(len(keys), len(lines))):
138 try:
139 key = self.browser.keylabel(keys[i])
140 except IndexError:
141 key = ""
142 try:
143 line = lines[i]
144 except IndexError:
145 line = ""
146 yield ipipe.Fields(fields, key=key, description=line)
147
148
149 class _BrowserLevel(object):
150 # This is used internally to store the state (iterator, fetch items,
151 # position of cursor and screen, etc.) of one browser level
152 # An ``ibrowse`` object keeps multiple ``_BrowserLevel`` objects in
153 # a stack.
154 def __init__(self, browser, input, mainsizey, *attrs):
155 self.browser = browser
156 self.input = input
157 self.header = [x for x in ipipe.xrepr(input, "header") if not isinstance(x[0], int)]
158 # iterator for the input
159 self.iterator = ipipe.xiter(input)
160
161 # is the iterator exhausted?
162 self.exhausted = False
163
164 # attributes to be display (autodetected if empty)
165 self.attrs = attrs
166
167 # fetched items (+ marked flag)
168 self.items = ipipe.deque()
169
170 # Number of marked objects
171 self.marked = 0
172
173 # Vertical cursor position
174 self.cury = 0
175
176 # Horizontal cursor position
177 self.curx = 0
178
179 # Index of first data column
180 self.datastartx = 0
181
182 # Index of first data line
183 self.datastarty = 0
184
185 # height of the data display area
186 self.mainsizey = mainsizey
187
188 # width of the data display area (changes when scrolling)
189 self.mainsizex = 0
190
191 # Size of row number (changes when scrolling)
192 self.numbersizex = 0
193
194 # Attributes to display (in this order)
195 self.displayattrs = []
196
197 # index and attribute under the cursor
198 self.displayattr = (None, ipipe.noitem)
199
200 # Maps attributes to column widths
201 self.colwidths = {}
202
203 # Set of hidden attributes
204 self.hiddenattrs = set()
205
206 # This takes care of all the caches etc.
207 self.moveto(0, 0, refresh=True)
208
209 def fetch(self, count):
210 # Try to fill ``self.items`` with at least ``count`` objects.
211 have = len(self.items)
212 while not self.exhausted and have < count:
213 try:
214 item = self.iterator.next()
215 except StopIteration:
216 self.exhausted = True
217 break
218 except (KeyboardInterrupt, SystemExit):
219 raise
220 except Exception as exc:
221 have += 1
222 self.items.append(_BrowserCachedItem(exc))
223 self.exhausted = True
224 break
225 else:
226 have += 1
227 self.items.append(_BrowserCachedItem(item))
228
229 def calcdisplayattrs(self):
230 # Calculate which attributes are available from the objects that are
231 # currently visible on screen (and store it in ``self.displayattrs``)
232
233 attrs = set()
234 self.displayattrs = []
235 if self.attrs:
236 # If the browser object specifies a fixed list of attributes,
237 # simply use it (removing hidden attributes).
238 for attr in self.attrs:
239 attr = ipipe.upgradexattr(attr)
240 if attr not in attrs and attr not in self.hiddenattrs:
241 self.displayattrs.append(attr)
242 attrs.add(attr)
243 else:
244 endy = min(self.datastarty+self.mainsizey, len(self.items))
245 for i in xrange(self.datastarty, endy):
246 for attr in ipipe.xattrs(self.items[i].item, "default"):
247 if attr not in attrs and attr not in self.hiddenattrs:
248 self.displayattrs.append(attr)
249 attrs.add(attr)
250
251 def getrow(self, i):
252 # Return a dictionary with the attributes for the object
253 # ``self.items[i]``. Attribute names are taken from
254 # ``self.displayattrs`` so ``calcdisplayattrs()`` must have been
255 # called before.
256 row = {}
257 item = self.items[i].item
258 for attr in self.displayattrs:
259 try:
260 value = attr.value(item)
261 except (KeyboardInterrupt, SystemExit):
262 raise
263 except Exception as exc:
264 value = exc
265 # only store attribute if it exists (or we got an exception)
266 if value is not ipipe.noitem:
267 # remember alignment, length and colored text
268 row[attr] = ipipe.xformat(value, "cell", self.browser.maxattrlength)
269 return row
270
271 def calcwidths(self):
272 # Recalculate the displayed fields and their widths.
273 # ``calcdisplayattrs()'' must have been called and the cache
274 # for attributes of the objects on screen (``self.displayrows``)
275 # must have been filled. This sets ``self.colwidths`` which maps
276 # attribute descriptors to widths.
277 self.colwidths = {}
278 for row in self.displayrows:
279 for attr in self.displayattrs:
280 try:
281 length = row[attr][1]
282 except KeyError:
283 length = 0
284 # always add attribute to colwidths, even if it doesn't exist
285 if attr not in self.colwidths:
286 self.colwidths[attr] = len(attr.name())
287 newwidth = max(self.colwidths[attr], length)
288 self.colwidths[attr] = newwidth
289
290 # How many characters do we need to paint the largest item number?
291 self.numbersizex = len(str(self.datastarty+self.mainsizey-1))
292 # How must space have we got to display data?
293 self.mainsizex = self.browser.scrsizex-self.numbersizex-3
294 # width of all columns
295 self.datasizex = sum(self.colwidths.itervalues()) + len(self.colwidths)
296
297 def calcdisplayattr(self):
298 # Find out which attribute the cursor is on and store this
299 # information in ``self.displayattr``.
300 pos = 0
301 for (i, attr) in enumerate(self.displayattrs):
302 if pos+self.colwidths[attr] >= self.curx:
303 self.displayattr = (i, attr)
304 break
305 pos += self.colwidths[attr]+1
306 else:
307 self.displayattr = (None, ipipe.noitem)
308
309 def moveto(self, x, y, refresh=False):
310 # Move the cursor to the position ``(x,y)`` (in data coordinates,
311 # not in screen coordinates). If ``refresh`` is true, all cached
312 # values will be recalculated (e.g. because the list has been
313 # resorted, so screen positions etc. are no longer valid).
314 olddatastarty = self.datastarty
315 oldx = self.curx
316 oldy = self.cury
317 x = int(x+0.5)
318 y = int(y+0.5)
319 newx = x # remember where we wanted to move
320 newy = y # remember where we wanted to move
321
322 scrollbordery = min(self.browser.scrollbordery, self.mainsizey//2)
323 scrollborderx = min(self.browser.scrollborderx, self.mainsizex//2)
324
325 # Make sure that the cursor didn't leave the main area vertically
326 if y < 0:
327 y = 0
328 # try to get enough items to fill the screen
329 self.fetch(max(y+scrollbordery+1, self.mainsizey))
330 if y >= len(self.items):
331 y = max(0, len(self.items)-1)
332
333 # Make sure that the cursor stays on screen vertically
334 if y < self.datastarty+scrollbordery:
335 self.datastarty = max(0, y-scrollbordery)
336 elif y >= self.datastarty+self.mainsizey-scrollbordery:
337 self.datastarty = max(0, min(y-self.mainsizey+scrollbordery+1,
338 len(self.items)-self.mainsizey))
339
340 if refresh: # Do we need to refresh the complete display?
341 self.calcdisplayattrs()
342 endy = min(self.datastarty+self.mainsizey, len(self.items))
343 self.displayrows = map(self.getrow, xrange(self.datastarty, endy))
344 self.calcwidths()
345 # Did we scroll vertically => update displayrows
346 # and various other attributes
347 elif self.datastarty != olddatastarty:
348 # Recalculate which attributes we have to display
349 olddisplayattrs = self.displayattrs
350 self.calcdisplayattrs()
351 # If there are new attributes, recreate the cache
352 if self.displayattrs != olddisplayattrs:
353 endy = min(self.datastarty+self.mainsizey, len(self.items))
354 self.displayrows = map(self.getrow, xrange(self.datastarty, endy))
355 elif self.datastarty<olddatastarty: # we did scroll up
356 # drop rows from the end
357 del self.displayrows[self.datastarty-olddatastarty:]
358 # fetch new items
359 for i in xrange(min(olddatastarty, self.datastarty+self.mainsizey)-1,
360 self.datastarty-1, -1):
361 try:
362 row = self.getrow(i)
363 except IndexError:
364 # we didn't have enough objects to fill the screen
365 break
366 self.displayrows.insert(0, row)
367 else: # we did scroll down
368 # drop rows from the start
369 del self.displayrows[:self.datastarty-olddatastarty]
370 # fetch new items
371 for i in xrange(max(olddatastarty+self.mainsizey, self.datastarty),
372 self.datastarty+self.mainsizey):
373 try:
374 row = self.getrow(i)
375 except IndexError:
376 # we didn't have enough objects to fill the screen
377 break
378 self.displayrows.append(row)
379 self.calcwidths()
380
381 # Make sure that the cursor didn't leave the data area horizontally
382 if x < 0:
383 x = 0
384 elif x >= self.datasizex:
385 x = max(0, self.datasizex-1)
386
387 # Make sure that the cursor stays on screen horizontally
388 if x < self.datastartx+scrollborderx:
389 self.datastartx = max(0, x-scrollborderx)
390 elif x >= self.datastartx+self.mainsizex-scrollborderx:
391 self.datastartx = max(0, min(x-self.mainsizex+scrollborderx+1,
392 self.datasizex-self.mainsizex))
393
394 if x == oldx and y == oldy and (x != newx or y != newy): # couldn't move
395 self.browser.beep()
396 else:
397 self.curx = x
398 self.cury = y
399 self.calcdisplayattr()
400
401 def sort(self, key, reverse=False):
402 """
403 Sort the currently list of items using the key function ``key``. If
404 ``reverse`` is true the sort order is reversed.
405 """
406 curitem = self.items[self.cury] # Remember where the cursor is now
407
408 # Sort items
409 def realkey(item):
410 return key(item.item)
411 self.items = ipipe.deque(sorted(self.items, key=realkey, reverse=reverse))
412
413 # Find out where the object under the cursor went
414 cury = self.cury
415 for (i, item) in enumerate(self.items):
416 if item is curitem:
417 cury = i
418 break
419
420 self.moveto(self.curx, cury, refresh=True)
421
422 def refresh(self):
423 """
424 Restart iterating the input.
425 """
426 self.iterator = ipipe.xiter(self.input)
427 self.items.clear()
428 self.exhausted = False
429 self.datastartx = self.datastarty = 0
430 self.moveto(0, 0, refresh=True)
431
432 def refreshfind(self):
433 """
434 Restart iterating the input and go back to the same object as before
435 (if it can be found in the new iterator).
436 """
437 try:
438 oldobject = self.items[self.cury].item
439 except IndexError:
440 oldobject = ipipe.noitem
441 self.iterator = ipipe.xiter(self.input)
442 self.items.clear()
443 self.exhausted = False
444 while True:
445 self.fetch(len(self.items)+1)
446 if self.exhausted:
447 curses.beep()
448 self.datastartx = self.datastarty = 0
449 self.moveto(self.curx, 0, refresh=True)
450 break
451 if self.items[-1].item == oldobject:
452 self.datastartx = self.datastarty = 0
453 self.moveto(self.curx, len(self.items)-1, refresh=True)
454 break
455
456
457 class _CommandInput(object):
458 keymap = Keymap()
459 keymap.register("left", curses.KEY_LEFT)
460 keymap.register("right", curses.KEY_RIGHT)
461 keymap.register("home", curses.KEY_HOME, "\x01") # Ctrl-A
462 keymap.register("end", curses.KEY_END, "\x05") # Ctrl-E
463 # FIXME: What's happening here?
464 keymap.register("backspace", curses.KEY_BACKSPACE, "\x08\x7f")
465 keymap.register("delete", curses.KEY_DC)
466 keymap.register("delend", 0x0b) # Ctrl-K
467 keymap.register("execute", "\r\n")
468 keymap.register("up", curses.KEY_UP)
469 keymap.register("down", curses.KEY_DOWN)
470 keymap.register("incsearchup", curses.KEY_PPAGE)
471 keymap.register("incsearchdown", curses.KEY_NPAGE)
472 keymap.register("exit", "\x18"), # Ctrl-X
473
474 def __init__(self, prompt):
475 self.prompt = prompt
476 self.history = []
477 self.maxhistory = 100
478 self.input = ""
479 self.curx = 0
480 self.cury = -1 # blank line
481
482 def start(self):
483 self.input = ""
484 self.curx = 0
485 self.cury = -1 # blank line
486
487 def handlekey(self, browser, key):
488 cmdname = self.keymap.get(key, None)
489 if cmdname is not None:
490 cmdfunc = getattr(self, "cmd_%s" % cmdname, None)
491 if cmdfunc is not None:
492 return cmdfunc(browser)
493 curses.beep()
494 elif key != -1:
495 try:
496 char = chr(key)
497 except ValueError:
498 curses.beep()
499 else:
500 return self.handlechar(browser, char)
501
502 def handlechar(self, browser, char):
503 self.input = self.input[:self.curx] + char + self.input[self.curx:]
504 self.curx += 1
505 return True
506
507 def dohistory(self):
508 self.history.insert(0, self.input)
509 del self.history[:-self.maxhistory]
510
511 def cmd_backspace(self, browser):
512 if self.curx:
513 self.input = self.input[:self.curx-1] + self.input[self.curx:]
514 self.curx -= 1
515 return True
516 else:
517 curses.beep()
518
519 def cmd_delete(self, browser):
520 if self.curx<len(self.input):
521 self.input = self.input[:self.curx] + self.input[self.curx+1:]
522 return True
523 else:
524 curses.beep()
525
526 def cmd_delend(self, browser):
527 if self.curx<len(self.input):
528 self.input = self.input[:self.curx]
529 return True
530
531 def cmd_left(self, browser):
532 if self.curx:
533 self.curx -= 1
534 return True
535 else:
536 curses.beep()
537
538 def cmd_right(self, browser):
539 if self.curx < len(self.input):
540 self.curx += 1
541 return True
542 else:
543 curses.beep()
544
545 def cmd_home(self, browser):
546 if self.curx:
547 self.curx = 0
548 return True
549 else:
550 curses.beep()
551
552 def cmd_end(self, browser):
553 if self.curx < len(self.input):
554 self.curx = len(self.input)
555 return True
556 else:
557 curses.beep()
558
559 def cmd_up(self, browser):
560 if self.cury < len(self.history)-1:
561 self.cury += 1
562 self.input = self.history[self.cury]
563 self.curx = len(self.input)
564 return True
565 else:
566 curses.beep()
567
568 def cmd_down(self, browser):
569 if self.cury >= 0:
570 self.cury -= 1
571 if self.cury>=0:
572 self.input = self.history[self.cury]
573 else:
574 self.input = ""
575 self.curx = len(self.input)
576 return True
577 else:
578 curses.beep()
579
580 def cmd_incsearchup(self, browser):
581 prefix = self.input[:self.curx]
582 cury = self.cury
583 while True:
584 cury += 1
585 if cury >= len(self.history):
586 break
587 if self.history[cury].startswith(prefix):
588 self.input = self.history[cury]
589 self.cury = cury
590 return True
591 curses.beep()
592
593 def cmd_incsearchdown(self, browser):
594 prefix = self.input[:self.curx]
595 cury = self.cury
596 while True:
597 cury -= 1
598 if cury <= 0:
599 break
600 if self.history[cury].startswith(prefix):
601 self.input = self.history[self.cury]
602 self.cury = cury
603 return True
604 curses.beep()
605
606 def cmd_exit(self, browser):
607 browser.mode = "default"
608 return True
609
610 def cmd_execute(self, browser):
611 raise NotImplementedError
612
613
614 class _CommandGoto(_CommandInput):
615 def __init__(self):
616 _CommandInput.__init__(self, "goto object #")
617
618 def handlechar(self, browser, char):
619 # Only accept digits
620 if not "0" <= char <= "9":
621 curses.beep()
622 else:
623 return _CommandInput.handlechar(self, browser, char)
624
625 def cmd_execute(self, browser):
626 level = browser.levels[-1]
627 if self.input:
628 self.dohistory()
629 level.moveto(level.curx, int(self.input))
630 browser.mode = "default"
631 return True
632
633
634 class _CommandFind(_CommandInput):
635 def __init__(self):
636 _CommandInput.__init__(self, "find expression")
637
638 def cmd_execute(self, browser):
639 level = browser.levels[-1]
640 if self.input:
641 self.dohistory()
642 while True:
643 cury = level.cury
644 level.moveto(level.curx, cury+1)
645 if cury == level.cury:
646 curses.beep()
647 break # hit end
648 item = level.items[level.cury].item
649 try:
650 globals = ipipe.getglobals(None)
651 if eval(self.input, globals, ipipe.AttrNamespace(item)):
652 break # found something
653 except (KeyboardInterrupt, SystemExit):
654 raise
655 except Exception as exc:
656 browser.report(exc)
657 curses.beep()
658 break # break on error
659 browser.mode = "default"
660 return True
661
662
663 class _CommandFindBackwards(_CommandInput):
664 def __init__(self):
665 _CommandInput.__init__(self, "find backwards expression")
666
667 def cmd_execute(self, browser):
668 level = browser.levels[-1]
669 if self.input:
670 self.dohistory()
671 while level.cury:
672 level.moveto(level.curx, level.cury-1)
673 item = level.items[level.cury].item
674 try:
675 globals = ipipe.getglobals(None)
676 if eval(self.input, globals, ipipe.AttrNamespace(item)):
677 break # found something
678 except (KeyboardInterrupt, SystemExit):
679 raise
680 except Exception as exc:
681 browser.report(exc)
682 curses.beep()
683 break # break on error
684 else:
685 curses.beep()
686 browser.mode = "default"
687 return True
688
689
690 class ibrowse(ipipe.Display):
691 # Show this many lines from the previous screen when paging horizontally
692 pageoverlapx = 1
693
694 # Show this many lines from the previous screen when paging vertically
695 pageoverlapy = 1
696
697 # Start scrolling when the cursor is less than this number of columns
698 # away from the left or right screen edge
699 scrollborderx = 10
700
701 # Start scrolling when the cursor is less than this number of lines
702 # away from the top or bottom screen edge
703 scrollbordery = 5
704
705 # Accelerate by this factor when scrolling horizontally
706 acceleratex = 1.05
707
708 # Accelerate by this factor when scrolling vertically
709 acceleratey = 1.05
710
711 # The maximum horizontal scroll speed
712 # (as a factor of the screen width (i.e. 0.5 == half a screen width)
713 maxspeedx = 0.5
714
715 # The maximum vertical scroll speed
716 # (as a factor of the screen height (i.e. 0.5 == half a screen height)
717 maxspeedy = 0.5
718
719 # The maximum number of header lines for browser level
720 # if the nesting is deeper, only the innermost levels are displayed
721 maxheaders = 5
722
723 # The approximate maximum length of a column entry
724 maxattrlength = 200
725
726 # Styles for various parts of the GUI
727 style_objheadertext = astyle.Style.fromstr("white:black:bold|reverse")
728 style_objheadernumber = astyle.Style.fromstr("white:blue:bold|reverse")
729 style_objheaderobject = astyle.Style.fromstr("white:black:reverse")
730 style_colheader = astyle.Style.fromstr("blue:white:reverse")
731 style_colheaderhere = astyle.Style.fromstr("green:black:bold|reverse")
732 style_colheadersep = astyle.Style.fromstr("blue:black:reverse")
733 style_number = astyle.Style.fromstr("blue:white:reverse")
734 style_numberhere = astyle.Style.fromstr("green:black:bold|reverse")
735 style_sep = astyle.Style.fromstr("blue:black")
736 style_data = astyle.Style.fromstr("white:black")
737 style_datapad = astyle.Style.fromstr("blue:black:bold")
738 style_footer = astyle.Style.fromstr("black:white")
739 style_report = astyle.Style.fromstr("white:black")
740
741 # Column separator in header
742 headersepchar = "|"
743
744 # Character for padding data cell entries
745 datapadchar = "."
746
747 # Column separator in data area
748 datasepchar = "|"
749
750 # Character to use for "empty" cell (i.e. for non-existing attributes)
751 nodatachar = "-"
752
753 # Prompts for modes that require keyboard input
754 prompts = {
755 "goto": _CommandGoto(),
756 "find": _CommandFind(),
757 "findbackwards": _CommandFindBackwards()
758 }
759
760 # Maps curses key codes to "function" names
761 keymap = Keymap()
762 keymap.register("quit", "q")
763 keymap.register("up", curses.KEY_UP)
764 keymap.register("down", curses.KEY_DOWN)
765 keymap.register("pageup", curses.KEY_PPAGE)
766 keymap.register("pagedown", curses.KEY_NPAGE)
767 keymap.register("left", curses.KEY_LEFT)
768 keymap.register("right", curses.KEY_RIGHT)
769 keymap.register("home", curses.KEY_HOME, "\x01")
770 keymap.register("end", curses.KEY_END, "\x05")
771 keymap.register("prevattr", "<\x1b")
772 keymap.register("nextattr", ">\t")
773 keymap.register("pick", "p")
774 keymap.register("pickattr", "P")
775 keymap.register("pickallattrs", "C")
776 keymap.register("pickmarked", "m")
777 keymap.register("pickmarkedattr", "M")
778 keymap.register("pickinput", "i")
779 keymap.register("pickinputattr", "I")
780 keymap.register("hideattr", "h")
781 keymap.register("unhideattrs", "H")
782 keymap.register("help", "?")
783 keymap.register("enter", "\r\n")
784 keymap.register("enterattr", "E")
785 # FIXME: What's happening here?
786 keymap.register("leave", curses.KEY_BACKSPACE, "x\x08\x7f")
787 keymap.register("detail", "d")
788 keymap.register("detailattr", "D")
789 keymap.register("tooglemark", " ")
790 keymap.register("markrange", "%")
791 keymap.register("sortattrasc", "v")
792 keymap.register("sortattrdesc", "V")
793 keymap.register("goto", "g")
794 keymap.register("find", "f")
795 keymap.register("findbackwards", "b")
796 keymap.register("refresh", "r")
797 keymap.register("refreshfind", "R")
798
799 def __init__(self, input=None, *attrs):
800 """
801 Create a new browser. If ``attrs`` is not empty, it is the list
802 of attributes that will be displayed in the browser, otherwise
803 these will be determined by the objects on screen.
804 """
805 ipipe.Display.__init__(self, input)
806
807 self.attrs = attrs
808
809 # Stack of browser levels
810 self.levels = []
811 # how many colums to scroll (Changes when accelerating)
812 self.stepx = 1.
813
814 # how many rows to scroll (Changes when accelerating)
815 self.stepy = 1.
816
817 # Beep on the edges of the data area? (Will be set to ``False``
818 # once the cursor hits the edge of the screen, so we don't get
819 # multiple beeps).
820 self._dobeep = True
821
822 # Cache for registered ``curses`` colors and styles.
823 self._styles = {}
824 self._colors = {}
825 self._maxcolor = 1
826
827 # How many header lines do we want to paint (the numbers of levels
828 # we have, but with an upper bound)
829 self._headerlines = 1
830
831 # Index of first header line
832 self._firstheaderline = 0
833
834 # curses window
835 self.scr = None
836 # report in the footer line (error, executed command etc.)
837 self._report = None
838
839 # value to be returned to the caller (set by commands)
840 self.returnvalue = None
841
842 # The mode the browser is in
843 # e.g. normal browsing or entering an argument for a command
844 self.mode = "default"
845
846 # set by the SIGWINCH signal handler
847 self.resized = False
848
849 def nextstepx(self, step):
850 """
851 Accelerate horizontally.
852 """
853 return max(1., min(step*self.acceleratex,
854 self.maxspeedx*self.levels[-1].mainsizex))
855
856 def nextstepy(self, step):
857 """
858 Accelerate vertically.
859 """
860 return max(1., min(step*self.acceleratey,
861 self.maxspeedy*self.levels[-1].mainsizey))
862
863 def getstyle(self, style):
864 """
865 Register the ``style`` with ``curses`` or get it from the cache,
866 if it has been registered before.
867 """
868 try:
869 return self._styles[style.fg, style.bg, style.attrs]
870 except KeyError:
871 attrs = 0
872 for b in astyle.A2CURSES:
873 if style.attrs & b:
874 attrs |= astyle.A2CURSES[b]
875 try:
876 color = self._colors[style.fg, style.bg]
877 except KeyError:
878 curses.init_pair(
879 self._maxcolor,
880 astyle.COLOR2CURSES[style.fg],
881 astyle.COLOR2CURSES[style.bg]
882 )
883 color = curses.color_pair(self._maxcolor)
884 self._colors[style.fg, style.bg] = color
885 self._maxcolor += 1
886 c = color | attrs
887 self._styles[style.fg, style.bg, style.attrs] = c
888 return c
889
890 def addstr(self, y, x, begx, endx, text, style):
891 """
892 A version of ``curses.addstr()`` that can handle ``x`` coordinates
893 that are outside the screen.
894 """
895 text2 = text[max(0, begx-x):max(0, endx-x)]
896 if text2:
897 self.scr.addstr(y, max(x, begx), text2, self.getstyle(style))
898 return len(text)
899
900 def addchr(self, y, x, begx, endx, c, l, style):
901 x0 = max(x, begx)
902 x1 = min(x+l, endx)
903 if x1>x0:
904 self.scr.addstr(y, x0, c*(x1-x0), self.getstyle(style))
905 return l
906
907 def _calcheaderlines(self, levels):
908 # Calculate how many headerlines do we have to display, if we have
909 # ``levels`` browser levels
910 if levels is None:
911 levels = len(self.levels)
912 self._headerlines = min(self.maxheaders, levels)
913 self._firstheaderline = levels-self._headerlines
914
915 def getstylehere(self, style):
916 """
917 Return a style for displaying the original style ``style``
918 in the row the cursor is on.
919 """
920 return astyle.Style(style.fg, astyle.COLOR_BLUE, style.attrs | astyle.A_BOLD)
921
922 def report(self, msg):
923 """
924 Store the message ``msg`` for display below the footer line. This
925 will be displayed as soon as the screen is redrawn.
926 """
927 self._report = msg
928
929 def enter(self, item, *attrs):
930 """
931 Enter the object ``item``. If ``attrs`` is specified, it will be used
932 as a fixed list of attributes to display.
933 """
934 if self.levels and item is self.levels[-1].input:
935 curses.beep()
936 self.report(CommandError("Recursion on input object"))
937 else:
938 oldlevels = len(self.levels)
939 self._calcheaderlines(oldlevels+1)
940 try:
941 level = _BrowserLevel(
942 self,
943 item,
944 self.scrsizey-1-self._headerlines-2,
945 *attrs
946 )
947 except (KeyboardInterrupt, SystemExit):
948 raise
949 except Exception as exc:
950 if not self.levels:
951 raise
952 self._calcheaderlines(oldlevels)
953 curses.beep()
954 self.report(exc)
955 else:
956 self.levels.append(level)
957
958 def startkeyboardinput(self, mode):
959 """
960 Enter mode ``mode``, which requires keyboard input.
961 """
962 self.mode = mode
963 self.prompts[mode].start()
964
965 def keylabel(self, keycode):
966 """
967 Return a pretty name for the ``curses`` key ``keycode`` (used in the
968 help screen and in reports about unassigned keys).
969 """
970 if keycode <= 0xff:
971 specialsnames = {
972 ord("\n"): "RETURN",
973 ord(" "): "SPACE",
974 ord("\t"): "TAB",
975 ord("\x7f"): "DELETE",
976 ord("\x08"): "BACKSPACE",
977 }
978 if keycode in specialsnames:
979 return specialsnames[keycode]
980 elif 0x00 < keycode < 0x20:
981 return "CTRL-%s" % chr(keycode + 64)
982 return repr(chr(keycode))
983 for name in dir(curses):
984 if name.startswith("KEY_") and getattr(curses, name) == keycode:
985 return name
986 return str(keycode)
987
988 def beep(self, force=False):
989 if force or self._dobeep:
990 curses.beep()
991 # don't beep again (as long as the same key is pressed)
992 self._dobeep = False
993
994 def cmd_up(self):
995 """
996 Move the cursor to the previous row.
997 """
998 level = self.levels[-1]
999 self.report("up")
1000 level.moveto(level.curx, level.cury-self.stepy)
1001
1002 def cmd_down(self):
1003 """
1004 Move the cursor to the next row.
1005 """
1006 level = self.levels[-1]
1007 self.report("down")
1008 level.moveto(level.curx, level.cury+self.stepy)
1009
1010 def cmd_pageup(self):
1011 """
1012 Move the cursor up one page.
1013 """
1014 level = self.levels[-1]
1015 self.report("page up")
1016 level.moveto(level.curx, level.cury-level.mainsizey+self.pageoverlapy)
1017
1018 def cmd_pagedown(self):
1019 """
1020 Move the cursor down one page.
1021 """
1022 level = self.levels[-1]
1023 self.report("page down")
1024 level.moveto(level.curx, level.cury+level.mainsizey-self.pageoverlapy)
1025
1026 def cmd_left(self):
1027 """
1028 Move the cursor left.
1029 """
1030 level = self.levels[-1]
1031 self.report("left")
1032 level.moveto(level.curx-self.stepx, level.cury)
1033
1034 def cmd_right(self):
1035 """
1036 Move the cursor right.
1037 """
1038 level = self.levels[-1]
1039 self.report("right")
1040 level.moveto(level.curx+self.stepx, level.cury)
1041
1042 def cmd_home(self):
1043 """
1044 Move the cursor to the first column.
1045 """
1046 level = self.levels[-1]
1047 self.report("home")
1048 level.moveto(0, level.cury)
1049
1050 def cmd_end(self):
1051 """
1052 Move the cursor to the last column.
1053 """
1054 level = self.levels[-1]
1055 self.report("end")
1056 level.moveto(level.datasizex+level.mainsizey-self.pageoverlapx, level.cury)
1057
1058 def cmd_prevattr(self):
1059 """
1060 Move the cursor one attribute column to the left.
1061 """
1062 level = self.levels[-1]
1063 if level.displayattr[0] is None or level.displayattr[0] == 0:
1064 self.beep()
1065 else:
1066 self.report("prevattr")
1067 pos = 0
1068 for (i, attrname) in enumerate(level.displayattrs):
1069 if i == level.displayattr[0]-1:
1070 break
1071 pos += level.colwidths[attrname] + 1
1072 level.moveto(pos, level.cury)
1073
1074 def cmd_nextattr(self):
1075 """
1076 Move the cursor one attribute column to the right.
1077 """
1078 level = self.levels[-1]
1079 if level.displayattr[0] is None or level.displayattr[0] == len(level.displayattrs)-1:
1080 self.beep()
1081 else:
1082 self.report("nextattr")
1083 pos = 0
1084 for (i, attrname) in enumerate(level.displayattrs):
1085 if i == level.displayattr[0]+1:
1086 break
1087 pos += level.colwidths[attrname] + 1
1088 level.moveto(pos, level.cury)
1089
1090 def cmd_pick(self):
1091 """
1092 'Pick' the object under the cursor (i.e. the row the cursor is on).
1093 This leaves the browser and returns the picked object to the caller.
1094 (In IPython this object will be available as the ``_`` variable.)
1095 """
1096 level = self.levels[-1]
1097 self.returnvalue = level.items[level.cury].item
1098 return True
1099
1100 def cmd_pickattr(self):
1101 """
1102 'Pick' the attribute under the cursor (i.e. the row/column the
1103 cursor is on).
1104 """
1105 level = self.levels[-1]
1106 attr = level.displayattr[1]
1107 if attr is ipipe.noitem:
1108 curses.beep()
1109 self.report(CommandError("no column under cursor"))
1110 return
1111 value = attr.value(level.items[level.cury].item)
1112 if value is ipipe.noitem:
1113 curses.beep()
1114 self.report(AttributeError(attr.name()))
1115 else:
1116 self.returnvalue = value
1117 return True
1118
1119 def cmd_pickallattrs(self):
1120 """
1121 Pick' the complete column under the cursor (i.e. the attribute under
1122 the cursor) from all currently fetched objects. These attributes
1123 will be returned as a list.
1124 """
1125 level = self.levels[-1]
1126 attr = level.displayattr[1]
1127 if attr is ipipe.noitem:
1128 curses.beep()
1129 self.report(CommandError("no column under cursor"))
1130 return
1131 result = []
1132 for cache in level.items:
1133 value = attr.value(cache.item)
1134 if value is not ipipe.noitem:
1135 result.append(value)
1136 self.returnvalue = result
1137 return True
1138
1139 def cmd_pickmarked(self):
1140 """
1141 'Pick' marked objects. Marked objects will be returned as a list.
1142 """
1143 level = self.levels[-1]
1144 self.returnvalue = [cache.item for cache in level.items if cache.marked]
1145 return True
1146
1147 def cmd_pickmarkedattr(self):
1148 """
1149 'Pick' the attribute under the cursor from all marked objects
1150 (This returns a list).
1151 """
1152
1153 level = self.levels[-1]
1154 attr = level.displayattr[1]
1155 if attr is ipipe.noitem:
1156 curses.beep()
1157 self.report(CommandError("no column under cursor"))
1158 return
1159 result = []
1160 for cache in level.items:
1161 if cache.marked:
1162 value = attr.value(cache.item)
1163 if value is not ipipe.noitem:
1164 result.append(value)
1165 self.returnvalue = result
1166 return True
1167
1168 def cmd_pickinput(self):
1169 """
1170 Use the object under the cursor (i.e. the row the cursor is on) as
1171 the next input line. This leaves the browser and puts the picked object
1172 in the input.
1173 """
1174 level = self.levels[-1]
1175 value = level.items[level.cury].item
1176 self.returnvalue = None
1177 api = ipapi.get()
1178 api.set_next_input(str(value))
1179 return True
1180
1181 def cmd_pickinputattr(self):
1182 """
1183 Use the attribute under the cursor i.e. the row/column the cursor is on)
1184 as the next input line. This leaves the browser and puts the picked
1185 object in the input.
1186 """
1187 level = self.levels[-1]
1188 attr = level.displayattr[1]
1189 if attr is ipipe.noitem:
1190 curses.beep()
1191 self.report(CommandError("no column under cursor"))
1192 return
1193 value = attr.value(level.items[level.cury].item)
1194 if value is ipipe.noitem:
1195 curses.beep()
1196 self.report(AttributeError(attr.name()))
1197 self.returnvalue = None
1198 api = ipapi.get()
1199 api.set_next_input(str(value))
1200 return True
1201
1202 def cmd_markrange(self):
1203 """
1204 Mark all objects from the last marked object before the current cursor
1205 position to the cursor position.
1206 """
1207 level = self.levels[-1]
1208 self.report("markrange")
1209 start = None
1210 if level.items:
1211 for i in xrange(level.cury, -1, -1):
1212 if level.items[i].marked:
1213 start = i
1214 break
1215 if start is None:
1216 self.report(CommandError("no mark before cursor"))
1217 curses.beep()
1218 else:
1219 for i in xrange(start, level.cury+1):
1220 cache = level.items[i]
1221 if not cache.marked:
1222 cache.marked = True
1223 level.marked += 1
1224
1225 def cmd_enter(self):
1226 """
1227 Enter the object under the cursor. (what this mean depends on the object
1228 itself (i.e. how it implements iteration). This opens a new browser 'level'.
1229 """
1230 level = self.levels[-1]
1231 try:
1232 item = level.items[level.cury].item
1233 except IndexError:
1234 self.report(CommandError("No object"))
1235 curses.beep()
1236 else:
1237 self.report("entering object...")
1238 self.enter(item)
1239
1240 def cmd_leave(self):
1241 """
1242 Leave the current browser level and go back to the previous one.
1243 """
1244 self.report("leave")
1245 if len(self.levels) > 1:
1246 self._calcheaderlines(len(self.levels)-1)
1247 self.levels.pop(-1)
1248 else:
1249 self.report(CommandError("This is the last level"))
1250 curses.beep()
1251
1252 def cmd_enterattr(self):
1253 """
1254 Enter the attribute under the cursor.
1255 """
1256 level = self.levels[-1]
1257 attr = level.displayattr[1]
1258 if attr is ipipe.noitem:
1259 curses.beep()
1260 self.report(CommandError("no column under cursor"))
1261 return
1262 try:
1263 item = level.items[level.cury].item
1264 except IndexError:
1265 self.report(CommandError("No object"))
1266 curses.beep()
1267 else:
1268 value = attr.value(item)
1269 name = attr.name()
1270 if value is ipipe.noitem:
1271 self.report(AttributeError(name))
1272 else:
1273 self.report("entering object attribute %s..." % name)
1274 self.enter(value)
1275
1276 def cmd_detail(self):
1277 """
1278 Show a detail view of the object under the cursor. This shows the
1279 name, type, doc string and value of the object attributes (and it
1280 might show more attributes than in the list view, depending on
1281 the object).
1282 """
1283 level = self.levels[-1]
1284 try:
1285 item = level.items[level.cury].item
1286 except IndexError:
1287 self.report(CommandError("No object"))
1288 curses.beep()
1289 else:
1290 self.report("entering detail view for object...")
1291 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
1292 self.enter(attrs)
1293
1294 def cmd_detailattr(self):
1295 """
1296 Show a detail view of the attribute under the cursor.
1297 """
1298 level = self.levels[-1]
1299 attr = level.displayattr[1]
1300 if attr is ipipe.noitem:
1301 curses.beep()
1302 self.report(CommandError("no attribute"))
1303 return
1304 try:
1305 item = level.items[level.cury].item
1306 except IndexError:
1307 self.report(CommandError("No object"))
1308 curses.beep()
1309 else:
1310 try:
1311 item = attr.value(item)
1312 except (KeyboardInterrupt, SystemExit):
1313 raise
1314 except Exception as exc:
1315 self.report(exc)
1316 else:
1317 self.report("entering detail view for attribute %s..." % attr.name())
1318 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
1319 self.enter(attrs)
1320
1321 def cmd_tooglemark(self):
1322 """
1323 Mark/unmark the object under the cursor. Marked objects have a '!'
1324 after the row number).
1325 """
1326 level = self.levels[-1]
1327 self.report("toggle mark")
1328 try:
1329 item = level.items[level.cury]
1330 except IndexError: # no items?
1331 pass
1332 else:
1333 if item.marked:
1334 item.marked = False
1335 level.marked -= 1
1336 else:
1337 item.marked = True
1338 level.marked += 1
1339
1340 def cmd_sortattrasc(self):
1341 """
1342 Sort the objects (in ascending order) using the attribute under
1343 the cursor as the sort key.
1344 """
1345 level = self.levels[-1]
1346 attr = level.displayattr[1]
1347 if attr is ipipe.noitem:
1348 curses.beep()
1349 self.report(CommandError("no column under cursor"))
1350 return
1351 self.report("sort by %s (ascending)" % attr.name())
1352 def key(item):
1353 try:
1354 return attr.value(item)
1355 except (KeyboardInterrupt, SystemExit):
1356 raise
1357 except Exception:
1358 return None
1359 level.sort(key)
1360
1361 def cmd_sortattrdesc(self):
1362 """
1363 Sort the objects (in descending order) using the attribute under
1364 the cursor as the sort key.
1365 """
1366 level = self.levels[-1]
1367 attr = level.displayattr[1]
1368 if attr is ipipe.noitem:
1369 curses.beep()
1370 self.report(CommandError("no column under cursor"))
1371 return
1372 self.report("sort by %s (descending)" % attr.name())
1373 def key(item):
1374 try:
1375 return attr.value(item)
1376 except (KeyboardInterrupt, SystemExit):
1377 raise
1378 except Exception:
1379 return None
1380 level.sort(key, reverse=True)
1381
1382 def cmd_hideattr(self):
1383 """
1384 Hide the attribute under the cursor.
1385 """
1386 level = self.levels[-1]
1387 if level.displayattr[0] is None:
1388 self.beep()
1389 else:
1390 self.report("hideattr")
1391 level.hiddenattrs.add(level.displayattr[1])
1392 level.moveto(level.curx, level.cury, refresh=True)
1393
1394 def cmd_unhideattrs(self):
1395 """
1396 Make all attributes visible again.
1397 """
1398 level = self.levels[-1]
1399 self.report("unhideattrs")
1400 level.hiddenattrs.clear()
1401 level.moveto(level.curx, level.cury, refresh=True)
1402
1403 def cmd_goto(self):
1404 """
1405 Jump to a row. The row number can be entered at the
1406 bottom of the screen.
1407 """
1408 self.startkeyboardinput("goto")
1409
1410 def cmd_find(self):
1411 """
1412 Search forward for a row. The search condition can be entered at the
1413 bottom of the screen.
1414 """
1415 self.startkeyboardinput("find")
1416
1417 def cmd_findbackwards(self):
1418 """
1419 Search backward for a row. The search condition can be entered at the
1420 bottom of the screen.
1421 """
1422 self.startkeyboardinput("findbackwards")
1423
1424 def cmd_refresh(self):
1425 """
1426 Refreshes the display by restarting the iterator.
1427 """
1428 level = self.levels[-1]
1429 self.report("refresh")
1430 level.refresh()
1431
1432 def cmd_refreshfind(self):
1433 """
1434 Refreshes the display by restarting the iterator and goes back to the
1435 same object the cursor was on before restarting (if this object can't be
1436 found the cursor jumps back to the first object).
1437 """
1438 level = self.levels[-1]
1439 self.report("refreshfind")
1440 level.refreshfind()
1441
1442 def cmd_help(self):
1443 """
1444 Opens the help screen as a new browser level, describing keyboard
1445 shortcuts.
1446 """
1447 for level in self.levels:
1448 if isinstance(level.input, _BrowserHelp):
1449 curses.beep()
1450 self.report(CommandError("help already active"))
1451 return
1452
1453 self.enter(_BrowserHelp(self))
1454
1455 def cmd_quit(self):
1456 """
1457 Quit the browser and return to the IPython prompt.
1458 """
1459 self.returnvalue = None
1460 return True
1461
1462 def sigwinchhandler(self, signal, frame):
1463 self.resized = True
1464
1465 def _dodisplay(self, scr):
1466 """
1467 This method is the workhorse of the browser. It handles screen
1468 drawing and the keyboard.
1469 """
1470 self.scr = scr
1471 curses.halfdelay(1)
1472 footery = 2
1473
1474 keys = []
1475 for cmd in ("quit", "help"):
1476 key = self.keymap.findkey(cmd, None)
1477 if key is not None:
1478 keys.append("%s=%s" % (self.keylabel(key), cmd))
1479 helpmsg = " | %s" % " ".join(keys)
1480
1481 scr.clear()
1482 msg = "Fetching first batch of objects..."
1483 (self.scrsizey, self.scrsizex) = scr.getmaxyx()
1484 scr.addstr(self.scrsizey//2, (self.scrsizex-len(msg))//2, msg)
1485 scr.refresh()
1486
1487 lastc = -1
1488
1489 self.levels = []
1490 # enter the first level
1491 self.enter(self.input, *self.attrs)
1492
1493 self._calcheaderlines(None)
1494
1495 while True:
1496 level = self.levels[-1]
1497 (self.scrsizey, self.scrsizex) = scr.getmaxyx()
1498 level.mainsizey = self.scrsizey-1-self._headerlines-footery
1499
1500 # Paint object header
1501 for i in xrange(self._firstheaderline, self._firstheaderline+self._headerlines):
1502 lv = self.levels[i]
1503 posx = 0
1504 posy = i-self._firstheaderline
1505 endx = self.scrsizex
1506 if i: # not the first level
1507 msg = " (%d/%d" % (self.levels[i-1].cury, len(self.levels[i-1].items))
1508 if not self.levels[i-1].exhausted:
1509 msg += "+"
1510 msg += ") "
1511 endx -= len(msg)+1
1512 posx += self.addstr(posy, posx, 0, endx, " ibrowse #%d: " % i, self.style_objheadertext)
1513 for (style, text) in lv.header:
1514 posx += self.addstr(posy, posx, 0, endx, text, self.style_objheaderobject)
1515 if posx >= endx:
1516 break
1517 if i:
1518 posx += self.addstr(posy, posx, 0, self.scrsizex, msg, self.style_objheadernumber)
1519 posx += self.addchr(posy, posx, 0, self.scrsizex, " ", self.scrsizex-posx, self.style_objheadernumber)
1520
1521 if not level.items:
1522 self.addchr(self._headerlines, 0, 0, self.scrsizex, " ", self.scrsizex, self.style_colheader)
1523 self.addstr(self._headerlines+1, 0, 0, self.scrsizex, " <empty>", astyle.style_error)
1524 scr.clrtobot()
1525 else:
1526 # Paint column headers
1527 scr.move(self._headerlines, 0)
1528 scr.addstr(" %*s " % (level.numbersizex, "#"), self.getstyle(self.style_colheader))
1529 scr.addstr(self.headersepchar, self.getstyle(self.style_colheadersep))
1530 begx = level.numbersizex+3
1531 posx = begx-level.datastartx
1532 for attr in level.displayattrs:
1533 attrname = attr.name()
1534 cwidth = level.colwidths[attr]
1535 header = attrname.ljust(cwidth)
1536 if attr is level.displayattr[1]:
1537 style = self.style_colheaderhere
1538 else:
1539 style = self.style_colheader
1540 posx += self.addstr(self._headerlines, posx, begx, self.scrsizex, header, style)
1541 posx += self.addstr(self._headerlines, posx, begx, self.scrsizex, self.headersepchar, self.style_colheadersep)
1542 if posx >= self.scrsizex:
1543 break
1544 else:
1545 scr.addstr(" "*(self.scrsizex-posx), self.getstyle(self.style_colheader))
1546
1547 # Paint rows
1548 posy = self._headerlines+1+level.datastarty
1549 for i in xrange(level.datastarty, min(level.datastarty+level.mainsizey, len(level.items))):
1550 cache = level.items[i]
1551 if i == level.cury:
1552 style = self.style_numberhere
1553 else:
1554 style = self.style_number
1555
1556 posy = self._headerlines+1+i-level.datastarty
1557 posx = begx-level.datastartx
1558
1559 scr.move(posy, 0)
1560 scr.addstr(" %*d%s" % (level.numbersizex, i, " !"[cache.marked]), self.getstyle(style))
1561 scr.addstr(self.headersepchar, self.getstyle(self.style_sep))
1562
1563 for attrname in level.displayattrs:
1564 cwidth = level.colwidths[attrname]
1565 try:
1566 (align, length, parts) = level.displayrows[i-level.datastarty][attrname]
1567 except KeyError:
1568 align = 2
1569 style = astyle.style_nodata
1570 if i == level.cury:
1571 style = self.getstylehere(style)
1572 padstyle = self.style_datapad
1573 sepstyle = self.style_sep
1574 if i == level.cury:
1575 padstyle = self.getstylehere(padstyle)
1576 sepstyle = self.getstylehere(sepstyle)
1577 if align == 2:
1578 posx += self.addchr(posy, posx, begx, self.scrsizex, self.nodatachar, cwidth, style)
1579 else:
1580 if align == 1:
1581 posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, cwidth-length, padstyle)
1582 elif align == 0:
1583 pad1 = (cwidth-length)//2
1584 pad2 = cwidth-length-len(pad1)
1585 posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, pad1, padstyle)
1586 for (style, text) in parts:
1587 if i == level.cury:
1588 style = self.getstylehere(style)
1589 posx += self.addstr(posy, posx, begx, self.scrsizex, text, style)
1590 if posx >= self.scrsizex:
1591 break
1592 if align == -1:
1593 posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, cwidth-length, padstyle)
1594 elif align == 0:
1595 posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, pad2, padstyle)
1596 posx += self.addstr(posy, posx, begx, self.scrsizex, self.datasepchar, sepstyle)
1597 else:
1598 scr.clrtoeol()
1599
1600 # Add blank row headers for the rest of the screen
1601 for posy in xrange(posy+1, self.scrsizey-2):
1602 scr.addstr(posy, 0, " " * (level.numbersizex+2), self.getstyle(self.style_colheader))
1603 scr.clrtoeol()
1604
1605 posy = self.scrsizey-footery
1606 # Display footer
1607 scr.addstr(posy, 0, " "*self.scrsizex, self.getstyle(self.style_footer))
1608
1609 if level.exhausted:
1610 flag = ""
1611 else:
1612 flag = "+"
1613
1614 endx = self.scrsizex-len(helpmsg)-1
1615 scr.addstr(posy, endx, helpmsg, self.getstyle(self.style_footer))
1616
1617 posx = 0
1618 msg = " %d%s objects (%d marked): " % (len(level.items), flag, level.marked)
1619 posx += self.addstr(posy, posx, 0, endx, msg, self.style_footer)
1620 try:
1621 item = level.items[level.cury].item
1622 except IndexError: # empty
1623 pass
1624 else:
1625 for (nostyle, text) in ipipe.xrepr(item, "footer"):
1626 if not isinstance(nostyle, int):
1627 posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
1628 if posx >= endx:
1629 break
1630
1631 attrstyle = [(astyle.style_default, "no attribute")]
1632 attr = level.displayattr[1]
1633 if attr is not ipipe.noitem and not isinstance(attr, ipipe.SelfDescriptor):
1634 posx += self.addstr(posy, posx, 0, endx, " | ", self.style_footer)
1635 posx += self.addstr(posy, posx, 0, endx, attr.name(), self.style_footer)
1636 posx += self.addstr(posy, posx, 0, endx, ": ", self.style_footer)
1637 try:
1638 value = attr.value(item)
1639 except (SystemExit, KeyboardInterrupt):
1640 raise
1641 except Exception as exc:
1642 value = exc
1643 if value is not ipipe.noitem:
1644 attrstyle = ipipe.xrepr(value, "footer")
1645 for (nostyle, text) in attrstyle:
1646 if not isinstance(nostyle, int):
1647 posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
1648 if posx >= endx:
1649 break
1650
1651 try:
1652 # Display input prompt
1653 if self.mode in self.prompts:
1654 history = self.prompts[self.mode]
1655 posx = 0
1656 posy = self.scrsizey-1
1657 posx += self.addstr(posy, posx, 0, endx, history.prompt, astyle.style_default)
1658 posx += self.addstr(posy, posx, 0, endx, " [", astyle.style_default)
1659 if history.cury==-1:
1660 text = "new"
1661 else:
1662 text = str(history.cury+1)
1663 posx += self.addstr(posy, posx, 0, endx, text, astyle.style_type_number)
1664 if history.history:
1665 posx += self.addstr(posy, posx, 0, endx, "/", astyle.style_default)
1666 posx += self.addstr(posy, posx, 0, endx, str(len(history.history)), astyle.style_type_number)
1667 posx += self.addstr(posy, posx, 0, endx, "]: ", astyle.style_default)
1668 inputstartx = posx
1669 posx += self.addstr(posy, posx, 0, endx, history.input, astyle.style_default)
1670 # Display report
1671 else:
1672 if self._report is not None:
1673 if isinstance(self._report, Exception):
1674 style = self.getstyle(astyle.style_error)
1675 if self._report.__class__.__module__ == "exceptions":
1676 msg = "%s: %s" % \
1677 (self._report.__class__.__name__, self._report)
1678 else:
1679 msg = "%s.%s: %s" % \
1680 (self._report.__class__.__module__,
1681 self._report.__class__.__name__, self._report)
1682 else:
1683 style = self.getstyle(self.style_report)
1684 msg = self._report
1685 scr.addstr(self.scrsizey-1, 0, msg[:self.scrsizex], style)
1686 self._report = None
1687 else:
1688 scr.move(self.scrsizey-1, 0)
1689 except curses.error:
1690 # Protect against errors from writing to the last line
1691 pass
1692 scr.clrtoeol()
1693
1694 # Position cursor
1695 if self.mode in self.prompts:
1696 history = self.prompts[self.mode]
1697 scr.move(self.scrsizey-1, inputstartx+history.curx)
1698 else:
1699 scr.move(
1700 1+self._headerlines+level.cury-level.datastarty,
1701 level.numbersizex+3+level.curx-level.datastartx
1702 )
1703 scr.refresh()
1704
1705 # Check keyboard
1706 while True:
1707 c = scr.getch()
1708 if self.resized:
1709 size = fcntl.ioctl(0, tty.TIOCGWINSZ, "12345678")
1710 size = struct.unpack("4H", size)
1711 oldsize = scr.getmaxyx()
1712 scr.erase()
1713 curses.resize_term(size[0], size[1])
1714 newsize = scr.getmaxyx()
1715 scr.erase()
1716 for l in self.levels:
1717 l.mainsizey += newsize[0]-oldsize[0]
1718 l.moveto(l.curx, l.cury, refresh=True)
1719 scr.refresh()
1720 self.resized = False
1721 break # Redisplay
1722 if self.mode in self.prompts:
1723 if self.prompts[self.mode].handlekey(self, c):
1724 break # Redisplay
1725 else:
1726 # if no key is pressed slow down and beep again
1727 if c == -1:
1728 self.stepx = 1.
1729 self.stepy = 1.
1730 self._dobeep = True
1731 else:
1732 # if a different key was pressed slow down and beep too
1733 if c != lastc:
1734 lastc = c
1735 self.stepx = 1.
1736 self.stepy = 1.
1737 self._dobeep = True
1738 cmdname = self.keymap.get(c, None)
1739 if cmdname is None:
1740 self.report(
1741 UnassignedKeyError("Unassigned key %s" %
1742 self.keylabel(c)))
1743 else:
1744 cmdfunc = getattr(self, "cmd_%s" % cmdname, None)
1745 if cmdfunc is None:
1746 self.report(
1747 UnknownCommandError("Unknown command %r" %
1748 (cmdname,)))
1749 elif cmdfunc():
1750 returnvalue = self.returnvalue
1751 self.returnvalue = None
1752 return returnvalue
1753 self.stepx = self.nextstepx(self.stepx)
1754 self.stepy = self.nextstepy(self.stepy)
1755 curses.flushinp() # get rid of type ahead
1756 break # Redisplay
1757 self.scr = None
1758
1759 def display(self):
1760 if hasattr(curses, "resize_term") and hasattr(signal, 'SIGWINCH'):
1761 oldhandler = signal.signal(signal.SIGWINCH, self.sigwinchhandler)
1762 try:
1763 return curses.wrapper(self._dodisplay)
1764 finally:
1765 signal.signal(signal.SIGWINCH, oldhandler)
1766 else:
1767 return curses.wrapper(self._dodisplay)
This diff has been collapsed as it changes many lines, (1126 lines changed) Show them Hide them
@@ -1,1126 +0,0 b''
1 # -*- coding: iso-8859-1 -*-
2
3 import ipipe, os, webbrowser, urllib
4 from IPython.core import ipapi
5 import wx
6 import wx.grid, wx.html
7
8 try:
9 sorted
10 except NameError:
11 from ipipe import sorted
12 try:
13 set
14 except:
15 from sets import Set as set
16
17
18 __all__ = ["igrid"]
19
20
21 help = """
22 <?xml version='1.0' encoding='iso-8859-1'?>
23 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
24 <html>
25 <head>
26 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
27 <link rel="stylesheet" href="igrid_help.css" type="text/css" />
28 <title>igrid help</title>
29 </head>
30 <body>
31 <h1>igrid help</h1>
32
33
34 <h2>Commands</h2>
35
36
37 <h3>pick (P)</h3>
38 <p>Pick the whole row (object is available as "_")</p>
39
40 <h3>pickattr (Shift-P)</h3>
41 <p>Pick the attribute under the cursor</p>
42
43 <h3>pickallattrs (Shift-C)</h3>
44 <p>Pick the complete column under the cursor (i.e. the attribute under the
45 cursor) from all currently fetched objects. These attributes will be returned
46 as a list.</p>
47
48 <h3>pickinput (I)</h3>
49 <p>Pick the current row as next input line in IPython. Additionally the row is stored as "_"</p>
50
51 <h3>pickinputattr (Shift-I)</h3>
52 <p>Pick the attribute under the cursor as next input line in IPython. Additionally the row is stored as "_"</p>
53
54 <h3>enter (E)</h3>
55 <p>Enter the object under the cursor. (what this mean depends on the object
56 itself, i.e. how it implements iteration). This opens a new browser 'level'.</p>
57
58 <h3>enterattr (Shift-E)</h3>
59 <p>Enter the attribute under the cursor.</p>
60
61 <h3>detail (D)</h3>
62 <p>Show a detail view of the object under the cursor. This shows the name,
63 type, doc string and value of the object attributes (and it might show more
64 attributes than in the list view, depending on the object).</p>
65
66 <h3>detailattr (Shift-D)</h3>
67 <p>Show a detail view of the attribute under the cursor.</p>
68
69 <h3>pickrows (M)</h3>
70 <p>Pick multiple selected rows (M)</p>
71
72 <h3>pickrowsattr (CTRL-M)</h3>
73 <p>From multiple selected rows pick the cells matching the attribute the cursor is in (CTRL-M)</p>
74
75 <h3>find (CTRL-F)</h3>
76 <p>Find text</p>
77
78 <h3>find_expression (CTRL-Shift-F)</h3>
79 <p>Find entries matching an expression</p>
80
81 <h3>find_next (F3)</h3>
82 <p>Find next occurrence</p>
83
84 <h3>find_previous (Shift-F3)</h3>
85 <p>Find previous occurrence</p>
86
87 <h3>sortattrasc (V)</h3>
88 <p>Sort the objects (in ascending order) using the attribute under the cursor as the sort key.</p>
89
90 <h3>sortattrdesc (Shift-V)</h3>
91 <p>Sort the objects (in descending order) using the attribute under the cursor as the sort key.</p>
92
93 <h3>refresh_once (R, F5)</h3>
94 <p>Refreshes the display by restarting the iterator</p>
95
96 <h3>refresh_every_second</h3>
97 <p>Refreshes the display by restarting the iterator every second until stopped by stop_refresh.</p>
98
99 <h3>refresh_interval</h3>
100 <p>Refreshes the display by restarting the iterator every X ms (X is a custom interval set by the user) until stopped by stop_refresh.</p>
101
102 <h3>stop_refresh</h3>
103 <p>Stops all refresh timers.</p>
104
105 <h3>leave (Backspace, DEL, X)</h3>
106 <p>Close current tab (and all the tabs to the right of the current one).</h3>
107
108 <h3>quit (ESC,Q)</h3>
109 <p>Quit igrid and return to the IPython prompt.</p>
110
111
112 <h2>Navigation</h2>
113
114
115 <h3>Jump to the last column of the current row (END, CTRL-E, CTRL-Right)</h3>
116
117 <h3>Jump to the first column of the current row (HOME, CTRL-A, CTRL-Left)</h3>
118
119 <h3>Move the cursor one column to the left (&lt;)</h3>
120
121 <h3>Move the cursor one column to the right (&gt;)</h3>
122
123 <h3>Jump to the first row in the current column (CTRL-Up)</h3>
124
125 <h3>Jump to the last row in the current column (CTRL-Down)</h3>
126
127 </body>
128 </html>
129
130 """
131
132
133 class IGridRenderer(wx.grid.PyGridCellRenderer):
134 """
135 This is a custom renderer for our IGridGrid
136 """
137 def __init__(self, table):
138 self.maxchars = 200
139 self.table = table
140 self.colormap = (
141 ( 0, 0, 0),
142 (174, 0, 0),
143 ( 0, 174, 0),
144 (174, 174, 0),
145 ( 0, 0, 174),
146 (174, 0, 174),
147 ( 0, 174, 174),
148 ( 64, 64, 64)
149 )
150
151 wx.grid.PyGridCellRenderer.__init__(self)
152
153 def _getvalue(self, row, col):
154 try:
155 value = self.table._displayattrs[col].value(self.table.items[row])
156 (align, width, text) = ipipe.xformat(value, "cell", self.maxchars)
157 except Exception as exc:
158 (align, width, text) = ipipe.xformat(exc, "cell", self.maxchars)
159 return (align, text)
160
161 def GetBestSize(self, grid, attr, dc, row, col):
162 text = grid.GetCellValue(row, col)
163 (align, text) = self._getvalue(row, col)
164 dc.SetFont(attr.GetFont())
165 (w, h) = dc.GetTextExtent(str(text))
166 return wx.Size(min(w+2, 600), h+2) # add border
167
168 def Draw(self, grid, attr, dc, rect, row, col, isSelected):
169 """
170 Takes care of drawing everything in the cell; aligns the text
171 """
172 text = grid.GetCellValue(row, col)
173 (align, text) = self._getvalue(row, col)
174 if isSelected:
175 bg = grid.GetSelectionBackground()
176 else:
177 bg = ["white", (240, 240, 240)][row%2]
178 dc.SetTextBackground(bg)
179 dc.SetBrush(wx.Brush(bg, wx.SOLID))
180 dc.SetPen(wx.TRANSPARENT_PEN)
181 dc.SetFont(attr.GetFont())
182 dc.DrawRectangleRect(rect)
183 dc.SetClippingRect(rect)
184 # Format the text
185 if align == -1: # left alignment
186 (width, height) = dc.GetTextExtent(str(text))
187 x = rect[0]+1
188 y = rect[1]+0.5*(rect[3]-height)
189
190 for (style, part) in text:
191 if isSelected:
192 fg = grid.GetSelectionForeground()
193 else:
194 fg = self.colormap[style.fg]
195 dc.SetTextForeground(fg)
196 (w, h) = dc.GetTextExtent(part)
197 dc.DrawText(part, x, y)
198 x += w
199 elif align == 0: # center alignment
200 (width, height) = dc.GetTextExtent(str(text))
201 x = rect[0]+0.5*(rect[2]-width)
202 y = rect[1]+0.5*(rect[3]-height)
203 for (style, part) in text:
204 if isSelected:
205 fg = grid.GetSelectionForeground()
206 else:
207 fg = self.colormap[style.fg]
208 dc.SetTextForeground(fg)
209 (w, h) = dc.GetTextExtent(part)
210 dc.DrawText(part, x, y)
211 x += w
212 else: # right alignment
213 (width, height) = dc.GetTextExtent(str(text))
214 x = rect[0]+rect[2]-1
215 y = rect[1]+0.5*(rect[3]-height)
216 for (style, part) in reversed(text):
217 (w, h) = dc.GetTextExtent(part)
218 x -= w
219 if isSelected:
220 fg = grid.GetSelectionForeground()
221 else:
222 fg = self.colormap[style.fg]
223 dc.SetTextForeground(fg)
224 dc.DrawText(part, x, y)
225 dc.DestroyClippingRegion()
226
227 def Clone(self):
228 return IGridRenderer(self.table)
229
230
231 class IGridTable(wx.grid.PyGridTableBase):
232 # The data table for the ``IGridGrid``. Some dirty tricks were used here:
233 # ``GetValue()`` does not get any values (or at least it does not return
234 # anything, accessing the values is done by the renderer)
235 # but rather tries to fetch the objects which were requested into the table.
236 # General behaviour is: Fetch the first X objects. If the user scrolls down
237 # to the last object another bunch of X objects is fetched (if possible)
238 def __init__(self, input, fontsize, *attrs):
239 wx.grid.PyGridTableBase.__init__(self)
240 self.input = input
241 self.iterator = ipipe.xiter(input)
242 self.items = []
243 self.attrs = [ipipe.upgradexattr(attr) for attr in attrs]
244 self._displayattrs = self.attrs[:]
245 self._displayattrset = set(self.attrs)
246 self.fontsize = fontsize
247 self._fetch(1)
248 self.timer = wx.Timer()
249 self.timer.Bind(wx.EVT_TIMER, self.refresh_content)
250
251 def GetAttr(self, *args):
252 attr = wx.grid.GridCellAttr()
253 attr.SetFont(wx.Font(self.fontsize, wx.TELETYPE, wx.NORMAL, wx.NORMAL))
254 return attr
255
256 def GetNumberRows(self):
257 return len(self.items)
258
259 def GetNumberCols(self):
260 return len(self._displayattrs)
261
262 def GetColLabelValue(self, col):
263 if col < len(self._displayattrs):
264 return self._displayattrs[col].name()
265 else:
266 return ""
267
268 def GetRowLabelValue(self, row):
269 return str(row)
270
271 def IsEmptyCell(self, row, col):
272 return False
273
274 def _append(self, item):
275 self.items.append(item)
276 # Nothing to do if the set of attributes has been fixed by the user
277 if not self.attrs:
278 for attr in ipipe.xattrs(item):
279 attr = ipipe.upgradexattr(attr)
280 if attr not in self._displayattrset:
281 self._displayattrs.append(attr)
282 self._displayattrset.add(attr)
283
284 def _fetch(self, count):
285 # Try to fill ``self.items`` with at least ``count`` objects.
286 have = len(self.items)
287 while self.iterator is not None and have < count:
288 try:
289 item = self.iterator.next()
290 except StopIteration:
291 self.iterator = None
292 break
293 except (KeyboardInterrupt, SystemExit):
294 raise
295 except Exception as exc:
296 have += 1
297 self._append(exc)
298 self.iterator = None
299 break
300 else:
301 have += 1
302 self._append(item)
303
304 def GetValue(self, row, col):
305 # some kind of dummy-function: does not return anything but "";
306 # (The value isn't use anyway)
307 # its main task is to trigger the fetch of new objects
308 sizing_needed = False
309 had_cols = len(self._displayattrs)
310 had_rows = len(self.items)
311 if row == had_rows - 1 and self.iterator is not None:
312 self._fetch(row + 20)
313 sizing_needed = True
314 have_rows = len(self.items)
315 have_cols = len(self._displayattrs)
316 if have_rows > had_rows:
317 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED, have_rows - had_rows)
318 self.GetView().ProcessTableMessage(msg)
319 sizing_needed = True
320 if row >= have_rows:
321 return ""
322 if have_cols != had_cols:
323 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED, have_cols - had_cols)
324 self.GetView().ProcessTableMessage(msg)
325 sizing_needed = True
326 if sizing_needed:
327 self.GetView().AutoSizeColumns(False)
328 return ""
329
330 def SetValue(self, row, col, value):
331 pass
332
333 def refresh_content(self, event):
334 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, 0, self.GetNumberRows())
335 self.GetView().ProcessTableMessage(msg)
336 self.iterator = ipipe.xiter(self.input)
337 self.items = []
338 self.attrs = [] # _append will calculate new displayattrs
339 self._fetch(1) # fetch one...
340 if self.items:
341 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED, 1)
342 self.GetView().ProcessTableMessage(msg)
343 self.GetValue(0, 0) # and trigger "fetch next 20"
344 item = self.items[0]
345 self.GetView().AutoSizeColumns(False)
346 panel = self.GetView().GetParent()
347 nb = panel.GetParent()
348 current = nb.GetSelection()
349 if nb.GetPage(current) == panel:
350 self.GetView().set_footer(item)
351
352 class IGridGrid(wx.grid.Grid):
353 # The actual grid
354 # all methods for selecting/sorting/picking/... data are implemented here
355 def __init__(self, panel, input, *attrs):
356 wx.grid.Grid.__init__(self, panel)
357 fontsize = 9
358 self.input = input
359 self.table = IGridTable(self.input, fontsize, *attrs)
360 self.SetTable(self.table, True)
361 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
362 self.SetDefaultRenderer(IGridRenderer(self.table))
363 self.EnableEditing(False)
364 self.Bind(wx.EVT_KEY_DOWN, self.key_pressed)
365 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.cell_doubleclicked)
366 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.cell_leftclicked)
367 self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_DCLICK, self.label_doubleclicked)
368 self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.on_label_leftclick)
369 self.Bind(wx.grid.EVT_GRID_RANGE_SELECT, self._on_selected_range)
370 self.Bind(wx.grid.EVT_GRID_SELECT_CELL, self._on_selected_cell)
371 self.current_selection = set()
372 self.maxchars = 200
373
374 def on_label_leftclick(self, event):
375 event.Skip()
376
377 def error_output(self, text):
378 wx.Bell()
379 frame = self.GetParent().GetParent().GetParent()
380 frame.SetStatusText(str(text))
381
382 def _on_selected_range(self, event):
383 # Internal update to the selection tracking lists
384 if event.Selecting():
385 # adding to the list...
386 self.current_selection.update(xrange(event.GetTopRow(), event.GetBottomRow()+1))
387 else:
388 # removal from list
389 for index in xrange(event.GetTopRow(), event.GetBottomRow()+1):
390 self.current_selection.discard(index)
391 event.Skip()
392
393 def _on_selected_cell(self, event):
394 # Internal update to the selection tracking list
395 self.current_selection = set([event.GetRow()])
396 event.Skip()
397
398 def sort(self, key, reverse=False):
399 """
400 Sort the current list of items using the key function ``key``. If
401 ``reverse`` is true the sort order is reversed.
402 """
403 row = self.GetGridCursorRow()
404 col = self.GetGridCursorCol()
405 curitem = self.table.items[row] # Remember where the cursor is now
406 # Sort items
407 def realkey(item):
408 try:
409 return key(item)
410 except (KeyboardInterrupt, SystemExit):
411 raise
412 except Exception:
413 return None
414 try:
415 self.table.items = ipipe.deque(sorted(self.table.items, key=realkey, reverse=reverse))
416 except TypeError as exc:
417 self.error_output("Exception encountered: %s" % exc)
418 return
419 # Find out where the object under the cursor went
420 for (i, item) in enumerate(self.table.items):
421 if item is curitem:
422 self.SetGridCursor(i,col)
423 self.MakeCellVisible(i,col)
424 self.Refresh()
425
426 def sortattrasc(self):
427 """
428 Sort in ascending order; sorting criteria is the current attribute
429 """
430 col = self.GetGridCursorCol()
431 attr = self.table._displayattrs[col]
432 frame = self.GetParent().GetParent().GetParent()
433 if attr is ipipe.noitem:
434 self.error_output("no column under cursor")
435 return
436 frame.SetStatusText("sort by %s (ascending)" % attr.name())
437 def key(item):
438 try:
439 return attr.value(item)
440 except (KeyboardInterrupt, SystemExit):
441 raise
442 except Exception:
443 return None
444 self.sort(key)
445
446 def sortattrdesc(self):
447 """
448 Sort in descending order; sorting criteria is the current attribute
449 """
450 col = self.GetGridCursorCol()
451 attr = self.table._displayattrs[col]
452 frame = self.GetParent().GetParent().GetParent()
453 if attr is ipipe.noitem:
454 self.error_output("no column under cursor")
455 return
456 frame.SetStatusText("sort by %s (descending)" % attr.name())
457 def key(item):
458 try:
459 return attr.value(item)
460 except (KeyboardInterrupt, SystemExit):
461 raise
462 except Exception:
463 return None
464 self.sort(key, reverse=True)
465
466 def label_doubleclicked(self, event):
467 row = event.GetRow()
468 col = event.GetCol()
469 if col == -1:
470 self.enter(row)
471
472 def _getvalue(self, row, col):
473 """
474 Gets the text which is displayed at ``(row, col)``
475 """
476 try:
477 value = self.table._displayattrs[col].value(self.table.items[row])
478 (align, width, text) = ipipe.xformat(value, "cell", self.maxchars)
479 except IndexError:
480 raise IndexError
481 except Exception as exc:
482 (align, width, text) = ipipe.xformat(exc, "cell", self.maxchars)
483 return text
484
485 def searchexpression(self, searchexp, startrow=None, search_forward=True ):
486 """
487 Find by expression
488 """
489 frame = self.GetParent().GetParent().GetParent()
490 if searchexp:
491 if search_forward:
492 if not startrow:
493 row = self.GetGridCursorRow()+1
494 else:
495 row = startrow + 1
496 while True:
497 try:
498 foo = self.table.GetValue(row, 0)
499 item = self.table.items[row]
500 try:
501 globals = ipipe.getglobals(None)
502 if eval(searchexp, globals, ipipe.AttrNamespace(item)):
503 self.SetGridCursor(row, 0) # found something
504 self.MakeCellVisible(row, 0)
505 break
506 except (KeyboardInterrupt, SystemExit):
507 raise
508 except Exception as exc:
509 frame.SetStatusText(str(exc))
510 wx.Bell()
511 break # break on error
512 except IndexError:
513 return
514 row += 1
515 else:
516 if not startrow:
517 row = self.GetGridCursorRow() - 1
518 else:
519 row = startrow - 1
520 while True:
521 try:
522 foo = self.table.GetValue(row, 0)
523 item = self.table.items[row]
524 try:
525 globals = ipipe.getglobals(None)
526 if eval(searchexp, globals, ipipe.AttrNamespace(item)):
527 self.SetGridCursor(row, 0) # found something
528 self.MakeCellVisible(row, 0)
529 break
530 except (KeyboardInterrupt, SystemExit):
531 raise
532 except Exception as exc:
533 frame.SetStatusText(str(exc))
534 wx.Bell()
535 break # break on error
536 except IndexError:
537 return
538 row -= 1
539
540
541 def search(self, searchtext, startrow=None, startcol=None, search_forward=True):
542 """
543 search for ``searchtext``, starting in ``(startrow, startcol)``;
544 if ``search_forward`` is true the direction is "forward"
545 """
546 searchtext = searchtext.lower()
547 if search_forward:
548 if startrow is not None and startcol is not None:
549 row = startrow
550 else:
551 startcol = self.GetGridCursorCol() + 1
552 row = self.GetGridCursorRow()
553 if startcol >= self.GetNumberCols():
554 startcol = 0
555 row += 1
556 while True:
557 for col in xrange(startcol, self.table.GetNumberCols()):
558 try:
559 foo = self.table.GetValue(row, col)
560 text = self._getvalue(row, col)
561 if searchtext in text.string().lower():
562 self.SetGridCursor(row, col)
563 self.MakeCellVisible(row, col)
564 return
565 except IndexError:
566 return
567 startcol = 0
568 row += 1
569 else:
570 if startrow is not None and startcol is not None:
571 row = startrow
572 else:
573 startcol = self.GetGridCursorCol() - 1
574 row = self.GetGridCursorRow()
575 if startcol < 0:
576 startcol = self.GetNumberCols() - 1
577 row -= 1
578 while True:
579 for col in xrange(startcol, -1, -1):
580 try:
581 foo = self.table.GetValue(row, col)
582 text = self._getvalue(row, col)
583 if searchtext in text.string().lower():
584 self.SetGridCursor(row, col)
585 self.MakeCellVisible(row, col)
586 return
587 except IndexError:
588 return
589 startcol = self.table.GetNumberCols()-1
590 row -= 1
591
592 def key_pressed(self, event):
593 """
594 Maps pressed keys to functions
595 """
596 frame = self.GetParent().GetParent().GetParent()
597 frame.SetStatusText("")
598 sh = event.ShiftDown()
599 ctrl = event.ControlDown()
600
601 keycode = event.GetKeyCode()
602 if keycode == ord("P"):
603 row = self.GetGridCursorRow()
604 if sh:
605 col = self.GetGridCursorCol()
606 self.pickattr(row, col)
607 else:
608 self.pick(row)
609 elif keycode == ord("M"):
610 if ctrl:
611 col = self.GetGridCursorCol()
612 self.pickrowsattr(sorted(self.current_selection), col)
613 else:
614 self.pickrows(sorted(self.current_selection))
615 elif keycode in (wx.WXK_BACK, wx.WXK_DELETE, ord("X")) and not (ctrl or sh):
616 self.delete_current_notebook()
617 elif keycode in (ord("E"), ord("\r")):
618 row = self.GetGridCursorRow()
619 if sh:
620 col = self.GetGridCursorCol()
621 self.enterattr(row, col)
622 else:
623 self.enter(row)
624 elif keycode == ord("E") and ctrl:
625 row = self.GetGridCursorRow()
626 self.SetGridCursor(row, self.GetNumberCols()-1)
627 elif keycode == wx.WXK_HOME or (keycode == ord("A") and ctrl):
628 row = self.GetGridCursorRow()
629 self.SetGridCursor(row, 0)
630 elif keycode == ord("C") and sh:
631 col = self.GetGridCursorCol()
632 attr = self.table._displayattrs[col]
633 result = []
634 for i in xrange(self.GetNumberRows()):
635 result.append(self.table._displayattrs[col].value(self.table.items[i]))
636 self.quit(result)
637 elif keycode in (wx.WXK_ESCAPE, ord("Q")) and not (ctrl or sh):
638 self.quit()
639 elif keycode == ord("<"):
640 row = self.GetGridCursorRow()
641 col = self.GetGridCursorCol()
642 if not event.ShiftDown():
643 newcol = col - 1
644 if newcol >= 0:
645 self.SetGridCursor(row, col - 1)
646 else:
647 newcol = col + 1
648 if newcol < self.GetNumberCols():
649 self.SetGridCursor(row, col + 1)
650 elif keycode == ord("D"):
651 col = self.GetGridCursorCol()
652 row = self.GetGridCursorRow()
653 if not sh:
654 self.detail(row, col)
655 else:
656 self.detail_attr(row, col)
657 elif keycode == ord("F") and ctrl:
658 if sh:
659 frame.enter_searchexpression(event)
660 else:
661 frame.enter_searchtext(event)
662 elif keycode == wx.WXK_F3:
663 if sh:
664 frame.find_previous(event)
665 else:
666 frame.find_next(event)
667 elif keycode == ord("V"):
668 if sh:
669 self.sortattrdesc()
670 else:
671 self.sortattrasc()
672 elif keycode == wx.WXK_DOWN:
673 row = self.GetGridCursorRow()
674 try:
675 item = self.table.items[row+1]
676 except IndexError:
677 item = self.table.items[row]
678 self.set_footer(item)
679 event.Skip()
680 elif keycode == wx.WXK_UP:
681 row = self.GetGridCursorRow()
682 if row >= 1:
683 item = self.table.items[row-1]
684 else:
685 item = self.table.items[row]
686 self.set_footer(item)
687 event.Skip()
688 elif keycode == wx.WXK_RIGHT:
689 row = self.GetGridCursorRow()
690 item = self.table.items[row]
691 self.set_footer(item)
692 event.Skip()
693 elif keycode == wx.WXK_LEFT:
694 row = self.GetGridCursorRow()
695 item = self.table.items[row]
696 self.set_footer(item)
697 event.Skip()
698 elif keycode == ord("R") or keycode == wx.WXK_F5:
699 self.table.refresh_content(event)
700 elif keycode == ord("I"):
701 row = self.GetGridCursorRow()
702 if not sh:
703 self.pickinput(row)
704 else:
705 col = self.GetGridCursorCol()
706 self.pickinputattr(row, col)
707 else:
708 event.Skip()
709
710 def delete_current_notebook(self):
711 """
712 deletes the current notebook tab
713 """
714 panel = self.GetParent()
715 nb = panel.GetParent()
716 current = nb.GetSelection()
717 count = nb.GetPageCount()
718 if count > 1:
719 for i in xrange(count-1, current-1, -1):
720 nb.DeletePage(i)
721 nb.GetCurrentPage().grid.SetFocus()
722 else:
723 frame = nb.GetParent()
724 frame.SetStatusText("This is the last level!")
725
726 def _doenter(self, value, *attrs):
727 """
728 "enter" a special item resulting in a new notebook tab
729 """
730 panel = self.GetParent()
731 nb = panel.GetParent()
732 frame = nb.GetParent()
733 current = nb.GetSelection()
734 count = nb.GetPageCount()
735 try: # if we want to enter something non-iterable, e.g. a function
736 if current + 1 == count and value is not self.input: # we have an event in the last tab
737 frame._add_notebook(value, *attrs)
738 elif value != self.input: # we have to delete all tabs newer than [panel] first
739 for i in xrange(count-1, current, -1): # some tabs don't close if we don't close in *reverse* order
740 nb.DeletePage(i)
741 frame._add_notebook(value)
742 except TypeError as exc:
743 if exc.__class__.__module__ == "exceptions":
744 msg = "%s: %s" % (exc.__class__.__name__, exc)
745 else:
746 msg = "%s.%s: %s" % (exc.__class__.__module__, exc.__class__.__name__, exc)
747 frame.SetStatusText(msg)
748
749 def enterattr(self, row, col):
750 try:
751 attr = self.table._displayattrs[col]
752 value = attr.value(self.table.items[row])
753 except Exception as exc:
754 self.error_output(str(exc))
755 else:
756 self._doenter(value)
757
758 def set_footer(self, item):
759 frame = self.GetParent().GetParent().GetParent()
760 frame.SetStatusText(" ".join([str(text) for (style, text) in ipipe.xformat(item, "footer", 20)[2]]), 0)
761
762 def enter(self, row):
763 try:
764 value = self.table.items[row]
765 except Exception as exc:
766 self.error_output(str(exc))
767 else:
768 self._doenter(value)
769
770 def detail(self, row, col):
771 """
772 shows a detail-view of the current cell
773 """
774 try:
775 attr = self.table._displayattrs[col]
776 item = self.table.items[row]
777 except Exception as exc:
778 self.error_output(str(exc))
779 else:
780 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
781 self._doenter(attrs)
782
783 def detail_attr(self, row, col):
784 try:
785 attr = self.table._displayattrs[col]
786 item = attr.value(self.table.items[row])
787 except Exception as exc:
788 self.error_output(str(exc))
789 else:
790 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
791 self._doenter(attrs)
792
793 def quit(self, result=None):
794 """
795 quit
796 """
797 frame = self.GetParent().GetParent().GetParent()
798 if frame.helpdialog:
799 frame.helpdialog.Destroy()
800 app = frame.parent
801 if app is not None:
802 app.result = result
803 frame.Close()
804 frame.Destroy()
805
806 def cell_doubleclicked(self, event):
807 self.enterattr(event.GetRow(), event.GetCol())
808 event.Skip()
809
810 def cell_leftclicked(self, event):
811 row = event.GetRow()
812 item = self.table.items[row]
813 self.set_footer(item)
814 event.Skip()
815
816 def pick(self, row):
817 """
818 pick a single row and return to the IPython prompt
819 """
820 try:
821 value = self.table.items[row]
822 except Exception as exc:
823 self.error_output(str(exc))
824 else:
825 self.quit(value)
826
827 def pickinput(self, row):
828 try:
829 value = self.table.items[row]
830 except Exception as exc:
831 self.error_output(str(exc))
832 else:
833 api = ipapi.get()
834 api.set_next_input(str(value))
835 self.quit(value)
836
837 def pickinputattr(self, row, col):
838 try:
839 attr = self.table._displayattrs[col]
840 value = attr.value(self.table.items[row])
841 except Exception as exc:
842 self.error_output(str(exc))
843 else:
844 api = ipapi.get()
845 api.set_next_input(str(value))
846 self.quit(value)
847
848 def pickrows(self, rows):
849 """
850 pick multiple rows and return to the IPython prompt
851 """
852 try:
853 value = [self.table.items[row] for row in rows]
854 except Exception as exc:
855 self.error_output(str(exc))
856 else:
857 self.quit(value)
858
859 def pickrowsattr(self, rows, col):
860 """"
861 pick one column from multiple rows
862 """
863 values = []
864 try:
865 attr = self.table._displayattrs[col]
866 for row in rows:
867 try:
868 values.append(attr.value(self.table.items[row]))
869 except (SystemExit, KeyboardInterrupt):
870 raise
871 except Exception:
872 raise #pass
873 except Exception as exc:
874 self.error_output(str(exc))
875 else:
876 self.quit(values)
877
878 def pickattr(self, row, col):
879 try:
880 attr = self.table._displayattrs[col]
881 value = attr.value(self.table.items[row])
882 except Exception as exc:
883 self.error_output(str(exc))
884 else:
885 self.quit(value)
886
887
888 class IGridPanel(wx.Panel):
889 # Each IGridPanel contains an IGridGrid
890 def __init__(self, parent, input, *attrs):
891 wx.Panel.__init__(self, parent, -1)
892 self.grid = IGridGrid(self, input, *attrs)
893 self.grid.FitInside()
894 sizer = wx.BoxSizer(wx.VERTICAL)
895 sizer.Add(self.grid, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
896 self.SetSizer(sizer)
897 sizer.Fit(self)
898 sizer.SetSizeHints(self)
899
900
901 class IGridHTMLHelp(wx.Frame):
902 def __init__(self, parent, title, size):
903 wx.Frame.__init__(self, parent, -1, title, size=size)
904 html = wx.html.HtmlWindow(self)
905 if "gtk2" in wx.PlatformInfo:
906 html.SetStandardFonts()
907 html.SetPage(help)
908
909
910 class IGridFrame(wx.Frame):
911 maxtitlelen = 30
912
913 def __init__(self, parent, input):
914 title = " ".join([str(text) for (style, text) in ipipe.xformat(input, "header", 20)[2]])
915 wx.Frame.__init__(self, None, title=title, size=(640, 480))
916 self.menubar = wx.MenuBar()
917 self.menucounter = 100
918 self.m_help = wx.Menu()
919 self.m_search = wx.Menu()
920 self.m_sort = wx.Menu()
921 self.m_refresh = wx.Menu()
922 self.notebook = wx.Notebook(self, -1, style=0)
923 self.statusbar = self.CreateStatusBar(1, wx.ST_SIZEGRIP)
924 self.statusbar.SetFieldsCount(2)
925 self.SetStatusWidths([-1, 200])
926 self.parent = parent
927 self._add_notebook(input)
928 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
929 self.makemenu(self.m_sort, "&Sort (asc)\tV", "Sort ascending", self.sortasc)
930 self.makemenu(self.m_sort, "Sort (&desc)\tShift-V", "Sort descending", self.sortdesc)
931 self.makemenu(self.m_help, "&Help\tF1", "Help", self.display_help)
932 # self.makemenu(self.m_help, "&Show help in browser", "Show help in browser", self.display_help_in_browser)
933 self.makemenu(self.m_search, "&Find text\tCTRL-F", "Find text", self.enter_searchtext)
934 self.makemenu(self.m_search, "Find by &expression\tCTRL-Shift-F", "Find by expression", self.enter_searchexpression)
935 self.makemenu(self.m_search, "Find &next\tF3", "Find next", self.find_next)
936 self.makemenu(self.m_search, "Find &previous\tShift-F3", "Find previous", self.find_previous)
937 self.makemenu(self.m_refresh, "&Refresh once \tF5", "Refresh once", self.refresh_once)
938 self.makemenu(self.m_refresh, "Refresh every &1s", "Refresh every second", self.refresh_every_second)
939 self.makemenu(self.m_refresh, "Refresh every &X seconds", "Refresh every X seconds", self.refresh_interval)
940 self.makemenu(self.m_refresh, "&Stop all refresh timers", "Stop refresh timers", self.stop_refresh)
941 self.menubar.Append(self.m_search, "&Find")
942 self.menubar.Append(self.m_sort, "&Sort")
943 self.menubar.Append(self.m_refresh, "&Refresh")
944 self.menubar.Append(self.m_help, "&Help")
945 self.SetMenuBar(self.menubar)
946 self.searchtext = ""
947 self.searchexpression = ""
948 self.helpdialog = None
949 self.refresh_interval = 1000
950 self.SetStatusText("Refreshing inactive", 1)
951
952 def refresh_once(self, event):
953 table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
954 table.refresh_content(event)
955
956 def refresh_interval(self, event):
957 table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
958 dlg = wx.TextEntryDialog(self, "Enter refresh interval (milliseconds):", "Refresh timer:", defaultValue=str(self.refresh_interval))
959 if dlg.ShowModal() == wx.ID_OK:
960 try:
961 milliseconds = int(dlg.GetValue())
962 except ValueError as exc:
963 self.SetStatusText(str(exc))
964 else:
965 table.timer.Start(milliseconds=milliseconds, oneShot=False)
966 self.SetStatusText("Refresh timer set to %s ms" % milliseconds)
967 self.SetStatusText("Refresh interval: %s ms" % milliseconds, 1)
968 self.refresh_interval = milliseconds
969 dlg.Destroy()
970
971 def stop_refresh(self, event):
972 for i in xrange(self.notebook.GetPageCount()):
973 nb = self.notebook.GetPage(i)
974 nb.grid.table.timer.Stop()
975 self.SetStatusText("Refreshing inactive", 1)
976
977 def refresh_every_second(self, event):
978 table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
979 table.timer.Start(milliseconds=1000, oneShot=False)
980 self.SetStatusText("Refresh interval: 1000 ms", 1)
981
982 def sortasc(self, event):
983 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
984 grid.sortattrasc()
985
986 def sortdesc(self, event):
987 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
988 grid.sortattrdesc()
989
990 def find_previous(self, event):
991 """
992 find previous occurrences
993 """
994 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
995 if self.searchtext:
996 row = grid.GetGridCursorRow()
997 col = grid.GetGridCursorCol()
998 self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
999 if col-1 >= 0:
1000 grid.search(self.searchtext, row, col-1, False)
1001 else:
1002 grid.search(self.searchtext, row-1, grid.table.GetNumberCols()-1, False)
1003 elif self.searchexpression:
1004 self.SetStatusText("Search mode: expression; looking for %s" % repr(self.searchexpression)[2:-1])
1005 grid.searchexpression(searchexp=self.searchexpression, search_forward=False)
1006 else:
1007 self.SetStatusText("No search yet: please enter search-text or -expression")
1008
1009 def find_next(self, event):
1010 """
1011 find the next occurrence
1012 """
1013 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
1014 if self.searchtext != "":
1015 row = grid.GetGridCursorRow()
1016 col = grid.GetGridCursorCol()
1017 self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
1018 if col+1 < grid.table.GetNumberCols():
1019 grid.search(self.searchtext, row, col+1)
1020 else:
1021 grid.search(self.searchtext, row+1, 0)
1022 elif self.searchexpression != "":
1023 self.SetStatusText('Search mode: expression; looking for %s' % repr(self.searchexpression)[2:-1])
1024 grid.searchexpression(searchexp=self.searchexpression)
1025 else:
1026 self.SetStatusText("No search yet: please enter search-text or -expression")
1027
1028 def display_help(self, event):
1029 """
1030 Display a help dialog
1031 """
1032 if self.helpdialog:
1033 self.helpdialog.Destroy()
1034 self.helpdialog = IGridHTMLHelp(None, title="Help", size=wx.Size(600,400))
1035 self.helpdialog.Show()
1036
1037 def display_help_in_browser(self, event):
1038 """
1039 Show the help-HTML in a browser (as a ``HtmlWindow`` does not understand
1040 CSS this looks better)
1041 """
1042 filename = urllib.pathname2url(os.path.abspath(os.path.join(os.path.dirname(__file__), "igrid_help.html")))
1043 if not filename.startswith("file"):
1044 filename = "file:" + filename
1045 webbrowser.open(filename, new=1, autoraise=True)
1046
1047 def enter_searchexpression(self, event):
1048 dlg = wx.TextEntryDialog(self, "Find:", "Find matching expression:", defaultValue=self.searchexpression)
1049 if dlg.ShowModal() == wx.ID_OK:
1050 self.searchexpression = dlg.GetValue()
1051 self.searchtext = ""
1052 self.SetStatusText('Search mode: expression; looking for %s' % repr(self.searchexpression)[2:-1])
1053 self.notebook.GetPage(self.notebook.GetSelection()).grid.searchexpression(self.searchexpression)
1054 dlg.Destroy()
1055
1056 def makemenu(self, menu, label, help, cmd):
1057 menu.Append(self.menucounter, label, help)
1058 self.Bind(wx.EVT_MENU, cmd, id=self.menucounter)
1059 self.menucounter += 1
1060
1061 def _add_notebook(self, input, *attrs):
1062 # Adds another notebook which has the starting object ``input``
1063 panel = IGridPanel(self.notebook, input, *attrs)
1064 text = str(ipipe.xformat(input, "header", self.maxtitlelen)[2])
1065 if len(text) >= self.maxtitlelen:
1066 text = text[:self.maxtitlelen].rstrip(".") + "..."
1067 self.notebook.AddPage(panel, text, True)
1068 panel.grid.SetFocus()
1069 self.Layout()
1070
1071 def OnCloseWindow(self, event):
1072 self.Destroy()
1073
1074 def enter_searchtext(self, event):
1075 # Displays a dialog asking for the searchtext
1076 dlg = wx.TextEntryDialog(self, "Find:", "Find in list", defaultValue=self.searchtext)
1077 if dlg.ShowModal() == wx.ID_OK:
1078 self.searchtext = dlg.GetValue()
1079 self.searchexpression = ""
1080 self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
1081 self.notebook.GetPage(self.notebook.GetSelection()).grid.search(self.searchtext)
1082 dlg.Destroy()
1083
1084
1085 class App(wx.App):
1086 def __init__(self, input):
1087 self.input = input
1088 self.result = None # Result to be returned to IPython. Set by quit().
1089 wx.App.__init__(self)
1090
1091 def OnInit(self):
1092 frame = IGridFrame(self, self.input)
1093 frame.Show()
1094 self.SetTopWindow(frame)
1095 frame.Raise()
1096 return True
1097
1098
1099 class igrid(ipipe.Display):
1100 """
1101 This is a wx-based display object that can be used instead of ``ibrowse``
1102 (which is curses-based) or ``idump`` (which simply does a print).
1103 """
1104
1105 if wx.VERSION < (2, 7):
1106 def display(self):
1107 try:
1108 # Try to create a "standalone" frame. If this works we're probably
1109 # running with -wthread.
1110 # Note that this sets the parent of the frame to None, but we can't
1111 # pass a result object back to the shell anyway.
1112 frame = IGridFrame(None, self.input)
1113 frame.Show()
1114 frame.Raise()
1115 except wx.PyNoAppError:
1116 # There's no wx application yet => create one.
1117 app = App(self.input)
1118 app.MainLoop()
1119 return app.result
1120 else:
1121 # With wx 2.7 it gets simpler.
1122 def display(self):
1123 app = App(self.input)
1124 app.MainLoop()
1125 return app.result
1126
@@ -1,45 +0,0 b''
1 body
2 {
3 background-color: #fff;
4 color: #000;
5 font-family: "Verdana", "Arial", "XHelvetica", "Helvetica", sans-serif;
6 padding: 20px 30px;
7 margin: 0px;
8 font-size: 11px;
9 }
10 h1
11 {
12 font-family: "Trebuchet MS", sans-serif;
13 font-size: 24px;
14 margin: -20px -30px 4px -30px;
15 padding: 6px 30px;
16 font-weight: normal;
17 border-bottom: 1px solid #000;
18 letter-spacing: 1px;
19 background-color: #666;
20 color: #fff;
21 }
22 h2
23 {
24 font-family: "Trebuchet MS", sans-serif;
25 font-size: 20px;
26 padding: 14px 0px 2px 0px;
27 margin: 0px;
28 font-weight: bold;
29 color: #333;
30 }
31 h3
32 {
33 font-family: "Trebuchet MS", sans-serif;
34 font-size: 14px;
35 padding: 12px 0px 2px 0px;
36 margin: 0px;
37 font-weight: bold;
38 color: #333;
39 }
40 p
41 {
42 line-height: 120%;
43 margin: 0px 0px 6px 0px;
44 padding: 0px;
45 }
@@ -1,86 +0,0 b''
1 <?xml version='1.0' encoding='iso-8859-1'?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
6 <link rel="stylesheet" href="igrid_help.css" type="text/css" />
7 <title>igrid help</title>
8 </head>
9 <body>
10 <h1>igrid help</h1>
11
12
13 <h2>Commands</h2>
14
15
16 <h3>pick (P)</h3>
17 <p>Pick the whole row (object is available as "_")</p>
18
19 <h3>pickattr (Shift-P)</h3>
20 <p>Pick the attribute under the cursor</p>
21
22 <h3>pickallattrs (Shift-C)</h3>
23 <p>Pick' the complete column under the cursor (i.e. the attribute under the
24 cursor) from all currently fetched objects. These attributes will be returned
25 as a list.</p>
26
27 <h3>enter (E)</h3>
28 <p>Enter the object under the cursor. (what this mean depends on the object
29 itself, i.e. how it implements iteration). This opens a new browser 'level'.</p>
30
31 <h3>enterattr (Shift-E)</h3>
32 <p>Enter the attribute under the cursor.</p>
33
34 <h3>detail (D)</h3>
35 <p>Show a detail view of the object under the cursor. This shows the name,
36 type, doc string and value of the object attributes (and it might show more
37 attributes than in the list view, depending on the object).</p>
38
39 <h3>detailattr (Shift-D)</h3>
40 <p>Show a detail view of the attribute under the cursor.</p>
41
42 <h3>pickrows (M)</h3>
43 <p>Pick multiple selected rows (M)</p>
44
45 <h3>pickrowsattr (CTRL-M)</h3>
46 <p>From multiple selected rows pick the cells matching the attribute the cursor is in (CTRL-M)</p>
47
48 <h3>find (CTRL-F)</h3>
49 <p>Find text</p>
50
51 <h3>find_next (F3)</h3>
52 <p>Find next occurrence of the searchtext</p>
53
54 <h3>find_previous (Shift-F3)</h3>
55 <p>Find previous occurrence of the searchtext </p>
56
57 <h3>sortattrasc (V)</h3>
58 <p>Sort the objects (in ascending order) using the attribute under the cursor as the sort key.</p>
59
60 <h3>sortattrdesc (Shift-V)</h3>
61 <p>Sort the objects (in descending order) using the attribute under the cursor as the sort key.</p>
62
63 <h3>leave (Backspace, DEL, X)</h3>
64 <p>Close current tab (and all the tabs to the right of the current one).</h3>
65
66 <h3>quit (ESC,Q)</h3>
67 <p>Quit igrid and return to the IPython prompt.</p>
68
69
70 <h2>Navigation</h2>
71
72
73 <h3>Jump to the last column of the current row (END, CTRL-E, CTRL-Right)</h3>
74
75 <h3>Jump to the first column of the current row (HOME, CTRL-A, CTRL-Left)</h3>
76
77 <h3>Move the cursor one column to the left (&lt;)</h3>
78
79 <h3>Move the cursor one column to the right (&gt;)</h3>
80
81 <h3>Jump to the first row in the current column (CTRL-Up)</h3>
82
83 <h3>Jump to the last row in the current column (CTRL-Down)</h3>
84
85 </body>
86 </html>
This diff has been collapsed as it changes many lines, (2328 lines changed) Show them Hide them
@@ -1,2328 +0,0 b''
1 # -*- coding: iso-8859-1 -*-
2
3 """
4 ``ipipe`` provides classes to be used in an interactive Python session. Doing a
5 ``from ipipe import *`` is the preferred way to do this. The name of all
6 objects imported this way starts with ``i`` to minimize collisions.
7
8 ``ipipe`` supports "pipeline expressions", which is something resembling Unix
9 pipes. An example is::
10
11 >>> ienv | isort("key.lower()")
12
13 This gives a listing of all environment variables sorted by name.
14
15
16 There are three types of objects in a pipeline expression:
17
18 * ``Table``s: These objects produce items. Examples are ``ils`` (listing the
19 current directory, ``ienv`` (listing environment variables), ``ipwd`` (listing
20 user accounts) and ``igrp`` (listing user groups). A ``Table`` must be the
21 first object in a pipe expression.
22
23 * ``Pipe``s: These objects sit in the middle of a pipe expression. They
24 transform the input in some way (e.g. filtering or sorting it). Examples are:
25 ``ifilter`` (which filters the input pipe), ``isort`` (which sorts the input
26 pipe) and ``ieval`` (which evaluates a function or expression for each object
27 in the input pipe).
28
29 * ``Display``s: These objects can be put as the last object in a pipeline
30 expression. There are responsible for displaying the result of the pipeline
31 expression. If a pipeline expression doesn't end in a display object a default
32 display objects will be used. One example is ``ibrowse`` which is a ``curses``
33 based browser.
34
35
36 Adding support for pipeline expressions to your own objects can be done through
37 three extensions points (all of them optional):
38
39 * An object that will be displayed as a row by a ``Display`` object should
40 implement the method ``__xattrs__(self, mode)`` method or register an
41 implementation of the generic function ``xattrs``. For more info see ``xattrs``.
42
43 * When an object ``foo`` is displayed by a ``Display`` object, the generic
44 function ``xrepr`` is used.
45
46 * Objects that can be iterated by ``Pipe``s must iterable. For special cases,
47 where iteration for display is different than the normal iteration a special
48 implementation can be registered with the generic function ``xiter``. This
49 makes it possible to use dictionaries and modules in pipeline expressions,
50 for example::
51
52 >>> import sys
53 >>> sys | ifilter("isinstance(value, int)") | idump
54 key |value
55 api_version| 1012
56 dllhandle | 503316480
57 hexversion | 33817328
58 maxint |2147483647
59 maxunicode | 65535
60 >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()")
61 ...
62
63 Note: The expression strings passed to ``ifilter()`` and ``isort()`` can
64 refer to the object to be filtered or sorted via the variable ``_`` and to any
65 of the attributes of the object, i.e.::
66
67 >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()")
68
69 does the same as::
70
71 >>> sys.modules | ifilter("value is not None") | isort("key.lower()")
72
73 In addition to expression strings, it's possible to pass callables (taking
74 the object as an argument) to ``ifilter()``, ``isort()`` and ``ieval()``::
75
76 >>> sys | ifilter(lambda _:isinstance(_.value, int)) \
77 ... | ieval(lambda _: (_.key, hex(_.value))) | idump
78 0 |1
79 api_version|0x3f4
80 dllhandle |0x1e000000
81 hexversion |0x20402f0
82 maxint |0x7fffffff
83 maxunicode |0xffff
84 """
85
86 skip_doctest = True # ignore top-level docstring as a doctest.
87
88 import sys, os, os.path, stat, glob, new, csv, datetime, types
89 import itertools, mimetypes, StringIO
90
91 try: # Python 2.3 compatibility
92 import collections
93 except ImportError:
94 deque = list
95 else:
96 deque = collections.deque
97
98 try: # Python 2.3 compatibility
99 set
100 except NameError:
101 import sets
102 set = sets.Set
103
104 try: # Python 2.3 compatibility
105 sorted
106 except NameError:
107 def sorted(iterator, key=None, reverse=False):
108 items = list(iterator)
109 if key is not None:
110 items.sort(lambda i1, i2: cmp(key(i1), key(i2)))
111 else:
112 items.sort()
113 if reverse:
114 items.reverse()
115 return items
116
117 try: # Python 2.4 compatibility
118 GeneratorExit
119 except NameError:
120 GeneratorExit = SystemExit
121
122 try:
123 import pwd
124 except ImportError:
125 pwd = None
126
127 try:
128 import grp
129 except ImportError:
130 grp = None
131
132 from IPython.external import simplegeneric
133 from IPython.external import path
134
135 try:
136 import IPython.utils.io
137 from IPython.utils import generics
138 except ImportError:
139 Term = None
140 generics = None
141
142 from IPython.core import ipapi
143
144
145 __all__ = [
146 "ifile", "ils", "iglob", "iwalk", "ipwdentry", "ipwd", "igrpentry", "igrp",
147 "icsv", "ix", "ichain", "isort", "ifilter", "ieval", "ienum",
148 "ienv", "ihist", "ialias", "icap", "idump", "iless"
149 ]
150
151
152 os.stat_float_times(True) # enable microseconds
153
154
155 class AttrNamespace(object):
156 """
157 Helper class that is used for providing a namespace for evaluating
158 expressions containing attribute names of an object.
159 """
160 def __init__(self, wrapped):
161 self.wrapped = wrapped
162
163 def __getitem__(self, name):
164 if name == "_":
165 return self.wrapped
166 try:
167 return getattr(self.wrapped, name)
168 except AttributeError:
169 raise KeyError(name)
170
171 # Python 2.3 compatibility
172 # use eval workaround to find out which names are used in the
173 # eval string and put them into the locals. This works for most
174 # normal uses case, bizarre ones like accessing the locals()
175 # will fail
176 try:
177 eval("_", None, AttrNamespace(None))
178 except TypeError:
179 real_eval = eval
180 def eval(codestring, _globals, _locals):
181 """
182 eval(source[, globals[, locals]]) -> value
183
184 Evaluate the source in the context of globals and locals.
185 The source may be a string representing a Python expression
186 or a code object as returned by compile().
187 The globals must be a dictionary and locals can be any mappping.
188
189 This function is a workaround for the shortcomings of
190 Python 2.3's eval.
191 """
192
193 if isinstance(codestring, basestring):
194 code = compile(codestring, "_eval", "eval")
195 else:
196 code = codestring
197 newlocals = {}
198 for name in code.co_names:
199 try:
200 newlocals[name] = _locals[name]
201 except KeyError:
202 pass
203 return real_eval(code, _globals, newlocals)
204
205
206 noitem = object()
207
208
209 def item(iterator, index, default=noitem):
210 """
211 Return the ``index``th item from the iterator ``iterator``.
212 ``index`` must be an integer (negative integers are relative to the
213 end (i.e. the last items produced by the iterator)).
214
215 If ``default`` is given, this will be the default value when
216 the iterator doesn't contain an item at this position. Otherwise an
217 ``IndexError`` will be raised.
218
219 Note that using this function will partially or totally exhaust the
220 iterator.
221 """
222 i = index
223 if i>=0:
224 for item in iterator:
225 if not i:
226 return item
227 i -= 1
228 else:
229 i = -index
230 cache = deque()
231 for item in iterator:
232 cache.append(item)
233 if len(cache)>i:
234 cache.popleft()
235 if len(cache)==i:
236 return cache.popleft()
237 if default is noitem:
238 raise IndexError(index)
239 else:
240 return default
241
242
243 def getglobals(g):
244 """
245 Return the global namespace that is used for expression strings in
246 ``ifilter`` and others. This is ``g`` or (if ``g`` is ``None``) IPython's
247 user namespace.
248 """
249 if g is None:
250 if ipapi is not None:
251 api = ipapi.get()
252 if api is not None:
253 return api.user_ns
254 return globals()
255 return g
256
257
258 class Descriptor(object):
259 """
260 A ``Descriptor`` object is used for describing the attributes of objects.
261 """
262 def __hash__(self):
263 return hash(self.__class__) ^ hash(self.key())
264
265 def __eq__(self, other):
266 return self.__class__ is other.__class__ and self.key() == other.key()
267
268 def __ne__(self, other):
269 return self.__class__ is not other.__class__ or self.key() != other.key()
270
271 def key(self):
272 pass
273
274 def name(self):
275 """
276 Return the name of this attribute for display by a ``Display`` object
277 (e.g. as a column title).
278 """
279 key = self.key()
280 if key is None:
281 return "_"
282 return str(key)
283
284 def attrtype(self, obj):
285 """
286 Return the type of this attribute (i.e. something like "attribute" or
287 "method").
288 """
289
290 def valuetype(self, obj):
291 """
292 Return the type of this attribute value of the object ``obj``.
293 """
294
295 def value(self, obj):
296 """
297 Return the value of this attribute of the object ``obj``.
298 """
299
300 def doc(self, obj):
301 """
302 Return the documentation for this attribute.
303 """
304
305 def shortdoc(self, obj):
306 """
307 Return a short documentation for this attribute (defaulting to the
308 first line).
309 """
310 doc = self.doc(obj)
311 if doc is not None:
312 doc = doc.strip().splitlines()[0].strip()
313 return doc
314
315 def iter(self, obj):
316 """
317 Return an iterator for this attribute of the object ``obj``.
318 """
319 return xiter(self.value(obj))
320
321
322 class SelfDescriptor(Descriptor):
323 """
324 A ``SelfDescriptor`` describes the object itself.
325 """
326 def key(self):
327 return None
328
329 def attrtype(self, obj):
330 return "self"
331
332 def valuetype(self, obj):
333 return type(obj)
334
335 def value(self, obj):
336 return obj
337
338 def __repr__(self):
339 return "Self"
340
341 selfdescriptor = SelfDescriptor() # there's no need for more than one
342
343
344 class AttributeDescriptor(Descriptor):
345 """
346 An ``AttributeDescriptor`` describes a simple attribute of an object.
347 """
348 __slots__ = ("_name", "_doc")
349
350 def __init__(self, name, doc=None):
351 self._name = name
352 self._doc = doc
353
354 def key(self):
355 return self._name
356
357 def doc(self, obj):
358 return self._doc
359
360 def attrtype(self, obj):
361 return "attr"
362
363 def valuetype(self, obj):
364 return type(getattr(obj, self._name))
365
366 def value(self, obj):
367 return getattr(obj, self._name)
368
369 def __repr__(self):
370 if self._doc is None:
371 return "Attribute(%r)" % self._name
372 else:
373 return "Attribute(%r, %r)" % (self._name, self._doc)
374
375
376 class IndexDescriptor(Descriptor):
377 """
378 An ``IndexDescriptor`` describes an "attribute" of an object that is fetched
379 via ``__getitem__``.
380 """
381 __slots__ = ("_index",)
382
383 def __init__(self, index):
384 self._index = index
385
386 def key(self):
387 return self._index
388
389 def attrtype(self, obj):
390 return "item"
391
392 def valuetype(self, obj):
393 return type(obj[self._index])
394
395 def value(self, obj):
396 return obj[self._index]
397
398 def __repr__(self):
399 return "Index(%r)" % self._index
400
401
402 class MethodDescriptor(Descriptor):
403 """
404 A ``MethodDescriptor`` describes a method of an object that can be called
405 without argument. Note that this method shouldn't change the object.
406 """
407 __slots__ = ("_name", "_doc")
408
409 def __init__(self, name, doc=None):
410 self._name = name
411 self._doc = doc
412
413 def key(self):
414 return self._name
415
416 def doc(self, obj):
417 if self._doc is None:
418 return getattr(obj, self._name).__doc__
419 return self._doc
420
421 def attrtype(self, obj):
422 return "method"
423
424 def valuetype(self, obj):
425 return type(self.value(obj))
426
427 def value(self, obj):
428 return getattr(obj, self._name)()
429
430 def __repr__(self):
431 if self._doc is None:
432 return "Method(%r)" % self._name
433 else:
434 return "Method(%r, %r)" % (self._name, self._doc)
435
436
437 class IterAttributeDescriptor(Descriptor):
438 """
439 An ``IterAttributeDescriptor`` works like an ``AttributeDescriptor`` but
440 doesn't return an attribute values (because this value might be e.g. a large
441 list).
442 """
443 __slots__ = ("_name", "_doc")
444
445 def __init__(self, name, doc=None):
446 self._name = name
447 self._doc = doc
448
449 def key(self):
450 return self._name
451
452 def doc(self, obj):
453 return self._doc
454
455 def attrtype(self, obj):
456 return "iter"
457
458 def valuetype(self, obj):
459 return noitem
460
461 def value(self, obj):
462 return noitem
463
464 def iter(self, obj):
465 return xiter(getattr(obj, self._name))
466
467 def __repr__(self):
468 if self._doc is None:
469 return "IterAttribute(%r)" % self._name
470 else:
471 return "IterAttribute(%r, %r)" % (self._name, self._doc)
472
473
474 class IterMethodDescriptor(Descriptor):
475 """
476 An ``IterMethodDescriptor`` works like an ``MethodDescriptor`` but doesn't
477 return an attribute values (because this value might be e.g. a large list).
478 """
479 __slots__ = ("_name", "_doc")
480
481 def __init__(self, name, doc=None):
482 self._name = name
483 self._doc = doc
484
485 def key(self):
486 return self._name
487
488 def doc(self, obj):
489 if self._doc is None:
490 return getattr(obj, self._name).__doc__
491 return self._doc
492
493 def attrtype(self, obj):
494 return "itermethod"
495
496 def valuetype(self, obj):
497 return noitem
498
499 def value(self, obj):
500 return noitem
501
502 def iter(self, obj):
503 return xiter(getattr(obj, self._name)())
504
505 def __repr__(self):
506 if self._doc is None:
507 return "IterMethod(%r)" % self._name
508 else:
509 return "IterMethod(%r, %r)" % (self._name, self._doc)
510
511
512 class FunctionDescriptor(Descriptor):
513 """
514 A ``FunctionDescriptor`` turns a function into a descriptor. The function
515 will be called with the object to get the type and value of the attribute.
516 """
517 __slots__ = ("_function", "_name", "_doc")
518
519 def __init__(self, function, name=None, doc=None):
520 self._function = function
521 self._name = name
522 self._doc = doc
523
524 def key(self):
525 return self._function
526
527 def name(self):
528 if self._name is not None:
529 return self._name
530 return getattr(self._function, "__xname__", self._function.__name__)
531
532 def doc(self, obj):
533 if self._doc is None:
534 return self._function.__doc__
535 return self._doc
536
537 def attrtype(self, obj):
538 return "function"
539
540 def valuetype(self, obj):
541 return type(self._function(obj))
542
543 def value(self, obj):
544 return self._function(obj)
545
546 def __repr__(self):
547 if self._doc is None:
548 return "Function(%r)" % self._name
549 else:
550 return "Function(%r, %r)" % (self._name, self._doc)
551
552
553 class Table(object):
554 """
555 A ``Table`` is an object that produces items (just like a normal Python
556 iterator/generator does) and can be used as the first object in a pipeline
557 expression. The displayhook will open the default browser for such an object
558 (instead of simply printing the ``repr()`` result).
559 """
560
561 # We want to support ``foo`` and ``foo()`` in pipeline expression:
562 # So we implement the required operators (``|`` and ``+``) in the metaclass,
563 # instantiate the class and forward the operator to the instance
564 class __metaclass__(type):
565 def __iter__(self):
566 return iter(self())
567
568 def __or__(self, other):
569 return self() | other
570
571 def __add__(self, other):
572 return self() + other
573
574 def __radd__(self, other):
575 return other + self()
576
577 def __getitem__(self, index):
578 return self()[index]
579
580 def __getitem__(self, index):
581 return item(self, index)
582
583 def __contains__(self, item):
584 for haveitem in self:
585 if item == haveitem:
586 return True
587 return False
588
589 def __or__(self, other):
590 # autoinstantiate right hand side
591 if isinstance(other, type) and issubclass(other, (Table, Display)):
592 other = other()
593 # treat simple strings and functions as ``ieval`` instances
594 elif not isinstance(other, Display) and not isinstance(other, Table):
595 other = ieval(other)
596 # forward operations to the right hand side
597 return other.__ror__(self)
598
599 def __add__(self, other):
600 # autoinstantiate right hand side
601 if isinstance(other, type) and issubclass(other, Table):
602 other = other()
603 return ichain(self, other)
604
605 def __radd__(self, other):
606 # autoinstantiate left hand side
607 if isinstance(other, type) and issubclass(other, Table):
608 other = other()
609 return ichain(other, self)
610
611
612 class Pipe(Table):
613 """
614 A ``Pipe`` is an object that can be used in a pipeline expression. It
615 processes the objects it gets from its input ``Table``/``Pipe``. Note that
616 a ``Pipe`` object can't be used as the first object in a pipeline
617 expression, as it doesn't produces items itself.
618 """
619 class __metaclass__(Table.__metaclass__):
620 def __ror__(self, input):
621 return input | self()
622
623 def __ror__(self, input):
624 # autoinstantiate left hand side
625 if isinstance(input, type) and issubclass(input, Table):
626 input = input()
627 self.input = input
628 return self
629
630
631 def xrepr(item, mode="default"):
632 """
633 Generic function that adds color output and different display modes to ``repr``.
634
635 The result of an ``xrepr`` call is iterable and consists of ``(style, string)``
636 tuples. The ``style`` in this tuple must be a ``Style`` object from the
637 ``astring`` module. To reconfigure the output the first yielded tuple can be
638 a ``(aligment, full)`` tuple instead of a ``(style, string)`` tuple.
639 ``alignment`` can be -1 for left aligned, 0 for centered and 1 for right
640 aligned (the default is left alignment). ``full`` is a boolean that specifies
641 whether the complete output must be displayed or the ``Display`` object is
642 allowed to stop output after enough text has been produced (e.g. a syntax
643 highlighted text line would use ``True``, but for a large data structure
644 (i.e. a nested list, tuple or dictionary) ``False`` would be used).
645 The default is full output.
646
647 There are four different possible values for ``mode`` depending on where
648 the ``Display`` object will display ``item``:
649
650 ``"header"``
651 ``item`` will be displayed in a header line (this is used by ``ibrowse``).
652
653 ``"footer"``
654 ``item`` will be displayed in a footer line (this is used by ``ibrowse``).
655
656 ``"cell"``
657 ``item`` will be displayed in a table cell/list.
658
659 ``"default"``
660 default mode. If an ``xrepr`` implementation recursively outputs objects,
661 ``"default"`` must be passed in the recursive calls to ``xrepr``.
662
663 If no implementation is registered for ``item``, ``xrepr`` will try the
664 ``__xrepr__`` method on ``item``. If ``item`` doesn't have an ``__xrepr__``
665 method it falls back to ``repr``/``__repr__`` for all modes.
666 """
667 try:
668 func = item.__xrepr__
669 except AttributeError:
670 yield (astyle.style_default, repr(item))
671 else:
672 try:
673 for x in func(mode):
674 yield x
675 except (KeyboardInterrupt, SystemExit, GeneratorExit):
676 raise
677 except Exception:
678 yield (astyle.style_default, repr(item))
679 xrepr = simplegeneric.generic(xrepr)
680
681
682 def xrepr_none(self, mode="default"):
683 yield (astyle.style_type_none, repr(self))
684 xrepr.when_object(None)(xrepr_none)
685
686
687 def xrepr_noitem(self, mode="default"):
688 yield (2, True)
689 yield (astyle.style_nodata, "<?>")
690 xrepr.when_object(noitem)(xrepr_noitem)
691
692
693 def xrepr_bool(self, mode="default"):
694 yield (astyle.style_type_bool, repr(self))
695 xrepr.when_type(bool)(xrepr_bool)
696
697
698 def xrepr_str(self, mode="default"):
699 if mode == "cell":
700 yield (astyle.style_default, repr(self.expandtabs(tab))[1:-1])
701 else:
702 yield (astyle.style_default, repr(self))
703 xrepr.when_type(str)(xrepr_str)
704
705
706 def xrepr_unicode(self, mode="default"):
707 if mode == "cell":
708 yield (astyle.style_default, repr(self.expandtabs(tab))[2:-1])
709 else:
710 yield (astyle.style_default, repr(self))
711 xrepr.when_type(unicode)(xrepr_unicode)
712
713
714 def xrepr_number(self, mode="default"):
715 yield (1, True)
716 yield (astyle.style_type_number, repr(self))
717 xrepr.when_type(int)(xrepr_number)
718 xrepr.when_type(long)(xrepr_number)
719 xrepr.when_type(float)(xrepr_number)
720
721
722 def xrepr_complex(self, mode="default"):
723 yield (astyle.style_type_number, repr(self))
724 xrepr.when_type(complex)(xrepr_number)
725
726
727 def xrepr_datetime(self, mode="default"):
728 if mode == "cell":
729 # Don't use strftime() here, as this requires year >= 1900
730 yield (astyle.style_type_datetime,
731 "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
732 (self.year, self.month, self.day,
733 self.hour, self.minute, self.second,
734 self.microsecond),
735 )
736 else:
737 yield (astyle.style_type_datetime, repr(self))
738 xrepr.when_type(datetime.datetime)(xrepr_datetime)
739
740
741 def xrepr_date(self, mode="default"):
742 if mode == "cell":
743 yield (astyle.style_type_datetime,
744 "%04d-%02d-%02d" % (self.year, self.month, self.day))
745 else:
746 yield (astyle.style_type_datetime, repr(self))
747 xrepr.when_type(datetime.date)(xrepr_date)
748
749
750 def xrepr_time(self, mode="default"):
751 if mode == "cell":
752 yield (astyle.style_type_datetime,
753 "%02d:%02d:%02d.%06d" % \
754 (self.hour, self.minute, self.second, self.microsecond))
755 else:
756 yield (astyle.style_type_datetime, repr(self))
757 xrepr.when_type(datetime.time)(xrepr_time)
758
759
760 def xrepr_timedelta(self, mode="default"):
761 yield (astyle.style_type_datetime, repr(self))
762 xrepr.when_type(datetime.timedelta)(xrepr_timedelta)
763
764
765 def xrepr_type(self, mode="default"):
766 if self.__module__ == "__builtin__":
767 yield (astyle.style_type_type, self.__name__)
768 else:
769 yield (astyle.style_type_type, "%s.%s" % (self.__module__, self.__name__))
770 xrepr.when_type(type)(xrepr_type)
771
772
773 def xrepr_exception(self, mode="default"):
774 if self.__class__.__module__ == "exceptions":
775 classname = self.__class__.__name__
776 else:
777 classname = "%s.%s" % \
778 (self.__class__.__module__, self.__class__.__name__)
779 if mode == "header" or mode == "footer":
780 yield (astyle.style_error, "%s: %s" % (classname, self))
781 else:
782 yield (astyle.style_error, classname)
783 xrepr.when_type(Exception)(xrepr_exception)
784
785
786 def xrepr_listtuple(self, mode="default"):
787 if mode == "header" or mode == "footer":
788 if self.__class__.__module__ == "__builtin__":
789 classname = self.__class__.__name__
790 else:
791 classname = "%s.%s" % \
792 (self.__class__.__module__,self.__class__.__name__)
793 yield (astyle.style_default,
794 "<%s object with %d items at 0x%x>" % \
795 (classname, len(self), id(self)))
796 else:
797 yield (-1, False)
798 if isinstance(self, list):
799 yield (astyle.style_default, "[")
800 end = "]"
801 else:
802 yield (astyle.style_default, "(")
803 end = ")"
804 for (i, subself) in enumerate(self):
805 if i:
806 yield (astyle.style_default, ", ")
807 for part in xrepr(subself, "default"):
808 yield part
809 yield (astyle.style_default, end)
810 xrepr.when_type(list)(xrepr_listtuple)
811 xrepr.when_type(tuple)(xrepr_listtuple)
812
813
814 def xrepr_dict(self, mode="default"):
815 if mode == "header" or mode == "footer":
816 if self.__class__.__module__ == "__builtin__":
817 classname = self.__class__.__name__
818 else:
819 classname = "%s.%s" % \
820 (self.__class__.__module__,self.__class__.__name__)
821 yield (astyle.style_default,
822 "<%s object with %d items at 0x%x>" % \
823 (classname, len(self), id(self)))
824 else:
825 yield (-1, False)
826 if isinstance(self, dict):
827 yield (astyle.style_default, "{")
828 end = "}"
829 else:
830 yield (astyle.style_default, "dictproxy((")
831 end = "})"
832 for (i, (key, value)) in enumerate(self.iteritems()):
833 if i:
834 yield (astyle.style_default, ", ")
835 for part in xrepr(key, "default"):
836 yield part
837 yield (astyle.style_default, ": ")
838 for part in xrepr(value, "default"):
839 yield part
840 yield (astyle.style_default, end)
841 xrepr.when_type(dict)(xrepr_dict)
842 xrepr.when_type(types.DictProxyType)(xrepr_dict)
843
844
845 def upgradexattr(attr):
846 """
847 Convert an attribute descriptor string to a real descriptor object.
848
849 If attr already is a descriptor object return it unmodified. A
850 ``SelfDescriptor`` will be returned if ``attr`` is ``None``. ``"foo"``
851 returns an ``AttributeDescriptor`` for the attribute named ``"foo"``.
852 ``"foo()"`` returns a ``MethodDescriptor`` for the method named ``"foo"``.
853 ``"-foo"`` will return an ``IterAttributeDescriptor`` for the attribute
854 named ``"foo"`` and ``"-foo()"`` will return an ``IterMethodDescriptor``
855 for the method named ``"foo"``. Furthermore integers will return the appropriate
856 ``IndexDescriptor`` and callables will return a ``FunctionDescriptor``.
857 """
858 if attr is None:
859 return selfdescriptor
860 elif isinstance(attr, Descriptor):
861 return attr
862 elif isinstance(attr, basestring):
863 if attr.endswith("()"):
864 if attr.startswith("-"):
865 return IterMethodDescriptor(attr[1:-2])
866 else:
867 return MethodDescriptor(attr[:-2])
868 else:
869 if attr.startswith("-"):
870 return IterAttributeDescriptor(attr[1:])
871 else:
872 return AttributeDescriptor(attr)
873 elif isinstance(attr, (int, long)):
874 return IndexDescriptor(attr)
875 elif callable(attr):
876 return FunctionDescriptor(attr)
877 else:
878 raise TypeError("can't handle descriptor %r" % attr)
879
880
881 def xattrs(item, mode="default"):
882 """
883 Generic function that returns an iterable of attribute descriptors
884 to be used for displaying the attributes ob the object ``item`` in display
885 mode ``mode``.
886
887 There are two possible modes:
888
889 ``"detail"``
890 The ``Display`` object wants to display a detailed list of the object
891 attributes.
892
893 ``"default"``
894 The ``Display`` object wants to display the object in a list view.
895
896 If no implementation is registered for the object ``item`` ``xattrs`` falls
897 back to trying the ``__xattrs__`` method of the object. If this doesn't
898 exist either, ``dir(item)`` is used for ``"detail"`` mode and ``(None,)``
899 for ``"default"`` mode.
900
901 The implementation must yield attribute descriptors (see the class
902 ``Descriptor`` for more info). The ``__xattrs__`` method may also return
903 attribute descriptor strings (and ``None``) which will be converted to real
904 descriptors by ``upgradexattr()``.
905 """
906 try:
907 func = item.__xattrs__
908 except AttributeError:
909 if mode == "detail":
910 for attrname in dir(item):
911 yield AttributeDescriptor(attrname)
912 else:
913 yield selfdescriptor
914 else:
915 for attr in func(mode):
916 yield upgradexattr(attr)
917 xattrs = simplegeneric.generic(xattrs)
918
919
920 def xattrs_complex(self, mode="default"):
921 if mode == "detail":
922 return (AttributeDescriptor("real"), AttributeDescriptor("imag"))
923 return (selfdescriptor,)
924 xattrs.when_type(complex)(xattrs_complex)
925
926
927 def _isdict(item):
928 try:
929 itermeth = item.__class__.__iter__
930 except (AttributeError, TypeError):
931 return False
932 return itermeth is dict.__iter__ or itermeth is types.DictProxyType.__iter__
933
934
935 def _isstr(item):
936 if not isinstance(item, basestring):
937 return False
938 try:
939 itermeth = item.__class__.__iter__
940 except AttributeError:
941 return True
942 return False # ``__iter__`` has been redefined
943
944
945 def xiter(item):
946 """
947 Generic function that implements iteration for pipeline expression. If no
948 implementation is registered for ``item`` ``xiter`` falls back to ``iter``.
949 """
950 try:
951 func = item.__xiter__
952 except AttributeError:
953 if _isdict(item):
954 def items(item):
955 fields = ("key", "value")
956 for (key, value) in item.iteritems():
957 yield Fields(fields, key=key, value=value)
958 return items(item)
959 elif isinstance(item, new.module):
960 def items(item):
961 fields = ("key", "value")
962 for key in sorted(item.__dict__):
963 yield Fields(fields, key=key, value=getattr(item, key))
964 return items(item)
965 elif _isstr(item):
966 if not item:
967 raise ValueError("can't enter empty string")
968 lines = item.splitlines()
969 if len(lines) == 1:
970 def iterone(item):
971 yield item
972 return iterone(item)
973 else:
974 return iter(lines)
975 return iter(item)
976 else:
977 return iter(func()) # iter() just to be safe
978 xiter = simplegeneric.generic(xiter)
979
980
981 class ichain(Pipe):
982 """
983 Chains multiple ``Table``s into one.
984 """
985
986 def __init__(self, *iters):
987 self.iters = iters
988
989 def __iter__(self):
990 return itertools.chain(*self.iters)
991
992 def __xrepr__(self, mode="default"):
993 if mode == "header" or mode == "footer":
994 for (i, item) in enumerate(self.iters):
995 if i:
996 yield (astyle.style_default, "+")
997 if isinstance(item, Pipe):
998 yield (astyle.style_default, "(")
999 for part in xrepr(item, mode):
1000 yield part
1001 if isinstance(item, Pipe):
1002 yield (astyle.style_default, ")")
1003 else:
1004 yield (astyle.style_default, repr(self))
1005
1006 def __repr__(self):
1007 args = ", ".join([repr(it) for it in self.iters])
1008 return "%s.%s(%s)" % \
1009 (self.__class__.__module__, self.__class__.__name__, args)
1010
1011
1012 class ifile(path.path):
1013 """
1014 file (or directory) object.
1015 """
1016
1017 def getmode(self):
1018 return self.stat().st_mode
1019 mode = property(getmode, None, None, "Access mode")
1020
1021 def gettype(self):
1022 data = [
1023 (stat.S_ISREG, "file"),
1024 (stat.S_ISDIR, "dir"),
1025 (stat.S_ISCHR, "chardev"),
1026 (stat.S_ISBLK, "blockdev"),
1027 (stat.S_ISFIFO, "fifo"),
1028 (stat.S_ISLNK, "symlink"),
1029 (stat.S_ISSOCK,"socket"),
1030 ]
1031 lstat = self.lstat()
1032 if lstat is not None:
1033 types = set([text for (func, text) in data if func(lstat.st_mode)])
1034 else:
1035 types = set()
1036 m = self.mode
1037 types.update([text for (func, text) in data if func(m)])
1038 return ", ".join(types)
1039 type = property(gettype, None, None, "file type (file, directory, link, etc.)")
1040
1041 def getmodestr(self):
1042 m = self.mode
1043 data = [
1044 (stat.S_IRUSR, "-r"),
1045 (stat.S_IWUSR, "-w"),
1046 (stat.S_IXUSR, "-x"),
1047 (stat.S_IRGRP, "-r"),
1048 (stat.S_IWGRP, "-w"),
1049 (stat.S_IXGRP, "-x"),
1050 (stat.S_IROTH, "-r"),
1051 (stat.S_IWOTH, "-w"),
1052 (stat.S_IXOTH, "-x"),
1053 ]
1054 return "".join([text[bool(m&bit)] for (bit, text) in data])
1055
1056 modestr = property(getmodestr, None, None, "Access mode as string")
1057
1058 def getblocks(self):
1059 return self.stat().st_blocks
1060 blocks = property(getblocks, None, None, "File size in blocks")
1061
1062 def getblksize(self):
1063 return self.stat().st_blksize
1064 blksize = property(getblksize, None, None, "Filesystem block size")
1065
1066 def getdev(self):
1067 return self.stat().st_dev
1068 dev = property(getdev)
1069
1070 def getnlink(self):
1071 return self.stat().st_nlink
1072 nlink = property(getnlink, None, None, "Number of links")
1073
1074 def getuid(self):
1075 return self.stat().st_uid
1076 uid = property(getuid, None, None, "User id of file owner")
1077
1078 def getgid(self):
1079 return self.stat().st_gid
1080 gid = property(getgid, None, None, "Group id of file owner")
1081
1082 def getowner(self):
1083 stat = self.stat()
1084 try:
1085 return pwd.getpwuid(stat.st_uid).pw_name
1086 except KeyError:
1087 return stat.st_uid
1088 owner = property(getowner, None, None, "Owner name (or id)")
1089
1090 def getgroup(self):
1091 stat = self.stat()
1092 try:
1093 return grp.getgrgid(stat.st_gid).gr_name
1094 except KeyError:
1095 return stat.st_gid
1096 group = property(getgroup, None, None, "Group name (or id)")
1097
1098 def getadate(self):
1099 return datetime.datetime.utcfromtimestamp(self.atime)
1100 adate = property(getadate, None, None, "Access date")
1101
1102 def getcdate(self):
1103 return datetime.datetime.utcfromtimestamp(self.ctime)
1104 cdate = property(getcdate, None, None, "Creation date")
1105
1106 def getmdate(self):
1107 return datetime.datetime.utcfromtimestamp(self.mtime)
1108 mdate = property(getmdate, None, None, "Modification date")
1109
1110 def mimetype(self):
1111 """
1112 Return MIME type guessed from the extension.
1113 """
1114 return mimetypes.guess_type(self.basename())[0]
1115
1116 def encoding(self):
1117 """
1118 Return guessed compression (like "compress" or "gzip").
1119 """
1120 return mimetypes.guess_type(self.basename())[1]
1121
1122 def __repr__(self):
1123 return "ifile(%s)" % path._base.__repr__(self)
1124
1125 if sys.platform == "win32":
1126 defaultattrs = (None, "type", "size", "modestr", "mdate")
1127 else:
1128 defaultattrs = (None, "type", "size", "modestr", "owner", "group", "mdate")
1129
1130 def __xattrs__(self, mode="default"):
1131 if mode == "detail":
1132 return (
1133 "name",
1134 "basename()",
1135 "abspath()",
1136 "realpath()",
1137 "type",
1138 "mode",
1139 "modestr",
1140 "stat()",
1141 "lstat()",
1142 "uid",
1143 "gid",
1144 "owner",
1145 "group",
1146 "dev",
1147 "nlink",
1148 "ctime",
1149 "mtime",
1150 "atime",
1151 "cdate",
1152 "mdate",
1153 "adate",
1154 "size",
1155 "blocks",
1156 "blksize",
1157 "isdir()",
1158 "islink()",
1159 "mimetype()",
1160 "encoding()",
1161 "-listdir()",
1162 "-dirs()",
1163 "-files()",
1164 "-walk()",
1165 "-walkdirs()",
1166 "-walkfiles()",
1167 )
1168 else:
1169 return self.defaultattrs
1170
1171
1172 def xiter_ifile(self):
1173 if self.isdir():
1174 yield (self / os.pardir).abspath()
1175 for child in sorted(self.listdir()):
1176 yield child
1177 else:
1178 f = self.open("rb")
1179 for line in f:
1180 yield line
1181 f.close()
1182 xiter.when_type(ifile)(xiter_ifile)
1183
1184
1185 # We need to implement ``xrepr`` for ``ifile`` as a generic function, because
1186 # otherwise ``xrepr_str`` would kick in.
1187 def xrepr_ifile(self, mode="default"):
1188 try:
1189 if self.isdir():
1190 name = "idir"
1191 style = astyle.style_dir
1192 else:
1193 name = "ifile"
1194 style = astyle.style_file
1195 except IOError:
1196 name = "ifile"
1197 style = astyle.style_default
1198 if mode in ("cell", "header", "footer"):
1199 abspath = repr(path._base(self.normpath()))
1200 if abspath.startswith("u"):
1201 abspath = abspath[2:-1]
1202 else:
1203 abspath = abspath[1:-1]
1204 if mode == "cell":
1205 yield (style, abspath)
1206 else:
1207 yield (style, "%s(%s)" % (name, abspath))
1208 else:
1209 yield (style, repr(self))
1210 xrepr.when_type(ifile)(xrepr_ifile)
1211
1212
1213 class ils(Table):
1214 """
1215 List the current (or a specified) directory.
1216
1217 Examples::
1218
1219 >>> ils
1220 <class 'IPython.extensions.ipipe.ils'>
1221 >>> ils("/usr/local/lib/python2.4")
1222 IPython.extensions.ipipe.ils('/usr/local/lib/python2.4')
1223 >>> ils("~")
1224 IPython.extensions.ipipe.ils('/home/fperez')
1225 # all-random
1226 """
1227 def __init__(self, base=os.curdir, dirs=True, files=True):
1228 self.base = os.path.expanduser(base)
1229 self.dirs = dirs
1230 self.files = files
1231
1232 def __iter__(self):
1233 base = ifile(self.base)
1234 yield (base / os.pardir).abspath()
1235 for child in sorted(base.listdir()):
1236 if self.dirs:
1237 if self.files:
1238 yield child
1239 else:
1240 if child.isdir():
1241 yield child
1242 elif self.files:
1243 if not child.isdir():
1244 yield child
1245
1246 def __xrepr__(self, mode="default"):
1247 return xrepr(ifile(self.base), mode)
1248
1249 def __repr__(self):
1250 return "%s.%s(%r)" % \
1251 (self.__class__.__module__, self.__class__.__name__, self.base)
1252
1253
1254 class iglob(Table):
1255 """
1256 List all files and directories matching a specified pattern.
1257 (See ``glob.glob()`` for more info.).
1258
1259 Examples::
1260
1261 >>> iglob("*.py")
1262 IPython.extensions.ipipe.iglob('*.py')
1263 """
1264 def __init__(self, glob):
1265 self.glob = glob
1266
1267 def __iter__(self):
1268 for name in glob.glob(self.glob):
1269 yield ifile(name)
1270
1271 def __xrepr__(self, mode="default"):
1272 if mode == "header" or mode == "footer" or mode == "cell":
1273 yield (astyle.style_default,
1274 "%s(%r)" % (self.__class__.__name__, self.glob))
1275 else:
1276 yield (astyle.style_default, repr(self))
1277
1278 def __repr__(self):
1279 return "%s.%s(%r)" % \
1280 (self.__class__.__module__, self.__class__.__name__, self.glob)
1281
1282
1283 class iwalk(Table):
1284 """
1285 List all files and directories in a directory and it's subdirectory::
1286
1287 >>> iwalk
1288 <class 'IPython.extensions.ipipe.iwalk'>
1289 >>> iwalk("/usr/lib")
1290 IPython.extensions.ipipe.iwalk('/usr/lib')
1291 >>> iwalk("~")
1292 IPython.extensions.ipipe.iwalk('/home/fperez') # random
1293
1294 """
1295 def __init__(self, base=os.curdir, dirs=True, files=True):
1296 self.base = os.path.expanduser(base)
1297 self.dirs = dirs
1298 self.files = files
1299
1300 def __iter__(self):
1301 for (dirpath, dirnames, filenames) in os.walk(self.base):
1302 if self.dirs:
1303 for name in sorted(dirnames):
1304 yield ifile(os.path.join(dirpath, name))
1305 if self.files:
1306 for name in sorted(filenames):
1307 yield ifile(os.path.join(dirpath, name))
1308
1309 def __xrepr__(self, mode="default"):
1310 if mode == "header" or mode == "footer" or mode == "cell":
1311 yield (astyle.style_default,
1312 "%s(%r)" % (self.__class__.__name__, self.base))
1313 else:
1314 yield (astyle.style_default, repr(self))
1315
1316 def __repr__(self):
1317 return "%s.%s(%r)" % \
1318 (self.__class__.__module__, self.__class__.__name__, self.base)
1319
1320
1321 class ipwdentry(object):
1322 """
1323 ``ipwdentry`` objects encapsulate entries in the Unix user account and
1324 password database.
1325 """
1326 def __init__(self, id):
1327 self._id = id
1328 self._entry = None
1329
1330 def __eq__(self, other):
1331 return self.__class__ is other.__class__ and self._id == other._id
1332
1333 def __ne__(self, other):
1334 return self.__class__ is not other.__class__ or self._id != other._id
1335
1336 def _getentry(self):
1337 if self._entry is None:
1338 if isinstance(self._id, basestring):
1339 self._entry = pwd.getpwnam(self._id)
1340 else:
1341 self._entry = pwd.getpwuid(self._id)
1342 return self._entry
1343
1344 def getname(self):
1345 if isinstance(self._id, basestring):
1346 return self._id
1347 else:
1348 return self._getentry().pw_name
1349 name = property(getname, None, None, "User name")
1350
1351 def getpasswd(self):
1352 return self._getentry().pw_passwd
1353 passwd = property(getpasswd, None, None, "Password")
1354
1355 def getuid(self):
1356 if isinstance(self._id, basestring):
1357 return self._getentry().pw_uid
1358 else:
1359 return self._id
1360 uid = property(getuid, None, None, "User id")
1361
1362 def getgid(self):
1363 return self._getentry().pw_gid
1364 gid = property(getgid, None, None, "Primary group id")
1365
1366 def getgroup(self):
1367 return igrpentry(self.gid)
1368 group = property(getgroup, None, None, "Group")
1369
1370 def getgecos(self):
1371 return self._getentry().pw_gecos
1372 gecos = property(getgecos, None, None, "Information (e.g. full user name)")
1373
1374 def getdir(self):
1375 return self._getentry().pw_dir
1376 dir = property(getdir, None, None, "$HOME directory")
1377
1378 def getshell(self):
1379 return self._getentry().pw_shell
1380 shell = property(getshell, None, None, "Login shell")
1381
1382 def __xattrs__(self, mode="default"):
1383 return ("name", "passwd", "uid", "gid", "gecos", "dir", "shell")
1384
1385 def __repr__(self):
1386 return "%s.%s(%r)" % \
1387 (self.__class__.__module__, self.__class__.__name__, self._id)
1388
1389
1390 class ipwd(Table):
1391 """
1392 List all entries in the Unix user account and password database.
1393
1394 Example::
1395
1396 >>> ipwd | isort("uid")
1397 <IPython.extensions.ipipe.isort key='uid' reverse=False at 0x849efec>
1398 # random
1399 """
1400 def __iter__(self):
1401 for entry in pwd.getpwall():
1402 yield ipwdentry(entry.pw_name)
1403
1404 def __xrepr__(self, mode="default"):
1405 if mode == "header" or mode == "footer" or mode == "cell":
1406 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1407 else:
1408 yield (astyle.style_default, repr(self))
1409
1410
1411 class igrpentry(object):
1412 """
1413 ``igrpentry`` objects encapsulate entries in the Unix group database.
1414 """
1415 def __init__(self, id):
1416 self._id = id
1417 self._entry = None
1418
1419 def __eq__(self, other):
1420 return self.__class__ is other.__class__ and self._id == other._id
1421
1422 def __ne__(self, other):
1423 return self.__class__ is not other.__class__ or self._id != other._id
1424
1425 def _getentry(self):
1426 if self._entry is None:
1427 if isinstance(self._id, basestring):
1428 self._entry = grp.getgrnam(self._id)
1429 else:
1430 self._entry = grp.getgrgid(self._id)
1431 return self._entry
1432
1433 def getname(self):
1434 if isinstance(self._id, basestring):
1435 return self._id
1436 else:
1437 return self._getentry().gr_name
1438 name = property(getname, None, None, "Group name")
1439
1440 def getpasswd(self):
1441 return self._getentry().gr_passwd
1442 passwd = property(getpasswd, None, None, "Password")
1443
1444 def getgid(self):
1445 if isinstance(self._id, basestring):
1446 return self._getentry().gr_gid
1447 else:
1448 return self._id
1449 gid = property(getgid, None, None, "Group id")
1450
1451 def getmem(self):
1452 return self._getentry().gr_mem
1453 mem = property(getmem, None, None, "Members")
1454
1455 def __xattrs__(self, mode="default"):
1456 return ("name", "passwd", "gid", "mem")
1457
1458 def __xrepr__(self, mode="default"):
1459 if mode == "header" or mode == "footer" or mode == "cell":
1460 yield (astyle.style_default, "group ")
1461 try:
1462 yield (astyle.style_default, self.name)
1463 except KeyError:
1464 if isinstance(self._id, basestring):
1465 yield (astyle.style_default, self.name_id)
1466 else:
1467 yield (astyle.style_type_number, str(self._id))
1468 else:
1469 yield (astyle.style_default, repr(self))
1470
1471 def __iter__(self):
1472 for member in self.mem:
1473 yield ipwdentry(member)
1474
1475 def __repr__(self):
1476 return "%s.%s(%r)" % \
1477 (self.__class__.__module__, self.__class__.__name__, self._id)
1478
1479
1480 class igrp(Table):
1481 """
1482 This ``Table`` lists all entries in the Unix group database.
1483 """
1484 def __iter__(self):
1485 for entry in grp.getgrall():
1486 yield igrpentry(entry.gr_name)
1487
1488 def __xrepr__(self, mode="default"):
1489 if mode == "header" or mode == "footer":
1490 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1491 else:
1492 yield (astyle.style_default, repr(self))
1493
1494
1495 class Fields(object):
1496 def __init__(self, fieldnames, **fields):
1497 self.__fieldnames = [upgradexattr(fieldname) for fieldname in fieldnames]
1498 for (key, value) in fields.iteritems():
1499 setattr(self, key, value)
1500
1501 def __xattrs__(self, mode="default"):
1502 return self.__fieldnames
1503
1504 def __xrepr__(self, mode="default"):
1505 yield (-1, False)
1506 if mode == "header" or mode == "cell":
1507 yield (astyle.style_default, self.__class__.__name__)
1508 yield (astyle.style_default, "(")
1509 for (i, f) in enumerate(self.__fieldnames):
1510 if i:
1511 yield (astyle.style_default, ", ")
1512 yield (astyle.style_default, f.name())
1513 yield (astyle.style_default, "=")
1514 for part in xrepr(getattr(self, f), "default"):
1515 yield part
1516 yield (astyle.style_default, ")")
1517 elif mode == "footer":
1518 yield (astyle.style_default, self.__class__.__name__)
1519 yield (astyle.style_default, "(")
1520 for (i, f) in enumerate(self.__fieldnames):
1521 if i:
1522 yield (astyle.style_default, ", ")
1523 yield (astyle.style_default, f.name())
1524 yield (astyle.style_default, ")")
1525 else:
1526 yield (astyle.style_default, repr(self))
1527
1528
1529 class FieldTable(Table, list):
1530 def __init__(self, *fields):
1531 Table.__init__(self)
1532 list.__init__(self)
1533 self.fields = fields
1534
1535 def add(self, **fields):
1536 self.append(Fields(self.fields, **fields))
1537
1538 def __xrepr__(self, mode="default"):
1539 yield (-1, False)
1540 if mode == "header" or mode == "footer":
1541 yield (astyle.style_default, self.__class__.__name__)
1542 yield (astyle.style_default, "(")
1543 for (i, f) in enumerate(self.__fieldnames):
1544 if i:
1545 yield (astyle.style_default, ", ")
1546 yield (astyle.style_default, f)
1547 yield (astyle.style_default, ")")
1548 else:
1549 yield (astyle.style_default, repr(self))
1550
1551 def __repr__(self):
1552 return "<%s.%s object with fields=%r at 0x%x>" % \
1553 (self.__class__.__module__, self.__class__.__name__,
1554 ", ".join(map(repr, self.fields)), id(self))
1555
1556
1557 class List(list):
1558 def __xattrs__(self, mode="default"):
1559 return xrange(len(self))
1560
1561 def __xrepr__(self, mode="default"):
1562 yield (-1, False)
1563 if mode == "header" or mode == "cell" or mode == "footer" or mode == "default":
1564 yield (astyle.style_default, self.__class__.__name__)
1565 yield (astyle.style_default, "(")
1566 for (i, item) in enumerate(self):
1567 if i:
1568 yield (astyle.style_default, ", ")
1569 for part in xrepr(item, "default"):
1570 yield part
1571 yield (astyle.style_default, ")")
1572 else:
1573 yield (astyle.style_default, repr(self))
1574
1575
1576 class ienv(Table):
1577 """
1578 List environment variables.
1579
1580 Example::
1581
1582 >>> ienv
1583 <class 'IPython.extensions.ipipe.ienv'>
1584 """
1585
1586 def __iter__(self):
1587 fields = ("key", "value")
1588 for (key, value) in os.environ.iteritems():
1589 yield Fields(fields, key=key, value=value)
1590
1591 def __xrepr__(self, mode="default"):
1592 if mode == "header" or mode == "cell":
1593 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1594 else:
1595 yield (astyle.style_default, repr(self))
1596
1597
1598 class ihist(Table):
1599 """
1600 IPython input history
1601
1602 Example::
1603
1604 >>> ihist
1605 <class 'IPython.extensions.ipipe.ihist'>
1606 >>> ihist(True) # raw mode
1607 <IPython.extensions.ipipe.ihist object at 0x849602c> # random
1608 """
1609 def __init__(self, raw=True):
1610 self.raw = raw
1611
1612 def __iter__(self):
1613 api = ipapi.get()
1614 if self.raw:
1615 for line in api.input_hist_raw:
1616 yield line.rstrip("\n")
1617 else:
1618 for line in api.input_hist:
1619 yield line.rstrip("\n")
1620
1621
1622 class Alias(object):
1623 """
1624 Entry in the alias table
1625 """
1626 def __init__(self, name, args, command):
1627 self.name = name
1628 self.args = args
1629 self.command = command
1630
1631 def __xattrs__(self, mode="default"):
1632 return ("name", "args", "command")
1633
1634
1635 class ialias(Table):
1636 """
1637 IPython alias list
1638
1639 Example::
1640
1641 >>> ialias
1642 <class 'IPython.extensions.ipipe.ialias'>
1643 """
1644 def __iter__(self):
1645 api = ipapi.get()
1646
1647 for (name, (args, command)) in api.alias_manager.alias_table.iteritems():
1648 yield Alias(name, args, command)
1649
1650
1651 class icsv(Pipe):
1652 """
1653 This ``Pipe`` turns the input (with must be a pipe outputting lines
1654 or an ``ifile``) into lines of CVS columns.
1655 """
1656 def __init__(self, **csvargs):
1657 """
1658 Create an ``icsv`` object. ``cvsargs`` will be passed through as
1659 keyword arguments to ``cvs.reader()``.
1660 """
1661 self.csvargs = csvargs
1662
1663 def __iter__(self):
1664 input = self.input
1665 if isinstance(input, ifile):
1666 input = input.open("rb")
1667 reader = csv.reader(input, **self.csvargs)
1668 for line in reader:
1669 yield List(line)
1670
1671 def __xrepr__(self, mode="default"):
1672 yield (-1, False)
1673 if mode == "header" or mode == "footer":
1674 input = getattr(self, "input", None)
1675 if input is not None:
1676 for part in xrepr(input, mode):
1677 yield part
1678 yield (astyle.style_default, " | ")
1679 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1680 for (i, (name, value)) in enumerate(self.csvargs.iteritems()):
1681 if i:
1682 yield (astyle.style_default, ", ")
1683 yield (astyle.style_default, name)
1684 yield (astyle.style_default, "=")
1685 for part in xrepr(value, "default"):
1686 yield part
1687 yield (astyle.style_default, ")")
1688 else:
1689 yield (astyle.style_default, repr(self))
1690
1691 def __repr__(self):
1692 args = ", ".join(["%s=%r" % item for item in self.csvargs.iteritems()])
1693 return "<%s.%s %s at 0x%x>" % \
1694 (self.__class__.__module__, self.__class__.__name__, args, id(self))
1695
1696
1697 class ix(Table):
1698 """
1699 Execute a system command and list its output as lines
1700 (similar to ``os.popen()``).
1701
1702 Examples::
1703
1704 >>> ix("ps x")
1705 IPython.extensions.ipipe.ix('ps x')
1706
1707 >>> ix("find .") | ifile
1708 <IPython.extensions.ipipe.ieval expr=<class 'IPython.extensions.ipipe.ifile'> at 0x8509d2c>
1709 # random
1710 """
1711 def __init__(self, cmd):
1712 self.cmd = cmd
1713 self._pipeout = None
1714
1715 def __iter__(self):
1716 (_pipein, self._pipeout) = os.popen4(self.cmd)
1717 _pipein.close()
1718 for l in self._pipeout:
1719 yield l.rstrip("\r\n")
1720 self._pipeout.close()
1721 self._pipeout = None
1722
1723 def __del__(self):
1724 if self._pipeout is not None and not self._pipeout.closed:
1725 self._pipeout.close()
1726 self._pipeout = None
1727
1728 def __xrepr__(self, mode="default"):
1729 if mode == "header" or mode == "footer":
1730 yield (astyle.style_default,
1731 "%s(%r)" % (self.__class__.__name__, self.cmd))
1732 else:
1733 yield (astyle.style_default, repr(self))
1734
1735 def __repr__(self):
1736 return "%s.%s(%r)" % \
1737 (self.__class__.__module__, self.__class__.__name__, self.cmd)
1738
1739
1740 class ifilter(Pipe):
1741 """
1742 Filter an input pipe. Only objects where an expression evaluates to true
1743 (and doesn't raise an exception) are listed.
1744
1745 Examples::
1746
1747 >>> ils | ifilter("_.isfile() and size>1000")
1748 >>> igrp | ifilter("len(mem)")
1749 >>> sys.modules | ifilter(lambda _:_.value is not None)
1750 # all-random
1751 """
1752
1753 def __init__(self, expr, globals=None, errors="raiseifallfail"):
1754 """
1755 Create an ``ifilter`` object. ``expr`` can be a callable or a string
1756 containing an expression. ``globals`` will be used as the global
1757 namespace for calling string expressions (defaulting to IPython's
1758 user namespace). ``errors`` specifies how exception during evaluation
1759 of ``expr`` are handled:
1760
1761 ``"drop"``
1762 drop all items that have errors;
1763
1764 ``"keep"``
1765 keep all items that have errors;
1766
1767 ``"keeperror"``
1768 keep the exception of all items that have errors;
1769
1770 ``"raise"``
1771 raise the exception;
1772
1773 ``"raiseifallfail"``
1774 raise the first exception if all items have errors; otherwise drop
1775 those with errors (this is the default).
1776 """
1777 self.expr = expr
1778 self.globals = globals
1779 self.errors = errors
1780
1781 def __iter__(self):
1782 if callable(self.expr):
1783 test = self.expr
1784 else:
1785 g = getglobals(self.globals)
1786 expr = compile(self.expr, "ipipe-expression", "eval")
1787 def test(item):
1788 return eval(expr, g, AttrNamespace(item))
1789
1790 ok = 0
1791 exc_info = None
1792 for item in xiter(self.input):
1793 try:
1794 if test(item):
1795 yield item
1796 ok += 1
1797 except (KeyboardInterrupt, SystemExit):
1798 raise
1799 except Exception as exc:
1800 if self.errors == "drop":
1801 pass # Ignore errors
1802 elif self.errors == "keep":
1803 yield item
1804 elif self.errors == "keeperror":
1805 yield exc
1806 elif self.errors == "raise":
1807 raise
1808 elif self.errors == "raiseifallfail":
1809 if exc_info is None:
1810 exc_info = sys.exc_info()
1811 if not ok and exc_info is not None:
1812 raise exc_info[0], exc_info[1], exc_info[2]
1813
1814 def __xrepr__(self, mode="default"):
1815 if mode == "header" or mode == "footer":
1816 input = getattr(self, "input", None)
1817 if input is not None:
1818 for part in xrepr(input, mode):
1819 yield part
1820 yield (astyle.style_default, " | ")
1821 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1822 for part in xrepr(self.expr, "default"):
1823 yield part
1824 yield (astyle.style_default, ")")
1825 else:
1826 yield (astyle.style_default, repr(self))
1827
1828 def __repr__(self):
1829 return "<%s.%s expr=%r at 0x%x>" % \
1830 (self.__class__.__module__, self.__class__.__name__,
1831 self.expr, id(self))
1832
1833
1834 class ieval(Pipe):
1835 """
1836 Evaluate an expression for each object in the input pipe.
1837
1838 Examples::
1839
1840 >>> ils | ieval("_.abspath()")
1841 # random
1842 >>> sys.path | ieval(ifile)
1843 # random
1844 """
1845
1846 def __init__(self, expr, globals=None, errors="raiseifallfail"):
1847 """
1848 Create an ``ieval`` object. ``expr`` can be a callable or a string
1849 containing an expression. For the meaning of ``globals`` and
1850 ``errors`` see ``ifilter``.
1851 """
1852 self.expr = expr
1853 self.globals = globals
1854 self.errors = errors
1855
1856 def __iter__(self):
1857 if callable(self.expr):
1858 do = self.expr
1859 else:
1860 g = getglobals(self.globals)
1861 expr = compile(self.expr, "ipipe-expression", "eval")
1862 def do(item):
1863 return eval(expr, g, AttrNamespace(item))
1864
1865 ok = 0
1866 exc_info = None
1867 for item in xiter(self.input):
1868 try:
1869 yield do(item)
1870 except (KeyboardInterrupt, SystemExit):
1871 raise
1872 except Exception as exc:
1873 if self.errors == "drop":
1874 pass # Ignore errors
1875 elif self.errors == "keep":
1876 yield item
1877 elif self.errors == "keeperror":
1878 yield exc
1879 elif self.errors == "raise":
1880 raise
1881 elif self.errors == "raiseifallfail":
1882 if exc_info is None:
1883 exc_info = sys.exc_info()
1884 if not ok and exc_info is not None:
1885 raise exc_info[0], exc_info[1], exc_info[2]
1886
1887 def __xrepr__(self, mode="default"):
1888 if mode == "header" or mode == "footer":
1889 input = getattr(self, "input", None)
1890 if input is not None:
1891 for part in xrepr(input, mode):
1892 yield part
1893 yield (astyle.style_default, " | ")
1894 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1895 for part in xrepr(self.expr, "default"):
1896 yield part
1897 yield (astyle.style_default, ")")
1898 else:
1899 yield (astyle.style_default, repr(self))
1900
1901 def __repr__(self):
1902 return "<%s.%s expr=%r at 0x%x>" % \
1903 (self.__class__.__module__, self.__class__.__name__,
1904 self.expr, id(self))
1905
1906
1907 class ienum(Pipe):
1908 """
1909 Enumerate the input pipe (i.e. wrap each input object in an object
1910 with ``index`` and ``object`` attributes).
1911
1912 Examples::
1913
1914 >>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object")
1915 """
1916 skip_doctest = True
1917
1918 def __iter__(self):
1919 fields = ("index", "object")
1920 for (index, object) in enumerate(xiter(self.input)):
1921 yield Fields(fields, index=index, object=object)
1922
1923
1924 class isort(Pipe):
1925 """
1926 Sorts the input pipe.
1927
1928 Examples::
1929
1930 >>> ils | isort("size")
1931 <IPython.extensions.ipipe.isort key='size' reverse=False at 0x849ec2c>
1932 >>> ils | isort("_.isdir(), _.lower()", reverse=True)
1933 <IPython.extensions.ipipe.isort key='_.isdir(), _.lower()' reverse=True at 0x849eacc>
1934 # all-random
1935 """
1936
1937 def __init__(self, key=None, globals=None, reverse=False):
1938 """
1939 Create an ``isort`` object. ``key`` can be a callable or a string
1940 containing an expression (or ``None`` in which case the items
1941 themselves will be sorted). If ``reverse`` is true the sort order
1942 will be reversed. For the meaning of ``globals`` see ``ifilter``.
1943 """
1944 self.key = key
1945 self.globals = globals
1946 self.reverse = reverse
1947
1948 def __iter__(self):
1949 if self.key is None:
1950 items = sorted(xiter(self.input), reverse=self.reverse)
1951 elif callable(self.key):
1952 items = sorted(xiter(self.input), key=self.key, reverse=self.reverse)
1953 else:
1954 g = getglobals(self.globals)
1955 key = compile(self.key, "ipipe-expression", "eval")
1956 def realkey(item):
1957 return eval(key, g, AttrNamespace(item))
1958 items = sorted(xiter(self.input), key=realkey, reverse=self.reverse)
1959 for item in items:
1960 yield item
1961
1962 def __xrepr__(self, mode="default"):
1963 if mode == "header" or mode == "footer":
1964 input = getattr(self, "input", None)
1965 if input is not None:
1966 for part in xrepr(input, mode):
1967 yield part
1968 yield (astyle.style_default, " | ")
1969 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1970 for part in xrepr(self.key, "default"):
1971 yield part
1972 if self.reverse:
1973 yield (astyle.style_default, ", ")
1974 for part in xrepr(True, "default"):
1975 yield part
1976 yield (astyle.style_default, ")")
1977 else:
1978 yield (astyle.style_default, repr(self))
1979
1980 def __repr__(self):
1981 return "<%s.%s key=%r reverse=%r at 0x%x>" % \
1982 (self.__class__.__module__, self.__class__.__name__,
1983 self.key, self.reverse, id(self))
1984
1985
1986 tab = 3 # for expandtabs()
1987
1988 def _format(field):
1989 if isinstance(field, str):
1990 text = repr(field.expandtabs(tab))[1:-1]
1991 elif isinstance(field, unicode):
1992 text = repr(field.expandtabs(tab))[2:-1]
1993 elif isinstance(field, datetime.datetime):
1994 # Don't use strftime() here, as this requires year >= 1900
1995 text = "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
1996 (field.year, field.month, field.day,
1997 field.hour, field.minute, field.second, field.microsecond)
1998 elif isinstance(field, datetime.date):
1999 text = "%04d-%02d-%02d" % (field.year, field.month, field.day)
2000 else:
2001 text = repr(field)
2002 return text
2003
2004
2005 class Display(object):
2006 class __metaclass__(type):
2007 def __ror__(self, input):
2008 return input | self()
2009
2010 def __init__(self, input=None):
2011 self.input = input
2012
2013 def __ror__(self, input):
2014 self.input = input
2015 return self
2016
2017 def display(self):
2018 pass
2019
2020
2021 class iless(Display):
2022 cmd = "less --quit-if-one-screen --LONG-PROMPT --LINE-NUMBERS --chop-long-lines --shift=8 --RAW-CONTROL-CHARS"
2023
2024 def display(self):
2025 try:
2026 pager = os.popen(self.cmd, "w")
2027 try:
2028 for item in xiter(self.input):
2029 first = False
2030 for attr in xattrs(item, "default"):
2031 if first:
2032 first = False
2033 else:
2034 pager.write(" ")
2035 attr = upgradexattr(attr)
2036 if not isinstance(attr, SelfDescriptor):
2037 pager.write(attr.name())
2038 pager.write("=")
2039 pager.write(str(attr.value(item)))
2040 pager.write("\n")
2041 finally:
2042 pager.close()
2043 except Exception as exc:
2044 print "%s: %s" % (exc.__class__.__name__, str(exc))
2045
2046
2047 class _RedirectIO(object):
2048 def __init__(self,*args,**kwargs):
2049 """
2050 Map the system output streams to self.
2051 """
2052 self.stream = StringIO.StringIO()
2053 self.stdout = sys.stdout
2054 sys.stdout = self
2055 self.stderr = sys.stderr
2056 sys.stderr = self
2057
2058 def write(self, text):
2059 """
2060 Write both to screen and to self.
2061 """
2062 self.stream.write(text)
2063 self.stdout.write(text)
2064 if "\n" in text:
2065 self.stdout.flush()
2066
2067 def writelines(self, lines):
2068 """
2069 Write lines both to screen and to self.
2070 """
2071 self.stream.writelines(lines)
2072 self.stdout.writelines(lines)
2073 self.stdout.flush()
2074
2075 def restore(self):
2076 """
2077 Restore the default system streams.
2078 """
2079 self.stdout.flush()
2080 self.stderr.flush()
2081 sys.stdout = self.stdout
2082 sys.stderr = self.stderr
2083
2084
2085 class icap(Table):
2086 """
2087 Execute a python string and capture any output to stderr/stdout.
2088
2089 Examples::
2090
2091 >>> import time
2092 >>> icap("for i in range(10): print i, time.sleep(0.1)")
2093
2094 """
2095 skip_doctest = True
2096
2097 def __init__(self, expr, globals=None):
2098 self.expr = expr
2099 self.globals = globals
2100 log = _RedirectIO()
2101 try:
2102 exec(expr, getglobals(globals))
2103 finally:
2104 log.restore()
2105 self.stream = log.stream
2106
2107 def __iter__(self):
2108 self.stream.seek(0)
2109 for line in self.stream:
2110 yield line.rstrip("\r\n")
2111
2112 def __xrepr__(self, mode="default"):
2113 if mode == "header" or mode == "footer":
2114 yield (astyle.style_default,
2115 "%s(%r)" % (self.__class__.__name__, self.expr))
2116 else:
2117 yield (astyle.style_default, repr(self))
2118
2119 def __repr__(self):
2120 return "%s.%s(%r)" % \
2121 (self.__class__.__module__, self.__class__.__name__, self.expr)
2122
2123
2124 def xformat(value, mode, maxlength):
2125 align = None
2126 full = True
2127 width = 0
2128 text = astyle.Text()
2129 for (style, part) in xrepr(value, mode):
2130 # only consider the first result
2131 if align is None:
2132 if isinstance(style, int):
2133 # (style, text) really is (alignment, stop)
2134 align = style
2135 full = part
2136 continue
2137 else:
2138 align = -1
2139 full = True
2140 if not isinstance(style, int):
2141 text.append((style, part))
2142 width += len(part)
2143 if width >= maxlength and not full:
2144 text.append((astyle.style_ellisis, "..."))
2145 width += 3
2146 break
2147 if align is None: # default to left alignment
2148 align = -1
2149 return (align, width, text)
2150
2151
2152
2153 import astyle
2154
2155 class idump(Display):
2156 # The approximate maximum length of a column entry
2157 maxattrlength = 200
2158
2159 # Style for column names
2160 style_header = astyle.Style.fromstr("white:black:bold")
2161
2162 def __init__(self, input=None, *attrs):
2163 Display.__init__(self, input)
2164 self.attrs = [upgradexattr(attr) for attr in attrs]
2165 self.headerpadchar = " "
2166 self.headersepchar = "|"
2167 self.datapadchar = " "
2168 self.datasepchar = "|"
2169
2170 def display(self):
2171 stream = Term.cout
2172 allattrs = []
2173 attrset = set()
2174 colwidths = {}
2175 rows = []
2176 for item in xiter(self.input):
2177 row = {}
2178 attrs = self.attrs
2179 if not attrs:
2180 attrs = xattrs(item, "default")
2181 for attr in attrs:
2182 if attr not in attrset:
2183 allattrs.append(attr)
2184 attrset.add(attr)
2185 colwidths[attr] = len(attr.name())
2186 try:
2187 value = attr.value(item)
2188 except (KeyboardInterrupt, SystemExit):
2189 raise
2190 except Exception as exc:
2191 value = exc
2192 (align, width, text) = xformat(value, "cell", self.maxattrlength)
2193 colwidths[attr] = max(colwidths[attr], width)
2194 # remember alignment, length and colored parts
2195 row[attr] = (align, width, text)
2196 rows.append(row)
2197
2198 stream.write("\n")
2199 for (i, attr) in enumerate(allattrs):
2200 attrname = attr.name()
2201 self.style_header(attrname).write(stream)
2202 spc = colwidths[attr] - len(attrname)
2203 if i < len(colwidths)-1:
2204 stream.write(self.headerpadchar*spc)
2205 stream.write(self.headersepchar)
2206 stream.write("\n")
2207
2208 for row in rows:
2209 for (i, attr) in enumerate(allattrs):
2210 (align, width, text) = row[attr]
2211 spc = colwidths[attr] - width
2212 if align == -1:
2213 text.write(stream)
2214 if i < len(colwidths)-1:
2215 stream.write(self.datapadchar*spc)
2216 elif align == 0:
2217 spc = colwidths[attr] - width
2218 spc1 = spc//2
2219 spc2 = spc-spc1
2220 stream.write(self.datapadchar*spc1)
2221 text.write(stream)
2222 if i < len(colwidths)-1:
2223 stream.write(self.datapadchar*spc2)
2224 else:
2225 stream.write(self.datapadchar*spc)
2226 text.write(stream)
2227 if i < len(colwidths)-1:
2228 stream.write(self.datasepchar)
2229 stream.write("\n")
2230
2231
2232 class AttributeDetail(Table):
2233 """
2234 ``AttributeDetail`` objects are use for displaying a detailed list of object
2235 attributes.
2236 """
2237 def __init__(self, object, descriptor):
2238 self.object = object
2239 self.descriptor = descriptor
2240
2241 def __iter__(self):
2242 return self.descriptor.iter(self.object)
2243
2244 def name(self):
2245 return self.descriptor.name()
2246
2247 def attrtype(self):
2248 return self.descriptor.attrtype(self.object)
2249
2250 def valuetype(self):
2251 return self.descriptor.valuetype(self.object)
2252
2253 def doc(self):
2254 return self.descriptor.doc(self.object)
2255
2256 def shortdoc(self):
2257 return self.descriptor.shortdoc(self.object)
2258
2259 def value(self):
2260 return self.descriptor.value(self.object)
2261
2262 def __xattrs__(self, mode="default"):
2263 attrs = ("name()", "attrtype()", "valuetype()", "value()", "shortdoc()")
2264 if mode == "detail":
2265 attrs += ("doc()",)
2266 return attrs
2267
2268 def __xrepr__(self, mode="default"):
2269 yield (-1, True)
2270 valuetype = self.valuetype()
2271 if valuetype is not noitem:
2272 for part in xrepr(valuetype):
2273 yield part
2274 yield (astyle.style_default, " ")
2275 yield (astyle.style_default, self.attrtype())
2276 yield (astyle.style_default, " ")
2277 yield (astyle.style_default, self.name())
2278 yield (astyle.style_default, " of ")
2279 for part in xrepr(self.object):
2280 yield part
2281
2282
2283 try:
2284 from ibrowse import ibrowse
2285 except ImportError:
2286 # No curses (probably Windows) => try igrid
2287 try:
2288 from igrid import igrid
2289 except ImportError:
2290 # no wx either => use ``idump`` as the default display.
2291 defaultdisplay = idump
2292 else:
2293 defaultdisplay = igrid
2294 __all__.append("igrid")
2295 else:
2296 defaultdisplay = ibrowse
2297 __all__.append("ibrowse")
2298
2299
2300 # If we're running under IPython, register our objects with IPython's
2301 # generic function ``result_display``, else install a displayhook
2302 # directly as sys.displayhook
2303 if generics is not None:
2304 def display_display(obj):
2305 return obj.display()
2306 generics.result_display.when_type(Display)(display_display)
2307
2308 def display_tableobject(obj):
2309 return display_display(defaultdisplay(obj))
2310 generics.result_display.when_type(Table)(display_tableobject)
2311
2312 def display_tableclass(obj):
2313 return display_tableobject(obj())
2314 generics.result_display.when_type(Table.__metaclass__)(display_tableclass)
2315 else:
2316 def installdisplayhook():
2317 _originalhook = sys.displayhook
2318 def displayhook(obj):
2319 if isinstance(obj, type) and issubclass(obj, Table):
2320 obj = obj()
2321 if isinstance(obj, Table):
2322 obj = defaultdisplay(obj)
2323 if isinstance(obj, Display):
2324 return obj.display()
2325 else:
2326 _originalhook(obj)
2327 sys.displayhook = displayhook
2328 installdisplayhook()
@@ -1,28 +0,0 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3 """
4 A backwards compatibility layer for IPython.iplib.
5
6 Previously, IPython had an IPython.iplib module. IPython.iplib has been moved
7 to IPython.core.iplib and is being refactored. This new module is provided
8 for backwards compatability. We strongly encourage everyone to start using
9 the new code in IPython.core.iplib.
10 """
11
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2011 The IPython Development Team
14 #
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
18
19 from warnings import warn
20
21 msg = """
22 This module (IPython.iplib) has been moved to a new location
23 (IPython.core.iplib) and is being refactored. Please update your code
24 to use the new IPython.core.iplib module"""
25
26 warn(msg, category=DeprecationWarning, stacklevel=1)
27
28 from IPython.core.iplib import *
This diff has been collapsed as it changes many lines, (669 lines changed) Show them Hide them
@@ -1,669 +0,0 b''
1 """ Module with physical constants for use with ipython, profile
2 "physics".
3
4 Definition of Fundamental Physical Constants, CODATA Recommended Values
5
6 Source, Peter J. Mohr and Barry N. Taylor,
7 CODATA Recommended Values of the Fundamental
8 Physical Constants, 1998
9
10 Website: physics.nist.gov/constants
11 """
12 # License: BSD-like
13 # Copyright: Gael Varoquaux (gael.varoquaux@normalesup.org)
14
15 # inspired by maxima's physconst.mac by Cliff Yapp
16
17 #from math import * # math MUST be imported BEFORE PhysicalQInteractive
18 from IPython.extensions.PhysicalQInteractive import PhysicalQuantityInteractive
19
20 # Math constants:
21
22 # Pi mathematical constants
23 pi = 3.141592653589793238462643383279502884197169399375105820974944592
24
25 # Universal Constants
26 #-------------------------------------------------------------------------
27
28 c = PhysicalQuantityInteractive(299792458 , 'm/s')
29 c.__doc__ = """speed of light in vacuum"""
30 c.__doc__ = "speed of light in vacuum"
31
32 u_0 = PhysicalQuantityInteractive(4*pi*1E-7 , 'N/(A**2)')
33 u_0.__doc__ = """magnetic constant"""
34 mu_0 = PhysicalQuantityInteractive(4*pi*1E-7 , 'N/(A**2)')
35
36 epsilon_0 = PhysicalQuantityInteractive(8.854187817E-12 , 'F/m')
37 epsilon_0.__doc__ = """electric constant """
38
39 Z_0 = PhysicalQuantityInteractive(376.730313461 , 'ohm')
40 Z_0.__doc__ = """characteristic impedance of vacuum """
41
42 G = PhysicalQuantityInteractive(6.673E-11 , 'm**3/(kg*s**2)')
43 G.__doc__ = """Newtonian constant of gravitation """
44
45
46 h = PhysicalQuantityInteractive(6.62606876E-34 , 'J*s')
47 h.__doc__ = """Planck constant """
48
49
50 h_eV = PhysicalQuantityInteractive(4.13566727E-15 , 'eV*s')
51 h_eV.__doc__ = """Planck constant in eVs """
52
53
54 h_bar = PhysicalQuantityInteractive(1.054571596E-34 , 'J*s')
55 h_bar.__doc__ = """Hbar"""
56
57
58 h_bar_eV = PhysicalQuantityInteractive(6.58211889E-16 , 'eV*s')
59 h_bar_eV.__doc__ = """Hbar in eV"""
60
61
62 P_m = PhysicalQuantityInteractive(2.1767E-8 , 'kg')
63 P_m.__doc__ = """Planck mass"""
64
65
66 P_l = PhysicalQuantityInteractive(1.6160E-35 , 'm')
67 P_l.__doc__ = """Planck length """
68
69
70 P_t = PhysicalQuantityInteractive(5.3906E-44 , 's')
71 P_t.__doc__ = """Planck time """
72
73 # Electromagnetic Constants
74 #------------------------------------------------------------------------
75
76 _e = PhysicalQuantityInteractive(1.602176462E-19 , 'C')
77 _e.__doc__ = """elementary charge"""
78 q = _e
79
80
81 capitalphi_0 = PhysicalQuantityInteractive(2.067833636E-15 , 'Wb')
82 capitalphi_0.__doc__ = """magnetic flux quantum """
83 mfq_0 = PhysicalQuantityInteractive(2.067833636E-15 , 'Wb')
84
85
86 G_0 = PhysicalQuantityInteractive(7.748091696E-5 , 'S')
87 G_0.__doc__ = """conductance quantum """
88
89
90 K_J = PhysicalQuantityInteractive(483597.898E9 , 'Hz/V')
91 K_J.__doc__ = """Josephson constant"""
92
93
94 R_K = PhysicalQuantityInteractive(25812.807572 , 'ohm')
95 R_K.__doc__ = """von Klitzing constant"""
96
97
98 u_B = PhysicalQuantityInteractive(927.400899E-26 , 'J/T')
99 u_B.__doc__ = """Bohr magneton"""
100
101 ueVT_B = PhysicalQuantityInteractive(5.788381749E-5 , 'eV/T')
102 ueVT_B.__doc__ = """Bohr magneton in eV T-1"""
103
104
105 u_N = PhysicalQuantityInteractive(5.05078317E-27 , 'J/T')
106 u_N.__doc__ = """nuclear magneton """
107
108 ueVT_N = PhysicalQuantityInteractive(3.152451238E-8 , 'eV/T')
109 ueVT_N.__doc__ = """nuclear magneton in eV T-1 """
110
111 # Atomic and Nuclear Constants
112 # General
113 #-------------------------------------------------------------------------
114 # fine-structure constant
115 alpha = 7.297352533E-3
116
117
118 Ry = PhysicalQuantityInteractive(10973731.568549 , '1/m')
119 Ry.__doc__ = """Rydberg constant """
120 Ry_INF = PhysicalQuantityInteractive(10973731.568549 , '1/m')
121
122
123 a_0 = PhysicalQuantityInteractive(0.5291772083E-10 , 'm')
124 a_0.__doc__ = """Bohr radius """
125
126
127 E_h = PhysicalQuantityInteractive(4.35974381E-18 , 'J')
128 E_h.__doc__ = """Hartree energy """
129
130 Eev_h = PhysicalQuantityInteractive(27.2113834 , 'eV')
131 Eev_h.__doc__ = """Hartree energy in eV """
132
133
134 qcir2 = PhysicalQuantityInteractive(3.636947516E-4 , 'm**2/s')
135 qcir2.__doc__ = """quantum of circulation h/(2me) """
136
137 qcir = PhysicalQuantityInteractive(7.273895032E-4 , 'm**2/s')
138 qcir.__doc__ = """quantum of circulation h/(me) """
139
140 # Electroweak
141 #-------------------------------------------------------------------------
142
143 Fcc = PhysicalQuantityInteractive(1.16639E-5 , '1/GeV**2')
144 Fcc.__doc__ = """Fermi coupling constant """
145 # weak mixing angled W (on-shell scheme)
146 wma_W = 0.2224
147
148 # Electron, e-
149 #-------------------------------------------------------------------------
150
151 m_e = PhysicalQuantityInteractive(9.10938188E-31 , 'kg')
152 m_e.__doc__ = """electron mass """
153
154 m_e_u = PhysicalQuantityInteractive(5.485799110E-4 , 'amu')
155 m_e_u.__doc__ = """electron mass (electron relative atomic mass times amu)"""
156
157 me_J = PhysicalQuantityInteractive(8.18710414E-14 , 'J')
158 me_J.__doc__ = """electron mass - energy equivalent """
159
160 me_MeV = PhysicalQuantityInteractive(0.510998902 , 'MeV')
161 me_MeV.__doc__ = """electron mass - energy equivalent in MeV"""
162
163 # electron-muon mass ratio
164 memu = 4.83633210E-3
165
166 # electron-tau mass ratio
167 metau = 2.87555E-4
168
169 # electron-proton mass ratio
170 memp = 5.446170232E-4
171
172 # electron-neutron mass ratio
173 memn = 5.438673462E-4
174
175 # electron-deuteron mass ratio
176 memd = 2.7244371170E-4
177
178 # electron to alpha particle mass ratio
179 memalpha = 1.3709335611E-4
180
181
182 echargeemass = PhysicalQuantityInteractive(-1.758820174E11 , 'C/kg')
183 echargeemass.__doc__ = """electron charge to mass quotient """
184
185
186 Molar_e = PhysicalQuantityInteractive(5.485799110E-7 , 'kg/mol')
187 Molar_e.__doc__ = """electron molar mass """
188
189
190 lambdaC = PhysicalQuantityInteractive(2.426310215E-12 , 'm')
191 lambdaC.__doc__ = """Compton wavelength """
192
193
194 r_e = PhysicalQuantityInteractive(2.817940285E-15 , 'm')
195 r_e.__doc__ = """classical electron radius """
196
197
198 sigma_e = PhysicalQuantityInteractive(0.665245854E-28 , 'm**2')
199 sigma_e.__doc__ = """Thomson cross section """
200
201
202 u_e = PhysicalQuantityInteractive(-928.476362E-26 , 'J/T')
203 u_e.__doc__ = """electron magnetic moment """
204
205 # electron magnetic moment to Bohr magneton ratio
206 ueuB = -1.0011596521869
207
208 # electron magnetic moment to nuclear magneton ratio
209 ueuN = -1838.2819660
210
211 # electron magnetic moment anomaly |ue|/uB - 1
212 a_e = 1.1596521869E-3
213
214 # electron g-factor
215 g_e = -2.0023193043737
216
217 # electron-muon magnetic moment ratio
218 ueuu = 206.7669720
219
220 # electron-proton magnetic moment ratio
221 ueup = -658.2106875
222
223 # electron to shielded proton magnetic moment ratio (H2O, sphere, 25 C)
224 ueusp = -658.2275954
225
226 # electron-neutron magnetic moment ratio
227 ueun = 960.92050
228
229 # electron-deuteron magnetic moment ratio
230 ueud = -2143.923498
231
232 # electron to shielded helione magnetic moment ratio (gas, sphere, 25 C)
233 ueush = 864.058255
234
235
236 gamma_e = PhysicalQuantityInteractive(1.760859794E11 , '1/(s*T)')
237 gamma_e.__doc__ = """electron gyromagnetic ratio """
238
239 # Muon, u-
240 #-------------------------------------------------------------------------
241
242 m_u = PhysicalQuantityInteractive(1.88353109E-28 , 'kg')
243 m_u.__doc__ = """muon mass """
244
245 mu_u = PhysicalQuantityInteractive(0.1134289168 , 'amu')
246 mu_u.__doc__ = """muon mass in muon relative atomic mass times amu """
247
248
249 muc2_J = PhysicalQuantityInteractive(1.69283332E-11 , 'J')
250 muc2_J.__doc__ = """energy equivalent """
251
252 muc2_MeV = PhysicalQuantityInteractive(105.6583568 , 'MeV')
253 muc2_MeV.__doc__ = """energy equivalent in MeV """
254
255 # muon-electron mass ratio
256 mume = 206.7682657
257
258 # muon-tau mass ratio
259 mum = 5.94572E-2
260
261 # muon-proton mass ratio
262 mump = 0.1126095173
263
264 # muon-neutron mass ratio
265 mumn = 0.1124545079
266
267
268 Molar_u = PhysicalQuantityInteractive(0.1134289168E-3 , 'kg/mol')
269 Molar_u.__doc__ = """muon molar mass """
270
271
272 lambda_C_u = PhysicalQuantityInteractive(11.73444197E-15 , 'm')
273 lambda_C_u.__doc__ = """muon Compton wavelength """
274
275
276 uu = PhysicalQuantityInteractive(-4.49044813E-26 , 'J/T')
277 uu.__doc__ = """muon magnetic moment """
278
279 # ratio of muon magnetic moment to Bohr magneton ratio
280 uuuB = -4.84197085E-3
281
282 # ratio of muon magnetic moment to nuclear magneton ratio
283 uuuN = -8.89059770
284
285 # muon magnetic moment anomaly |uu|/(e /2mu) - 1
286 a_u = 1.16591602E-3
287
288 # muon g-factor -2(1 + au)
289 g_u = -2.0023318320
290
291 # muon-proton magnetic moment ratio
292 uuup = -3.18334539
293
294 # Tau, tau-
295 #-------------------------------------------------------------------------
296
297 m_tau = PhysicalQuantityInteractive(3.16788E-27 , 'kg')
298 m_tau.__doc__ = """tau mass """
299
300 mu_tau = PhysicalQuantityInteractive(1.90774 , 'amu')
301 mu_tau.__doc__ = """tau mass (tau relative atomic mass times amu) """
302
303
304 mtauc2_J = PhysicalQuantityInteractive(2.84715E-10 , 'J')
305 mtauc2_J.__doc__ = """tau mass energy equivalent """
306
307
308 mtauc2_MeV = PhysicalQuantityInteractive(1777.05 , 'MeV')
309 mtauc2_MeV.__doc__ = """tau mass energy equivalent in MeV """
310
311 # tau-electron mass ratio
312 mtaume = 3477.60
313
314 # tau-muon mass ratio
315 mtaumu = 16.8188
316
317 # tau-proton mass ratio
318 mtaump = 1.89396
319
320 # tau-neutron mass ratio
321 mtaumn = 1.89135
322
323
324 Molar_tau = PhysicalQuantityInteractive(1.90774E-3 , 'kg/mol')
325 Molar_tau.__doc__ = """tau molar mass """
326
327
328 lambda_C_tau = PhysicalQuantityInteractive(0.69770E-15 , 'm')
329 lambda_C_tau.__doc__ = """tau Compton wavelength """
330
331 # Proton, p
332 #-------------------------------------------------------------------------
333
334 m_p = PhysicalQuantityInteractive(1.67262158E-27 , 'kg')
335 m_p.__doc__ = """proton mass """
336
337 mu_p = PhysicalQuantityInteractive(1.00727646688 , 'amu')
338 mu_p.__doc__ = """proton mass (proton relative atomic mass times amu) """
339
340
341 mpc2_J = PhysicalQuantityInteractive(1.50327731E-10 , 'J')
342 mpc2_J.__doc__ = """energy equivalent """
343
344 mpc2_MeV = PhysicalQuantityInteractive(938.271998 , 'MeV')
345 mpc2_MeV.__doc__ = """energy equivalent in MeV """
346
347 # proton-electron mass ratio
348 mpme = 1836.1526675
349
350 # proton-muon mass ratio
351 mpmu = 8.88024408
352
353 # proton-tau mass ratio
354 mpmtau = 0.527994
355
356 # proton-neutron mass ratio
357 mpmn = 0.99862347855
358
359
360 emp = PhysicalQuantityInteractive(9.57883408E7 , 'C/kg')
361 emp.__doc__ = """proton charge to mass quotient """
362
363
364 Molar_p = PhysicalQuantityInteractive(1.00727646688E-3 , 'kg/mol')
365 Molar_p.__doc__ = """proton molar mass """
366
367
368 lambda_C_p = PhysicalQuantityInteractive(1.321409847E-15 , 'm')
369 lambda_C_p.__doc__ = """proton Compton wavelength h/mpc """
370
371
372 up = PhysicalQuantityInteractive(1.410606633E-26 , 'J/T')
373 up.__doc__ = """proton magnetic moment """
374
375 # proton magnetic moment to Bohr magneton ratio
376 upuB = 1.521032203E-3
377
378 # proton magnetic moment to nuclear magneton ratio
379 upuN = 2.792847337
380
381 # proton g-factor 2up/uN
382 g_p = 5.585694675
383
384 # proton-neutron magnetic moment ratio
385 upun = -1.45989805
386
387
388 usp = PhysicalQuantityInteractive(1.410570399E-26 , 'J/T')
389 usp.__doc__ = """shielded proton magnetic moment (H2O, sphere, 25 C)"""
390
391 # shielded proton magnetic moment to Bohr magneton ratio
392 uspuB = 1.520993132E-3
393
394 # shielded proton magnetic moment to nuclear magneton ratio
395 uspuN = 2.792775597
396
397 # proton magnetic shielding correction 1 - u p/up (H2O, sphere, 25 C)
398 spc = 25.687E-6
399
400
401 gamma_p = PhysicalQuantityInteractive(2.67522212E8 , '1/(s*T)')
402 gamma_p.__doc__ = """proton gyromagnetic ratio """
403
404
405 gamma_sp = PhysicalQuantityInteractive(2.67515341E8 , '1/(s*T)')
406 gamma_sp.__doc__ = """shielded proton gyromagnetic ratio (H2O, sphere, 25 C)"""
407
408 # Neutron, n
409 #-------------------------------------------------------------------------
410
411 m_n = PhysicalQuantityInteractive(1.67492716E-27 , 'kg')
412 m_n.__doc__ = """neutron mass """
413
414 mu_n = PhysicalQuantityInteractive(1.00866491578 , 'amu')
415 mu_n.__doc__ = """neutron mass (neutron relative atomic mass times amu) """
416
417
418 mnc2_J = PhysicalQuantityInteractive(1.50534946E-10 , 'J')
419 mnc2_J.__doc__ = """neutron mass energy equivalent """
420
421
422 mnc2_MeV = PhysicalQuantityInteractive(939.565330 , 'MeV')
423 mnc2_MeV.__doc__ = """neutron mass energy equivalent in MeV """
424
425 # neutron-electron mass ratio
426 mnme = 1838.6836550
427
428 # neutron-muon mass ratio
429 mnmu = 8.89248478
430
431 # neutron-tau mass ratio
432 mnm = 0.528722
433
434 # neutron-proton mass ratio
435 mnmp = 1.00137841887
436
437
438 Molar_n = PhysicalQuantityInteractive(1.00866491578E-3 , 'kg/mol')
439 Molar_n.__doc__ = """neutron molar mass """
440
441
442 lambda_C_n = PhysicalQuantityInteractive(1.319590898E-15 , 'm')
443 lambda_C_n.__doc__ = """neutron Compton wavelength"""
444
445
446 un = PhysicalQuantityInteractive(-0.96623640E-26 , 'J/T')
447 un.__doc__ = """neutron magnetic moment """
448
449 # neutron magnetic moment to Bohr magneton ratio
450 unuB = -1.04187563E-3
451
452 # neutron magnetic moment to nuclear magneton ratio
453 unuN = -1.91304272
454
455 # neutron g-factor
456 g_n = -3.82608545
457
458 # neutron-electron magnetic moment ratio
459 unue = 1.04066882E-3
460
461 # neutron-proton magnetic moment ratio
462 unup = -0.68497934
463
464 # neutron to shielded proton magnetic moment ratio (H2O, sphere, 25 C)
465 unusp = -0.68499694
466
467
468 gamma_n = PhysicalQuantityInteractive(1.83247188E8 , '1/(s*T)')
469 gamma_n.__doc__ = """neutron gyromagnetic ratio """
470
471 # Deuteron, d
472 #-------------------------------------------------------------------------
473
474 m_d = PhysicalQuantityInteractive(3.34358309E-27 , 'kg')
475 m_d.__doc__ = """deuteron mass """
476
477
478 mu_d = PhysicalQuantityInteractive(2.01355321271 , 'amu')
479 mu_d.__doc__ = """deuteron mass (deuteron relative atomic mass times amu) """
480
481
482 mdc2_J = PhysicalQuantityInteractive(3.00506262E-10 , 'J')
483 mdc2_J.__doc__ = """deuteron mass energy equivalent """
484
485
486 mdc2_eV = PhysicalQuantityInteractive(1875.612762 , 'MeV')
487 mdc2_eV.__doc__ = """deuteron mass energy equivalent in MeV """
488
489 # deuteron-electron mass ratio
490 mdme = 3670.4829550
491
492 # deuteron-proton mass ratio
493 mdmp = 1.99900750083
494
495
496 Molar_d = PhysicalQuantityInteractive(2.01355321271E-3 , 'kg/mol')
497 Molar_d.__doc__ = """deuteron molar mass """
498
499
500 ud = PhysicalQuantityInteractive(0.433073457E-26 , 'J/T')
501 ud.__doc__ = """deuteron magnetic moment """
502
503 # deuteron magnetic moment to Bohr magneton ratio
504 uduB = 0.4669754556E-3
505
506 # deuteron magnetic moment to nuclear magneton ratio
507 uduN = 0.8574382284
508
509 # deuteron-electron magnetic moment ratio
510 udue = -4.664345537E-4
511
512 # deuteron-proton magnetic moment ratio
513 udup = 0.3070122083
514
515 # deuteron-neutron magnetic moment ratio
516 udun = -0.44820652
517
518 # Helion, h
519 #-------------------------------------------------------------------------
520
521 m_h = PhysicalQuantityInteractive(5.00641174E-27 , 'kg')
522 m_h.__doc__ = """helion mass """
523
524
525 mu_h = PhysicalQuantityInteractive(3.01493223469 , 'amu')
526 mu_h.__doc__ = """helion mass (helion relative atomic mass times amu) """
527
528
529 mhc2_J = PhysicalQuantityInteractive(4.49953848E-10 , 'J')
530 mhc2_J.__doc__ = """helion mass energy equivalent """
531
532 mhc2_MeV = PhysicalQuantityInteractive(2808.39132 , 'MeV')
533 mhc2_MeV.__doc__ = """helion mass energy equivalent in MeV """
534
535 # helion-electron mass ratio
536 mhme = 5495.885238
537
538 # helion-proton mass ratio
539 mhmp = 2.99315265850
540
541
542 Molar_h = PhysicalQuantityInteractive(3.01493223469E-3 , 'kg/mol')
543 Molar_h.__doc__ = """helion molar mass """
544
545
546 ush = PhysicalQuantityInteractive(-1.074552967E-26 , 'J/T')
547 ush.__doc__ = """shielded helion magnetic moment (gas, sphere, 25 C)"""
548
549 # shielded helion magnetic moment to Bohr magneton ratio
550 ushuB = -1.158671474E-3
551
552 # shielded helion magnetic moment to nuclear magneton ratio
553 ushuN = -2.127497718
554
555 # shielded helion to proton magnetic moment ratio (gas, sphere, 25 C)
556 ushup = -0.761766563
557
558 # shielded helion to shielded proton magnetic moment ratio (gas/H2O, spheres, 25 C)
559 ushusp = -0.7617861313
560
561
562 gamma_h = PhysicalQuantityInteractive(2.037894764E8 , '1/(s*T)')
563 gamma_h.__doc__ = """shielded helion gyromagnetic (gas, sphere, 25 C) """
564
565 # Alpha particle,
566 #-------------------------------------------------------------------------
567
568 m_alpha = PhysicalQuantityInteractive(6.64465598E-27 , 'kg')
569 m_alpha.__doc__ = """alpha particle mass """
570
571 mu_alpha = PhysicalQuantityInteractive(4.0015061747 , 'amu')
572 mu_alpha.__doc__ = """alpha particle mass (alpha particle relative atomic mass times amu) """
573
574
575 malphac2_J = PhysicalQuantityInteractive(5.97191897E-10 , 'J')
576 malphac2_J.__doc__ = """alpha particle mass energy equivalent """
577
578
579 malphac2_MeV = PhysicalQuantityInteractive(3727.37904 , 'MeV')
580 malphac2_MeV.__doc__ = """alpha particle mass energy equivalent in MeV """
581
582 # alpha particle to electron mass ratio
583 malphame = 7294.299508
584
585 # alpha particle to proton mass ratio
586 malphamp = 3.9725996846
587
588
589 Molar_alpha = PhysicalQuantityInteractive(4.0015061747E-3 , 'kg/mol')
590 Molar_alpha.__doc__ = """alpha particle molar mass"""
591
592 # PHYSICO-CHEMICAL
593 #-------------------------------------------------------------------------
594
595 N_A = PhysicalQuantityInteractive(6.02214199E23 , '1/mol')
596 N_A.__doc__ = """Avogadro constant """
597 L = PhysicalQuantityInteractive(6.02214199E23 , '1/mol')
598
599
600 m_u = PhysicalQuantityInteractive(1.66053873E-27 , 'kg')
601 m_u.__doc__ = """atomic mass constant mu = 112m(12C) = 1 u = 10E-3 kg mol-1/NA"""
602 # atomic mass constant mu = 112m(12C) = 1 u = 10E-3 kg mol-1/NA
603 amu = m_u
604
605
606 muc2_J = PhysicalQuantityInteractive(1.49241778E-10 , 'J')
607 muc2_J.__doc__ = """energy equivalent of the atomic mass constant"""
608
609
610 muc2_MeV = PhysicalQuantityInteractive(931.494013 , 'MeV')
611 muc2_MeV.__doc__ = """energy equivalent of the atomic mass constant in MeV """
612
613
614 F = PhysicalQuantityInteractive(96485.3415 , 'C/mol')
615 F.__doc__ = """Faraday constant"""
616
617
618 N_Ah = PhysicalQuantityInteractive(3.990312689E-10 , 'J*s/mol')
619 N_Ah.__doc__ = """molar Planck constant """
620
621
622 R = PhysicalQuantityInteractive(8.314472 , 'J/(mol*K)')
623 R.__doc__ = """molar gas constant """
624
625
626 k_J = PhysicalQuantityInteractive(1.3806503E-23 , 'J/K')
627 k_J.__doc__ = """Boltzmann constant """
628
629
630 k_eV = PhysicalQuantityInteractive(8.617342E-5 , 'eV/K')
631 k_eV.__doc__ = """Boltzmann constant in eV """
632
633
634 n_0 = PhysicalQuantityInteractive(2.6867775E25 , '1/m**3')
635 n_0.__doc__ = """Loschmidt constant NA/Vm """
636
637
638 Vm_1 = PhysicalQuantityInteractive(22.413996E-3 , 'm**3/mol')
639 Vm_1.__doc__ = """molar volume of ideal gas RT/p T = 273.15 K, p = 101.325 kPa """
640
641 Vm_2 = PhysicalQuantityInteractive(22.710981E-3 , 'm**3/mol')
642 Vm_2.__doc__ = """molar volume of ideal gas RT/p T = 273.15 K, p = 100 kPa """
643
644 # Sackur-Tetrode constant (absolute entropy constant) 52 + ln_(2 mukT1/h2)3/2kT1/p0
645 # T1 = 1 K, p0 = 100 kPa
646 S_0R_1 = -1.1517048
647 # T1 = 1 K, p0 = 101.325 kPa
648 S_0R_2 = -1.1648678
649
650
651 sigma = PhysicalQuantityInteractive(5.670400E-8 , 'W/(m**2*K**4)')
652 sigma.__doc__ = """Stefan-Boltzmann constant """
653
654
655 c_1 = PhysicalQuantityInteractive(3.74177107E-16 , 'W*m**2')
656 c_1.__doc__ = """first radiation constant"""
657
658
659 c_1L = PhysicalQuantityInteractive(1.191042722E-16 , 'W*m**2/sr')
660 c_1L.__doc__ = """first radiation constant for spectral radiance"""
661
662
663 c_2 = PhysicalQuantityInteractive(1.4387752E-2 , 'm*K')
664 c_2.__doc__ = """second radiation constant"""
665
666
667 b = PhysicalQuantityInteractive(2.8977686E-3 , 'm*K')
668 b.__doc__ = """Wien displacement law constant b = maxT = c2/4.965 114231... """
669
@@ -1,62 +0,0 b''
1 """ Set default options for IPython.
2
3 Just import this module to get reasonable defaults for everything.
4
5 These configurations used to be performed in ipythonrc (or ipythonrc.ini).
6 Therefore importing this in your config files makes ipython basically
7 ignore your ipythonrc. This is *not* imported by default, you need to import
8 this manually in one of your config files.
9
10 You can further override these defaults in e.g. your ipy_user_config.py,
11 ipy_profile_PROFILENAME etc.
12
13 """
14
15 import IPython.utils.rlineimpl as readline
16 from IPython.core import ipapi
17 ip = ipapi.get()
18
19 o = ip.options
20
21 o.colors = "Linux"
22 o.color_info=1
23 o.confirm_exit=1
24 o.pprint=1
25 o.multi_line_specials=1
26 o.xmode="Context"
27
28
29 o.prompt_in1='In [\#]: '
30 o.prompt_in2 =' .\D.: '
31 o.prompt_out = 'Out[\#]: '
32 o.prompts_pad_left=1
33
34 o.autoindent = 1
35
36 o.readline_remove_delims="-/~"
37 o.readline_merge_completions=1
38
39 o.readline = 1
40
41 rlopts = """\
42 tab: complete
43 "\C-l": possible-completions
44 set show-all-if-ambiguous on
45 "\C-o": tab-insert
46 "\M-i": " "
47 "\M-o": "\d\d\d\d"
48 "\M-I": "\d\d\d\d"
49 "\C-r": reverse-search-history
50 "\C-s": forward-search-history
51 "\C-p": history-search-backward
52 "\C-n": history-search-forward
53 "\e[A": history-search-backward
54 "\e[B": history-search-forward
55 "\C-k": kill-line
56 "\C-u": unix-line-discard"""
57
58 if readline.have_readline:
59 for cmd in rlopts.split('\n'):
60 readline.parse_and_bind(cmd)
61
62
@@ -1,80 +0,0 b''
1 import os,sys
2
3 import ipy_rehashdir,glob
4 from ipy_rehashdir import selflaunch, PyLauncher
5
6 def pylaunchers():
7 """Create launchers for python scripts in cwd and store them in alias table
8
9 This is useful if you want to invoke .py scripts from ipykit session,
10 just adding .py files in PATH does not work without file association.
11
12 .ipy files will be run like macros.
13
14 """
15 fs = glob.glob('*.py') + glob.glob('*.ipy')
16 for f in fs:
17 l = PyLauncher(f)
18 n = os.path.splitext(f)[0]
19 ip.define_alias(n, l)
20 ip.magic('store '+n)
21
22
23 def exta_imports():
24 # add some modules that you'd want to be bundled in the ipykit
25 # library zip file here. Do this if you get ImportErrors from scripts you
26 # try to launch with 'py' or pylaunchers. In theory you could include
27 # the whole stdlib here for full script coverage
28
29 # note that this is never run, it's just here for py2exe
30 import distutils.dir_util
31
32 def kitroot():
33 return os.environ.get('IPYKITROOT', None)
34
35 def main():
36
37 if not kitroot():
38 print "Can't configure ipykit, IPYKITROOT should be set."
39 return
40
41 os.environ["PATH"] = os.environ["PATH"] + ";" + kitroot() + "\\bin;"
42 ip.push("pylaunchers")
43 cmds = ip.db.get('syscmdlist', None)
44 if cmds is None:
45 ip.magic('rehashx')
46 cmds = ip.db.get('syscmdlist', [])
47 #print cmds
48 if 'sc1' in cmds:
49 print "Default editor: Sc1"
50 import ipy_editors
51 ipy_editors.scite('sc1')
52
53 # for icp, imv, imkdir, etc.
54 import ipy_fsops
55
56 greeting = """\n\n === Welcome to ipykit ===
57
58 %quickref - learn quickly about IPython.
59
60 """
61
62 def ipython_firstrun(ip):
63
64 print "First run of ipykit - configuring"
65
66 ip.define_alias('py',selflaunch)
67 ip.define_alias('d','dir /w /og /on')
68 ip.magic('store py')
69 ip.magic('store d')
70
71 bins = kitroot() +'/bin'
72
73 print greeting
74
75 def init_ipython(ipy):
76 global ip
77 ip = ipy
78 main()
79
80
@@ -1,62 +0,0 b''
1 """ Legacy stuff
2
3 Various stuff that are there for historical / familiarity reasons.
4
5 This is automatically imported by default profile, though not other profiles
6 (e.g. 'sh' profile).
7
8 Stuff that is considered obsolete / redundant is gradually moved here.
9
10 """
11
12 from IPython.core import ipapi
13 ip = ipapi.get()
14
15 import os,sys
16
17 from IPython.utils.genutils import *
18
19 # use rehashx
20
21 def magic_rehash(self, parameter_s = ''):
22 """Update the alias table with all entries in $PATH.
23
24 This version does no checks on execute permissions or whether the
25 contents of $PATH are truly files (instead of directories or something
26 else). For such a safer (but slower) version, use %rehashx."""
27
28 # This function (and rehashx) manipulate the alias_table directly
29 # rather than calling magic_alias, for speed reasons. A rehash on a
30 # typical Linux box involves several thousand entries, so efficiency
31 # here is a top concern.
32
33 path = filter(os.path.isdir,os.environ.get('PATH','').split(os.pathsep))
34 alias_table = self.shell.alias_table
35 for pdir in path:
36 for ff in os.listdir(pdir):
37 # each entry in the alias table must be (N,name), where
38 # N is the number of positional arguments of the alias.
39 alias_table[ff] = (0,ff)
40 # Make sure the alias table doesn't contain keywords or builtins
41 self.shell.alias_table_validate()
42 # Call again init_auto_alias() so we get 'rm -i' and other modified
43 # aliases since %rehash will probably clobber them
44 self.shell.init_auto_alias()
45
46 ip.define_magic("rehash", magic_rehash)
47
48 # Exit
49 def magic_Quit(self, parameter_s=''):
50 """Exit IPython without confirmation (like %Exit)."""
51
52 self.shell.ask_exit()
53
54 ip.define_magic("Quit", magic_Quit)
55
56
57 # make it autocallable fn if you really need it
58 def magic_p(self, parameter_s=''):
59 """Just a short alias for Python's 'print'."""
60 exec 'print ' + parameter_s in self.shell.user_ns
61
62 ip.define_magic("p", magic_p)
@@ -1,47 +0,0 b''
1 # -*- coding: utf-8 -*-
2 """
3 Add %p4 magic for pythonic p4 (Perforce) usage.
4 """
5
6 from IPython.core import ipapi
7 ip = ipapi.get()
8
9 import os,sys,marshal
10
11 import ipy_stock_completers
12
13 def p4_f(self, parameter_s=''):
14 cmd = 'p4 -G ' + parameter_s
15 fobj = os.popen(cmd)
16 out = []
17 while 1:
18 try:
19 out.append(marshal.load(fobj))
20 except EOFError:
21 break
22
23 return out
24
25 def p4d(fname):
26 return os.popen('p4 where ' + fname).read().split()[0]
27
28 ip.push("p4d")
29
30 ip.define_magic('p4', p4_f)
31
32 p4_commands = """\
33 add admin annotate branch branches change changes changelist
34 changelists client clients counter counters delete depot depots
35 describe diff diff2 dirs edit filelog files fix fixes flush fstat
36 group groups have help info integrate integrated job jobs jobspec
37 label labels labelsync lock logger login logout monitor obliterate
38 opened passwd print protect rename reopen resolve resolved revert
39 review reviews set submit sync tag tickets triggers typemap unlock
40 user users verify workspace workspaces where"""
41
42 def p4_completer(self,event):
43 return ipy_stock_completers.vcs_completer(p4_commands, event)
44
45 ip.set_hook('complete_command', p4_completer, str_key = '%p4')
46 ip.set_hook('complete_command', p4_completer, str_key = 'p4')
47
@@ -1,4 +0,0 b''
1 """ Config file for 'default' profile """
2
3 # get various stuff that are there for historical / familiarity reasons
4 import ipy_legacy No newline at end of file
@@ -1,24 +0,0 b''
1 """ IPython 'numpy' profile, to preload NumPy.
2
3 This profile loads the math/cmath modules as well as all of numpy.
4
5 It exposes numpy via the 'np' shorthand as well for convenience.
6 """
7
8 from IPython.core import ipapi
9 import ipy_defaults
10
11 def main():
12 ip = ipapi.get()
13
14 try:
15 ip.ex("import math,cmath")
16 ip.ex("import numpy")
17 ip.ex("import numpy as np")
18
19 ip.ex("from numpy import *")
20
21 except ImportError:
22 print "Unable to start NumPy profile, is numpy installed?"
23
24 main()
@@ -1,29 +0,0 b''
1 """ IPython 'scipy' profile, preloads NumPy and SciPy.
2
3 This profile loads the math/cmath modules as well as all of numpy and scipy.
4
5 It exposes numpy and scipy via the 'np' and 'sp' shorthands as well for
6 convenience.
7 """
8
9 from IPython.core import ipapi
10 import ipy_defaults
11
12 def main():
13 ip = ipapi.get()
14
15 try:
16 ip.ex("import math,cmath")
17 ip.ex("import numpy")
18 ip.ex("import scipy")
19
20 ip.ex("import numpy as np")
21 ip.ex("import scipy as sp")
22
23 ip.ex("from numpy import *")
24 ip.ex("from scipy import *")
25
26 except ImportError:
27 print "Unable to start scipy profile, are numpy and scipy installed?"
28
29 main()
@@ -1,268 +0,0 b''
1 """Shell mode for IPython.
2
3 Start ipython in shell mode by invoking "ipython -p sh"
4
5 (the old version, "ipython -p pysh" still works but this is the more "modern"
6 shell mode and is recommended for users who don't care about pysh-mode
7 compatibility)
8 """
9
10 from IPython.core import ipapi
11 from IPython.core.error import TryNext
12 import os,re,textwrap
13
14 # The import below effectively obsoletes your old-style ipythonrc[.ini],
15 # so consider yourself warned!
16
17 import ipy_defaults
18
19 def main():
20 ip = ipapi.get()
21 o = ip.options
22 # autocall to "full" mode (smart mode is default, I like full mode)
23
24 o.autocall = 2
25
26 # Jason Orendorff's path class is handy to have in user namespace
27 # if you are doing shell-like stuff
28 try:
29 ip.ex("from IPython.external.path import path" )
30 except ImportError:
31 pass
32
33 # beefed up %env is handy in shell mode
34 import envpersist
35
36 # To see where mycmd resides (in path/aliases), do %which mycmd
37 import ipy_which
38
39 # tab completers for hg, svn, ...
40 import ipy_app_completers
41
42 # To make executables foo and bar in mybin usable without PATH change, do:
43 # %rehashdir c:/mybin
44 # %store foo
45 # %store bar
46 import ipy_rehashdir
47
48 # does not work without subprocess module!
49 #import ipy_signals
50
51 ip.ex('import os')
52 ip.ex("def up(): os.chdir('..')")
53 ip.user_ns['LA'] = LastArgFinder()
54
55 # You can assign to _prompt_title variable
56 # to provide some extra information for prompt
57 # (e.g. the current mode, host/username...)
58
59 ip.user_ns['_prompt_title'] = ''
60
61 # Nice prompt
62 o.prompt_in1= r'\C_Green${_prompt_title}\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Green|\#> '
63 o.prompt_in2= r'\C_Green|\C_LightGreen\D\C_Green> '
64 o.prompt_out= '<\#> '
65
66 from IPython.core import release
67
68 import sys
69 # Non-chatty banner
70 o.banner = "IPython %s [on Py %s]\n" % (release.version,sys.version.split(None,1)[0])
71
72
73 ip.default_option('cd','-q')
74 ip.default_option('macro', '-r')
75 # If you only rarely want to execute the things you %edit...
76 #ip.default_option('edit','-x')
77
78
79 o.prompts_pad_left="1"
80 # Remove all blank lines in between prompts, like a normal shell.
81 o.separate_in="0"
82 o.separate_out="0"
83 o.separate_out2="0"
84
85 # now alias all syscommands
86
87 db = ip.db
88
89 syscmds = db.get("syscmdlist",[] )
90 if not syscmds:
91 print textwrap.dedent("""
92 System command list not initialized, probably the first run...
93 running %rehashx to refresh the command list. Run %rehashx
94 again to refresh command list (after installing new software etc.)
95 """)
96 ip.magic('rehashx')
97 syscmds = db.get("syscmdlist")
98
99 # lowcase aliases on win32 only
100 if os.name == 'posix':
101 mapper = lambda s:s
102 else:
103 def mapper(s): return s.lower()
104
105 for cmd in syscmds:
106 # print "sys",cmd #dbg
107 noext, ext = os.path.splitext(cmd)
108 if ext.lower() == '.exe':
109 cmd = noext
110
111 key = mapper(cmd)
112 if key not in ip.alias_manager.alias_table:
113 # Dots will be removed from alias names, since ipython
114 # assumes names with dots to be python code
115
116 ip.define_alias(key.replace('.',''), cmd)
117
118 # win32 is crippled w/o cygwin, try to help it a little bit
119 if sys.platform == 'win32':
120 if 'cygwin' in os.environ['PATH'].lower():
121 # use the colors of cygwin ls (recommended)
122 ip.define_alias('d', 'ls -F --color=auto')
123 else:
124 # get icp, imv, imkdir, igrep, irm,...
125 ip.load('ipy_fsops')
126
127 # and the next best thing to real 'ls -F'
128 ip.define_alias('d','dir /w /og /on')
129
130 ip.set_hook('input_prefilter', slash_prefilter_f)
131 extend_shell_behavior(ip)
132
133 class LastArgFinder:
134 """ Allow $LA to work as "last argument of previous command", like $! in bash
135
136 To call this in normal IPython code, do LA()
137 """
138 def __call__(self, hist_idx = None):
139 ip = ipapi.get()
140 if hist_idx is None:
141 return str(self)
142 return ip.input_hist_raw[hist_idx].strip().split()[-1]
143 def __str__(self):
144 ip = ipapi.get()
145 for cmd in reversed(ip.input_hist_raw):
146 parts = cmd.strip().split()
147 if len(parts) < 2 or parts[-1] in ['$LA', 'LA()']:
148 continue
149 return parts[-1]
150 return ""
151
152 def slash_prefilter_f(self,line):
153 """ ./foo, ~/foo and /bin/foo now run foo as system command
154
155 Removes the need for doing !./foo, !~/foo or !/bin/foo
156 """
157 from IPython.utils import genutils
158 if re.match('(?:[.~]|/[a-zA-Z_0-9]+)/', line):
159 return "get_ipython().system(" + genutils.make_quoted_expr(line)+")"
160 raise TryNext
161
162 # XXX You do not need to understand the next function!
163 # This should probably be moved out of profile
164
165 def extend_shell_behavior(ip):
166
167 # Instead of making signature a global variable tie it to IPSHELL.
168 # In future if it is required to distinguish between different
169 # shells we can assign a signature per shell basis
170 ip.__sig__ = 0xa005
171 # mark the IPSHELL with this signature
172 ip.user_ns['__builtins__'].__dict__['__sig__'] = ip.__sig__
173
174 from IPython.external.Itpl import ItplNS
175 from IPython.utils.genutils import shell
176 # utility to expand user variables via Itpl
177 # xxx do something sensible with depth?
178 ip.var_expand = lambda cmd, lvars=None, depth=2: \
179 str(ItplNS(cmd, ip.user_ns, get_locals()))
180
181 def get_locals():
182 """ Substituting a variable through Itpl deep inside the IPSHELL stack
183 requires the knowledge of all the variables in scope upto the last
184 IPSHELL frame. This routine simply merges all the local variables
185 on the IPSHELL stack without worrying about their scope rules
186 """
187 import sys
188 # note lambda expression constitues a function call
189 # hence fno should be incremented by one
190 getsig = lambda fno: sys._getframe(fno+1).f_globals \
191 ['__builtins__'].__dict__['__sig__']
192 getlvars = lambda fno: sys._getframe(fno+1).f_locals
193 # trackback until we enter the IPSHELL
194 frame_no = 1
195 sig = ip.__sig__
196 fsig = ~sig
197 while fsig != sig :
198 try:
199 fsig = getsig(frame_no)
200 except (AttributeError, KeyError):
201 frame_no += 1
202 except ValueError:
203 # stack is depleted
204 # call did not originate from IPSHELL
205 return {}
206 first_frame = frame_no
207 # walk further back until we exit from IPSHELL or deplete stack
208 try:
209 while(sig == getsig(frame_no+1)):
210 frame_no += 1
211 except (AttributeError, KeyError, ValueError):
212 pass
213 # merge the locals from top down hence overriding
214 # any re-definitions of variables, functions etc.
215 lvars = {}
216 for fno in range(frame_no, first_frame-1, -1):
217 lvars.update(getlvars(fno))
218 #print '\n'*5, first_frame, frame_no, '\n', lvars, '\n'*5 #dbg
219 return lvars
220
221 def _runlines(lines):
222 """Run a string of one or more lines of source.
223
224 This method is capable of running a string containing multiple source
225 lines, as if they had been entered at the IPython prompt. Since it
226 exposes IPython's processing machinery, the given strings can contain
227 magic calls (%magic), special shell access (!cmd), etc."""
228
229 # We must start with a clean buffer, in case this is run from an
230 # interactive IPython session (via a magic, for example).
231 ip.resetbuffer()
232 lines = lines.split('\n')
233 more = 0
234 command = ''
235 for line in lines:
236 # skip blank lines so we don't mess up the prompt counter, but do
237 # NOT skip even a blank line if we are in a code block (more is
238 # true)
239 # if command is not empty trim the line
240 if command != '' :
241 line = line.strip()
242 # add the broken line to the command
243 if line and line[-1] == '\\' :
244 command += line[0:-1] + ' '
245 more = True
246 continue
247 else :
248 # add the last (current) line to the command
249 command += line
250 if command or more:
251 # push to raw history, so hist line numbers stay in sync
252 ip.input_hist_raw.append("# " + command + "\n")
253
254 more = ip.push_line(ip.prefilter(command,more))
255 command = ''
256 # IPython's runsource returns None if there was an error
257 # compiling the code. This allows us to stop processing right
258 # away, so the user gets the error message at the right place.
259 if more is None:
260 break
261 # final newline in case the input didn't have it, so that the code
262 # actually does get executed
263 if more:
264 ip.push_line('\n')
265
266 ip.runlines = _runlines
267
268 main()
@@ -1,324 +0,0 b''
1 # -*- coding: utf-8 -*-
2 """ An ipython profile for zope and plone.
3
4 Some ideas stolen from http://www.tomster.org.
5
6
7 Authors
8 -------
9 - Stefan Eletzhofer <stefan.eletzhofer@inquant.de>
10 """
11
12 # File: ipy_profile_zope.py
13 #
14 # Copyright (c) InQuant GmbH
15 #
16 #
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
19
20 from IPython.core import ipapi
21 from IPython.core import release
22 from types import StringType
23 import sys
24 import os
25 import textwrap
26
27 sys_oldstdin = sys.stdin
28
29 # The import below effectively obsoletes your old-style ipythonrc[.ini],
30 # so consider yourself warned!
31 # import ipy_defaults
32
33 _marker = []
34 def shasattr(obj, attr, acquire=False):
35 """ See Archetypes/utils.py
36 """
37 if not acquire:
38 obj = obj.aq_base
39 return getattr(obj, attr, _marker) is not _marker
40
41 class ZopeDebug(object):
42 def __init__(self):
43
44 self.instancehome = os.environ.get( "INSTANCE_HOME" )
45
46 configfile = os.environ.get( "CONFIG_FILE" )
47 if configfile is None and self.instancehome is not None:
48 configfile = os.path.join( self.instancehome, "etc", "zope.conf" )
49
50 if configfile is None:
51 raise RuntimeError( "CONFIG_FILE env not set" )
52
53 print "CONFIG_FILE=", configfile
54 print "INSTANCE_HOME=", self.instancehome
55
56 self.configfile = configfile
57
58 try:
59 from Zope2 import configure
60 except ImportError:
61 from Zope import configure
62
63 configure( configfile )
64
65 try:
66 import Zope2
67 app = Zope2.app()
68 except ImportError:
69 import Zope
70 app = Zope.app()
71
72 from Testing.makerequest import makerequest
73 self.app = makerequest( app )
74
75 try:
76 self._make_permissive()
77 print "Permissive security installed"
78 except:
79 print "Permissive security NOT installed"
80
81 self._pwd = self.portal or self.app
82
83 try:
84 from zope.component import getSiteManager
85 from zope.component import getGlobalSiteManager
86 from zope.app.component.hooks import setSite
87
88 if self.portal is not None:
89 setSite( self.portal )
90
91 gsm = getGlobalSiteManager()
92 sm = getSiteManager()
93
94 if sm is gsm:
95 print "ERROR SETTING SITE!"
96 except:
97 pass
98
99
100 @property
101 def utils(self):
102 class Utils(object):
103 commit = self.commit
104 sync = self.sync
105 objectInfo = self.objectInfo
106 ls = self.ls
107 pwd = self.pwd
108 cd = self.cd
109 su = self.su
110 getCatalogInfo = self.getCatalogInfo
111
112 @property
113 def cwd(self):
114 return self.pwd()
115
116 return Utils()
117
118 @property
119 def namespace(self):
120 return dict( utils=self.utils, app=self.app, portal=self.portal )
121
122 @property
123 def portal(self):
124 portals = self.app.objectValues( "Plone Site" )
125 if len(portals):
126 return portals[0]
127 else:
128 raise KeyError( "No Plone Site found.")
129
130 def pwd(self):
131 return self._pwd
132
133 def _make_permissive(self):
134 """
135 Make a permissive security manager with all rights. Hell,
136 we're developers, aren't we? Security is for whimps. :)
137 """
138 from Products.CMFCore.tests.base.security import PermissiveSecurityPolicy
139 import AccessControl
140 from AccessControl.SecurityManagement import newSecurityManager
141 from AccessControl.SecurityManager import setSecurityPolicy
142
143 _policy = PermissiveSecurityPolicy()
144 self.oldpolicy = setSecurityPolicy(_policy)
145 newSecurityManager(None, AccessControl.User.system)
146
147 def su(self, username):
148 """ Change to named user.
149 """
150 # TODO Make it easy to change back to permissive security.
151 user = self.portal.acl_users.getUser(username)
152 if not user:
153 print "Can't find %s in %s" % (username, self.portal.acl_users)
154 return
155
156 from AccessControl import ZopeSecurityPolicy
157 import AccessControl
158 from AccessControl.SecurityManagement import newSecurityManager, getSecurityManager
159 from AccessControl.SecurityManager import setSecurityPolicy
160
161 _policy = ZopeSecurityPolicy
162 self.oldpolicy = setSecurityPolicy(_policy)
163 wrapped_user = user.__of__(self.portal.acl_users)
164 newSecurityManager(None, user)
165 print 'User changed.'
166 return getSecurityManager().getUser()
167
168 def getCatalogInfo(self, obj=None, catalog='portal_catalog', query=None, sort_on='created', sort_order='reverse' ):
169 """ Inspect portal_catalog. Pass an object or object id for a
170 default query on that object, or pass an explicit query.
171 """
172 if obj and query:
173 print "Ignoring %s, using query." % obj
174
175 catalog = self.portal.get(catalog)
176 if not catalog:
177 return 'No catalog'
178
179 indexes = catalog._catalog.indexes
180 if not query:
181 if type(obj) is StringType:
182 cwd = self.pwd()
183 obj = cwd.unrestrictedTraverse( obj )
184 # If the default in the signature is mutable, its value will
185 # persist across invocations.
186 query = {}
187 if indexes.get('path'):
188 from string import join
189 path = join(obj.getPhysicalPath(), '/')
190 query.update({'path': path})
191 if indexes.get('getID'):
192 query.update({'getID': obj.id, })
193 if indexes.get('UID') and shasattr(obj, 'UID'):
194 query.update({'UID': obj.UID(), })
195 if indexes.get(sort_on):
196 query.update({'sort_on': sort_on, 'sort_order': sort_order})
197 if not query:
198 return 'Empty query'
199 results = catalog(**query)
200
201 result_info = []
202 for r in results:
203 rid = r.getRID()
204 if rid:
205 result_info.append(
206 {'path': catalog.getpath(rid),
207 'metadata': catalog.getMetadataForRID(rid),
208 'indexes': catalog.getIndexDataForRID(rid), }
209 )
210 else:
211 result_info.append({'missing': rid})
212
213 if len(result_info) == 1:
214 return result_info[0]
215 return result_info
216
217 def commit(self):
218 """
219 Commit the transaction.
220 """
221 try:
222 import transaction
223 transaction.get().commit()
224 except ImportError:
225 get_transaction().commit()
226
227 def sync(self):
228 """
229 Sync the app's view of the zodb.
230 """
231 self.app._p_jar.sync()
232
233 def objectInfo( self, o ):
234 """
235 Return a descriptive string of an object
236 """
237 Title = ""
238 t = getattr( o, 'Title', None )
239 if t:
240 Title = t()
241 return {'id': o.getId(),
242 'Title': Title,
243 'portal_type': getattr( o, 'portal_type', o.meta_type),
244 'folderish': o.isPrincipiaFolderish
245 }
246
247 def cd( self, path ):
248 """
249 Change current dir to a specific folder.
250
251 cd( ".." )
252 cd( "/plone/Members/admin" )
253 cd( portal.Members.admin )
254 etc.
255 """
256 if type(path) is not StringType:
257 path = '/'.join(path.getPhysicalPath())
258 cwd = self.pwd()
259 x = cwd.unrestrictedTraverse( path )
260 if x is None:
261 raise KeyError( "Can't cd to %s" % path )
262
263 print "%s -> %s" % ( self.pwd().getId(), x.getId() )
264 self._pwd = x
265
266 def ls( self, x=None ):
267 """
268 List object(s)
269 """
270 if type(x) is StringType:
271 cwd = self.pwd()
272 x = cwd.unrestrictedTraverse( x )
273 if x is None:
274 x = self.pwd()
275 if x.isPrincipiaFolderish:
276 return [self.objectInfo(o) for id, o in x.objectItems()]
277 else:
278 return self.objectInfo( x )
279
280 zope_debug = None
281
282 def ipy_set_trace():
283 from IPython.core import debugger
284 debugger.Pdb().set_trace()
285
286 def main():
287 global zope_debug
288 ip = ipapi.get()
289 o = ip.options
290 # autocall to "full" mode (smart mode is default, I like full mode)
291
292 SOFTWARE_HOME = os.environ.get( "SOFTWARE_HOME" )
293 sys.path.append( SOFTWARE_HOME )
294 print "SOFTWARE_HOME=%s\n" % SOFTWARE_HOME
295
296 zope_debug = ZopeDebug()
297
298 # <HACK ALERT>
299 import pdb;
300 pdb.set_trace = ipy_set_trace
301 # </HACK ALERT>
302
303 # I like my banner minimal.
304 o.banner = "ZOPE Py %s IPy %s\n" % (sys.version.split('\n')[0],release.version)
305
306 print textwrap.dedent("""\
307 ZOPE mode iPython shell.
308
309 Bound names:
310 app
311 portal
312 utils.{ %s }
313
314 Uses the $SOFTWARE_HOME and $CONFIG_FILE environment
315 variables.
316 """ % ( ",".join([ x for x in dir(zope_debug.utils) if not x.startswith("_") ] ) ) )
317
318
319 sys.stdin = sys_oldstdin
320 ip.user_ns.update( zope_debug.namespace )
321
322
323 main()
324 # vim: set ft=python ts=4 sw=4 expandtab :
@@ -1,219 +0,0 b''
1 """Traits-aware tab completion.
2
3 This module provides a custom tab-completer that intelligently hides the names
4 that the enthought.traits library (http://code.enthought.com/traits)
5 automatically adds to all objects that inherit from its base HasTraits class.
6
7
8 Activation
9 ==========
10
11 To use this, put in your ~/.ipython/ipy_user_conf.py file:
12
13 from ipy_traits_completer import activate
14 activate([complete_threshold])
15
16 The optional complete_threshold argument is the minimal length of text you need
17 to type for tab-completion to list names that are automatically generated by
18 traits. The default value is 3. Note that at runtime, you can change this
19 value simply by doing:
20
21 import ipy_traits_completer
22 ipy_traits_completer.COMPLETE_THRESHOLD = 4
23
24
25 Usage
26 =====
27
28 The system works as follows. If t is an empty object that HasTraits, then
29 (assuming the threshold is at the default value of 3):
30
31 In [7]: t.ed<TAB>
32
33 doesn't show anything at all, but:
34
35 In [7]: t.edi<TAB>
36 t.edit_traits t.editable_traits
37
38 shows these two names that come from traits. This allows you to complete on
39 the traits-specific names by typing at least 3 letters from them (or whatever
40 you set your threshold to), but to otherwise not see them in normal completion.
41
42
43 Notes
44 =====
45
46 - This requires Python 2.4 to work (I use sets). I don't think anyone is
47 using traits with 2.3 anyway, so that's OK.
48
49 - Imports from enthought.traits are deferred until an object with a class that
50 looks like it subclasses from HasTraits comes along. This test is done by
51 looking at the name of the class and its superclasses.
52 """
53
54 #############################################################################
55 # IPython imports
56 from IPython.core.error import TryNext
57 from IPython.core.ipapi import get as ipget
58 from IPython.utils.dir2 import dir2
59 try:
60 set
61 except:
62 from sets import Set as set
63
64 #############################################################################
65 # Module constants
66
67 # The completion threshold
68 # This is currently implemented as a module global, since this sytem isn't
69 # likely to be modified at runtime by multiple instances. If needed in the
70 # future, we can always make it local to the completer as a function attribute.
71 COMPLETE_THRESHOLD = 3
72
73 # Set of names that Traits automatically adds to ANY traits-inheriting object.
74 # These are the names we'll filter out.
75 TRAIT_NAMES = None
76 def get_trait_names():
77 global TRAIT_NAMES
78 from enthought.traits.api import HasTraits
79 if TRAIT_NAMES is None:
80 TRAIT_NAMES = set( dir2(HasTraits()) ) - set( dir2(object()) )
81 else:
82 return TRAIT_NAMES
83
84 #############################################################################
85 # Code begins
86
87 def looks_like_isinstance(obj, classname):
88 """ Return True if the object has a class or superclass with the given class
89 name.
90
91 Ignores old-style classes.
92 """
93 from types import InstanceType
94
95 t = type(obj)
96 if t is InstanceType:
97 # Old-style classes.
98 return False
99 elif t.__name__ == classname:
100 return True
101 for klass in t.__mro__:
102 if klass.__name__ == classname:
103 return True
104 return False
105
106 def trait_completer(self,event):
107 """A custom IPython tab-completer that is traits-aware.
108
109 It tries to hide the internal traits attributes, and reveal them only when
110 it can reasonably guess that the user really is after one of them.
111 """
112
113 #print '\nevent is:',event # dbg
114 symbol_parts = event.symbol.split('.')
115 base = '.'.join(symbol_parts[:-1])
116 #print 'base:',base # dbg
117
118 oinfo = self._ofind(base)
119 if not oinfo['found']:
120 raise TryNext
121
122 obj = oinfo['obj']
123 # OK, we got the object. See if it's traits, else punt
124 if not looks_like_isinstance(obj, 'HasTraits'):
125 raise TryNext
126
127 # Defer import until here so as not to require Traits until we get something
128 # that looks like it might be a HasTraits instance.
129 from enthought.traits.api import HasTraits
130 if not isinstance(obj, HasTraits):
131 raise TryNext
132
133 # it's a traits object, don't show the tr* attributes unless the completion
134 # begins with 'tr'
135 attrs = dir2(obj)
136 # Now, filter out the attributes that start with the user's request
137 attr_start = symbol_parts[-1]
138 if attr_start:
139 attrs = [a for a in attrs if a.startswith(attr_start)]
140
141 # Let's also respect the user's readline_omit__names setting:
142 omit__names = ipget().options.readline_omit__names
143 if omit__names == 1:
144 attrs = [a for a in attrs if not a.startswith('__')]
145 elif omit__names == 2:
146 attrs = [a for a in attrs if not a.startswith('_')]
147
148 #print '\nastart:<%r>' % attr_start # dbg
149
150 if len(attr_start)<COMPLETE_THRESHOLD:
151 attrs = list(set(attrs) - get_trait_names())
152
153 # The base of the completion, so we can form the final results list
154 bdot = base+'.'
155
156 tcomp = [bdot+a for a in attrs]
157 #print 'tcomp:',tcomp
158 return tcomp
159
160 def activate(complete_threshold = COMPLETE_THRESHOLD):
161 """Activate the Traits completer.
162
163 :Keywords:
164 complete_threshold : int
165 The minimum number of letters that a user must type in order to
166 activate completion of traits-private names."""
167
168 if not (isinstance(complete_threshold,int) and
169 complete_threshold>0):
170 e='complete_threshold must be a positive integer, not %r' % \
171 complete_threshold
172 raise ValueError(e)
173
174 # Set the module global
175 global COMPLETE_THRESHOLD
176 COMPLETE_THRESHOLD = complete_threshold
177
178 # Activate the traits aware completer
179 ip = ipget()
180 ip.set_hook('complete_command', trait_completer, re_key = '.*')
181
182
183 #############################################################################
184 if __name__ == '__main__':
185 # Testing/debugging
186 from enthought.traits.api import HasTraits
187
188 # A sorted list of the names we'll filter out
189 TNL = list(get_trait_names())
190 TNL.sort()
191
192 # Make a few objects for testing
193 class TClean(HasTraits): pass
194 class Bunch(object): pass
195 # A clean traits object
196 t = TClean()
197 # A nested object containing t
198 f = Bunch()
199 f.t = t
200 # And a naked new-style object
201 o = object()
202
203 ip = ipget().IP
204
205 # A few simplistic tests
206
207 # Reset the threshold to the default, in case the test is running inside an
208 # instance of ipython that changed it
209 import ipy_traits_completer
210 ipy_traits_completer.COMPLETE_THRESHOLD = 3
211
212 assert ip.complete('t.ed') ==[]
213
214 # For some bizarre reason, these fail on the first time I run them, but not
215 # afterwards. Traits does some really weird stuff at object instantiation
216 # time...
217 ta = ip.complete('t.edi')
218 assert ta == ['t.edit_traits', 't.editable_traits']
219 print 'Tests OK'
@@ -1,245 +0,0 b''
1 """ Integration with gvim, by Erich Heine
2
3 Provides a %vim magic command, and reuses the same vim session. Uses
4 unix domain sockets for communication between vim and IPython. ipy.vim is
5 available in doc/examples of the IPython distribution.
6
7 Slightly touched up email announcement (and description how to use it) by
8 Erich Heine is here:
9
10 Ive recently been playing with ipython, and like it quite a bit. I did
11 however discover a bit of frustration, namely with editor interaction.
12 I am a gvim user, and using the command edit on a new file causes
13 ipython to try and run that file as soon as the text editor opens
14 up. The -x command of course fixes this, but its still a bit annoying,
15 switching windows to do a run file, then back to the text
16 editor. Being a heavy tab user in gvim, another annoyance is not being
17 able to specify weather a new tab is how I choose to open the file.
18
19 Not being one to shirk my open source duties (and seeing this as a
20 good excuse to poke around ipython internals), Ive created a script
21 for having gvim and ipython work very nicely together. Ive attached
22 both to this email (hoping of course that the mailing list allows such
23 things).
24
25 There are 2 files:
26
27 ipy_vimserver.py -- this file contains the ipython stuff
28 ipy.vim -- this file contains the gvim stuff
29
30 In combination they allow for a few functionalities:
31
32 #1. the vim magic command. This is a fancy wrapper around the edit
33 magic, that allows for a new option, -t, which opens the text in a new
34 gvim tab. Otherwise it works the same as edit -x. (it internally
35 calls edit -x). This magic command also juggles vim server management,
36 so when it is called when there is not a gvim running, it creates a
37 new gvim instance, named after the ipython session name. Once such a
38 gvim instance is running, it will be used for subsequent uses of the
39 vim command.
40
41 #2. ipython - gvim interaction. Once a file has been opened with the
42 vim magic (and a session set up, see below), pressing the F5 key in
43 vim will cause the calling ipython instance to execute run
44 filename.py. (if you typo like I do, this is very useful)
45
46 #3. ipython server - this is a thread wich listens on a unix domain
47 socket, and runs commands sent to that socket.
48
49 Note, this only works on POSIX systems, that allow for AF_UNIX type
50 sockets. It has only been tested on linux (a fairly recent debian
51 testing distro).
52
53 To install it put, the ipserver.py in your favorite locaion for
54 sourcing ipython scripts. I put the ipy.vim in
55 ~/.vim/after/ftplugin/python/.
56
57 To use (this can be scripted im sure, but i usually have 2 or 3
58 ipythons and corresponding gvims open):
59
60 import ipy_vimserver
61 ipy_vimserver.setup('sessionname')
62
63 (Editors note - you can probably add these to your ipy_user_conf.py)
64
65 Then use ipython as you normally would, until you need to edit
66 something. Instead of edit, use the vim magic. Thats it!
67
68 """
69
70 from IPython.core import ipapi
71 from IPython.core.error import TryNext
72
73 import socket, select
74 import os, threading, subprocess
75 import re
76
77 try:
78 ERRCONDS = select.POLLHUP|select.POLLERR
79 except AttributeError:
80 raise ImportError("Vim server not supported on this platform - select "
81 "missing necessary POLLHUP/POLLERR functionality")
82
83 SERVER = None
84 ip = ipapi.get()
85
86 # this listens to a unix domain socket in a separate thread, so that comms
87 # between a vim instance and ipython can happen in a fun and productive way
88 class IpyServer(threading.Thread):
89 def __init__(self, sname):
90 super(IpyServer, self).__init__()
91 self.keep_running = True
92 self.__sname = sname
93 self.socket = socket.socket(socket.AF_UNIX)
94 self.poller = select.poll()
95 self.current_conns = dict()
96 self.setDaemon(True)
97
98 def listen(self):
99 self.socket.bind(self.__sname)
100 self.socket.listen(1)
101
102 def __handle_error(self, socket):
103 if socket == self.socket.fileno():
104 self.keep_running = False
105 for a in self.current_conns.values():
106 a.close()
107 return False
108 else:
109 y = self.current_conns[socket]
110 del self.current_conns[socket]
111 y.close()
112 self.poller.unregister(socket)
113
114 def serve_me(self):
115 self.listen()
116 self.poller.register(self.socket,select.POLLIN|ERRCONDS)
117
118 while self.keep_running:
119 try:
120 avail = self.poller.poll(1)
121 except:
122 continue
123
124 if not avail: continue
125
126 for sock, conds in avail:
127 if conds & (ERRCONDS):
128 if self.__handle_error(sock): continue
129 else: break
130
131 if sock == self.socket.fileno():
132 y = self.socket.accept()[0]
133 self.poller.register(y, select.POLLIN|ERRCONDS)
134 self.current_conns[y.fileno()] = y
135 else: y = self.current_conns.get(sock)
136
137 self.handle_request(y)
138
139 os.remove(self.__sname)
140
141 run = serve_me
142
143 def stop(self):
144 self.keep_running = False
145
146 def handle_request(self,sock):
147 sock.settimeout(1)
148 while self.keep_running:
149 try:
150 x = sock.recv(4096)
151 except socket.timeout:
152 pass
153 else:
154 break
155 self.do_it(x)
156
157 def do_it(self, data):
158 data = data.split('\n')
159 cmds = list()
160 for line in data:
161 cmds.append(line)
162 ip.runlines(cmds)
163
164
165 # try to help ensure that the unix domain socket is cleaned up proper
166 def shutdown_server(self):
167 if SERVER:
168 SERVER.stop()
169 SERVER.join(3)
170 raise TryNext
171
172 ip.set_hook('shutdown_hook', shutdown_server, 10)
173
174 # this fun function exists to make setup easier for all, and makes the
175 # vimhook function ready for instance specific communication
176 def setup(sessionname='',socketdir=os.path.expanduser('~/.ipython/')):
177 global SERVER
178
179 if sessionname:
180 session = sessionname
181 elif os.environ.get('IPY_SESSION'):
182 session = os.environ.get('IPY_SESSION')
183 else:
184 session = 'IPYS'
185 vimhook.vimserver=session
186 vimhook.ipyserver = os.path.join(socketdir, session)
187 if not SERVER:
188 SERVER = IpyServer(vimhook.ipyserver)
189 SERVER.start()
190
191
192
193 # calls gvim, with all ops happening on the correct gvim instance for this
194 # ipython instance. it then calls edit -x (since gvim will return right away)
195 # things of note: it sets up a special environment, so that the ipy.vim script
196 # can connect back to the ipython instance and do fun things, like run the file
197 def vimhook(self, fname, line):
198 env = os.environ.copy()
199 vserver = vimhook.vimserver.upper()
200 check = subprocess.Popen('gvim --serverlist', stdout = subprocess.PIPE,
201 shell=True)
202 check.wait()
203 cval = [l for l in check.stdout.readlines() if vserver in l]
204
205 if cval:
206 vimargs = '--remote%s' % (vimhook.extras,)
207 else:
208 vimargs = ''
209 vimhook.extras = ''
210
211 env['IPY_SESSION'] = vimhook.vimserver
212 env['IPY_SERVER'] = vimhook.ipyserver
213
214 if line is None: line = ''
215 else: line = '+' + line
216 vim_cmd = 'gvim --servername %s %s %s %s' % (vimhook.vimserver, vimargs,
217 line, fname)
218 subprocess.call(vim_cmd, env=env, shell=True)
219
220
221 #default values to keep it sane...
222 vimhook.vimserver = ''
223 vimhook.ipyserver = ''
224
225 ip.set_hook('editor',vimhook)
226
227 # this is set up so more vim specific commands can be added, instead of just
228 # the current -t. all thats required is a compiled regex, a call to do_arg(pat)
229 # and the logic to deal with the new feature
230 newtab = re.compile(r'-t(?:\s|$)')
231 def vim(self, argstr):
232 def do_arg(pat, rarg):
233 x = len(pat.findall(argstr))
234 if x:
235 a = pat.sub('',argstr)
236 return rarg, a
237 else: return '', argstr
238
239 t, argstr = do_arg(newtab, '-tab')
240 vimhook.extras = t
241 argstr = 'edit -x ' + argstr
242 ip.magic(argstr)
243
244 ip.define_magic('vim', vim)
245
@@ -1,11 +0,0 b''
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 """wxIPython -- An enhanced Interactive Python GUI fonrtend
4 This script starts the Wx graphical frontend.
5 This is experimental so far.
6 Currently it support only ipython0 instance. Will be upgraded to ipython1 one.
7 """
8
9 from IPython.gui.wx import wxIPython
10
11 wxIPython.main()
@@ -1,11 +0,0 b''
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 """IPythonX -- An enhanced Interactive Python
4
5 This script starts the Wx graphical frontend. This is experimental so
6 far.
7 """
8
9 from IPython.frontend.wx import ipythonx
10
11 ipythonx.main()
@@ -1,43 +0,0 b''
1 # -*- coding: utf-8 -*-
2 """
3 Extension for printing Numeric Arrays in flexible ways.
4 """
5
6 from Numeric import ArrayType
7
8 def num_display(self,arg):
9 """Display method for printing which treats Numeric arrays specially.
10 """
11
12 # Non-numpy variables are printed using the system default
13 if type(arg) != ArrayType:
14 self._display(arg)
15 return
16 # Otherwise, we do work.
17 format = __IPYTHON__.runtime_rc.numarray_print_format
18 print 'NumPy array, format:',format
19 # Here is where all the printing logic needs to be implemented
20 print arg # nothing yet :)
21
22
23 def magic_format(self,parameter_s=''):
24 """Specifies format of numerical output.
25
26 This command is similar to Ocave's format command.
27 """
28
29 valid_formats = ['long','short']
30
31 if parameter_s in valid_formats:
32 self.runtime_rc.numarray_print_format = parameter_s
33 print 'Numeric output format is now:',parameter_s
34 else:
35 print 'Invalid format:',parameter_s
36 print 'Valid formats:',valid_formats
37
38 # setup default format
39 __IPYTHON__.runtime_rc.numarray_print_format = 'long'
40
41 # Bind our new functions to the interpreter
42 __IPYTHON__.__class__.magic_format = magic_format
43 __IPYTHON__.hooks.display = num_display
@@ -1,302 +0,0 b''
1 # -*- coding: utf-8 -*-
2 """
3 A set of convenient utilities for numerical work.
4
5 Most of this module requires Numerical Python or is meant to be used with it.
6 See http://www.pfdubois.com/numpy for details.
7 """
8
9 #*****************************************************************************
10 # Copyright (C) 2001-2005 Fernando Perez <fperez@colorado.edu>
11 #
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
14 #*****************************************************************************
15
16 __all__ = ['sum_flat','mean_flat','rms_flat','base_repr','binary_repr',
17 'amin','amax','amap','zeros_like','empty_like',
18 'frange','diagonal_matrix','identity',
19 'fromfunction_kw','log2','ispower2',
20 'norm','l1norm','l2norm','exp_safe',
21 'inf','infty','Infinity',
22 'Numeric']
23
24 #****************************************************************************
25 # required modules
26 import __main__
27 import math
28 import operator
29 import sys
30
31 import Numeric
32 from Numeric import *
33
34 #*****************************************************************************
35 # Globals
36
37 # useful for testing infinities in results of array divisions (which don't
38 # raise an exception)
39 # Python, LaTeX and Mathematica names.
40 inf = infty = Infinity = (array([1])/0.0)[0]
41
42 #****************************************************************************
43 # function definitions
44 exp_safe_MIN = math.log(2.2250738585072014e-308)
45 exp_safe_MAX = 1.7976931348623157e+308
46
47 def exp_safe(x):
48 """Compute exponentials which safely underflow to zero.
49
50 Slow but convenient to use. Note that NumArray will introduce proper
51 floating point exception handling with access to the underlying
52 hardware."""
53
54 if type(x) is ArrayType:
55 return exp(clip(x,exp_safe_MIN,exp_safe_MAX))
56 else:
57 return math.exp(x)
58
59 def amap(fn,*args):
60 """amap(function, sequence[, sequence, ...]) -> array.
61
62 Works like map(), but it returns an array. This is just a convenient
63 shorthand for Numeric.array(map(...))"""
64 return array(map(fn,*args))
65
66 def amin(m,axis=0):
67 """amin(m,axis=0) returns the minimum of m along dimension axis.
68 """
69 return minimum.reduce(asarray(m),axis)
70
71 def amax(m,axis=0):
72 """amax(m,axis=0) returns the maximum of m along dimension axis.
73 """
74 return maximum.reduce(asarray(m),axis)
75
76 def zeros_like(a):
77 """Return an array of zeros of the shape and typecode of a.
78
79 If you don't explicitly need the array to be zeroed, you should instead
80 use empty_like(), which is faster as it only allocates memory."""
81
82 return zeros(a.shape,a.typecode())
83
84 def empty_like(a):
85 """Return an empty (uninitialized) array of the shape and typecode of a.
86
87 Note that this does NOT initialize the returned array. If you require
88 your array to be initialized, you should use zeros_like().
89
90 This requires Numeric.empty(), which appeared in Numeric 23.7."""
91
92 return empty(a.shape,a.typecode())
93
94 def sum_flat(a):
95 """Return the sum of all the elements of a, flattened out.
96
97 It uses a.flat, and if a is not contiguous, a call to ravel(a) is made."""
98
99 if a.iscontiguous():
100 return Numeric.sum(a.flat)
101 else:
102 return Numeric.sum(ravel(a))
103
104 def mean_flat(a):
105 """Return the mean of all the elements of a, flattened out."""
106
107 return sum_flat(a)/float(size(a))
108
109 def rms_flat(a):
110 """Return the root mean square of all the elements of a, flattened out."""
111
112 return math.sqrt(sum_flat(absolute(a)**2)/float(size(a)))
113
114 def l1norm(a):
115 """Return the l1 norm of a, flattened out.
116
117 Implemented as a separate function (not a call to norm() for speed).
118
119 Ref: http://mathworld.wolfram.com/L1-Norm.html"""
120
121 return sum_flat(absolute(a))
122
123 def l2norm(a):
124 """Return the l2 norm of a, flattened out.
125
126 Implemented as a separate function (not a call to norm() for speed).
127
128 Ref: http://mathworld.wolfram.com/L2-Norm.html"""
129
130 return math.sqrt(sum_flat(absolute(a)**2))
131
132 def norm(a,p=2):
133 """norm(a,p=2) -> l-p norm of a.flat
134
135 Return the l-p norm of a, considered as a flat array. This is NOT a true
136 matrix norm, since arrays of arbitrary rank are always flattened.
137
138 p can be a number or one of the strings ('inf','Infinity') to get the
139 L-infinity norm.
140
141 Ref: http://mathworld.wolfram.com/VectorNorm.html
142 http://mathworld.wolfram.com/L-Infinity-Norm.html"""
143
144 if p in ('inf','Infinity'):
145 return max(absolute(a).flat)
146 else:
147 return (sum_flat(absolute(a)**p))**(1.0/p)
148
149 def frange(xini,xfin=None,delta=None,**kw):
150 """frange([start,] stop[, step, keywords]) -> array of floats
151
152 Return a Numeric array() containing a progression of floats. Similar to
153 arange(), but defaults to a closed interval.
154
155 frange(x0, x1) returns [x0, x0+1, x0+2, ..., x1]; start defaults to 0, and
156 the endpoint *is included*. This behavior is different from that of
157 range() and arange(). This is deliberate, since frange will probably be
158 more useful for generating lists of points for function evaluation, and
159 endpoints are often desired in this use. The usual behavior of range() can
160 be obtained by setting the keyword 'closed=0', in this case frange()
161 basically becomes arange().
162
163 When step is given, it specifies the increment (or decrement). All
164 arguments can be floating point numbers.
165
166 frange(x0,x1,d) returns [x0,x0+d,x0+2d,...,xfin] where xfin<=x1.
167
168 frange can also be called with the keyword 'npts'. This sets the number of
169 points the list should contain (and overrides the value 'step' might have
170 been given). arange() doesn't offer this option.
171
172 Examples:
173 >>> frange(3)
174 array([ 0., 1., 2., 3.])
175 >>> frange(3,closed=0)
176 array([ 0., 1., 2.])
177 >>> frange(1,6,2)
178 array([1, 3, 5])
179 >>> frange(1,6.5,npts=5)
180 array([ 1. , 2.375, 3.75 , 5.125, 6.5 ])
181 """
182
183 #defaults
184 kw.setdefault('closed',1)
185 endpoint = kw['closed'] != 0
186
187 # funny logic to allow the *first* argument to be optional (like range())
188 # This was modified with a simpler version from a similar frange() found
189 # at http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66472
190 if xfin == None:
191 xfin = xini + 0.0
192 xini = 0.0
193
194 if delta == None:
195 delta = 1.0
196
197 # compute # of points, spacing and return final list
198 try:
199 npts=kw['npts']
200 delta=(xfin-xini)/float(npts-endpoint)
201 except KeyError:
202 # round() gets npts right even with the vagaries of floating point.
203 npts=int(round((xfin-xini)/delta+endpoint))
204
205 return arange(npts)*delta+xini
206
207 def diagonal_matrix(diag):
208 """Return square diagonal matrix whose non-zero elements are given by the
209 input array."""
210
211 return diag*identity(len(diag))
212
213 def identity(n,rank=2,typecode='l'):
214 """identity(n,r) returns the identity matrix of shape (n,n,...,n) (rank r).
215
216 For ranks higher than 2, this object is simply a multi-index Kronecker
217 delta:
218 / 1 if i0=i1=...=iR,
219 id[i0,i1,...,iR] = -|
220 \ 0 otherwise.
221
222 Optionally a typecode may be given (it defaults to 'l').
223
224 Since rank defaults to 2, this function behaves in the default case (when
225 only n is given) like the Numeric identity function."""
226
227 iden = zeros((n,)*rank,typecode=typecode)
228 for i in range(n):
229 idx = (i,)*rank
230 iden[idx] = 1
231 return iden
232
233 def base_repr (number, base = 2, padding = 0):
234 """Return the representation of a number in any given base."""
235 chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
236 if number < base: \
237 return (padding - 1) * chars [0] + chars [int (number)]
238 max_exponent = int (math.log (number)/math.log (base))
239 max_power = long (base) ** max_exponent
240 lead_digit = int (number/max_power)
241 return chars [lead_digit] + \
242 base_repr (number - max_power * lead_digit, base, \
243 max (padding - 1, max_exponent))
244
245 def binary_repr(number, max_length = 1025):
246 """Return the binary representation of the input number as a string.
247
248 This is more efficient than using base_repr with base 2.
249
250 Increase the value of max_length for very large numbers. Note that on
251 32-bit machines, 2**1023 is the largest integer power of 2 which can be
252 converted to a Python float."""
253
254 assert number < 2L << max_length
255 shifts = map (operator.rshift, max_length * [number], \
256 range (max_length - 1, -1, -1))
257 digits = map (operator.mod, shifts, max_length * [2])
258 if not digits.count (1): return 0
259 digits = digits [digits.index (1):]
260 return ''.join (map (repr, digits)).replace('L','')
261
262 def log2(x,ln2 = math.log(2.0)):
263 """Return the log(x) in base 2.
264
265 This is a _slow_ function but which is guaranteed to return the correct
266 integer value if the input is an ineger exact power of 2."""
267
268 try:
269 bin_n = binary_repr(x)[1:]
270 except (AssertionError,TypeError):
271 return math.log(x)/ln2
272 else:
273 if '1' in bin_n:
274 return math.log(x)/ln2
275 else:
276 return len(bin_n)
277
278 def ispower2(n):
279 """Returns the log base 2 of n if n is a power of 2, zero otherwise.
280
281 Note the potential ambiguity if n==1: 2**0==1, interpret accordingly."""
282
283 bin_n = binary_repr(n)[1:]
284 if '1' in bin_n:
285 return 0
286 else:
287 return len(bin_n)
288
289 def fromfunction_kw(function, dimensions, **kwargs):
290 """Drop-in replacement for fromfunction() from Numerical Python.
291
292 Allows passing keyword arguments to the desired function.
293
294 Call it as (keywords are optional):
295 fromfunction_kw(MyFunction, dimensions, keywords)
296
297 The function MyFunction() is responsible for handling the dictionary of
298 keywords it will recieve."""
299
300 return function(tuple(indices(dimensions)),**kwargs)
301
302 #**************************** end file <numutils.py> ************************
@@ -1,82 +0,0 b''
1 """
2 Base front end class for all async frontends.
3 """
4 __docformat__ = "restructuredtext en"
5
6 # Tell nose to skip this module
7 __test__ = {}
8
9 #-------------------------------------------------------------------------------
10 # Copyright (C) 2008-2011 The IPython Development Team
11 #
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
14 #-------------------------------------------------------------------------------
15
16 #-------------------------------------------------------------------------------
17 # Imports
18 #-------------------------------------------------------------------------------
19
20 # Third-party
21 from twisted.python.failure import Failure
22 from zope.interface import implements, classProvides
23
24 # From IPython
25 from IPython.frontend.frontendbase import (FrontEndBase, IFrontEnd,
26 IFrontEndFactory)
27 from IPython.kernel.core.history import FrontEndHistory
28 from IPython.kernel.engineservice import IEngineCore
29
30 import uuid
31
32 #-----------------------------------------------------------------------------
33 # Classes and functions
34 #-----------------------------------------------------------------------------
35
36 class AsyncFrontEndBase(FrontEndBase):
37 """
38 Overrides FrontEndBase to wrap execute in a deferred result.
39 All callbacks are made as callbacks on the deferred result.
40 """
41
42 implements(IFrontEnd)
43 classProvides(IFrontEndFactory)
44
45 def __init__(self, engine=None, history=None):
46 assert(engine==None or IEngineCore.providedBy(engine))
47 self.engine = IEngineCore(engine)
48 if history is None:
49 self.history = FrontEndHistory(input_cache=[''])
50 else:
51 self.history = history
52
53 def execute(self, block, blockID=None):
54 """Execute the block and return the deferred result.
55
56 Parameters:
57 block : {str, AST}
58 blockID : any
59 Caller may provide an ID to identify this block.
60 result['blockID'] := blockID
61
62 Result:
63 Deferred result of self.interpreter.execute
64 """
65
66 if(not self.is_complete(block)):
67 return Failure(Exception("Block is not compilable"))
68
69 if(blockID == None):
70 blockID = uuid.uuid4()
71
72 d = self.engine.execute(block)
73 d.addCallback(self._add_history, block=block)
74 d.addCallbacks(self._add_block_id_for_result,
75 errback=self._add_block_id_for_failure,
76 callbackArgs=(blockID,),
77 errbackArgs=(blockID,))
78 d.addBoth(self.update_cell_prompt, blockID=blockID)
79 d.addCallbacks(self.render_result,
80 errback=self.render_error)
81
82 return d
This diff has been collapsed as it changes many lines, (560 lines changed) Show them Hide them
@@ -1,560 +0,0 b''
1 # encoding: utf-8
2 # -*- test-case-name: IPython.frontend.cocoa.tests.test_cocoa_frontend -*-
3
4 """PyObjC classes to provide a Cocoa frontend to the
5 IPython.kernel.engineservice.IEngineBase.
6
7 To add an IPython interpreter to a cocoa app, instantiate an
8 IPythonCocoaController in a XIB and connect its textView outlet to an
9 NSTextView instance in your UI. That's it.
10
11 Author: Barry Wark
12 """
13
14 __docformat__ = "restructuredtext en"
15
16 #-----------------------------------------------------------------------------
17 # Copyright (C) 2008-2011 The IPython Development Team
18 #
19 # Distributed under the terms of the BSD License. The full license is in
20 # the file COPYING, distributed as part of this software.
21 #-----------------------------------------------------------------------------
22
23 #-----------------------------------------------------------------------------
24 # Imports
25 #-----------------------------------------------------------------------------
26
27 import sys
28 import objc
29 import uuid
30
31 from Foundation import NSObject, NSMutableArray, NSMutableDictionary,\
32 NSLog, NSNotificationCenter, NSMakeRange,\
33 NSLocalizedString, NSIntersectionRange,\
34 NSString, NSAutoreleasePool
35
36 from AppKit import NSApplicationWillTerminateNotification, NSBeep,\
37 NSTextView, NSRulerView, NSVerticalRuler
38
39 from pprint import saferepr
40
41 import IPython
42 from IPython.kernel.engineservice import ThreadedEngineService
43 from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase
44
45 from twisted.internet.threads import blockingCallFromThread
46 from twisted.python.failure import Failure
47
48 #-----------------------------------------------------------------------------
49 # Classes to implement the Cocoa frontend
50 #-----------------------------------------------------------------------------
51
52 # TODO:
53 # 1. use MultiEngineClient and out-of-process engine rather than
54 # ThreadedEngineService?
55 # 2. integrate Xgrid launching of engines
56
57 class AutoreleasePoolWrappedThreadedEngineService(ThreadedEngineService):
58 """Wrap all blocks in an NSAutoreleasePool"""
59
60 def wrapped_execute(self, msg, lines):
61 """wrapped_execute"""
62 try:
63 p = NSAutoreleasePool.alloc().init()
64 result = super(AutoreleasePoolWrappedThreadedEngineService,
65 self).wrapped_execute(msg, lines)
66 finally:
67 p.drain()
68
69 return result
70
71
72
73 class Cell(NSObject):
74 """
75 Representation of the prompts, input and output of a cell in the
76 frontend
77 """
78
79 blockNumber = objc.ivar().unsigned_long()
80 blockID = objc.ivar()
81 inputBlock = objc.ivar()
82 output = objc.ivar()
83
84
85
86 class CellBlock(object):
87 """
88 Storage for information about text ranges relating to a single cell
89 """
90
91
92 def __init__(self, inputPromptRange, inputRange=None, outputPromptRange=None,
93 outputRange=None):
94 super(CellBlock, self).__init__()
95 self.inputPromptRange = inputPromptRange
96 self.inputRange = inputRange
97 self.outputPromptRange = outputPromptRange
98 self.outputRange = outputRange
99
100 def update_ranges_for_insertion(self, text, textRange):
101 """Update ranges for text insertion at textRange"""
102
103 for r in [self.inputPromptRange,self.inputRange,
104 self.outputPromptRange, self.outputRange]:
105 if(r == None):
106 continue
107 intersection = NSIntersectionRange(r,textRange)
108 if(intersection.length == 0): #ranges don't intersect
109 if r.location >= textRange.location:
110 r.location += len(text)
111 else: #ranges intersect
112 if(r.location > textRange.location):
113 offset = len(text) - intersection.length
114 r.length -= offset
115 r.location += offset
116 elif(r.location == textRange.location):
117 r.length += len(text) - intersection.length
118 else:
119 r.length -= intersection.length
120
121
122 def update_ranges_for_deletion(self, textRange):
123 """Update ranges for text deletion at textRange"""
124
125 for r in [self.inputPromptRange,self.inputRange,
126 self.outputPromptRange, self.outputRange]:
127 if(r==None):
128 continue
129 intersection = NSIntersectionRange(r, textRange)
130 if(intersection.length == 0): #ranges don't intersect
131 if r.location >= textRange.location:
132 r.location -= textRange.length
133 else: #ranges intersect
134 if(r.location > textRange.location):
135 offset = intersection.length
136 r.length -= offset
137 r.location += offset
138 elif(r.location == textRange.location):
139 r.length += intersection.length
140 else:
141 r.length -= intersection.length
142
143 def __repr__(self):
144 return 'CellBlock('+ str((self.inputPromptRange,
145 self.inputRange,
146 self.outputPromptRange,
147 self.outputRange)) + ')'
148
149
150
151
152 class IPythonCocoaController(NSObject, AsyncFrontEndBase):
153 userNS = objc.ivar() #mirror of engine.user_ns (key=>str(value))
154 waitingForEngine = objc.ivar().bool()
155 textView = objc.IBOutlet()
156
157 def init(self):
158 self = super(IPythonCocoaController, self).init()
159 AsyncFrontEndBase.__init__(self,
160 engine=AutoreleasePoolWrappedThreadedEngineService())
161 if(self != None):
162 self._common_init()
163
164 return self
165
166 def _common_init(self):
167 """_common_init"""
168
169 self.userNS = NSMutableDictionary.dictionary()
170 self.waitingForEngine = False
171
172 self.lines = {}
173 self.tabSpaces = 4
174 self.tabUsesSpaces = True
175 self.currentBlockID = self.next_block_ID()
176 self.blockRanges = {} # blockID=>CellBlock
177
178
179 def awakeFromNib(self):
180 """awakeFromNib"""
181
182 self._common_init()
183
184 # Start the IPython engine
185 self.engine.startService()
186 NSLog('IPython engine started')
187
188 # Register for app termination
189 nc = NSNotificationCenter.defaultCenter()
190 nc.addObserver_selector_name_object_(
191 self,
192 'appWillTerminate:',
193 NSApplicationWillTerminateNotification,
194 None)
195
196 self.textView.setDelegate_(self)
197 self.textView.enclosingScrollView().setHasVerticalRuler_(True)
198 r = NSRulerView.alloc().initWithScrollView_orientation_(
199 self.textView.enclosingScrollView(),
200 NSVerticalRuler)
201 self.verticalRulerView = r
202 self.verticalRulerView.setClientView_(self.textView)
203 self._start_cli_banner()
204 self.start_new_block()
205
206
207 def appWillTerminate_(self, notification):
208 """appWillTerminate"""
209
210 self.engine.stopService()
211
212
213 def complete(self, token):
214 """Complete token in engine's user_ns
215
216 Parameters
217 ----------
218 token : string
219
220 Result
221 ------
222 Deferred result of
223 IPython.kernel.engineservice.IEngineBase.complete
224 """
225
226 return self.engine.complete(token)
227
228
229 def execute(self, block, blockID=None):
230 self.waitingForEngine = True
231 self.willChangeValueForKey_('commandHistory')
232 d = super(IPythonCocoaController, self).execute(block,
233 blockID)
234 d.addBoth(self._engine_done)
235 d.addCallback(self._update_user_ns)
236
237 return d
238
239
240 def push_(self, namespace):
241 """Push dictionary of key=>values to python namespace"""
242
243 self.waitingForEngine = True
244 self.willChangeValueForKey_('commandHistory')
245 d = self.engine.push(namespace)
246 d.addBoth(self._engine_done)
247 d.addCallback(self._update_user_ns)
248
249
250 def pull_(self, keys):
251 """Pull keys from python namespace"""
252
253 self.waitingForEngine = True
254 result = blockingCallFromThread(self.engine.pull, keys)
255 self.waitingForEngine = False
256
257 @objc.signature('v@:@I')
258 def executeFileAtPath_encoding_(self, path, encoding):
259 """Execute file at path in an empty namespace. Update the engine
260 user_ns with the resulting locals."""
261
262 lines,err = NSString.stringWithContentsOfFile_encoding_error_(
263 path,
264 encoding,
265 None)
266 self.engine.execute(lines)
267
268
269 def _engine_done(self, x):
270 self.waitingForEngine = False
271 self.didChangeValueForKey_('commandHistory')
272 return x
273
274 def _update_user_ns(self, result):
275 """Update self.userNS from self.engine's namespace"""
276 d = self.engine.keys()
277 d.addCallback(self._get_engine_namespace_values_for_keys)
278
279 return result
280
281
282 def _get_engine_namespace_values_for_keys(self, keys):
283 d = self.engine.pull(keys)
284 d.addCallback(self._store_engine_namespace_values, keys=keys)
285
286
287 def _store_engine_namespace_values(self, values, keys=[]):
288 assert(len(values) == len(keys))
289 self.willChangeValueForKey_('userNS')
290 for (k,v) in zip(keys,values):
291 self.userNS[k] = saferepr(v)
292 self.didChangeValueForKey_('userNS')
293
294
295 def update_cell_prompt(self, result, blockID=None):
296 print self.blockRanges
297 if(isinstance(result, Failure)):
298 prompt = self.input_prompt()
299
300 else:
301 prompt = self.input_prompt(number=result['number'])
302
303 r = self.blockRanges[blockID].inputPromptRange
304 self.insert_text(prompt,
305 textRange=r,
306 scrollToVisible=False
307 )
308
309 return result
310
311
312 def render_result(self, result):
313 blockID = result['blockID']
314 inputRange = self.blockRanges[blockID].inputRange
315 del self.blockRanges[blockID]
316
317 #print inputRange,self.current_block_range()
318 self.insert_text('\n' +
319 self.output_prompt(number=result['number']) +
320 result.get('display',{}).get('pprint','') +
321 '\n\n',
322 textRange=NSMakeRange(inputRange.location+inputRange.length,
323 0))
324 return result
325
326
327 def render_error(self, failure):
328 print failure
329 blockID = failure.blockID
330 inputRange = self.blockRanges[blockID].inputRange
331 self.insert_text('\n' +
332 self.output_prompt() +
333 '\n' +
334 failure.getErrorMessage() +
335 '\n\n',
336 textRange=NSMakeRange(inputRange.location +
337 inputRange.length,
338 0))
339 self.start_new_block()
340 return failure
341
342
343 def _start_cli_banner(self):
344 """Print banner"""
345
346 banner = """IPython1 %s -- An enhanced Interactive Python.""" % \
347 IPython.__version__
348
349 self.insert_text(banner + '\n\n')
350
351
352 def start_new_block(self):
353 """"""
354
355 self.currentBlockID = self.next_block_ID()
356 self.blockRanges[self.currentBlockID] = self.new_cell_block()
357 self.insert_text(self.input_prompt(),
358 textRange=self.current_block_range().inputPromptRange)
359
360
361
362 def next_block_ID(self):
363
364 return uuid.uuid4()
365
366 def new_cell_block(self):
367 """A new CellBlock at the end of self.textView.textStorage()"""
368
369 return CellBlock(NSMakeRange(self.textView.textStorage().length(),
370 0), #len(self.input_prompt())),
371 NSMakeRange(self.textView.textStorage().length(),# + len(self.input_prompt()),
372 0))
373
374
375 def current_block_range(self):
376 return self.blockRanges.get(self.currentBlockID,
377 self.new_cell_block())
378
379 def current_block(self):
380 """The current block's text"""
381
382 return self.text_for_range(self.current_block_range().inputRange)
383
384 def text_for_range(self, textRange):
385 """text_for_range"""
386
387 ts = self.textView.textStorage()
388 return ts.string().substringWithRange_(textRange)
389
390 def current_line(self):
391 block = self.text_for_range(self.current_block_range().inputRange)
392 block = block.split('\n')
393 return block[-1]
394
395
396 def insert_text(self, string=None, textRange=None, scrollToVisible=True):
397 """Insert text into textView at textRange, updating blockRanges
398 as necessary
399 """
400 if(textRange == None):
401 #range for end of text
402 textRange = NSMakeRange(self.textView.textStorage().length(), 0)
403
404
405 self.textView.replaceCharactersInRange_withString_(
406 textRange, string)
407
408 for r in self.blockRanges.itervalues():
409 r.update_ranges_for_insertion(string, textRange)
410
411 self.textView.setSelectedRange_(textRange)
412 if(scrollToVisible):
413 self.textView.scrollRangeToVisible_(textRange)
414
415
416
417 def replace_current_block_with_string(self, textView, string):
418 textView.replaceCharactersInRange_withString_(
419 self.current_block_range().inputRange,
420 string)
421 self.current_block_range().inputRange.length = len(string)
422 r = NSMakeRange(textView.textStorage().length(), 0)
423 textView.scrollRangeToVisible_(r)
424 textView.setSelectedRange_(r)
425
426
427 def current_indent_string(self):
428 """returns string for indent or None if no indent"""
429
430 return self._indent_for_block(self.current_block())
431
432
433 def _indent_for_block(self, block):
434 lines = block.split('\n')
435 if(len(lines) > 1):
436 currentIndent = len(lines[-1]) - len(lines[-1].lstrip())
437 if(currentIndent == 0):
438 currentIndent = self.tabSpaces
439
440 if(self.tabUsesSpaces):
441 result = ' ' * currentIndent
442 else:
443 result = '\t' * (currentIndent/self.tabSpaces)
444 else:
445 result = None
446
447 return result
448
449
450 # NSTextView delegate methods...
451 def textView_doCommandBySelector_(self, textView, selector):
452 assert(textView == self.textView)
453 NSLog("textView_doCommandBySelector_: "+selector)
454
455
456 if(selector == 'insertNewline:'):
457 indent = self.current_indent_string()
458 if(indent):
459 line = indent + self.current_line()
460 else:
461 line = self.current_line()
462
463 if(self.is_complete(self.current_block())):
464 self.execute(self.current_block(),
465 blockID=self.currentBlockID)
466 self.start_new_block()
467
468 return True
469
470 return False
471
472 elif(selector == 'moveUp:'):
473 prevBlock = self.get_history_previous(self.current_block())
474 if(prevBlock != None):
475 self.replace_current_block_with_string(textView, prevBlock)
476 else:
477 NSBeep()
478 return True
479
480 elif(selector == 'moveDown:'):
481 nextBlock = self.get_history_next()
482 if(nextBlock != None):
483 self.replace_current_block_with_string(textView, nextBlock)
484 else:
485 NSBeep()
486 return True
487
488 elif(selector == 'moveToBeginningOfParagraph:'):
489 textView.setSelectedRange_(NSMakeRange(
490 self.current_block_range().inputRange.location,
491 0))
492 return True
493 elif(selector == 'moveToEndOfParagraph:'):
494 textView.setSelectedRange_(NSMakeRange(
495 self.current_block_range().inputRange.location + \
496 self.current_block_range().inputRange.length, 0))
497 return True
498 elif(selector == 'deleteToEndOfParagraph:'):
499 if(textView.selectedRange().location <= \
500 self.current_block_range().location):
501 raise NotImplemented()
502
503 return False # don't actually handle the delete
504
505 elif(selector == 'insertTab:'):
506 if(len(self.current_line().strip()) == 0): #only white space
507 return False
508 else:
509 self.textView.complete_(self)
510 return True
511
512 elif(selector == 'deleteBackward:'):
513 #if we're at the beginning of the current block, ignore
514 if(textView.selectedRange().location == \
515 self.current_block_range().inputRange.location):
516 return True
517 else:
518 for r in self.blockRanges.itervalues():
519 deleteRange = textView.selectedRange
520 if(deleteRange.length == 0):
521 deleteRange.location -= 1
522 deleteRange.length = 1
523 r.update_ranges_for_deletion(deleteRange)
524 return False
525 return False
526
527
528 def textView_shouldChangeTextInRanges_replacementStrings_(self,
529 textView, ranges, replacementStrings):
530 """
531 Delegate method for NSTextView.
532
533 Refuse change text in ranges not at end, but make those changes at
534 end.
535 """
536
537 assert(len(ranges) == len(replacementStrings))
538 allow = True
539 for r,s in zip(ranges, replacementStrings):
540 r = r.rangeValue()
541 if(textView.textStorage().length() > 0 and
542 r.location < self.current_block_range().inputRange.location):
543 self.insert_text(s)
544 allow = False
545
546 return allow
547
548 def textView_completions_forPartialWordRange_indexOfSelectedItem_(self,
549 textView, words, charRange, index):
550 try:
551 ts = textView.textStorage()
552 token = ts.string().substringWithRange_(charRange)
553 completions = blockingCallFromThread(self.complete, token)
554 except:
555 completions = objc.nil
556 NSBeep()
557
558 return (completions,0)
559
560
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
This diff has been collapsed as it changes many lines, (3424 lines changed) Show them Hide them
@@ -1,3424 +0,0 b''
1 <?xml version="1.0" encoding="UTF-8"?>
2 <archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.01">
3 <data>
4 <int key="IBDocument.SystemTarget">1050</int>
5 <string key="IBDocument.SystemVersion">9D34</string>
6 <string key="IBDocument.InterfaceBuilderVersion">629</string>
7 <string key="IBDocument.AppKitVersion">949.33</string>
8 <string key="IBDocument.HIToolboxVersion">352.00</string>
9 <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
10 <bool key="EncodedWithXMLCoder">YES</bool>
11 <integer value="416"/>
12 <integer value="29"/>
13 </object>
14 <object class="NSArray" key="IBDocument.PluginDependencies">
15 <bool key="EncodedWithXMLCoder">YES</bool>
16 <string id="885801228">com.apple.InterfaceBuilderKit</string>
17 <string id="113577022">com.apple.InterfaceBuilder.CocoaPlugin</string>
18 </object>
19 <object class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
20 <bool key="EncodedWithXMLCoder">YES</bool>
21 <object class="NSCustomObject" id="1021">
22 <string key="NSClassName" id="190635311">NSApplication</string>
23 </object>
24 <object class="NSCustomObject" id="1014">
25 <string key="NSClassName">FirstResponder</string>
26 </object>
27 <object class="NSCustomObject" id="1050">
28 <reference key="NSClassName" ref="190635311"/>
29 </object>
30 <object class="NSMenu" id="649796088">
31 <string key="NSTitle">AMainMenu</string>
32 <object class="NSMutableArray" key="NSMenuItems">
33 <bool key="EncodedWithXMLCoder">YES</bool>
34 <object class="NSMenuItem" id="694149608">
35 <reference key="NSMenu" ref="649796088"/>
36 <string key="NSTitle" id="837240250">IPython1Sandbox</string>
37 <string key="NSKeyEquiv" id="255189770"/>
38 <int key="NSKeyEquivModMask">1048576</int>
39 <int key="NSMnemonicLoc">2147483647</int>
40 <object class="NSCustomResource" key="NSOnImage" id="271266416">
41 <string key="NSClassName" id="375865337">NSImage</string>
42 <string key="NSResourceName">NSMenuCheckmark</string>
43 </object>
44 <object class="NSCustomResource" key="NSMixedImage" id="508123839">
45 <reference key="NSClassName" ref="375865337"/>
46 <string key="NSResourceName">NSMenuMixedState</string>
47 </object>
48 <string key="NSAction">submenuAction:</string>
49 <object class="NSMenu" key="NSSubmenu" id="110575045">
50 <reference key="NSTitle" ref="837240250"/>
51 <object class="NSMutableArray" key="NSMenuItems">
52 <bool key="EncodedWithXMLCoder">YES</bool>
53 <object class="NSMenuItem" id="238522557">
54 <reference key="NSMenu" ref="110575045"/>
55 <string key="NSTitle">About IPython1Sandbox</string>
56 <reference key="NSKeyEquiv" ref="255189770"/>
57 <int key="NSMnemonicLoc">2147483647</int>
58 <reference key="NSOnImage" ref="271266416"/>
59 <reference key="NSMixedImage" ref="508123839"/>
60 </object>
61 <object class="NSMenuItem" id="304266470">
62 <reference key="NSMenu" ref="110575045"/>
63 <bool key="NSIsDisabled">YES</bool>
64 <bool key="NSIsSeparator">YES</bool>
65 <reference key="NSTitle" ref="255189770"/>
66 <reference key="NSKeyEquiv" ref="255189770"/>
67 <int key="NSKeyEquivModMask">1048576</int>
68 <int key="NSMnemonicLoc">2147483647</int>
69 <reference key="NSOnImage" ref="271266416"/>
70 <reference key="NSMixedImage" ref="508123839"/>
71 </object>
72 <object class="NSMenuItem" id="609285721">
73 <reference key="NSMenu" ref="110575045"/>
74 <string type="base64-UTF8" key="NSTitle">UHJlZmVyZW5jZXPigKY</string>
75 <string key="NSKeyEquiv">,</string>
76 <int key="NSKeyEquivModMask">1048576</int>
77 <int key="NSMnemonicLoc">2147483647</int>
78 <reference key="NSOnImage" ref="271266416"/>
79 <reference key="NSMixedImage" ref="508123839"/>
80 </object>
81 <object class="NSMenuItem" id="481834944">
82 <reference key="NSMenu" ref="110575045"/>
83 <bool key="NSIsDisabled">YES</bool>
84 <bool key="NSIsSeparator">YES</bool>
85 <reference key="NSTitle" ref="255189770"/>
86 <reference key="NSKeyEquiv" ref="255189770"/>
87 <int key="NSKeyEquivModMask">1048576</int>
88 <int key="NSMnemonicLoc">2147483647</int>
89 <reference key="NSOnImage" ref="271266416"/>
90 <reference key="NSMixedImage" ref="508123839"/>
91 </object>
92 <object class="NSMenuItem" id="1046388886">
93 <reference key="NSMenu" ref="110575045"/>
94 <string key="NSTitle" id="642338826">Services</string>
95 <reference key="NSKeyEquiv" ref="255189770"/>
96 <int key="NSKeyEquivModMask">1048576</int>
97 <int key="NSMnemonicLoc">2147483647</int>
98 <reference key="NSOnImage" ref="271266416"/>
99 <reference key="NSMixedImage" ref="508123839"/>
100 <string key="NSAction">submenuAction:</string>
101 <object class="NSMenu" key="NSSubmenu" id="752062318">
102 <reference key="NSTitle" ref="642338826"/>
103 <object class="NSMutableArray" key="NSMenuItems">
104 <bool key="EncodedWithXMLCoder">YES</bool>
105 </object>
106 <string key="NSName">_NSServicesMenu</string>
107 </object>
108 </object>
109 <object class="NSMenuItem" id="646227648">
110 <reference key="NSMenu" ref="110575045"/>
111 <bool key="NSIsDisabled">YES</bool>
112 <bool key="NSIsSeparator">YES</bool>
113 <reference key="NSTitle" ref="255189770"/>
114 <reference key="NSKeyEquiv" ref="255189770"/>
115 <int key="NSKeyEquivModMask">1048576</int>
116 <int key="NSMnemonicLoc">2147483647</int>
117 <reference key="NSOnImage" ref="271266416"/>
118 <reference key="NSMixedImage" ref="508123839"/>
119 </object>
120 <object class="NSMenuItem" id="755159360">
121 <reference key="NSMenu" ref="110575045"/>
122 <string key="NSTitle">Hide IPython1Sandbox</string>
123 <string key="NSKeyEquiv" id="940330891">h</string>
124 <int key="NSKeyEquivModMask">1048576</int>
125 <int key="NSMnemonicLoc">2147483647</int>
126 <reference key="NSOnImage" ref="271266416"/>
127 <reference key="NSMixedImage" ref="508123839"/>
128 </object>
129 <object class="NSMenuItem" id="342932134">
130 <reference key="NSMenu" ref="110575045"/>
131 <string key="NSTitle">Hide Others</string>
132 <reference key="NSKeyEquiv" ref="940330891"/>
133 <int key="NSKeyEquivModMask">1572864</int>
134 <int key="NSMnemonicLoc">2147483647</int>
135 <reference key="NSOnImage" ref="271266416"/>
136 <reference key="NSMixedImage" ref="508123839"/>
137 </object>
138 <object class="NSMenuItem" id="908899353">
139 <reference key="NSMenu" ref="110575045"/>
140 <string key="NSTitle">Show All</string>
141 <reference key="NSKeyEquiv" ref="255189770"/>
142 <int key="NSKeyEquivModMask">1048576</int>
143 <int key="NSMnemonicLoc">2147483647</int>
144 <reference key="NSOnImage" ref="271266416"/>
145 <reference key="NSMixedImage" ref="508123839"/>
146 </object>
147 <object class="NSMenuItem" id="1056857174">
148 <reference key="NSMenu" ref="110575045"/>
149 <bool key="NSIsDisabled">YES</bool>
150 <bool key="NSIsSeparator">YES</bool>
151 <reference key="NSTitle" ref="255189770"/>
152 <reference key="NSKeyEquiv" ref="255189770"/>
153 <int key="NSKeyEquivModMask">1048576</int>
154 <int key="NSMnemonicLoc">2147483647</int>
155 <reference key="NSOnImage" ref="271266416"/>
156 <reference key="NSMixedImage" ref="508123839"/>
157 </object>
158 <object class="NSMenuItem" id="632727374">
159 <reference key="NSMenu" ref="110575045"/>
160 <string key="NSTitle">Quit IPython1Sandbox</string>
161 <string key="NSKeyEquiv">q</string>
162 <int key="NSKeyEquivModMask">1048576</int>
163 <int key="NSMnemonicLoc">2147483647</int>
164 <reference key="NSOnImage" ref="271266416"/>
165 <reference key="NSMixedImage" ref="508123839"/>
166 </object>
167 </object>
168 <string key="NSName">_NSAppleMenu</string>
169 </object>
170 </object>
171 <object class="NSMenuItem" id="379814623">
172 <reference key="NSMenu" ref="649796088"/>
173 <string key="NSTitle" id="881404960">File</string>
174 <reference key="NSKeyEquiv" ref="255189770"/>
175 <int key="NSKeyEquivModMask">1048576</int>
176 <int key="NSMnemonicLoc">2147483647</int>
177 <reference key="NSOnImage" ref="271266416"/>
178 <reference key="NSMixedImage" ref="508123839"/>
179 <string key="NSAction">submenuAction:</string>
180 <object class="NSMenu" key="NSSubmenu" id="720053764">
181 <reference key="NSTitle" ref="881404960"/>
182 <object class="NSMutableArray" key="NSMenuItems">
183 <bool key="EncodedWithXMLCoder">YES</bool>
184 <object class="NSMenuItem" id="705341025">
185 <reference key="NSMenu" ref="720053764"/>
186 <string key="NSTitle">New</string>
187 <string key="NSKeyEquiv">n</string>
188 <int key="NSKeyEquivModMask">1048576</int>
189 <int key="NSMnemonicLoc">2147483647</int>
190 <reference key="NSOnImage" ref="271266416"/>
191 <reference key="NSMixedImage" ref="508123839"/>
192 </object>
193 <object class="NSMenuItem" id="722745758">
194 <reference key="NSMenu" ref="720053764"/>
195 <string type="base64-UTF8" key="NSTitle">T3BlbuKApg</string>
196 <string key="NSKeyEquiv">o</string>
197 <int key="NSKeyEquivModMask">1048576</int>
198 <int key="NSMnemonicLoc">2147483647</int>
199 <reference key="NSOnImage" ref="271266416"/>
200 <reference key="NSMixedImage" ref="508123839"/>
201 </object>
202 <object class="NSMenuItem" id="1025936716">
203 <reference key="NSMenu" ref="720053764"/>
204 <string key="NSTitle" id="975517829">Open Recent</string>
205 <reference key="NSKeyEquiv" ref="255189770"/>
206 <int key="NSKeyEquivModMask">1048576</int>
207 <int key="NSMnemonicLoc">2147483647</int>
208 <reference key="NSOnImage" ref="271266416"/>
209 <reference key="NSMixedImage" ref="508123839"/>
210 <string key="NSAction">submenuAction:</string>
211 <object class="NSMenu" key="NSSubmenu" id="1065607017">
212 <reference key="NSTitle" ref="975517829"/>
213 <object class="NSMutableArray" key="NSMenuItems">
214 <bool key="EncodedWithXMLCoder">YES</bool>
215 <object class="NSMenuItem" id="759406840">
216 <reference key="NSMenu" ref="1065607017"/>
217 <string key="NSTitle">Clear Menu</string>
218 <reference key="NSKeyEquiv" ref="255189770"/>
219 <int key="NSKeyEquivModMask">1048576</int>
220 <int key="NSMnemonicLoc">2147483647</int>
221 <reference key="NSOnImage" ref="271266416"/>
222 <reference key="NSMixedImage" ref="508123839"/>
223 </object>
224 </object>
225 <string key="NSName">_NSRecentDocumentsMenu</string>
226 </object>
227 </object>
228 <object class="NSMenuItem" id="425164168">
229 <reference key="NSMenu" ref="720053764"/>
230 <bool key="NSIsDisabled">YES</bool>
231 <bool key="NSIsSeparator">YES</bool>
232 <reference key="NSTitle" ref="255189770"/>
233 <reference key="NSKeyEquiv" ref="255189770"/>
234 <int key="NSKeyEquivModMask">1048576</int>
235 <int key="NSMnemonicLoc">2147483647</int>
236 <reference key="NSOnImage" ref="271266416"/>
237 <reference key="NSMixedImage" ref="508123839"/>
238 </object>
239 <object class="NSMenuItem" id="776162233">
240 <reference key="NSMenu" ref="720053764"/>
241 <string key="NSTitle">Close</string>
242 <string key="NSKeyEquiv">w</string>
243 <int key="NSKeyEquivModMask">1048576</int>
244 <int key="NSMnemonicLoc">2147483647</int>
245 <reference key="NSOnImage" ref="271266416"/>
246 <reference key="NSMixedImage" ref="508123839"/>
247 </object>
248 <object class="NSMenuItem" id="1023925487">
249 <reference key="NSMenu" ref="720053764"/>
250 <string key="NSTitle">Save</string>
251 <string key="NSKeyEquiv">s</string>
252 <int key="NSKeyEquivModMask">1048576</int>
253 <int key="NSMnemonicLoc">2147483647</int>
254 <reference key="NSOnImage" ref="271266416"/>
255 <reference key="NSMixedImage" ref="508123839"/>
256 </object>
257 <object class="NSMenuItem" id="117038363">
258 <reference key="NSMenu" ref="720053764"/>
259 <string type="base64-UTF8" key="NSTitle">U2F2ZSBBc+KApg</string>
260 <string key="NSKeyEquiv">S</string>
261 <int key="NSKeyEquivModMask">1179648</int>
262 <int key="NSMnemonicLoc">2147483647</int>
263 <reference key="NSOnImage" ref="271266416"/>
264 <reference key="NSMixedImage" ref="508123839"/>
265 </object>
266 <object class="NSMenuItem" id="579971712">
267 <reference key="NSMenu" ref="720053764"/>
268 <string key="NSTitle">Revert to Saved</string>
269 <reference key="NSKeyEquiv" ref="255189770"/>
270 <int key="NSMnemonicLoc">2147483647</int>
271 <reference key="NSOnImage" ref="271266416"/>
272 <reference key="NSMixedImage" ref="508123839"/>
273 </object>
274 <object class="NSMenuItem" id="1010469920">
275 <reference key="NSMenu" ref="720053764"/>
276 <bool key="NSIsDisabled">YES</bool>
277 <bool key="NSIsSeparator">YES</bool>
278 <reference key="NSTitle" ref="255189770"/>
279 <reference key="NSKeyEquiv" ref="255189770"/>
280 <int key="NSKeyEquivModMask">1048576</int>
281 <int key="NSMnemonicLoc">2147483647</int>
282 <reference key="NSOnImage" ref="271266416"/>
283 <reference key="NSMixedImage" ref="508123839"/>
284 </object>
285 <object class="NSMenuItem" id="294629803">
286 <reference key="NSMenu" ref="720053764"/>
287 <string key="NSTitle">Page Setup...</string>
288 <string key="NSKeyEquiv">P</string>
289 <int key="NSKeyEquivModMask">1179648</int>
290 <int key="NSMnemonicLoc">2147483647</int>
291 <reference key="NSOnImage" ref="271266416"/>
292 <reference key="NSMixedImage" ref="508123839"/>
293 <reference key="NSToolTip" ref="255189770"/>
294 </object>
295 <object class="NSMenuItem" id="49223823">
296 <reference key="NSMenu" ref="720053764"/>
297 <string type="base64-UTF8" key="NSTitle">UHJpbnTigKY</string>
298 <string key="NSKeyEquiv">p</string>
299 <int key="NSKeyEquivModMask">1048576</int>
300 <int key="NSMnemonicLoc">2147483647</int>
301 <reference key="NSOnImage" ref="271266416"/>
302 <reference key="NSMixedImage" ref="508123839"/>
303 </object>
304 </object>
305 </object>
306 </object>
307 <object class="NSMenuItem" id="952259628">
308 <reference key="NSMenu" ref="649796088"/>
309 <string key="NSTitle" id="1037326483">Edit</string>
310 <reference key="NSKeyEquiv" ref="255189770"/>
311 <int key="NSKeyEquivModMask">1048576</int>
312 <int key="NSMnemonicLoc">2147483647</int>
313 <reference key="NSOnImage" ref="271266416"/>
314 <reference key="NSMixedImage" ref="508123839"/>
315 <string key="NSAction">submenuAction:</string>
316 <object class="NSMenu" key="NSSubmenu" id="789758025">
317 <reference key="NSTitle" ref="1037326483"/>
318 <object class="NSMutableArray" key="NSMenuItems">
319 <bool key="EncodedWithXMLCoder">YES</bool>
320 <object class="NSMenuItem" id="1058277027">
321 <reference key="NSMenu" ref="789758025"/>
322 <string key="NSTitle">Undo</string>
323 <string key="NSKeyEquiv">z</string>
324 <int key="NSKeyEquivModMask">1048576</int>
325 <int key="NSMnemonicLoc">2147483647</int>
326 <reference key="NSOnImage" ref="271266416"/>
327 <reference key="NSMixedImage" ref="508123839"/>
328 </object>
329 <object class="NSMenuItem" id="790794224">
330 <reference key="NSMenu" ref="789758025"/>
331 <string key="NSTitle">Redo</string>
332 <string key="NSKeyEquiv">Z</string>
333 <int key="NSKeyEquivModMask">1179648</int>
334 <int key="NSMnemonicLoc">2147483647</int>
335 <reference key="NSOnImage" ref="271266416"/>
336 <reference key="NSMixedImage" ref="508123839"/>
337 </object>
338 <object class="NSMenuItem" id="1040322652">
339 <reference key="NSMenu" ref="789758025"/>
340 <bool key="NSIsDisabled">YES</bool>
341 <bool key="NSIsSeparator">YES</bool>
342 <reference key="NSTitle" ref="255189770"/>
343 <reference key="NSKeyEquiv" ref="255189770"/>
344 <int key="NSKeyEquivModMask">1048576</int>
345 <int key="NSMnemonicLoc">2147483647</int>
346 <reference key="NSOnImage" ref="271266416"/>
347 <reference key="NSMixedImage" ref="508123839"/>
348 </object>
349 <object class="NSMenuItem" id="296257095">
350 <reference key="NSMenu" ref="789758025"/>
351 <string key="NSTitle">Cut</string>
352 <string key="NSKeyEquiv">x</string>
353 <int key="NSKeyEquivModMask">1048576</int>
354 <int key="NSMnemonicLoc">2147483647</int>
355 <reference key="NSOnImage" ref="271266416"/>
356 <reference key="NSMixedImage" ref="508123839"/>
357 </object>
358 <object class="NSMenuItem" id="860595796">
359 <reference key="NSMenu" ref="789758025"/>
360 <string key="NSTitle">Copy</string>
361 <string key="NSKeyEquiv">c</string>
362 <int key="NSKeyEquivModMask">1048576</int>
363 <int key="NSMnemonicLoc">2147483647</int>
364 <reference key="NSOnImage" ref="271266416"/>
365 <reference key="NSMixedImage" ref="508123839"/>
366 </object>
367 <object class="NSMenuItem" id="29853731">
368 <reference key="NSMenu" ref="789758025"/>
369 <string key="NSTitle">Paste</string>
370 <string key="NSKeyEquiv">v</string>
371 <int key="NSKeyEquivModMask">1048576</int>
372 <int key="NSMnemonicLoc">2147483647</int>
373 <reference key="NSOnImage" ref="271266416"/>
374 <reference key="NSMixedImage" ref="508123839"/>
375 </object>
376 <object class="NSMenuItem" id="437104165">
377 <reference key="NSMenu" ref="789758025"/>
378 <string key="NSTitle">Delete</string>
379 <reference key="NSKeyEquiv" ref="255189770"/>
380 <int key="NSKeyEquivModMask">1048576</int>
381 <int key="NSMnemonicLoc">2147483647</int>
382 <reference key="NSOnImage" ref="271266416"/>
383 <reference key="NSMixedImage" ref="508123839"/>
384 </object>
385 <object class="NSMenuItem" id="583158037">
386 <reference key="NSMenu" ref="789758025"/>
387 <string key="NSTitle">Select All</string>
388 <string key="NSKeyEquiv">a</string>
389 <int key="NSKeyEquivModMask">1048576</int>
390 <int key="NSMnemonicLoc">2147483647</int>
391 <reference key="NSOnImage" ref="271266416"/>
392 <reference key="NSMixedImage" ref="508123839"/>
393 </object>
394 <object class="NSMenuItem" id="212016141">
395 <reference key="NSMenu" ref="789758025"/>
396 <bool key="NSIsDisabled">YES</bool>
397 <bool key="NSIsSeparator">YES</bool>
398 <reference key="NSTitle" ref="255189770"/>
399 <reference key="NSKeyEquiv" ref="255189770"/>
400 <int key="NSKeyEquivModMask">1048576</int>
401 <int key="NSMnemonicLoc">2147483647</int>
402 <reference key="NSOnImage" ref="271266416"/>
403 <reference key="NSMixedImage" ref="508123839"/>
404 </object>
405 <object class="NSMenuItem" id="892235320">
406 <reference key="NSMenu" ref="789758025"/>
407 <string key="NSTitle" id="688083180">Find</string>
408 <reference key="NSKeyEquiv" ref="255189770"/>
409 <int key="NSKeyEquivModMask">1048576</int>
410 <int key="NSMnemonicLoc">2147483647</int>
411 <reference key="NSOnImage" ref="271266416"/>
412 <reference key="NSMixedImage" ref="508123839"/>
413 <string key="NSAction">submenuAction:</string>
414 <object class="NSMenu" key="NSSubmenu" id="963351320">
415 <reference key="NSTitle" ref="688083180"/>
416 <object class="NSMutableArray" key="NSMenuItems">
417 <bool key="EncodedWithXMLCoder">YES</bool>
418 <object class="NSMenuItem" id="447796847">
419 <reference key="NSMenu" ref="963351320"/>
420 <string type="base64-UTF8" key="NSTitle">RmluZOKApg</string>
421 <string key="NSKeyEquiv" id="469505129">f</string>
422 <int key="NSKeyEquivModMask">1048576</int>
423 <int key="NSMnemonicLoc">2147483647</int>
424 <reference key="NSOnImage" ref="271266416"/>
425 <reference key="NSMixedImage" ref="508123839"/>
426 <int key="NSTag">1</int>
427 </object>
428 <object class="NSMenuItem" id="326711663">
429 <reference key="NSMenu" ref="963351320"/>
430 <string key="NSTitle">Find Next</string>
431 <string key="NSKeyEquiv" id="762398675">g</string>
432 <int key="NSKeyEquivModMask">1048576</int>
433 <int key="NSMnemonicLoc">2147483647</int>
434 <reference key="NSOnImage" ref="271266416"/>
435 <reference key="NSMixedImage" ref="508123839"/>
436 <int key="NSTag">2</int>
437 </object>
438 <object class="NSMenuItem" id="270902937">
439 <reference key="NSMenu" ref="963351320"/>
440 <string key="NSTitle">Find Previous</string>
441 <string key="NSKeyEquiv" id="819654342">G</string>
442 <int key="NSKeyEquivModMask">1179648</int>
443 <int key="NSMnemonicLoc">2147483647</int>
444 <reference key="NSOnImage" ref="271266416"/>
445 <reference key="NSMixedImage" ref="508123839"/>
446 <int key="NSTag">3</int>
447 </object>
448 <object class="NSMenuItem" id="159080638">
449 <reference key="NSMenu" ref="963351320"/>
450 <string key="NSTitle">Use Selection for Find</string>
451 <string key="NSKeyEquiv">e</string>
452 <int key="NSKeyEquivModMask">1048576</int>
453 <int key="NSMnemonicLoc">2147483647</int>
454 <reference key="NSOnImage" ref="271266416"/>
455 <reference key="NSMixedImage" ref="508123839"/>
456 <int key="NSTag">7</int>
457 </object>
458 <object class="NSMenuItem" id="88285865">
459 <reference key="NSMenu" ref="963351320"/>
460 <string key="NSTitle">Jump to Selection</string>
461 <string key="NSKeyEquiv">j</string>
462 <int key="NSKeyEquivModMask">1048576</int>
463 <int key="NSMnemonicLoc">2147483647</int>
464 <reference key="NSOnImage" ref="271266416"/>
465 <reference key="NSMixedImage" ref="508123839"/>
466 </object>
467 </object>
468 </object>
469 </object>
470 <object class="NSMenuItem" id="972420730">
471 <reference key="NSMenu" ref="789758025"/>
472 <string key="NSTitle" id="739167250">Spelling and Grammar</string>
473 <reference key="NSKeyEquiv" ref="255189770"/>
474 <int key="NSKeyEquivModMask">1048576</int>
475 <int key="NSMnemonicLoc">2147483647</int>
476 <reference key="NSOnImage" ref="271266416"/>
477 <reference key="NSMixedImage" ref="508123839"/>
478 <string key="NSAction">submenuAction:</string>
479 <object class="NSMenu" key="NSSubmenu" id="769623530">
480 <reference key="NSTitle" ref="739167250"/>
481 <object class="NSMutableArray" key="NSMenuItems">
482 <bool key="EncodedWithXMLCoder">YES</bool>
483 <object class="NSMenuItem" id="679648819">
484 <reference key="NSMenu" ref="769623530"/>
485 <string type="base64-UTF8" key="NSTitle">U2hvdyBTcGVsbGluZ+KApg</string>
486 <string key="NSKeyEquiv">:</string>
487 <int key="NSKeyEquivModMask">1048576</int>
488 <int key="NSMnemonicLoc">2147483647</int>
489 <reference key="NSOnImage" ref="271266416"/>
490 <reference key="NSMixedImage" ref="508123839"/>
491 </object>
492 <object class="NSMenuItem" id="96193923">
493 <reference key="NSMenu" ref="769623530"/>
494 <string key="NSTitle">Check Spelling</string>
495 <string key="NSKeyEquiv">;</string>
496 <int key="NSKeyEquivModMask">1048576</int>
497 <int key="NSMnemonicLoc">2147483647</int>
498 <reference key="NSOnImage" ref="271266416"/>
499 <reference key="NSMixedImage" ref="508123839"/>
500 </object>
501 <object class="NSMenuItem" id="948374510">
502 <reference key="NSMenu" ref="769623530"/>
503 <string key="NSTitle">Check Spelling While Typing</string>
504 <reference key="NSKeyEquiv" ref="255189770"/>
505 <int key="NSKeyEquivModMask">1048576</int>
506 <int key="NSMnemonicLoc">2147483647</int>
507 <reference key="NSOnImage" ref="271266416"/>
508 <reference key="NSMixedImage" ref="508123839"/>
509 </object>
510 <object class="NSMenuItem" id="967646866">
511 <reference key="NSMenu" ref="769623530"/>
512 <string key="NSTitle">Check Grammar With Spelling</string>
513 <reference key="NSKeyEquiv" ref="255189770"/>
514 <int key="NSKeyEquivModMask">1048576</int>
515 <int key="NSMnemonicLoc">2147483647</int>
516 <reference key="NSOnImage" ref="271266416"/>
517 <reference key="NSMixedImage" ref="508123839"/>
518 </object>
519 </object>
520 </object>
521 </object>
522 <object class="NSMenuItem" id="507821607">
523 <reference key="NSMenu" ref="789758025"/>
524 <string key="NSTitle" id="904739598">Substitutions</string>
525 <reference key="NSKeyEquiv" ref="255189770"/>
526 <int key="NSKeyEquivModMask">1048576</int>
527 <int key="NSMnemonicLoc">2147483647</int>
528 <reference key="NSOnImage" ref="271266416"/>
529 <reference key="NSMixedImage" ref="508123839"/>
530 <string key="NSAction">submenuAction:</string>
531 <object class="NSMenu" key="NSSubmenu" id="698887838">
532 <reference key="NSTitle" ref="904739598"/>
533 <object class="NSMutableArray" key="NSMenuItems">
534 <bool key="EncodedWithXMLCoder">YES</bool>
535 <object class="NSMenuItem" id="605118523">
536 <reference key="NSMenu" ref="698887838"/>
537 <string key="NSTitle">Smart Copy/Paste</string>
538 <reference key="NSKeyEquiv" ref="469505129"/>
539 <int key="NSKeyEquivModMask">1048576</int>
540 <int key="NSMnemonicLoc">2147483647</int>
541 <reference key="NSOnImage" ref="271266416"/>
542 <reference key="NSMixedImage" ref="508123839"/>
543 <int key="NSTag">1</int>
544 </object>
545 <object class="NSMenuItem" id="197661976">
546 <reference key="NSMenu" ref="698887838"/>
547 <string key="NSTitle">Smart Quotes</string>
548 <reference key="NSKeyEquiv" ref="762398675"/>
549 <int key="NSKeyEquivModMask">1048576</int>
550 <int key="NSMnemonicLoc">2147483647</int>
551 <reference key="NSOnImage" ref="271266416"/>
552 <reference key="NSMixedImage" ref="508123839"/>
553 <int key="NSTag">2</int>
554 </object>
555 <object class="NSMenuItem" id="708854459">
556 <reference key="NSMenu" ref="698887838"/>
557 <string key="NSTitle">Smart Links</string>
558 <reference key="NSKeyEquiv" ref="819654342"/>
559 <int key="NSKeyEquivModMask">1179648</int>
560 <int key="NSMnemonicLoc">2147483647</int>
561 <reference key="NSOnImage" ref="271266416"/>
562 <reference key="NSMixedImage" ref="508123839"/>
563 <int key="NSTag">3</int>
564 </object>
565 </object>
566 </object>
567 </object>
568 <object class="NSMenuItem" id="676164635">
569 <reference key="NSMenu" ref="789758025"/>
570 <string key="NSTitle" id="812002426">Speech</string>
571 <reference key="NSKeyEquiv" ref="255189770"/>
572 <int key="NSKeyEquivModMask">1048576</int>
573 <int key="NSMnemonicLoc">2147483647</int>
574 <reference key="NSOnImage" ref="271266416"/>
575 <reference key="NSMixedImage" ref="508123839"/>
576 <string key="NSAction">submenuAction:</string>
577 <object class="NSMenu" key="NSSubmenu" id="785027613">
578 <reference key="NSTitle" ref="812002426"/>
579 <object class="NSMutableArray" key="NSMenuItems">
580 <bool key="EncodedWithXMLCoder">YES</bool>
581 <object class="NSMenuItem" id="731782645">
582 <reference key="NSMenu" ref="785027613"/>
583 <string key="NSTitle">Start Speaking</string>
584 <reference key="NSKeyEquiv" ref="255189770"/>
585 <int key="NSKeyEquivModMask">1048576</int>
586 <int key="NSMnemonicLoc">2147483647</int>
587 <reference key="NSOnImage" ref="271266416"/>
588 <reference key="NSMixedImage" ref="508123839"/>
589 </object>
590 <object class="NSMenuItem" id="680220178">
591 <reference key="NSMenu" ref="785027613"/>
592 <string key="NSTitle">Stop Speaking</string>
593 <reference key="NSKeyEquiv" ref="255189770"/>
594 <int key="NSKeyEquivModMask">1048576</int>
595 <int key="NSMnemonicLoc">2147483647</int>
596 <reference key="NSOnImage" ref="271266416"/>
597 <reference key="NSMixedImage" ref="508123839"/>
598 </object>
599 </object>
600 </object>
601 </object>
602 </object>
603 </object>
604 </object>
605 <object class="NSMenuItem" id="626404410">
606 <reference key="NSMenu" ref="649796088"/>
607 <string key="NSTitle" id="241242548">Format</string>
608 <reference key="NSKeyEquiv" ref="255189770"/>
609 <int key="NSKeyEquivModMask">1048576</int>
610 <int key="NSMnemonicLoc">2147483647</int>
611 <reference key="NSOnImage" ref="271266416"/>
612 <reference key="NSMixedImage" ref="508123839"/>
613 <string key="NSAction">submenuAction:</string>
614 <object class="NSMenu" key="NSSubmenu" id="502084290">
615 <reference key="NSTitle" ref="241242548"/>
616 <object class="NSMutableArray" key="NSMenuItems">
617 <bool key="EncodedWithXMLCoder">YES</bool>
618 <object class="NSMenuItem" id="519768076">
619 <reference key="NSMenu" ref="502084290"/>
620 <string key="NSTitle">Show Fonts</string>
621 <string key="NSKeyEquiv" id="806579634">t</string>
622 <int key="NSKeyEquivModMask">1048576</int>
623 <int key="NSMnemonicLoc">2147483647</int>
624 <reference key="NSOnImage" ref="271266416"/>
625 <reference key="NSMixedImage" ref="508123839"/>
626 </object>
627 <object class="NSMenuItem" id="1028416764">
628 <reference key="NSMenu" ref="502084290"/>
629 <string key="NSTitle">Show Colors</string>
630 <string key="NSKeyEquiv">C</string>
631 <int key="NSKeyEquivModMask">1179648</int>
632 <int key="NSMnemonicLoc">2147483647</int>
633 <reference key="NSOnImage" ref="271266416"/>
634 <reference key="NSMixedImage" ref="508123839"/>
635 </object>
636 </object>
637 </object>
638 </object>
639 <object class="NSMenuItem" id="586577488">
640 <reference key="NSMenu" ref="649796088"/>
641 <string key="NSTitle" id="809723865">View</string>
642 <reference key="NSKeyEquiv" ref="255189770"/>
643 <int key="NSKeyEquivModMask">1048576</int>
644 <int key="NSMnemonicLoc">2147483647</int>
645 <reference key="NSOnImage" ref="271266416"/>
646 <reference key="NSMixedImage" ref="508123839"/>
647 <string key="NSAction">submenuAction:</string>
648 <object class="NSMenu" key="NSSubmenu" id="466310130">
649 <reference key="NSTitle" ref="809723865"/>
650 <object class="NSMutableArray" key="NSMenuItems">
651 <bool key="EncodedWithXMLCoder">YES</bool>
652 <object class="NSMenuItem" id="102151532">
653 <reference key="NSMenu" ref="466310130"/>
654 <string key="NSTitle">Show Toolbar</string>
655 <reference key="NSKeyEquiv" ref="806579634"/>
656 <int key="NSKeyEquivModMask">1572864</int>
657 <int key="NSMnemonicLoc">2147483647</int>
658 <reference key="NSOnImage" ref="271266416"/>
659 <reference key="NSMixedImage" ref="508123839"/>
660 </object>
661 <object class="NSMenuItem" id="237841660">
662 <reference key="NSMenu" ref="466310130"/>
663 <string type="base64-UTF8" key="NSTitle">Q3VzdG9taXplIFRvb2xiYXLigKY</string>
664 <reference key="NSKeyEquiv" ref="255189770"/>
665 <int key="NSKeyEquivModMask">1048576</int>
666 <int key="NSMnemonicLoc">2147483647</int>
667 <reference key="NSOnImage" ref="271266416"/>
668 <reference key="NSMixedImage" ref="508123839"/>
669 </object>
670 </object>
671 </object>
672 </object>
673 <object class="NSMenuItem" id="713487014">
674 <reference key="NSMenu" ref="649796088"/>
675 <string key="NSTitle" id="64165424">Window</string>
676 <reference key="NSKeyEquiv" ref="255189770"/>
677 <int key="NSKeyEquivModMask">1048576</int>
678 <int key="NSMnemonicLoc">2147483647</int>
679 <reference key="NSOnImage" ref="271266416"/>
680 <reference key="NSMixedImage" ref="508123839"/>
681 <string key="NSAction">submenuAction:</string>
682 <object class="NSMenu" key="NSSubmenu" id="835318025">
683 <reference key="NSTitle" ref="64165424"/>
684 <object class="NSMutableArray" key="NSMenuItems">
685 <bool key="EncodedWithXMLCoder">YES</bool>
686 <object class="NSMenuItem" id="1011231497">
687 <reference key="NSMenu" ref="835318025"/>
688 <string key="NSTitle">Minimize</string>
689 <string key="NSKeyEquiv">m</string>
690 <int key="NSKeyEquivModMask">1048576</int>
691 <int key="NSMnemonicLoc">2147483647</int>
692 <reference key="NSOnImage" ref="271266416"/>
693 <reference key="NSMixedImage" ref="508123839"/>
694 </object>
695 <object class="NSMenuItem" id="575023229">
696 <reference key="NSMenu" ref="835318025"/>
697 <string key="NSTitle">Zoom</string>
698 <reference key="NSKeyEquiv" ref="255189770"/>
699 <int key="NSKeyEquivModMask">1048576</int>
700 <int key="NSMnemonicLoc">2147483647</int>
701 <reference key="NSOnImage" ref="271266416"/>
702 <reference key="NSMixedImage" ref="508123839"/>
703 </object>
704 <object class="NSMenuItem" id="299356726">
705 <reference key="NSMenu" ref="835318025"/>
706 <bool key="NSIsDisabled">YES</bool>
707 <bool key="NSIsSeparator">YES</bool>
708 <reference key="NSTitle" ref="255189770"/>
709 <reference key="NSKeyEquiv" ref="255189770"/>
710 <int key="NSKeyEquivModMask">1048576</int>
711 <int key="NSMnemonicLoc">2147483647</int>
712 <reference key="NSOnImage" ref="271266416"/>
713 <reference key="NSMixedImage" ref="508123839"/>
714 </object>
715 <object class="NSMenuItem" id="625202149">
716 <reference key="NSMenu" ref="835318025"/>
717 <string key="NSTitle">Bring All to Front</string>
718 <reference key="NSKeyEquiv" ref="255189770"/>
719 <int key="NSKeyEquivModMask">1048576</int>
720 <int key="NSMnemonicLoc">2147483647</int>
721 <reference key="NSOnImage" ref="271266416"/>
722 <reference key="NSMixedImage" ref="508123839"/>
723 </object>
724 </object>
725 <string key="NSName">_NSWindowsMenu</string>
726 </object>
727 </object>
728 <object class="NSMenuItem" id="391199113">
729 <reference key="NSMenu" ref="649796088"/>
730 <string key="NSTitle" id="461919786">Help</string>
731 <reference key="NSKeyEquiv" ref="255189770"/>
732 <int key="NSKeyEquivModMask">1048576</int>
733 <int key="NSMnemonicLoc">2147483647</int>
734 <reference key="NSOnImage" ref="271266416"/>
735 <reference key="NSMixedImage" ref="508123839"/>
736 <string key="NSAction">submenuAction:</string>
737 <object class="NSMenu" key="NSSubmenu" id="374024848">
738 <reference key="NSTitle" ref="461919786"/>
739 <object class="NSMutableArray" key="NSMenuItems">
740 <bool key="EncodedWithXMLCoder">YES</bool>
741 <object class="NSMenuItem" id="238773614">
742 <reference key="NSMenu" ref="374024848"/>
743 <string key="NSTitle">IPython1Sandbox Help</string>
744 <string key="NSKeyEquiv">?</string>
745 <int key="NSKeyEquivModMask">1048576</int>
746 <int key="NSMnemonicLoc">2147483647</int>
747 <reference key="NSOnImage" ref="271266416"/>
748 <reference key="NSMixedImage" ref="508123839"/>
749 </object>
750 </object>
751 </object>
752 </object>
753 </object>
754 <string key="NSName">_NSMainMenu</string>
755 </object>
756 <object class="NSWindowTemplate" id="972006081">
757 <int key="NSWindowStyleMask">15</int>
758 <int key="NSWindowBacking">2</int>
759 <string key="NSWindowRect">{{335, 413}, {725, 337}}</string>
760 <int key="NSWTFlags">1946157056</int>
761 <string key="NSWindowTitle">IPython1 (Cocoa)</string>
762 <string key="NSWindowClass">NSWindow</string>
763 <nil key="NSViewClass"/>
764 <object class="NSView" key="NSWindowView" id="439893737">
765 <reference key="NSNextResponder"/>
766 <int key="NSvFlags">256</int>
767 <object class="NSMutableArray" key="NSSubviews">
768 <bool key="EncodedWithXMLCoder">YES</bool>
769 <object class="NSSplitView" id="741760375">
770 <reference key="NSNextResponder" ref="439893737"/>
771 <int key="NSvFlags">274</int>
772 <object class="NSMutableArray" key="NSSubviews">
773 <bool key="EncodedWithXMLCoder">YES</bool>
774 <object class="NSBox" id="554641139">
775 <reference key="NSNextResponder" ref="741760375"/>
776 <int key="NSvFlags">22</int>
777 <object class="NSMutableArray" key="NSSubviews">
778 <bool key="EncodedWithXMLCoder">YES</bool>
779 <object class="NSView" id="597872307">
780 <reference key="NSNextResponder" ref="554641139"/>
781 <int key="NSvFlags">256</int>
782 <object class="NSMutableArray" key="NSSubviews">
783 <bool key="EncodedWithXMLCoder">YES</bool>
784 <object class="NSScrollView" id="188193463">
785 <reference key="NSNextResponder" ref="597872307"/>
786 <int key="NSvFlags">274</int>
787 <object class="NSMutableArray" key="NSSubviews">
788 <bool key="EncodedWithXMLCoder">YES</bool>
789 <object class="NSClipView" id="638544389">
790 <reference key="NSNextResponder" ref="188193463"/>
791 <int key="NSvFlags">2304</int>
792 <object class="NSMutableArray" key="NSSubviews">
793 <bool key="EncodedWithXMLCoder">YES</bool>
794 <object class="NSTextView" id="163417131">
795 <reference key="NSNextResponder" ref="638544389"/>
796 <int key="NSvFlags">2322</int>
797 <object class="NSMutableSet" key="NSDragTypes">
798 <bool key="EncodedWithXMLCoder">YES</bool>
799 <object class="NSMutableArray" key="set.sortedObjects">
800 <bool key="EncodedWithXMLCoder">YES</bool>
801 <string>Apple HTML pasteboard type</string>
802 <string>Apple PDF pasteboard type</string>
803 <string>Apple PICT pasteboard type</string>
804 <string>Apple PNG pasteboard type</string>
805 <string>Apple URL pasteboard type</string>
806 <string>CorePasteboardFlavorType 0x6D6F6F76</string>
807 <string>CorePasteboardFlavorType 0x75726C20</string>
808 <string>NSColor pasteboard type</string>
809 <string>NSFilenamesPboardType</string>
810 <string>NSStringPboardType</string>
811 <string>NeXT Encapsulated PostScript v1.2 pasteboard type</string>
812 <string>NeXT RTFD pasteboard type</string>
813 <string>NeXT Rich Text Format v1.0 pasteboard type</string>
814 <string>NeXT TIFF v4.0 pasteboard type</string>
815 <string>NeXT font pasteboard type</string>
816 <string>NeXT ruler pasteboard type</string>
817 <string>WebURLsWithTitlesPboardType</string>
818 </object>
819 </object>
820 <string key="NSFrame">{{0, 38}, {433, 14}}</string>
821 <reference key="NSSuperview" ref="638544389"/>
822 <reference key="NSWindow"/>
823 <object class="NSTextContainer" key="NSTextContainer" id="662117317">
824 <object class="NSLayoutManager" key="NSLayoutManager">
825 <object class="NSTextStorage" key="NSTextStorage">
826 <object class="NSMutableString" key="NSString">
827 <characters key="NS.bytes"/>
828 </object>
829 <nil key="NSDelegate"/>
830 </object>
831 <object class="NSMutableArray" key="NSTextContainers">
832 <bool key="EncodedWithXMLCoder">YES</bool>
833 <reference ref="662117317"/>
834 </object>
835 <int key="NSLMFlags">6</int>
836 <nil key="NSDelegate"/>
837 </object>
838 <reference key="NSTextView" ref="163417131"/>
839 <double key="NSWidth">4.330000e+02</double>
840 <int key="NSTCFlags">1</int>
841 </object>
842 <object class="NSTextViewSharedData" key="NSSharedData">
843 <int key="NSFlags">346991</int>
844 <object class="NSColor" key="NSBackgroundColor">
845 <int key="NSColorSpace">2</int>
846 <bytes key="NSRGB">MSAwLjk1Mjk0MTI0IDAuODUwOTgwNDYAA</bytes>
847 </object>
848 <object class="NSColor" key="NSInsertionColor" id="555789289">
849 <int key="NSColorSpace">3</int>
850 <bytes key="NSWhite">MAA</bytes>
851 </object>
852 <object class="NSDictionary" key="NSSelectedAttributes">
853 <bool key="EncodedWithXMLCoder">YES</bool>
854 <object class="NSMutableArray" key="dict.sortedKeys">
855 <bool key="EncodedWithXMLCoder">YES</bool>
856 <string>NSBackgroundColor</string>
857 <string id="19777717">NSColor</string>
858 </object>
859 <object class="NSMutableArray" key="dict.values">
860 <bool key="EncodedWithXMLCoder">YES</bool>
861 <object class="NSColor">
862 <int key="NSColorSpace">6</int>
863 <string key="NSCatalogName" id="484387293">System</string>
864 <string key="NSColorName">selectedTextBackgroundColor</string>
865 <object class="NSColor" key="NSColor" id="377165725">
866 <int key="NSColorSpace">3</int>
867 <bytes key="NSWhite">MC42NjY2NjY2OQA</bytes>
868 </object>
869 </object>
870 <object class="NSColor">
871 <int key="NSColorSpace">6</int>
872 <reference key="NSCatalogName" ref="484387293"/>
873 <string key="NSColorName">selectedTextColor</string>
874 <reference key="NSColor" ref="555789289"/>
875 </object>
876 </object>
877 </object>
878 <nil key="NSMarkedAttributes"/>
879 <object class="NSDictionary" key="NSLinkAttributes">
880 <bool key="EncodedWithXMLCoder">YES</bool>
881 <object class="NSMutableArray" key="dict.sortedKeys">
882 <bool key="EncodedWithXMLCoder">YES</bool>
883 <reference ref="19777717"/>
884 <string>NSUnderline</string>
885 </object>
886 <object class="NSMutableArray" key="dict.values">
887 <bool key="EncodedWithXMLCoder">YES</bool>
888 <object class="NSColor">
889 <int key="NSColorSpace">1</int>
890 <bytes key="NSRGB">MCAwIDEAA</bytes>
891 </object>
892 <integer value="1" id="9"/>
893 </object>
894 </object>
895 <nil key="NSDefaultParagraphStyle"/>
896 </object>
897 <int key="NSTVFlags">6</int>
898 <string key="NSMaxSize">{480, 1e+07}</string>
899 <string key="NSMinize">{84, 0}</string>
900 <nil key="NSDelegate"/>
901 </object>
902 </object>
903 <string key="NSFrame">{{1, 1}, {433, 231}}</string>
904 <string key="NSBounds">{{0, 38}, {433, 231}}</string>
905 <reference key="NSSuperview" ref="188193463"/>
906 <reference key="NSWindow"/>
907 <reference key="NSNextKeyView" ref="163417131"/>
908 <reference key="NSDocView" ref="163417131"/>
909 <object class="NSColor" key="NSBGColor" id="521347521">
910 <int key="NSColorSpace">3</int>
911 <bytes key="NSWhite">MQA</bytes>
912 </object>
913 <object class="NSCursor" key="NSCursor">
914 <string key="NSHotSpot">{4, -5}</string>
915 <int key="NSCursorType">1</int>
916 </object>
917 <int key="NScvFlags">4</int>
918 </object>
919 <object class="NSScroller" id="418410897">
920 <reference key="NSNextResponder" ref="188193463"/>
921 <int key="NSvFlags">-2147483392</int>
922 <string key="NSFrame">{{427, 1}, {15, 263}}</string>
923 <reference key="NSSuperview" ref="188193463"/>
924 <reference key="NSWindow"/>
925 <reference key="NSTarget" ref="188193463"/>
926 <string key="NSAction" id="688920982">_doScroller:</string>
927 <double key="NSPercent">3.389175e-01</double>
928 </object>
929 <object class="NSScroller" id="936733673">
930 <reference key="NSNextResponder" ref="188193463"/>
931 <int key="NSvFlags">256</int>
932 <string key="NSFrame">{{-100, -100}, {87, 18}}</string>
933 <reference key="NSSuperview" ref="188193463"/>
934 <reference key="NSWindow"/>
935 <int key="NSsFlags">1</int>
936 <reference key="NSTarget" ref="188193463"/>
937 <reference key="NSAction" ref="688920982"/>
938 <double key="NSCurValue">1.000000e+00</double>
939 <double key="NSPercent">9.456522e-01</double>
940 </object>
941 </object>
942 <string key="NSFrame">{{18, 14}, {435, 233}}</string>
943 <reference key="NSSuperview" ref="597872307"/>
944 <reference key="NSWindow"/>
945 <reference key="NSNextKeyView" ref="638544389"/>
946 <int key="NSsFlags">530</int>
947 <reference key="NSVScroller" ref="418410897"/>
948 <reference key="NSHScroller" ref="936733673"/>
949 <reference key="NSContentView" ref="638544389"/>
950 </object>
951 </object>
952 <string key="NSFrame">{{1, 1}, {471, 257}}</string>
953 <reference key="NSSuperview" ref="554641139"/>
954 <reference key="NSWindow"/>
955 </object>
956 </object>
957 <string key="NSFrameSize">{473, 273}</string>
958 <reference key="NSSuperview" ref="741760375"/>
959 <reference key="NSWindow"/>
960 <string key="NSOffsets" id="1055927954">{0, 0}</string>
961 <object class="NSTextFieldCell" key="NSTitleCell">
962 <int key="NSCellFlags">67239424</int>
963 <int key="NSCellFlags2">0</int>
964 <string key="NSContents">Console</string>
965 <object class="NSFont" key="NSSupport" id="26">
966 <string key="NSName" id="378950370">LucidaGrande</string>
967 <double key="NSSize">1.100000e+01</double>
968 <int key="NSfFlags">3100</int>
969 </object>
970 <object class="NSColor" key="NSBackgroundColor" id="131515055">
971 <int key="NSColorSpace">6</int>
972 <reference key="NSCatalogName" ref="484387293"/>
973 <string key="NSColorName">textBackgroundColor</string>
974 <reference key="NSColor" ref="521347521"/>
975 </object>
976 <object class="NSColor" key="NSTextColor">
977 <int key="NSColorSpace">3</int>
978 <bytes key="NSWhite">MCAwLjgwMDAwMDAxAA</bytes>
979 </object>
980 </object>
981 <reference key="NSContentView" ref="597872307"/>
982 <int key="NSBorderType">1</int>
983 <int key="NSBoxType">0</int>
984 <int key="NSTitlePosition">2</int>
985 <bool key="NSTransparent">NO</bool>
986 </object>
987 <object class="NSBox" id="764100755">
988 <reference key="NSNextResponder" ref="741760375"/>
989 <int key="NSvFlags">51</int>
990 <object class="NSMutableArray" key="NSSubviews">
991 <bool key="EncodedWithXMLCoder">YES</bool>
992 <object class="NSView" id="581281551">
993 <reference key="NSNextResponder" ref="764100755"/>
994 <int key="NSvFlags">256</int>
995 <object class="NSMutableArray" key="NSSubviews">
996 <bool key="EncodedWithXMLCoder">YES</bool>
997 <object class="NSScrollView" id="516244966">
998 <reference key="NSNextResponder" ref="581281551"/>
999 <int key="NSvFlags">274</int>
1000 <object class="NSMutableArray" key="NSSubviews">
1001 <bool key="EncodedWithXMLCoder">YES</bool>
1002 <object class="NSClipView" id="119083427">
1003 <reference key="NSNextResponder" ref="516244966"/>
1004 <int key="NSvFlags">2304</int>
1005 <object class="NSMutableArray" key="NSSubviews">
1006 <bool key="EncodedWithXMLCoder">YES</bool>
1007 <object class="NSTableView" id="23853726">
1008 <reference key="NSNextResponder" ref="119083427"/>
1009 <int key="NSvFlags">256</int>
1010 <string key="NSFrameSize">{156, 200}</string>
1011 <reference key="NSSuperview" ref="119083427"/>
1012 <reference key="NSWindow"/>
1013 <bool key="NSEnabled">YES</bool>
1014 <object class="NSTableHeaderView" key="NSHeaderView" id="1048357090">
1015 <reference key="NSNextResponder" ref="746968320"/>
1016 <int key="NSvFlags">256</int>
1017 <string key="NSFrameSize">{156, 17}</string>
1018 <reference key="NSSuperview" ref="746968320"/>
1019 <reference key="NSWindow"/>
1020 <reference key="NSTableView" ref="23853726"/>
1021 </object>
1022 <object class="_NSCornerView" key="NSCornerView" id="212282722">
1023 <reference key="NSNextResponder" ref="516244966"/>
1024 <int key="NSvFlags">256</int>
1025 <string key="NSFrame">{{157, 0}, {16, 17}}</string>
1026 <reference key="NSSuperview" ref="516244966"/>
1027 <reference key="NSWindow"/>
1028 </object>
1029 <object class="NSMutableArray" key="NSTableColumns">
1030 <bool key="EncodedWithXMLCoder">YES</bool>
1031 <object class="NSTableColumn" id="920426212">
1032 <double key="NSWidth">7.100000e+01</double>
1033 <double key="NSMinWidth">4.000000e+01</double>
1034 <double key="NSMaxWidth">1.000000e+03</double>
1035 <object class="NSTableHeaderCell" key="NSHeaderCell">
1036 <int key="NSCellFlags">75628032</int>
1037 <int key="NSCellFlags2">0</int>
1038 <string key="NSContents">Variable</string>
1039 <reference key="NSSupport" ref="26"/>
1040 <object class="NSColor" key="NSBackgroundColor" id="890615311">
1041 <int key="NSColorSpace">3</int>
1042 <bytes key="NSWhite">MC4zMzMzMzI5OQA</bytes>
1043 </object>
1044 <object class="NSColor" key="NSTextColor" id="866628999">
1045 <int key="NSColorSpace">6</int>
1046 <reference key="NSCatalogName" ref="484387293"/>
1047 <string key="NSColorName">headerTextColor</string>
1048 <reference key="NSColor" ref="555789289"/>
1049 </object>
1050 </object>
1051 <object class="NSTextFieldCell" key="NSDataCell" id="525071236">
1052 <int key="NSCellFlags">337772096</int>
1053 <int key="NSCellFlags2">2048</int>
1054 <string key="NSContents" id="456204663">Text Cell</string>
1055 <object class="NSFont" key="NSSupport" id="8196371">
1056 <reference key="NSName" ref="378950370"/>
1057 <double key="NSSize">1.300000e+01</double>
1058 <int key="NSfFlags">1044</int>
1059 </object>
1060 <reference key="NSControlView" ref="23853726"/>
1061 <object class="NSColor" key="NSBackgroundColor" id="224028609">
1062 <int key="NSColorSpace">6</int>
1063 <reference key="NSCatalogName" ref="484387293"/>
1064 <string key="NSColorName">controlBackgroundColor</string>
1065 <reference key="NSColor" ref="377165725"/>
1066 </object>
1067 <object class="NSColor" key="NSTextColor" id="205104690">
1068 <int key="NSColorSpace">6</int>
1069 <reference key="NSCatalogName" ref="484387293"/>
1070 <string key="NSColorName">controlTextColor</string>
1071 <reference key="NSColor" ref="555789289"/>
1072 </object>
1073 </object>
1074 <int key="NSResizingMask">3</int>
1075 <bool key="NSIsResizeable">YES</bool>
1076 <bool key="NSIsEditable">YES</bool>
1077 <reference key="NSTableView" ref="23853726"/>
1078 </object>
1079 <object class="NSTableColumn" id="857054683">
1080 <double key="NSWidth">7.900000e+01</double>
1081 <double key="NSMinWidth">4.000000e+01</double>
1082 <double key="NSMaxWidth">1.000000e+03</double>
1083 <object class="NSTableHeaderCell" key="NSHeaderCell">
1084 <int key="NSCellFlags">75628032</int>
1085 <int key="NSCellFlags2">0</int>
1086 <string key="NSContents">Value</string>
1087 <reference key="NSSupport" ref="26"/>
1088 <reference key="NSBackgroundColor" ref="890615311"/>
1089 <reference key="NSTextColor" ref="866628999"/>
1090 </object>
1091 <object class="NSTextFieldCell" key="NSDataCell" id="377147224">
1092 <int key="NSCellFlags">337772096</int>
1093 <int key="NSCellFlags2">2048</int>
1094 <reference key="NSContents" ref="456204663"/>
1095 <reference key="NSSupport" ref="8196371"/>
1096 <reference key="NSControlView" ref="23853726"/>
1097 <reference key="NSBackgroundColor" ref="224028609"/>
1098 <reference key="NSTextColor" ref="205104690"/>
1099 </object>
1100 <int key="NSResizingMask">3</int>
1101 <bool key="NSIsResizeable">YES</bool>
1102 <bool key="NSIsEditable">YES</bool>
1103 <reference key="NSTableView" ref="23853726"/>
1104 </object>
1105 </object>
1106 <double key="NSIntercellSpacingWidth">3.000000e+00</double>
1107 <double key="NSIntercellSpacingHeight">2.000000e+00</double>
1108 <reference key="NSBackgroundColor" ref="521347521"/>
1109 <object class="NSColor" key="NSGridColor">
1110 <int key="NSColorSpace">6</int>
1111 <reference key="NSCatalogName" ref="484387293"/>
1112 <string key="NSColorName">gridColor</string>
1113 <object class="NSColor" key="NSColor">
1114 <int key="NSColorSpace">3</int>
1115 <bytes key="NSWhite">MC41AA</bytes>
1116 </object>
1117 </object>
1118 <double key="NSRowHeight">1.700000e+01</double>
1119 <int key="NSTvFlags">-692060160</int>
1120 <int key="NSGridStyleMask">1</int>
1121 <int key="NSColumnAutoresizingStyle">4</int>
1122 <int key="NSDraggingSourceMaskForLocal">15</int>
1123 <int key="NSDraggingSourceMaskForNonLocal">0</int>
1124 <bool key="NSAllowsTypeSelect">YES</bool>
1125 </object>
1126 </object>
1127 <string key="NSFrame">{{1, 17}, {156, 200}}</string>
1128 <reference key="NSSuperview" ref="516244966"/>
1129 <reference key="NSWindow"/>
1130 <reference key="NSNextKeyView" ref="23853726"/>
1131 <reference key="NSDocView" ref="23853726"/>
1132 <reference key="NSBGColor" ref="224028609"/>
1133 <int key="NScvFlags">4</int>
1134 </object>
1135 <object class="NSScroller" id="512953560">
1136 <reference key="NSNextResponder" ref="516244966"/>
1137 <int key="NSvFlags">256</int>
1138 <string key="NSFrame">{{157, 17}, {15, 200}}</string>
1139 <reference key="NSSuperview" ref="516244966"/>
1140 <reference key="NSWindow"/>
1141 <reference key="NSTarget" ref="516244966"/>
1142 <reference key="NSAction" ref="688920982"/>
1143 <double key="NSPercent">9.961240e-01</double>
1144 </object>
1145 <object class="NSScroller" id="47103270">
1146 <reference key="NSNextResponder" ref="516244966"/>
1147 <int key="NSvFlags">256</int>
1148 <string key="NSFrame">{{1, 217}, {156, 15}}</string>
1149 <reference key="NSSuperview" ref="516244966"/>
1150 <reference key="NSWindow"/>
1151 <int key="NSsFlags">1</int>
1152 <reference key="NSTarget" ref="516244966"/>
1153 <reference key="NSAction" ref="688920982"/>
1154 <double key="NSPercent">7.179487e-01</double>
1155 </object>
1156 <object class="NSClipView" id="746968320">
1157 <reference key="NSNextResponder" ref="516244966"/>
1158 <int key="NSvFlags">2304</int>
1159 <object class="NSMutableArray" key="NSSubviews">
1160 <bool key="EncodedWithXMLCoder">YES</bool>
1161 <reference ref="1048357090"/>
1162 </object>
1163 <string key="NSFrame">{{1, 0}, {156, 17}}</string>
1164 <reference key="NSSuperview" ref="516244966"/>
1165 <reference key="NSWindow"/>
1166 <reference key="NSNextKeyView" ref="1048357090"/>
1167 <reference key="NSDocView" ref="1048357090"/>
1168 <reference key="NSBGColor" ref="224028609"/>
1169 <int key="NScvFlags">4</int>
1170 </object>
1171 <reference ref="212282722"/>
1172 </object>
1173 <string key="NSFrame">{{18, 14}, {173, 233}}</string>
1174 <reference key="NSSuperview" ref="581281551"/>
1175 <reference key="NSWindow"/>
1176 <reference key="NSNextKeyView" ref="119083427"/>
1177 <int key="NSsFlags">50</int>
1178 <reference key="NSVScroller" ref="512953560"/>
1179 <reference key="NSHScroller" ref="47103270"/>
1180 <reference key="NSContentView" ref="119083427"/>
1181 <reference key="NSHeaderClipView" ref="746968320"/>
1182 <reference key="NSCornerView" ref="212282722"/>
1183 <bytes key="NSScrollAmts">QSAAAEEgAABBmAAAQZgAAA</bytes>
1184 </object>
1185 </object>
1186 <string key="NSFrame">{{1, 1}, {209, 257}}</string>
1187 <reference key="NSSuperview" ref="764100755"/>
1188 <reference key="NSWindow"/>
1189 </object>
1190 </object>
1191 <string key="NSFrame">{{474, 0}, {211, 273}}</string>
1192 <reference key="NSSuperview" ref="741760375"/>
1193 <reference key="NSWindow"/>
1194 <reference key="NSOffsets" ref="1055927954"/>
1195 <object class="NSTextFieldCell" key="NSTitleCell">
1196 <int key="NSCellFlags">67239424</int>
1197 <int key="NSCellFlags2">0</int>
1198 <string key="NSContents">Workspace</string>
1199 <reference key="NSSupport" ref="26"/>
1200 <reference key="NSBackgroundColor" ref="131515055"/>
1201 <object class="NSColor" key="NSTextColor">
1202 <int key="NSColorSpace">3</int>
1203 <bytes key="NSWhite">MCAwLjgwMDAwMDAxAA</bytes>
1204 </object>
1205 </object>
1206 <reference key="NSContentView" ref="581281551"/>
1207 <int key="NSBorderType">1</int>
1208 <int key="NSBoxType">0</int>
1209 <int key="NSTitlePosition">2</int>
1210 <bool key="NSTransparent">NO</bool>
1211 </object>
1212 </object>
1213 <string key="NSFrame">{{20, 44}, {685, 273}}</string>
1214 <reference key="NSSuperview" ref="439893737"/>
1215 <reference key="NSWindow"/>
1216 <bool key="NSIsVertical">YES</bool>
1217 <int key="NSDividerStyle">2</int>
1218 <string key="NSAutosaveName">ipython1_console_workspace_split</string>
1219 </object>
1220 <object class="NSProgressIndicator" id="74807016">
1221 <reference key="NSNextResponder" ref="439893737"/>
1222 <int key="NSvFlags">1313</int>
1223 <object class="NSPSMatrix" key="NSDrawMatrix"/>
1224 <string key="NSFrame">{{689, 20}, {16, 16}}</string>
1225 <reference key="NSSuperview" ref="439893737"/>
1226 <reference key="NSWindow"/>
1227 <int key="NSpiFlags">28938</int>
1228 <double key="NSMinValue">1.600000e+01</double>
1229 <double key="NSMaxValue">1.000000e+02</double>
1230 </object>
1231 </object>
1232 <string key="NSFrameSize">{725, 337}</string>
1233 <reference key="NSSuperview"/>
1234 <reference key="NSWindow"/>
1235 </object>
1236 <string key="NSScreenRect">{{0, 0}, {1280, 778}}</string>
1237 <string key="NSFrameAutosaveName">ipython1_sandbox</string>
1238 </object>
1239 <object class="NSCustomObject" id="610635028">
1240 <string key="NSClassName" id="982950837">IPython1SandboxAppDelegate</string>
1241 </object>
1242 <object class="NSDictionaryController" id="808393665">
1243 <object class="NSMutableArray" key="NSDeclaredKeys">
1244 <bool key="EncodedWithXMLCoder">YES</bool>
1245 <string>keys</string>
1246 <string id="181461860">key</string>
1247 <string id="276523235">value</string>
1248 </object>
1249 <bool key="NSEditable">YES</bool>
1250 <bool key="NSAvoidsEmptySelection">YES</bool>
1251 <bool key="NSPreservesSelection">YES</bool>
1252 <bool key="NSSelectsInsertedObjects">YES</bool>
1253 <bool key="NSFilterRestrictsInsertion">YES</bool>
1254 <object class="NSArray" key="NSSortDescriptors">
1255 <bool key="EncodedWithXMLCoder">YES</bool>
1256 <object class="NSSortDescriptor">
1257 <reference key="NSKey" ref="181461860"/>
1258 <bool key="NSAscending">YES</bool>
1259 <string key="NSSelector">compare:</string>
1260 </object>
1261 </object>
1262 <bool key="NSClearsFilterPredicateOnInsertion">YES</bool>
1263 <reference key="NSInitialKey" ref="181461860"/>
1264 <reference key="NSInitialValue" ref="276523235"/>
1265 </object>
1266 <object class="NSCustomObject" id="631572152">
1267 <string key="NSClassName" id="695797635">IPythonCocoaController</string>
1268 </object>
1269 </object>
1270 <object class="IBObjectContainer" key="IBDocument.Objects">
1271 <object class="NSMutableArray" key="connectionRecords">
1272 <bool key="EncodedWithXMLCoder">YES</bool>
1273 <object class="IBConnectionRecord">
1274 <object class="IBActionConnection" key="connection">
1275 <string key="label">performMiniaturize:</string>
1276 <reference key="source" ref="1014"/>
1277 <reference key="destination" ref="1011231497"/>
1278 </object>
1279 <int key="connectionID">37</int>
1280 </object>
1281 <object class="IBConnectionRecord">
1282 <object class="IBActionConnection" key="connection">
1283 <string key="label">arrangeInFront:</string>
1284 <reference key="source" ref="1014"/>
1285 <reference key="destination" ref="625202149"/>
1286 </object>
1287 <int key="connectionID">39</int>
1288 </object>
1289 <object class="IBConnectionRecord">
1290 <object class="IBActionConnection" key="connection">
1291 <string key="label">print:</string>
1292 <reference key="source" ref="1014"/>
1293 <reference key="destination" ref="49223823"/>
1294 </object>
1295 <int key="connectionID">86</int>
1296 </object>
1297 <object class="IBConnectionRecord">
1298 <object class="IBActionConnection" key="connection">
1299 <string key="label">runPageLayout:</string>
1300 <reference key="source" ref="1014"/>
1301 <reference key="destination" ref="294629803"/>
1302 </object>
1303 <int key="connectionID">87</int>
1304 </object>
1305 <object class="IBConnectionRecord">
1306 <object class="IBActionConnection" key="connection">
1307 <string key="label">clearRecentDocuments:</string>
1308 <reference key="source" ref="1014"/>
1309 <reference key="destination" ref="759406840"/>
1310 </object>
1311 <int key="connectionID">127</int>
1312 </object>
1313 <object class="IBConnectionRecord">
1314 <object class="IBActionConnection" key="connection">
1315 <string key="label">orderFrontStandardAboutPanel:</string>
1316 <reference key="source" ref="1021"/>
1317 <reference key="destination" ref="238522557"/>
1318 </object>
1319 <int key="connectionID">142</int>
1320 </object>
1321 <object class="IBConnectionRecord">
1322 <object class="IBActionConnection" key="connection">
1323 <string key="label">performClose:</string>
1324 <reference key="source" ref="1014"/>
1325 <reference key="destination" ref="776162233"/>
1326 </object>
1327 <int key="connectionID">193</int>
1328 </object>
1329 <object class="IBConnectionRecord">
1330 <object class="IBActionConnection" key="connection">
1331 <string key="label">toggleContinuousSpellChecking:</string>
1332 <reference key="source" ref="1014"/>
1333 <reference key="destination" ref="948374510"/>
1334 </object>
1335 <int key="connectionID">222</int>
1336 </object>
1337 <object class="IBConnectionRecord">
1338 <object class="IBActionConnection" key="connection">
1339 <string key="label">undo:</string>
1340 <reference key="source" ref="1014"/>
1341 <reference key="destination" ref="1058277027"/>
1342 </object>
1343 <int key="connectionID">223</int>
1344 </object>
1345 <object class="IBConnectionRecord">
1346 <object class="IBActionConnection" key="connection">
1347 <string key="label">copy:</string>
1348 <reference key="source" ref="1014"/>
1349 <reference key="destination" ref="860595796"/>
1350 </object>
1351 <int key="connectionID">224</int>
1352 </object>
1353 <object class="IBConnectionRecord">
1354 <object class="IBActionConnection" key="connection">
1355 <string key="label">checkSpelling:</string>
1356 <reference key="source" ref="1014"/>
1357 <reference key="destination" ref="96193923"/>
1358 </object>
1359 <int key="connectionID">225</int>
1360 </object>
1361 <object class="IBConnectionRecord">
1362 <object class="IBActionConnection" key="connection">
1363 <string key="label">paste:</string>
1364 <reference key="source" ref="1014"/>
1365 <reference key="destination" ref="29853731"/>
1366 </object>
1367 <int key="connectionID">226</int>
1368 </object>
1369 <object class="IBConnectionRecord">
1370 <object class="IBActionConnection" key="connection">
1371 <string key="label">stopSpeaking:</string>
1372 <reference key="source" ref="1014"/>
1373 <reference key="destination" ref="680220178"/>
1374 </object>
1375 <int key="connectionID">227</int>
1376 </object>
1377 <object class="IBConnectionRecord">
1378 <object class="IBActionConnection" key="connection">
1379 <string key="label">cut:</string>
1380 <reference key="source" ref="1014"/>
1381 <reference key="destination" ref="296257095"/>
1382 </object>
1383 <int key="connectionID">228</int>
1384 </object>
1385 <object class="IBConnectionRecord">
1386 <object class="IBActionConnection" key="connection">
1387 <string key="label">showGuessPanel:</string>
1388 <reference key="source" ref="1014"/>
1389 <reference key="destination" ref="679648819"/>
1390 </object>
1391 <int key="connectionID">230</int>
1392 </object>
1393 <object class="IBConnectionRecord">
1394 <object class="IBActionConnection" key="connection">
1395 <string key="label">redo:</string>
1396 <reference key="source" ref="1014"/>
1397 <reference key="destination" ref="790794224"/>
1398 </object>
1399 <int key="connectionID">231</int>
1400 </object>
1401 <object class="IBConnectionRecord">
1402 <object class="IBActionConnection" key="connection">
1403 <string key="label">selectAll:</string>
1404 <reference key="source" ref="1014"/>
1405 <reference key="destination" ref="583158037"/>
1406 </object>
1407 <int key="connectionID">232</int>
1408 </object>
1409 <object class="IBConnectionRecord">
1410 <object class="IBActionConnection" key="connection">
1411 <string key="label">startSpeaking:</string>
1412 <reference key="source" ref="1014"/>
1413 <reference key="destination" ref="731782645"/>
1414 </object>
1415 <int key="connectionID">233</int>
1416 </object>
1417 <object class="IBConnectionRecord">
1418 <object class="IBActionConnection" key="connection">
1419 <string key="label">delete:</string>
1420 <reference key="source" ref="1014"/>
1421 <reference key="destination" ref="437104165"/>
1422 </object>
1423 <int key="connectionID">235</int>
1424 </object>
1425 <object class="IBConnectionRecord">
1426 <object class="IBActionConnection" key="connection">
1427 <string key="label">performZoom:</string>
1428 <reference key="source" ref="1014"/>
1429 <reference key="destination" ref="575023229"/>
1430 </object>
1431 <int key="connectionID">240</int>
1432 </object>
1433 <object class="IBConnectionRecord">
1434 <object class="IBActionConnection" key="connection">
1435 <string key="label">performFindPanelAction:</string>
1436 <reference key="source" ref="1014"/>
1437 <reference key="destination" ref="447796847"/>
1438 </object>
1439 <int key="connectionID">241</int>
1440 </object>
1441 <object class="IBConnectionRecord">
1442 <object class="IBActionConnection" key="connection">
1443 <string key="label">centerSelectionInVisibleArea:</string>
1444 <reference key="source" ref="1014"/>
1445 <reference key="destination" ref="88285865"/>
1446 </object>
1447 <int key="connectionID">245</int>
1448 </object>
1449 <object class="IBConnectionRecord">
1450 <object class="IBActionConnection" key="connection">
1451 <string key="label">toggleGrammarChecking:</string>
1452 <reference key="source" ref="1014"/>
1453 <reference key="destination" ref="967646866"/>
1454 </object>
1455 <int key="connectionID">347</int>
1456 </object>
1457 <object class="IBConnectionRecord">
1458 <object class="IBActionConnection" key="connection">
1459 <string key="label">toggleSmartInsertDelete:</string>
1460 <reference key="source" ref="1014"/>
1461 <reference key="destination" ref="605118523"/>
1462 </object>
1463 <int key="connectionID">355</int>
1464 </object>
1465 <object class="IBConnectionRecord">
1466 <object class="IBActionConnection" key="connection">
1467 <string key="label">toggleAutomaticQuoteSubstitution:</string>
1468 <reference key="source" ref="1014"/>
1469 <reference key="destination" ref="197661976"/>
1470 </object>
1471 <int key="connectionID">356</int>
1472 </object>
1473 <object class="IBConnectionRecord">
1474 <object class="IBActionConnection" key="connection">
1475 <string key="label">toggleAutomaticLinkDetection:</string>
1476 <reference key="source" ref="1014"/>
1477 <reference key="destination" ref="708854459"/>
1478 </object>
1479 <int key="connectionID">357</int>
1480 </object>
1481 <object class="IBConnectionRecord">
1482 <object class="IBActionConnection" key="connection">
1483 <string key="label">showHelp:</string>
1484 <reference key="source" ref="1014"/>
1485 <reference key="destination" ref="238773614"/>
1486 </object>
1487 <int key="connectionID">360</int>
1488 </object>
1489 <object class="IBConnectionRecord">
1490 <object class="IBActionConnection" key="connection">
1491 <string key="label">orderFrontColorPanel:</string>
1492 <reference key="source" ref="1014"/>
1493 <reference key="destination" ref="1028416764"/>
1494 </object>
1495 <int key="connectionID">361</int>
1496 </object>
1497 <object class="IBConnectionRecord">
1498 <object class="IBActionConnection" key="connection">
1499 <string key="label">saveDocument:</string>
1500 <reference key="source" ref="1014"/>
1501 <reference key="destination" ref="1023925487"/>
1502 </object>
1503 <int key="connectionID">362</int>
1504 </object>
1505 <object class="IBConnectionRecord">
1506 <object class="IBActionConnection" key="connection">
1507 <string key="label">saveDocumentAs:</string>
1508 <reference key="source" ref="1014"/>
1509 <reference key="destination" ref="117038363"/>
1510 </object>
1511 <int key="connectionID">363</int>
1512 </object>
1513 <object class="IBConnectionRecord">
1514 <object class="IBActionConnection" key="connection">
1515 <string key="label">revertDocumentToSaved:</string>
1516 <reference key="source" ref="1014"/>
1517 <reference key="destination" ref="579971712"/>
1518 </object>
1519 <int key="connectionID">364</int>
1520 </object>
1521 <object class="IBConnectionRecord">
1522 <object class="IBActionConnection" key="connection">
1523 <string key="label">runToolbarCustomizationPalette:</string>
1524 <reference key="source" ref="1014"/>
1525 <reference key="destination" ref="237841660"/>
1526 </object>
1527 <int key="connectionID">365</int>
1528 </object>
1529 <object class="IBConnectionRecord">
1530 <object class="IBActionConnection" key="connection">
1531 <string key="label">toggleToolbarShown:</string>
1532 <reference key="source" ref="1014"/>
1533 <reference key="destination" ref="102151532"/>
1534 </object>
1535 <int key="connectionID">366</int>
1536 </object>
1537 <object class="IBConnectionRecord">
1538 <object class="IBActionConnection" key="connection">
1539 <string key="label">hide:</string>
1540 <reference key="source" ref="1014"/>
1541 <reference key="destination" ref="755159360"/>
1542 </object>
1543 <int key="connectionID">367</int>
1544 </object>
1545 <object class="IBConnectionRecord">
1546 <object class="IBActionConnection" key="connection">
1547 <string key="label">hideOtherApplications:</string>
1548 <reference key="source" ref="1014"/>
1549 <reference key="destination" ref="342932134"/>
1550 </object>
1551 <int key="connectionID">368</int>
1552 </object>
1553 <object class="IBConnectionRecord">
1554 <object class="IBActionConnection" key="connection">
1555 <string key="label">terminate:</string>
1556 <reference key="source" ref="1014"/>
1557 <reference key="destination" ref="632727374"/>
1558 </object>
1559 <int key="connectionID">369</int>
1560 </object>
1561 <object class="IBConnectionRecord">
1562 <object class="IBActionConnection" key="connection">
1563 <string key="label">unhideAllApplications:</string>
1564 <reference key="source" ref="1014"/>
1565 <reference key="destination" ref="908899353"/>
1566 </object>
1567 <int key="connectionID">370</int>
1568 </object>
1569 <object class="IBConnectionRecord">
1570 <object class="IBOutletConnection" key="connection">
1571 <string key="label" id="606168085">delegate</string>
1572 <reference key="source" ref="1050"/>
1573 <reference key="destination" ref="610635028"/>
1574 </object>
1575 <int key="connectionID">374</int>
1576 </object>
1577 <object class="IBConnectionRecord">
1578 <object class="IBBindingConnection" key="connection">
1579 <string key="label" id="187454546">contentDictionary: userNS</string>
1580 <reference key="source" ref="808393665"/>
1581 <reference key="destination" ref="631572152"/>
1582 <object class="NSNibBindingConnector" key="connector">
1583 <reference key="NSSource" ref="808393665"/>
1584 <reference key="NSDestination" ref="631572152"/>
1585 <reference key="NSLabel" ref="187454546"/>
1586 <string key="NSBinding">contentDictionary</string>
1587 <string key="NSKeyPath">userNS</string>
1588 <int key="NSNibBindingConnectorVersion">2</int>
1589 </object>
1590 </object>
1591 <int key="connectionID">424</int>
1592 </object>
1593 <object class="IBConnectionRecord">
1594 <object class="IBBindingConnection" key="connection">
1595 <string key="label" id="688370141">value: arrangedObjects.value</string>
1596 <reference key="source" ref="857054683"/>
1597 <reference key="destination" ref="808393665"/>
1598 <object class="NSNibBindingConnector" key="connector">
1599 <reference key="NSSource" ref="857054683"/>
1600 <reference key="NSDestination" ref="808393665"/>
1601 <reference key="NSLabel" ref="688370141"/>
1602 <reference key="NSBinding" ref="276523235"/>
1603 <string key="NSKeyPath">arrangedObjects.value</string>
1604 <int key="NSNibBindingConnectorVersion">2</int>
1605 </object>
1606 </object>
1607 <int key="connectionID">427</int>
1608 </object>
1609 <object class="IBConnectionRecord">
1610 <object class="IBBindingConnection" key="connection">
1611 <string key="label" id="764859820">value: arrangedObjects.key</string>
1612 <reference key="source" ref="920426212"/>
1613 <reference key="destination" ref="808393665"/>
1614 <object class="NSNibBindingConnector" key="connector">
1615 <reference key="NSSource" ref="920426212"/>
1616 <reference key="NSDestination" ref="808393665"/>
1617 <reference key="NSLabel" ref="764859820"/>
1618 <reference key="NSBinding" ref="276523235"/>
1619 <string key="NSKeyPath">arrangedObjects.key</string>
1620 <int key="NSNibBindingConnectorVersion">2</int>
1621 </object>
1622 </object>
1623 <int key="connectionID">428</int>
1624 </object>
1625 <object class="IBConnectionRecord">
1626 <object class="IBOutletConnection" key="connection">
1627 <reference key="label" ref="606168085"/>
1628 <reference key="source" ref="972006081"/>
1629 <reference key="destination" ref="631572152"/>
1630 </object>
1631 <int key="connectionID">429</int>
1632 </object>
1633 <object class="IBConnectionRecord">
1634 <object class="IBBindingConnection" key="connection">
1635 <string key="label" id="97087091">animate: waitingForEngine</string>
1636 <reference key="source" ref="74807016"/>
1637 <reference key="destination" ref="631572152"/>
1638 <object class="NSNibBindingConnector" key="connector">
1639 <reference key="NSSource" ref="74807016"/>
1640 <reference key="NSDestination" ref="631572152"/>
1641 <reference key="NSLabel" ref="97087091"/>
1642 <string key="NSBinding">animate</string>
1643 <string key="NSKeyPath">waitingForEngine</string>
1644 <int key="NSNibBindingConnectorVersion">2</int>
1645 </object>
1646 </object>
1647 <int key="connectionID">437</int>
1648 </object>
1649 <object class="IBConnectionRecord">
1650 <object class="IBBindingConnection" key="connection">
1651 <string key="label" id="289275654">filterPredicate: workspaceFilterPredicate</string>
1652 <reference key="source" ref="808393665"/>
1653 <reference key="destination" ref="610635028"/>
1654 <object class="NSNibBindingConnector" key="connector">
1655 <reference key="NSSource" ref="808393665"/>
1656 <reference key="NSDestination" ref="610635028"/>
1657 <reference key="NSLabel" ref="289275654"/>
1658 <string key="NSBinding">filterPredicate</string>
1659 <string key="NSKeyPath">workspaceFilterPredicate</string>
1660 <int key="NSNibBindingConnectorVersion">2</int>
1661 </object>
1662 </object>
1663 <int key="connectionID">440</int>
1664 </object>
1665 <object class="IBConnectionRecord">
1666 <object class="IBOutletConnection" key="connection">
1667 <string key="label">ipythonController</string>
1668 <reference key="source" ref="610635028"/>
1669 <reference key="destination" ref="631572152"/>
1670 </object>
1671 <int key="connectionID">441</int>
1672 </object>
1673 <object class="IBConnectionRecord">
1674 <object class="IBOutletConnection" key="connection">
1675 <string key="label" id="684042788">textView</string>
1676 <reference key="source" ref="631572152"/>
1677 <reference key="destination" ref="163417131"/>
1678 </object>
1679 <int key="connectionID">444</int>
1680 </object>
1681 <object class="IBConnectionRecord">
1682 <object class="IBOutletConnection" key="connection">
1683 <string key="label">initialFirstResponder</string>
1684 <reference key="source" ref="972006081"/>
1685 <reference key="destination" ref="163417131"/>
1686 </object>
1687 <int key="connectionID">445</int>
1688 </object>
1689 </object>
1690 <object class="IBMutableOrderedSet" key="objectRecords">
1691 <object class="NSArray" key="orderedObjects">
1692 <bool key="EncodedWithXMLCoder">YES</bool>
1693 <object class="IBObjectRecord">
1694 <int key="objectID">0</int>
1695 <object class="NSArray" key="object" id="1049">
1696 <bool key="EncodedWithXMLCoder">YES</bool>
1697 </object>
1698 <reference key="children" ref="1048"/>
1699 <nil key="parent"/>
1700 </object>
1701 <object class="IBObjectRecord">
1702 <int key="objectID">-2</int>
1703 <reference key="object" ref="1021"/>
1704 <reference key="parent" ref="1049"/>
1705 <string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
1706 </object>
1707 <object class="IBObjectRecord">
1708 <int key="objectID">-1</int>
1709 <reference key="object" ref="1014"/>
1710 <reference key="parent" ref="1049"/>
1711 <string key="objectName">First Responder</string>
1712 </object>
1713 <object class="IBObjectRecord">
1714 <int key="objectID">-3</int>
1715 <reference key="object" ref="1050"/>
1716 <reference key="parent" ref="1049"/>
1717 <string key="objectName">Application</string>
1718 </object>
1719 <object class="IBObjectRecord">
1720 <int key="objectID">29</int>
1721 <reference key="object" ref="649796088"/>
1722 <object class="NSMutableArray" key="children">
1723 <bool key="EncodedWithXMLCoder">YES</bool>
1724 <reference ref="713487014"/>
1725 <reference ref="694149608"/>
1726 <reference ref="391199113"/>
1727 <reference ref="952259628"/>
1728 <reference ref="379814623"/>
1729 <reference ref="586577488"/>
1730 <reference ref="626404410"/>
1731 </object>
1732 <reference key="parent" ref="1049"/>
1733 <string key="objectName">MainMenu</string>
1734 </object>
1735 <object class="IBObjectRecord">
1736 <int key="objectID">19</int>
1737 <reference key="object" ref="713487014"/>
1738 <object class="NSMutableArray" key="children">
1739 <bool key="EncodedWithXMLCoder">YES</bool>
1740 <reference ref="835318025"/>
1741 </object>
1742 <reference key="parent" ref="649796088"/>
1743 </object>
1744 <object class="IBObjectRecord">
1745 <int key="objectID">56</int>
1746 <reference key="object" ref="694149608"/>
1747 <object class="NSMutableArray" key="children">
1748 <bool key="EncodedWithXMLCoder">YES</bool>
1749 <reference ref="110575045"/>
1750 </object>
1751 <reference key="parent" ref="649796088"/>
1752 </object>
1753 <object class="IBObjectRecord">
1754 <int key="objectID">103</int>
1755 <reference key="object" ref="391199113"/>
1756 <object class="NSMutableArray" key="children">
1757 <bool key="EncodedWithXMLCoder">YES</bool>
1758 <reference ref="374024848"/>
1759 </object>
1760 <reference key="parent" ref="649796088"/>
1761 <string key="objectName" id="508169456">1</string>
1762 </object>
1763 <object class="IBObjectRecord">
1764 <int key="objectID">217</int>
1765 <reference key="object" ref="952259628"/>
1766 <object class="NSMutableArray" key="children">
1767 <bool key="EncodedWithXMLCoder">YES</bool>
1768 <reference ref="789758025"/>
1769 </object>
1770 <reference key="parent" ref="649796088"/>
1771 </object>
1772 <object class="IBObjectRecord">
1773 <int key="objectID">83</int>
1774 <reference key="object" ref="379814623"/>
1775 <object class="NSMutableArray" key="children">
1776 <bool key="EncodedWithXMLCoder">YES</bool>
1777 <reference ref="720053764"/>
1778 </object>
1779 <reference key="parent" ref="649796088"/>
1780 </object>
1781 <object class="IBObjectRecord">
1782 <int key="objectID">81</int>
1783 <reference key="object" ref="720053764"/>
1784 <object class="NSMutableArray" key="children">
1785 <bool key="EncodedWithXMLCoder">YES</bool>
1786 <reference ref="1023925487"/>
1787 <reference ref="117038363"/>
1788 <reference ref="49223823"/>
1789 <reference ref="722745758"/>
1790 <reference ref="705341025"/>
1791 <reference ref="1025936716"/>
1792 <reference ref="294629803"/>
1793 <reference ref="776162233"/>
1794 <reference ref="425164168"/>
1795 <reference ref="579971712"/>
1796 <reference ref="1010469920"/>
1797 </object>
1798 <reference key="parent" ref="379814623"/>
1799 </object>
1800 <object class="IBObjectRecord">
1801 <int key="objectID">75</int>
1802 <reference key="object" ref="1023925487"/>
1803 <reference key="parent" ref="720053764"/>
1804 <string key="objectName">3</string>
1805 </object>
1806 <object class="IBObjectRecord">
1807 <int key="objectID">80</int>
1808 <reference key="object" ref="117038363"/>
1809 <reference key="parent" ref="720053764"/>
1810 <string key="objectName">8</string>
1811 </object>
1812 <object class="IBObjectRecord">
1813 <int key="objectID">78</int>
1814 <reference key="object" ref="49223823"/>
1815 <reference key="parent" ref="720053764"/>
1816 <string key="objectName">6</string>
1817 </object>
1818 <object class="IBObjectRecord">
1819 <int key="objectID">72</int>
1820 <reference key="object" ref="722745758"/>
1821 <reference key="parent" ref="720053764"/>
1822 </object>
1823 <object class="IBObjectRecord">
1824 <int key="objectID">82</int>
1825 <reference key="object" ref="705341025"/>
1826 <reference key="parent" ref="720053764"/>
1827 <string key="objectName">9</string>
1828 </object>
1829 <object class="IBObjectRecord">
1830 <int key="objectID">124</int>
1831 <reference key="object" ref="1025936716"/>
1832 <object class="NSMutableArray" key="children">
1833 <bool key="EncodedWithXMLCoder">YES</bool>
1834 <reference ref="1065607017"/>
1835 </object>
1836 <reference key="parent" ref="720053764"/>
1837 </object>
1838 <object class="IBObjectRecord">
1839 <int key="objectID">77</int>
1840 <reference key="object" ref="294629803"/>
1841 <reference key="parent" ref="720053764"/>
1842 <string key="objectName">5</string>
1843 </object>
1844 <object class="IBObjectRecord">
1845 <int key="objectID">73</int>
1846 <reference key="object" ref="776162233"/>
1847 <reference key="parent" ref="720053764"/>
1848 <reference key="objectName" ref="508169456"/>
1849 </object>
1850 <object class="IBObjectRecord">
1851 <int key="objectID">79</int>
1852 <reference key="object" ref="425164168"/>
1853 <reference key="parent" ref="720053764"/>
1854 <string key="objectName">7</string>
1855 </object>
1856 <object class="IBObjectRecord">
1857 <int key="objectID">112</int>
1858 <reference key="object" ref="579971712"/>
1859 <reference key="parent" ref="720053764"/>
1860 <string key="objectName">10</string>
1861 </object>
1862 <object class="IBObjectRecord">
1863 <int key="objectID">74</int>
1864 <reference key="object" ref="1010469920"/>
1865 <reference key="parent" ref="720053764"/>
1866 <string key="objectName" id="464456376">2</string>
1867 </object>
1868 <object class="IBObjectRecord">
1869 <int key="objectID">125</int>
1870 <reference key="object" ref="1065607017"/>
1871 <object class="NSMutableArray" key="children">
1872 <bool key="EncodedWithXMLCoder">YES</bool>
1873 <reference ref="759406840"/>
1874 </object>
1875 <reference key="parent" ref="1025936716"/>
1876 </object>
1877 <object class="IBObjectRecord">
1878 <int key="objectID">126</int>
1879 <reference key="object" ref="759406840"/>
1880 <reference key="parent" ref="1065607017"/>
1881 </object>
1882 <object class="IBObjectRecord">
1883 <int key="objectID">205</int>
1884 <reference key="object" ref="789758025"/>
1885 <object class="NSMutableArray" key="children">
1886 <bool key="EncodedWithXMLCoder">YES</bool>
1887 <reference ref="437104165"/>
1888 <reference ref="583158037"/>
1889 <reference ref="1058277027"/>
1890 <reference ref="212016141"/>
1891 <reference ref="296257095"/>
1892 <reference ref="29853731"/>
1893 <reference ref="860595796"/>
1894 <reference ref="1040322652"/>
1895 <reference ref="790794224"/>
1896 <reference ref="892235320"/>
1897 <reference ref="972420730"/>
1898 <reference ref="676164635"/>
1899 <reference ref="507821607"/>
1900 </object>
1901 <reference key="parent" ref="952259628"/>
1902 </object>
1903 <object class="IBObjectRecord">
1904 <int key="objectID">202</int>
1905 <reference key="object" ref="437104165"/>
1906 <reference key="parent" ref="789758025"/>
1907 </object>
1908 <object class="IBObjectRecord">
1909 <int key="objectID">198</int>
1910 <reference key="object" ref="583158037"/>
1911 <reference key="parent" ref="789758025"/>
1912 </object>
1913 <object class="IBObjectRecord">
1914 <int key="objectID">207</int>
1915 <reference key="object" ref="1058277027"/>
1916 <reference key="parent" ref="789758025"/>
1917 </object>
1918 <object class="IBObjectRecord">
1919 <int key="objectID">214</int>
1920 <reference key="object" ref="212016141"/>
1921 <reference key="parent" ref="789758025"/>
1922 </object>
1923 <object class="IBObjectRecord">
1924 <int key="objectID">199</int>
1925 <reference key="object" ref="296257095"/>
1926 <reference key="parent" ref="789758025"/>
1927 </object>
1928 <object class="IBObjectRecord">
1929 <int key="objectID">203</int>
1930 <reference key="object" ref="29853731"/>
1931 <reference key="parent" ref="789758025"/>
1932 </object>
1933 <object class="IBObjectRecord">
1934 <int key="objectID">197</int>
1935 <reference key="object" ref="860595796"/>
1936 <reference key="parent" ref="789758025"/>
1937 </object>
1938 <object class="IBObjectRecord">
1939 <int key="objectID">206</int>
1940 <reference key="object" ref="1040322652"/>
1941 <reference key="parent" ref="789758025"/>
1942 </object>
1943 <object class="IBObjectRecord">
1944 <int key="objectID">215</int>
1945 <reference key="object" ref="790794224"/>
1946 <reference key="parent" ref="789758025"/>
1947 </object>
1948 <object class="IBObjectRecord">
1949 <int key="objectID">218</int>
1950 <reference key="object" ref="892235320"/>
1951 <object class="NSMutableArray" key="children">
1952 <bool key="EncodedWithXMLCoder">YES</bool>
1953 <reference ref="963351320"/>
1954 </object>
1955 <reference key="parent" ref="789758025"/>
1956 </object>
1957 <object class="IBObjectRecord">
1958 <int key="objectID">216</int>
1959 <reference key="object" ref="972420730"/>
1960 <object class="NSMutableArray" key="children">
1961 <bool key="EncodedWithXMLCoder">YES</bool>
1962 <reference ref="769623530"/>
1963 </object>
1964 <reference key="parent" ref="789758025"/>
1965 </object>
1966 <object class="IBObjectRecord">
1967 <int key="objectID">200</int>
1968 <reference key="object" ref="769623530"/>
1969 <object class="NSMutableArray" key="children">
1970 <bool key="EncodedWithXMLCoder">YES</bool>
1971 <reference ref="948374510"/>
1972 <reference ref="96193923"/>
1973 <reference ref="679648819"/>
1974 <reference ref="967646866"/>
1975 </object>
1976 <reference key="parent" ref="972420730"/>
1977 </object>
1978 <object class="IBObjectRecord">
1979 <int key="objectID">219</int>
1980 <reference key="object" ref="948374510"/>
1981 <reference key="parent" ref="769623530"/>
1982 </object>
1983 <object class="IBObjectRecord">
1984 <int key="objectID">201</int>
1985 <reference key="object" ref="96193923"/>
1986 <reference key="parent" ref="769623530"/>
1987 </object>
1988 <object class="IBObjectRecord">
1989 <int key="objectID">204</int>
1990 <reference key="object" ref="679648819"/>
1991 <reference key="parent" ref="769623530"/>
1992 </object>
1993 <object class="IBObjectRecord">
1994 <int key="objectID">220</int>
1995 <reference key="object" ref="963351320"/>
1996 <object class="NSMutableArray" key="children">
1997 <bool key="EncodedWithXMLCoder">YES</bool>
1998 <reference ref="270902937"/>
1999 <reference ref="88285865"/>
2000 <reference ref="159080638"/>
2001 <reference ref="326711663"/>
2002 <reference ref="447796847"/>
2003 </object>
2004 <reference key="parent" ref="892235320"/>
2005 </object>
2006 <object class="IBObjectRecord">
2007 <int key="objectID">213</int>
2008 <reference key="object" ref="270902937"/>
2009 <reference key="parent" ref="963351320"/>
2010 </object>
2011 <object class="IBObjectRecord">
2012 <int key="objectID">210</int>
2013 <reference key="object" ref="88285865"/>
2014 <reference key="parent" ref="963351320"/>
2015 </object>
2016 <object class="IBObjectRecord">
2017 <int key="objectID">221</int>
2018 <reference key="object" ref="159080638"/>
2019 <reference key="parent" ref="963351320"/>
2020 </object>
2021 <object class="IBObjectRecord">
2022 <int key="objectID">208</int>
2023 <reference key="object" ref="326711663"/>
2024 <reference key="parent" ref="963351320"/>
2025 </object>
2026 <object class="IBObjectRecord">
2027 <int key="objectID">209</int>
2028 <reference key="object" ref="447796847"/>
2029 <reference key="parent" ref="963351320"/>
2030 </object>
2031 <object class="IBObjectRecord">
2032 <int key="objectID">106</int>
2033 <reference key="object" ref="374024848"/>
2034 <object class="NSMutableArray" key="children">
2035 <bool key="EncodedWithXMLCoder">YES</bool>
2036 <reference ref="238773614"/>
2037 </object>
2038 <reference key="parent" ref="391199113"/>
2039 <reference key="objectName" ref="464456376"/>
2040 </object>
2041 <object class="IBObjectRecord">
2042 <int key="objectID">111</int>
2043 <reference key="object" ref="238773614"/>
2044 <reference key="parent" ref="374024848"/>
2045 </object>
2046 <object class="IBObjectRecord">
2047 <int key="objectID">57</int>
2048 <reference key="object" ref="110575045"/>
2049 <object class="NSMutableArray" key="children">
2050 <bool key="EncodedWithXMLCoder">YES</bool>
2051 <reference ref="238522557"/>
2052 <reference ref="755159360"/>
2053 <reference ref="908899353"/>
2054 <reference ref="632727374"/>
2055 <reference ref="646227648"/>
2056 <reference ref="609285721"/>
2057 <reference ref="481834944"/>
2058 <reference ref="304266470"/>
2059 <reference ref="1046388886"/>
2060 <reference ref="1056857174"/>
2061 <reference ref="342932134"/>
2062 </object>
2063 <reference key="parent" ref="694149608"/>
2064 </object>
2065 <object class="IBObjectRecord">
2066 <int key="objectID">58</int>
2067 <reference key="object" ref="238522557"/>
2068 <reference key="parent" ref="110575045"/>
2069 </object>
2070 <object class="IBObjectRecord">
2071 <int key="objectID">134</int>
2072 <reference key="object" ref="755159360"/>
2073 <reference key="parent" ref="110575045"/>
2074 </object>
2075 <object class="IBObjectRecord">
2076 <int key="objectID">150</int>
2077 <reference key="object" ref="908899353"/>
2078 <reference key="parent" ref="110575045"/>
2079 </object>
2080 <object class="IBObjectRecord">
2081 <int key="objectID">136</int>
2082 <reference key="object" ref="632727374"/>
2083 <reference key="parent" ref="110575045"/>
2084 <string key="objectName">1111</string>
2085 </object>
2086 <object class="IBObjectRecord">
2087 <int key="objectID">144</int>
2088 <reference key="object" ref="646227648"/>
2089 <reference key="parent" ref="110575045"/>
2090 </object>
2091 <object class="IBObjectRecord">
2092 <int key="objectID">129</int>
2093 <reference key="object" ref="609285721"/>
2094 <reference key="parent" ref="110575045"/>
2095 <string key="objectName">121</string>
2096 </object>
2097 <object class="IBObjectRecord">
2098 <int key="objectID">143</int>
2099 <reference key="object" ref="481834944"/>
2100 <reference key="parent" ref="110575045"/>
2101 </object>
2102 <object class="IBObjectRecord">
2103 <int key="objectID">236</int>
2104 <reference key="object" ref="304266470"/>
2105 <reference key="parent" ref="110575045"/>
2106 </object>
2107 <object class="IBObjectRecord">
2108 <int key="objectID">131</int>
2109 <reference key="object" ref="1046388886"/>
2110 <object class="NSMutableArray" key="children">
2111 <bool key="EncodedWithXMLCoder">YES</bool>
2112 <reference ref="752062318"/>
2113 </object>
2114 <reference key="parent" ref="110575045"/>
2115 </object>
2116 <object class="IBObjectRecord">
2117 <int key="objectID">149</int>
2118 <reference key="object" ref="1056857174"/>
2119 <reference key="parent" ref="110575045"/>
2120 </object>
2121 <object class="IBObjectRecord">
2122 <int key="objectID">145</int>
2123 <reference key="object" ref="342932134"/>
2124 <reference key="parent" ref="110575045"/>
2125 </object>
2126 <object class="IBObjectRecord">
2127 <int key="objectID">130</int>
2128 <reference key="object" ref="752062318"/>
2129 <reference key="parent" ref="1046388886"/>
2130 </object>
2131 <object class="IBObjectRecord">
2132 <int key="objectID">24</int>
2133 <reference key="object" ref="835318025"/>
2134 <object class="NSMutableArray" key="children">
2135 <bool key="EncodedWithXMLCoder">YES</bool>
2136 <reference ref="299356726"/>
2137 <reference ref="625202149"/>
2138 <reference ref="575023229"/>
2139 <reference ref="1011231497"/>
2140 </object>
2141 <reference key="parent" ref="713487014"/>
2142 </object>
2143 <object class="IBObjectRecord">
2144 <int key="objectID">92</int>
2145 <reference key="object" ref="299356726"/>
2146 <reference key="parent" ref="835318025"/>
2147 </object>
2148 <object class="IBObjectRecord">
2149 <int key="objectID">5</int>
2150 <reference key="object" ref="625202149"/>
2151 <reference key="parent" ref="835318025"/>
2152 </object>
2153 <object class="IBObjectRecord">
2154 <int key="objectID">239</int>
2155 <reference key="object" ref="575023229"/>
2156 <reference key="parent" ref="835318025"/>
2157 </object>
2158 <object class="IBObjectRecord">
2159 <int key="objectID">23</int>
2160 <reference key="object" ref="1011231497"/>
2161 <reference key="parent" ref="835318025"/>
2162 </object>
2163 <object class="IBObjectRecord">
2164 <int key="objectID">295</int>
2165 <reference key="object" ref="586577488"/>
2166 <object class="NSMutableArray" key="children">
2167 <bool key="EncodedWithXMLCoder">YES</bool>
2168 <reference ref="466310130"/>
2169 </object>
2170 <reference key="parent" ref="649796088"/>
2171 </object>
2172 <object class="IBObjectRecord">
2173 <int key="objectID">296</int>
2174 <reference key="object" ref="466310130"/>
2175 <object class="NSMutableArray" key="children">
2176 <bool key="EncodedWithXMLCoder">YES</bool>
2177 <reference ref="102151532"/>
2178 <reference ref="237841660"/>
2179 </object>
2180 <reference key="parent" ref="586577488"/>
2181 </object>
2182 <object class="IBObjectRecord">
2183 <int key="objectID">297</int>
2184 <reference key="object" ref="102151532"/>
2185 <reference key="parent" ref="466310130"/>
2186 </object>
2187 <object class="IBObjectRecord">
2188 <int key="objectID">298</int>
2189 <reference key="object" ref="237841660"/>
2190 <reference key="parent" ref="466310130"/>
2191 </object>
2192 <object class="IBObjectRecord">
2193 <int key="objectID">299</int>
2194 <reference key="object" ref="626404410"/>
2195 <object class="NSMutableArray" key="children">
2196 <bool key="EncodedWithXMLCoder">YES</bool>
2197 <reference ref="502084290"/>
2198 </object>
2199 <reference key="parent" ref="649796088"/>
2200 </object>
2201 <object class="IBObjectRecord">
2202 <int key="objectID">300</int>
2203 <reference key="object" ref="502084290"/>
2204 <object class="NSMutableArray" key="children">
2205 <bool key="EncodedWithXMLCoder">YES</bool>
2206 <reference ref="519768076"/>
2207 <reference ref="1028416764"/>
2208 </object>
2209 <reference key="parent" ref="626404410"/>
2210 </object>
2211 <object class="IBObjectRecord">
2212 <int key="objectID">344</int>
2213 <reference key="object" ref="519768076"/>
2214 <reference key="parent" ref="502084290"/>
2215 </object>
2216 <object class="IBObjectRecord">
2217 <int key="objectID">345</int>
2218 <reference key="object" ref="1028416764"/>
2219 <reference key="parent" ref="502084290"/>
2220 </object>
2221 <object class="IBObjectRecord">
2222 <int key="objectID">211</int>
2223 <reference key="object" ref="676164635"/>
2224 <object class="NSMutableArray" key="children">
2225 <bool key="EncodedWithXMLCoder">YES</bool>
2226 <reference ref="785027613"/>
2227 </object>
2228 <reference key="parent" ref="789758025"/>
2229 </object>
2230 <object class="IBObjectRecord">
2231 <int key="objectID">212</int>
2232 <reference key="object" ref="785027613"/>
2233 <object class="NSMutableArray" key="children">
2234 <bool key="EncodedWithXMLCoder">YES</bool>
2235 <reference ref="680220178"/>
2236 <reference ref="731782645"/>
2237 </object>
2238 <reference key="parent" ref="676164635"/>
2239 </object>
2240 <object class="IBObjectRecord">
2241 <int key="objectID">195</int>
2242 <reference key="object" ref="680220178"/>
2243 <reference key="parent" ref="785027613"/>
2244 </object>
2245 <object class="IBObjectRecord">
2246 <int key="objectID">196</int>
2247 <reference key="object" ref="731782645"/>
2248 <reference key="parent" ref="785027613"/>
2249 </object>
2250 <object class="IBObjectRecord">
2251 <int key="objectID">346</int>
2252 <reference key="object" ref="967646866"/>
2253 <reference key="parent" ref="769623530"/>
2254 </object>
2255 <object class="IBObjectRecord">
2256 <int key="objectID">348</int>
2257 <reference key="object" ref="507821607"/>
2258 <object class="NSMutableArray" key="children">
2259 <bool key="EncodedWithXMLCoder">YES</bool>
2260 <reference ref="698887838"/>
2261 </object>
2262 <reference key="parent" ref="789758025"/>
2263 </object>
2264 <object class="IBObjectRecord">
2265 <int key="objectID">349</int>
2266 <reference key="object" ref="698887838"/>
2267 <object class="NSMutableArray" key="children">
2268 <bool key="EncodedWithXMLCoder">YES</bool>
2269 <reference ref="605118523"/>
2270 <reference ref="197661976"/>
2271 <reference ref="708854459"/>
2272 </object>
2273 <reference key="parent" ref="507821607"/>
2274 </object>
2275 <object class="IBObjectRecord">
2276 <int key="objectID">350</int>
2277 <reference key="object" ref="605118523"/>
2278 <reference key="parent" ref="698887838"/>
2279 </object>
2280 <object class="IBObjectRecord">
2281 <int key="objectID">351</int>
2282 <reference key="object" ref="197661976"/>
2283 <reference key="parent" ref="698887838"/>
2284 </object>
2285 <object class="IBObjectRecord">
2286 <int key="objectID">354</int>
2287 <reference key="object" ref="708854459"/>
2288 <reference key="parent" ref="698887838"/>
2289 </object>
2290 <object class="IBObjectRecord">
2291 <int key="objectID">371</int>
2292 <reference key="object" ref="972006081"/>
2293 <object class="NSMutableArray" key="children">
2294 <bool key="EncodedWithXMLCoder">YES</bool>
2295 <reference ref="439893737"/>
2296 </object>
2297 <reference key="parent" ref="1049"/>
2298 </object>
2299 <object class="IBObjectRecord">
2300 <int key="objectID">372</int>
2301 <reference key="object" ref="439893737"/>
2302 <object class="NSMutableArray" key="children">
2303 <bool key="EncodedWithXMLCoder">YES</bool>
2304 <reference ref="741760375"/>
2305 <reference ref="74807016"/>
2306 </object>
2307 <reference key="parent" ref="972006081"/>
2308 </object>
2309 <object class="IBObjectRecord">
2310 <int key="objectID">373</int>
2311 <reference key="object" ref="610635028"/>
2312 <reference key="parent" ref="1049"/>
2313 <reference key="objectName" ref="982950837"/>
2314 </object>
2315 <object class="IBObjectRecord">
2316 <int key="objectID">385</int>
2317 <reference key="object" ref="808393665"/>
2318 <reference key="parent" ref="1049"/>
2319 <string key="objectName">User Namespace Controller</string>
2320 </object>
2321 <object class="IBObjectRecord">
2322 <int key="objectID">421</int>
2323 <reference key="object" ref="741760375"/>
2324 <object class="NSMutableArray" key="children">
2325 <bool key="EncodedWithXMLCoder">YES</bool>
2326 <reference ref="554641139"/>
2327 <reference ref="764100755"/>
2328 </object>
2329 <reference key="parent" ref="439893737"/>
2330 </object>
2331 <object class="IBObjectRecord">
2332 <int key="objectID">420</int>
2333 <reference key="object" ref="554641139"/>
2334 <object class="NSMutableArray" key="children">
2335 <bool key="EncodedWithXMLCoder">YES</bool>
2336 <reference ref="188193463"/>
2337 </object>
2338 <reference key="parent" ref="741760375"/>
2339 </object>
2340 <object class="IBObjectRecord">
2341 <int key="objectID">416</int>
2342 <reference key="object" ref="188193463"/>
2343 <object class="NSMutableArray" key="children">
2344 <bool key="EncodedWithXMLCoder">YES</bool>
2345 <reference ref="418410897"/>
2346 <reference ref="936733673"/>
2347 <reference ref="163417131"/>
2348 </object>
2349 <reference key="parent" ref="554641139"/>
2350 </object>
2351 <object class="IBObjectRecord">
2352 <int key="objectID">417</int>
2353 <reference key="object" ref="418410897"/>
2354 <reference key="parent" ref="188193463"/>
2355 </object>
2356 <object class="IBObjectRecord">
2357 <int key="objectID">418</int>
2358 <reference key="object" ref="936733673"/>
2359 <reference key="parent" ref="188193463"/>
2360 </object>
2361 <object class="IBObjectRecord">
2362 <int key="objectID">419</int>
2363 <reference key="object" ref="163417131"/>
2364 <reference key="parent" ref="188193463"/>
2365 </object>
2366 <object class="IBObjectRecord">
2367 <int key="objectID">406</int>
2368 <reference key="object" ref="764100755"/>
2369 <object class="NSMutableArray" key="children">
2370 <bool key="EncodedWithXMLCoder">YES</bool>
2371 <reference ref="516244966"/>
2372 </object>
2373 <reference key="parent" ref="741760375"/>
2374 </object>
2375 <object class="IBObjectRecord">
2376 <int key="objectID">407</int>
2377 <reference key="object" ref="516244966"/>
2378 <object class="NSMutableArray" key="children">
2379 <bool key="EncodedWithXMLCoder">YES</bool>
2380 <reference ref="23853726"/>
2381 <reference ref="47103270"/>
2382 <reference ref="512953560"/>
2383 <reference ref="1048357090"/>
2384 </object>
2385 <reference key="parent" ref="764100755"/>
2386 </object>
2387 <object class="IBObjectRecord">
2388 <int key="objectID">411</int>
2389 <reference key="object" ref="23853726"/>
2390 <object class="NSMutableArray" key="children">
2391 <bool key="EncodedWithXMLCoder">YES</bool>
2392 <reference ref="857054683"/>
2393 <reference ref="920426212"/>
2394 </object>
2395 <reference key="parent" ref="516244966"/>
2396 </object>
2397 <object class="IBObjectRecord">
2398 <int key="objectID">410</int>
2399 <reference key="object" ref="47103270"/>
2400 <reference key="parent" ref="516244966"/>
2401 </object>
2402 <object class="IBObjectRecord">
2403 <int key="objectID">409</int>
2404 <reference key="object" ref="512953560"/>
2405 <reference key="parent" ref="516244966"/>
2406 </object>
2407 <object class="IBObjectRecord">
2408 <int key="objectID">408</int>
2409 <reference key="object" ref="1048357090"/>
2410 <reference key="parent" ref="516244966"/>
2411 </object>
2412 <object class="IBObjectRecord">
2413 <int key="objectID">413</int>
2414 <reference key="object" ref="857054683"/>
2415 <object class="NSMutableArray" key="children">
2416 <bool key="EncodedWithXMLCoder">YES</bool>
2417 <reference ref="377147224"/>
2418 </object>
2419 <reference key="parent" ref="23853726"/>
2420 </object>
2421 <object class="IBObjectRecord">
2422 <int key="objectID">412</int>
2423 <reference key="object" ref="920426212"/>
2424 <object class="NSMutableArray" key="children">
2425 <bool key="EncodedWithXMLCoder">YES</bool>
2426 <reference ref="525071236"/>
2427 </object>
2428 <reference key="parent" ref="23853726"/>
2429 </object>
2430 <object class="IBObjectRecord">
2431 <int key="objectID">415</int>
2432 <reference key="object" ref="525071236"/>
2433 <reference key="parent" ref="920426212"/>
2434 </object>
2435 <object class="IBObjectRecord">
2436 <int key="objectID">414</int>
2437 <reference key="object" ref="377147224"/>
2438 <reference key="parent" ref="857054683"/>
2439 </object>
2440 <object class="IBObjectRecord">
2441 <int key="objectID">422</int>
2442 <reference key="object" ref="631572152"/>
2443 <reference key="parent" ref="1049"/>
2444 </object>
2445 <object class="IBObjectRecord">
2446 <int key="objectID">436</int>
2447 <reference key="object" ref="74807016"/>
2448 <reference key="parent" ref="439893737"/>
2449 </object>
2450 </object>
2451 </object>
2452 <object class="NSMutableDictionary" key="flattenedProperties">
2453 <bool key="EncodedWithXMLCoder">YES</bool>
2454 <object class="NSMutableArray" key="dict.sortedKeys">
2455 <bool key="EncodedWithXMLCoder">YES</bool>
2456 <string>-1.IBPluginDependency</string>
2457 <string>-2.IBPluginDependency</string>
2458 <string>-3.IBPluginDependency</string>
2459 <string>103.IBPluginDependency</string>
2460 <string>103.ImportedFromIB2</string>
2461 <string>106.IBPluginDependency</string>
2462 <string>106.ImportedFromIB2</string>
2463 <string>106.editorWindowContentRectSynchronizationRect</string>
2464 <string>111.IBPluginDependency</string>
2465 <string>111.ImportedFromIB2</string>
2466 <string>112.IBPluginDependency</string>
2467 <string>112.ImportedFromIB2</string>
2468 <string>124.IBPluginDependency</string>
2469 <string>124.ImportedFromIB2</string>
2470 <string>125.IBPluginDependency</string>
2471 <string>125.ImportedFromIB2</string>
2472 <string>125.editorWindowContentRectSynchronizationRect</string>
2473 <string>126.IBPluginDependency</string>
2474 <string>126.ImportedFromIB2</string>
2475 <string>129.IBPluginDependency</string>
2476 <string>129.ImportedFromIB2</string>
2477 <string>130.IBPluginDependency</string>
2478 <string>130.ImportedFromIB2</string>
2479 <string>130.editorWindowContentRectSynchronizationRect</string>
2480 <string>131.IBPluginDependency</string>
2481 <string>131.ImportedFromIB2</string>
2482 <string>134.IBPluginDependency</string>
2483 <string>134.ImportedFromIB2</string>
2484 <string>136.IBPluginDependency</string>
2485 <string>136.ImportedFromIB2</string>
2486 <string>143.IBPluginDependency</string>
2487 <string>143.ImportedFromIB2</string>
2488 <string>144.IBPluginDependency</string>
2489 <string>144.ImportedFromIB2</string>
2490 <string>145.IBPluginDependency</string>
2491 <string>145.ImportedFromIB2</string>
2492 <string>149.IBPluginDependency</string>
2493 <string>149.ImportedFromIB2</string>
2494 <string>150.IBPluginDependency</string>
2495 <string>150.ImportedFromIB2</string>
2496 <string>19.IBPluginDependency</string>
2497 <string>19.ImportedFromIB2</string>
2498 <string>195.IBPluginDependency</string>
2499 <string>195.ImportedFromIB2</string>
2500 <string>196.IBPluginDependency</string>
2501 <string>196.ImportedFromIB2</string>
2502 <string>197.IBPluginDependency</string>
2503 <string>197.ImportedFromIB2</string>
2504 <string>198.IBPluginDependency</string>
2505 <string>198.ImportedFromIB2</string>
2506 <string>199.IBPluginDependency</string>
2507 <string>199.ImportedFromIB2</string>
2508 <string>200.IBPluginDependency</string>
2509 <string>200.ImportedFromIB2</string>
2510 <string>200.editorWindowContentRectSynchronizationRect</string>
2511 <string>201.IBPluginDependency</string>
2512 <string>201.ImportedFromIB2</string>
2513 <string>202.IBPluginDependency</string>
2514 <string>202.ImportedFromIB2</string>
2515 <string>203.IBPluginDependency</string>
2516 <string>203.ImportedFromIB2</string>
2517 <string>204.IBPluginDependency</string>
2518 <string>204.ImportedFromIB2</string>
2519 <string>205.IBPluginDependency</string>
2520 <string>205.ImportedFromIB2</string>
2521 <string>205.editorWindowContentRectSynchronizationRect</string>
2522 <string>206.IBPluginDependency</string>
2523 <string>206.ImportedFromIB2</string>
2524 <string>207.IBPluginDependency</string>
2525 <string>207.ImportedFromIB2</string>
2526 <string>208.IBPluginDependency</string>
2527 <string>208.ImportedFromIB2</string>
2528 <string>209.IBPluginDependency</string>
2529 <string>209.ImportedFromIB2</string>
2530 <string>210.IBPluginDependency</string>
2531 <string>210.ImportedFromIB2</string>
2532 <string>211.IBPluginDependency</string>
2533 <string>211.ImportedFromIB2</string>
2534 <string>212.IBPluginDependency</string>
2535 <string>212.ImportedFromIB2</string>
2536 <string>212.editorWindowContentRectSynchronizationRect</string>
2537 <string>213.IBPluginDependency</string>
2538 <string>213.ImportedFromIB2</string>
2539 <string>214.IBPluginDependency</string>
2540 <string>214.ImportedFromIB2</string>
2541 <string>215.IBPluginDependency</string>
2542 <string>215.ImportedFromIB2</string>
2543 <string>216.IBPluginDependency</string>
2544 <string>216.ImportedFromIB2</string>
2545 <string>217.IBPluginDependency</string>
2546 <string>217.ImportedFromIB2</string>
2547 <string>218.IBPluginDependency</string>
2548 <string>218.ImportedFromIB2</string>
2549 <string>219.IBPluginDependency</string>
2550 <string>219.ImportedFromIB2</string>
2551 <string>220.IBPluginDependency</string>
2552 <string>220.ImportedFromIB2</string>
2553 <string>220.editorWindowContentRectSynchronizationRect</string>
2554 <string>221.IBPluginDependency</string>
2555 <string>221.ImportedFromIB2</string>
2556 <string>23.IBPluginDependency</string>
2557 <string>23.ImportedFromIB2</string>
2558 <string>236.IBPluginDependency</string>
2559 <string>236.ImportedFromIB2</string>
2560 <string>239.IBPluginDependency</string>
2561 <string>239.ImportedFromIB2</string>
2562 <string>24.IBPluginDependency</string>
2563 <string>24.ImportedFromIB2</string>
2564 <string>24.editorWindowContentRectSynchronizationRect</string>
2565 <string>29.IBPluginDependency</string>
2566 <string>29.ImportedFromIB2</string>
2567 <string>29.WindowOrigin</string>
2568 <string>29.editorWindowContentRectSynchronizationRect</string>
2569 <string>295.IBPluginDependency</string>
2570 <string>296.IBPluginDependency</string>
2571 <string>296.editorWindowContentRectSynchronizationRect</string>
2572 <string>297.IBPluginDependency</string>
2573 <string>298.IBPluginDependency</string>
2574 <string>299.IBPluginDependency</string>
2575 <string>300.IBPluginDependency</string>
2576 <string>300.editorWindowContentRectSynchronizationRect</string>
2577 <string>344.IBPluginDependency</string>
2578 <string>345.IBPluginDependency</string>
2579 <string>346.IBPluginDependency</string>
2580 <string>346.ImportedFromIB2</string>
2581 <string>348.IBPluginDependency</string>
2582 <string>348.ImportedFromIB2</string>
2583 <string>349.IBPluginDependency</string>
2584 <string>349.ImportedFromIB2</string>
2585 <string>349.editorWindowContentRectSynchronizationRect</string>
2586 <string>350.IBPluginDependency</string>
2587 <string>350.ImportedFromIB2</string>
2588 <string>351.IBPluginDependency</string>
2589 <string>351.ImportedFromIB2</string>
2590 <string>354.IBPluginDependency</string>
2591 <string>354.ImportedFromIB2</string>
2592 <string>371.IBPluginDependency</string>
2593 <string>371.IBViewEditorWindowController.showingLayoutRectangles</string>
2594 <string>371.IBWindowTemplateEditedContentRect</string>
2595 <string>371.NSWindowTemplate.visibleAtLaunch</string>
2596 <string>371.editorWindowContentRectSynchronizationRect</string>
2597 <string>372.IBPluginDependency</string>
2598 <string>373.IBPluginDependency</string>
2599 <string>385.IBPluginDependency</string>
2600 <string>407.IBPluginDependency</string>
2601 <string>409.IBPluginDependency</string>
2602 <string>410.IBPluginDependency</string>
2603 <string>411.IBPluginDependency</string>
2604 <string>412.IBPluginDependency</string>
2605 <string>413.IBPluginDependency</string>
2606 <string>414.IBPluginDependency</string>
2607 <string>415.IBPluginDependency</string>
2608 <string>416.IBPluginDependency</string>
2609 <string>417.IBPluginDependency</string>
2610 <string>418.IBPluginDependency</string>
2611 <string>419.IBAttributePlaceholdersKey</string>
2612 <string>419.IBPluginDependency</string>
2613 <string>422.IBPluginDependency</string>
2614 <string>436.IBPluginDependency</string>
2615 <string>5.IBPluginDependency</string>
2616 <string>5.ImportedFromIB2</string>
2617 <string>56.IBPluginDependency</string>
2618 <string>56.ImportedFromIB2</string>
2619 <string>57.IBPluginDependency</string>
2620 <string>57.ImportedFromIB2</string>
2621 <string>57.editorWindowContentRectSynchronizationRect</string>
2622 <string>58.IBPluginDependency</string>
2623 <string>58.ImportedFromIB2</string>
2624 <string>72.IBPluginDependency</string>
2625 <string>72.ImportedFromIB2</string>
2626 <string>73.IBPluginDependency</string>
2627 <string>73.ImportedFromIB2</string>
2628 <string>74.IBPluginDependency</string>
2629 <string>74.ImportedFromIB2</string>
2630 <string>75.IBPluginDependency</string>
2631 <string>75.ImportedFromIB2</string>
2632 <string>77.IBPluginDependency</string>
2633 <string>77.ImportedFromIB2</string>
2634 <string>78.IBPluginDependency</string>
2635 <string>78.ImportedFromIB2</string>
2636 <string>79.IBPluginDependency</string>
2637 <string>79.ImportedFromIB2</string>
2638 <string>80.IBPluginDependency</string>
2639 <string>80.ImportedFromIB2</string>
2640 <string>81.IBPluginDependency</string>
2641 <string>81.ImportedFromIB2</string>
2642 <string>81.editorWindowContentRectSynchronizationRect</string>
2643 <string>82.IBPluginDependency</string>
2644 <string>82.ImportedFromIB2</string>
2645 <string>83.IBPluginDependency</string>
2646 <string>83.ImportedFromIB2</string>
2647 <string>92.IBPluginDependency</string>
2648 <string>92.ImportedFromIB2</string>
2649 </object>
2650 <object class="NSMutableArray" key="dict.values">
2651 <bool key="EncodedWithXMLCoder">YES</bool>
2652 <reference ref="113577022"/>
2653 <reference ref="885801228"/>
2654 <reference ref="885801228"/>
2655 <reference ref="113577022"/>
2656 <reference ref="9"/>
2657 <reference ref="113577022"/>
2658 <reference ref="9"/>
2659 <string>{{596, 852}, {216, 23}}</string>
2660 <reference ref="113577022"/>
2661 <reference ref="9"/>
2662 <reference ref="113577022"/>
2663 <reference ref="9"/>
2664 <reference ref="113577022"/>
2665 <reference ref="9"/>
2666 <reference ref="113577022"/>
2667 <reference ref="9"/>
2668 <string>{{522, 812}, {146, 23}}</string>
2669 <reference ref="113577022"/>
2670 <reference ref="9"/>
2671 <reference ref="113577022"/>
2672 <reference ref="9"/>
2673 <reference ref="113577022"/>
2674 <reference ref="9"/>
2675 <string>{{436, 809}, {64, 6}}</string>
2676 <reference ref="113577022"/>
2677 <reference ref="9"/>
2678 <reference ref="113577022"/>
2679 <reference ref="9"/>
2680 <reference ref="113577022"/>
2681 <reference ref="9"/>
2682 <reference ref="113577022"/>
2683 <reference ref="9"/>
2684 <reference ref="113577022"/>
2685 <reference ref="9"/>
2686 <reference ref="113577022"/>
2687 <reference ref="9"/>
2688 <reference ref="113577022"/>
2689 <reference ref="9"/>
2690 <reference ref="113577022"/>
2691 <reference ref="9"/>
2692 <reference ref="113577022"/>
2693 <reference ref="9"/>
2694 <reference ref="113577022"/>
2695 <reference ref="9"/>
2696 <reference ref="113577022"/>
2697 <reference ref="9"/>
2698 <reference ref="113577022"/>
2699 <reference ref="9"/>
2700 <reference ref="113577022"/>
2701 <reference ref="9"/>
2702 <reference ref="113577022"/>
2703 <reference ref="9"/>
2704 <reference ref="113577022"/>
2705 <reference ref="9"/>
2706 <string>{{608, 612}, {275, 83}}</string>
2707 <reference ref="113577022"/>
2708 <reference ref="9"/>
2709 <reference ref="113577022"/>
2710 <reference ref="9"/>
2711 <reference ref="113577022"/>
2712 <reference ref="9"/>
2713 <reference ref="113577022"/>
2714 <reference ref="9"/>
2715 <reference ref="113577022"/>
2716 <reference ref="9"/>
2717 <string>{{365, 632}, {243, 243}}</string>
2718 <reference ref="113577022"/>
2719 <reference ref="9"/>
2720 <reference ref="113577022"/>
2721 <reference ref="9"/>
2722 <reference ref="113577022"/>
2723 <reference ref="9"/>
2724 <reference ref="113577022"/>
2725 <reference ref="9"/>
2726 <reference ref="113577022"/>
2727 <reference ref="9"/>
2728 <reference ref="113577022"/>
2729 <reference ref="9"/>
2730 <reference ref="113577022"/>
2731 <reference ref="9"/>
2732 <string>{{608, 612}, {167, 43}}</string>
2733 <reference ref="113577022"/>
2734 <reference ref="9"/>
2735 <reference ref="113577022"/>
2736 <reference ref="9"/>
2737 <reference ref="113577022"/>
2738 <reference ref="9"/>
2739 <reference ref="113577022"/>
2740 <reference ref="9"/>
2741 <reference ref="113577022"/>
2742 <reference ref="9"/>
2743 <reference ref="113577022"/>
2744 <reference ref="9"/>
2745 <reference ref="113577022"/>
2746 <reference ref="9"/>
2747 <reference ref="113577022"/>
2748 <reference ref="9"/>
2749 <string>{{608, 612}, {241, 103}}</string>
2750 <reference ref="113577022"/>
2751 <reference ref="9"/>
2752 <reference ref="113577022"/>
2753 <reference ref="9"/>
2754 <reference ref="113577022"/>
2755 <reference ref="9"/>
2756 <reference ref="113577022"/>
2757 <reference ref="9"/>
2758 <reference ref="113577022"/>
2759 <reference ref="9"/>
2760 <string>{{525, 802}, {197, 73}}</string>
2761 <reference ref="113577022"/>
2762 <reference ref="9"/>
2763 <string>{74, 862}</string>
2764 <string>{{11, 736}, {489, 20}}</string>
2765 <reference ref="113577022"/>
2766 <reference ref="113577022"/>
2767 <string>{{475, 832}, {234, 43}}</string>
2768 <reference ref="113577022"/>
2769 <reference ref="113577022"/>
2770 <reference ref="113577022"/>
2771 <reference ref="113577022"/>
2772 <string>{{409, 832}, {176, 43}}</string>
2773 <reference ref="113577022"/>
2774 <reference ref="113577022"/>
2775 <reference ref="113577022"/>
2776 <reference ref="9"/>
2777 <reference ref="113577022"/>
2778 <reference ref="9"/>
2779 <reference ref="113577022"/>
2780 <reference ref="9"/>
2781 <string>{{608, 612}, {215, 63}}</string>
2782 <reference ref="113577022"/>
2783 <reference ref="9"/>
2784 <reference ref="113577022"/>
2785 <reference ref="9"/>
2786 <reference ref="113577022"/>
2787 <reference ref="9"/>
2788 <reference ref="113577022"/>
2789 <integer value="0"/>
2790 <string>{{27, 368}, {725, 337}}</string>
2791 <reference ref="9"/>
2792 <string>{{27, 368}, {725, 337}}</string>
2793 <reference ref="113577022"/>
2794 <reference ref="113577022"/>
2795 <reference ref="113577022"/>
2796 <reference ref="113577022"/>
2797 <reference ref="113577022"/>
2798 <reference ref="113577022"/>
2799 <reference ref="113577022"/>
2800 <reference ref="113577022"/>
2801 <reference ref="113577022"/>
2802 <reference ref="113577022"/>
2803 <reference ref="113577022"/>
2804 <reference ref="113577022"/>
2805 <reference ref="113577022"/>
2806 <reference ref="113577022"/>
2807 <object class="NSMutableDictionary">
2808 <bool key="EncodedWithXMLCoder">YES</bool>
2809 <object class="NSArray" key="dict.sortedKeys">
2810 <bool key="EncodedWithXMLCoder">YES</bool>
2811 </object>
2812 <object class="NSMutableArray" key="dict.values">
2813 <bool key="EncodedWithXMLCoder">YES</bool>
2814 </object>
2815 </object>
2816 <reference ref="113577022"/>
2817 <reference ref="113577022"/>
2818 <reference ref="113577022"/>
2819 <reference ref="113577022"/>
2820 <reference ref="9"/>
2821 <reference ref="113577022"/>
2822 <reference ref="9"/>
2823 <reference ref="113577022"/>
2824 <reference ref="9"/>
2825 <string>{{23, 794}, {245, 183}}</string>
2826 <reference ref="113577022"/>
2827 <reference ref="9"/>
2828 <reference ref="113577022"/>
2829 <reference ref="9"/>
2830 <reference ref="113577022"/>
2831 <reference ref="9"/>
2832 <reference ref="113577022"/>
2833 <reference ref="9"/>
2834 <reference ref="113577022"/>
2835 <reference ref="9"/>
2836 <reference ref="113577022"/>
2837 <reference ref="9"/>
2838 <reference ref="113577022"/>
2839 <reference ref="9"/>
2840 <reference ref="113577022"/>
2841 <reference ref="9"/>
2842 <reference ref="113577022"/>
2843 <reference ref="9"/>
2844 <reference ref="113577022"/>
2845 <reference ref="9"/>
2846 <string>{{323, 672}, {199, 203}}</string>
2847 <reference ref="113577022"/>
2848 <reference ref="9"/>
2849 <reference ref="113577022"/>
2850 <reference ref="9"/>
2851 <reference ref="113577022"/>
2852 <reference ref="9"/>
2853 </object>
2854 </object>
2855 <object class="NSMutableDictionary" key="unlocalizedProperties">
2856 <bool key="EncodedWithXMLCoder">YES</bool>
2857 <object class="NSArray" key="dict.sortedKeys">
2858 <bool key="EncodedWithXMLCoder">YES</bool>
2859 </object>
2860 <object class="NSMutableArray" key="dict.values">
2861 <bool key="EncodedWithXMLCoder">YES</bool>
2862 </object>
2863 </object>
2864 <nil key="activeLocalization"/>
2865 <object class="NSMutableDictionary" key="localizations">
2866 <bool key="EncodedWithXMLCoder">YES</bool>
2867 <object class="NSArray" key="dict.sortedKeys">
2868 <bool key="EncodedWithXMLCoder">YES</bool>
2869 </object>
2870 <object class="NSMutableArray" key="dict.values">
2871 <bool key="EncodedWithXMLCoder">YES</bool>
2872 </object>
2873 </object>
2874 <nil key="sourceID"/>
2875 <int key="maxID">445</int>
2876 </object>
2877 <object class="IBClassDescriber" key="IBDocument.Classes">
2878 <object class="NSMutableArray" key="referencedPartialClassDescriptions">
2879 <bool key="EncodedWithXMLCoder">YES</bool>
2880 <object class="IBPartialClassDescription">
2881 <reference key="className" ref="695797635"/>
2882 <nil key="superclassName"/>
2883 <object class="NSMutableDictionary" key="actions">
2884 <bool key="EncodedWithXMLCoder">YES</bool>
2885 <object class="NSArray" key="dict.sortedKeys">
2886 <bool key="EncodedWithXMLCoder">YES</bool>
2887 </object>
2888 <object class="NSMutableArray" key="dict.values">
2889 <bool key="EncodedWithXMLCoder">YES</bool>
2890 </object>
2891 </object>
2892 <object class="NSMutableDictionary" key="outlets">
2893 <reference key="NS.key.0" ref="684042788"/>
2894 <string key="NS.object.0">NSTextView</string>
2895 </object>
2896 <object class="IBClassDescriptionSource" key="sourceIdentifier">
2897 <string key="majorKey">IBUserSource</string>
2898 <reference key="minorKey" ref="255189770"/>
2899 </object>
2900 </object>
2901 <object class="IBPartialClassDescription">
2902 <string key="className">IPython1SandboxAppDelegate</string>
2903 <string key="superclassName">NSObject</string>
2904 <object class="NSMutableDictionary" key="actions">
2905 <bool key="EncodedWithXMLCoder">YES</bool>
2906 <object class="NSArray" key="dict.sortedKeys">
2907 <bool key="EncodedWithXMLCoder">YES</bool>
2908 </object>
2909 <object class="NSMutableArray" key="dict.values">
2910 <bool key="EncodedWithXMLCoder">YES</bool>
2911 </object>
2912 </object>
2913 <object class="NSMutableDictionary" key="outlets">
2914 <string key="NS.key.0">ipythonController</string>
2915 <string key="NS.object.0">id</string>
2916 </object>
2917 <object class="IBClassDescriptionSource" key="sourceIdentifier">
2918 <string key="majorKey">IBProjectSource</string>
2919 <string key="minorKey">IPython1SandboxAppDelegate.py</string>
2920 </object>
2921 </object>
2922 </object>
2923 </object>
2924 <int key="IBDocument.localizationMode">0</int>
2925 <string key="IBDocument.LastKnownRelativeProjectPath">../../IPython1Sandbox.xcodeproj</string>
2926 <int key="IBDocument.defaultPropertyAccessControl">3</int>
2927 <object class="NSMutableData" key="IBDocument.RunnableNib">
2928 <bytes key="NS.bytes">YnBsaXN0MDDUAAEAAgADAAQABQAGAAkAClgkdmVyc2lvblQkdG9wWSRhcmNoaXZlclgkb2JqZWN0cxIA
2929 AYag0QAHAAhdSUIub2JqZWN0ZGF0YYABXxAPTlNLZXllZEFyY2hpdmVyrxEC/gALAAwAMQA1ADYAPAA9
2930 AEIAWABZAFoAWwALAGgAbQB7AIAAlQCZAKAApAC0ALoAzQDRAOYA+gD7APwA/QD+AP8BAAEBAQIBAwEE
2931 AQUBBgEHAQgBCQEKAQsBDwEQARkBIQEmASoBLQExATUBOQE7AT0BTQFSAVUBWgFBAVQBYwFqAWsBbAFv
2932 AXQBdQF4AYAAkAGBAYQBhwGIAYkBjgGPAZABkwGYAZkBmwGeAasBrAGtAbEBvAG9Ab4BwQHCAcQBxQHG
2933 AdIB0wHbAdwB3wHkAeUB6AHtAfAB/AIAAgcCCwIdAiUCLwIzAlECUgJaAmQCZQJoAm4CbwJyAncCiAKP
2934 ApACkwKYApkCnAKmAqcCrAKxArICtwK4ArsCwwLJAsoC0QLWAtcC2gLcAt0C5gLnAvAC8QL1AvYC9wL4
2935 AvkC/wMAAwIDAwMEAwcDFgMYAxsDHAMfAAsDIAMhAyIDJQNXA10DbQNzASkDdAN5A3oDewN+A4IDgwOG
2936 A4cDiwOPA5YDmgObA5wDnQOhA6gDrAOtA64DrwOzA7wDwAPBA8IDwwPHA84D0gPTA9QD1QPZA+AD5APl
2937 A+YD6gPxA/UD9gP3A/gD/AQDBAQEBQQJBBAEEQQSBBMEFwQeBB8EIAQkBCsELwQwBDEENQQ9BD4EPwRA
2938 BEQESwRMBE0ETgRUBFcEWgRbBFwEXwRjBGoEawRsBG0EcgR1BHYEdwR7BIIEgwSEBIUEiQSQBJUElgSX
2939 BJgEnASjBKQEpQSmBKoEsQSyBLMEtAS4BL8EwwTEBMUExgTKBNEE0gTTBNQE2ATfBOAE4QTiBOYE7QTx
2940 BPIE8wT0BPgE/wUABQEFBgUNBQ4FDwUTBRwFHQUeBR8FJAUoBS8FMAUxBTIFNwU4BTwFQwVEBUUFRgVK
2941 BVEFVgVXBVgFXAVjBWQFZQVpBXAFcQVyBXcFeAV8BYMFhAWFBYkFkAWRBZIFlgWdBZ4FnwWjBaoFqwWs
2942 BbAFtwW4BbkFugW+BcUFxgXHBcgFzAXTBdQF1QXWBeAF9gX8Bf0F/gX/BgMGCwYMBg8GEQYXBhgGGQYa
2943 Bh0GJAYlBiYGJwYuBi8GMAY3BjgGOQZABkEGQgZDBq0GuAbCBscGyAbJBs4G1QbWBtgG2QbdBt4GyAbn
2944 BvAGyAbxBvgHAQbIBwIHEgcbByQHLQbIBy4HNgc9Bz4HRQdGB04HTwdQB1kGyAdaB2AHaQbIB2oHbwdw
2945 B3oHgwbIB4QHkgebB6IHowekB60HtgbIB7cHvAe/B8AHyQfKB9MGyAfUB+IH6QfqB+sH8gfzB/QH/QgG
2946 CA8GyAgQCBUIHgbICB8IJggvCDAIOQbICDoIPgg/CKkJFAl/CYAJgQmCCYMJhAmFCYYJhwmICYkJigmL
2947 CYwJjQmOCY8JkAmRCZIJkwmUCZUJlgmXCZgJmQmaCZsJnAmdCZ4JnwmgCaEJogmjCaQJpQmmCacJqAmp
2948 CaoJqwmsCa0JrgmvCbAJsQmyCbMJtAm1CbYJtwm4CbkJugm7CbwJvQm+Cb8JwAnBCcIJwwnECcUJxgnH
2949 CcgJyQnKCcsJzAnNCc4JzwnQCdEJ0gnTCdQJ1QnWCdcJ2AnZCdoJ2wncCd0J3gnfCeAJ4QniCeMJ5Anl
2950 CeYJ6QnsCoYLIAshCyILIwskCyULJgsnCygLKQsqCysLLAstCy4LLwswCzELMgszCzQLNQs2CzcLOAs5
2951 CzoLOws8Cz0LPgs/C0ALQQtCC0MLRAtFC0YLRwtIC0kLSgtLC0wLTQtOC08LUAtRC1ILUwtUC1ULVgtX
2952 C1gLWQtaC1sLXAtdC14LXwtgC2ELYgtjC2QLZQtmC2cLaAtpC2oLawtsC20LbgtvC3ALcQtyC3MLdAt1
2953 C3YLdwt4C3kLegt7C3wLfQt+C38LgAuBC4ILgwuEC4ULhguHC4gLiQuKC4sLjAuNC44LjwuQC5ELkguT
2954 C5QLlQuWC5cLmAuZC5oLmwucC50LngufC6ALoQuiC6MLpAulC6YLpwuoC6kLqgurC6wLrQuuC68LsAux
2955 C7ILswu0C7ULtgu3C7oLvQvAVSRudWxs3xASAA0ADgAPABAAEQASABMAFAAVABYAFwAYABkAGgAbABwA
2956 HQAeAB8AIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwVk5TUm9vdFYkY2xhc3NdTlNPYmpl
2957 Y3RzS2V5c18QD05TQ2xhc3Nlc1ZhbHVlc18QGU5TQWNjZXNzaWJpbGl0eU9pZHNWYWx1ZXNdTlNDb25u
2958 ZWN0aW9uc1tOU05hbWVzS2V5c1tOU0ZyYW1ld29ya11OU0NsYXNzZXNLZXlzWk5TT2lkc0tleXNdTlNO
2959 YW1lc1ZhbHVlc18QGU5TQWNjZXNzaWJpbGl0eUNvbm5lY3RvcnNdTlNGb250TWFuYWdlcl8QEE5TVmlz
2960 aWJsZVdpbmRvd3NfEA9OU09iamVjdHNWYWx1ZXNfEBdOU0FjY2Vzc2liaWxpdHlPaWRzS2V5c1lOU05l
2961 eHRPaWRcTlNPaWRzVmFsdWVzgAKBAv2BAZuBAmCBAvyArYEB9oAFgQJfgQJhgQH3gQL6gACABoEB9YEC
2962 +xEBv4ECYtIADgAyADMANFtOU0NsYXNzTmFtZYAEgANdTlNBcHBsaWNhdGlvbtIANwA4ADkAOlgkY2xh
2963 c3Nlc1okY2xhc3NuYW1logA6ADteTlNDdXN0b21PYmplY3RYTlNPYmplY3RfEBBJQkNvY29hRnJhbWV3
2964 b3Jr0gAOAD4APwBAWk5TLm9iamVjdHOAK6EAQYAH2wBDAA4ARABFAEYARwBIAEkASgBLAEwATQBOAE8A
2965 UABRAFIAUwBUAFUAVgArXE5TV2luZG93Vmlld1xOU1NjcmVlblJlY3RfEBNOU0ZyYW1lQXV0b3NhdmVO
2966 YW1lXU5TV2luZG93VGl0bGVZTlNXVEZsYWdzXU5TV2luZG93Q2xhc3NcTlNXaW5kb3dSZWN0XxAPTlNX
2967 aW5kb3dCYWNraW5nXxARTlNXaW5kb3dTdHlsZU1hc2tbTlNWaWV3Q2xhc3OAC4CsgKqAq4AJEnQAAACA
2968 CoAIEAIQD4AAXxAYe3szMzUsIDQxM30sIHs3MjUsIDMzN319XxAQSVB5dGhvbjEgKENvY29hKVhOU1dp
2969 bmRvd9cAXAAOAF0AXgBfAFoAYABhAGIAYwBkAGUAYQBnXxAPTlNOZXh0UmVzcG9uZGVyWk5TU3Vidmll
2970 d3NYTlN2RmxhZ3NbTlNGcmFtZVNpemVbTlNTdXBlcnZpZXeADIBdgA0RAQCAqIAMgKnSAA4APgBpAGqA
2971 NKIAawBsgA6Ao9oAXAAOAG4AXQBeAG8AcABaAGAAcQBNAHMAdAB1AHYAdwBVAGEATQB6V05TRnJhbWVe
2972 TlNBdXRvc2F2ZU5hbWVeTlNEaXZpZGVyU3R5bGVcTlNJc1ZlcnRpY2FsgAuAooCggA8RARKAoYAMgAsJ
2973 0gAOAD4AaQB9gDSiAH4Af4AQgGreAFwAgQAOAIIAgwBdAF4AXwCEAFoAhQCGAGAAhwBrAIkAigCLAIwA
2974 jQCOAI8AkABhAJIAVQBrAJRZTlNCb3hUeXBlW05TVGl0bGVDZWxsXU5TVHJhbnNwYXJlbnRcTlNCb3Jk
2975 ZXJUeXBlWU5TT2Zmc2V0c18QD05TVGl0bGVQb3NpdGlvbl1OU0NvbnRlbnRWaWV3gA4QAIBpgGAIgBEQ
2976 FoBeEAGADIBfgA6AEtIADgA+AGkAl4A0oQCUgBLXAFwADgBuAF0AXgBaAGAAfgBiAJwAnQBkAGEAfoAQ
2977 gF2AXIATgAyAENIADgA+AGkAooA0oQCjgBTcAFwApQAOAG4ApgBdAF4AWgBgAKcAqACHAJQAqgCrAKwA
2978 rQCuAHYAYQCUALEAsgCyW05TSFNjcm9sbGVyWE5Tc0ZsYWdzW05TVlNjcm9sbGVyXU5TTmV4dEtleVZp
2979 ZXeAEoBYgFuAWhECEoAVgAyAEoBUgBaAFtIADgA+AGkAtoA0owCyALEAqoAWgFSAWN0AXAAOAG4AuwC8
2980 AL0AXQBeAL4AWgC/AGAAqACjAMEAwgDDAMQAxQDGAMcAyABhAMoAowDIWE5TQm91bmRzWE5TQ3Vyc29y
2981 WU5TY3ZGbGFnc1lOU0RvY1ZpZXdZTlNCR0NvbG9ygBSAU4BNgE6AUBAEgBcRCQCAGIAMgE+AFIAY0gAO
2982 AD4AaQDPgDShAMiAGN0AXAAOAG4A0gDTANQA1QBeANYAWgDXAGAA2ACyANoA2wDcAN0A3gDfAOAA4QBh
2983 AOMAsgArXxAPTlNUZXh0Q29udGFpbmVyWU5TVFZGbGFnc1xOU1NoYXJlZERhdGFbTlNEcmFnVHlwZXNZ
2984 TlNNYXhTaXplWE5TTWluaXplWk5TRGVsZWdhdGWAFoBMgCyALRAGgDeAGREJEoBKgAyAS4AWgADSAA4A
2985 PgA/AOiAK68QEQDpAOoA6wDsAO0A7gDvAPAA8QDyAPMA9AD1APYA9wD4APmAGoAbgByAHYAegB+AIIAh
2986 gCKAI4AkgCWAJoAngCiAKYAqXxAZTmVYVCBSVEZEIHBhc3RlYm9hcmQgdHlwZV8QEk5TU3RyaW5nUGJv
2987 YXJkVHlwZV8QGk5lWFQgcnVsZXIgcGFzdGVib2FyZCB0eXBlXxAeTmVYVCBUSUZGIHY0LjAgcGFzdGVi
2988 b2FyZCB0eXBlXxAZQXBwbGUgVVJMIHBhc3RlYm9hcmQgdHlwZV8QI0NvcmVQYXN0ZWJvYXJkRmxhdm9y
2989 VHlwZSAweDZENkY2Rjc2XxAjQ29yZVBhc3RlYm9hcmRGbGF2b3JUeXBlIDB4NzU3MjZDMjBfEBtXZWJV
2990 UkxzV2l0aFRpdGxlc1Bib2FyZFR5cGVfEBlBcHBsZSBQREYgcGFzdGVib2FyZCB0eXBlXxAZQXBwbGUg
2991 UE5HIHBhc3RlYm9hcmQgdHlwZV8QGkFwcGxlIEhUTUwgcGFzdGVib2FyZCB0eXBlXxAVTlNGaWxlbmFt
2992 ZXNQYm9hcmRUeXBlXxAXTlNDb2xvciBwYXN0ZWJvYXJkIHR5cGVfEDFOZVhUIEVuY2Fwc3VsYXRlZCBQ
2993 b3N0U2NyaXB0IHYxLjIgcGFzdGVib2FyZCB0eXBlXxAaQXBwbGUgUElDVCBwYXN0ZWJvYXJkIHR5cGVf
2994 EBlOZVhUIGZvbnQgcGFzdGVib2FyZCB0eXBlXxAqTmVYVCBSaWNoIFRleHQgRm9ybWF0IHYxLjAgcGFz
2995 dGVib2FyZCB0eXBl0gA3ADgBDAENowENAQ4AO1xOU011dGFibGVTZXRVTlNTZXRfEBR7ezAsIDM4fSwg
2996 ezQzMywgMTR9fdUBEQAOARIBEwEUAJABFQDIARcBGFlOU1RDRmxhZ3NaTlNUZXh0Vmlld1dOU1dpZHRo
2997 XxAPTlNMYXlvdXRNYW5hZ2VygDaAGCNAexAAAAAAAIAu1QAOARoBGwEcANgBHQEeAR8A3QArXxAQTlNU
2998 ZXh0Q29udGFpbmVyc11OU1RleHRTdG9yYWdlWU5TTE1GbGFnc4A1gDOAL4AA0wAOASIA2AEjASQAK1hO
2999 U1N0cmluZ4AygDCAANIADgEnASgBKVlOUy5zdHJpbmeAMVDSADcAOAErASyjASwBIgA7XxAPTlNNdXRh
3000 YmxlU3RyaW5n0gA3ADgBLgEbpAEbAS8BMAA7XxAZTlNNdXRhYmxlQXR0cmlidXRlZFN0cmluZ18QEk5T
3001 QXR0cmlidXRlZFN0cmluZ9IADgA+AGkBM4A0oQDcgC3SADcAOAE2ATejATcBOAA7Xk5TTXV0YWJsZUFy
3002 cmF5V05TQXJyYXnSADcAOAE6ARSiARQAO9IANwA4ATwA0qIA0gA72AAOAT4BPwFAAUEBQgFDAUQBRQFG
3003 ACsBSAFJAUoAKwFMV05TRmxhZ3NfEBdOU0RlZmF1bHRQYXJhZ3JhcGhTdHlsZV8QEE5TSW5zZXJ0aW9u
3004 Q29sb3JfEBFOU0JhY2tncm91bmRDb2xvcl8QFE5TU2VsZWN0ZWRBdHRyaWJ1dGVzXxASTlNNYXJrZWRB
3005 dHRyaWJ1dGVzXxAQTlNMaW5rQXR0cmlidXRlc4BJEgAFS2+AAIA6gDiAO4AAgEXTAA4BTgFPAVAAVQFR
3006 XE5TQ29sb3JTcGFjZVVOU1JHQoA5TxAYMSAwLjk1Mjk0MTI0IDAuODUwOTgwNDYA0gA3ADgBUwFUogFU
3007 ADtXTlNDb2xvctMADgFOAVYBUAFYAVlXTlNXaGl0ZYA5EANCMADTAA4BWwA+AVwBXQFgV05TLmtleXOA
3008 RKIBXgFfgDyAPaIBYQFigD6AQtUADgFUAU4BZAFlAVABZwDdAWgBaVtOU0NvbG9yTmFtZV1OU0NhdGFs
3009 b2dOYW1lgDmAQYBAgD9WU3lzdGVtXxAbc2VsZWN0ZWRUZXh0QmFja2dyb3VuZENvbG9y0wAOAU4BVgFQ
3010 AVgBboA5SzAuNjY2NjY2NjkA1QAOAVQBTgFkAWUBUAFIAN0BcgFpgDmAOoBDgD9fEBFzZWxlY3RlZFRl
3011 eHRDb2xvctIANwA4AXYBd6IBdwA7XE5TRGljdGlvbmFyedMADgFbAD4BXAF6AX2ARKIBewFfgEaAPaIB
3012 fgF/gEeASFtOU1VuZGVybGluZdMADgFOAU8BUACQAYOAOUYwIDAgMQDSADcAOAGFAYaiAYYAO18QFE5T
3013 VGV4dFZpZXdTaGFyZWREYXRhXHs0ODAsIDFlKzA3fVd7ODQsIDB90gA3ADgBigESpQESAYsBjAGNADtW
3014 TlNUZXh0Vk5TVmlld1tOU1Jlc3BvbmRlcl8QFHt7MSwgMX0sIHs0MzMsIDIzMX19XxAVe3swLCAzOH0s
3015 IHs0MzMsIDIzMX190wAOAU4BVgFQAVgBkoA5QjEA0wAOAZQBlQGWAZcAkFlOU0hvdFNwb3RcTlNDdXJz
3016 b3JUeXBlgFKAUVd7NCwgLTV90gA3ADgBmgC8ogC8ADvSADcAOAGcAZ2kAZ0BjAGNADtaTlNDbGlwVmll
3017 d9kAXAGfAA4AbgBeAFoBoABgAaEAowCjAaQBpQGmAGEBqACjAapYTlNUYXJnZXRYTlNBY3Rpb25ZTlNQ
3018 ZXJjZW50gBSAFIBXgFUT/////4AAAQCADIBWgBQjP9Ww0wAAAABfEBV7ezQyNywgMX0sIHsxNSwgMjYz
3019 fX1cX2RvU2Nyb2xsZXI60gA3ADgBrgGvpQGvAbABjAGNADtaTlNTY3JvbGxlcllOU0NvbnRyb2zbAFwB
3020 nwAOAG4ApgBeAFoBoABgAbIBoQCjAKMBpAG2AJAAZABhAagAowG6AbtaTlNDdXJWYWx1ZYAUgBSAV4BZ
3021 gAyAVoAUIz/wAAAAAAAAIz/uQshgAAAAXxAYe3stMTAwLCAtMTAwfSwgezg3LCAxOH19XxAWe3sxOCwg
3022 MTR9LCB7NDM1LCAyMzN9fdIANwA4Ab8BwKQBwAGMAY0AO1xOU1Njcm9sbFZpZXdfEBR7ezEsIDF9LCB7
3023 NDcxLCAyNTd9fdIANwA4AcMBjKMBjAGNADtaezQ3MywgMjczfVZ7MCwgMH3XAccADgFBAcgByQHKAcsB
3024 zAHNAc4BzwHQAIkB0VtOU0NlbGxGbGFnc1pOU0NvbnRlbnRzWU5TU3VwcG9ydFxOU0NlbGxGbGFnczJb
3025 TlNUZXh0Q29sb3ISBAH+AIBogGWAYYBigGdXQ29uc29sZdQADgHUAdUB1gHXAdgB2QHaVk5TU2l6ZVZO
3026 U05hbWVYTlNmRmxhZ3OAZCNAJgAAAAAAAIBjEQwcXEx1Y2lkYUdyYW5kZdIANwA4Ad0B3qIB3gA7Vk5T
3027 Rm9udNUADgFUAU4BZAFlAVAAygDdAeIBaYA5gE+AZoA/XxATdGV4dEJhY2tncm91bmRDb2xvctMADgFO
3028 AVYBUAFYAeeAOU0wIDAuODAwMDAwMDEA0gA3ADgB6QHqpAHqAesB7AA7XxAPTlNUZXh0RmllbGRDZWxs
3029 XE5TQWN0aW9uQ2VsbFZOU0NlbGzSADcAOAHuAe+kAe8BjAGNADtVTlNCb3jeAFwAgQAOAIIAbgCDAF0A
3030 XgCEAFoAhQCGAGAAhwBrAIkAigHzAfQAjAH2AfcAkABhAJIAVQBrAfuADoBpgJ2AnAiAaxAzgAyAX4AO
3031 gGzSAA4APgBpAf6ANKEB+4Bs1wBcAA4AbgBdAF4AWgBgAH8AYgIDAgQAZABhAH+AaoBdgJuAbYAMgGrS
3032 AA4APgBpAgmANKECCoBu3xAPAFwApQAOAG4ApgIMAg0AXQIOAF4AWgBgAKcAqACHAfsCEACrAhICEwIU
3033 AhUCFgIXAHYAYQH7AhoCGwIbXE5TQ29ybmVyVmlld18QEE5TSGVhZGVyQ2xpcFZpZXdcTlNTY3JvbGxB
3034 bXRzgGyAloBbgJoQMoB4gHWAb08QEEEgAABBIAAAQZgAAEGYAACADIBsgJSAcIBw0gAOAD4AaQIfgDSl
3035 AhsCGgIQAhUCFIBwgJSAloB1gHjbAFwADgBuAL0AXQBeAL4AWgC/AGAAqAIKAMECKADFAikAxwIqAGEC
3036 LAIKAiqAboBTgJOAcYBygAyAhoBugHLSAA4APgBpAjGANKECKoBy3xAVAFwCNAAOAjUCNgFBAjcCDAI4
3037 AjkCOgBeAF8COwBaAjwCPQBgAj4CPwJAAhsAiQJCAkMCRADKAHoCFAJIAMUCSQBkAkoAegBhAk0AkAIb
3038 Ak8AVgJQXxAfTlNEcmFnZ2luZ1NvdXJjZU1hc2tGb3JOb25Mb2NhbFlOU1R2RmxhZ3NcTlNIZWFkZXJW
3039 aWV3XxASTlNBbGxvd3NUeXBlU2VsZWN0XxAXTlNJbnRlcmNlbGxTcGFjaW5nV2lkdGhfEBlOU0NvbHVt
3040 bkF1dG9yZXNpemluZ1N0eWxlXxAYTlNJbnRlcmNlbGxTcGFjaW5nSGVpZ2h0WU5TRW5hYmxlZFtOU0dy
3041 aWRDb2xvcl8QD05TR3JpZFN0eWxlTWFza15OU1RhYmxlQ29sdW1uc18QHE5TRHJhZ2dpbmdTb3VyY2VN
3042 YXNrRm9yTG9jYWxbTlNSb3dIZWlnaHSAcICSE//////WwAAAgHSATwmAeCNACAAAAAAAACNAAAAAAAAA
3043 AIBzCYAMgI+AcIB7I0AxAAAAAAAAWnsxNTYsIDIwMH3XAFwADgBeAF8AWgBgAlMCFQJVAGQCVgBhAhUC
3044 KltOU1RhYmxlVmlld4B1gHeAdoAMgHWActsAXAAOAG4AvQBdAF4AvgBaAL8AYACoAgoAwQJdAMUCXgDH
3045 AkQAYQIsAgoCRIBugFOAmYCYgHSADICGgG6AdFl7MTU2LCAxN33SADcAOAJmAmekAmcBjAGNADtfEBFO
3046 U1RhYmxlSGVhZGVyVmlld9YAXAAOAG4AXgBaAGACCgJqAmsAZABhAgqAboB6gHmADIBuXxAUe3sxNTcs
3047 IDB9LCB7MTYsIDE3fX3SADcAOAJwAnGkAnEBjAGNADtdX05TQ29ybmVyVmlld9IADgA+AGkCdIA0ogJ1
3048 AnaAfICL2gJ4AA4CeQETAnoCewJ8An0CfgJTAHoCgAKBAoICgwFYAoQChQB6AipeTlNJc1Jlc2l6ZWFi
3049 bGVcTlNIZWFkZXJDZWxsWk5TRGF0YUNlbGxeTlNSZXNpemluZ01hc2taTlNNaW5XaWR0aFpOU01heFdp
3050 ZHRoXE5TSXNFZGl0YWJsZQmAioB9I0BRwAAAAAAAgIMjQEQAAAAAAAAjQI9AAAAAAAAJgHLXAccADgFB
3051 AcgByQHKAcsCiQKKAosCjAHQAIkCjhIEgf4AgIKAf4B+gGKAgFhWYXJpYWJsZdMADgFOAVYBUAFYApKA
3052 OUswLjMzMzMzMjk5ANUADgFUAU4BZAFlAVABSADdApYBaYA5gDqAgYA/XxAPaGVhZGVyVGV4dENvbG9y
3053 0gA3ADgCmgKbpQKbAeoB6wHsADtfEBFOU1RhYmxlSGVhZGVyQ2VsbNgBxwAOAUEByAHJAp0BygHLAp4B
3054 zQIsAqECogIqAqQCpV1OU0NvbnRyb2xWaWV3EhQh/kCAaICGgISAhYByEQgAgIhZVGV4dCBDZWxs1AAO
3055 AdQB1QHWAdcCqQHZAquAZCNAKgAAAAAAAIBjEQQU1QAOAVQBTgFkAWUBUAFnAN0CrwFpgDmAQYCHgD9f
3056 EBZjb250cm9sQmFja2dyb3VuZENvbG9y1QAOAVQBTgFkAWUBUAFIAN0CtQFpgDmAOoCJgD9fEBBjb250
3057 cm9sVGV4dENvbG9y0gA3ADgCuQK6ogK6ADtdTlNUYWJsZUNvbHVtbtoCeAAOAnkBEwJ6AnsCfAJ9An4C
3058 UwB6AoACvgK/AsABWAKEAoUAegIqCYCKgIwjQFPAAAAAAACAjgmActcBxwAOAUEByAHJAcoBywKJAooC
3059 iwLGAdAAiQKOgIKAf4CNgGKAgFVWYWx1ZdgBxwAOAUEByAHJAp0BygHLAp4BzQIsAqECogIqAqQCpYBo
3060 gIaAhICFgHKAiNUADgFUAU4BZAFlAVAC0wDdAtQBaYA5gJGAkIA/WWdyaWRDb2xvctMADgFOAVYBUAFY
3061 AtmAOUQwLjUA0gA3ADgC2wJTpQJTAbABjAGNADtfEBV7ezEsIDE3fSwgezE1NiwgMjAwfX3ZAFwBnwAO
3062 AG4AXgBaAaAAYAGhAgoCCgGkAuEAZABhAagCCgLlgG6AboBXgJWADIBWgG4jP+/gP4AAAABfEBZ7ezE1
3063 NywgMTd9LCB7MTUsIDIwMH192gBcAZ8ADgBuAKYAXgBaAaAAYAGhAgoCCgGkAusAkABkAGEBqAIKAu+A
3064 boBugFeAl4AMgFaAbiM/5vlvoAAAAF8QFXt7MSwgMjE3fSwgezE1NiwgMTV9fdIADgA+AGkC84A0oQJE
3065 gHRfEBN7ezEsIDB9LCB7MTU2LCAxN319XxAWe3sxOCwgMTR9LCB7MTczLCAyMzN9fV8QFHt7MSwgMX0s
3066 IHsyMDksIDI1N319XxAWe3s0NzQsIDB9LCB7MjExLCAyNzN9fdcBxwAOAUEByAHJAcoBywHMAc0BzgL8
3067 AdAAiQL+gGiAZYCegGKAn1lXb3Jrc3BhY2XTAA4BTgFWAVABWAHngDlfEBZ7ezIwLCA0NH0sIHs2ODUs
3068 IDI3M319XxAgaXB5dGhvbjFfY29uc29sZV93b3Jrc3BhY2Vfc3BsaXTSADcAOAMFAwakAwYBjAGNADtb
3069 TlNTcGxpdFZpZXfaAFwADgBuAwgDCQBeAFoDCgBgAwsATQMNAw4DDwMQAxEAYQMTAE0DFVpOU01heFZh
3070 bHVlWk5TTWluVmFsdWVZTlNwaUZsYWdzXE5TRHJhd01hdHJpeIALgKeApiNAWQAAAAAAACNAMAAAAAAA
3071 ABEFIYAMEXEKgAuApNEADgMXgKXSADcAOAMZAxqiAxoAO1pOU1BTTWF0cml4XxAVe3s2ODksIDIwfSwg
3072 ezE2LCAxNn190gA3ADgDHQMepAMeAYwBjQA7XxATTlNQcm9ncmVzc0luZGljYXRvclp7NzI1LCAzMzd9
3073 XxAVe3swLCAwfSwgezEyODAsIDc3OH19XxAQaXB5dGhvbjFfc2FuZGJveNIANwA4AyMDJKIDJAA7XxAQ
3074 TlNXaW5kb3dUZW1wbGF0ZdIADgA+AGkDJ4A0rxAvAygDKQMqAysDLAMtAy4DLwMwAzEDMgMzAzQDNQM2
3075 AzcDOAM5AzoDOwM8Az0DPgM/A0ADQQNCA0MDRANFA0YDRwNIA0kDSgNLA0wDTQNOA08DUANRA1IDUwNU
3076 A1UDVoCugLyAwoDIgM6A1IDZgN+A44DogOyA8YD2gPuBAQGBAQaBAQqBAQ+BARWBARqBAR+BASWBASqB
3077 AS+BATWBATmBAT2BAUKBAUOBAUiBAUqBAU+BAVSBAViBAVyBAV6BAWKBAWaBAWqBAW6BAXOBAXiBAX2B
3078 AY2BAZGBAZSBAZfTAA4DWANZA1oDWwNcWE5TU291cmNlV05TTGFiZWyAu4CvgLrYAA4DXgNfA2ADYQNi
3079 A2MDZANlA2YDZwNoA2kDagNrA2xXTlNUaXRsZV8QEU5TS2V5RXF1aXZNb2RNYXNrWk5TS2V5RXF1aXZd
3080 TlNNbmVtb25pY0xvY1lOU09uSW1hZ2VcTlNNaXhlZEltYWdlVk5TTWVudYC5gLESABAAAICyEn////+A
3081 s4C3gLDUAA4DXgHVA24DbwNwA3EDcltOU01lbnVJdGVtc4EBpIEByoEB2YEBzFhTaG93IEFsbNMADgAy
3082 A3UDdgN3A3heTlNSZXNvdXJjZU5hbWWAtoC0gLVXTlNJbWFnZV8QD05TTWVudUNoZWNrbWFya9IANwA4
3083 A3wDfaIDfQA7XxAQTlNDdXN0b21SZXNvdXJjZdMADgAyA3UDdgN3A4GAtoC0gLhfEBBOU01lbnVNaXhl
3084 ZFN0YXRl0gA3ADgDhAOFogOFADtaTlNNZW51SXRlbV8QFnVuaGlkZUFsbEFwcGxpY2F0aW9uczrSADcA
3085 OAOIA4mjA4kDigA7XxAVTlNOaWJDb250cm9sQ29ubmVjdG9yXk5TTmliQ29ubmVjdG9y0wAOA1gDWQNa
3086 A40DjoC7gL2AwdgADgNeA18DYANhA2IDYwNkA2UDkQNnA5IDaQNqA2sDlYC5gL+AwICzgLeAvtMADgNe
3087 A24DbwOYA5mBAaSBAauBAa1eQ2hlY2sgU3BlbGxpbmdRO15jaGVja1NwZWxsaW5nOtMADgNYA1kDWgOf
3088 A6CAu4DDgMfYAA4DXgNfA2ADYQNiA2MDZANlA6MDZwOkA2kDagNrA6eAuYDFgMaAs4C3gMTTAA4DXgNu
3089 A28DqgOrgQGkgQHbgQHdZgBQAHIAaQBuAHQgJlFwVnByaW50OtMADgNYA1kDWgOxA7KAu4DJgM3ZAA4D
3090 XgNfA2ADYQNiA2MDZAO0A2UDtgO3A7gDaQNqA2sDuwFYVU5TVGFngLmAyxIAEgAAgMyAs4C3gMrTAA4D
3091 XgNuA28DvgO/gQGkgQHAgQHCW1NtYXJ0IExpbmtzUUdfEB10b2dnbGVBdXRvbWF0aWNMaW5rRGV0ZWN0
3092 aW9uOtMADgNYA1kDWgPFA8aAu4DPgNPYAA4DXgNfA2ADYQNiA2MDZANlA8kDtwPKA2kDagNrA82AuYDR
3093 gNKAs4C3gNDTAA4DXgNuA28D0APRgQGkgQGvgQGxVFJlZG9RWlVyZWRvOtMADgNYA1kDWgPXA9iAu4DV
3094 gNjYAA4DXgNfA2ADYQNiA2MDZANlA9sDZwNoA2kDagNrA9+AuYDXgLKAs4C3gNbTAA4DXgNuA28D4gPj
3095 gQGkgQHEgQHGXlN0YXJ0IFNwZWFraW5nXnN0YXJ0U3BlYWtpbmc60wAOA1gDWQNaA+gD6YC7gNqA3tgA
3096 DgNeA18DYANhA2IDYwNkA2UD7ANnA+0DaQNqA2sD8IC5gNyA3YCzgLeA29MADgNeA24DbwPzA/SBAaSB
3097 AfGBAfNfEBRJUHl0aG9uMVNhbmRib3ggSGVscFE/WXNob3dIZWxwOtMADgNYA1kDWgP6A/uAu4DggOLY
3098 AA4DXgNfA2ADYQNiA2MDZANlA/4DZwNoA2kDagNrA5WAuYDhgLKAs4C3gL5fEBtDaGVjayBTcGVsbGlu
3099 ZyBXaGlsZSBUeXBpbmdfEB50b2dnbGVDb250aW51b3VzU3BlbGxDaGVja2luZzrTAA4DWANZA1oEBwQI
3100 gLuA5IDn2AAOA14DXwNgA2EDYgNjA2QDZQQLA2cEDANpA2oDawPNgLmA5YDmgLOAt4DQWlNlbGVjdCBB
3101 bGxRYVpzZWxlY3RBbGw60wAOA1gDWQNaBBUEFoC7gOmA69gADgNeA18DYANhA2IDYwNkA2UEGQNnA2gD
3102 aQNqA2sDlYC5gOqAsoCzgLeAvl8QG0NoZWNrIEdyYW1tYXIgV2l0aCBTcGVsbGluZ18QFnRvZ2dsZUdy
3103 YW1tYXJDaGVja2luZzrTAA4DWANZA1oEIgQjgLuA7YDw2AAOA14DXwNgA2EDYgNjA2QDZQQmA2cDaANp
3104 A2oDawQqgLmA74CygLOAt4Du0wAOA14DbgNvBC0ELoEBpIEB54EB6W8QEgBDAHUAcwB0AG8AbQBpAHoA
3105 ZQAgAFQAbwBvAGwAYgBhAHIgJl8QH3J1blRvb2xiYXJDdXN0b21pemF0aW9uUGFsZXR0ZTrTAA4DWANZ
3106 A1oEMwQ0gLuA8oD12AAOA14DXwNgA2EDYgNjA2QDZQQ3BDgEOQNpA2oDawQqgLmA8xIAGAAAgPSAs4C3
3107 gO5cU2hvdyBUb29sYmFyUXRfEBN0b2dnbGVUb29sYmFyU2hvd2460wAOA1gDWQNaBEIEQ4C7gPeA+tgA
3108 DgNeA18DYANhA2IDYwNkA2UERgNnBEcDaQNqA2sDp4C5gPiA+YCzgLeAxFRTYXZlUXNdc2F2ZURvY3Vt
3109 ZW50OtQADgRPA1gDWQRQBFEEUgRTXU5TRGVzdGluYXRpb26BAQCA/YD8gP/SAA4AMgAzADSABIAD0gAO
3110 ADIAMwRZgASA/l8QGklQeXRob24xU2FuZGJveEFwcERlbGVnYXRlWGRlbGVnYXRl0gA3ADgEXQReowRe
3111 A4oAO18QFE5TTmliT3V0bGV0Q29ubmVjdG9y0wAOA1gDWQNaBGEEYoC7gQECgQEF2QAOA14DXwNgA2ED
3112 YgNjA2QDtANlBGUDZwRmA2kDagNrA7sAVYC5gQEDgQEEgLOAt4DKXFNtYXJ0IFF1b3Rlc1FnXxAhdG9n
3113 Z2xlQXV0b21hdGljUXVvdGVTdWJzdGl0dXRpb2461AAOBE8DWANZBFAEbwRRBHGBAQCBAQeA/YEBCdIA
3114 DgAyADMEdIAEgQEIXxAWSVB5dGhvbkNvY29hQ29udHJvbGxlcl8QEWlweXRob25Db250cm9sbGVy0wAO
3115 A1gDWQNaBHkEeoC7gQELgQEO2AAOA14DXwNgA2EDYgNjA2QDZQR9A2cEfgNpA2oDawNsgLmBAQyBAQ2A
3116 s4C3gLBfEBRRdWl0IElQeXRob24xU2FuZGJveFFxWnRlcm1pbmF0ZTrTAA4DWANZA1oEhwSIgLuBARCB
3117 ARTYAA4DXgNfA2ADYQNiA2MDZANlBIsDZwSMA2kDagNrBI+AuYEBEoEBE4CzgLeBARHUAA4DXgHVA24D
3118 bwSSBJMElIEBpIEB64EB74EB7VhNaW5pbWl6ZVFtXxATcGVyZm9ybU1pbmlhdHVyaXplOtMADgNYA1kD
3119 WgSaBJuAu4EBFoEBGdgADgNeA18DYANhA2IDYwNkA2UEngNnBJ8DaQNqA2sDzYC5gQEXgQEYgLOAt4DQ
3120 VFVuZG9RelV1bmRvOtMADgNYA1kDWgSoBKmAu4EBG4EBHtgADgNeA18DYANhA2IDYwNkA2UErANnBK0D
3121 aQNqA2sDlYC5gQEcgQEdgLOAt4C+bgBTAGgAbwB3ACAAUwBwAGUAbABsAGkAbgBnICZROl8QD3Nob3dH
3122 dWVzc1BhbmVsOtMADgNYA1kDWgS2BLeAu4EBIIEBJNgADgNeA18DYANhA2IDYwNkA2UEugO3BLsDaQNq
3123 A2sEvoC5gQEigQEjgLOAt4EBIdMADgNeA24DbwTBBMKBAaSBAZ+BAaFbU2hvdyBDb2xvcnNRQ18QFW9y
3124 ZGVyRnJvbnRDb2xvclBhbmVsOtMADgNYA1kDWgTIBMmAu4EBJoEBKdgADgNeA18DYANhA2IDYwNkA2UE
3125 zAQ4BM0DaQNqA2sDbIC5gQEngQEogLOAt4CwW0hpZGUgT3RoZXJzUWhfEBZoaWRlT3RoZXJBcHBsaWNh
3126 dGlvbnM60wAOA1gDWQNaBNYE14C7gQErgQEu2AAOA14DXwNgA2EDYgNjA2QDZQTaA2cE2wNpA2oDawPN
3127 gLmBASyBAS2As4C3gNBUQ29weVFjVWNvcHk60wAOA1gDWQNaBOQE5YC7gQEwgQE02QAOA14DXwNgA2ED
3128 YgNjA2QDtANlBOgDZwTpA2kDagNrBOwAkIC5gQEygQEzgLOAt4EBMdMADgNeA24DbwTvBPCBAaSBAbWB
3129 AbdlAEYAaQBuAGQgJlFmXxAXcGVyZm9ybUZpbmRQYW5lbEFjdGlvbjrTAA4DWANZA1oE9gT3gLuBATaB
3130 ATjYAA4DXgNfA2ADYQNiA2MDZANlBPoDZwNoA2kDagNrA9+AuYEBN4CygLOAt4DWXVN0b3AgU3BlYWtp
3131 bmddc3RvcFNwZWFraW5nOtQADgRPA1gDWQNaAB8FBAUFgLuAAoEBOoEBPNcADgNeA2ADYQNiA2MDZANl
3132 BQgDaANpA2oDawNsgLmBATuAsoCzgLeAsF8QFUFib3V0IElQeXRob24xU2FuZGJveF8QHW9yZGVyRnJv
3133 bnRTdGFuZGFyZEFib3V0UGFuZWw60wAOA1gDWQNaBREFEoC7gQE+gQFB2QAOBRQDXgNfA2ADYQNiA2MD
3134 ZANlA2gFFwO3BRgDaQNqA2sDp1lOU1Rvb2xUaXCAuYCygQE/gQFAgLOAt4DEXVBhZ2UgU2V0dXAuLi5R
3135 UF5ydW5QYWdlTGF5b3V0OtQADgRPA1gDWQRQBG8AQQRTgQEAgQEHgAeA/9MADgNYA1kDWgUmBSeAu4EB
3136 RIEBR9gADgNeA18DYANhA2IDYwNkA2UFKgNnBSsDaQNqA2sDzYC5gQFFgQFGgLOAt4DQVVBhc3RlUXZW
3137 cGFzdGU61AAOBE8DWANZBFAAyABBBTaBAQCAGIAHgQFJXxAVaW5pdGlhbEZpcnN0UmVzcG9uZGVy0wAO
3138 A1gDWQNaBToFO4C7gQFLgQFO2AAOA14DXwNgA2EDYgNjA2QDZQU+A2cFPwNpA2oDawTsgLmBAUyBAU2A
3139 s4C3gQExXxARSnVtcCB0byBTZWxlY3Rpb25Ral8QHWNlbnRlclNlbGVjdGlvbkluVmlzaWJsZUFyZWE6
3140 0wAOA1gDWQNaBUgFSYC7gQFQgQFT2AAOA14DXwNgA2EDYgNjA2QDZQVMA2cDaANpA2oDawVQgLmBAVKA
3141 soCzgLeBAVHUAA4DXgHVA24DbwVTBVQFVYEBpIEBpYEBp4EBplpDbGVhciBNZW51XxAVY2xlYXJSZWNl
3142 bnREb2N1bWVudHM60wAOA1gDWQNaBVoFW4C7gQFVgQFX2AAOA14DXwNgA2EDYgNjA2QDZQVeA2cDaANp
3143 A2oDawPNgLmBAVaAsoCzgLeA0FZEZWxldGVXZGVsZXRlOtMADgNYA1kDWgVnBWiAu4EBWYEBW9cADgNe
3144 A2ADYQNiA2MDZANlBWsDaANpA2oDawOngLmBAVqAsoCzgLeAxF8QD1JldmVydCB0byBTYXZlZF8QFnJl
3145 dmVydERvY3VtZW50VG9TYXZlZDrUAA4ETwNYA1kEUADIBG8FdoEBAIAYgQEHgQFdWHRleHRWaWV30wAO
3146 A1gDWQNaBXoFe4C7gQFfgQFh2AAOA14DXwNgA2EDYgNjA2QDZQV+A2cDaANpA2oDawSPgLmBAWCAsoCz
3147 gLeBARFfEBJCcmluZyBBbGwgdG8gRnJvbnRfEA9hcnJhbmdlSW5Gcm9udDrTAA4DWANZA1oFhwWIgLuB
3148 AWOBAWXYAA4DXgNfA2ADYQNiA2MDZANlBYsDZwTNA2kDagNrA2yAuYEBZIEBKICzgLeAsF8QFEhpZGUg
3149 SVB5dGhvbjFTYW5kYm94VWhpZGU60wAOA1gDWQNaBZQFlYC7gQFngQFp2AAOA14DXwNgA2EDYgNjA2QD
3150 ZQWYA2cDaANpA2oDawSPgLmBAWiAsoCzgLeBARFUWm9vbVxwZXJmb3JtWm9vbTrTAA4DWANZA1oFoQWi
3151 gLuBAWuBAW3ZAA4DXgNfA2ADYQNiA2MDZAO0A2UFpQNnBOkDaQNqA2sDuwCQgLmBAWyBATOAs4C3gMpf
3152 EBBTbWFydCBDb3B5L1Bhc3RlXxAYdG9nZ2xlU21hcnRJbnNlcnREZWxldGU60wAOA1gDWQNaBa4Fr4C7
3153 gQFvgQFy2AAOA14DXwNgA2EDYgNjA2QDZQWyA7cFswNpA2oDawOngLmBAXCBAXGAs4C3gMRoAFMAYQB2
3154 AGUAIABBAHMgJlFTXxAPc2F2ZURvY3VtZW50QXM60wAOA1gDWQNaBbwFvYC7gQF0gQF32AAOA14DXwNg
3155 A2EDYgNjA2QDZQXAA2cFwQNpA2oDawPNgLmBAXWBAXaAs4C3gNBTQ3V0UXhUY3V0OtMADgNYA1kDWgXK
3156 BcuAu4EBeYEBfNgADgNeA18DYANhA2IDYwNkA2UFzgNnBc8DaQNqA2sDp4C5gQF6gQF7gLOAt4DEVUNs
3157 b3NlUXddcGVyZm9ybUNsb3NlOtcADgRPBdcF2ANYA1kF2QXaBFEF3AXdBd4F3wBVWU5TS2V5UGF0aFlO
3158 U0JpbmRpbmdfEBxOU05pYkJpbmRpbmdDb25uZWN0b3JWZXJzaW9ugQGMgP2BAYuBAYqBAX6BAYnbBeEA
3159 DgXiBeMF5AXlBeYF5wXoBekF6gB6BewAegXuAHoF8AXxAHoAegB6BfVfEBpOU0ZpbHRlclJlc3RyaWN0
3160 c0luc2VydGlvbl8QFE5TUHJlc2VydmVzU2VsZWN0aW9uXE5TSW5pdGlhbEtleVpOU0VkaXRhYmxlXk5T
3161 RGVjbGFyZWRLZXlzXk5TSW5pdGlhbFZhbHVlXxAiTlNDbGVhcnNGaWx0ZXJQcmVkaWNhdGVPbkluc2Vy
3162 dGlvbl8QGE5TU2VsZWN0c0luc2VydGVkT2JqZWN0c18QFk5TQXZvaWRzRW1wdHlTZWxlY3Rpb25fEBFO
3163 U1NvcnREZXNjcmlwdG9ycwmBAYgJgQGBCYEBf4EBggkJCYEBg9IADgA+AGkF+IA0owX5Be4F8YEBgIEB
3164 gYEBglRrZXlzU2tleVV2YWx1ZdIADgA+BgAGAYEBh6EGAoEBhNQADgYEBgUGBgYHBe4GCQB6VU5TS2V5
3165 Wk5TU2VsZWN0b3JbTlNBc2NlbmRpbmeBAYaBAYGBAYUJWGNvbXBhcmU60gA3ADgGDQYOogYOADtfEBBO
3166 U1NvcnREZXNjcmlwdG9y0gA3ADgGEAE4ogE4ADvSADcAOAYSBhOlBhMGFAYVBhYAO18QFk5TRGljdGlv
3167 bmFyeUNvbnRyb2xsZXJfEBFOU0FycmF5Q29udHJvbGxlcl8QEk5TT2JqZWN0Q29udHJvbGxlclxOU0Nv
3168 bnRyb2xsZXJfEClmaWx0ZXJQcmVkaWNhdGU6IHdvcmtzcGFjZUZpbHRlclByZWRpY2F0ZV8QD2ZpbHRl
3169 clByZWRpY2F0ZV8QGHdvcmtzcGFjZUZpbHRlclByZWRpY2F0ZdIANwA4BhsGHKMGHAOKADtfEBVOU05p
3170 YkJpbmRpbmdDb25uZWN0b3LXAA4ETwXXBdgDWANZBdkF2gRvBiAGIQXeBiMAVYEBjIEBB4EBkIEBj4EB
3171 foEBjl8QGWNvbnRlbnREaWN0aW9uYXJ5OiB1c2VyTlNfEBFjb250ZW50RGljdGlvbmFyeVZ1c2VyTlPX
3172 AA4ETwXXBdgDWANZBdkF2gXeBioF8QJ2Bi0AVYEBjIEBfoEBk4EBgoCLgQGSXxAcdmFsdWU6IGFycmFu
3173 Z2VkT2JqZWN0cy52YWx1ZV8QFWFycmFuZ2VkT2JqZWN0cy52YWx1ZdcADgRPBdcF2ANYA1kF2QXaBd4G
3174 MwXxAnUGNgBVgQGMgQF+gQGWgQGCgHyBAZVfEBp2YWx1ZTogYXJyYW5nZWRPYmplY3RzLmtleV8QE2Fy
3175 cmFuZ2VkT2JqZWN0cy5rZXnXAA4ETwXXBdgDWANZBdkF2gRvBjwGPQBsBj8AVYEBjIEBB4EBmoEBmYCj
3176 gQGYXxAZYW5pbWF0ZTogd2FpdGluZ0ZvckVuZ2luZVdhbmltYXRlXxAQd2FpdGluZ0ZvckVuZ2luZdIA
3177 DgA+BgAGRYEBh68QZwZGAGsE5AVaBkoCwAVQBk0CgwZPBlAE1gZSBlMGVARCAE0AfgPwA7sEBwT2A7EE
3178 FQP6AgoAfwNsBJoGYwOnAEECKgTIA1sEeQPfBSYFegRSBm4EbwPoAMgF3gWuBnQE7AONBUgGeAZ5BGED
3179 nwOVA80GfgQqBoAEUQaCBREEMwIaBoYGhwaIBokAqgaLBCIFBASoA9cAbAWHBcoCRAaUA8UGlgJ2ALEF
3180 OgS+BpsFvAJ1Bp4FZwagBIcFoQS2AKMGpQIQBqcGqAWUBqoGqwSPgQGcgA6BATCBAVWBAZ2AjoEBUYEB
3181 qICDgQGqgQGugQErgQGygQGegQG/gPeAC4AQgNuAyoDkgQE2gMmA6YDggG6AaoCwgQEWgQHYgMSAB4By
3182 gQEmgK+BAQuA1oEBRIEBX4D8gQHVgQEHgNqAGIEBfoEBb4EB6oEBMYC9gQFQgQHlgQHugQECgMOAvoDQ
3183 gQG4gO6BAeGA/YEBzoEBPoDygJSBAbyBAcmBAd6BAeaAWIEBtIDtgQE6gQEbgNWAo4EBY4EBeYB0gQHN
3184 gM+BAdqAi4BUgQFLgQEhgQHwgQF0gHyBAbOBAVmBAcOBARCBAWuBASCAFIEB0YCWgQHSgQGigQFngQG6
3185 gQHkgQER2gAOA14DXwauA2AGrwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA2xdTlNJc1NlcGFyYXRv
3186 clxOU0lzRGlzYWJsZWSAuYCyCYCyCYCzgLeAsNoADga5A14DXwNgA2EDYgNjA2QBoANlBL4EwQNnA2gD
3187 aQNqA2sGUwbBWU5TU3VibWVudYC5gQEhgQGfgLKAs4C3gQGegQGg1AAOA14B1QNuA28GxAbFBsaBAaSB
3188 AceBAfSBAchWRm9ybWF0XnN1Ym1lbnVBY3Rpb2460gAOAD4AaQbLgDSiBqgEtoEBooEBINgADgNeA18D
3189 YANhA2IDYwNkA2UG0ANnBDkDaQNqA2sEvoC5gQGjgPSAs4C3gQEhWlNob3cgRm9udHPSADcAOAbXA2Si
3190 A2QAO1tPcGVuIFJlY2VudNIADgA+AGkG24A0oQVIgQFQXxAWX05TUmVjZW50RG9jdW1lbnRzTWVuddoA
3191 Dga5A14DXwNgA2EDYgNjA2QBoANlBVAFUwNnA2gDaQNqA2sDpwbmgLmBAVGBAaWAsoCzgLeAxIEBqdoA
3192 Dga5A14DXwNgA2EDYgNjA2QBoANlA5UDmANnA2gDaQNqA2sDzQbvgLmAvoEBq4CygLOAt4DQgQGsXxAU
3193 U3BlbGxpbmcgYW5kIEdyYW1tYXLSAA4APgBpBvOANKQEqAONA/oEFYEBG4C9gOCA6doADga5A14DXwNg
3194 A2EDYgNjA2QBoANlA80D0ANnA2gDaQNqA2sGUwcAgLmA0IEBr4CygLOAt4EBnoEBsFRFZGl00gAOAD4A
3195 aQcEgDStBJoDxQZSBbwE1gUmBVoEBwaeBosGTwZUBqCBARaAz4EBsoEBdIEBK4EBRIEBVYDkgQGzgQG0
3196 gQGqgQG/gQHD2gAOA14DXwauA2AGrwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA82AuYCyCYCyCYCz
3197 gLeA0NoADgNeA18GrgNgBq8DYQNiA2MDZANlA2gDZwB6A2gAegNpA2oDawPNgLmAsgmAsgmAs4C3gNDa
3198 AA4GuQNeA18DYANhA2IDYwNkAaADZQTsBO8DZwNoA2kDagNrA80HLIC5gQExgQG1gLKAs4C3gNCBAbZU
3199 RmluZNIADgA+AGkHMIA0pQTkBn4GqgaGBTqBATCBAbiBAbqBAbyBAUvZAA4DXgNfA2ADYQNiA2MDZAO0
3200 A2UHOANnBGYDaQNqA2sE7ABVgLmBAbmBAQSAs4C3gQExWUZpbmQgTmV4dNkADgNeA18DYANhA2IDYwNk
3201 A7QDZQdAA7cDuANpA2oDawTsAViAuYEBu4DMgLOAt4EBMV1GaW5kIFByZXZpb3Vz2QAOA14DXwNgA2ED
3202 YgNjA2QDtANlB0gDZwdJA2kDagNrBOwHTYC5gQG9gQG+gLOAt4EBMRAHXxAWVXNlIFNlbGVjdGlvbiBm
3203 b3IgRmluZFFl2gAOBrkDXgNfA2ADYQNiA2MDZAGgA2UDuwO+A2cDaANpA2oDawPNB1iAuYDKgQHAgLKA
3204 s4C3gNCBAcFdU3Vic3RpdHV0aW9uc9IADgA+AGkHXIA0owWhBGEDsYEBa4EBAoDJ2gAOBrkDXgNfA2AD
3205 YQNiA2MDZAGgA2UD3wPiA2cDaANpA2oDawPNB2iAuYDWgQHEgLKAs4C3gNCBAcVWU3BlZWNo0gAOAD4A
3206 aQdsgDSiA9cE9oDVgQE2WUFNYWluTWVuddIADgA+AGkHcoA0pwaHBpYGUAZKBokGdAabgQHJgQHagQGu
3207 gQGdgQHmgQHqgQHw2gAOBrkDXgNfA2ADYQNiA2MDZAGgA2UDbANwA2cDaANpA2oDawZTB4KAuYCwgQHK
3208 gLKAs4C3gQGegQHLXxAPSVB5dGhvbjFTYW5kYm940gAOAD4AaQeGgDSrBQQGlAaCBqUGpwZGBYcEyANb
3209 BmMEeYEBOoEBzYEBzoEB0YEB0oEBnIEBY4EBJoCvgQHYgQEL2gAOA14DXwauA2AGrwNhA2IDYwNkA2UD
3210 aANnAHoDaAB6A2kDagNrA2yAuYCyCYCyCYCzgLeAsNgADgNeA18DYANhA2IDYwNkA2UHnQNnB54DaQNq
3211 A2sDbIC5gQHPgQHQgLOAt4CwbABQAHIAZQBmAGUAcgBlAG4AYwBlAHMgJlEs2gAOA14DXwauA2AGrwNh
3212 A2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA2yAuYCyCYCyCYCzgLeAsNoADga5A14DXwNgA2EDYgNjA2QB
3213 oANlBm4HsANnA2gDaQNqA2sDbAe1gLmBAdWBAdOAsoCzgLeAsIEB1FhTZXJ2aWNlc9QADgNeAdUDbgNv
3214 B7AHuge7gQGkgQHTgQHXgQHW0gAOAD4AaQe+gDSgXxAPX05TU2VydmljZXNNZW512gAOA14DXwauA2AG
3215 rwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA2yAuYCyCYCyCYCzgLeAsFxfTlNBcHBsZU1lbnXaAA4G
3216 uQNeA18DYANhA2IDYwNkAaADZQOnA6oDZwNoA2kDagNrBlMH0oC5gMSBAduAsoCzgLeBAZ6BAdxURmls
3217 ZdIADgA+AGkH1oA0qwaIBoAGTQarBcoEQgWuBWcGeAURA5+BAd6BAeGBAaiBAeSBAXmA94EBb4EBWYEB
3218 5YEBPoDD2AAOA14DXwNgA2EDYgNjA2QDZQfkA2cH5QNpA2oDawOngLmBAd+BAeCAs4C3gMRTTmV3UW7Y
3219 AA4DXgNfA2ADYQNiA2MDZANlB+0DZwfuA2kDagNrA6eAuYEB4oEB44CzgLeAxGUATwBwAGUAbiAmUW/a
3220 AA4DXgNfBq4DYAavA2EDYgNjA2QDZQNoA2cAegNoAHoDaQNqA2sDp4C5gLIJgLIJgLOAt4DE2gAOA14D
3221 XwauA2AGrwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA6eAuYCyCYCyCYCzgLeAxNoADga5A14DXwNg
3222 A2EDYgNjA2QBoANlBCoELQNnA2gDaQNqA2sGUwgOgLmA7oEB54CygLOAt4EBnoEB6FRWaWV30gAOAD4A
3223 aQgSgDSiBDMEIoDygO3aAA4GuQNeA18DYANhA2IDYwNkAaADZQSPBJIDZwNoA2kDagNrBlMIHYC5gQER
3224 gQHrgLKAs4C3gQGegQHsVldpbmRvd9IADgA+AGkIIYA0pASHBZQGeQV6gQEQgQFngQHugQFf2gAOA14D
3225 XwauA2AGrwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrBI+AuYCyCYCyCYCzgLeBARFeX05TV2luZG93
3226 c01lbnXaAA4GuQNeA18DYANhA2IDYwNkAaADZQPwA/MDZwNoA2kDagNrBlMIOIC5gNuBAfGAsoCzgLeB
3227 AZ6BAfJUSGVscNIADgA+AGkIPIA0oQPogNpbX05TTWFpbk1lbnXSAA4APgYACEGBAYevEGcDbABNBOwD
3228 zQZTAnYGTQOnAnUDzQZTA80DzQAfA80DpwBBAGsGmwZUA80D3wO7A5UDlQB/AGsGhwPNA2wGlgAfAgoD
3229 bANsA2wGoAPNBI8AHwanAB8D8ACjAB8DpwZTBosDlQVQA6cEjwO7A6cGTwZQBOwGiQOnAB8DbAOnBCoC
3230 CgTsBlMDpwZTAKMDzQQqA2wDlQPfAE0DbAOnAgoDbAPNBlMCKgCjBOwGSgZTA80CKgPNA6cDzQSPA7sE
3231 vgB+A2wCCgNsBL4EjwTsA6cGdICwgAuBATGA0IEBnoCLgQGogMSAfIDQgQGegNCA0IACgNCAxIAHgA6B
3232 AfCBAb+A0IDWgMqAvoC+gGqADoEByYDQgLCBAdqAAoBugLCAsICwgQHDgNCBARGAAoEB0oACgNuAFIAC
3233 gMSBAZ6BAbSAvoEBUYDEgQERgMqAxIEBqoEBroEBMYEB5oDEgAKAsIDEgO6AboEBMYEBnoDEgQGegBSA
3234 0IDugLCAvoDWgAuAsIDEgG6AsIDQgQGegHKAFIEBMYEBnYEBnoDQgHKA0IDEgNCBARGAyoEBIYAQgLCA
3235 boCwgQEhgQERgQExgMSBAerSAA4APgYACKuBAYevEGgAawZGBOQFWgZKAsAFUAZNAoMGTwZQBNYGUgZT
3236 BlQATQRCAH4D8AO7BAcE9gOxBBUCCgP6AH8DbABBA6cEmgZjAioEyANbBHkD3wUmBXoEUgZuBG8D6ADI
3237 Bd4AHwWuBnQGeATsA40FSAZ5BGEDnwOVA80EKgZ+BoAEUQaCBREEMwIaBoYGhwaJBogAqgaLBCIFBABs
3238 BKgD1wWHBcoCRAaUA8UGlgJ2ALEEvgU6BpsFvAJ1Bp4FZwagBIcFoQS2AKMGpQIQBqcGqAWUBqoGqwSP
3239 gA6BAZyBATCBAVWBAZ2AjoEBUYEBqICDgQGqgQGugQErgQGygQGegQG/gAuA94AQgNuAyoDkgQE2gMmA
3240 6YBugOCAaoCwgAeAxIEBFoEB2IBygQEmgK+BAQuA1oEBRIEBX4D8gQHVgQEHgNqAGIEBfoACgQFvgQHq
3241 gQHlgQExgL2BAVCBAe6BAQKAw4C+gNCA7oEBuIEB4YD9gQHOgQE+gPKAlIEBvIEByYEB5oEB3oBYgQG0
3242 gO2BATqAo4EBG4DVgQFjgQF5gHSBAc2Az4EB2oCLgFSBASGBAUuBAfCBAXSAfIEBs4EBWYEBw4EBEIEB
3243 a4EBIIAUgQHRgJaBAdKBAaKBAWeBAbqBAeSBARHSAA4APgYACRaBAYevEGgJFwkYCRkJGgkbCRwJHQke
3244 CR8JIAkhCSIJIwkkCSUJJgknCSgJKQkqCSsJLAktCS4JLwkwCTEJMgkzCTQJNQk2CTcJOAk5CToJOwk8
3245 CT0JPgk/CUAJQQlCCUMJRAlFCUYJRwlICUkJSglLCUwJTQlOCU8JUAlRCVIEWQlUCVUJVglXCVgJWQla
3246 CVsJXAldCV4JXwlgCWEJYgljCWQJZQlmCWcJaAlpCWoJawlsCW0JbglvCXAJcQlyCXMJdAl1CXYJdwl4
3247 CXkJegl7CXwJfQl+gQH4gQH5gQH6gQH7gQH8gQH9gQH+gQH/gQIAgQIBgQICgQIDgQIEgQIFgQIGgQIH
3248 gQIIgQIJgQIKgQILgQIMgQINgQIOgQIPgQIQgQIRgQISgQITgQIUgQIVgQIWgQIXgQIYgQIZgQIagQIb
3249 gQIcgQIdgQIegQIfgQIggQIhgQIigQIjgQIkgQIlgQImgQIngQIogQIpgQIqgQIrgQIsgQItgQIugQIv
3250 gQIwgQIxgQIygQIzgP6BAjSBAjWBAjaBAjeBAjiBAjmBAjqBAjuBAjyBAj2BAj6BAj+BAkCBAkGBAkKB
3251 AkOBAkSBAkWBAkaBAkeBAkiBAkmBAkqBAkuBAkyBAk2BAk6BAk+BAlCBAlGBAlKBAlOBAlSBAlWBAlaB
3252 AleBAliBAlmBAlqBAluBAlyBAl2BAl5aU3BsaXQgVmlld1tTZXBhcmF0b3ItM28QEQBNAGUAbgB1ACAA
3253 SQB0AGUAbQAgACgARgBpAG4AZCAmAClfEBJNZW51IEl0ZW0gKERlbGV0ZSlfEBJNZW51IEl0ZW0gKEZv
3254 cm1hdClfEBtUZXh0IEZpZWxkIENlbGwgKFRleHQgQ2VsbClfEBJNZW51IChPcGVuIFJlY2VudClfEBdN
3255 ZW51IEl0ZW0gKE9wZW4gUmVjZW50KV8QHVRleHQgRmllbGQgQ2VsbCAoVGV4dCBDZWxsKS0xXxAgTWVu
3256 dSBJdGVtIChTcGVsbGluZyBhbmQgR3JhbW1hcilfEBBNZW51IEl0ZW0gKEVkaXQpXxAQTWVudSBJdGVt
3257 IChDb3B5KVlTZXBhcmF0b3JYTWFpbk1lbnVfEBlNZW51IEl0ZW0gKFN1YnN0aXR1dGlvbnMpXENvbnRl
3258 bnQgVmlld1EzXUJveCAoQ29uc29sZSlRMl8QFE1lbnUgKFN1YnN0aXR1dGlvbnMpXxAWTWVudSBJdGVt
3259 IChTZWxlY3QgQWxsKV8QGU1lbnUgSXRlbSAoU3RvcCBTcGVha2luZylfEBdNZW51IEl0ZW0gKFNtYXJ0
3260 IExpbmtzKV8QJ01lbnUgSXRlbSAoQ2hlY2sgR3JhbW1hciBXaXRoIFNwZWxsaW5nKV1TY3JvbGwgVmll
3261 dy0xXxAnTWVudSBJdGVtIChDaGVjayBTcGVsbGluZyBXaGlsZSBUeXBpbmcpXxAPQm94IChXb3Jrc3Bh
3262 Y2UpXxAWTWVudSAoSVB5dGhvbjFTYW5kYm94KV8QGVdpbmRvdyAoSVB5dGhvbjEgKENvY29hKSlbTWVu
3263 dSAoRmlsZSlfEBBNZW51IEl0ZW0gKFVuZG8pW1NlcGFyYXRvci00XxAcVGFibGUgVmlldyAoVmFyaWFi
3264 bGUsIFZhbHVlKV8QF01lbnUgSXRlbSAoSGlkZSBPdGhlcnMpXxAUTWVudSBJdGVtIChTaG93IEFsbClU
3265 MTExMV1NZW51IChTcGVlY2gpXxARTWVudSBJdGVtIChQYXN0ZSlfEB5NZW51IEl0ZW0gKEJyaW5nIEFs
3266 bCB0byBGcm9udClbQXBwbGljYXRpb25fEA9NZW51IChTZXJ2aWNlcylfEBdQeXRob24gQ29jb2EgQ29u
3267 dHJvbGxlcl8QIE1lbnUgSXRlbSAoSVB5dGhvbjFTYW5kYm94IEhlbHApWVRleHQgVmlld18QGVVzZXIg
3268 TmFtZXNwYWNlIENvbnRyb2xsZXJcRmlsZSdzIE93bmVyUThfEBJNZW51IEl0ZW0gKFdpbmRvdylTMi0x
3269 W01lbnUgKEZpbmQpXxAaTWVudSBJdGVtIChDaGVjayBTcGVsbGluZylfEBZNZW51IEl0ZW0gKENsZWFy
3270 IE1lbnUpW1NlcGFyYXRvci0yXxAYTWVudSBJdGVtIChTbWFydCBRdW90ZXMpUTZfEBtNZW51IChTcGVs
3271 bGluZyBhbmQgR3JhbW1hcilbTWVudSAoRWRpdClbTWVudSAoVmlldylfEBVNZW51IEl0ZW0gKEZpbmQg
3272 TmV4dClvEBEATQBlAG4AdQAgAEkAdABlAG0AIAAoAE8AcABlAG4gJgApUzEyMVE1XxAYTWVudSBJdGVt
3273 IChTaG93IFRvb2xiYXIpXxATVmVydGljYWwgU2Nyb2xsZXItMV8QIk1lbnUgSXRlbSAoVXNlIFNlbGVj
3274 dGlvbiBmb3IgRmluZClfEBtNZW51IEl0ZW0gKElQeXRob24xU2FuZGJveClfEBBNZW51IEl0ZW0gKFZp
3275 ZXcpUTlfEBNIb3Jpem9udGFsIFNjcm9sbGVyXxAQTWVudSBJdGVtIChGaW5kKW8QHgBNAGUAbgB1ACAA
3276 SQB0AGUAbQAgACgAQwB1AHMAdABvAG0AaQB6AGUAIABUAG8AbwBsAGIAYQByICYAKV8QIU1lbnUgSXRl
3277 bSAoQWJvdXQgSVB5dGhvbjFTYW5kYm94KVxBc3luYyBBcnJvd3NvEBoATQBlAG4AdQAgAEkAdABlAG0A
3278 IAAoAFMAaABvAHcAIABTAHAAZQBsAGwAaQBuAGcgJgApXxAaTWVudSBJdGVtIChTdGFydCBTcGVha2lu
3279 ZylfECBNZW51IEl0ZW0gKEhpZGUgSVB5dGhvbjFTYW5kYm94KVMxLTFfEBFUYWJsZSBIZWFkZXIgVmll
3280 d1tTZXBhcmF0b3ItNV8QEE1lbnUgSXRlbSAoUmVkbylfEBBNZW51IEl0ZW0gKEZpbGUpXxAUVGFibGUg
3281 Q29sdW1uIChWYWx1ZSlfEBFWZXJ0aWNhbCBTY3JvbGxlcl1NZW51IChGb3JtYXQpXxAdTWVudSBJdGVt
3282 IChKdW1wIHRvIFNlbGVjdGlvbilRMV8QD01lbnUgSXRlbSAoQ3V0KV8QF1RhYmxlIENvbHVtbiAoVmFy
3283 aWFibGUpW1NlcGFyYXRvci0xUjEwXxASTWVudSBJdGVtIChTcGVlY2gpXxAUTWVudSBJdGVtIChNaW5p
3284 bWl6ZSlfEBxNZW51IEl0ZW0gKFNtYXJ0IENvcHkvUGFzdGUpXxAXTWVudSBJdGVtIChTaG93IENvbG9y
3285 cylbU2Nyb2xsIFZpZXdbU2VwYXJhdG9yLTZfEBVIb3Jpem9udGFsIFNjcm9sbGVyLTFfEBRNZW51IEl0
3286 ZW0gKFNlcnZpY2VzKV8QFk1lbnUgSXRlbSAoU2hvdyBGb250cylfEBBNZW51IEl0ZW0gKFpvb20pXxAZ
3287 TWVudSBJdGVtIChGaW5kIFByZXZpb3VzKVE3XU1lbnUgKFdpbmRvdynSAA4APgYACeiBAYeg0gAOAD4G
3288 AAnrgQGHoNIADgA+BgAJ7oEBh68QlwZGAGsDUATkBVoGSgM8Az8CwAVQBk0DLQNHA1UCgwNEBk8GUAMr
3289 A08E1gZSAygDSAZTBlQEQgBNAH4D8AO7BAcE9gOxA0kEFQP6AgoAfwNsBJoGYwOnAEECKgTIA0EDWwNG
3290 BHkD3wNKBSYFegRSAzQDTgNUA1EDMgM3A00GbgRvA+gAyAXeAB8FrgZ0BOwDjQVIBngDMQM6BnkEYQOf
3291 AzsDlQPNAzkGfgQqAykGgARRBoIFEQQzAhoDOANFAyoGhgMwBocGiAaJAKoGiwQiAywFBASoA9cAbAWH
3292 A0wFygM2AkQGlAPFBpYCdgNCAzMDLgCxBToEvgabBbwCdQaeBWcGoAM1Az0EhwNLBaEEtgM+AKMDUgal
3293 AhADVganBqgDQANDBZQGqgMvA1MGqwSPgQGcgA6BAXOBATCBAVWBAZ2BAR+BAS+AjoEBUYEBqIDUgQFP
3294 gQGUgIOBAUOBAaqBAa6AyIEBboEBK4EBsoCugQFUgQGegQG/gPeAC4AQgNuAyoDkgQE2gMmBAViA6YDg
3295 gG6AaoCwgQEWgQHYgMSAB4BygQEmgQE5gK+BAUqBAQuA1oEBXIEBRIEBX4D8gPaBAWqBAZGBAXiA7IEB
3296 BoEBZoEB1YEBB4DagBiBAX6AAoEBb4EB6oEBMYC9gQFQgQHlgOiBARWBAe6BAQKAw4EBGoC+gNCBAQ+B
3297 AbiA7oC8gQHhgP2BAc6BAT6A8oCUgQEKgQFIgMKBAbyA44EByYEB3oEB5oBYgQG0gO2AzoEBOoEBG4DV
3298 gKOBAWOBAWKBAXmBAQGAdIEBzYDPgQHagIuBAT2A8YDZgFSBAUuBASGBAfCBAXSAfIEBs4EBWYEBw4D7
3299 gQElgQEQgQFegQFrgQEggQEqgBSBAX2BAdGAloEBl4EB0oEBooEBNYEBQoEBZ4EBuoDfgQGNgQHkgQER
3300 0gAOAD4GAAqIgQGHrxCXCokKigqLCowKjQqOCo8KkAqRCpIKkwqUCpUKlgqXCpgKmQqaCpsKnAqdCp4K
3301 nwqgCqEKogqjCqQKpQqmCqcKqAqpCqoKqwqsCq0KrgqvCrAKsQqyCrMKtAq1CrYKtwq4CrkKugq7CrwK
3302 vQq+Cr8KwArBCsIKwwrECsUKxgrHCsgKyQrKCssKzArNCs4KzwrQCtEK0grTCtQK1QrWCtcK2ArZCtoK
3303 2wrcCt0K3grfCuAK4QriCuMK5ArlCuYK5wroCukK6grrCuwK7QruCu8K8ArxCvIK8wr0CvUK9gr3CvgK
3304 +Qr6CvsK/Ar9Cv4K/wsACwELAgsDCwQLBQsGCwcLCAsJCwoLCwsMCw0LDgsPCxALEQsSCxMLFAsVCxYL
3305 FwsYCxkLGgsbCxwLHQseCx+BAmOBAmSBAmWBAmaBAmeBAmiBAmmBAmqBAmuBAmyBAm2BAm6BAm+BAnCB
3306 AnGBAnKBAnOBAnSBAnWBAnaBAneBAniBAnmBAnqBAnuBAnyBAn2BAn6BAn+BAoCBAoGBAoKBAoOBAoSB
3307 AoWBAoaBAoeBAoiBAomBAoqBAouBAoyBAo2BAo6BAo+BApCBApGBApKBApOBApSBApWBApaBApeBApiB
3308 ApmBApqBApuBApyBAp2BAp6BAp+BAqCBAqGBAqKBAqOBAqSBAqWBAqaBAqeBAqiBAqmBAqqBAquBAqyB
3309 Aq2BAq6BAq+BArCBArGBArKBArOBArSBArWBAraBAreBAriBArmBArqBAruBAryBAr2BAr6BAr+BAsCB
3310 AsGBAsKBAsOBAsSBAsWBAsaBAseBAsiBAsmBAsqBAsuBAsyBAs2BAs6BAs+BAtCBAtGBAtKBAtOBAtSB
3311 AtWBAtaBAteBAtiBAtmBAtqBAtuBAtyBAt2BAt6BAt+BAuCBAuGBAuKBAuOBAuSBAuWBAuaBAueBAuiB
3312 AumBAuqBAuuBAuyBAu2BAu6BAu+BAvCBAvGBAvKBAvOBAvSBAvWBAvaBAveBAviBAvkQkBEBpRDkENEQ
3313 yhEBKxEBaRDxEQGeEH0QfBDpEH8RAawRAZ8Q4hDYENkRAWURAWsQxRDOEQFyEOsQHREBXBBLEQF0EQGk
3314 EGoRAV0QxhDDEQFiEQFsEQFaENsRAZcRAZYQORDPEJUQUREBcxEBmxCREI4QlhD1EIgQ1BEBvBDLEAUT
3315 //////////0RAWoRAWMRAasQwREBbREBuRDwEIIRAaYQbxEBoxEBgREBvhBQEBMQ3BDJEH4QShEBWxDf
3316 EFwRAV8QThDmEMgQzRAlENARASgQ4RBIEQF1EIEQTREBKREBmREBcREBvRBWEN0Q6BA4EFIRAScRAaIQ
3317 2hEBKhDnEDoQzBDEEQG0EIYRAW8QSREBZBEBmBDsENcQUxEBnRBXEQFuEQFoEQGhENIRASwQZxDHEQGc
3318 ENYQcBDTEQF2EQFwEBcQJxEBXhEBWRDgEQGgEQG4EI8RAZoRAbUQgxEBWBDjEQGtEO8Q1RDeEQGoEE8Q
3319 GNIADgA+AGkLuYA0oNIADgA+BgALvIEBh6DSAA4APgYAC7+BAYeg0gA3ADgLwQvCogvCADteTlNJQk9i
3320 amVjdERhdGEACAAZACIAJwAxADoAPwBEAFIAVABmBmYGbAa3Br4GxQbTBuUHAQcPBxsHJwc1B0AHTgdq
3321 B3gHiwedB7cHwQfOB9AH0wfWB9kH3AfeB+EH4wfmB+kH7AfvB/EH8wf2B/kH/Af/CAgIFAgWCBgIJggv
3322 CDgIQwhICFcIYAhzCHwIhwiJCIwIjgi7CMgI1QjrCPkJAwkRCR4JMAlECVAJUglUCVYJWAlaCV8JYQlj
3323 CWUJZwlpCYQJlwmgCb0JzwnaCeMJ7wn7Cf0J/woBCgQKBgoICgoKEwoVChoKHAoeCkcKTwpeCm0Kegp8
3324 Cn4KgAqCCoUKhwqJCosKjAqVCpcKnAqeCqAK2QrjCu8K/QsKCxQLJgs0CzYLOAs6CzwLPQs/C0ELQwtF
3325 C0cLSQtLC00LVgtYC1sLXQt6C3wLfguAC4ILhAuGC48LkQuUC5YLxwvTC9wL6Av2C/gL+gv8C/4MAQwD
3326 DAUMBwwJDAsMDQwWDBgMHwwhDCMMJQxaDGMMbAx2DIAMigyMDI4MkAySDJQMlgyYDJsMnQyfDKEMowyl
3327 DK4MsAyzDLUM6gz8DQYNEw0fDSkNMg09DT8NQQ1DDUUNRw1JDUsNTg1QDVINVA1WDVgNYQ1jDYgNig2M
3328 DY4NkA2SDZQNlg2YDZoNnA2eDaANog2kDaYNqA2qDcYN2w34DhkONQ5bDoEOnw67DtcO9A8MDyYPWg93
3329 D5MPwA/JD9AP3Q/jD/oQDxAZECQQLBA+EEAQQhBLEE0QYhB1EIMQjRCPEJEQkxCVEKIQqxCtEK8QsRC6
3330 EMQQxhDHENAQ1xDpEPIQ+xEXESwRNRE3EToRPBFFEUwRWxFjEWwRcRF6EX8RoBGoEcIR1RHpEgASFRIo
3331 EioSLxIxEjMSNRI3EjkSOxJIElUSWxJdEngSgRKGEo4SmxKjEqUSpxKqErcSvxLBEsYSyBLKEs8S0RLT
3332 EugS9BMCEwQTBhMIEwoTERMvEzwTPhNKE18TYRNjE2UTZxN7E4QTiROWE6MTpROqE6wTrhOzE7UTtxPD
3333 E9AT0hPZE+IT5xP+FAsUExQcFCcULhQ1FEEUWBRwFH0UfxSCFI8UmRSmFKgUqhSyFLsUwBTJFNIU3RUC
3334 FQsVFBUeFSAVIhUkFSYVLxUxFTMVNRU+FVYVYxVsFXcVghWMFbkVxBXGFcgVyhXMFc4V0BXSFdsV5BX/
3335 FhgWIRYqFjcWThZXFl4WaRZwFo0WmRakFq4WuxbHFswWzhbQFtIW1BbWFt4W7xb2Fv0XBhcIFxEXExcW
3336 FyMXLBcxFzgXTRdPF1EXUxdVF2sXeBd6F4gXkReaF6wXuRfAF8kX0hfYGBEYExgVGBcYGRgaGBwYHhgg
3337 GCIYJBgmGC8YMRg0GDYYUxhVGFcYWRhbGF0YXxhoGGoYbRhvGK4YuxjOGNsY3RjfGOEY4xjlGOcY6Rjr
3338 GP4ZABkCGQQZBhkIGREZExkeGSAZIhkkGSYZKBlVGVcZWRlbGV0ZXxlhGWMZZRlnGXAZchl1GXcZzhnw
3339 GfoaBxocGjYaUhptGncagxqVGqQawxrPGtEa0xrcGt4a4BrhGuMa7Br1Gvca+Br6Gvwa/hsAGwkbFBsx
3340 Gz0bPxtBG0MbRRtHG0kbdht4G3obfBt+G4AbghuEG4YbiBuSG5sbpBu4G9Eb0xvVG9cb2RvbG/Ib+xwE
3341 HBIcGxwdHCIcJBwmHE8cXhxrHHYchRyQHJscqBypHKscrRy2HLgcwRzKHMsczRzqHO8c8RzzHPUc9xz5
3342 HQIdDx0RHR0dMh00HTYdOB06HUwdVR1gHXQdlR2jHagdqh2sHa4dsB2yHbUdtx3BHdId1B3dHd8d4h33
3343 Hfkd+x39Hf8eGB4tHi8eMR4zHjUeSB5RHlYeZB6NHo4ekB6SHpsenR6eHqAevR6/HsEewx7FHscezR7u
3344 HvAe8h70HvYe+B76Hw8fER8THxUfFx8hHy4fMB81Hz4fSR9hH4YfiB+KH4wfjh+QH5IflB+dH7Yf3x/h
3345 H+Mf5R/nH+kf6x/tH/YgDiAXIBkgHCAeIDQgTSBkIH0gmiCcIJ4goCCiIKQgriC7IL0g1iD5IQIhCyEX
3346 IUAhSyFWIWAhbSFvIXEhcyF8IYUhiCGKIY0hjyGRIZYhmCGhIaYhsSHJIdIh2yHxIfwiFCInIjAiNSJI
3347 IlEiUyK0IrYiuCK6IrwiviLAIsIixCLGIsgiyiLMIs4i0CLTItYi2SLcIt8i4iLlIugi6yLuIvEi9CL3
3348 Ivoi/SMAIwMjBiMJIwwjDyMSIxUjGCMbIx4jISMkIycjKiMtIzAjMyNAI0kjUSNTI1UjVyN4I4AjlCOf
3349 I60jtyPEI8sjzSPPI9Qj1iPbI90j3yPhI/Ij/iQBJAQkByQKJBMkICQvJDEkMyQ1JD0kTyRYJF0kcCR9
3350 JH8kgSSDJJYknySkJK8kyCTRJNgk8CT/JQwlDiUQJRIlMyU1JTclOSU7JT0lPyVMJU8lUiVVJWQlZiV1
3351 JYIlhCWGJYglqSWrJa0lryWxJbMltSXCJcUlyCXLJdgl2iXhJe4l8CXyJfQmGSYfJiEmIyYoJiomLCYu
3352 JjAmPSZAJkMmRiZSJlQmdCaBJoMmhSaHJqgmqiasJq4msCayJrQmwSbEJscmyibPJtEm1ybkJuYm6Cbq
3353 JwsnDScPJxEnEycVJxcnJCcnJyonLSc8J0snWCdaJ1wnXid/J4EngyeFJ4cniSeLJ5gnmyeeJ6EnuCe6
3354 J8Qn0SfTJ9Un1yf4J/on/Cf+KAAoAigEKCIoQyhQKFIoVChWKHcoeSh7KH0ofyiBKIMojiiQKJsoqCiq
3355 KKworijPKNEo0yjVKNco2SjbKPkpEikfKSEpIyklKUYpSClKKUwpTilQKVIpXyliKWUpaCmPKbEpvinA
3356 KcIpxCnlKecp6SnuKfAp8in0KfYqAyoFKhsqKCoqKiwqLipPKlEqUypVKlcqWSpbKmAqYipwKoEqjyqS
3357 KpQqliqYKqEqoyqlKq4qsCqyKs8q2CrhKugq/ysMKw4rESsUKzkrOys+K0ErQytFK0crVCtWK3oriyuO
3358 K5ErkyuWK58roSukK70r0SveK+Ar4yvmLAcsCSwMLA8sESwTLBUsLCwuLDksRixILEssTixvLHEsdCx3
3359 LHkseyx+LI8skiyVLJgsmyykLKYsvCzJLMsszizRLPIs9Cz3LPos/Cz+LQAtBS0HLQ0tGi0cLR8tIi1D
3360 LUUtSC1LLU0tTy1RLW4tcC2CLY8tkS2ULZctuC26Lb0twC3CLcQtxy3ULdct2i3dLekt6y4DLhAuEi4V
3361 LhguOS47Lj4uQS5DLkUuRy5TLlUubi57Ln0ugC6DLqQupi6pLqwuri6wLrIuty65Lr8uzC7OLtEu1C75
3362 Lvsu/i8BLwMvBS8ILxUvGC8bLx4vKS8rL0UvUi9UL1cvWi97L30vgC+CL4Qvhi+IL5YvpC+1L7cvuS+8
3363 L78v3C/eL+Ev4y/lL+cv6TABMCEwLjAwMDMwNjBbMGUwZzBpMGwwbzBxMHMwdTCDMIUwlDClMKgwqzCt
3364 MK8wvDC+MMEwxDDlMOcw6jDtMO8w8TDzMPkw+zECMRMxFjEYMRoxHTE1MUIxRDFHMUoxazFtMXAxczF1
3365 MXcxejGOMZAxsDG9Mb8xwjHFMeYx6DHrMe0x7zHxMfQyBTIIMgsyDjIRMhwyNDJBMkMyRjJJMmoybDJv
3366 MnEyczJ1MncyfjKGMpMylTKYMpsyuDK6Mr0yvzLBMsMyxTLXMvAzATMEMwYzCTMMMxUzIjMkMyczKjNL
3367 M00zUDNSM1QzVjNZM24zgDONM48zkjOVM7YzuDO7M74zwDPCM8Qz2zPhM+4z8DPzM/Y0FzQZNBw0HjQg
3368 NCI0JTQqNDc0RDRGNEk0TDRxNHM0djR5NHs0fTR/NJI0rTS6NLw0vzTCNOM05TToNOs07TTvNPE1AjUE
3369 NRY1IzUlNSg1KzVMNU41UTVUNVY1WDVaNV41YDVlNXI1dDV3NXo1mzWdNaA1ozWlNac1qTWvNbE1vzXc
3370 NeY18DYPNhI2FDYXNho2HTYgNk02ajaBNo42mTaoNrc23Db3NxA3JDclNyg3KTcsNy03MDczNzQ3NTc2
3371 Nzk3QjdEN0s3TjdRN1Q3WTddN2M3bDdvN3I3dTeGN4w3lzejN6Y3qTesN603tje/N8Q31zfgN+U37jf5
3372 OBI4Jjg7OEg4dDiGOKE4qjixOMk45jjpOOw47zjyOPU4+DkUOSg5LzlMOU85UjlVOVg5WjldOXw5lDmx
3373 ObQ5tzm6Ob05vznCOd859ToSOhU6GDobOh46IDojOj86RzpaOmM6Zjs3Ozo7PDs/O0I7RTtHO0o7TTtP
3374 O1I7VTtYO1s7XjthO2M7ZTtnO2k7azttO3A7cjt0O3Y7eDt6O3w7fzuCO4Q7hjuIO4s7jTuQO5I7lTuY
3375 O5o7nTugO6I7pDunO6o7rTuwO7I7tTu4O7s7vjvAO8I7xDvHO8k7zDvOO9E71DvWO9g72zveO+E75Dvm
3376 O+k76zvuO/E78zv1O/g7+zv9PAA8AjwFPAc8CTwMPA88EjwVPBc8GjwdPCA8IzwmPCk8KzwuPDA8Mzw2
3377 PDk8PDw/PEI8azx5PIY8iDyKPIs8jTyOPJA8kjyUPL08xzzJPMw8zzzRPNM81TzYPNs87DzvPPI89Tz4
3378 PP89Dj0XPRk9Hj0hPSQ9RT1HPUo9TD1OPVA9Uz1ePWc9bD14PYE9gz2GPYk9oj3LPc090D3TPdU91z3Z
3379 Pds93j4HPgk+Cz4OPhA+Ej4UPhY+GT4wPjk+Oz5EPkc+ST5LPk0+dj54Pno+fT5/PoE+gz6GPok+jj6X
3380 Ppk+tD63Prk+vD6/PsI+xT7IPso+zT7QPtM+1j7ZPwI/BD8GPwc/CT8KPww/Dj8QPzk/Oz89Pz4/QD9B
3381 P0M/RT9HP3A/cj91P3g/ej98P34/gD+DP4g/kT+TP54/oT+kP6c/qj+tP9I/1D/XP9o/3D/eP+E/60AQ
3382 QBJAFUAXQBlAG0AeQCxAUUBTQFZAWUBbQF1AYEBiQHtAfUCmQKhAqkCtQK9AsUCzQLVAuEDGQM9A0UDY
3383 QNtA3kDgQQlBC0ENQRBBEkEUQRZBGEEbQSJBK0EtQTJBNEE3QUFBSkFMQVtBXkFhQWRBZ0FqQW1BcEGZ
3384 QZtBnUGgQaJBpEGmQalBrEG+QcdByUHgQeNB5kHpQexB70HyQfVB+EH6Qf1CAEIpQitCLUIuQjBCMUIz
3385 QjVCN0JYQlpCXUJgQmJCZEJmQn9CgUKqQqxCrkKvQrFCskK0QrZCuELhQuNC5kLpQutC7ULvQvFC9EL9
3386 Qw5DEUMUQxdDGkMjQyVDJkM4Q2FDY0NlQ2ZDaENpQ2tDbUNvQ3xDpUOnQ6lDrEOuQ7BDskO1Q7hDvUPG
3387 Q8hD30PiQ+VD6EPrQ+5D8EPzQ/ZD+UP8Q/5EH0QhRCREJ0QpRCtELUQxRDNEVERWRFlEXEReRGBEYkRt
3388 RG9EmESaRJxEnUSfRKBEokSkRKZEz0TRRNNE1ETWRNdE2UTbRN1FBkUIRQpFDUUPRRFFE0UWRRlFHkUn
3389 RSlFLkUwRTJFW0VdRWBFY0VlRWdFaUVsRW9FdkV/RYFFikWNRZBFk0WWRb9FwUXDRcRFxkXHRclFy0XO
3390 Rd1GBkYIRgpGDUYPRhFGE0YWRhlGHkYnRilGLEYuRjpGQ0ZGRxdHGUcbRx5HIEcjRyVHKEcqRyxHLkcx
3391 RzNHNUc3RzlHO0c9Rz9HQkdFR0dHSUdLR01HT0dRR1NHVkdYR1pHXUdfR2FHY0dlR2dHakdsR29HcUd0
3392 R3ZHeEd6R3xHfkeBR4RHhkeJR4tHjkeQR5JHlUeYR5tHnkegR6JHpEemR6hHqketR7BHske1R7dHuUe7
3393 R71Hv0fBR8NHxUfHR8lHy0fNR9BH0kfUR9dH2kfdR99H4UfjR+VH50fqR+xH70fxR/NH9Uf3R/pH/UgA
3394 SAJIBUgOSBFI5EjmSOlI7EjvSPJI9Ej3SPpI/Ej/SQJJBUkISQtJDkkQSRJJFEkWSRhJGkkdSR9JIUkj
3395 SSVJJ0kpSStJLUkwSTNJNUk4STpJPUk/SUJJRUlHSUpJTUlPSVFJVElWSVlJXElfSWJJZElnSWpJbUlv
3396 SXFJc0l1SXhJe0l9SYBJg0mFSYdJikmNSZBJk0mVSZhJmkmdSZ9JokmkSadJqkmsSa9JsUm0SbZJuEm7
3397 Sb5JwUnEScZJyUnMSc9J0knVSdhJ2kndSd9J4knlSehJ60nuSfFJ+kn9StBK00rWStlK3ErfSuJK5Uro
3398 SutK7krxSvRK90r6Sv1LAEsDSwZLCUsMSw9LEksVSxhLG0seSyFLJEsnSypLLUswSzNLNks5SzxLP0tC
3399 S0VLSEtLS05LUUtUS1dLWktdS2BLY0tmS2lLbEtvS3JLdUt4S3tLfkuBS4RLhkuJS4xLj0uSS5VLmEub
3400 S55LoUukS6dLqkutS7BLs0u2S7lLvEu/S8JLxUvIS8tLzkvRS9RL10vaS91L4EvjS+ZL6UvsS+9L8kv1
3401 S/hL+0v+TAFMBEwHTBJMHkxDTFhMbUyLTKBMukzaTP1NEE0jTS1NNk1STV9NYU1vTXFNiE2hTb1N104B
3402 Tg9OOU5LTmROgE6MTp9Oq07KTuRO+08ATw5PIk9DT09PYU97T55PqE/ET9FP00/oT+xP+FAVUC5QOlBV
3403 UFdQdVCBUI1QpVDKUM5Q0FDrUQFRJlFEUVdRWVFvUYJRwVHlUfJSKVJGUmlSbVKBUo1SoFKzUspS3lLs
3404 UwxTDlMgUzpTRlNJU15TdVOUU65TulPGU95T9VQOVCFUPVQ/VE1UVlRZVFpUY1RmVGdUcFRzVaRVp1Wp
3405 VaxVr1WyVbVVuFW7Vb1VwFXDVcVVyFXLVc1V0FXTVdZV2FXbVd5V4VXjVeZV6VXsVe5V8FXyVfRV9lX4
3406 VftV/VYAVgJWBFYGVghWClYNVhBWElYUVhZWGVYcVh5WIVYkViZWKVYsVi9WMVYzVjZWOVY8Vj5WQVZE
3407 VkdWSlZMVk5WUVZTVlZWWVZcVl5WYVZkVmZWaVZsVm9WcVZ0VnZWeFZ7Vn5WgFaCVoVWh1aKVo1Wj1aR
3408 VpRWl1aZVpxWnlahVqRWp1apVqxWrlawVrNWtla4VrpWvVbAVsNWxlbIVstWzVbQVtJW1VbXVtlW21be
3409 VuFW5FbnVulW7FbvVvJW9Fb3VvpW/VcAVwNXBlcIVwtXDlcQVxNXFlcZVxxXH1ciVyVXJ1cqVy1XMFc5
3410 VzxYbVhwWHNYdlh5WHxYf1iCWIVYiFiLWI5YkViUWJdYmlidWKBYo1imWKlYrFivWLJYtVi4WLtYvljB
3411 WMRYx1jKWM1Y0FjTWNZY2VjcWN9Y4ljlWOhY61juWPFY9Fj3WPpY/VkAWQNZBlkJWQxZD1kSWRVZGFkb
3412 WR5ZIVkkWSdZKlktWTBZM1k2WTlZPFk/WUJZRVlIWUtZTllRWVRZV1laWV1ZYFljWWZZaVlsWW9Zcll1
3413 WXhZe1l+WYFZhFmHWYpZjVmQWZNZllmZWZxZn1miWaVZqFmrWa5ZsVm0WbdZulm9WcBZw1nGWclZzFnP
3414 WdJZ1VnYWdtZ3lnhWeRZ51nqWe1Z8FnzWfZZ+Vn8Wf9aAloFWghaC1oOWhFaFFoXWhpaHVogWiNaJlop
3415 WixaL1oyWjRaN1o5WjtaPVpAWkNaRVpIWkpaTFpOWlBaU1pWWlhaWlpcWl9aYlpkWmZaaVprWm1acFpy
3416 WnVaeFp6Wn1af1qBWoRah1qKWoxaj1qSWpRallqYWppanVqgWqJapFqmWqhaqlqsWq9asVqzWrxav1rC
3417 WsVax1rKWs1az1rRWtRa1lrZWtxa31rhWuNa5VrnWula61ruWvBa8lr1Wvda+Vr7Wv1a/1sBWwRbBlsI
3418 WwtbDVsPWxJbFVsYWxtbHVsfWyFbI1slWyhbK1stWzBbMls0WzZbOFs7Wz1bQFtCW0VbSFtKW0xbTltR
3419 W1NbVltZW1xbXlthW2NbZVtoW2pbbFtuW3FbdFt2W3hbe1t+W4Bbg1uGW4hbi1uOW5Bbk1uVW5hbmluc
3420 W55boVujW6VbrluwW7Fbulu9W75bx1vKW8tb1FvZAAAAAAAAAgIAAAAAAAALwwAAAAAAAAAAAAAAAAAA
3421 W+g</bytes>
3422 </object>
3423 </data>
3424 </archive>
@@ -1,293 +0,0 b''
1 // !$*UTF8*$!
2 {
3 archiveVersion = 1;
4 classes = {
5 };
6 objectVersion = 44;
7 objects = {
8
9 /* Begin PBXBuildFile section */
10 77631A270C06C501005415CB /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77631A260C06C501005415CB /* Python.framework */; };
11 77631A3F0C0748CF005415CB /* main.py in Resources */ = {isa = PBXBuildFile; fileRef = 77631A3E0C0748CF005415CB /* main.py */; };
12 7790198F0C07548A00326F66 /* IPython1SandboxAppDelegate.py in Resources */ = {isa = PBXBuildFile; fileRef = 7790198E0C07548A00326F66 /* IPython1SandboxAppDelegate.py */; };
13 77C8C1F90C07829500965286 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 77C8C1F70C07829500965286 /* MainMenu.xib */; };
14 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
15 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
16 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
17 /* End PBXBuildFile section */
18
19 /* Begin PBXFileReference section */
20 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
21 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
22 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
23 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
24 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
25 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
26 32CA4F630368D1EE00C91783 /* IPython1Sandbox_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IPython1Sandbox_Prefix.pch; sourceTree = "<group>"; };
27 4CA32F870D8879B100311764 /* IPythonCocoaController Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "IPythonCocoaController Tests-Info.plist"; sourceTree = "<group>"; };
28 77631A260C06C501005415CB /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Python.framework; path = /System/Library/Frameworks/Python.framework; sourceTree = "<absolute>"; };
29 77631A3E0C0748CF005415CB /* main.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = main.py; sourceTree = "<group>"; };
30 7790198E0C07548A00326F66 /* IPython1SandboxAppDelegate.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = IPython1SandboxAppDelegate.py; sourceTree = "<group>"; };
31 77C8C1F80C07829500965286 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = "<group>"; };
32 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
33 8D1107320486CEB800E47090 /* IPython1Sandbox.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IPython1Sandbox.app; sourceTree = BUILT_PRODUCTS_DIR; };
34 /* End PBXFileReference section */
35
36 /* Begin PBXFrameworksBuildPhase section */
37 8D11072E0486CEB800E47090 /* Frameworks */ = {
38 isa = PBXFrameworksBuildPhase;
39 buildActionMask = 2147483647;
40 files = (
41 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
42 77631A270C06C501005415CB /* Python.framework in Frameworks */,
43 );
44 runOnlyForDeploymentPostprocessing = 0;
45 };
46 /* End PBXFrameworksBuildPhase section */
47
48 /* Begin PBXGroup section */
49 080E96DDFE201D6D7F000001 /* Classes */ = {
50 isa = PBXGroup;
51 children = (
52 7790198E0C07548A00326F66 /* IPython1SandboxAppDelegate.py */,
53 );
54 name = Classes;
55 sourceTree = "<group>";
56 };
57 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
58 isa = PBXGroup;
59 children = (
60 77631A260C06C501005415CB /* Python.framework */,
61 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
62 );
63 name = "Linked Frameworks";
64 sourceTree = "<group>";
65 };
66 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = {
67 isa = PBXGroup;
68 children = (
69 29B97324FDCFA39411CA2CEA /* AppKit.framework */,
70 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */,
71 29B97325FDCFA39411CA2CEA /* Foundation.framework */,
72 );
73 name = "Other Frameworks";
74 sourceTree = "<group>";
75 };
76 19C28FACFE9D520D11CA2CBB /* Products */ = {
77 isa = PBXGroup;
78 children = (
79 8D1107320486CEB800E47090 /* IPython1Sandbox.app */,
80 );
81 name = Products;
82 sourceTree = "<group>";
83 };
84 29B97314FDCFA39411CA2CEA /* IPython1Sandbox */ = {
85 isa = PBXGroup;
86 children = (
87 080E96DDFE201D6D7F000001 /* Classes */,
88 29B97315FDCFA39411CA2CEA /* Other Sources */,
89 29B97317FDCFA39411CA2CEA /* Resources */,
90 29B97323FDCFA39411CA2CEA /* Frameworks */,
91 19C28FACFE9D520D11CA2CBB /* Products */,
92 4CA32F870D8879B100311764 /* IPythonCocoaController Tests-Info.plist */,
93 );
94 name = IPython1Sandbox;
95 sourceTree = "<group>";
96 };
97 29B97315FDCFA39411CA2CEA /* Other Sources */ = {
98 isa = PBXGroup;
99 children = (
100 32CA4F630368D1EE00C91783 /* IPython1Sandbox_Prefix.pch */,
101 29B97316FDCFA39411CA2CEA /* main.m */,
102 77631A3E0C0748CF005415CB /* main.py */,
103 );
104 name = "Other Sources";
105 sourceTree = "<group>";
106 };
107 29B97317FDCFA39411CA2CEA /* Resources */ = {
108 isa = PBXGroup;
109 children = (
110 77C8C1F70C07829500965286 /* MainMenu.xib */,
111 8D1107310486CEB800E47090 /* Info.plist */,
112 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
113 );
114 name = Resources;
115 sourceTree = "<group>";
116 };
117 29B97323FDCFA39411CA2CEA /* Frameworks */ = {
118 isa = PBXGroup;
119 children = (
120 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
121 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */,
122 );
123 name = Frameworks;
124 sourceTree = "<group>";
125 };
126 /* End PBXGroup section */
127
128 /* Begin PBXNativeTarget section */
129 8D1107260486CEB800E47090 /* IPython1Sandbox */ = {
130 isa = PBXNativeTarget;
131 buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "IPython1Sandbox" */;
132 buildPhases = (
133 8D1107290486CEB800E47090 /* Resources */,
134 8D11072C0486CEB800E47090 /* Sources */,
135 8D11072E0486CEB800E47090 /* Frameworks */,
136 );
137 buildRules = (
138 );
139 dependencies = (
140 );
141 name = IPython1Sandbox;
142 productInstallPath = "$(HOME)/Applications";
143 productName = IPython1Sandbox;
144 productReference = 8D1107320486CEB800E47090 /* IPython1Sandbox.app */;
145 productType = "com.apple.product-type.application";
146 };
147 /* End PBXNativeTarget section */
148
149 /* Begin PBXProject section */
150 29B97313FDCFA39411CA2CEA /* Project object */ = {
151 isa = PBXProject;
152 buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "IPython1Sandbox" */;
153 compatibilityVersion = "Xcode 3.0";
154 hasScannedForEncodings = 1;
155 mainGroup = 29B97314FDCFA39411CA2CEA /* IPython1Sandbox */;
156 projectDirPath = "";
157 projectRoot = "";
158 targets = (
159 8D1107260486CEB800E47090 /* IPython1Sandbox */,
160 );
161 };
162 /* End PBXProject section */
163
164 /* Begin PBXResourcesBuildPhase section */
165 8D1107290486CEB800E47090 /* Resources */ = {
166 isa = PBXResourcesBuildPhase;
167 buildActionMask = 2147483647;
168 files = (
169 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */,
170 77631A3F0C0748CF005415CB /* main.py in Resources */,
171 7790198F0C07548A00326F66 /* IPython1SandboxAppDelegate.py in Resources */,
172 77C8C1F90C07829500965286 /* MainMenu.xib in Resources */,
173 );
174 runOnlyForDeploymentPostprocessing = 0;
175 };
176 /* End PBXResourcesBuildPhase section */
177
178 /* Begin PBXSourcesBuildPhase section */
179 8D11072C0486CEB800E47090 /* Sources */ = {
180 isa = PBXSourcesBuildPhase;
181 buildActionMask = 2147483647;
182 files = (
183 8D11072D0486CEB800E47090 /* main.m in Sources */,
184 );
185 runOnlyForDeploymentPostprocessing = 0;
186 };
187 /* End PBXSourcesBuildPhase section */
188
189 /* Begin PBXVariantGroup section */
190 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = {
191 isa = PBXVariantGroup;
192 children = (
193 089C165DFE840E0CC02AAC07 /* English */,
194 );
195 name = InfoPlist.strings;
196 sourceTree = "<group>";
197 };
198 77C8C1F70C07829500965286 /* MainMenu.xib */ = {
199 isa = PBXVariantGroup;
200 children = (
201 77C8C1F80C07829500965286 /* English */,
202 );
203 name = MainMenu.xib;
204 sourceTree = "<group>";
205 };
206 /* End PBXVariantGroup section */
207
208 /* Begin XCBuildConfiguration section */
209 C01FCF4B08A954540054247B /* Debug */ = {
210 isa = XCBuildConfiguration;
211 buildSettings = {
212 COPY_PHASE_STRIP = NO;
213 CURRENT_PROJECT_VERSION = 1;
214 GCC_DYNAMIC_NO_PIC = NO;
215 GCC_ENABLE_FIX_AND_CONTINUE = YES;
216 GCC_MODEL_TUNING = G5;
217 GCC_OPTIMIZATION_LEVEL = 0;
218 GCC_PRECOMPILE_PREFIX_HEADER = YES;
219 GCC_PREFIX_HEADER = IPython1Sandbox_Prefix.pch;
220 INFOPLIST_FILE = Info.plist;
221 INSTALL_PATH = "$(HOME)/Applications";
222 PRODUCT_NAME = IPython1Sandbox;
223 VERSIONING_SYSTEM = "apple-generic";
224 WRAPPER_EXTENSION = app;
225 ZERO_LINK = YES;
226 };
227 name = Debug;
228 };
229 C01FCF4C08A954540054247B /* Release */ = {
230 isa = XCBuildConfiguration;
231 buildSettings = {
232 CURRENT_PROJECT_VERSION = 1;
233 DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
234 GCC_MODEL_TUNING = G5;
235 GCC_PRECOMPILE_PREFIX_HEADER = YES;
236 GCC_PREFIX_HEADER = IPython1Sandbox_Prefix.pch;
237 INFOPLIST_FILE = Info.plist;
238 INSTALL_PATH = "$(HOME)/Applications";
239 PRODUCT_NAME = IPython1Sandbox;
240 VERSIONING_SYSTEM = "apple-generic";
241 WRAPPER_EXTENSION = app;
242 };
243 name = Release;
244 };
245 C01FCF4F08A954540054247B /* Debug */ = {
246 isa = XCBuildConfiguration;
247 buildSettings = {
248 GCC_WARN_ABOUT_RETURN_TYPE = YES;
249 GCC_WARN_UNUSED_VARIABLE = YES;
250 PREBINDING = NO;
251 SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
252 };
253 name = Debug;
254 };
255 C01FCF5008A954540054247B /* Release */ = {
256 isa = XCBuildConfiguration;
257 buildSettings = {
258 ARCHS = (
259 ppc,
260 i386,
261 );
262 GCC_WARN_ABOUT_RETURN_TYPE = YES;
263 GCC_WARN_UNUSED_VARIABLE = YES;
264 PREBINDING = NO;
265 SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
266 };
267 name = Release;
268 };
269 /* End XCBuildConfiguration section */
270
271 /* Begin XCConfigurationList section */
272 C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "IPython1Sandbox" */ = {
273 isa = XCConfigurationList;
274 buildConfigurations = (
275 C01FCF4B08A954540054247B /* Debug */,
276 C01FCF4C08A954540054247B /* Release */,
277 );
278 defaultConfigurationIsVisible = 0;
279 defaultConfigurationName = Release;
280 };
281 C01FCF4E08A954540054247B /* Build configuration list for PBXProject "IPython1Sandbox" */ = {
282 isa = XCConfigurationList;
283 buildConfigurations = (
284 C01FCF4F08A954540054247B /* Debug */,
285 C01FCF5008A954540054247B /* Release */,
286 );
287 defaultConfigurationIsVisible = 0;
288 defaultConfigurationName = Release;
289 };
290 /* End XCConfigurationList section */
291 };
292 rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
293 }
@@ -1,39 +0,0 b''
1 #
2 # IPython1SandboxAppDelegate.py
3 # IPython1Sandbox
4 #
5 # Created by Barry Wark on 3/4/08.
6 # Copyright __MyCompanyName__ 2008. All rights reserved.
7 #
8
9 from Foundation import NSObject, NSPredicate
10 import objc
11 import threading
12
13 from PyObjCTools import AppHelper
14
15 from twisted.internet import reactor
16
17 class IPython1SandboxAppDelegate(NSObject):
18 ipythonController = objc.IBOutlet()
19
20 def applicationShouldTerminate_(self, sender):
21 if reactor.running:
22 reactor.addSystemEventTrigger(
23 'after', 'shutdown', AppHelper.stopEventLoop)
24 reactor.stop()
25 return False
26 return True
27
28
29 def applicationDidFinishLaunching_(self, sender):
30 reactor.interleave(AppHelper.callAfter)
31 assert(reactor.running)
32
33
34 def workspaceFilterPredicate(self):
35 return NSPredicate.predicateWithFormat_("NOT (self.value BEGINSWITH '<')")
36
37
38
39
@@ -1,7 +0,0 b''
1 //
2 // Prefix header for all source files of the 'IPython1Sandbox' target in the 'IPython1Sandbox' project
3 //
4
5 #ifdef __OBJC__
6 #import <Cocoa/Cocoa.h>
7 #endif
@@ -1,20 +0,0 b''
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 <plist version="1.0">
4 <dict>
5 <key>CFBundleDevelopmentRegion</key>
6 <string>English</string>
7 <key>CFBundleExecutable</key>
8 <string>${EXECUTABLE_NAME}</string>
9 <key>CFBundleIdentifier</key>
10 <string>com.yourcompany.IPythonCocoaController Tests</string>
11 <key>CFBundleInfoDictionaryVersion</key>
12 <string>6.0</string>
13 <key>CFBundlePackageType</key>
14 <string>BNDL</string>
15 <key>CFBundleSignature</key>
16 <string>????</string>
17 <key>CFBundleVersion</key>
18 <string>1.0</string>
19 </dict>
20 </plist>
@@ -1,30 +0,0 b''
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 <plist version="1.0">
4 <dict>
5 <key>CFBundleDevelopmentRegion</key>
6 <string>English</string>
7 <key>CFBundleExecutable</key>
8 <string>${EXECUTABLE_NAME}</string>
9 <key>CFBundleIconFile</key>
10 <string></string>
11 <key>CFBundleIdentifier</key>
12 <string>com.yourcompany.IPython1Sandbox</string>
13 <key>CFBundleInfoDictionaryVersion</key>
14 <string>6.0</string>
15 <key>CFBundleName</key>
16 <string>${PRODUCT_NAME}</string>
17 <key>CFBundlePackageType</key>
18 <string>APPL</string>
19 <key>CFBundleShortVersionString</key>
20 <string>0.1</string>
21 <key>CFBundleSignature</key>
22 <string>????</string>
23 <key>CFBundleVersion</key>
24 <string>1.0</string>
25 <key>NSMainNibFile</key>
26 <string>MainMenu</string>
27 <key>NSPrincipalClass</key>
28 <string>NSApplication</string>
29 </dict>
30 </plist>
@@ -1,49 +0,0 b''
1 //
2 // main.m
3 // IPython1Sandbox
4 //
5 // Created by Barry Wark on 3/4/08.
6 // Copyright __MyCompanyName__ 2008. All rights reserved.
7 //
8
9 #import <Python/Python.h>
10 #import <Cocoa/Cocoa.h>
11
12 int main(int argc, char *argv[])
13 {
14 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
15
16 NSBundle *mainBundle = [NSBundle mainBundle];
17 NSString *resourcePath = [mainBundle resourcePath];
18 NSArray *pythonPathArray = [NSArray arrayWithObjects: resourcePath, [resourcePath stringByAppendingPathComponent:@"PyObjC"], nil];
19
20 setenv("PYTHONPATH", [[pythonPathArray componentsJoinedByString:@":"] UTF8String], 1);
21
22 NSArray *possibleMainExtensions = [NSArray arrayWithObjects: @"py", @"pyc", @"pyo", nil];
23 NSString *mainFilePath = nil;
24
25 for (NSString *possibleMainExtension in possibleMainExtensions) {
26 mainFilePath = [mainBundle pathForResource: @"main" ofType: possibleMainExtension];
27 if ( mainFilePath != nil ) break;
28 }
29
30 if ( !mainFilePath ) {
31 [NSException raise: NSInternalInconsistencyException format: @"%s:%d main() Failed to find the Main.{py,pyc,pyo} file in the application wrapper's Resources directory.", __FILE__, __LINE__];
32 }
33
34 Py_SetProgramName("/usr/bin/python");
35 Py_Initialize();
36 PySys_SetArgv(argc, (char **)argv);
37
38 const char *mainFilePathPtr = [mainFilePath UTF8String];
39 FILE *mainFile = fopen(mainFilePathPtr, "r");
40 int result = PyRun_SimpleFile(mainFile, (char *)[[mainFilePath lastPathComponent] UTF8String]);
41
42 if ( result != 0 )
43 [NSException raise: NSInternalInconsistencyException
44 format: @"%s:%d main() PyRun_SimpleFile failed with file '%@'. See console for errors.", __FILE__, __LINE__, mainFilePath];
45
46 [pool drain];
47
48 return result;
49 }
@@ -1,24 +0,0 b''
1 #
2 # main.py
3 # IPython1Sandbox
4 #
5 # Created by Barry Wark on 3/4/08.
6 # Copyright __MyCompanyName__ 2008. All rights reserved.
7 #
8
9 #import modules required by application
10 import objc
11 import Foundation
12 import AppKit
13
14 from PyObjCTools import AppHelper
15
16 from twisted.internet import _threadedselect
17 reactor = _threadedselect.install()
18
19 # import modules containing classes required to start application and load MainMenu.nib
20 import IPython1SandboxAppDelegate
21 import IPython.frontend.cocoa.cocoa_frontend
22
23 # pass control to AppKit
24 AppHelper.runEventLoop()
@@ -1,256 +0,0 b''
1 // !$*UTF8*$!
2 {
3 archiveVersion = 1;
4 classes = {
5 };
6 objectVersion = 42;
7 objects = {
8
9 /* Begin PBXContainerItemProxy section */
10 4C5B7ADB0E1A0BCD006CB905 /* PBXContainerItemProxy */ = {
11 isa = PBXContainerItemProxy;
12 containerPortal = 4C96F4FE0E199AB500B03430 /* Project object */;
13 proxyType = 1;
14 remoteGlobalIDString = 4C96F50C0E199AF100B03430;
15 remoteInfo = "Cocoa Frontend Plugin";
16 };
17 /* End PBXContainerItemProxy section */
18
19 /* Begin PBXFileReference section */
20 4C5B7A8D0E1A0B4C006CB905 /* Plugin-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Plugin-Info.plist"; sourceTree = "<group>"; };
21 4C5B7AD30E1A0BC8006CB905 /* Placeholder (Do Not Use).bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Placeholder (Do Not Use).bundle"; sourceTree = BUILT_PRODUCTS_DIR; };
22 4C5B7AD40E1A0BC8006CB905 /* Placeholder (Do Not Use)-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Placeholder (Do Not Use)-Info.plist"; sourceTree = "<group>"; };
23 /* End PBXFileReference section */
24
25 /* Begin PBXFrameworksBuildPhase section */
26 4C5B7AD10E1A0BC8006CB905 /* Frameworks */ = {
27 isa = PBXFrameworksBuildPhase;
28 buildActionMask = 2147483647;
29 files = (
30 );
31 runOnlyForDeploymentPostprocessing = 0;
32 };
33 /* End PBXFrameworksBuildPhase section */
34
35 /* Begin PBXGroup section */
36 4C5B7A8C0E1A0B4C006CB905 /* Products */ = {
37 isa = PBXGroup;
38 children = (
39 4C5B7AD30E1A0BC8006CB905 /* Placeholder (Do Not Use).bundle */,
40 );
41 name = Products;
42 sourceTree = "<group>";
43 };
44 4C96F4FC0E199AB500B03430 = {
45 isa = PBXGroup;
46 children = (
47 4C5B7A8C0E1A0B4C006CB905 /* Products */,
48 4C5B7A8D0E1A0B4C006CB905 /* Plugin-Info.plist */,
49 4C5B7AD40E1A0BC8006CB905 /* Placeholder (Do Not Use)-Info.plist */,
50 );
51 sourceTree = "<group>";
52 };
53 /* End PBXGroup section */
54
55 /* Begin PBXLegacyTarget section */
56 4C96F50C0E199AF100B03430 /* Cocoa Frontend Plugin */ = {
57 isa = PBXLegacyTarget;
58 buildArgumentsString = "$(ACTION)";
59 buildConfigurationList = 4C96F5110E199B3300B03430 /* Build configuration list for PBXLegacyTarget "Cocoa Frontend Plugin" */;
60 buildPhases = (
61 );
62 buildToolPath = /usr/bin/make;
63 buildWorkingDirectory = "";
64 dependencies = (
65 );
66 name = "Cocoa Frontend Plugin";
67 passBuildSettingsInEnvironment = 1;
68 productName = "Cocoa Frontend Plugin";
69 };
70 /* End PBXLegacyTarget section */
71
72 /* Begin PBXNativeTarget section */
73 4C5B7AD20E1A0BC8006CB905 /* Placeholder (Do Not Use) */ = {
74 isa = PBXNativeTarget;
75 buildConfigurationList = 4C5B7ADA0E1A0BC9006CB905 /* Build configuration list for PBXNativeTarget "Placeholder (Do Not Use)" */;
76 buildPhases = (
77 4C5B7ACF0E1A0BC8006CB905 /* Resources */,
78 4C5B7AD00E1A0BC8006CB905 /* Sources */,
79 4C5B7AD10E1A0BC8006CB905 /* Frameworks */,
80 );
81 buildRules = (
82 );
83 dependencies = (
84 4C5B7ADC0E1A0BCD006CB905 /* PBXTargetDependency */,
85 );
86 name = "Placeholder (Do Not Use)";
87 productName = "Placeholder (Do Not Use)";
88 productReference = 4C5B7AD30E1A0BC8006CB905 /* Placeholder (Do Not Use).bundle */;
89 productType = "com.apple.product-type.bundle";
90 };
91 /* End PBXNativeTarget section */
92
93 /* Begin PBXProject section */
94 4C96F4FE0E199AB500B03430 /* Project object */ = {
95 isa = PBXProject;
96 buildConfigurationList = 4C96F5010E199AB500B03430 /* Build configuration list for PBXProject "CocoaFrontendPlugin" */;
97 compatibilityVersion = "Xcode 2.4";
98 hasScannedForEncodings = 0;
99 mainGroup = 4C96F4FC0E199AB500B03430;
100 productRefGroup = 4C5B7A8C0E1A0B4C006CB905 /* Products */;
101 projectDirPath = "";
102 projectRoot = "";
103 targets = (
104 4C96F50C0E199AF100B03430 /* Cocoa Frontend Plugin */,
105 4C5B7AD20E1A0BC8006CB905 /* Placeholder (Do Not Use) */,
106 );
107 };
108 /* End PBXProject section */
109
110 /* Begin PBXResourcesBuildPhase section */
111 4C5B7ACF0E1A0BC8006CB905 /* Resources */ = {
112 isa = PBXResourcesBuildPhase;
113 buildActionMask = 2147483647;
114 files = (
115 );
116 runOnlyForDeploymentPostprocessing = 0;
117 };
118 /* End PBXResourcesBuildPhase section */
119
120 /* Begin PBXSourcesBuildPhase section */
121 4C5B7AD00E1A0BC8006CB905 /* Sources */ = {
122 isa = PBXSourcesBuildPhase;
123 buildActionMask = 2147483647;
124 files = (
125 );
126 runOnlyForDeploymentPostprocessing = 0;
127 };
128 /* End PBXSourcesBuildPhase section */
129
130 /* Begin PBXTargetDependency section */
131 4C5B7ADC0E1A0BCD006CB905 /* PBXTargetDependency */ = {
132 isa = PBXTargetDependency;
133 target = 4C96F50C0E199AF100B03430 /* Cocoa Frontend Plugin */;
134 targetProxy = 4C5B7ADB0E1A0BCD006CB905 /* PBXContainerItemProxy */;
135 };
136 /* End PBXTargetDependency section */
137
138 /* Begin XCBuildConfiguration section */
139 4C5B7AD50E1A0BC9006CB905 /* Debug */ = {
140 isa = XCBuildConfiguration;
141 buildSettings = {
142 COPY_PHASE_STRIP = NO;
143 GCC_DYNAMIC_NO_PIC = NO;
144 GCC_ENABLE_FIX_AND_CONTINUE = YES;
145 GCC_MODEL_TUNING = G5;
146 GCC_OPTIMIZATION_LEVEL = 0;
147 GCC_PRECOMPILE_PREFIX_HEADER = YES;
148 GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
149 INFOPLIST_FILE = "Placeholder (Do Not Use)-Info.plist";
150 INSTALL_PATH = "$(HOME)/Library/Bundles";
151 OTHER_LDFLAGS = (
152 "-framework",
153 Foundation,
154 "-framework",
155 AppKit,
156 );
157 PREBINDING = NO;
158 PRODUCT_NAME = "Placeholder (Do Not Use)";
159 WRAPPER_EXTENSION = bundle;
160 ZERO_LINK = YES;
161 };
162 name = Debug;
163 };
164 4C5B7AD60E1A0BC9006CB905 /* Release */ = {
165 isa = XCBuildConfiguration;
166 buildSettings = {
167 COPY_PHASE_STRIP = YES;
168 DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
169 GCC_ENABLE_FIX_AND_CONTINUE = NO;
170 GCC_MODEL_TUNING = G5;
171 GCC_PRECOMPILE_PREFIX_HEADER = YES;
172 GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
173 INFOPLIST_FILE = "Placeholder (Do Not Use)-Info.plist";
174 INSTALL_PATH = "$(HOME)/Library/Bundles";
175 OTHER_LDFLAGS = (
176 "-framework",
177 Foundation,
178 "-framework",
179 AppKit,
180 );
181 PREBINDING = NO;
182 PRODUCT_NAME = "Placeholder (Do Not Use)";
183 WRAPPER_EXTENSION = bundle;
184 ZERO_LINK = NO;
185 };
186 name = Release;
187 };
188 4C96F4FF0E199AB500B03430 /* Debug */ = {
189 isa = XCBuildConfiguration;
190 buildSettings = {
191 COPY_PHASE_STRIP = NO;
192 };
193 name = Debug;
194 };
195 4C96F5000E199AB500B03430 /* Release */ = {
196 isa = XCBuildConfiguration;
197 buildSettings = {
198 COPY_PHASE_STRIP = YES;
199 };
200 name = Release;
201 };
202 4C96F50D0E199AF100B03430 /* Debug */ = {
203 isa = XCBuildConfiguration;
204 buildSettings = {
205 COPY_PHASE_STRIP = NO;
206 GCC_DYNAMIC_NO_PIC = NO;
207 GCC_OPTIMIZATION_LEVEL = 0;
208 PRODUCT_NAME = "Cocoa Frontend Plugin";
209 };
210 name = Debug;
211 };
212 4C96F50E0E199AF100B03430 /* Release */ = {
213 isa = XCBuildConfiguration;
214 buildSettings = {
215 COPY_PHASE_STRIP = YES;
216 DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
217 GCC_ENABLE_FIX_AND_CONTINUE = NO;
218 PRODUCT_NAME = "Cocoa Frontend Plugin";
219 ZERO_LINK = NO;
220 };
221 name = Release;
222 };
223 /* End XCBuildConfiguration section */
224
225 /* Begin XCConfigurationList section */
226 4C5B7ADA0E1A0BC9006CB905 /* Build configuration list for PBXNativeTarget "Placeholder (Do Not Use)" */ = {
227 isa = XCConfigurationList;
228 buildConfigurations = (
229 4C5B7AD50E1A0BC9006CB905 /* Debug */,
230 4C5B7AD60E1A0BC9006CB905 /* Release */,
231 );
232 defaultConfigurationIsVisible = 0;
233 defaultConfigurationName = Release;
234 };
235 4C96F5010E199AB500B03430 /* Build configuration list for PBXProject "CocoaFrontendPlugin" */ = {
236 isa = XCConfigurationList;
237 buildConfigurations = (
238 4C96F4FF0E199AB500B03430 /* Debug */,
239 4C96F5000E199AB500B03430 /* Release */,
240 );
241 defaultConfigurationIsVisible = 0;
242 defaultConfigurationName = Release;
243 };
244 4C96F5110E199B3300B03430 /* Build configuration list for PBXLegacyTarget "Cocoa Frontend Plugin" */ = {
245 isa = XCConfigurationList;
246 buildConfigurations = (
247 4C96F50D0E199AF100B03430 /* Debug */,
248 4C96F50E0E199AF100B03430 /* Release */,
249 );
250 defaultConfigurationIsVisible = 0;
251 defaultConfigurationName = Release;
252 };
253 /* End XCConfigurationList section */
254 };
255 rootObject = 4C96F4FE0E199AB500B03430 /* Project object */;
256 }
@@ -1,25 +0,0 b''
1 # encoding: utf-8
2 """
3 Provides a namespace for loading the Cocoa frontend via a Cocoa plugin.
4
5 Author: Barry Wark
6 """
7 __docformat__ = "restructuredtext en"
8
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2008-2011 The IPython Development Team
11 #
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
15
16 from PyObjCTools import AppHelper
17 from twisted.internet import _threadedselect
18
19 #make sure _threadedselect is installed first
20 reactor = _threadedselect.install()
21
22 # load the Cocoa frontend controller
23 from IPython.frontend.cocoa.cocoa_frontend import IPythonCocoaController
24 reactor.interleave(AppHelper.callAfter)
25 assert(reactor.running)
@@ -1,6 +0,0 b''
1 include ./plugins.mk
2
3 all : dist/IPythonCocoaController.plugin
4
5 dist/IPythonCocoaController.plugin : ./IPythonCocoaFrontendLoader.py\
6 ./setup.py No newline at end of file
@@ -1,20 +0,0 b''
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 <plist version="1.0">
4 <dict>
5 <key>CFBundleDevelopmentRegion</key>
6 <string>English</string>
7 <key>CFBundleExecutable</key>
8 <string>${EXECUTABLE_NAME}</string>
9 <key>CFBundleIdentifier</key>
10 <string>com.yourcompany.Placeholder (Do Not Use)</string>
11 <key>CFBundleInfoDictionaryVersion</key>
12 <string>6.0</string>
13 <key>CFBundlePackageType</key>
14 <string>BNDL</string>
15 <key>CFBundleSignature</key>
16 <string>????</string>
17 <key>CFBundleVersion</key>
18 <string>1.0</string>
19 </dict>
20 </plist>
@@ -1,21 +0,0 b''
1 %.plugin::
2 rm -rf dist/$(notdir $@)
3 rm -rf build dist && \
4 python setup.py py2app -s
5
6 %.py:
7 @echo "test -f $@"
8 @test -f %@
9
10 %.nib:
11 @echo "test -f $@"
12 @test -f %@
13
14 .DEFAULT_GOAL := all
15
16 .PHONY : all clean
17
18 clean :
19 rm -rf build dist
20
21
@@ -1,35 +0,0 b''
1 # encoding: utf-8
2 """
3 setup.py
4
5 Setuptools installer script for generating a Cocoa plugin for the
6 IPython cocoa frontend
7
8 Author: Barry Wark
9 """
10 __docformat__ = "restructuredtext en"
11
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2011 The IPython Development Team
14 #
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
18
19 from setuptools import setup
20
21 infoPlist = dict(
22 CFBundleDevelopmentRegion='English',
23 CFBundleIdentifier='org.scipy.ipython.cocoa_frontend',
24 NSPrincipalClass='IPythonCocoaController',
25 )
26
27 setup(
28 plugin=['IPythonCocoaFrontendLoader.py'],
29 setup_requires=['py2app'],
30 options=dict(py2app=dict(
31 plist=infoPlist,
32 site_packages=True,
33 excludes=['IPython','twisted','PyObjCTools']
34 )),
35 ) No newline at end of file
@@ -1,100 +0,0 b''
1 # encoding: utf-8
2 """This file contains unittests for the
3 IPython.frontend.cocoa.cocoa_frontend module.
4 """
5 __docformat__ = "restructuredtext en"
6
7 #---------------------------------------------------------------------------
8 # Copyright (C) 2005-2011 The IPython Development Team
9 #
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
12 #---------------------------------------------------------------------------
13
14 #---------------------------------------------------------------------------
15 # Imports
16 #---------------------------------------------------------------------------
17
18 # Tell nose to skip this module
19 __test__ = {}
20
21 from twisted.trial import unittest
22 from twisted.internet.defer import succeed
23
24 from IPython.kernel.core.interpreter import Interpreter
25 import IPython.kernel.engineservice as es
26
27 try:
28 from IPython.frontend.cocoa.cocoa_frontend import IPythonCocoaController
29 from Foundation import NSMakeRect
30 from AppKit import NSTextView, NSScrollView
31 except ImportError:
32 # This tells twisted.trial to skip this module if PyObjC is not found
33 skip = True
34
35 #---------------------------------------------------------------------------
36 # Tests
37 #---------------------------------------------------------------------------
38 class TestIPythonCocoaControler(unittest.TestCase):
39 """Tests for IPythonCocoaController"""
40
41 def setUp(self):
42 self.controller = IPythonCocoaController.alloc().init()
43 self.engine = es.EngineService()
44 self.engine.startService()
45
46 def tearDown(self):
47 self.controller = None
48 self.engine.stopService()
49
50 def testControllerExecutesCode(self):
51 code ="""5+5"""
52 expected = Interpreter().execute(code)
53 del expected['number']
54 def removeNumberAndID(result):
55 del result['number']
56 del result['id']
57 return result
58 d = self.controller.execute(code)
59 d.addCallback(removeNumberAndID)
60 d.addCallback(lambda r: self.assertEquals(r, expected))
61
62 def testControllerMirrorsUserNSWithValuesAsStrings(self):
63 code = """userns1=1;userns2=2"""
64 def testControllerUserNS(result):
65 self.assertEquals(self.controller.userNS['userns1'], 1)
66 self.assertEquals(self.controller.userNS['userns2'], 2)
67 self.controller.execute(code).addCallback(testControllerUserNS)
68
69 def testControllerInstantiatesIEngine(self):
70 self.assert_(es.IEngineBase.providedBy(self.controller.engine))
71
72 def testControllerCompletesToken(self):
73 code = """longNameVariable=10"""
74 def testCompletes(result):
75 self.assert_("longNameVariable" in result)
76
77 def testCompleteToken(result):
78 self.controller.complete("longNa").addCallback(testCompletes)
79
80 self.controller.execute(code).addCallback(testCompletes)
81
82
83 def testCurrentIndent(self):
84 """test that current_indent_string returns current indent or None.
85 Uses _indent_for_block for direct unit testing.
86 """
87
88 self.controller.tabUsesSpaces = True
89 self.assert_(self.controller._indent_for_block("""a=3""") == None)
90 self.assert_(self.controller._indent_for_block("") == None)
91 block = """def test():\n a=3"""
92 self.assert_(self.controller._indent_for_block(block) == \
93 ' ' * self.controller.tabSpaces)
94
95 block = """if(True):\n%sif(False):\n%spass""" % \
96 (' '*self.controller.tabSpaces,
97 2*' '*self.controller.tabSpaces)
98 self.assert_(self.controller._indent_for_block(block) == \
99 2*(' '*self.controller.tabSpaces))
100
@@ -1,343 +0,0 b''
1 # encoding: utf-8
2 # -*- test-case-name: IPython.frontend.tests.test_frontendbase -*-
3 """
4 frontendbase provides an interface and base class for GUI frontends for
5 IPython.kernel/IPython.kernel.core.
6
7 Frontend implementations will likely want to subclass FrontEndBase.
8
9 Author: Barry Wark
10 """
11 __docformat__ = "restructuredtext en"
12
13 #-------------------------------------------------------------------------------
14 # Copyright (C) 2008-2011 The IPython Development Team
15 #
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
18 #-------------------------------------------------------------------------------
19
20 #-------------------------------------------------------------------------------
21 # Imports
22 #-------------------------------------------------------------------------------
23 import string
24 import codeop
25 import uuid
26
27
28 from IPython.frontend.zopeinterface import (
29 Interface,
30 Attribute,
31 )
32 from IPython.kernel.core.history import FrontEndHistory
33 from IPython.kernel.core.util import Bunch
34
35 ##############################################################################
36 # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
37 # not
38
39 rc = Bunch()
40 rc.prompt_in1 = r'In [$number]: '
41 rc.prompt_in2 = r'...'
42 rc.prompt_out = r'Out [$number]: '
43
44 ##############################################################################
45 # Interface definitions
46 ##############################################################################
47
48 class IFrontEndFactory(Interface):
49 """Factory interface for frontends."""
50
51 def __call__(engine=None, history=None):
52 """
53 Parameters:
54 interpreter : IPython.kernel.engineservice.IEngineCore
55 """
56
57 pass
58
59
60 class IFrontEnd(Interface):
61 """Interface for frontends. All methods return t.i.d.Deferred"""
62
63 Attribute("input_prompt_template", "string.Template instance\
64 substituteable with execute result.")
65 Attribute("output_prompt_template", "string.Template instance\
66 substituteable with execute result.")
67 Attribute("continuation_prompt_template", "string.Template instance\
68 substituteable with execute result.")
69
70 def update_cell_prompt(result, blockID=None):
71 """Subclass may override to update the input prompt for a block.
72
73 In asynchronous frontends, this method will be called as a
74 twisted.internet.defer.Deferred's callback/errback.
75 Implementations should thus return result when finished.
76
77 Result is a result dict in case of success, and a
78 twisted.python.util.failure.Failure in case of an error
79 """
80
81 pass
82
83 def render_result(result):
84 """Render the result of an execute call. Implementors may choose the
85 method of rendering.
86 For example, a notebook-style frontend might render a Chaco plot
87 inline.
88
89 Parameters:
90 result : dict (result of IEngineBase.execute )
91 blockID = result['blockID']
92
93 Result:
94 Output of frontend rendering
95 """
96
97 pass
98
99 def render_error(failure):
100 """Subclasses must override to render the failure.
101
102 In asynchronous frontend, since this method will be called as a
103 twisted.internet.defer.Deferred's callback. Implementations
104 should thus return result when finished.
105
106 blockID = failure.blockID
107 """
108
109 pass
110
111 def input_prompt(number=''):
112 """Returns the input prompt by subsituting into
113 self.input_prompt_template
114 """
115 pass
116
117 def output_prompt(number=''):
118 """Returns the output prompt by subsituting into
119 self.output_prompt_template
120 """
121
122 pass
123
124 def continuation_prompt():
125 """Returns the continuation prompt by subsituting into
126 self.continuation_prompt_template
127 """
128
129 pass
130
131 def is_complete(block):
132 """Returns True if block is complete, False otherwise."""
133
134 pass
135
136
137 def get_history_previous(current_block):
138 """Returns the block previous in the history. Saves currentBlock if
139 the history_cursor is currently at the end of the input history"""
140 pass
141
142 def get_history_next():
143 """Returns the next block in the history."""
144
145 pass
146
147 def complete(self, line):
148 """Returns the list of possible completions, and the completed
149 line.
150
151 The input argument is the full line to be completed. This method
152 returns both the line completed as much as possible, and the list
153 of further possible completions (full words).
154 """
155 pass
156
157
158 ##############################################################################
159 # Base class for all the frontends.
160 ##############################################################################
161
162 class FrontEndBase(object):
163 """
164 FrontEndBase manages the state tasks for a CLI frontend:
165 - Input and output history management
166 - Input/continuation and output prompt generation
167
168 Some issues (due to possibly unavailable engine):
169 - How do we get the current cell number for the engine?
170 - How do we handle completions?
171 """
172
173 history_cursor = 0
174
175 input_prompt_template = string.Template(rc.prompt_in1)
176 output_prompt_template = string.Template(rc.prompt_out)
177 continuation_prompt_template = string.Template(rc.prompt_in2)
178
179 def __init__(self, shell=None, history=None):
180 self.shell = shell
181 if history is None:
182 self.history = FrontEndHistory(input_cache=[''])
183 else:
184 self.history = history
185
186
187 def input_prompt(self, number=''):
188 """Returns the current input prompt
189
190 It would be great to use ipython1.core.prompts.Prompt1 here
191 """
192 return self.input_prompt_template.safe_substitute({'number':number})
193
194
195 def continuation_prompt(self):
196 """Returns the current continuation prompt"""
197
198 return self.continuation_prompt_template.safe_substitute()
199
200 def output_prompt(self, number=''):
201 """Returns the output prompt for result"""
202
203 return self.output_prompt_template.safe_substitute({'number':number})
204
205
206 def is_complete(self, block):
207 """Determine if block is complete.
208
209 Parameters
210 block : string
211
212 Result
213 True if block can be sent to the engine without compile errors.
214 False otherwise.
215 """
216
217 try:
218 is_complete = codeop.compile_command(block.rstrip() + '\n\n',
219 "<string>", "exec")
220 except:
221 return False
222
223 lines = block.split('\n')
224 return ((is_complete is not None)
225 and (len(lines)==1 or str(lines[-1])==''))
226
227
228 def execute(self, block, blockID=None):
229 """Execute the block and return the result.
230
231 Parameters:
232 block : {str, AST}
233 blockID : any
234 Caller may provide an ID to identify this block.
235 result['blockID'] := blockID
236
237 Result:
238 Deferred result of self.interpreter.execute
239 """
240
241 if(not self.is_complete(block)):
242 raise Exception("Block is not compilable")
243
244 if(blockID == None):
245 blockID = uuid.uuid4()
246
247 try:
248 result = self.shell.execute(block)
249 except Exception as e:
250 e = self._add_block_id_for_failure(e, blockID=blockID)
251 e = self.update_cell_prompt(e, blockID=blockID)
252 e = self.render_error(e)
253 else:
254 result = self._add_block_id_for_result(result, blockID=blockID)
255 result = self.update_cell_prompt(result, blockID=blockID)
256 result = self.render_result(result)
257
258 return result
259
260
261 def _add_block_id_for_result(self, result, blockID):
262 """Add the blockID to result or failure. Unfortunatley, we have to
263 treat failures differently than result dicts.
264 """
265
266 result['blockID'] = blockID
267
268 return result
269
270 def _add_block_id_for_failure(self, failure, blockID):
271 """_add_block_id_for_failure"""
272 failure.blockID = blockID
273 return failure
274
275
276 def _add_history(self, result, block=None):
277 """Add block to the history"""
278
279 assert(block != None)
280 self.history.add_items([block])
281 self.history_cursor += 1
282
283 return result
284
285
286 def get_history_previous(self, current_block):
287 """ Returns previous history string and decrement history cursor.
288 """
289 command = self.history.get_history_item(self.history_cursor - 1)
290
291 if command is not None:
292 if(self.history_cursor+1 == len(self.history.input_cache)):
293 self.history.input_cache[self.history_cursor] = current_block
294 self.history_cursor -= 1
295 return command
296
297
298 def get_history_next(self):
299 """ Returns next history string and increment history cursor.
300 """
301 command = self.history.get_history_item(self.history_cursor+1)
302
303 if command is not None:
304 self.history_cursor += 1
305 return command
306
307 ###
308 # Subclasses probably want to override these methods...
309 ###
310
311 def update_cell_prompt(self, result, blockID=None):
312 """Subclass may override to update the input prompt for a block.
313
314 This method only really makes sens in asyncrhonous frontend.
315 Since this method will be called as a
316 twisted.internet.defer.Deferred's callback, implementations should
317 return result when finished.
318 """
319
320 raise NotImplementedError
321
322
323 def render_result(self, result):
324 """Subclasses must override to render result.
325
326 In asynchronous frontends, this method will be called as a
327 twisted.internet.defer.Deferred's callback. Implementations
328 should thus return result when finished.
329 """
330
331 raise NotImplementedError
332
333
334 def render_error(self, failure):
335 """Subclasses must override to render the failure.
336
337 In asynchronous frontends, this method will be called as a
338 twisted.internet.defer.Deferred's callback. Implementations
339 should thus return result when finished.
340 """
341
342 raise NotImplementedError
343
@@ -1,373 +0,0 b''
1 """
2 Base front end class for all line-oriented frontends, rather than
3 block-oriented.
4
5 Currently this focuses on synchronous frontends.
6 """
7 __docformat__ = "restructuredtext en"
8
9 #-------------------------------------------------------------------------------
10 # Copyright (C) 2008-2011 The IPython Development Team
11 #
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
14 #-------------------------------------------------------------------------------
15
16 #-------------------------------------------------------------------------------
17 # Imports
18 #-------------------------------------------------------------------------------
19 import re
20
21 import sys
22 import codeop
23
24 from frontendbase import FrontEndBase
25 from IPython.kernel.core.interpreter import Interpreter
26
27 def common_prefix(strings):
28 """ Given a list of strings, return the common prefix between all
29 these strings.
30 """
31 ref = strings[0]
32 prefix = ''
33 for size in range(len(ref)):
34 test_prefix = ref[:size+1]
35 for string in strings[1:]:
36 if not string.startswith(test_prefix):
37 return prefix
38 prefix = test_prefix
39
40 return prefix
41
42 #-----------------------------------------------------------------------------
43 # Base class for the line-oriented front ends
44 #-----------------------------------------------------------------------------
45
46 class LineFrontEndBase(FrontEndBase):
47 """ Concrete implementation of the FrontEndBase class. This is meant
48 to be the base class behind all the frontend that are line-oriented,
49 rather than block-oriented.
50 """
51
52 # We need to keep the prompt number, to be able to increment
53 # it when there is an exception.
54 prompt_number = 1
55
56 # We keep a reference to the last result: it helps testing and
57 # programatic control of the frontend.
58 last_result = dict(number=0)
59
60 # The last prompt displayed. Useful for continuation prompts.
61 last_prompt = ''
62
63 # The input buffer being edited
64 input_buffer = ''
65
66 # Set to true for debug output
67 debug = False
68
69 # A banner to print at startup
70 banner = None
71
72 #--------------------------------------------------------------------------
73 # FrontEndBase interface
74 #--------------------------------------------------------------------------
75
76 def __init__(self, shell=None, history=None, banner=None, *args, **kwargs):
77 if shell is None:
78 shell = Interpreter()
79 FrontEndBase.__init__(self, shell=shell, history=history)
80
81 if banner is not None:
82 self.banner = banner
83
84 def start(self):
85 """ Put the frontend in a state where it is ready for user
86 interaction.
87 """
88 if self.banner is not None:
89 self.write(self.banner, refresh=False)
90
91 self.new_prompt(self.input_prompt_template.substitute(number=1))
92
93
94 def complete(self, line):
95 """Complete line in engine's user_ns
96
97 Parameters
98 ----------
99 line : string
100
101 Returns
102 -------
103 The replacement for the line and the list of possible completions.
104 """
105 completions = self.shell.complete(line)
106 complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
107 if completions:
108 prefix = common_prefix(completions)
109 residual = complete_sep.split(line)[:-1]
110 line = line[:-len(residual)] + prefix
111 return line, completions
112
113
114 def render_result(self, result):
115 """ Frontend-specific rendering of the result of a calculation
116 that has been sent to an engine.
117 """
118 if 'stdout' in result and result['stdout']:
119 self.write('\n' + result['stdout'])
120 if 'display' in result and result['display']:
121 self.write("%s%s\n" % (
122 self.output_prompt_template.substitute(
123 number=result['number']),
124 result['display']['pprint']
125 ) )
126
127
128 def render_error(self, failure):
129 """ Frontend-specific rendering of error.
130 """
131 self.write('\n\n'+str(failure)+'\n\n')
132 return failure
133
134
135 def is_complete(self, string):
136 """ Check if a string forms a complete, executable set of
137 commands.
138
139 For the line-oriented frontend, multi-line code is not executed
140 as soon as it is complete: the users has to enter two line
141 returns.
142 """
143 if string in ('', '\n'):
144 # Prefiltering, eg through ipython0, may return an empty
145 # string although some operations have been accomplished. We
146 # thus want to consider an empty string as a complete
147 # statement.
148 return True
149 elif ( len(self.input_buffer.split('\n'))>2
150 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
151 return False
152 else:
153 self.capture_output()
154 try:
155 # Add line returns here, to make sure that the statement is
156 # complete (except if '\' was used).
157 # This should probably be done in a different place (like
158 # maybe 'prefilter_input' method? For now, this works.
159 clean_string = string.rstrip('\n')
160 if not clean_string.endswith('\\'): clean_string +='\n\n'
161 is_complete = codeop.compile_command(clean_string,
162 "<string>", "exec")
163 self.release_output()
164 except Exception as e:
165 # XXX: Hack: return True so that the
166 # code gets executed and the error captured.
167 is_complete = True
168 return is_complete
169
170
171 def write(self, string, refresh=True):
172 """ Write some characters to the display.
173
174 Subclass should overide this method.
175
176 The refresh keyword argument is used in frontends with an
177 event loop, to choose whether the write should trigget an UI
178 refresh, and thus be syncrhonous, or not.
179 """
180 print >>sys.__stderr__, string
181
182
183 def execute(self, python_string, raw_string=None):
184 """ Stores the raw_string in the history, and sends the
185 python string to the interpreter.
186 """
187 if raw_string is None:
188 raw_string = python_string
189 # Create a false result, in case there is an exception
190 self.last_result = dict(number=self.prompt_number)
191
192 try:
193 try:
194 self.history.input_cache[-1] = raw_string.rstrip()
195 result = self.shell.execute(python_string)
196 self.last_result = result
197 self.render_result(result)
198 except:
199 self.show_traceback()
200 finally:
201 self.after_execute()
202
203
204 #--------------------------------------------------------------------------
205 # LineFrontEndBase interface
206 #--------------------------------------------------------------------------
207
208 def prefilter_input(self, string):
209 """ Prefilter the input to turn it in valid python.
210 """
211 string = string.replace('\r\n', '\n')
212 string = string.replace('\t', 4*' ')
213 # Clean the trailing whitespace
214 string = '\n'.join(l.rstrip() for l in string.split('\n'))
215 return string
216
217
218 def after_execute(self):
219 """ All the operations required after an execution to put the
220 terminal back in a shape where it is usable.
221 """
222 self.prompt_number += 1
223 self.new_prompt(self.input_prompt_template.substitute(
224 number=(self.last_result['number'] + 1)))
225 # Start a new empty history entry
226 self._add_history(None, '')
227 self.history_cursor = len(self.history.input_cache) - 1
228
229
230 def complete_current_input(self):
231 """ Do code completion on current line.
232 """
233 if self.debug:
234 print >>sys.__stdout__, "complete_current_input",
235 line = self.input_buffer
236 new_line, completions = self.complete(line)
237 if len(completions)>1:
238 self.write_completion(completions, new_line=new_line)
239 elif not line == new_line:
240 self.input_buffer = new_line
241 if self.debug:
242 print >>sys.__stdout__, 'line', line
243 print >>sys.__stdout__, 'new_line', new_line
244 print >>sys.__stdout__, completions
245
246
247 def get_line_width(self):
248 """ Return the width of the line in characters.
249 """
250 return 80
251
252
253 def write_completion(self, possibilities, new_line=None):
254 """ Write the list of possible completions.
255
256 new_line is the completed input line that should be displayed
257 after the completion are writen. If None, the input_buffer
258 before the completion is used.
259 """
260 if new_line is None:
261 new_line = self.input_buffer
262
263 self.write('\n')
264 max_len = len(max(possibilities, key=len)) + 1
265
266 # Now we check how much symbol we can put on a line...
267 chars_per_line = self.get_line_width()
268 symbols_per_line = max(1, chars_per_line/max_len)
269
270 pos = 1
271 completion_string = []
272 for symbol in possibilities:
273 if pos < symbols_per_line:
274 completion_string.append(symbol.ljust(max_len))
275 pos += 1
276 else:
277 completion_string.append(symbol.rstrip() + '\n')
278 pos = 1
279 self.write(''.join(completion_string))
280 self.new_prompt(self.input_prompt_template.substitute(
281 number=self.last_result['number'] + 1))
282 self.input_buffer = new_line
283
284
285 def new_prompt(self, prompt):
286 """ Prints a prompt and starts a new editing buffer.
287
288 Subclasses should use this method to make sure that the
289 terminal is put in a state favorable for a new line
290 input.
291 """
292 self.input_buffer = ''
293 self.write(prompt)
294
295
296 def continuation_prompt(self):
297 """Returns the current continuation prompt.
298 """
299 return ("."*(len(self.last_prompt)-2) + ': ')
300
301
302 def execute_command(self, command, hidden=False):
303 """ Execute a command, not only in the model, but also in the
304 view, if any.
305 """
306 return self.shell.execute(command)
307
308 #--------------------------------------------------------------------------
309 # Private API
310 #--------------------------------------------------------------------------
311
312 def _on_enter(self, new_line_pos=0):
313 """ Called when the return key is pressed in a line editing
314 buffer.
315
316 Parameters
317 ----------
318 new_line_pos : integer, optional
319 Position of the new line to add, starting from the
320 end (0 adds a new line after the last line, -1 before
321 the last line...)
322
323 Returns
324 -------
325 True if execution is triggered
326 """
327 current_buffer = self.input_buffer
328 # XXX: This string replace is ugly, but there should be no way it
329 # fails.
330 prompt_less_buffer = re.sub('^' + self.continuation_prompt(),
331 '', current_buffer).replace('\n' + self.continuation_prompt(),
332 '\n')
333 cleaned_buffer = self.prefilter_input(prompt_less_buffer)
334 if self.is_complete(cleaned_buffer):
335 self.execute(cleaned_buffer, raw_string=current_buffer)
336 return True
337 else:
338 # Start a new line.
339 new_line_pos = -new_line_pos
340 lines = current_buffer.split('\n')[:-1]
341 prompt_less_lines = prompt_less_buffer.split('\n')
342 # Create the new line, with the continuation prompt, and the
343 # same amount of indent than the line above it.
344 new_line = self.continuation_prompt() + \
345 self._get_indent_string('\n'.join(
346 prompt_less_lines[:new_line_pos-1]))
347 if len(lines) == 1:
348 # We are starting a first continuation line. Indent it.
349 new_line += '\t'
350 elif current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
351 # The last line ends with ":", autoindent the new line.
352 new_line += '\t'
353
354 if new_line_pos == 0:
355 lines.append(new_line)
356 else:
357 lines.insert(new_line_pos, new_line)
358 self.input_buffer = '\n'.join(lines)
359
360
361 def _get_indent_string(self, string):
362 """ Return the string of whitespace that prefixes a line. Used to
363 add the right amount of indendation when creating a new line.
364 """
365 string = string.replace('\t', ' '*4)
366 string = string.split('\n')[-1]
367 indent_chars = len(string) - len(string.lstrip())
368 indent_string = '\t'*(indent_chars // 4) + \
369 ' '*(indent_chars % 4)
370
371 return indent_string
372
373
@@ -1,256 +0,0 b''
1 """
2 Frontend class that uses IPython0 to prefilter the inputs.
3
4 Using the IPython0 mechanism gives us access to the magics.
5
6 This is a transitory class, used here to do the transition between
7 ipython0 and ipython1. This class is meant to be short-lived as more
8 functionnality is abstracted out of ipython0 in reusable functions and
9 is added on the interpreter. This class can be a used to guide this
10 refactoring.
11 """
12
13 #-------------------------------------------------------------------------------
14 # Copyright (C) 2008-2011 The IPython Development Team
15 #
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
18 #-------------------------------------------------------------------------------
19
20 #-------------------------------------------------------------------------------
21 # Imports
22 #-------------------------------------------------------------------------------
23 import sys
24 import pydoc
25 import os
26 import re
27 import __builtin__
28
29 from IPython.core.iplib import InteractiveShell
30 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
31
32 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
33
34 import IPython.utils.io
35
36 from linefrontendbase import LineFrontEndBase, common_prefix
37
38 #-----------------------------------------------------------------------------
39 # Utility functions
40 #-----------------------------------------------------------------------------
41
42 def mk_system_call(system_call_function, command):
43 """ given a os.system replacement, and a leading string command,
44 returns a function that will execute the command with the given
45 argument string.
46 """
47 def my_system_call(args):
48 system_call_function("%s %s" % (command, args))
49
50 my_system_call.__doc__ = "Calls %s" % command
51 return my_system_call
52
53 #-----------------------------------------------------------------------------
54 # Frontend class using ipython0 to do the prefiltering.
55 #-----------------------------------------------------------------------------
56
57 class PrefilterFrontEnd(LineFrontEndBase):
58 """ Class that uses ipython0 to do prefilter the input, do the
59 completion and the magics.
60
61 The core trick is to use an ipython0 instance to prefilter the
62 input, and share the namespace between the interpreter instance used
63 to execute the statements and the ipython0 used for code
64 completion...
65 """
66
67 debug = False
68
69 def __init__(self, ipython0=None, *args, **kwargs):
70 """ Parameters
71 ----------
72
73 ipython0: an optional ipython0 instance to use for command
74 prefiltering and completion.
75 """
76 LineFrontEndBase.__init__(self, *args, **kwargs)
77 self.shell.output_trap = RedirectorOutputTrap(
78 out_callback=self.write,
79 err_callback=self.write,
80 )
81 self.shell.traceback_trap = SyncTracebackTrap(
82 formatters=self.shell.traceback_trap.formatters,
83 )
84
85 # Start the ipython0 instance:
86 self.save_output_hooks()
87 if ipython0 is None:
88 # Instanciate an IPython0 InteractiveShell to be able to use the
89 # prefiltering.
90 # Suppress all key input, to avoid waiting
91 def my_rawinput(x=None):
92 return '\n'
93 old_rawinput = __builtin__.raw_input
94 __builtin__.raw_input = my_rawinput
95 ipython0 = InteractiveShell(
96 parent=None, user_ns=self.shell.user_ns,
97 user_global_ns=self.shell.user_global_ns
98 )
99 __builtin__.raw_input = old_rawinput
100 self.ipython0 = ipython0
101 # Set the pager:
102 self.ipython0.set_hook('show_in_pager',
103 lambda s, string: self.write("\n" + string))
104 self.ipython0.write = self.write
105 self._ip = _ip = self.ipython0
106 # Make sure the raw system call doesn't get called, as we don't
107 # have a stdin accessible.
108 self._ip.system = self.system_call
109 # XXX: Muck around with magics so that they work better
110 # in our environment
111 if not sys.platform.startswith('win'):
112 self.ipython0.magic_ls = mk_system_call(self.system_call,
113 'ls -CF')
114 # And now clean up the mess created by ipython0
115 self.release_output()
116
117
118 if not 'banner' in kwargs and self.banner is None:
119 self.banner = self.ipython0.banner
120
121 # FIXME: __init__ and start should be two different steps
122 self.start()
123
124 #--------------------------------------------------------------------------
125 # FrontEndBase interface
126 #--------------------------------------------------------------------------
127
128 def show_traceback(self):
129 """ Use ipython0 to capture the last traceback and display it.
130 """
131 # Don't do the capture; the except_hook has already done some
132 # modifications to the IO streams, if we store them, we'll be
133 # storing the wrong ones.
134 #self.capture_output()
135 self.ipython0.showtraceback(tb_offset=-1)
136 self.release_output()
137
138
139 def execute(self, python_string, raw_string=None):
140 if self.debug:
141 print 'Executing Python code:', repr(python_string)
142 self.capture_output()
143 LineFrontEndBase.execute(self, python_string,
144 raw_string=raw_string)
145 self.release_output()
146
147
148 def save_output_hooks(self):
149 """ Store all the output hooks we can think of, to be able to
150 restore them.
151
152 We need to do this early, as starting the ipython0 instance will
153 screw ouput hooks.
154 """
155 self.__old_cout_write = Term.cout.write
156 self.__old_cerr_write = Term.cerr.write
157 self.__old_stdout = sys.stdout
158 self.__old_stderr= sys.stderr
159 self.__old_help_output = pydoc.help.output
160 self.__old_display_hook = sys.displayhook
161
162
163 def capture_output(self):
164 """ Capture all the output mechanisms we can think of.
165 """
166 self.save_output_hooks()
167 Term.cout.write = self.write
168 Term.cerr.write = self.write
169 sys.stdout = Term.cout
170 sys.stderr = Term.cerr
171 pydoc.help.output = self.shell.output_trap.out
172
173
174 def release_output(self):
175 """ Release all the different captures we have made.
176 """
177 Term.cout.write = self.__old_cout_write
178 Term.cerr.write = self.__old_cerr_write
179 sys.stdout = self.__old_stdout
180 sys.stderr = self.__old_stderr
181 pydoc.help.output = self.__old_help_output
182 sys.displayhook = self.__old_display_hook
183
184
185 def complete(self, line):
186 # FIXME: This should be factored out in the linefrontendbase
187 # method.
188 word = self._get_completion_text(line)
189 completions = self.ipython0.complete(word)
190 # FIXME: The proper sort should be done in the complete method.
191 key = lambda x: x.replace('_', '')
192 completions.sort(key=key)
193 if completions:
194 prefix = common_prefix(completions)
195 line = line[:-len(word)] + prefix
196 return line, completions
197
198 #--------------------------------------------------------------------------
199 # LineFrontEndBase interface
200 #--------------------------------------------------------------------------
201
202 def prefilter_input(self, input_string):
203 """ Using IPython0 to prefilter the commands to turn them
204 in executable statements that are valid Python strings.
205 """
206 input_string = LineFrontEndBase.prefilter_input(self, input_string)
207 filtered_lines = []
208 # The IPython0 prefilters sometime produce output. We need to
209 # capture it.
210 self.capture_output()
211 self.last_result = dict(number=self.prompt_number)
212
213 try:
214 try:
215 for line in input_string.split('\n'):
216 pf = self.ipython0.prefilter_manager.prefilter_lines
217 filtered_lines.append(pf(line, False).rstrip())
218 except:
219 # XXX: probably not the right thing to do.
220 self.ipython0.showsyntaxerror()
221 self.after_execute()
222 finally:
223 self.release_output()
224
225 # Clean up the trailing whitespace, to avoid indentation errors
226 filtered_string = '\n'.join(filtered_lines)
227 return filtered_string
228
229 #--------------------------------------------------------------------------
230 # PrefilterFrontEnd interface
231 #--------------------------------------------------------------------------
232
233 def system_call(self, command_string):
234 """ Allows for frontend to define their own system call, to be
235 able capture output and redirect input.
236 """
237 return os.system(command_string)
238
239 def do_exit(self):
240 """ Exit the shell, cleanup and save the history.
241 """
242 self.ipython0.atexit_operations()
243
244 def _get_completion_text(self, line):
245 """ Returns the text to be completed by breaking the line at specified
246 delimiters.
247 """
248 # Break at: spaces, '=', all parentheses (except if balanced).
249 # FIXME2: In the future, we need to make the implementation similar to
250 # that in the 'pyreadline' module (modes/basemode.py) where we break at
251 # each delimiter and try to complete the residual line, until we get a
252 # successful list of completions.
253 expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})'
254 complete_sep = re.compile(expression)
255 text = complete_sep.split(line)[-1]
256 return text
@@ -1,19 +0,0 b''
1 """
2 Package for dealing for process execution in a callback environment, in a
3 portable way.
4
5 killable_process.py is a wrapper of subprocess.Popen that allows the
6 subprocess and its children to be killed in a reliable way, including
7 under windows.
8
9 winprocess.py is required by killable_process.py to kill processes under
10 windows.
11
12 piped_process.py wraps process execution with callbacks to print output,
13 in a non-blocking way. It can be used to interact with a subprocess in eg
14 a GUI event loop.
15 """
16
17 from pipedprocess import PipedProcess
18
19
@@ -1,184 +0,0 b''
1 # Addapted from killableprocess.py.
2 #______________________________________________________________________________
3 #
4 # killableprocess - subprocesses which can be reliably killed
5 #
6 # Parts of this module are copied from the subprocess.py file contained
7 # in the Python distribution.
8 #
9 # Copyright (c) 2003-2004 by Peter Astrand <astrand@lysator.liu.se>
10 #
11 # Additions and modifications written by Benjamin Smedberg
12 # <benjamin@smedbergs.us> are Copyright (c) 2006 by the Mozilla Foundation
13 # <http://www.mozilla.org/>
14 #
15 # By obtaining, using, and/or copying this software and/or its
16 # associated documentation, you agree that you have read, understood,
17 # and will comply with the following terms and conditions:
18 #
19 # Permission to use, copy, modify, and distribute this software and
20 # its associated documentation for any purpose and without fee is
21 # hereby granted, provided that the above copyright notice appears in
22 # all copies, and that both that copyright notice and this permission
23 # notice appear in supporting documentation, and that the name of the
24 # author not be used in advertising or publicity pertaining to
25 # distribution of the software without specific, written prior
26 # permission.
27 #
28 # THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
29 # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
30 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
31 # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
32 # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
33 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
34 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35
36 r"""killableprocess - Subprocesses which can be reliably killed
37
38 This module is a subclass of the builtin "subprocess" module. It allows
39 processes that launch subprocesses to be reliably killed on Windows (via the Popen.kill() method.
40
41 It also adds a timeout argument to Wait() for a limited period of time before
42 forcefully killing the process.
43
44 Note: On Windows, this module requires Windows 2000 or higher (no support for
45 Windows 95, 98, or NT 4.0). It also requires ctypes, which is bundled with
46 Python 2.5+ or available from http://python.net/crew/theller/ctypes/
47 """
48
49 import subprocess
50 from subprocess import PIPE
51 import sys
52 import os
53 import types
54
55 try:
56 from subprocess import CalledProcessError
57 except ImportError:
58 # Python 2.4 doesn't implement CalledProcessError
59 class CalledProcessError(Exception):
60 """This exception is raised when a process run by check_call() returns
61 a non-zero exit status. The exit status will be stored in the
62 returncode attribute."""
63 def __init__(self, returncode, cmd):
64 self.returncode = returncode
65 self.cmd = cmd
66 def __str__(self):
67 return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
68
69 mswindows = (sys.platform == "win32")
70
71 skip = False
72
73 if mswindows:
74 import platform
75 if platform.uname()[3] == '' or platform.uname()[3] > '6.0.6000':
76 # Killable process does not work under vista when starting for
77 # something else than cmd.
78 skip = True
79 else:
80 import winprocess
81 else:
82 import signal
83
84 if not mswindows:
85 def DoNothing(*args):
86 pass
87
88
89 if skip:
90 Popen = subprocess.Popen
91 else:
92 class Popen(subprocess.Popen):
93 if not mswindows:
94 # Override __init__ to set a preexec_fn
95 def __init__(self, *args, **kwargs):
96 if len(args) >= 7:
97 raise Exception("Arguments preexec_fn and after must be passed by keyword.")
98
99 real_preexec_fn = kwargs.pop("preexec_fn", None)
100 def setpgid_preexec_fn():
101 os.setpgid(0, 0)
102 if real_preexec_fn:
103 apply(real_preexec_fn)
104
105 kwargs['preexec_fn'] = setpgid_preexec_fn
106
107 subprocess.Popen.__init__(self, *args, **kwargs)
108
109 if mswindows:
110 def _execute_child(self, args, executable, preexec_fn, close_fds,
111 cwd, env, universal_newlines, startupinfo,
112 creationflags, shell,
113 p2cread, p2cwrite,
114 c2pread, c2pwrite,
115 errread, errwrite):
116 if not isinstance(args, types.StringTypes):
117 args = subprocess.list2cmdline(args)
118
119 if startupinfo is None:
120 startupinfo = winprocess.STARTUPINFO()
121
122 if None not in (p2cread, c2pwrite, errwrite):
123 startupinfo.dwFlags |= winprocess.STARTF_USESTDHANDLES
124
125 startupinfo.hStdInput = int(p2cread)
126 startupinfo.hStdOutput = int(c2pwrite)
127 startupinfo.hStdError = int(errwrite)
128 if shell:
129 startupinfo.dwFlags |= winprocess.STARTF_USESHOWWINDOW
130 startupinfo.wShowWindow = winprocess.SW_HIDE
131 comspec = os.environ.get("COMSPEC", "cmd.exe")
132 args = comspec + " /c " + args
133
134 # We create a new job for this process, so that we can kill
135 # the process and any sub-processes
136 self._job = winprocess.CreateJobObject()
137
138 creationflags |= winprocess.CREATE_SUSPENDED
139 creationflags |= winprocess.CREATE_UNICODE_ENVIRONMENT
140
141 hp, ht, pid, tid = winprocess.CreateProcess(
142 executable, args,
143 None, None, # No special security
144 1, # Must inherit handles!
145 creationflags,
146 winprocess.EnvironmentBlock(env),
147 cwd, startupinfo)
148
149 self._child_created = True
150 self._handle = hp
151 self._thread = ht
152 self.pid = pid
153
154 # XXX: A try/except to fix UAC-related problems under
155 # Windows Vista, when reparenting jobs.
156 try:
157 winprocess.AssignProcessToJobObject(self._job, hp)
158 except WindowsError:
159 pass
160 winprocess.ResumeThread(ht)
161
162 if p2cread is not None:
163 p2cread.Close()
164 if c2pwrite is not None:
165 c2pwrite.Close()
166 if errwrite is not None:
167 errwrite.Close()
168
169 def kill(self, group=True):
170 """Kill the process. If group=True, all sub-processes will also be killed."""
171 if mswindows:
172 if group:
173 winprocess.TerminateJobObject(self._job, 127)
174 else:
175 winprocess.TerminateProcess(self._handle, 127)
176 self.returncode = 127
177 else:
178 if group:
179 os.killpg(self.pid, signal.SIGKILL)
180 else:
181 os.kill(self.pid, signal.SIGKILL)
182 self.returncode = -9
183
184
@@ -1,74 +0,0 b''
1 # encoding: utf-8
2 """
3 Object for encapsulating process execution by using callbacks for stdout,
4 stderr and stdin.
5 """
6 __docformat__ = "restructuredtext en"
7
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
14
15 #-------------------------------------------------------------------------------
16 # Imports
17 #-------------------------------------------------------------------------------
18 from killableprocess import Popen, PIPE
19 from threading import Thread
20 from time import sleep
21 import os
22
23 class PipedProcess(Thread):
24 """ Class that encapsulates process execution by using callbacks for
25 stdout, stderr and stdin, and providing a reliable way of
26 killing it.
27 """
28
29 def __init__(self, command_string, out_callback,
30 end_callback=None,):
31 """ command_string: the command line executed to start the
32 process.
33
34 out_callback: the python callable called on stdout/stderr.
35
36 end_callback: an optional callable called when the process
37 finishes.
38
39 These callbacks are called from a different thread as the
40 thread from which is started.
41 """
42 self.command_string = command_string
43 self.out_callback = out_callback
44 self.end_callback = end_callback
45 Thread.__init__(self)
46
47
48 def run(self):
49 """ Start the process and hook up the callbacks.
50 """
51 env = os.environ
52 env['TERM'] = 'xterm'
53 process = Popen(self.command_string + ' 2>&1', shell=True,
54 env=env,
55 universal_newlines=True,
56 stdout=PIPE, stdin=PIPE, )
57 self.process = process
58 while True:
59 out_char = process.stdout.read(1)
60 if out_char == '':
61 if process.poll() is not None:
62 # The process has finished
63 break
64 else:
65 # The process is not giving any interesting
66 # output. No use polling it immediatly.
67 sleep(0.1)
68 else:
69 self.out_callback(out_char)
70
71 if self.end_callback is not None:
72 self.end_callback()
73
74
@@ -1,264 +0,0 b''
1 # A module to expose various thread/process/job related structures and
2 # methods from kernel32
3 #
4 # The MIT License
5 #
6 # Copyright (c) 2006 the Mozilla Foundation <http://www.mozilla.org>
7 #
8 # Permission is hereby granted, free of charge, to any person obtaining a
9 # copy of this software and associated documentation files (the "Software"),
10 # to deal in the Software without restriction, including without limitation
11 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 # and/or sell copies of the Software, and to permit persons to whom the
13 # Software is furnished to do so, subject to the following conditions:
14 #
15 # The above copyright notice and this permission notice shall be included in
16 # all copies or substantial portions of the Software.
17 #
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 # DEALINGS IN THE SOFTWARE.
25
26 from ctypes import c_void_p, POINTER, sizeof, Structure, windll, WinError, WINFUNCTYPE
27 from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LPCWSTR, LPWSTR, UINT, WORD
28
29 LPVOID = c_void_p
30 LPBYTE = POINTER(BYTE)
31 LPDWORD = POINTER(DWORD)
32
33 SW_HIDE = 0
34
35 def ErrCheckBool(result, func, args):
36 """errcheck function for Windows functions that return a BOOL True
37 on success"""
38 if not result:
39 raise WinError()
40 return args
41
42 # CloseHandle()
43
44 CloseHandleProto = WINFUNCTYPE(BOOL, HANDLE)
45 CloseHandle = CloseHandleProto(("CloseHandle", windll.kernel32))
46 CloseHandle.errcheck = ErrCheckBool
47
48 # AutoHANDLE
49
50 class AutoHANDLE(HANDLE):
51 """Subclass of HANDLE which will call CloseHandle() on deletion."""
52 def Close(self):
53 if self.value:
54 CloseHandle(self)
55 self.value = 0
56
57 def __del__(self):
58 self.Close()
59
60 def __int__(self):
61 return self.value
62
63 def ErrCheckHandle(result, func, args):
64 """errcheck function for Windows functions that return a HANDLE."""
65 if not result:
66 raise WinError()
67 return AutoHANDLE(result)
68
69 # PROCESS_INFORMATION structure
70
71 class PROCESS_INFORMATION(Structure):
72 _fields_ = [("hProcess", HANDLE),
73 ("hThread", HANDLE),
74 ("dwProcessID", DWORD),
75 ("dwThreadID", DWORD)]
76
77 def __init__(self):
78 Structure.__init__(self)
79
80 self.cb = sizeof(self)
81
82 LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION)
83
84 # STARTUPINFO structure
85
86 class STARTUPINFO(Structure):
87 _fields_ = [("cb", DWORD),
88 ("lpReserved", LPWSTR),
89 ("lpDesktop", LPWSTR),
90 ("lpTitle", LPWSTR),
91 ("dwX", DWORD),
92 ("dwY", DWORD),
93 ("dwXSize", DWORD),
94 ("dwYSize", DWORD),
95 ("dwXCountChars", DWORD),
96 ("dwYCountChars", DWORD),
97 ("dwFillAttribute", DWORD),
98 ("dwFlags", DWORD),
99 ("wShowWindow", WORD),
100 ("cbReserved2", WORD),
101 ("lpReserved2", LPBYTE),
102 ("hStdInput", HANDLE),
103 ("hStdOutput", HANDLE),
104 ("hStdError", HANDLE)
105 ]
106 LPSTARTUPINFO = POINTER(STARTUPINFO)
107
108 STARTF_USESHOWWINDOW = 0x01
109 STARTF_USESIZE = 0x02
110 STARTF_USEPOSITION = 0x04
111 STARTF_USECOUNTCHARS = 0x08
112 STARTF_USEFILLATTRIBUTE = 0x10
113 STARTF_RUNFULLSCREEN = 0x20
114 STARTF_FORCEONFEEDBACK = 0x40
115 STARTF_FORCEOFFFEEDBACK = 0x80
116 STARTF_USESTDHANDLES = 0x100
117
118 # EnvironmentBlock
119
120 class EnvironmentBlock:
121 """An object which can be passed as the lpEnv parameter of CreateProcess.
122 It is initialized with a dictionary."""
123
124 def __init__(self, dict):
125 if not dict:
126 self._as_parameter_ = None
127 else:
128 values = ["%s=%s" % (key, value)
129 for (key, value) in dict.iteritems()]
130 values.append("")
131 self._as_parameter_ = LPCWSTR("\0".join(values))
132
133 # CreateProcess()
134
135 CreateProcessProto = WINFUNCTYPE(BOOL, # Return type
136 LPCWSTR, # lpApplicationName
137 LPWSTR, # lpCommandLine
138 LPVOID, # lpProcessAttributes
139 LPVOID, # lpThreadAttributes
140 BOOL, # bInheritHandles
141 DWORD, # dwCreationFlags
142 LPVOID, # lpEnvironment
143 LPCWSTR, # lpCurrentDirectory
144 LPSTARTUPINFO, # lpStartupInfo
145 LPPROCESS_INFORMATION # lpProcessInformation
146 )
147
148 CreateProcessFlags = ((1, "lpApplicationName", None),
149 (1, "lpCommandLine"),
150 (1, "lpProcessAttributes", None),
151 (1, "lpThreadAttributes", None),
152 (1, "bInheritHandles", True),
153 (1, "dwCreationFlags", 0),
154 (1, "lpEnvironment", None),
155 (1, "lpCurrentDirectory", None),
156 (1, "lpStartupInfo"),
157 (2, "lpProcessInformation"))
158
159 def ErrCheckCreateProcess(result, func, args):
160 ErrCheckBool(result, func, args)
161 # return a tuple (hProcess, hThread, dwProcessID, dwThreadID)
162 pi = args[9]
163 return AutoHANDLE(pi.hProcess), AutoHANDLE(pi.hThread), pi.dwProcessID, pi.dwThreadID
164
165 CreateProcess = CreateProcessProto(("CreateProcessW", windll.kernel32),
166 CreateProcessFlags)
167 CreateProcess.errcheck = ErrCheckCreateProcess
168
169 CREATE_BREAKAWAY_FROM_JOB = 0x01000000
170 CREATE_DEFAULT_ERROR_MODE = 0x04000000
171 CREATE_NEW_CONSOLE = 0x00000010
172 CREATE_NEW_PROCESS_GROUP = 0x00000200
173 CREATE_NO_WINDOW = 0x08000000
174 CREATE_SUSPENDED = 0x00000004
175 CREATE_UNICODE_ENVIRONMENT = 0x00000400
176 DEBUG_ONLY_THIS_PROCESS = 0x00000002
177 DEBUG_PROCESS = 0x00000001
178 DETACHED_PROCESS = 0x00000008
179
180 # CreateJobObject()
181
182 CreateJobObjectProto = WINFUNCTYPE(HANDLE, # Return type
183 LPVOID, # lpJobAttributes
184 LPCWSTR # lpName
185 )
186
187 CreateJobObjectFlags = ((1, "lpJobAttributes", None),
188 (1, "lpName", None))
189
190 CreateJobObject = CreateJobObjectProto(("CreateJobObjectW", windll.kernel32),
191 CreateJobObjectFlags)
192 CreateJobObject.errcheck = ErrCheckHandle
193
194 # AssignProcessToJobObject()
195
196 AssignProcessToJobObjectProto = WINFUNCTYPE(BOOL, # Return type
197 HANDLE, # hJob
198 HANDLE # hProcess
199 )
200 AssignProcessToJobObjectFlags = ((1, "hJob"),
201 (1, "hProcess"))
202 AssignProcessToJobObject = AssignProcessToJobObjectProto(
203 ("AssignProcessToJobObject", windll.kernel32),
204 AssignProcessToJobObjectFlags)
205 AssignProcessToJobObject.errcheck = ErrCheckBool
206
207 # ResumeThread()
208
209 def ErrCheckResumeThread(result, func, args):
210 if result == -1:
211 raise WinError()
212
213 return args
214
215 ResumeThreadProto = WINFUNCTYPE(DWORD, # Return type
216 HANDLE # hThread
217 )
218 ResumeThreadFlags = ((1, "hThread"),)
219 ResumeThread = ResumeThreadProto(("ResumeThread", windll.kernel32),
220 ResumeThreadFlags)
221 ResumeThread.errcheck = ErrCheckResumeThread
222
223 # TerminateJobObject()
224
225 TerminateJobObjectProto = WINFUNCTYPE(BOOL, # Return type
226 HANDLE, # hJob
227 UINT # uExitCode
228 )
229 TerminateJobObjectFlags = ((1, "hJob"),
230 (1, "uExitCode", 127))
231 TerminateJobObject = TerminateJobObjectProto(
232 ("TerminateJobObject", windll.kernel32),
233 TerminateJobObjectFlags)
234 TerminateJobObject.errcheck = ErrCheckBool
235
236 # WaitForSingleObject()
237
238 WaitForSingleObjectProto = WINFUNCTYPE(DWORD, # Return type
239 HANDLE, # hHandle
240 DWORD, # dwMilliseconds
241 )
242 WaitForSingleObjectFlags = ((1, "hHandle"),
243 (1, "dwMilliseconds", -1))
244 WaitForSingleObject = WaitForSingleObjectProto(
245 ("WaitForSingleObject", windll.kernel32),
246 WaitForSingleObjectFlags)
247
248 INFINITE = -1
249 WAIT_TIMEOUT = 0x0102
250 WAIT_OBJECT_0 = 0x0
251 WAIT_ABANDONED = 0x0080
252
253 # GetExitCodeProcess()
254
255 GetExitCodeProcessProto = WINFUNCTYPE(BOOL, # Return type
256 HANDLE, # hProcess
257 LPDWORD, # lpExitCode
258 )
259 GetExitCodeProcessFlags = ((1, "hProcess"),
260 (2, "lpExitCode"))
261 GetExitCodeProcess = GetExitCodeProcessProto(
262 ("GetExitCodeProcess", windll.kernel32),
263 GetExitCodeProcessFlags)
264 GetExitCodeProcess.errcheck = ErrCheckBool
@@ -1,106 +0,0 b''
1 # encoding: utf-8
2 """This file contains unittests for the asyncfrontendbase module."""
3
4 #---------------------------------------------------------------------------
5 # Copyright (C) 2008-2011 The IPython Development Team
6 #
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
9 #---------------------------------------------------------------------------
10
11 #---------------------------------------------------------------------------
12 # Imports
13 #---------------------------------------------------------------------------
14
15 from twisted.trial import unittest
16
17 from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase
18 from IPython.frontend import frontendbase
19 from IPython.kernel.engineservice import EngineService
20 from IPython.testing.parametric import Parametric, parametric
21
22 #-----------------------------------------------------------------------------
23 # Classes and functions
24 #-----------------------------------------------------------------------------
25
26 class FrontEndCallbackChecker(AsyncFrontEndBase):
27 """FrontEndBase subclass for checking callbacks"""
28 def __init__(self, engine=None, history=None):
29 super(FrontEndCallbackChecker, self).__init__(engine=engine,
30 history=history)
31 self.updateCalled = False
32 self.renderResultCalled = False
33 self.renderErrorCalled = False
34
35 def update_cell_prompt(self, result, blockID=None):
36 self.updateCalled = True
37 return result
38
39 def render_result(self, result):
40 self.renderResultCalled = True
41 return result
42
43 def render_error(self, failure):
44 self.renderErrorCalled = True
45 return failure
46
47
48 class TestAsyncFrontendBase(unittest.TestCase):
49 def setUp(self):
50 """Setup the EngineService and FrontEndBase"""
51
52 self.fb = FrontEndCallbackChecker(engine=EngineService())
53
54 def test_implements_IFrontEnd(self):
55 self.assert_(frontendbase.IFrontEnd.implementedBy(
56 AsyncFrontEndBase))
57
58 def test_is_complete_returns_False_for_incomplete_block(self):
59 block = """def test(a):"""
60 self.assert_(self.fb.is_complete(block) == False)
61
62 def test_is_complete_returns_True_for_complete_block(self):
63 block = """def test(a): pass"""
64 self.assert_(self.fb.is_complete(block))
65 block = """a=3"""
66 self.assert_(self.fb.is_complete(block))
67
68 def test_blockID_added_to_result(self):
69 block = """3+3"""
70 d = self.fb.execute(block, blockID='TEST_ID')
71 d.addCallback(lambda r: self.assert_(r['blockID']=='TEST_ID'))
72 return d
73
74 def test_blockID_added_to_failure(self):
75 block = "raise Exception()"
76 d = self.fb.execute(block,blockID='TEST_ID')
77 d.addErrback(lambda f: self.assert_(f.blockID=='TEST_ID'))
78 return d
79
80 def test_callbacks_added_to_execute(self):
81 d = self.fb.execute("10+10")
82 d.addCallback(lambda r: self.assert_(self.fb.updateCalled and self.fb.renderResultCalled))
83 return d
84
85 def test_error_callback_added_to_execute(self):
86 """Test that render_error called on execution error."""
87
88 d = self.fb.execute("raise Exception()")
89 d.addErrback(lambda f: self.assert_(self.fb.renderErrorCalled))
90 return d
91
92 def test_history_returns_expected_block(self):
93 """Make sure history browsing doesn't fail."""
94
95 blocks = ["a=1","a=2","a=3"]
96 d = self.fb.execute(blocks[0])
97 d.addCallback(lambda _: self.fb.execute(blocks[1]))
98 d.addCallback(lambda _: self.fb.execute(blocks[2]))
99 d.addCallback(lambda _: self.assert_(self.fb.get_history_previous("")==blocks[-2]))
100 d.addCallback(lambda _: self.assert_(self.fb.get_history_previous("")==blocks[-3]))
101 d.addCallback(lambda _: self.assert_(self.fb.get_history_next()==blocks[-2]))
102 return d
103
104 def test_history_returns_none_at_startup(self):
105 self.assert_(self.fb.get_history_previous("")==None)
106 self.assert_(self.fb.get_history_next()==None)
@@ -1,32 +0,0 b''
1 # encoding: utf-8
2 """
3 Test the basic functionality of frontendbase.
4 """
5
6 __docformat__ = "restructuredtext en"
7
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is
12 # in the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
14
15 from IPython.frontend.frontendbase import FrontEndBase
16
17 def test_iscomplete():
18 """ Check that is_complete works.
19 """
20 f = FrontEndBase()
21 assert f.is_complete('(a + a)')
22 assert not f.is_complete('(a + a')
23 assert f.is_complete('1')
24 assert not f.is_complete('1 + ')
25 assert not f.is_complete('1 + \n\n')
26 assert f.is_complete('if True:\n print 1\n')
27 assert not f.is_complete('if True:\n print 1')
28 assert f.is_complete('def f():\n print 1\n')
29
30 if __name__ == '__main__':
31 test_iscomplete()
32
@@ -1,37 +0,0 b''
1 # encoding: utf-8
2 """
3 Test the LineFrontEnd
4 """
5
6 __docformat__ = "restructuredtext en"
7
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is
12 # in the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
14
15 from IPython.frontend.linefrontendbase import LineFrontEndBase
16 from copy import deepcopy
17 import nose.tools as nt
18
19 class ConcreteLineFrontEnd(LineFrontEndBase):
20 """ A concrete class to test the LineFrontEndBase.
21 """
22 def capture_output(self):
23 pass
24
25 def release_output(self):
26 pass
27
28
29 def test_is_complete():
30 """ Tests line completion heuristic.
31 """
32 frontend = ConcreteLineFrontEnd()
33 yield nt.assert_true, not frontend.is_complete('for x in \\')
34 yield nt.assert_true, not frontend.is_complete('for x in (1, ):')
35 yield nt.assert_true, frontend.is_complete('for x in (1, ):\n pass')
36
37
@@ -1,268 +0,0 b''
1 # encoding: utf-8
2 """
3 Test process execution and IO redirection.
4 """
5
6 __docformat__ = "restructuredtext en"
7
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is
12 # in the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
14
15 from copy import copy, deepcopy
16 from cStringIO import StringIO
17 import string
18 import sys
19
20 from nose.tools import assert_equal
21
22 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
23 from IPython.testing.globalipapp import get_ipython
24
25 #-----------------------------------------------------------------------------
26 # Support utilities
27 #-----------------------------------------------------------------------------
28
29 class TestPrefilterFrontEnd(PrefilterFrontEnd):
30
31 input_prompt_template = string.Template('')
32 output_prompt_template = string.Template('')
33 banner = ''
34
35 def __init__(self):
36 self.out = StringIO()
37 PrefilterFrontEnd.__init__(self)
38 # Some more code for isolation (yeah, crazy)
39 self._on_enter()
40 self.out.flush()
41 self.out.reset()
42 self.out.truncate()
43
44 def write(self, string, *args, **kwargs):
45 self.out.write(string)
46
47 def _on_enter(self):
48 self.input_buffer += '\n'
49 PrefilterFrontEnd._on_enter(self)
50
51
52 def isolate_ipython0(func):
53 """ Decorator to isolate execution that involves an iptyhon0.
54
55 Notes
56 -----
57
58 Apply only to functions with no arguments. Nose skips functions
59 with arguments.
60 """
61 def my_func():
62 ip0 = get_ipython()
63 if ip0 is None:
64 return func()
65 # We have a real ipython running...
66 user_ns = ip0.user_ns
67 user_global_ns = ip0.user_global_ns
68
69 # Previously the isolation was attempted with a deep copy of the user
70 # dicts, but we found cases where this didn't work correctly. I'm not
71 # quite sure why, but basically it did damage the user namespace, such
72 # that later tests stopped working correctly. Instead we use a simpler
73 # approach, just computing the list of added keys to the namespace and
74 # eliminating those afterwards. Existing keys that may have been
75 # modified remain modified. So far this has proven to be robust.
76
77 # Compute set of old local/global keys
78 old_locals = set(user_ns.keys())
79 old_globals = set(user_global_ns.keys())
80 try:
81 out = func()
82 finally:
83 # Find new keys, and if any, remove them
84 new_locals = set(user_ns.keys()) - old_locals
85 new_globals = set(user_global_ns.keys()) - old_globals
86 for k in new_locals:
87 del user_ns[k]
88 for k in new_globals:
89 del user_global_ns[k]
90 return out
91
92 my_func.__name__ = func.__name__
93 return my_func
94
95 #-----------------------------------------------------------------------------
96 # Tests
97 #-----------------------------------------------------------------------------
98
99 @isolate_ipython0
100 def test_execution():
101 """ Test execution of a command.
102 """
103 f = TestPrefilterFrontEnd()
104 f.input_buffer = 'print(1)'
105 f._on_enter()
106 out_value = f.out.getvalue()
107 assert_equal(out_value, '1\n')
108
109
110 @isolate_ipython0
111 def test_multiline():
112 """ Test execution of a multiline command.
113 """
114 f = TestPrefilterFrontEnd()
115 f.input_buffer = 'if True:'
116 f._on_enter()
117 f.input_buffer += 'print 1'
118 f._on_enter()
119 out_value = f.out.getvalue()
120 yield assert_equal, out_value, ''
121 f._on_enter()
122 out_value = f.out.getvalue()
123 yield assert_equal, out_value, '1\n'
124 f = TestPrefilterFrontEnd()
125 f.input_buffer='(1 +'
126 f._on_enter()
127 f.input_buffer += '0)'
128 f._on_enter()
129 out_value = f.out.getvalue()
130 yield assert_equal, out_value, ''
131 f._on_enter()
132 out_value = f.out.getvalue()
133 yield assert_equal, out_value, '1\n'
134
135
136 @isolate_ipython0
137 def test_capture():
138 """ Test the capture of output in different channels.
139 """
140 # Test on the OS-level stdout, stderr.
141 f = TestPrefilterFrontEnd()
142 f.input_buffer = \
143 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
144 f._on_enter()
145 out_value = f.out.getvalue()
146 yield assert_equal, out_value, '1'
147 f = TestPrefilterFrontEnd()
148 f.input_buffer = \
149 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
150 f._on_enter()
151 out_value = f.out.getvalue()
152 yield assert_equal, out_value, '1'
153
154
155 @isolate_ipython0
156 def test_magic():
157 """ Test the magic expansion and history.
158
159 This test is fairly fragile and will break when magics change.
160 """
161 f = TestPrefilterFrontEnd()
162 # Before checking the interactive namespace, make sure it's clear (it can
163 # otherwise pick up things stored in the user's local db)
164 f.input_buffer += '%reset -f'
165 f._on_enter()
166 f.complete_current_input()
167 # Now, run the %who magic and check output
168 f.input_buffer += '%who'
169 f._on_enter()
170 out_value = f.out.getvalue()
171 assert_equal(out_value, 'Interactive namespace is empty.\n')
172
173
174 @isolate_ipython0
175 def test_help():
176 """ Test object inspection.
177 """
178 f = TestPrefilterFrontEnd()
179 f.input_buffer += "def f():"
180 f._on_enter()
181 f.input_buffer += "'foobar'"
182 f._on_enter()
183 f.input_buffer += "pass"
184 f._on_enter()
185 f._on_enter()
186 f.input_buffer += "f?"
187 f._on_enter()
188 assert 'traceback' not in f.last_result
189 ## XXX: ipython doctest magic breaks this. I have no clue why
190 #out_value = f.out.getvalue()
191 #assert out_value.split()[-1] == 'foobar'
192
193
194 @isolate_ipython0
195 def test_completion_simple():
196 """ Test command-line completion on trivial examples.
197 """
198 f = TestPrefilterFrontEnd()
199 f.input_buffer = 'zzza = 1'
200 f._on_enter()
201 f.input_buffer = 'zzzb = 2'
202 f._on_enter()
203 f.input_buffer = 'zz'
204 f.complete_current_input()
205 out_value = f.out.getvalue()
206 yield assert_equal, out_value, '\nzzza zzzb '
207 yield assert_equal, f.input_buffer, 'zzz'
208
209
210 @isolate_ipython0
211 def test_completion_parenthesis():
212 """ Test command-line completion when a parenthesis is open.
213 """
214 f = TestPrefilterFrontEnd()
215 f.input_buffer = 'zzza = 1'
216 f._on_enter()
217 f.input_buffer = 'zzzb = 2'
218 f._on_enter()
219 f.input_buffer = 'map(zz'
220 f.complete_current_input()
221 out_value = f.out.getvalue()
222 yield assert_equal, out_value, '\nzzza zzzb '
223 yield assert_equal, f.input_buffer, 'map(zzz'
224
225
226 @isolate_ipython0
227 def test_completion_indexing():
228 """ Test command-line completion when indexing on objects.
229 """
230 f = TestPrefilterFrontEnd()
231 f.input_buffer = 'a = [0]'
232 f._on_enter()
233 f.input_buffer = 'a[0].'
234 f.complete_current_input()
235
236 if sys.version_info[:2] >= (2,6):
237 # In Python 2.6, ints picked up a few non __ methods, so now there are
238 # no completions.
239 assert_equal(f.input_buffer, 'a[0].')
240 else:
241 # Right answer for 2.4/2.5
242 assert_equal(f.input_buffer, 'a[0].__')
243
244
245 @isolate_ipython0
246 def test_completion_equal():
247 """ Test command-line completion when the delimiter is "=", not " ".
248 """
249 f = TestPrefilterFrontEnd()
250 f.input_buffer = 'a=1.'
251 f.complete_current_input()
252 if sys.version_info[:2] >= (2,6):
253 # In Python 2.6, ints picked up a few non __ methods, so now there are
254 # no completions.
255 assert_equal(f.input_buffer, 'a=1.')
256 else:
257 # Right answer for 2.4/2.5
258 assert_equal(f.input_buffer, 'a=1.__')
259
260
261 if __name__ == '__main__':
262 test_magic()
263 test_help()
264 test_execution()
265 test_multiline()
266 test_capture()
267 test_completion_simple()
268 test_completion_complex()
@@ -1,68 +0,0 b''
1 # encoding: utf-8
2 """
3 Test process execution and IO redirection.
4 """
5
6 __docformat__ = "restructuredtext en"
7
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is
12 # in the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
14
15 from cStringIO import StringIO
16 from time import sleep
17 import sys
18
19 from IPython.frontend.process import PipedProcess
20 from IPython.testing import decorators as dec
21
22
23 def test_capture_out():
24 """ A simple test to see if we can execute a process and get the output.
25 """
26 s = StringIO()
27 p = PipedProcess('echo 1', out_callback=s.write, )
28 p.start()
29 p.join()
30 result = s.getvalue().rstrip()
31 assert result == '1'
32
33
34 def test_io():
35 """ Checks that we can send characters on stdin to the process.
36 """
37 s = StringIO()
38 p = PipedProcess(sys.executable + ' -c "a = raw_input(); print a"',
39 out_callback=s.write, )
40 p.start()
41 test_string = '12345\n'
42 while not hasattr(p, 'process'):
43 sleep(0.1)
44 p.process.stdin.write(test_string)
45 p.join()
46 result = s.getvalue()
47 assert result == test_string
48
49
50 @dec.skip_win32
51 def test_kill():
52 """ Check that we can kill a process, and its subprocess.
53 """
54 s = StringIO()
55 p = PipedProcess(sys.executable + ' -c "a = raw_input();"',
56 out_callback=s.write, )
57 p.start()
58 while not hasattr(p, 'process'):
59 sleep(0.1)
60 p.process.kill()
61 assert p.process.poll() is not None
62
63
64 if __name__ == '__main__':
65 test_capture_out()
66 test_io()
67 test_kill()
68
This diff has been collapsed as it changes many lines, (625 lines changed) Show them Hide them
@@ -1,625 +0,0 b''
1 # encoding: utf-8
2 """
3 A Wx widget to act as a console and input commands.
4
5 This widget deals with prompts and provides an edit buffer
6 restricted to after the last prompt.
7 """
8
9 __docformat__ = "restructuredtext en"
10
11 #-------------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
14 # Distributed under the terms of the BSD License. The full license is
15 # in the file COPYING, distributed as part of this software.
16 #-------------------------------------------------------------------------------
17
18 #-------------------------------------------------------------------------------
19 # Imports
20 #-------------------------------------------------------------------------------
21
22 import wx
23 import wx.stc as stc
24
25 from wx.py import editwindow
26 import time
27 import sys
28 import string
29
30 LINESEP = '\n'
31 if sys.platform == 'win32':
32 LINESEP = '\n\r'
33
34 import re
35
36 # FIXME: Need to provide an API for non user-generated display on the
37 # screen: this should not be editable by the user.
38 #-------------------------------------------------------------------------------
39 # Constants
40 #-------------------------------------------------------------------------------
41 _COMPLETE_BUFFER_MARKER = 31
42 _ERROR_MARKER = 30
43 _INPUT_MARKER = 29
44
45 _DEFAULT_SIZE = 10
46 if sys.platform == 'darwin':
47 _DEFAULT_SIZE = 12
48
49 _DEFAULT_STYLE = {
50 #background definition
51 'default' : 'size:%d' % _DEFAULT_SIZE,
52 'bracegood' : 'fore:#00AA00,back:#000000,bold',
53 'bracebad' : 'fore:#FF0000,back:#000000,bold',
54
55 # Edge column: a number of None
56 'edge_column' : -1,
57
58 # properties for the various Python lexer styles
59 'comment' : 'fore:#007F00',
60 'number' : 'fore:#007F7F',
61 'string' : 'fore:#7F007F,italic',
62 'char' : 'fore:#7F007F,italic',
63 'keyword' : 'fore:#00007F,bold',
64 'triple' : 'fore:#7F0000',
65 'tripledouble' : 'fore:#7F0000',
66 'class' : 'fore:#0000FF,bold,underline',
67 'def' : 'fore:#007F7F,bold',
68 'operator' : 'bold',
69
70 # Default colors
71 'trace' : '#FAFAF1', # Nice green
72 'stdout' : '#FDFFD3', # Nice yellow
73 'stderr' : '#FFF1F1', # Nice red
74
75 # Default scintilla settings
76 'antialiasing' : True,
77 'carret_color' : 'BLACK',
78 'background_color' :'WHITE',
79
80 #prompt definition
81 'prompt_in1' : \
82 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02',
83
84 'prompt_out': \
85 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02',
86 }
87
88 # new style numbers
89 _STDOUT_STYLE = 15
90 _STDERR_STYLE = 16
91 _TRACE_STYLE = 17
92
93
94 # system colors
95 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
96
97 # Translation table from ANSI escape sequences to color.
98 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
99 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
100 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
101 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
102 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
103 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
104 '1;34': [12, 'LIGHT BLUE'], '1;35':
105 [13, 'MEDIUM VIOLET RED'],
106 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
107
108 # XXX: Maybe one day we should factor this code with coloransi. Right now
109 # coloransi is hard to reuse and makes our code more complex.
110
111 #we define platform specific fonts
112 if wx.Platform == '__WXMSW__':
113 FACES = { 'times': 'Times New Roman',
114 'mono' : 'Courier New',
115 'helv' : 'Arial',
116 'other': 'Comic Sans MS',
117 'size' : 10,
118 'size2': 8,
119 }
120 elif wx.Platform == '__WXMAC__':
121 FACES = { 'times': 'Times New Roman',
122 'mono' : 'Monaco',
123 'helv' : 'Arial',
124 'other': 'Comic Sans MS',
125 'size' : 10,
126 'size2': 8,
127 }
128 else:
129 FACES = { 'times': 'Times',
130 'mono' : 'Courier',
131 'helv' : 'Helvetica',
132 'other': 'new century schoolbook',
133 'size' : 10,
134 'size2': 8,
135 }
136
137
138 #-----------------------------------------------------------------------------
139 # The console widget class
140 #-----------------------------------------------------------------------------
141
142 class ConsoleWidget(editwindow.EditWindow):
143 """ Specialized styled text control view for console-like workflow.
144
145 This widget is mainly interested in dealing with the prompt and
146 keeping the cursor inside the editing line.
147 """
148
149 # This is where the title captured from the ANSI escape sequences are
150 # stored.
151 title = 'Console'
152
153 # Last prompt printed
154 last_prompt = ''
155
156 # The buffer being edited.
157 def _set_input_buffer(self, string):
158 self.SetSelection(self.current_prompt_pos, self.GetLength())
159 self.ReplaceSelection(string)
160 self.GotoPos(self.GetLength())
161
162 def _get_input_buffer(self):
163 """ Returns the text in current edit buffer.
164 """
165 input_buffer = self.GetTextRange(self.current_prompt_pos,
166 self.GetLength())
167 input_buffer = input_buffer.replace(LINESEP, '\n')
168 return input_buffer
169
170 input_buffer = property(_get_input_buffer, _set_input_buffer)
171
172 style = _DEFAULT_STYLE.copy()
173
174 # Translation table from ANSI escape sequences to color. Override
175 # this to specify your colors.
176 ANSI_STYLES = ANSI_STYLES.copy()
177
178 # Font faces
179 faces = FACES.copy()
180
181 # Store the last time a refresh was done
182 _last_refresh_time = 0
183
184 #--------------------------------------------------------------------------
185 # Public API
186 #--------------------------------------------------------------------------
187
188 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
189 size=wx.DefaultSize, style=wx.WANTS_CHARS, ):
190 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
191 self.configure_scintilla()
192 # Track if 'enter' key as ever been processed
193 # This variable will only be reallowed until key goes up
194 self.enter_catched = False
195 self.current_prompt_pos = 0
196
197 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
198 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
199
200
201 def write(self, text, refresh=True):
202 """ Write given text to buffer, while translating the ansi escape
203 sequences.
204 """
205 # XXX: do not put print statements to sys.stdout/sys.stderr in
206 # this method, the print statements will call this method, as
207 # you will end up with an infinit loop
208 title = self.title_pat.split(text)
209 if len(title)>1:
210 self.title = title[-2]
211
212 text = self.title_pat.sub('', text)
213 segments = self.color_pat.split(text)
214 segment = segments.pop(0)
215 self.GotoPos(self.GetLength())
216 self.StartStyling(self.GetLength(), 0xFF)
217 try:
218 self.AppendText(segment)
219 except UnicodeDecodeError:
220 # XXX: Do I really want to skip the exception?
221 pass
222
223 if segments:
224 for ansi_tag, text in zip(segments[::2], segments[1::2]):
225 self.StartStyling(self.GetLength(), 0xFF)
226 try:
227 self.AppendText(text)
228 except UnicodeDecodeError:
229 # XXX: Do I really want to skip the exception?
230 pass
231
232 if ansi_tag not in self.ANSI_STYLES:
233 style = 0
234 else:
235 style = self.ANSI_STYLES[ansi_tag][0]
236
237 self.SetStyling(len(text), style)
238
239 self.GotoPos(self.GetLength())
240 if refresh:
241 current_time = time.time()
242 if current_time - self._last_refresh_time > 0.03:
243 if sys.platform == 'win32':
244 wx.SafeYield()
245 else:
246 wx.Yield()
247 # self.ProcessEvent(wx.PaintEvent())
248 self._last_refresh_time = current_time
249
250
251 def new_prompt(self, prompt):
252 """ Prints a prompt at start of line, and move the start of the
253 current block there.
254
255 The prompt can be given with ascii escape sequences.
256 """
257 self.write(prompt, refresh=False)
258 # now we update our cursor giving end of prompt
259 self.current_prompt_pos = self.GetLength()
260 self.current_prompt_line = self.GetCurrentLine()
261 self.EnsureCaretVisible()
262 self.last_prompt = prompt
263
264
265 def continuation_prompt(self):
266 """ Returns the current continuation prompt.
267 We need to implement this method here to deal with the
268 ascii escape sequences cleaning up.
269 """
270 # ASCII-less prompt
271 ascii_less = ''.join(self.color_pat.split(self.last_prompt)[2::2])
272 return "."*(len(ascii_less)-2) + ': '
273
274
275 def scroll_to_bottom(self):
276 maxrange = self.GetScrollRange(wx.VERTICAL)
277 self.ScrollLines(maxrange)
278
279
280 def pop_completion(self, possibilities, offset=0):
281 """ Pops up an autocompletion menu. Offset is the offset
282 in characters of the position at which the menu should
283 appear, relativ to the cursor.
284 """
285 self.AutoCompSetIgnoreCase(False)
286 self.AutoCompSetAutoHide(False)
287 self.AutoCompSetMaxHeight(len(possibilities))
288 self.AutoCompShow(offset, " ".join(possibilities))
289
290
291 def get_line_width(self):
292 """ Return the width of the line in characters.
293 """
294 return self.GetSize()[0]/self.GetCharWidth()
295
296
297 def configure_scintilla(self):
298 """ Set up all the styling option of the embedded scintilla
299 widget.
300 """
301 p = self.style.copy()
302
303 # Marker for complete buffer.
304 self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
305 background=p['trace'])
306
307 # Marker for current input buffer.
308 self.MarkerDefine(_INPUT_MARKER, stc.STC_MARK_BACKGROUND,
309 background=p['stdout'])
310 # Marker for tracebacks.
311 self.MarkerDefine(_ERROR_MARKER, stc.STC_MARK_BACKGROUND,
312 background=p['stderr'])
313
314 self.SetEOLMode(stc.STC_EOL_LF)
315
316 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
317 # the widget
318 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
319 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
320 # Also allow Ctrl Shift "=" for poor non US keyboard users.
321 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
322 stc.STC_CMD_ZOOMIN)
323
324 # Keys: we need to clear some of the keys the that don't play
325 # well with a console.
326 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
327 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
328 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
329 self.CmdKeyClear(ord('A'), stc.STC_SCMOD_CTRL)
330
331 self.SetEOLMode(stc.STC_EOL_CRLF)
332 self.SetWrapMode(stc.STC_WRAP_CHAR)
333 self.SetWrapMode(stc.STC_WRAP_WORD)
334 self.SetBufferedDraw(True)
335
336 self.SetUseAntiAliasing(p['antialiasing'])
337
338 self.SetLayoutCache(stc.STC_CACHE_PAGE)
339 self.SetUndoCollection(False)
340 self.SetUseTabs(True)
341 self.SetIndent(4)
342 self.SetTabWidth(4)
343
344 # we don't want scintilla's autocompletion to choose
345 # automaticaly out of a single choice list, as we pop it up
346 # automaticaly
347 self.AutoCompSetChooseSingle(False)
348 self.AutoCompSetMaxHeight(10)
349 # XXX: this doesn't seem to have an effect.
350 self.AutoCompSetFillUps('\n')
351
352 self.SetMargins(3, 3) #text is moved away from border with 3px
353 # Suppressing Scintilla margins
354 self.SetMarginWidth(0, 0)
355 self.SetMarginWidth(1, 0)
356 self.SetMarginWidth(2, 0)
357
358 # Xterm escape sequences
359 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
360 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
361
362 # styles
363
364 self.SetCaretForeground(p['carret_color'])
365
366 background_color = p['background_color']
367
368 if 'default' in p:
369 if 'back' not in p['default']:
370 p['default'] += ',back:%s' % background_color
371 if 'size' not in p['default']:
372 p['default'] += ',size:%s' % self.faces['size']
373 if 'face' not in p['default']:
374 p['default'] += ',face:%s' % self.faces['mono']
375
376 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
377 else:
378 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
379 "fore:%s,back:%s,size:%d,face:%s"
380 % (self.ANSI_STYLES['0;30'][1],
381 background_color,
382 self.faces['size'], self.faces['mono']))
383
384 self.StyleClearAll()
385
386 # XXX: two lines below are usefull if not using the lexer
387 #for style in self.ANSI_STYLES.values():
388 # self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
389
390 # prompt definition
391 self.prompt_in1 = p['prompt_in1']
392 self.prompt_out = p['prompt_out']
393
394 self.output_prompt_template = string.Template(self.prompt_out)
395 self.input_prompt_template = string.Template(self.prompt_in1)
396
397 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
398 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
399 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
400 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
401 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
402 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
403 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
404 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
405 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
406 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
407 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
408 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
409 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
410 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
411 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
412 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
413 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
414
415 edge_column = p['edge_column']
416 if edge_column is not None and edge_column > 0:
417 #we add a vertical line to console widget
418 self.SetEdgeMode(stc.STC_EDGE_LINE)
419 self.SetEdgeColumn(edge_column)
420
421
422 #--------------------------------------------------------------------------
423 # EditWindow API
424 #--------------------------------------------------------------------------
425
426 def OnUpdateUI(self, event):
427 """ Override the OnUpdateUI of the EditWindow class, to prevent
428 syntax highlighting both for faster redraw, and for more
429 consistent look and feel.
430 """
431
432
433 #--------------------------------------------------------------------------
434 # Private API
435 #--------------------------------------------------------------------------
436
437 def _on_key_down(self, event, skip=True):
438 """ Key press callback used for correcting behavior for
439 console-like interfaces: the cursor is constraint to be after
440 the last prompt.
441
442 Return True if event as been catched.
443 """
444 catched = True
445 # XXX: Would the right way to do this be to have a
446 # dictionary at the instance level associating keys with
447 # callbacks? How would we deal with inheritance? And Do the
448 # different callbacks share local variables?
449
450 # Intercept some specific keys.
451 key_code = event.GetKeyCode()
452 if key_code == ord('L') and event.ControlDown() :
453 self.scroll_to_bottom()
454 elif key_code == ord('K') and event.ControlDown() :
455 self.input_buffer = ''
456 elif key_code == ord('A') and event.ControlDown() :
457 self.GotoPos(self.GetLength())
458 self.SetSelectionStart(self.current_prompt_pos)
459 self.SetSelectionEnd(self.GetCurrentPos())
460 catched = True
461 elif key_code == ord('E') and event.ControlDown() :
462 self.GotoPos(self.GetLength())
463 catched = True
464 elif key_code == wx.WXK_PAGEUP:
465 self.ScrollPages(-1)
466 elif key_code == wx.WXK_PAGEDOWN:
467 self.ScrollPages(1)
468 elif key_code == wx.WXK_HOME:
469 self.GotoPos(self.GetLength())
470 elif key_code == wx.WXK_END:
471 self.GotoPos(self.GetLength())
472 elif key_code == wx.WXK_UP and event.ShiftDown():
473 self.ScrollLines(-1)
474 elif key_code == wx.WXK_DOWN and event.ShiftDown():
475 self.ScrollLines(1)
476 else:
477 catched = False
478
479 if self.AutoCompActive():
480 event.Skip()
481 else:
482 if key_code in (13, wx.WXK_NUMPAD_ENTER):
483 # XXX: not catching modifiers, to be wx2.6-compatible
484 catched = True
485 if not self.enter_catched:
486 self.CallTipCancel()
487 if event.ShiftDown():
488 # Try to force execution
489 self.GotoPos(self.GetLength())
490 self.write('\n' + self.continuation_prompt(),
491 refresh=False)
492 self._on_enter()
493 else:
494 self._on_enter()
495 self.enter_catched = True
496
497 elif key_code == wx.WXK_HOME:
498 if not event.ShiftDown():
499 self.GotoPos(self.current_prompt_pos)
500 catched = True
501 else:
502 # FIXME: This behavior is not ideal: if the selection
503 # is already started, it will jump.
504 self.SetSelectionStart(self.current_prompt_pos)
505 self.SetSelectionEnd(self.GetCurrentPos())
506 catched = True
507
508 elif key_code == wx.WXK_UP:
509 if self.GetCurrentLine() > self.current_prompt_line:
510 if self.GetCurrentLine() == self.current_prompt_line + 1 \
511 and self.GetColumn(self.GetCurrentPos()) < \
512 self.GetColumn(self.current_prompt_pos):
513 self.GotoPos(self.current_prompt_pos)
514 else:
515 event.Skip()
516 catched = True
517
518 elif key_code in (wx.WXK_LEFT, wx.WXK_BACK):
519 if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1):
520 event.Skip()
521 catched = True
522
523 elif key_code == wx.WXK_RIGHT:
524 if not self._keep_cursor_in_buffer(self.GetCurrentPos() + 1):
525 event.Skip()
526 catched = True
527
528
529 elif key_code == wx.WXK_DELETE:
530 if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1):
531 event.Skip()
532 catched = True
533
534 if skip and not catched:
535 # Put the cursor back in the edit region
536 if not self._keep_cursor_in_buffer():
537 if not (self.GetCurrentPos() == self.GetLength()
538 and key_code == wx.WXK_DELETE):
539 event.Skip()
540 catched = True
541
542 return catched
543
544
545 def _on_key_up(self, event, skip=True):
546 """ If cursor is outside the editing region, put it back.
547 """
548 if skip:
549 event.Skip()
550 self._keep_cursor_in_buffer()
551
552
553 # XXX: I need to avoid the problem of having an empty glass;
554 def _keep_cursor_in_buffer(self, pos=None):
555 """ Checks if the cursor is where it is allowed to be. If not,
556 put it back.
557
558 Returns
559 -------
560 cursor_moved: Boolean
561 whether or not the cursor was moved by this routine.
562
563 Notes
564 ------
565 WARNING: This does proper checks only for horizontal
566 movements.
567 """
568 if pos is None:
569 current_pos = self.GetCurrentPos()
570 else:
571 current_pos = pos
572 if current_pos < self.current_prompt_pos:
573 self.GotoPos(self.current_prompt_pos)
574 return True
575 line_num = self.LineFromPosition(current_pos)
576 if not current_pos > self.GetLength():
577 line_pos = self.GetColumn(current_pos)
578 else:
579 line_pos = self.GetColumn(self.GetLength())
580 line = self.GetLine(line_num)
581 # Jump the continuation prompt
582 continuation_prompt = self.continuation_prompt()
583 if ( line.startswith(continuation_prompt)
584 and line_pos < len(continuation_prompt)):
585 if line_pos < 2:
586 # We are at the beginning of the line, trying to move
587 # forward: jump forward.
588 self.GotoPos(current_pos + 1 +
589 len(continuation_prompt) - line_pos)
590 else:
591 # Jump back up
592 self.GotoPos(self.GetLineEndPosition(line_num-1))
593 return True
594 elif ( current_pos > self.GetLineEndPosition(line_num)
595 and not current_pos == self.GetLength()):
596 # Jump to next line
597 self.GotoPos(current_pos + 1 +
598 len(continuation_prompt))
599 return True
600
601 # We re-allow enter event processing
602 self.enter_catched = False
603 return False
604
605
606 if __name__ == '__main__':
607 # Some simple code to test the console widget.
608 class MainWindow(wx.Frame):
609 def __init__(self, parent, id, title):
610 wx.Frame.__init__(self, parent, id, title, size=(300, 250))
611 self._sizer = wx.BoxSizer(wx.VERTICAL)
612 self.console_widget = ConsoleWidget(self)
613 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
614 self.SetSizer(self._sizer)
615 self.SetAutoLayout(1)
616 self.Show(True)
617
618 app = wx.PySimpleApp()
619 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
620 w.SetSize((780, 460))
621 w.Show()
622
623 app.MainLoop()
624
625
@@ -1,118 +0,0 b''
1 """
2 Entry point for a simple application giving a graphical frontend to
3 ipython.
4 """
5
6 try:
7 import wx
8 except ImportError as e:
9 e.args[0] = """%s
10 ________________________________________________________________________________
11 You need wxPython to run this application.
12 """ % e.args[0]
13 raise e
14
15 from wx_frontend import WxController
16 import __builtin__
17
18
19 class IPythonXController(WxController):
20 """ Sub class of WxController that adds some application-specific
21 bindings.
22 """
23
24 debug = False
25
26 def __init__(self, *args, **kwargs):
27 WxController.__init__(self, *args, **kwargs)
28 self.ipython0.ask_exit = self.do_exit
29 # Scroll to top
30 maxrange = self.GetScrollRange(wx.VERTICAL)
31 self.ScrollLines(-maxrange)
32
33
34 def _on_key_down(self, event, skip=True):
35 # Intercept Ctrl-D to quit
36 if event.KeyCode == ord('D') and event.ControlDown() and \
37 self.input_buffer == '' and \
38 self._input_state == 'readline':
39 wx.CallAfter(self.ask_exit)
40 else:
41 WxController._on_key_down(self, event, skip=skip)
42
43
44 def ask_exit(self):
45 """ Ask the user whether to exit.
46 """
47 self._input_state = 'subprocess'
48 self.write('\n', refresh=False)
49 self.capture_output()
50 self.ipython0.exit()
51 self.release_output()
52 if not self.ipython0.exit_now:
53 wx.CallAfter(self.new_prompt,
54 self.input_prompt_template.substitute(
55 number=self.last_result['number'] + 1))
56 else:
57 wx.CallAfter(wx.GetApp().Exit)
58 self.write('Exiting ...', refresh=False)
59
60
61 def do_exit(self):
62 """ Exits the interpreter, kills the windows.
63 """
64 WxController.do_exit(self)
65 self.release_output()
66 wx.CallAfter(wx.Exit)
67
68
69
70 class IPythonX(wx.Frame):
71 """ Main frame of the IPythonX app.
72 """
73
74 def __init__(self, parent, id, title, debug=False):
75 wx.Frame.__init__(self, parent, id, title, size=(300,250))
76 self._sizer = wx.BoxSizer(wx.VERTICAL)
77 self.shell = IPythonXController(self, debug=debug)
78 self._sizer.Add(self.shell, 1, wx.EXPAND)
79 self.SetSizer(self._sizer)
80 self.SetAutoLayout(1)
81 self.Show(True)
82 wx.EVT_CLOSE(self, self.on_close)
83
84
85 def on_close(self, event):
86 """ Called on closing the windows.
87
88 Stops the event loop, to close all the child windows.
89 """
90 wx.CallAfter(wx.Exit)
91
92
93 def main():
94 from optparse import OptionParser
95 usage = """usage: %prog [options]
96
97 Simple graphical frontend to IPython, using WxWidgets."""
98 parser = OptionParser(usage=usage)
99 parser.add_option("-d", "--debug",
100 action="store_true", dest="debug", default=False,
101 help="Enable debug message for the wx frontend.")
102
103 options, args = parser.parse_args()
104
105 # Clear the options, to avoid having the ipython0 instance complain
106 import sys
107 sys.argv = sys.argv[:1]
108
109 app = wx.PySimpleApp()
110 frame = IPythonX(None, wx.ID_ANY, 'IPythonX', debug=options.debug)
111 frame.shell.SetFocus()
112 frame.shell.app = app
113 frame.SetSize((680, 460))
114
115 app.MainLoop()
116
117 if __name__ == '__main__':
118 main()
This diff has been collapsed as it changes many lines, (602 lines changed) Show them Hide them
@@ -1,602 +0,0 b''
1 # encoding: utf-8 -*- test-case-name:
2 # FIXME: Need to add tests.
3 # ipython1.frontend.wx.tests.test_wx_frontend -*-
4
5 """Classes to provide a Wx frontend to the
6 IPython.kernel.core.interpreter.
7
8 This class inherits from ConsoleWidget, that provides a console-like
9 widget to provide a text-rendering widget suitable for a terminal.
10 """
11
12 __docformat__ = "restructuredtext en"
13
14 #-------------------------------------------------------------------------------
15 # Copyright (C) 2008-2011 The IPython Development Team
16 #
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
19 #-------------------------------------------------------------------------------
20
21 #-------------------------------------------------------------------------------
22 # Imports
23 #-------------------------------------------------------------------------------
24
25 # Major library imports
26 import re
27 import __builtin__
28 import sys
29 from threading import Lock
30
31 import wx
32 from wx import stc
33
34 # Ipython-specific imports.
35 from IPython.frontend.process import PipedProcess
36 from console_widget import ConsoleWidget, _COMPLETE_BUFFER_MARKER, \
37 _ERROR_MARKER, _INPUT_MARKER
38 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
39
40 #-------------------------------------------------------------------------------
41 # Classes to implement the Wx frontend
42 #-------------------------------------------------------------------------------
43 class WxController(ConsoleWidget, PrefilterFrontEnd):
44 """Classes to provide a Wx frontend to the
45 IPython.kernel.core.interpreter.
46
47 This class inherits from ConsoleWidget, that provides a console-like
48 widget to provide a text-rendering widget suitable for a terminal.
49 """
50
51 # Print debug info on what is happening to the console.
52 debug = False
53
54 # The title of the terminal, as captured through the ANSI escape
55 # sequences.
56 def _set_title(self, title):
57 return self.Parent.SetTitle(title)
58
59 def _get_title(self):
60 return self.Parent.GetTitle()
61
62 title = property(_get_title, _set_title)
63
64
65 # The buffer being edited.
66 # We are duplicating the definition here because of multiple
67 # inheritence
68 def _set_input_buffer(self, string):
69 ConsoleWidget._set_input_buffer(self, string)
70 self._colorize_input_buffer()
71
72 def _get_input_buffer(self):
73 """ Returns the text in current edit buffer.
74 """
75 return ConsoleWidget._get_input_buffer(self)
76
77 input_buffer = property(_get_input_buffer, _set_input_buffer)
78
79
80 #--------------------------------------------------------------------------
81 # Private Attributes
82 #--------------------------------------------------------------------------
83
84 # A flag governing the behavior of the input. Can be:
85 #
86 # 'readline' for readline-like behavior with a prompt
87 # and an edit buffer.
88 # 'raw_input' similar to readline, but triggered by a raw-input
89 # call. Can be used by subclasses to act differently.
90 # 'subprocess' for sending the raw input directly to a
91 # subprocess.
92 # 'buffering' for buffering of the input, that will be used
93 # when the input state switches back to another state.
94 _input_state = 'readline'
95
96 # Attribute to store reference to the pipes of a subprocess, if we
97 # are running any.
98 _running_process = False
99
100 # A queue for writing fast streams to the screen without flooding the
101 # event loop
102 _out_buffer = []
103
104 # A lock to lock the _out_buffer to make sure we don't empty it
105 # while it is being swapped
106 _out_buffer_lock = Lock()
107
108 # The different line markers used to higlight the prompts.
109 _markers = dict()
110
111 #--------------------------------------------------------------------------
112 # Public API
113 #--------------------------------------------------------------------------
114
115 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
116 size=wx.DefaultSize,
117 style=wx.CLIP_CHILDREN|wx.WANTS_CHARS,
118 styledef=None,
119 *args, **kwds):
120 """ Create Shell instance.
121
122 Parameters
123 -----------
124 styledef : dict, optional
125 styledef is the dictionary of options used to define the
126 style.
127 """
128 if styledef is not None:
129 self.style = styledef
130 ConsoleWidget.__init__(self, parent, id, pos, size, style)
131 PrefilterFrontEnd.__init__(self, **kwds)
132
133 # Stick in our own raw_input:
134 self.ipython0.raw_input = self.raw_input
135
136 # A time for flushing the write buffer
137 BUFFER_FLUSH_TIMER_ID = 100
138 self._buffer_flush_timer = wx.Timer(self, BUFFER_FLUSH_TIMER_ID)
139 wx.EVT_TIMER(self, BUFFER_FLUSH_TIMER_ID, self._buffer_flush)
140
141 if 'debug' in kwds:
142 self.debug = kwds['debug']
143 kwds.pop('debug')
144
145 # Inject self in namespace, for debug
146 if self.debug:
147 self.shell.user_ns['self'] = self
148 # Inject our own raw_input in namespace
149 self.shell.user_ns['raw_input'] = self.raw_input
150
151 def raw_input(self, prompt=''):
152 """ A replacement from python's raw_input.
153 """
154 self.new_prompt(prompt)
155 self._input_state = 'raw_input'
156 if hasattr(self, '_cursor'):
157 del self._cursor
158 self.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
159 self.__old_on_enter = self._on_enter
160 event_loop = wx.EventLoop()
161 def my_on_enter():
162 event_loop.Exit()
163 self._on_enter = my_on_enter
164 # XXX: Running a separate event_loop. Ugly.
165 event_loop.Run()
166 self._on_enter = self.__old_on_enter
167 self._input_state = 'buffering'
168 self._cursor = wx.BusyCursor()
169 return self.input_buffer.rstrip('\n')
170
171
172 def system_call(self, command_string):
173 self._input_state = 'subprocess'
174 event_loop = wx.EventLoop()
175 def _end_system_call():
176 self._input_state = 'buffering'
177 self._running_process = False
178 event_loop.Exit()
179
180 self._running_process = PipedProcess(command_string,
181 out_callback=self.buffered_write,
182 end_callback = _end_system_call)
183 self._running_process.start()
184 # XXX: Running a separate event_loop. Ugly.
185 event_loop.Run()
186 # Be sure to flush the buffer.
187 self._buffer_flush(event=None)
188
189
190 def do_calltip(self):
191 """ Analyse current and displays useful calltip for it.
192 """
193 if self.debug:
194 print >>sys.__stdout__, "do_calltip"
195 separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
196 symbol = self.input_buffer
197 symbol_string = separators.split(symbol)[-1]
198 base_symbol_string = symbol_string.split('.')[0]
199 if base_symbol_string in self.shell.user_ns:
200 symbol = self.shell.user_ns[base_symbol_string]
201 elif base_symbol_string in self.shell.user_global_ns:
202 symbol = self.shell.user_global_ns[base_symbol_string]
203 elif base_symbol_string in __builtin__.__dict__:
204 symbol = __builtin__.__dict__[base_symbol_string]
205 else:
206 return False
207 try:
208 for name in symbol_string.split('.')[1:] + ['__doc__']:
209 symbol = getattr(symbol, name)
210 self.AutoCompCancel()
211 # Check that the symbol can indeed be converted to a string:
212 symbol += ''
213 wx.CallAfter(self.CallTipShow, self.GetCurrentPos(), symbol)
214 except:
215 # The retrieve symbol couldn't be converted to a string
216 pass
217
218
219 def _popup_completion(self, create=False):
220 """ Updates the popup completion menu if it exists. If create is
221 true, open the menu.
222 """
223 if self.debug:
224 print >>sys.__stdout__, "_popup_completion"
225 line = self.input_buffer
226 if (self.AutoCompActive() and line and not line[-1] == '.') \
227 or create==True:
228 suggestion, completions = self.complete(line)
229 if completions:
230 offset = len(self._get_completion_text(line))
231 self.pop_completion(completions, offset=offset)
232 if self.debug:
233 print >>sys.__stdout__, completions
234
235
236 def buffered_write(self, text):
237 """ A write method for streams, that caches the stream in order
238 to avoid flooding the event loop.
239
240 This can be called outside of the main loop, in separate
241 threads.
242 """
243 self._out_buffer_lock.acquire()
244 self._out_buffer.append(text)
245 self._out_buffer_lock.release()
246 if not self._buffer_flush_timer.IsRunning():
247 wx.CallAfter(self._buffer_flush_timer.Start,
248 milliseconds=100, oneShot=True)
249
250
251 def clear_screen(self):
252 """ Empty completely the widget.
253 """
254 self.ClearAll()
255 self.new_prompt(self.input_prompt_template.substitute(
256 number=(self.last_result['number'] + 1)))
257
258
259 #--------------------------------------------------------------------------
260 # LineFrontEnd interface
261 #--------------------------------------------------------------------------
262
263 def execute(self, python_string, raw_string=None):
264 self._input_state = 'buffering'
265 self.CallTipCancel()
266 self._cursor = wx.BusyCursor()
267 if raw_string is None:
268 raw_string = python_string
269 end_line = self.current_prompt_line \
270 + max(1, len(raw_string.split('\n'))-1)
271 for i in range(self.current_prompt_line, end_line):
272 if i in self._markers:
273 self.MarkerDeleteHandle(self._markers[i])
274 self._markers[i] = self.MarkerAdd(i, _COMPLETE_BUFFER_MARKER)
275 # Use a callafter to update the display robustly under windows
276 def callback():
277 self.GotoPos(self.GetLength())
278 PrefilterFrontEnd.execute(self, python_string,
279 raw_string=raw_string)
280 wx.CallAfter(callback)
281
282
283 def execute_command(self, command, hidden=False):
284 """ Execute a command, not only in the model, but also in the
285 view.
286 """
287 # XXX: This method needs to be integrated in the base fronted
288 # interface
289 if hidden:
290 return self.shell.execute(command)
291 else:
292 # XXX: we are not storing the input buffer previous to the
293 # execution, as this forces us to run the execution
294 # input_buffer a yield, which is not good.
295 ##current_buffer = self.shell.control.input_buffer
296 command = command.rstrip()
297 if len(command.split('\n')) > 1:
298 # The input command is several lines long, we need to
299 # force the execution to happen
300 command += '\n'
301 cleaned_command = self.prefilter_input(command)
302 self.input_buffer = command
303 # Do not use wx.Yield() (aka GUI.process_events()) to avoid
304 # recursive yields.
305 self.ProcessEvent(wx.PaintEvent())
306 self.write('\n')
307 if not self.is_complete(cleaned_command + '\n'):
308 self._colorize_input_buffer()
309 self.render_error('Incomplete or invalid input')
310 self.new_prompt(self.input_prompt_template.substitute(
311 number=(self.last_result['number'] + 1)))
312 return False
313 self._on_enter()
314 return True
315
316
317 def save_output_hooks(self):
318 self.__old_raw_input = __builtin__.raw_input
319 PrefilterFrontEnd.save_output_hooks(self)
320
321 def capture_output(self):
322 self.SetLexer(stc.STC_LEX_NULL)
323 PrefilterFrontEnd.capture_output(self)
324 __builtin__.raw_input = self.raw_input
325
326
327 def release_output(self):
328 __builtin__.raw_input = self.__old_raw_input
329 PrefilterFrontEnd.release_output(self)
330 self.SetLexer(stc.STC_LEX_PYTHON)
331
332
333 def after_execute(self):
334 PrefilterFrontEnd.after_execute(self)
335 # Clear the wait cursor
336 if hasattr(self, '_cursor'):
337 del self._cursor
338 self.SetCursor(wx.StockCursor(wx.CURSOR_CHAR))
339
340
341 def show_traceback(self):
342 start_line = self.GetCurrentLine()
343 PrefilterFrontEnd.show_traceback(self)
344 self.ProcessEvent(wx.PaintEvent())
345 #wx.Yield()
346 for i in range(start_line, self.GetCurrentLine()):
347 self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER)
348
349
350 #--------------------------------------------------------------------------
351 # FrontEndBase interface
352 #--------------------------------------------------------------------------
353
354 def render_error(self, e):
355 start_line = self.GetCurrentLine()
356 self.write('\n' + e + '\n')
357 for i in range(start_line, self.GetCurrentLine()):
358 self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER)
359
360
361 #--------------------------------------------------------------------------
362 # ConsoleWidget interface
363 #--------------------------------------------------------------------------
364
365 def new_prompt(self, prompt):
366 """ Display a new prompt, and start a new input buffer.
367 """
368 self._input_state = 'readline'
369 ConsoleWidget.new_prompt(self, prompt)
370 i = self.current_prompt_line
371 self._markers[i] = self.MarkerAdd(i, _INPUT_MARKER)
372
373
374 def continuation_prompt(self, *args, **kwargs):
375 # Avoid multiple inheritence, be explicit about which
376 # parent method class gets called
377 return ConsoleWidget.continuation_prompt(self, *args, **kwargs)
378
379
380 def write(self, *args, **kwargs):
381 # Avoid multiple inheritence, be explicit about which
382 # parent method class gets called
383 return ConsoleWidget.write(self, *args, **kwargs)
384
385
386 def _on_key_down(self, event, skip=True):
387 """ Capture the character events, let the parent
388 widget handle them, and put our logic afterward.
389 """
390 # FIXME: This method needs to be broken down in smaller ones.
391 current_line_num = self.GetCurrentLine()
392 key_code = event.GetKeyCode()
393 if key_code in (ord('c'), ord('C')) and event.ControlDown():
394 # Capture Control-C
395 if self._input_state == 'subprocess':
396 if self.debug:
397 print >>sys.__stderr__, 'Killing running process'
398 if hasattr(self._running_process, 'process'):
399 self._running_process.process.kill()
400 elif self._input_state == 'buffering':
401 if self.debug:
402 print >>sys.__stderr__, 'Raising KeyboardInterrupt'
403 raise KeyboardInterrupt
404 # XXX: We need to make really sure we
405 # get back to a prompt.
406 elif self._input_state == 'subprocess' and (
407 ( key_code <256 and not event.ControlDown() )
408 or
409 ( key_code in (ord('d'), ord('D')) and
410 event.ControlDown())):
411 # We are running a process, we redirect keys.
412 ConsoleWidget._on_key_down(self, event, skip=skip)
413 char = chr(key_code)
414 # Deal with some inconsistency in wx keycodes:
415 if char == '\r':
416 char = '\n'
417 elif not event.ShiftDown():
418 char = char.lower()
419 if event.ControlDown() and key_code in (ord('d'), ord('D')):
420 char = '\04'
421 self._running_process.process.stdin.write(char)
422 self._running_process.process.stdin.flush()
423 elif key_code in (ord('('), 57, 53):
424 # Calltips
425 event.Skip()
426 self.do_calltip()
427 elif self.AutoCompActive() and not key_code == ord('\t'):
428 event.Skip()
429 if key_code in (wx.WXK_BACK, wx.WXK_DELETE):
430 wx.CallAfter(self._popup_completion, create=True)
431 elif not key_code in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
432 wx.WXK_RIGHT, wx.WXK_ESCAPE):
433 wx.CallAfter(self._popup_completion)
434 else:
435 # Up history
436 if key_code == wx.WXK_UP and (
437 event.ControlDown() or
438 current_line_num == self.current_prompt_line
439 ):
440 new_buffer = self.get_history_previous(
441 self.input_buffer)
442 if new_buffer is not None:
443 self.input_buffer = new_buffer
444 if self.GetCurrentLine() > self.current_prompt_line:
445 # Go to first line, for seemless history up.
446 self.GotoPos(self.current_prompt_pos)
447 # Down history
448 elif key_code == wx.WXK_DOWN and (
449 event.ControlDown() or
450 current_line_num == self.LineCount -1
451 ):
452 new_buffer = self.get_history_next()
453 if new_buffer is not None:
454 self.input_buffer = new_buffer
455 # Tab-completion
456 elif key_code == ord('\t'):
457 current_line, current_line_num = self.CurLine
458 if not re.match(r'^%s\s*$' % self.continuation_prompt(),
459 current_line):
460 self.complete_current_input()
461 if self.AutoCompActive():
462 wx.CallAfter(self._popup_completion, create=True)
463 else:
464 event.Skip()
465 elif key_code == wx.WXK_BACK:
466 # If characters where erased, check if we have to
467 # remove a line.
468 # XXX: What about DEL?
469 # FIXME: This logics should be in ConsoleWidget, as it is
470 # independant of IPython
471 current_line, _ = self.CurLine
472 current_pos = self.GetCurrentPos()
473 current_line_num = self.LineFromPosition(current_pos)
474 current_col = self.GetColumn(current_pos)
475 len_prompt = len(self.continuation_prompt())
476 if ( current_line.startswith(self.continuation_prompt())
477 and current_col == len_prompt):
478 new_lines = []
479 for line_num, line in enumerate(
480 self.input_buffer.split('\n')):
481 if (line_num + self.current_prompt_line ==
482 current_line_num):
483 new_lines.append(line[len_prompt:])
484 else:
485 new_lines.append('\n'+line)
486 # The first character is '\n', due to the above
487 # code:
488 self.input_buffer = ''.join(new_lines)[1:]
489 self.GotoPos(current_pos - 1 - len_prompt)
490 else:
491 ConsoleWidget._on_key_down(self, event, skip=skip)
492 else:
493 ConsoleWidget._on_key_down(self, event, skip=skip)
494
495
496
497 def _on_key_up(self, event, skip=True):
498 """ Called when any key is released.
499 """
500 if event.GetKeyCode() in (59, ord('.')):
501 # Intercepting '.'
502 event.Skip()
503 wx.CallAfter(self._popup_completion, create=True)
504 else:
505 ConsoleWidget._on_key_up(self, event, skip=skip)
506 # Make sure the continuation_prompts are always followed by a
507 # whitespace
508 new_lines = []
509 if self._input_state == 'readline':
510 position = self.GetCurrentPos()
511 continuation_prompt = self.continuation_prompt()[:-1]
512 for line in self.input_buffer.split('\n'):
513 if not line == continuation_prompt:
514 new_lines.append(line)
515 self.input_buffer = '\n'.join(new_lines)
516 self.GotoPos(position)
517
518
519 def _on_enter(self):
520 """ Called on return key down, in readline input_state.
521 """
522 last_line_num = self.LineFromPosition(self.GetLength())
523 current_line_num = self.LineFromPosition(self.GetCurrentPos())
524 new_line_pos = (last_line_num - current_line_num)
525 if self.debug:
526 print >>sys.__stdout__, repr(self.input_buffer)
527 self.write('\n', refresh=False)
528 # Under windows scintilla seems to be doing funny
529 # stuff to the line returns here, but the getter for
530 # input_buffer filters this out.
531 if sys.platform == 'win32':
532 self.input_buffer = self.input_buffer
533 old_prompt_num = self.current_prompt_pos
534 has_executed = PrefilterFrontEnd._on_enter(self,
535 new_line_pos=new_line_pos)
536 if old_prompt_num == self.current_prompt_pos:
537 # No execution has happened
538 self.GotoPos(self.GetLineEndPosition(current_line_num + 1))
539 return has_executed
540
541
542 #--------------------------------------------------------------------------
543 # EditWindow API
544 #--------------------------------------------------------------------------
545
546 def OnUpdateUI(self, event):
547 """ Override the OnUpdateUI of the EditWindow class, to prevent
548 syntax highlighting both for faster redraw, and for more
549 consistent look and feel.
550 """
551 if not self._input_state == 'readline':
552 ConsoleWidget.OnUpdateUI(self, event)
553
554 #--------------------------------------------------------------------------
555 # Private API
556 #--------------------------------------------------------------------------
557
558 def _buffer_flush(self, event):
559 """ Called by the timer to flush the write buffer.
560
561 This is always called in the mainloop, by the wx timer.
562 """
563 self._out_buffer_lock.acquire()
564 _out_buffer = self._out_buffer
565 self._out_buffer = []
566 self._out_buffer_lock.release()
567 self.write(''.join(_out_buffer), refresh=False)
568
569
570 def _colorize_input_buffer(self):
571 """ Keep the input buffer lines at a bright color.
572 """
573 if not self._input_state in ('readline', 'raw_input'):
574 return
575 end_line = self.GetCurrentLine()
576 if not sys.platform == 'win32':
577 end_line += 1
578 for i in range(self.current_prompt_line, end_line):
579 if i in self._markers:
580 self.MarkerDeleteHandle(self._markers[i])
581 self._markers[i] = self.MarkerAdd(i, _INPUT_MARKER)
582
583
584 if __name__ == '__main__':
585 class MainWindow(wx.Frame):
586 def __init__(self, parent, id, title):
587 wx.Frame.__init__(self, parent, id, title, size=(300,250))
588 self._sizer = wx.BoxSizer(wx.VERTICAL)
589 self.shell = WxController(self)
590 self._sizer.Add(self.shell, 1, wx.EXPAND)
591 self.SetSizer(self._sizer)
592 self.SetAutoLayout(1)
593 self.Show(True)
594
595 app = wx.PySimpleApp()
596 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
597 frame.shell.SetFocus()
598 frame.SetSize((680, 460))
599 self = frame.shell
600
601 app.MainLoop()
602
@@ -1,27 +0,0 b''
1 # encoding: utf-8
2 # -*- test-case-name: IPython.frontend.tests.test_frontendbase -*-
3 """
4 zope.interface mock. If zope is installed, this module provides a zope
5 interface classes, if not it provides mocks for them.
6
7 Classes provided:
8 Interface, Attribute, implements, classProvides
9 """
10 __docformat__ = "restructuredtext en"
11
12 #-------------------------------------------------------------------------------
13 # Copyright (C) 2008-2011 The IPython Development Team
14 #
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
17 #-------------------------------------------------------------------------------
18
19 try:
20 from zope.interface import Interface, Attribute, implements, classProvides
21 except ImportError:
22 #zope.interface is not available
23 Interface = object
24 def Attribute(name, doc): pass
25 def implements(interface): pass
26 def classProvides(interface): pass
27
@@ -1,258 +0,0 b''
1 # -*- coding: utf-8 -*-
2 """Class to trap stdout and stderr and log them separately.
3 """
4
5 #*****************************************************************************
6 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
7 #
8 # Distributed under the terms of the BSD License. The full license is in
9 # the file COPYING, distributed as part of this software.
10 #*****************************************************************************
11
12 import exceptions
13 import sys
14 from cStringIO import StringIO
15
16 class OutputTrapError(exceptions.Exception):
17 """Exception for OutputTrap class."""
18
19 def __init__(self,args=None):
20 exceptions.Exception.__init__(self)
21 self.args = args
22
23 class OutputTrap:
24
25 """Class to trap standard output and standard error. They get logged in
26 StringIO objects which are available as <instance>.out and
27 <instance>.err. The class also offers summary methods which format this
28 data a bit.
29
30 A word of caution: because it blocks messages, using this class can make
31 debugging very tricky. If you are having bizarre problems silently, try
32 turning your output traps off for a while. You can call the constructor
33 with the parameter debug=1 for these cases. This turns actual trapping
34 off, but you can keep the rest of your code unchanged (this has already
35 been a life saver).
36
37 Example:
38
39 # config: trapper with a line of dots as log separator (final '\\n' needed)
40 config = OutputTrap('Config','Out ','Err ','.'*80+'\\n')
41
42 # start trapping output
43 config.trap_all()
44
45 # now all output is logged ...
46 # do stuff...
47
48 # output back to normal:
49 config.release_all()
50
51 # print all that got logged:
52 print config.summary()
53
54 # print individual raw data:
55 print config.out.getvalue()
56 print config.err.getvalue()
57 """
58
59 def __init__(self,name='Generic Output Trap',
60 out_head='Standard Output. ',err_head='Standard Error. ',
61 sum_sep='\n',debug=0,trap_out=0,trap_err=0,
62 quiet_out=0,quiet_err=0):
63 self.name = name
64 self.out_head = out_head
65 self.err_head = err_head
66 self.sum_sep = sum_sep
67 self.out = StringIO()
68 self.err = StringIO()
69 self.out_save = None
70 self.err_save = None
71 self.debug = debug
72 self.quiet_out = quiet_out
73 self.quiet_err = quiet_err
74 if trap_out:
75 self.trap_out()
76 if trap_err:
77 self.trap_err()
78
79 def trap_out(self):
80 """Trap and log stdout."""
81 if sys.stdout is self.out:
82 raise OutputTrapError,'You are already trapping stdout.'
83 if not self.debug:
84 self._out_save = sys.stdout
85 sys.stdout = self.out
86
87 def release_out(self):
88 """Release stdout."""
89 if not self.debug:
90 if not sys.stdout is self.out:
91 raise OutputTrapError,'You are not trapping stdout.'
92 sys.stdout = self._out_save
93 self.out_save = None
94
95 def summary_out(self):
96 """Return as a string the log from stdout."""
97 out = self.out.getvalue()
98 if out:
99 if self.quiet_out:
100 return out
101 else:
102 return self.out_head + 'Log by '+ self.name + ':\n' + out
103 else:
104 return ''
105
106 def flush_out(self):
107 """Flush the stdout log. All data held in the log is lost."""
108
109 self.out.close()
110 self.out = StringIO()
111
112 def trap_err(self):
113 """Trap and log stderr."""
114 if sys.stderr is self.err:
115 raise OutputTrapError,'You are already trapping stderr.'
116 if not self.debug:
117 self._err_save = sys.stderr
118 sys.stderr = self.err
119
120 def release_err(self):
121 """Release stderr."""
122 if not self.debug:
123 if not sys.stderr is self.err:
124 raise OutputTrapError,'You are not trapping stderr.'
125 sys.stderr = self._err_save
126 self.err_save = None
127
128 def summary_err(self):
129 """Return as a string the log from stderr."""
130 err = self.err.getvalue()
131 if err:
132 if self.quiet_err:
133 return err
134 else:
135 return self.err_head + 'Log by '+ self.name + ':\n' + err
136 else:
137 return ''
138
139 def flush_err(self):
140 """Flush the stdout log. All data held in the log is lost."""
141
142 self.err.close()
143 self.err = StringIO()
144
145 def trap_all(self):
146 """Trap and log both stdout and stderr.
147
148 Cacthes and discards OutputTrapError exceptions raised."""
149 try:
150 self.trap_out()
151 except OutputTrapError:
152 pass
153 try:
154 self.trap_err()
155 except OutputTrapError:
156 pass
157
158 def release_all(self):
159 """Release both stdout and stderr.
160
161 Cacthes and discards OutputTrapError exceptions raised."""
162 try:
163 self.release_out()
164 except OutputTrapError:
165 pass
166 try:
167 self.release_err()
168 except OutputTrapError:
169 pass
170
171 def summary_all(self):
172 """Return as a string the log from stdout and stderr, prepending a separator
173 to each (defined in __init__ as sum_sep)."""
174 sum = ''
175 sout = self.summary_out()
176 if sout:
177 sum += self.sum_sep + sout
178 serr = self.summary_err()
179 if serr:
180 sum += '\n'+self.sum_sep + serr
181 return sum
182
183 def flush_all(self):
184 """Flush stdout and stderr"""
185 self.flush_out()
186 self.flush_err()
187
188 # a few shorthands
189 trap = trap_all
190 release = release_all
191 summary = summary_all
192 flush = flush_all
193 # end OutputTrap
194
195
196 #****************************************************************************
197 # Module testing. Incomplete, I'm lazy...
198
199 def _test_all():
200
201 """Module testing functions, activated when the module is called as a
202 script (not imported)."""
203
204 # Put tests for this module in here.
205 # Define them as nested functions so they don't clobber the
206 # pydoc-generated docs
207
208 def _test_():
209 name = ''
210 print '#'*50+'\nRunning test for ' + name
211 # ...
212 print 'Finished test for '+ name +'\n'+'#'*50
213
214 def _test_OutputTrap():
215 trap = OutputTrap(name = 'Test Trap', sum_sep = '.'*50+'\n',
216 out_head = 'SOut. ', err_head = 'SErr. ')
217
218 name = 'OutputTrap class'
219 print '#'*50+'\nRunning test for ' + name
220 print 'Trapping out'
221 trap.trap_out()
222 print >>sys.stdout, '>>stdout. stdout is trapped.'
223 print >>sys.stderr, '>>stderr. stdout is trapped.'
224 trap.release_out()
225 print trap.summary_out()
226
227 print 'Trapping err'
228 trap.trap_err()
229 print >>sys.stdout, '>>stdout. stderr is trapped.'
230 print >>sys.stderr, '>>stderr. stderr is trapped.'
231 trap.release_err()
232 print trap.summary_err()
233
234 print 'Trapping all (no flushing)'
235 trap.trap_all()
236 print >>sys.stdout, '>>stdout. stdout/err is trapped.'
237 print >>sys.stderr, '>>stderr. stdout/err is trapped.'
238 trap.release_all()
239 print trap.summary_all()
240
241 print 'Trapping all (flushing first)'
242 trap.flush()
243 trap.trap_all()
244 print >>sys.stdout, '>>stdout. stdout/err is trapped.'
245 print >>sys.stderr, '>>stderr. stdout/err is trapped.'
246 trap.release_all()
247 print trap.summary_all()
248 print 'Finished test for '+ name +'\n'+'#'*50
249
250 # call the actual tests here:
251 _test_OutputTrap()
252
253
254 if __name__=="__main__":
255 # _test_all() # XXX BROKEN.
256 pass
257
258 #************************ end of file <OutputTrap.py> ************************
@@ -1,47 +0,0 b''
1 # coding: utf-8
2 """
3 A simple class for quitting IPython.
4
5 Authors
6 -------
7 * Fernando Perez
8 * Brian Granger
9 """
10
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
17
18 #-----------------------------------------------------------------------------
19 # Imports
20 #-----------------------------------------------------------------------------
21
22
23 #-----------------------------------------------------------------------------
24 # Code
25 #-----------------------------------------------------------------------------
26
27
28 class Quitter(object):
29 """Simple class to handle exit, similar to Python 2.5's.
30
31 It handles exiting in an ipython-safe manner, which the one in Python 2.5
32 doesn't do (obviously, since it doesn't know about ipython)."""
33
34 def __init__(self, shell, name):
35 self.shell = shell
36 self.name = name
37
38 def __str__(self):
39 return 'Type %s() to exit.' % self.name
40
41 def __call__(self):
42 self.shell.ask_exit()
43
44 # Repr MUST return a string, else display like pprint hooks get confused
45 def __repr__(self):
46 self.shell.ask_exit()
47 return ''
@@ -1,26 +0,0 b''
1 import win32api
2 import win32gui
3 import win32con
4
5 import struct
6 import array
7
8 def findWindows():
9 ret = []
10 sdi = win32api.RegisterWindowMessage("SciTEDirectorInterface")
11 w = win32gui.GetWindow(win32gui.GetDesktopWindow(), win32con.GW_CHILD)
12 while w:
13 res = win32gui.SendMessage(w, sdi, 0, 0)
14 if res == sdi:
15 ret.append(w)
16 w = win32gui.GetWindow(w, win32con.GW_HWNDNEXT)
17
18 return ret
19
20 def sendCommand(w, message):
21 CopyDataStruct = "IIP"
22 char_buffer = array.array('c', message)
23 char_buffer_address = char_buffer.buffer_info()[0]
24 char_buffer_size = char_buffer.buffer_info()[1]
25 cds = struct.pack(CopyDataStruct, 0, char_buffer_size, char_buffer_address)
26 win32gui.SendMessage(w, win32con.WM_COPYDATA, 0, cds)
@@ -1,440 +0,0 b''
1 """
2 Test which prefilter transformations get called for various input lines.
3 Note that this does *not* test the transformations themselves -- it's just
4 verifying that a particular combination of, e.g. config options and escape
5 chars trigger the proper handle_X transform of the input line.
6
7 Usage: run from the command line with *normal* python, not ipython:
8 > python test_prefilter.py
9
10 Fairly quiet output by default. Pass in -v to get everyone's favorite dots.
11 """
12
13 # The prefilter always ends in a call to some self.handle_X method. We swap
14 # all of those out so that we can capture which one was called.
15
16 import sys
17 sys.path.append('..')
18 import IPython
19 import IPython.ipapi
20
21 verbose = False
22 if len(sys.argv) > 1:
23 if sys.argv[1] == '-v':
24 sys.argv = sys.argv[:-1] # IPython is confused by -v, apparently
25 verbose = True
26
27 IPython.Shell.start()
28
29 ip = IPython.ipapi.get()
30
31 # Collect failed tests + stats and print them at the end
32 failures = []
33 num_tests = 0
34
35 # Store the results in module vars as we go
36 last_line = None
37 handler_called = None
38 def install_mock_handler(name):
39 """Swap out one of the IP.handle_x methods with a function which can
40 record which handler was called and what line was produced. The mock
41 handler func always returns '', which causes ipython to cease handling
42 the string immediately. That way, that it doesn't echo output, raise
43 exceptions, etc. But do note that testing multiline strings thus gets
44 a bit hard."""
45 def mock_handler(self, line, continue_prompt=None,
46 pre=None,iFun=None,theRest=None,
47 obj=None):
48 #print "Inside %s with '%s'" % (name, line)
49 global last_line, handler_called
50 last_line = line
51 handler_called = name
52 return ''
53 mock_handler.name = name
54 setattr(IPython.iplib.InteractiveShell, name, mock_handler)
55
56 install_mock_handler('handle_normal')
57 install_mock_handler('handle_auto')
58 install_mock_handler('handle_magic')
59 install_mock_handler('handle_help')
60 install_mock_handler('handle_shell_escape')
61 install_mock_handler('handle_alias')
62 install_mock_handler('handle_emacs')
63
64
65 def reset_esc_handlers():
66 """The escape handlers are stored in a hash (as an attribute of the
67 InteractiveShell *instance*), so we have to rebuild that hash to get our
68 new handlers in there."""
69 s = ip.IP
70 s.esc_handlers = {s.ESC_PAREN : s.handle_auto,
71 s.ESC_QUOTE : s.handle_auto,
72 s.ESC_QUOTE2 : s.handle_auto,
73 s.ESC_MAGIC : s.handle_magic,
74 s.ESC_HELP : s.handle_help,
75 s.ESC_SHELL : s.handle_shell_escape,
76 s.ESC_SH_CAP : s.handle_shell_escape,
77 }
78 reset_esc_handlers()
79
80 # This is so I don't have to quote over and over. Gotta be a better way.
81 handle_normal = 'handle_normal'
82 handle_auto = 'handle_auto'
83 handle_magic = 'handle_magic'
84 handle_help = 'handle_help'
85 handle_shell_escape = 'handle_shell_escape'
86 handle_alias = 'handle_alias'
87 handle_emacs = 'handle_emacs'
88
89 def check(assertion, failure_msg):
90 """Check a boolean assertion and fail with a message if necessary. Store
91 an error essage in module-level failures list in case of failure. Print
92 '.' or 'F' if module var Verbose is true.
93 """
94 global num_tests
95 num_tests += 1
96 if assertion:
97 if verbose:
98 sys.stdout.write('.')
99 sys.stdout.flush()
100 else:
101 if verbose:
102 sys.stdout.write('F')
103 sys.stdout.flush()
104 failures.append(failure_msg)
105
106
107 def check_handler(expected_handler, line):
108 """Verify that the expected hander was called (for the given line,
109 passed in for failure reporting).
110
111 Pulled out to its own function so that tests which don't use
112 run_handler_tests can still take advantage of it."""
113 check(handler_called == expected_handler,
114 "Expected %s to be called for %s, "
115 "instead %s called" % (expected_handler,
116 repr(line),
117 handler_called))
118
119
120 def run_handler_tests(h_tests):
121 """Loop through a series of (input_line, handler_name) pairs, verifying
122 that, for each ip calls the given handler for the given line.
123
124 The verbose complaint includes the line passed in, so if that line can
125 include enough info to find the error, the tests are modestly
126 self-documenting.
127 """
128 for ln, expected_handler in h_tests:
129 global handler_called
130 handler_called = None
131 ip.runlines(ln)
132 check_handler(expected_handler, ln)
133
134 def run_one_test(ln, expected_handler):
135 run_handler_tests([(ln, expected_handler)])
136
137
138 # =========================================
139 # Tests
140 # =========================================
141
142
143 # Fundamental escape characters + whitespace & misc
144 # =================================================
145 esc_handler_tests = [
146 ( '?thing', handle_help, ),
147 ( 'thing?', handle_help ), # '?' can trail...
148 ( 'thing!', handle_normal), # but only '?' can trail
149 ( ' ?thing', handle_normal), # leading whitespace turns off esc chars
150 ( '!ls', handle_shell_escape),
151 ( '! true', handle_shell_escape),
152 ( '!! true', handle_shell_escape),
153 ( '%magic', handle_magic),
154 # XXX Possibly, add test for /,; once those are unhooked from %autocall
155 ( 'emacs_mode # PYTHON-MODE', handle_emacs ),
156 ( ' ', handle_normal),
157
158 # Trailing qmark combos. Odd special cases abound
159
160 # ! always takes priority!
161 ( '!thing?', handle_shell_escape),
162 ( '!thing arg?', handle_shell_escape),
163 ( '!!thing?', handle_shell_escape),
164 ( '!!thing arg?', handle_shell_escape),
165 ( ' !!thing arg?', handle_shell_escape),
166
167 # For all other leading esc chars, we always trigger help
168 ( '%cmd?', handle_help),
169 ( '%cmd ?', handle_help),
170 ( '/cmd?', handle_help),
171 ( '/cmd ?', handle_help),
172 ( ';cmd?', handle_help),
173 ( ',cmd?', handle_help),
174 ]
175 run_handler_tests(esc_handler_tests)
176
177
178
179 # Shell Escapes in Multi-line statements
180 # ======================================
181 #
182 # We can't test this via runlines, since the hacked-over-for-testing
183 # handlers all return None, so continue_prompt never becomes true. Instead
184 # we drop into prefilter directly and pass in continue_prompt.
185
186 old_mls = ip.options.multi_line_specials
187 for ln in [ ' !ls $f multi_line_specials %s',
188 ' !!ls $f multi_line_specials %s', # !! escapes work on mls
189 # Trailing ? doesn't trigger help:
190 ' !ls $f multi_line_specials %s ?',
191 ' !!ls $f multi_line_specials %s ?',
192 ]:
193 ip.options.multi_line_specials = 1
194 on_ln = ln % 'on'
195 ignore = ip.IP.prefilter(on_ln, continue_prompt=True)
196 check_handler(handle_shell_escape, on_ln)
197
198 ip.options.multi_line_specials = 0
199 off_ln = ln % 'off'
200 ignore = ip.IP.prefilter(off_ln, continue_prompt=True)
201 check_handler(handle_normal, off_ln)
202
203 ip.options.multi_line_specials = old_mls
204
205
206 # Automagic
207 # =========
208
209 # Pick one magic fun and one non_magic fun, make sure both exist
210 assert hasattr(ip.IP, "magic_cpaste")
211 assert not hasattr(ip.IP, "magic_does_not_exist")
212 ip.options.autocall = 0 # gotta have this off to get handle_normal
213 ip.options.automagic = 0
214 run_handler_tests([
215 # Without automagic, only shows up with explicit escape
216 ( 'cpaste', handle_normal),
217 ( '%cpaste', handle_magic),
218 ( '%does_not_exist', handle_magic),
219 ])
220 ip.options.automagic = 1
221 run_handler_tests([
222 ( 'cpaste', handle_magic),
223 ( '%cpaste', handle_magic),
224 ( 'does_not_exist', handle_normal),
225 ( '%does_not_exist', handle_magic),
226 ( 'cd /', handle_magic),
227 ( 'cd = 2', handle_normal),
228 ( 'r', handle_magic),
229 ( 'r thing', handle_magic),
230 ( 'r"str"', handle_normal),
231 ])
232
233 # If next elt starts with anything that could be an assignment, func call,
234 # etc, we don't call the magic func, unless explicitly escaped to do so.
235 #magic_killing_tests = []
236 #for c in list('!=()<>,'):
237 # magic_killing_tests.append(('cpaste %s killed_automagic' % c, handle_normal))
238 # magic_killing_tests.append(('%%cpaste %s escaped_magic' % c, handle_magic))
239 #run_handler_tests(magic_killing_tests)
240
241 # magic on indented continuation lines -- on iff multi_line_specials == 1
242 ip.options.multi_line_specials = 0
243 ln = ' cpaste multi_line off kills magic'
244 ignore = ip.IP.prefilter(ln, continue_prompt=True)
245 check_handler(handle_normal, ln)
246
247 ip.options.multi_line_specials = 1
248 ln = ' cpaste multi_line on enables magic'
249 ignore = ip.IP.prefilter(ln, continue_prompt=True)
250 check_handler(handle_magic, ln)
251
252 # user namespace shadows the magic one unless shell escaped
253 ip.user_ns['cpaste'] = 'user_ns'
254 run_handler_tests([
255 ( 'cpaste', handle_normal),
256 ( '%cpaste', handle_magic)])
257 del ip.user_ns['cpaste']
258
259
260
261 # Check for !=() turning off .ofind
262 # =================================
263 class AttributeMutator(object):
264 """A class which will be modified on attribute access, to test ofind"""
265 def __init__(self):
266 self.called = False
267
268 def getFoo(self): self.called = True
269 foo = property(getFoo)
270
271 attr_mutator = AttributeMutator()
272 ip.to_user_ns('attr_mutator')
273
274 ip.options.autocall = 1
275
276 run_one_test('attr_mutator.foo should mutate', handle_normal)
277 check(attr_mutator.called, 'ofind should be called in absence of assign characters')
278
279 for c in list('!=()<>+*/%^&|'):
280 attr_mutator.called = False
281 run_one_test('attr_mutator.foo %s should *not* mutate' % c, handle_normal)
282 run_one_test('attr_mutator.foo%s should *not* mutate' % c, handle_normal)
283
284 check(not attr_mutator.called,
285 'ofind should not be called near character %s' % c)
286
287
288
289 # Alias expansion
290 # ===============
291
292 # With autocall on or off, aliases should be shadowed by user, internal and
293 # __builtin__ namespaces
294 #
295 # XXX Can aliases have '.' in their name? With autocall off, that works,
296 # with autocall on, it doesn't. Hmmm.
297 import __builtin__
298 for ac_state in [0,1]:
299 ip.options.autocall = ac_state
300 ip.IP.alias_table['alias_cmd'] = 'alias_result'
301 ip.IP.alias_table['alias_head.with_dot'] = 'alias_result'
302 run_handler_tests([
303 ("alias_cmd", handle_alias),
304 # XXX See note above
305 #("alias_head.with_dot unshadowed, autocall=%s" % ac_state, handle_alias),
306 ("alias_cmd.something aliases must match whole expr", handle_normal),
307 ("alias_cmd /", handle_alias),
308 ])
309
310 for ns in [ip.user_ns, ip.IP.internal_ns, __builtin__.__dict__ ]:
311 ns['alias_cmd'] = 'a user value'
312 ns['alias_head'] = 'a user value'
313 run_handler_tests([
314 ("alias_cmd", handle_normal),
315 ("alias_head.with_dot", handle_normal)])
316 del ns['alias_cmd']
317 del ns['alias_head']
318
319 ip.options.autocall = 1
320
321
322
323
324 # Autocall
325 # ========
326
327 # For all the tests below, 'len' is callable / 'thing' is not
328
329 # Objects which are instances of IPyAutocall are *always* autocalled
330 import IPython.ipapi
331 class Autocallable(IPython.ipapi.IPyAutocall):
332 def __call__(self):
333 return "called"
334
335 autocallable = Autocallable()
336 ip.to_user_ns('autocallable')
337
338
339 # First, with autocalling fully off
340 ip.options.autocall = 0
341 run_handler_tests( [
342 # With no escapes, no autocalling expansions happen, callable or not,
343 # unless the obj extends IPyAutocall
344 ( 'len autocall_0', handle_normal),
345 ( 'thing autocall_0', handle_normal),
346 ( 'autocallable', handle_auto),
347
348 # With explicit escapes, callable and non-callables both get expanded,
349 # regardless of the %autocall setting:
350 ( '/len autocall_0', handle_auto),
351 ( ',len autocall_0 b0', handle_auto),
352 ( ';len autocall_0 b0', handle_auto),
353
354 ( '/thing autocall_0', handle_auto),
355 ( ',thing autocall_0 b0', handle_auto),
356 ( ';thing autocall_0 b0', handle_auto),
357
358 # Explicit autocall should not trigger if there is leading whitespace
359 ( ' /len autocall_0', handle_normal),
360 ( ' ;len autocall_0', handle_normal),
361 ( ' ,len autocall_0', handle_normal),
362 ( ' / len autocall_0', handle_normal),
363
364 # But should work if the whitespace comes after the esc char
365 ( '/ len autocall_0', handle_auto),
366 ( '; len autocall_0', handle_auto),
367 ( ', len autocall_0', handle_auto),
368 ( '/ len autocall_0', handle_auto),
369 ])
370
371
372 # Now, with autocall in default, 'smart' mode
373 ip.options.autocall = 1
374 run_handler_tests( [
375 # Autocalls without escapes -- only expand if it's callable
376 ( 'len a1', handle_auto),
377 ( 'thing a1', handle_normal),
378 ( 'autocallable', handle_auto),
379
380 # As above, all explicit escapes generate auto-calls, callable or not
381 ( '/len a1', handle_auto),
382 ( ',len a1 b1', handle_auto),
383 ( ';len a1 b1', handle_auto),
384 ( '/thing a1', handle_auto),
385 ( ',thing a1 b1', handle_auto),
386 ( ';thing a1 b1', handle_auto),
387
388 # Autocalls only happen on things which look like funcs, even if
389 # explicitly requested. Which, in this case means they look like a
390 # sequence of identifiers and . attribute references. Possibly the
391 # second of these two should trigger handle_auto. But not for now.
392 ( '"abc".join range(4)', handle_normal),
393 ( '/"abc".join range(4)', handle_normal),
394 ])
395
396
397 # No tests for autocall = 2, since the extra magic there happens inside the
398 # handle_auto function, which our test doesn't examine.
399
400 # Note that we leave autocall in default, 1, 'smart' mode
401
402
403 # Autocall / Binary operators
404 # ==========================
405
406 # Even with autocall on, 'len in thing' won't transform.
407 # But ';len in thing' will
408
409 # Note, the tests below don't check for multi-char ops. It could.
410
411 # XXX % is a binary op and should be in the list, too, but fails
412 bin_ops = list(r'<>,&^|*/+-') + 'is not in and or'.split()
413 bin_tests = []
414 for b in bin_ops:
415 bin_tests.append(('len %s binop_autocall' % b, handle_normal))
416 bin_tests.append((';len %s binop_autocall' % b, handle_auto))
417 bin_tests.append((',len %s binop_autocall' % b, handle_auto))
418 bin_tests.append(('/len %s binop_autocall' % b, handle_auto))
419
420 # Who loves auto-generating tests?
421 run_handler_tests(bin_tests)
422
423
424 # Possibly add tests for namespace shadowing (really ofind's business?).
425 #
426 # user > ipython internal > python builtin > alias > magic
427
428
429 # ============
430 # Test Summary
431 # ============
432 num_f = len(failures)
433 if verbose:
434 print
435 print "%s tests run, %s failure%s" % (num_tests,
436 num_f,
437 num_f != 1 and "s" or "")
438 for f in failures:
439 print f
440
@@ -1,287 +0,0 b''
1 """Twisted shell support.
2
3 XXX - This module is missing proper docs.
4 """
5 # Tell nose to skip this module
6 __test__ = {}
7
8 import sys
9
10 from twisted.internet import reactor, threads
11
12 from IPython.core.ipmaker import make_IPython
13 from IPython.core.iplib import InteractiveShell
14 from IPython.utils.ipstruct import Struct
15 import Queue,thread,threading,signal
16 from signal import signal, SIGINT
17 import IPython.utils.io, ask_yes_no
18 from IPython.utils.warn import warn, error
19 from IPython.utils.decorators import flag_calls
20 from IPython.core import shellglobals
21
22 def install_gtk2():
23 """ Install gtk2 reactor, needs to be called bef """
24 from twisted.internet import gtk2reactor
25 gtk2reactor.install()
26
27
28 def hijack_reactor():
29 """Modifies Twisted's reactor with a dummy so user code does
30 not block IPython. This function returns the original
31 'twisted.internet.reactor' that has been hijacked.
32
33 NOTE: Make sure you call this *AFTER* you've installed
34 the reactor of your choice.
35 """
36 from twisted import internet
37 orig_reactor = internet.reactor
38
39 class DummyReactor(object):
40 def run(self):
41 pass
42 def __getattr__(self, name):
43 return getattr(orig_reactor, name)
44 def __setattr__(self, name, value):
45 return setattr(orig_reactor, name, value)
46
47 internet.reactor = DummyReactor()
48 return orig_reactor
49
50 class TwistedInteractiveShell(InteractiveShell):
51 """Simple multi-threaded shell."""
52
53 # Threading strategy taken from:
54 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
55 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
56 # from the pygtk mailing list, to avoid lockups with system calls.
57
58 # class attribute to indicate whether the class supports threads or not.
59 # Subclasses with thread support should override this as needed.
60 isthreaded = True
61
62 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
63 user_ns=None,user_global_ns=None,banner2='',**kw):
64 """Similar to the normal InteractiveShell, but with threading control"""
65
66 InteractiveShell.__init__(self,name,usage,rc,user_ns,
67 user_global_ns,banner2)
68
69
70 # A queue to hold the code to be executed.
71 self.code_queue = Queue.Queue()
72
73 # Stuff to do at closing time
74 self._kill = None
75 on_kill = kw.get('on_kill', [])
76 # Check that all things to kill are callable:
77 for t in on_kill:
78 if not callable(t):
79 raise TypeError,'on_kill must be a list of callables'
80 self.on_kill = on_kill
81 # thread identity of the "worker thread" (that may execute code directly)
82 self.worker_ident = None
83 self.reactor_started = False
84 self.first_run = True
85
86 def runsource(self, source, filename="<input>", symbol="single"):
87 """Compile and run some source in the interpreter.
88
89 Modified version of code.py's runsource(), to handle threading issues.
90 See the original for full docstring details."""
91
92 # If Ctrl-C was typed, we reset the flag and return right away
93 if shellglobals.KBINT:
94 shellglobals.KBINT = False
95 return False
96
97 if self._kill:
98 # can't queue new code if we are being killed
99 return True
100
101 try:
102 code = self.compile(source, filename, symbol)
103 except (OverflowError, SyntaxError, ValueError):
104 # Case 1
105 self.showsyntaxerror(filename)
106 return False
107
108 if code is None:
109 # Case 2
110 return True
111
112 # shortcut - if we are in worker thread, or the worker thread is not running,
113 # execute directly (to allow recursion and prevent deadlock if code is run early
114 # in IPython construction)
115
116 if (not self.reactor_started or (self.worker_ident is None and not self.first_run)
117 or self.worker_ident == thread.get_ident() or shellglobals.run_in_frontend(source)):
118 InteractiveShell.runcode(self,code)
119 return
120
121 # Case 3
122 # Store code in queue, so the execution thread can handle it.
123
124 self.first_run = False
125 completed_ev, received_ev = threading.Event(), threading.Event()
126
127 self.code_queue.put((code,completed_ev, received_ev))
128
129 reactor.callLater(0.0,self.runcode)
130 received_ev.wait(5)
131 if not received_ev.isSet():
132 # the mainloop is dead, start executing code directly
133 print "Warning: Timeout for mainloop thread exceeded"
134 print "switching to nonthreaded mode (until mainloop wakes up again)"
135 self.worker_ident = None
136 else:
137 completed_ev.wait()
138
139 return False
140
141 def runcode(self):
142 """Execute a code object.
143
144 Multithreaded wrapper around IPython's runcode()."""
145
146
147 # we are in worker thread, stash out the id for runsource()
148 self.worker_ident = thread.get_ident()
149
150 if self._kill:
151 print >>Term.cout, 'Closing threads...',
152 Term.cout.flush()
153 for tokill in self.on_kill:
154 tokill()
155 print >>Term.cout, 'Done.'
156 # allow kill() to return
157 self._kill.set()
158 return True
159
160 # Install SIGINT handler. We do it every time to ensure that if user
161 # code modifies it, we restore our own handling.
162 try:
163 pass
164 signal(SIGINT,shellglobals.sigint_handler)
165 except SystemError:
166 # This happens under Windows, which seems to have all sorts
167 # of problems with signal handling. Oh well...
168 pass
169
170 # Flush queue of pending code by calling the run methood of the parent
171 # class with all items which may be in the queue.
172 code_to_run = None
173 while 1:
174 try:
175 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
176 except Queue.Empty:
177 break
178 received_ev.set()
179
180
181 # Exceptions need to be raised differently depending on which
182 # thread is active. This convoluted try/except is only there to
183 # protect against asynchronous exceptions, to ensure that a shellglobals.KBINT
184 # at the wrong time doesn't deadlock everything. The global
185 # CODE_TO_RUN is set to true/false as close as possible to the
186 # runcode() call, so that the KBINT handler is correctly informed.
187 try:
188 try:
189 shellglobals.CODE_RUN = True
190 InteractiveShell.runcode(self,code_to_run)
191 except KeyboardInterrupt:
192 print "Keyboard interrupted in mainloop"
193 while not self.code_queue.empty():
194 code = self.code_queue.get_nowait()
195 break
196 finally:
197 shellglobals.CODE_RUN = False
198 # allow runsource() return from wait
199 completed_ev.set()
200
201 # This MUST return true for gtk threading to work
202 return True
203
204 def kill(self):
205 """Kill the thread, returning when it has been shut down."""
206 self._kill = threading.Event()
207 reactor.callLater(0.0,self.runcode)
208 self._kill.wait()
209
210
211
212 class IPShellTwisted:
213 """Run a Twisted reactor while in an IPython session.
214
215 Python commands can be passed to the thread where they will be
216 executed. This is implemented by periodically checking for
217 passed code using a Twisted reactor callback.
218 """
219
220 TIMEOUT = 0.01 # Millisecond interval between reactor runs.
221
222 def __init__(self, argv=None, user_ns=None, debug=1,
223 shell_class=TwistedInteractiveShell):
224
225 from twisted.internet import reactor
226 self.reactor = hijack_reactor()
227
228 mainquit = self.reactor.stop
229
230 # Make sure IPython keeps going after reactor stop.
231 def reactorstop():
232 pass
233 self.reactor.stop = reactorstop
234 reactorrun_orig = self.reactor.run
235 self.quitting = False
236 def reactorrun():
237 while True and not self.quitting:
238 reactorrun_orig()
239 self.reactor.run = reactorrun
240
241 self.IP = make_IPython(argv, user_ns=user_ns, debug=debug,
242 shell_class=shell_class,
243 on_kill=[mainquit])
244
245 # threading.Thread.__init__(self)
246
247 def run(self):
248 self.IP.mainloop()
249 self.quitting = True
250 self.IP.kill()
251
252 def mainloop(self):
253 def mainLoopThreadDeath(r):
254 print "mainLoopThreadDeath: ", str(r)
255 def spawnMainloopThread():
256 d=threads.deferToThread(self.run)
257 d.addBoth(mainLoopThreadDeath)
258 reactor.callWhenRunning(spawnMainloopThread)
259 self.IP.reactor_started = True
260 self.reactor.run()
261 print "mainloop ending...."
262
263 exists = True
264
265
266 if __name__ == '__main__':
267 # Sample usage.
268
269 # Create the shell object. This steals twisted.internet.reactor
270 # for its own purposes, to make sure you've already installed a
271 # reactor of your choice.
272 shell = IPShellTwisted(
273 argv=[],
274 user_ns={'__name__': '__example__',
275 'hello': 'world',
276 },
277 )
278
279 # Run the mainloop. This runs the actual reactor.run() method.
280 # The twisted.internet.reactor object at this point is a dummy
281 # object that passes through to the actual reactor, but prevents
282 # run() from being called on it again.
283 shell.mainloop()
284
285 # You must exit IPython to terminate your program.
286 print 'Goodbye!'
287
1 NO CONTENT: file was removed
NO CONTENT: file was removed
@@ -1,1 +0,0 b''
1 Subproject commit 2a98f498092682f11affe9b0b86bd7e642cf7b13
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now