##// END OF EJS Templates
Track upstream
Gael Varoquaux -
r1354:678c861f merge
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -0,0 +1,256 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 }
@@ -0,0 +1,25 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 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)
@@ -0,0 +1,6 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
@@ -0,0 +1,20 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>
@@ -0,0 +1,21 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
@@ -0,0 +1,35 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 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
@@ -0,0 +1,20 b''
1 # Set this prefix to where you want to install the plugin
2 PREFIX=~/usr/local
3 PREFIX=~/tmp/local
4
5 plugin: IPython_doctest_plugin.egg-info
6
7 test: plugin dtexample.py
8 nosetests -s --with-ipdoctest --doctest-tests --doctest-extension=txt \
9 dtexample.py test*.txt
10
11 deb: plugin dtexample.py
12 nosetests -vs --with-ipdoctest --doctest-tests --doctest-extension=txt \
13 test_combo.txt
14
15 IPython_doctest_plugin.egg-info: ipdoctest.py setup.py
16 python setup.py install --prefix=$(PREFIX)
17 touch $@
18
19 clean:
20 rm -rf IPython_doctest_plugin.egg-info *~ *pyc build/ dist/
@@ -0,0 +1,39 b''
1 =======================================================
2 Nose plugin with IPython and extension module support
3 =======================================================
4
5 This directory provides the key functionality for test support that IPython
6 needs as a nose plugin, which can be installed for use in projects other than
7 IPython.
8
9 The presence of a Makefile here is mostly for development and debugging
10 purposes as it only provides a few shorthand commands. You can manually
11 install the plugin by using standard Python procedures (``setup.py install``
12 with appropriate arguments).
13
14 To install the plugin using the Makefile, edit its first line to reflect where
15 you'd like the installation. If you want it system-wide, you may want to edit
16 the install line in the plugin target to use sudo and no prefix::
17
18 sudo python setup.py install
19
20 instead of the code using `--prefix` that's in there.
21
22 Once you've set the prefix, simply build/install the plugin with::
23
24 make
25
26 and run the tests with::
27
28 make test
29
30 You should see output similar to::
31
32 maqroll[plugin]> make test
33 nosetests -s --with-ipdoctest --doctest-tests dtexample.py
34 ..
35 ----------------------------------------------------------------------
36 Ran 2 tests in 0.016s
37
38 OK
39
@@ -0,0 +1,72 b''
1 """Simple example using doctests.
2
3 This file just contains doctests both using plain python and IPython prompts.
4 All tests should be loaded by nose.
5 """
6
7 def pyfunc():
8 """Some pure python tests...
9
10 >>> pyfunc()
11 'pyfunc'
12
13 >>> import os
14
15 >>> 2+3
16 5
17
18 >>> for i in range(3):
19 ... print i,
20 ... print i+1,
21 ...
22 0 1 1 2 2 3
23 """
24
25 return 'pyfunc'
26
27 def ipfunc():
28 """Some ipython tests...
29
30 In [1]: import os
31
32 In [2]: cd /
33 /
34
35 In [3]: 2+3
36 Out[3]: 5
37
38 In [26]: for i in range(3):
39 ....: print i,
40 ....: print i+1,
41 ....:
42 0 1 1 2 2 3
43
44
45 Examples that access the operating system work:
46
47 In [1]: !echo hello
48 hello
49
50 In [2]: !echo hello > /tmp/foo
51
52 In [3]: !cat /tmp/foo
53 hello
54
55 In [4]: rm -f /tmp/foo
56
57 It's OK to use '_' for the last result, but do NOT try to use IPython's
58 numbered history of _NN outputs, since those won't exist under the
59 doctest environment:
60
61 In [7]: 3+4
62 Out[7]: 7
63
64 In [8]: _+3
65 Out[8]: 10
66
67 In [9]: ipfunc()
68 Out[9]: 'ipfunc'
69 """
70
71 return 'ipfunc'
72
This diff has been collapsed as it changes many lines, (587 lines changed) Show them Hide them
@@ -0,0 +1,587 b''
1 """Nose Plugin that supports IPython doctests.
2
3 Limitations:
4
5 - When generating examples for use as doctests, make sure that you have
6 pretty-printing OFF. This can be done either by starting ipython with the
7 flag '--nopprint', by setting pprint to 0 in your ipythonrc file, or by
8 interactively disabling it with %Pprint. This is required so that IPython
9 output matches that of normal Python, which is used by doctest for internal
10 execution.
11
12 - Do not rely on specific prompt numbers for results (such as using
13 '_34==True', for example). For IPython tests run via an external process the
14 prompt numbers may be different, and IPython tests run as normal python code
15 won't even have these special _NN variables set at all.
16
17 - IPython functions that produce output as a side-effect of calling a system
18 process (e.g. 'ls') can be doc-tested, but they must be handled in an
19 external IPython process. Such doctests must be tagged with:
20
21 # ipdoctest: EXTERNAL
22
23 so that the testing machinery handles them differently. Since these are run
24 via pexpect in an external process, they can't deal with exceptions or other
25 fancy featurs of regular doctests. You must limit such tests to simple
26 matching of the output. For this reason, I recommend you limit these kinds
27 of doctests to features that truly require a separate process, and use the
28 normal IPython ones (which have all the features of normal doctests) for
29 everything else. See the examples at the bottom of this file for a
30 comparison of what can be done with both types.
31 """
32
33
34 #-----------------------------------------------------------------------------
35 # Module imports
36
37 # From the standard library
38 import __builtin__
39 import commands
40 import doctest
41 import inspect
42 import logging
43 import os
44 import re
45 import sys
46 import unittest
47
48 from inspect import getmodule
49
50 # Third-party modules
51 import nose.core
52
53 from nose.plugins import doctests, Plugin
54 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
55
56 # Our own imports
57 #from extdoctest import ExtensionDoctest, DocTestFinder
58 #from dttools import DocTestFinder, DocTestCase
59 #-----------------------------------------------------------------------------
60 # Module globals and other constants
61
62 log = logging.getLogger(__name__)
63
64 ###########################################################################
65 # *** HACK ***
66 # We must start our own ipython object and heavily muck with it so that all the
67 # modifications IPython makes to system behavior don't send the doctest
68 # machinery into a fit. This code should be considered a gross hack, but it
69 # gets the job done.
70
71 def start_ipython():
72 """Start a global IPython shell, which we need for IPython-specific syntax.
73 """
74 import IPython
75
76 def xsys(cmd):
77 """Execute a command and print its output.
78
79 This is just a convenience function to replace the IPython system call
80 with one that is more doctest-friendly.
81 """
82 cmd = _ip.IP.var_expand(cmd,depth=1)
83 sys.stdout.write(commands.getoutput(cmd))
84 sys.stdout.flush()
85
86 # Store certain global objects that IPython modifies
87 _displayhook = sys.displayhook
88 _excepthook = sys.excepthook
89 _main = sys.modules.get('__main__')
90
91 # Start IPython instance
92 IPython.Shell.IPShell(['--classic','--noterm_title'])
93
94 # Deactivate the various python system hooks added by ipython for
95 # interactive convenience so we don't confuse the doctest system
96 sys.modules['__main__'] = _main
97 sys.displayhook = _displayhook
98 sys.excepthook = _excepthook
99
100 # So that ipython magics and aliases can be doctested (they work by making
101 # a call into a global _ip object)
102 _ip = IPython.ipapi.get()
103 __builtin__._ip = _ip
104
105 # Modify the IPython system call with one that uses getoutput, so that we
106 # can capture subcommands and print them to Python's stdout, otherwise the
107 # doctest machinery would miss them.
108 _ip.system = xsys
109
110 # The start call MUST be made here. I'm not sure yet why it doesn't work if
111 # it is made later, at plugin initialization time, but in all my tests, that's
112 # the case.
113 start_ipython()
114
115 # *** END HACK ***
116 ###########################################################################
117
118 #-----------------------------------------------------------------------------
119 # Modified version of the one in the stdlib, that fixes a python bug (doctests
120 # not found in extension modules, http://bugs.python.org/issue3158)
121 class DocTestFinder(doctest.DocTestFinder):
122
123 def _from_module(self, module, object):
124 """
125 Return true if the given object is defined in the given
126 module.
127 """
128 if module is None:
129 #print '_fm C1' # dbg
130 return True
131 elif inspect.isfunction(object):
132 #print '_fm C2' # dbg
133 return module.__dict__ is object.func_globals
134 elif inspect.isbuiltin(object):
135 #print '_fm C2-1' # dbg
136 return module.__name__ == object.__module__
137 elif inspect.isclass(object):
138 #print '_fm C3' # dbg
139 return module.__name__ == object.__module__
140 elif inspect.ismethod(object):
141 # This one may be a bug in cython that fails to correctly set the
142 # __module__ attribute of methods, but since the same error is easy
143 # to make by extension code writers, having this safety in place
144 # isn't such a bad idea
145 #print '_fm C3-1' # dbg
146 return module.__name__ == object.im_class.__module__
147 elif inspect.getmodule(object) is not None:
148 #print '_fm C4' # dbg
149 #print 'C4 mod',module,'obj',object # dbg
150 return module is inspect.getmodule(object)
151 elif hasattr(object, '__module__'):
152 #print '_fm C5' # dbg
153 return module.__name__ == object.__module__
154 elif isinstance(object, property):
155 #print '_fm C6' # dbg
156 return True # [XX] no way not be sure.
157 else:
158 raise ValueError("object must be a class or function")
159
160
161
162 def _find(self, tests, obj, name, module, source_lines, globs, seen):
163 """
164 Find tests for the given object and any contained objects, and
165 add them to `tests`.
166 """
167
168 doctest.DocTestFinder._find(self,tests, obj, name, module,
169 source_lines, globs, seen)
170
171 # Below we re-run pieces of the above method with manual modifications,
172 # because the original code is buggy and fails to correctly identify
173 # doctests in extension modules.
174
175 # Local shorthands
176 from inspect import isroutine, isclass, ismodule
177
178 # Look for tests in a module's contained objects.
179 if inspect.ismodule(obj) and self._recurse:
180 for valname, val in obj.__dict__.items():
181 valname1 = '%s.%s' % (name, valname)
182 if ( (isroutine(val) or isclass(val))
183 and self._from_module(module, val) ):
184
185 self._find(tests, val, valname1, module, source_lines,
186 globs, seen)
187
188
189 # Look for tests in a class's contained objects.
190 if inspect.isclass(obj) and self._recurse:
191 #print 'RECURSE into class:',obj # dbg
192 for valname, val in obj.__dict__.items():
193 #valname1 = '%s.%s' % (name, valname) # dbg
194 #print 'N',name,'VN:',valname,'val:',str(val)[:77] # dbg
195 # Special handling for staticmethod/classmethod.
196 if isinstance(val, staticmethod):
197 val = getattr(obj, valname)
198 if isinstance(val, classmethod):
199 val = getattr(obj, valname).im_func
200
201 # Recurse to methods, properties, and nested classes.
202 if ((inspect.isfunction(val) or inspect.isclass(val) or
203 inspect.ismethod(val) or
204 isinstance(val, property)) and
205 self._from_module(module, val)):
206 valname = '%s.%s' % (name, valname)
207 self._find(tests, val, valname, module, source_lines,
208 globs, seen)
209
210
211 class DocTestCase(doctests.DocTestCase):
212 """Proxy for DocTestCase: provides an address() method that
213 returns the correct address for the doctest case. Otherwise
214 acts as a proxy to the test case. To provide hints for address(),
215 an obj may also be passed -- this will be used as the test object
216 for purposes of determining the test address, if it is provided.
217 """
218
219 # doctests loaded via find(obj) omit the module name
220 # so we need to override id, __repr__ and shortDescription
221 # bonus: this will squash a 2.3 vs 2.4 incompatiblity
222 def id(self):
223 name = self._dt_test.name
224 filename = self._dt_test.filename
225 if filename is not None:
226 pk = getpackage(filename)
227 if pk is not None and not name.startswith(pk):
228 name = "%s.%s" % (pk, name)
229 return name
230
231
232 # Classes and functions
233
234 def is_extension_module(filename):
235 """Return whether the given filename is an extension module.
236
237 This simply checks that the extension is either .so or .pyd.
238 """
239 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
240
241
242 # A simple subclassing of the original with a different class name, so we can
243 # distinguish and treat differently IPython examples from pure python ones.
244 class IPExample(doctest.Example): pass
245
246 class IPExternalExample(doctest.Example):
247 """Doctest examples to be run in an external process."""
248
249 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
250 options=None):
251 # Parent constructor
252 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
253
254 # An EXTRA newline is needed to prevent pexpect hangs
255 self.source += '\n'
256
257 class IPDocTestParser(doctest.DocTestParser):
258 """
259 A class used to parse strings containing doctest examples.
260
261 Note: This is a version modified to properly recognize IPython input and
262 convert any IPython examples into valid Python ones.
263 """
264 # This regular expression is used to find doctest examples in a
265 # string. It defines three groups: `source` is the source code
266 # (including leading indentation and prompts); `indent` is the
267 # indentation of the first (PS1) line of the source code; and
268 # `want` is the expected output (including leading indentation).
269
270 # Classic Python prompts or default IPython ones
271 _PS1_PY = r'>>>'
272 _PS2_PY = r'\.\.\.'
273
274 _PS1_IP = r'In\ \[\d+\]:'
275 _PS2_IP = r'\ \ \ \.\.\.+:'
276
277 _RE_TPL = r'''
278 # Source consists of a PS1 line followed by zero or more PS2 lines.
279 (?P<source>
280 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
281 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
282 \n? # a newline
283 # Want consists of any non-blank lines that do not start with PS1.
284 (?P<want> (?:(?![ ]*$) # Not a blank line
285 (?![ ]*%s) # Not a line starting with PS1
286 (?![ ]*%s) # Not a line starting with PS2
287 .*$\n? # But any other line
288 )*)
289 '''
290
291 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
292 re.MULTILINE | re.VERBOSE)
293
294 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
295 re.MULTILINE | re.VERBOSE)
296
297 def ip2py(self,source):
298 """Convert input IPython source into valid Python."""
299 out = []
300 newline = out.append
301 for line in source.splitlines():
302 #newline(_ip.IPipython.prefilter(line,True))
303 newline(_ip.IP.prefilter(line,True))
304 newline('') # ensure a closing newline, needed by doctest
305 return '\n'.join(out)
306
307 def parse(self, string, name='<string>'):
308 """
309 Divide the given string into examples and intervening text,
310 and return them as a list of alternating Examples and strings.
311 Line numbers for the Examples are 0-based. The optional
312 argument `name` is a name identifying this string, and is only
313 used for error messages.
314 """
315
316 #print 'Parse string:\n',string # dbg
317
318 string = string.expandtabs()
319 # If all lines begin with the same indentation, then strip it.
320 min_indent = self._min_indent(string)
321 if min_indent > 0:
322 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
323
324 output = []
325 charno, lineno = 0, 0
326
327 # Whether to convert the input from ipython to python syntax
328 ip2py = False
329 # Find all doctest examples in the string. First, try them as Python
330 # examples, then as IPython ones
331 terms = list(self._EXAMPLE_RE_PY.finditer(string))
332 if terms:
333 # Normal Python example
334 #print '-'*70 # dbg
335 #print 'PyExample, Source:\n',string # dbg
336 #print '-'*70 # dbg
337 Example = doctest.Example
338 else:
339 # It's an ipython example. Note that IPExamples are run
340 # in-process, so their syntax must be turned into valid python.
341 # IPExternalExamples are run out-of-process (via pexpect) so they
342 # don't need any filtering (a real ipython will be executing them).
343 terms = list(self._EXAMPLE_RE_IP.finditer(string))
344 if re.search(r'#\s*ipdoctest:\s*EXTERNAL',string):
345 #print '-'*70 # dbg
346 #print 'IPExternalExample, Source:\n',string # dbg
347 #print '-'*70 # dbg
348 Example = IPExternalExample
349 else:
350 #print '-'*70 # dbg
351 #print 'IPExample, Source:\n',string # dbg
352 #print '-'*70 # dbg
353 Example = IPExample
354 ip2py = True
355
356 for m in terms:
357 # Add the pre-example text to `output`.
358 output.append(string[charno:m.start()])
359 # Update lineno (lines before this example)
360 lineno += string.count('\n', charno, m.start())
361 # Extract info from the regexp match.
362 (source, options, want, exc_msg) = \
363 self._parse_example(m, name, lineno,ip2py)
364 if Example is IPExternalExample:
365 options[doctest.NORMALIZE_WHITESPACE] = True
366 want += '\n'
367 # Create an Example, and add it to the list.
368 if not self._IS_BLANK_OR_COMMENT(source):
369 #print 'Example source:', source # dbg
370 output.append(Example(source, want, exc_msg,
371 lineno=lineno,
372 indent=min_indent+len(m.group('indent')),
373 options=options))
374 # Update lineno (lines inside this example)
375 lineno += string.count('\n', m.start(), m.end())
376 # Update charno.
377 charno = m.end()
378 # Add any remaining post-example text to `output`.
379 output.append(string[charno:])
380
381 return output
382
383 def _parse_example(self, m, name, lineno,ip2py=False):
384 """
385 Given a regular expression match from `_EXAMPLE_RE` (`m`),
386 return a pair `(source, want)`, where `source` is the matched
387 example's source code (with prompts and indentation stripped);
388 and `want` is the example's expected output (with indentation
389 stripped).
390
391 `name` is the string's name, and `lineno` is the line number
392 where the example starts; both are used for error messages.
393
394 Optional:
395 `ip2py`: if true, filter the input via IPython to convert the syntax
396 into valid python.
397 """
398
399 # Get the example's indentation level.
400 indent = len(m.group('indent'))
401
402 # Divide source into lines; check that they're properly
403 # indented; and then strip their indentation & prompts.
404 source_lines = m.group('source').split('\n')
405
406 # We're using variable-length input prompts
407 ps1 = m.group('ps1')
408 ps2 = m.group('ps2')
409 ps1_len = len(ps1)
410
411 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
412 if ps2:
413 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
414
415 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
416
417 if ip2py:
418 # Convert source input from IPython into valid Python syntax
419 source = self.ip2py(source)
420
421 # Divide want into lines; check that it's properly indented; and
422 # then strip the indentation. Spaces before the last newline should
423 # be preserved, so plain rstrip() isn't good enough.
424 want = m.group('want')
425 want_lines = want.split('\n')
426 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
427 del want_lines[-1] # forget final newline & spaces after it
428 self._check_prefix(want_lines, ' '*indent, name,
429 lineno + len(source_lines))
430
431 # Remove ipython output prompt that might be present in the first line
432 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
433
434 want = '\n'.join([wl[indent:] for wl in want_lines])
435
436 # If `want` contains a traceback message, then extract it.
437 m = self._EXCEPTION_RE.match(want)
438 if m:
439 exc_msg = m.group('msg')
440 else:
441 exc_msg = None
442
443 # Extract options from the source.
444 options = self._find_options(source, name, lineno)
445
446 return source, options, want, exc_msg
447
448 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
449 """
450 Given the lines of a source string (including prompts and
451 leading indentation), check to make sure that every prompt is
452 followed by a space character. If any line is not followed by
453 a space character, then raise ValueError.
454
455 Note: IPython-modified version which takes the input prompt length as a
456 parameter, so that prompts of variable length can be dealt with.
457 """
458 space_idx = indent+ps1_len
459 min_len = space_idx+1
460 for i, line in enumerate(lines):
461 if len(line) >= min_len and line[space_idx] != ' ':
462 raise ValueError('line %r of the docstring for %s '
463 'lacks blank after %s: %r' %
464 (lineno+i+1, name,
465 line[indent:space_idx], line))
466
467 SKIP = doctest.register_optionflag('SKIP')
468
469 ###########################################################################
470
471 class DocFileCase(doctest.DocFileCase):
472 """Overrides to provide filename
473 """
474 def address(self):
475 return (self._dt_test.filename, None, None)
476
477
478 class ExtensionDoctest(doctests.Doctest):
479 """Nose Plugin that supports doctests in extension modules.
480 """
481 name = 'extdoctest' # call nosetests with --with-extdoctest
482 enabled = True
483
484 def options(self, parser, env=os.environ):
485 Plugin.options(self, parser, env)
486
487 def configure(self, options, config):
488 Plugin.configure(self, options, config)
489 self.doctest_tests = options.doctest_tests
490 self.extension = tolist(options.doctestExtension)
491 self.finder = DocTestFinder()
492 self.parser = doctest.DocTestParser()
493
494
495 def loadTestsFromExtensionModule(self,filename):
496 bpath,mod = os.path.split(filename)
497 modname = os.path.splitext(mod)[0]
498 try:
499 sys.path.append(bpath)
500 module = __import__(modname)
501 tests = list(self.loadTestsFromModule(module))
502 finally:
503 sys.path.pop()
504 return tests
505
506 def loadTestsFromFile(self, filename):
507 if is_extension_module(filename):
508 for t in self.loadTestsFromExtensionModule(filename):
509 yield t
510 else:
511 ## for t in list(doctests.Doctest.loadTestsFromFile(self,filename)):
512 ## yield t
513 pass
514
515 if self.extension and anyp(filename.endswith, self.extension):
516 #print 'lTF',filename # dbg
517 name = os.path.basename(filename)
518 dh = open(filename)
519 try:
520 doc = dh.read()
521 finally:
522 dh.close()
523 test = self.parser.get_doctest(
524 doc, globs={'__file__': filename}, name=name,
525 filename=filename, lineno=0)
526 if test.examples:
527 #print 'FileCase:',test.examples # dbg
528 yield DocFileCase(test)
529 else:
530 yield False # no tests to load
531
532
533 def wantFile(self,filename):
534 """Return whether the given filename should be scanned for tests.
535
536 Modified version that accepts extension modules as valid containers for
537 doctests.
538 """
539 #print 'Filename:',filename # dbg
540
541 if is_extension_module(filename):
542 return True
543 else:
544 return doctests.Doctest.wantFile(self,filename)
545
546 # NOTE: the method below is a *copy* of the one in the nose doctests
547 # plugin, but we have to replicate it here in order to have it resolve the
548 # DocTestCase (last line) to our local copy, since the nose plugin doesn't
549 # provide a public hook for what TestCase class to use. The alternative
550 # would be to monkeypatch doctest in the stdlib, but that's ugly and
551 # brittle, since a change in plugin load order can break it. So for now,
552 # we just paste this in here, inelegant as this may be.
553
554 def loadTestsFromModule(self, module):
555 #print 'lTM',module # dbg
556
557 if not self.matches(module.__name__):
558 log.debug("Doctest doesn't want module %s", module)
559 return
560 tests = self.finder.find(module)
561 if not tests:
562 return
563 tests.sort()
564 module_file = module.__file__
565 if module_file[-4:] in ('.pyc', '.pyo'):
566 module_file = module_file[:-1]
567 for test in tests:
568 if not test.examples:
569 continue
570 if not test.filename:
571 test.filename = module_file
572 yield DocTestCase(test)
573
574 class IPythonDoctest(ExtensionDoctest):
575 """Nose Plugin that supports doctests in extension modules.
576 """
577 name = 'ipdoctest' # call nosetests with --with-ipdoctest
578 enabled = True
579
580 def configure(self, options, config):
581
582 Plugin.configure(self, options, config)
583 self.doctest_tests = options.doctest_tests
584 self.extension = tolist(options.doctestExtension)
585 self.parser = IPDocTestParser()
586 #self.finder = DocTestFinder(parser=IPDocTestParser())
587 self.finder = DocTestFinder(parser=self.parser)
@@ -0,0 +1,18 b''
1 #!/usr/bin/env python
2 """Nose-based test runner.
3 """
4
5 from nose.core import main
6 from nose.plugins.builtin import plugins
7 from nose.plugins.doctests import Doctest
8
9 import ipdoctest
10 from ipdoctest import IPDocTestRunner
11
12 if __name__ == '__main__':
13 print 'WARNING: this code is incomplete!'
14 print
15
16 pp = [x() for x in plugins] # activate all builtin plugins first
17 main(testRunner=IPDocTestRunner(),
18 plugins=pp+[ipdoctest.IPythonDoctest(),Doctest()])
@@ -0,0 +1,18 b''
1 #!/usr/bin/env python
2 """A Nose plugin to support IPython doctests.
3 """
4
5 from setuptools import setup
6
7 setup(name='IPython doctest plugin',
8 version='0.1',
9 author='The IPython Team',
10 description = 'Nose plugin to load IPython-extended doctests',
11 license = 'LGPL',
12 py_modules = ['ipdoctest'],
13 entry_points = {
14 'nose.plugins.0.10': ['ipdoctest = ipdoctest:IPythonDoctest',
15 'extdoctest = ipdoctest:ExtensionDoctest',
16 ],
17 },
18 )
@@ -0,0 +1,36 b''
1 =======================
2 Combo testing example
3 =======================
4
5 This is a simple example that mixes ipython doctests::
6
7 In [1]: import code
8
9 In [2]: 2**12
10 Out[2]: 4096
11
12 with command-line example information that does *not* get executed::
13
14 $ mpirun -n 4 ipengine --controller-port=10000 --controller-ip=host0
15
16 and with literal examples of Python source code::
17
18 controller = dict(host='myhost',
19 engine_port=None, # default is 10105
20 control_port=None,
21 )
22
23 # keys are hostnames, values are the number of engine on that host
24 engines = dict(node1=2,
25 node2=2,
26 node3=2,
27 node3=2,
28 )
29
30 # Force failure to detect that this test is being run.
31 1/0
32
33 These source code examples are executed but no output is compared at all. An
34 error or failure is reported only if an exception is raised.
35
36 NOTE: the execution of pure python blocks is not yet working!
@@ -0,0 +1,24 b''
1 =====================================
2 Tests in example form - pure python
3 =====================================
4
5 This file contains doctest examples embedded as code blocks, using normal
6 Python prompts. See the accompanying file for similar examples using IPython
7 prompts (you can't mix both types within one file). The following will be run
8 as a test::
9
10 >>> 1+1
11 2
12 >>> print "hello"
13 hello
14
15 More than one example works::
16
17 >>> s="Hello World"
18
19 >>> s.upper()
20 'HELLO WORLD'
21
22 but you should note that the *entire* test file is considered to be a single
23 test. Individual code blocks that fail are printed separately as ``example
24 failures``, but the whole file is still counted and reported as one test.
@@ -0,0 +1,30 b''
1 =================================
2 Tests in example form - IPython
3 =================================
4
5 You can write text files with examples that use IPython prompts (as long as you
6 use the nose ipython doctest plugin), but you can not mix and match prompt
7 styles in a single file. That is, you either use all ``>>>`` prompts or all
8 IPython-style prompts. Your test suite *can* have both types, you just need to
9 put each type of example in a separate. Using IPython prompts, you can paste
10 directly from your session::
11
12 In [5]: s="Hello World"
13
14 In [6]: s.upper()
15 Out[6]: 'HELLO WORLD'
16
17 Another example::
18
19 In [8]: 1+3
20 Out[8]: 4
21
22 Just like in IPython docstrings, you can use all IPython syntax and features::
23
24 In [9]: !echo "hello"
25 hello
26
27 In [10]: a='hi'
28
29 In [11]: !echo $a
30 hi
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
@@ -0,0 +1,23 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3
4 # A super simple example showing how to use all of this in a fully
5 # asynchronous manner. The TaskClient also works in this mode.
6
7 from twisted.internet import reactor, defer
8 from IPython.kernel import asyncclient
9
10 def printer(r):
11 print r
12 return r
13
14 def submit(client):
15 d = client.push(dict(a=5, b='asdf', c=[1,2,3]),targets=0,block=True)
16 d.addCallback(lambda _: client.pull(('a','b','c'),targets=0,block=True))
17 d.addBoth(printer)
18 d.addCallback(lambda _: reactor.stop())
19
20 d = asyncclient.get_multiengine_client()
21 d.addCallback(submit)
22
23 reactor.run() No newline at end of file
@@ -0,0 +1,32 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3
4 # This example shows how the AsynTaskClient can be used
5 # This example is currently broken
6
7 from twisted.internet import reactor, defer
8 from IPython.kernel import asyncclient
9
10 mec = asyncclient.AsyncMultiEngineClient(('localhost', 10105))
11 tc = asyncclient.AsyncTaskClient(('localhost',10113))
12
13 cmd1 = """\
14 a = 5
15 b = 10*d
16 c = a*b*d
17 """
18
19 t1 = asyncclient.Task(cmd1, clear_before=False, clear_after=True, pull=['a','b','c'])
20
21 d = mec.push(dict(d=30))
22
23 def raise_and_print(tr):
24 tr.raiseException()
25 print "a, b: ", tr.ns.a, tr.ns.b
26 return tr
27
28 d.addCallback(lambda _: tc.run(t1))
29 d.addCallback(lambda tid: tc.get_task_result(tid,block=True))
30 d.addCallback(raise_and_print)
31 d.addCallback(lambda _: reactor.stop())
32 reactor.run()
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -2728,8 +2728,7 b' Defaulting color scheme to \'NoColor\'"""'
2728 os.chdir(os.path.expanduser(ps))
2728 os.chdir(os.path.expanduser(ps))
2729 if self.shell.rc.term_title:
2729 if self.shell.rc.term_title:
2730 #print 'set term title:',self.shell.rc.term_title # dbg
2730 #print 'set term title:',self.shell.rc.term_title # dbg
2731 ttitle = 'IPy ' + abbrev_cwd()
2731 platutils.set_term_title('IPy ' + abbrev_cwd())
2732 platutils.set_term_title(ttitle)
2733 except OSError:
2732 except OSError:
2734 print sys.exc_info()[1]
2733 print sys.exc_info()[1]
2735 else:
2734 else:
@@ -3195,7 +3194,7 b' Defaulting color scheme to \'NoColor\'"""'
3195 exec b in self.user_ns
3194 exec b in self.user_ns
3196 self.user_ns['pasted_block'] = b
3195 self.user_ns['pasted_block'] = b
3197 else:
3196 else:
3198 self.user_ns[par] = block
3197 self.user_ns[par] = SList(block.splitlines())
3199 print "Block assigned to '%s'" % par
3198 print "Block assigned to '%s'" % par
3200
3199
3201 def magic_quickref(self,arg):
3200 def magic_quickref(self,arg):
@@ -22,15 +22,19 b" name = 'ipython'"
22 # because bdist_rpm does not accept dashes (an RPM) convention, and
22 # because bdist_rpm does not accept dashes (an RPM) convention, and
23 # bdist_deb does not accept underscores (a Debian convention).
23 # bdist_deb does not accept underscores (a Debian convention).
24
24
25 revision = '1016'
25 development = True # change this to False to do a release
26 version_base = '0.9.0'
26 branch = 'ipython'
27 branch = 'ipython'
28 revision = '1016'
27
29
28 if branch == 'ipython':
30 if development:
29 version = '0.9.0.bzr.r' + revision
31 if branch == 'ipython':
32 version = '%s.bzr.r%s' % (version_base, revision)
33 else:
34 version = '%s.bzr.r%s.%s' % (version_base, revision, branch)
30 else:
35 else:
31 version = '0.9.0.bzr.r%s.%s' % (revision,branch)
36 version = version_base
32
37
33 # version = '0.8.4'
34
38
35 description = "Tools for interactive development in Python."
39 description = "Tools for interactive development in Python."
36
40
@@ -53,7 +53,7 b' globsyntax = """\\'
53 - readme*, exclude files ending with .bak
53 - readme*, exclude files ending with .bak
54 !.svn/ !.hg/ !*_Data/ rec:.
54 !.svn/ !.hg/ !*_Data/ rec:.
55 - Skip .svn, .hg, foo_Data dirs (and their subdirs) in recurse.
55 - Skip .svn, .hg, foo_Data dirs (and their subdirs) in recurse.
56 Trailing / is the key, \ does not work!
56 Trailing / is the key, \ does not work! Use !.*/ for all hidden.
57 dir:foo
57 dir:foo
58 - the directory foo if it exists (not files in foo)
58 - the directory foo if it exists (not files in foo)
59 dir:*
59 dir:*
@@ -63,13 +63,16 b' globsyntax = """\\'
63 foo.py is *not* included twice.
63 foo.py is *not* included twice.
64 @filelist.txt
64 @filelist.txt
65 - All files listed in 'filelist.txt' file, on separate lines.
65 - All files listed in 'filelist.txt' file, on separate lines.
66 "cont:class \wak:" rec:*.py
67 - Match files containing regexp. Applies to subsequent files.
68 note quotes because of whitespace.
66 """
69 """
67
70
68
71
69 __version__ = "0.2"
72 __version__ = "0.2"
70
73
71
74
72 import os,glob,fnmatch,sys
75 import os,glob,fnmatch,sys,re
73 from sets import Set as set
76 from sets import Set as set
74
77
75
78
@@ -84,21 +87,34 b' def expand(flist,exp_dirs = False):'
84
87
85 """
88 """
86 if isinstance(flist, basestring):
89 if isinstance(flist, basestring):
87 flist = flist.split()
90 import shlex
91 flist = shlex.split(flist)
88 done_set = set()
92 done_set = set()
89 denied_set = set()
93 denied_set = set()
90
94 cont_set = set()
95 cur_rejected_dirs = set()
96
91 def recfind(p, pats = ["*"]):
97 def recfind(p, pats = ["*"]):
92 denied_dirs = ["*" + d+"*" for d in denied_set if d.endswith("/")]
98 denied_dirs = [os.path.dirname(d) for d in denied_set if d.endswith("/")]
93 #print "de", denied_dirs
94 for (dp,dnames,fnames) in os.walk(p):
99 for (dp,dnames,fnames) in os.walk(p):
95 # see if we should ignore the whole directory
100 # see if we should ignore the whole directory
96 dp_norm = dp.replace("\\","/") + "/"
101 dp_norm = dp.replace("\\","/") + "/"
97 deny = False
102 deny = False
103 # do not traverse under already rejected dirs
104 for d in cur_rejected_dirs:
105 if dp.startswith(d):
106 deny = True
107 break
108 if deny:
109 continue
110
111
98 #print "dp",dp
112 #print "dp",dp
113 bname = os.path.basename(dp)
99 for deny_pat in denied_dirs:
114 for deny_pat in denied_dirs:
100 if fnmatch.fnmatch( dp_norm, deny_pat):
115 if fnmatch.fnmatch( bname, deny_pat):
101 deny = True
116 deny = True
117 cur_rejected_dirs.add(dp)
102 break
118 break
103 if deny:
119 if deny:
104 continue
120 continue
@@ -124,6 +140,17 b' def expand(flist,exp_dirs = False):'
124 if fnmatch.fnmatch(os.path.basename(p), deny_pat):
140 if fnmatch.fnmatch(os.path.basename(p), deny_pat):
125 deny = True
141 deny = True
126 break
142 break
143 if cont_set:
144 try:
145 cont = open(p).read()
146 except IOError:
147 # deny
148 continue
149 for pat in cont_set:
150 if not re.search(pat,cont, re.IGNORECASE):
151 deny = True
152 break
153
127 if not deny:
154 if not deny:
128 yield it
155 yield it
129 return
156 return
@@ -158,7 +185,8 b' def expand(flist,exp_dirs = False):'
158 # glob only dirs
185 # glob only dirs
159 elif ent.lower().startswith('dir:'):
186 elif ent.lower().startswith('dir:'):
160 res.extend(once_filter(filter(os.path.isdir,glob.glob(ent[4:]))))
187 res.extend(once_filter(filter(os.path.isdir,glob.glob(ent[4:]))))
161
188 elif ent.lower().startswith('cont:'):
189 cont_set.add(ent[5:])
162 # get all files in the specified dir
190 # get all files in the specified dir
163 elif os.path.isdir(ent) and exp_dirs:
191 elif os.path.isdir(ent) and exp_dirs:
164 res.extend(once_filter(filter(os.path.isfile,glob.glob(ent + os.sep+"*"))))
192 res.extend(once_filter(filter(os.path.isfile,glob.glob(ent + os.sep+"*"))))
@@ -24,12 +24,14 b' __docformat__ = "restructuredtext en"'
24 # Imports
24 # Imports
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 import sys
27 import objc
28 import objc
28 import uuid
29 import uuid
29
30
30 from Foundation import NSObject, NSMutableArray, NSMutableDictionary,\
31 from Foundation import NSObject, NSMutableArray, NSMutableDictionary,\
31 NSLog, NSNotificationCenter, NSMakeRange,\
32 NSLog, NSNotificationCenter, NSMakeRange,\
32 NSLocalizedString, NSIntersectionRange
33 NSLocalizedString, NSIntersectionRange,\
34 NSString, NSAutoreleasePool
33
35
34 from AppKit import NSApplicationWillTerminateNotification, NSBeep,\
36 from AppKit import NSApplicationWillTerminateNotification, NSBeep,\
35 NSTextView, NSRulerView, NSVerticalRuler
37 NSTextView, NSRulerView, NSVerticalRuler
@@ -38,7 +40,7 b' from pprint import saferepr'
38
40
39 import IPython
41 import IPython
40 from IPython.kernel.engineservice import ThreadedEngineService
42 from IPython.kernel.engineservice import ThreadedEngineService
41 from IPython.frontend.frontendbase import FrontEndBase
43 from IPython.frontend.frontendbase import AsyncFrontEndBase
42
44
43 from twisted.internet.threads import blockingCallFromThread
45 from twisted.internet.threads import blockingCallFromThread
44 from twisted.python.failure import Failure
46 from twisted.python.failure import Failure
@@ -52,17 +54,57 b' from twisted.python.failure import Failure'
52 # ThreadedEngineService?
54 # ThreadedEngineService?
53 # 2. integrate Xgrid launching of engines
55 # 2. integrate Xgrid launching of engines
54
56
57 class AutoreleasePoolWrappedThreadedEngineService(ThreadedEngineService):
58 """Wrap all blocks in an NSAutoreleasePool"""
55
59
60 def wrapped_execute(self, msg, lines):
61 """wrapped_execute"""
62 try:
63 p = NSAutoreleasePool.alloc().init()
64 result = self.shell.execute(lines)
65 except Exception,e:
66 # This gives the following:
67 # et=exception class
68 # ev=exception class instance
69 # tb=traceback object
70 et,ev,tb = sys.exc_info()
71 # This call adds attributes to the exception value
72 et,ev,tb = self.shell.formatTraceback(et,ev,tb,msg)
73 # Add another attribute
74
75 # Create a new exception with the new attributes
76 e = et(ev._ipython_traceback_text)
77 e._ipython_engine_info = msg
78
79 # Re-raise
80 raise e
81 finally:
82 p.drain()
83
84 return result
85
86 def execute(self, lines):
87 # Only import this if we are going to use this class
88 from twisted.internet import threads
89
90 msg = {'engineid':self.id,
91 'method':'execute',
92 'args':[lines]}
93
94 d = threads.deferToThread(self.wrapped_execute, msg, lines)
95 d.addCallback(self.addIDToResult)
96 return d
56
97
57
98
58 class IPythonCocoaController(NSObject, FrontEndBase):
99 class IPythonCocoaController(NSObject, AsyncFrontEndBase):
59 userNS = objc.ivar() #mirror of engine.user_ns (key=>str(value))
100 userNS = objc.ivar() #mirror of engine.user_ns (key=>str(value))
60 waitingForEngine = objc.ivar().bool()
101 waitingForEngine = objc.ivar().bool()
61 textView = objc.IBOutlet()
102 textView = objc.IBOutlet()
62
103
63 def init(self):
104 def init(self):
64 self = super(IPythonCocoaController, self).init()
105 self = super(IPythonCocoaController, self).init()
65 FrontEndBase.__init__(self, engine=ThreadedEngineService())
106 AsyncFrontEndBase.__init__(self,
107 engine=AutoreleasePoolWrappedThreadedEngineService())
66 if(self != None):
108 if(self != None):
67 self._common_init()
109 self._common_init()
68
110
@@ -133,13 +175,43 b' class IPythonCocoaController(NSObject, FrontEndBase):'
133 def execute(self, block, blockID=None):
175 def execute(self, block, blockID=None):
134 self.waitingForEngine = True
176 self.waitingForEngine = True
135 self.willChangeValueForKey_('commandHistory')
177 self.willChangeValueForKey_('commandHistory')
136 d = super(IPythonCocoaController, self).execute(block, blockID)
178 d = super(IPythonCocoaController, self).execute(block,
179 blockID)
137 d.addBoth(self._engine_done)
180 d.addBoth(self._engine_done)
138 d.addCallback(self._update_user_ns)
181 d.addCallback(self._update_user_ns)
139
182
140 return d
183 return d
141
184
185
186 def push_(self, namespace):
187 """Push dictionary of key=>values to python namespace"""
142
188
189 self.waitingForEngine = True
190 self.willChangeValueForKey_('commandHistory')
191 d = self.engine.push(namespace)
192 d.addBoth(self._engine_done)
193 d.addCallback(self._update_user_ns)
194
195
196 def pull_(self, keys):
197 """Pull keys from python namespace"""
198
199 self.waitingForEngine = True
200 result = blockingCallFromThread(self.engine.pull, keys)
201 self.waitingForEngine = False
202
203 @objc.signature('v@:@I')
204 def executeFileAtPath_encoding_(self, path, encoding):
205 """Execute file at path in an empty namespace. Update the engine
206 user_ns with the resulting locals."""
207
208 lines,err = NSString.stringWithContentsOfFile_encoding_error_(
209 path,
210 encoding,
211 None)
212 self.engine.execute(lines)
213
214
143 def _engine_done(self, x):
215 def _engine_done(self, x):
144 self.waitingForEngine = False
216 self.waitingForEngine = False
145 self.didChangeValueForKey_('commandHistory')
217 self.didChangeValueForKey_('commandHistory')
@@ -166,14 +238,14 b' class IPythonCocoaController(NSObject, FrontEndBase):'
166 self.didChangeValueForKey_('userNS')
238 self.didChangeValueForKey_('userNS')
167
239
168
240
169 def update_cell_prompt(self, result):
241 def update_cell_prompt(self, result, blockID=None):
170 if(isinstance(result, Failure)):
242 if(isinstance(result, Failure)):
171 blockID = result.blockID
243 self.insert_text(self.input_prompt(),
244 textRange=NSMakeRange(self.blockRanges[blockID].location,0),
245 scrollToVisible=False
246 )
172 else:
247 else:
173 blockID = result['blockID']
248 self.insert_text(self.input_prompt(number=result['number']),
174
175
176 self.insert_text(self.input_prompt(result=result),
177 textRange=NSMakeRange(self.blockRanges[blockID].location,0),
249 textRange=NSMakeRange(self.blockRanges[blockID].location,0),
178 scrollToVisible=False
250 scrollToVisible=False
179 )
251 )
@@ -188,7 +260,7 b' class IPythonCocoaController(NSObject, FrontEndBase):'
188
260
189 #print inputRange,self.current_block_range()
261 #print inputRange,self.current_block_range()
190 self.insert_text('\n' +
262 self.insert_text('\n' +
191 self.output_prompt(result) +
263 self.output_prompt(number=result['number']) +
192 result.get('display',{}).get('pprint','') +
264 result.get('display',{}).get('pprint','') +
193 '\n\n',
265 '\n\n',
194 textRange=NSMakeRange(inputRange.location+inputRange.length,
266 textRange=NSMakeRange(inputRange.location+inputRange.length,
@@ -197,7 +269,11 b' class IPythonCocoaController(NSObject, FrontEndBase):'
197
269
198
270
199 def render_error(self, failure):
271 def render_error(self, failure):
200 self.insert_text('\n\n'+str(failure)+'\n\n')
272 self.insert_text('\n' +
273 self.output_prompt() +
274 '\n' +
275 failure.getErrorMessage() +
276 '\n\n')
201 self.start_new_block()
277 self.start_new_block()
202 return failure
278 return failure
203
279
@@ -288,9 +364,13 b' class IPythonCocoaController(NSObject, FrontEndBase):'
288 def current_indent_string(self):
364 def current_indent_string(self):
289 """returns string for indent or None if no indent"""
365 """returns string for indent or None if no indent"""
290
366
291 if(len(self.current_block()) > 0):
367 return self._indent_for_block(self.current_block())
292 lines = self.current_block().split('\n')
368
293 currentIndent = len(lines[-1]) - len(lines[-1])
369
370 def _indent_for_block(self, block):
371 lines = block.split('\n')
372 if(len(lines) > 1):
373 currentIndent = len(lines[-1]) - len(lines[-1].lstrip())
294 if(currentIndent == 0):
374 if(currentIndent == 0):
295 currentIndent = self.tabSpaces
375 currentIndent = self.tabSpaces
296
376
@@ -70,3 +70,22 b' class TestIPythonCocoaControler(DeferredTestCase):'
70
70
71 self.controller.execute(code).addCallback(testCompletes)
71 self.controller.execute(code).addCallback(testCompletes)
72
72
73
74 def testCurrentIndent(self):
75 """test that current_indent_string returns current indent or None.
76 Uses _indent_for_block for direct unit testing.
77 """
78
79 self.controller.tabUsesSpaces = True
80 self.assert_(self.controller._indent_for_block("""a=3""") == None)
81 self.assert_(self.controller._indent_for_block("") == None)
82 block = """def test():\n a=3"""
83 self.assert_(self.controller._indent_for_block(block) == \
84 ' ' * self.controller.tabSpaces)
85
86 block = """if(True):\n%sif(False):\n%spass""" % \
87 (' '*self.controller.tabSpaces,
88 2*' '*self.controller.tabSpaces)
89 self.assert_(self.controller._indent_for_block(block) == \
90 2*(' '*self.controller.tabSpaces))
91
@@ -24,13 +24,24 b' import string'
24 import uuid
24 import uuid
25 import _ast
25 import _ast
26
26
27 import zope.interface as zi
27 try:
28 from zope.interface import Interface, Attribute, implements, classProvides
29 except ImportError:
30 #zope.interface is not available
31 Interface = object
32 def Attribute(name, doc): pass
33 def implements(interface): pass
34 def classProvides(interface): pass
28
35
29 from IPython.kernel.core.history import FrontEndHistory
36 from IPython.kernel.core.history import FrontEndHistory
30 from IPython.kernel.core.util import Bunch
37 from IPython.kernel.core.util import Bunch
31 from IPython.kernel.engineservice import IEngineCore
38 from IPython.kernel.engineservice import IEngineCore
32
39
33 from twisted.python.failure import Failure
40 try:
41 from twisted.python.failure import Failure
42 except ImportError:
43 #Twisted not available
44 Failure = Exception
34
45
35 ##############################################################################
46 ##############################################################################
36 # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
47 # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
@@ -43,7 +54,7 b" rc.prompt_out = r'Out [$number]: '"
43
54
44 ##############################################################################
55 ##############################################################################
45
56
46 class IFrontEndFactory(zi.Interface):
57 class IFrontEndFactory(Interface):
47 """Factory interface for frontends."""
58 """Factory interface for frontends."""
48
59
49 def __call__(engine=None, history=None):
60 def __call__(engine=None, history=None):
@@ -56,33 +67,30 b' class IFrontEndFactory(zi.Interface):'
56
67
57
68
58
69
59 class IFrontEnd(zi.Interface):
70 class IFrontEnd(Interface):
60 """Interface for frontends. All methods return t.i.d.Deferred"""
71 """Interface for frontends. All methods return t.i.d.Deferred"""
61
72
62 zi.Attribute("input_prompt_template", "string.Template instance\
73 Attribute("input_prompt_template", "string.Template instance\
63 substituteable with execute result.")
74 substituteable with execute result.")
64 zi.Attribute("output_prompt_template", "string.Template instance\
75 Attribute("output_prompt_template", "string.Template instance\
65 substituteable with execute result.")
76 substituteable with execute result.")
66 zi.Attribute("continuation_prompt_template", "string.Template instance\
77 Attribute("continuation_prompt_template", "string.Template instance\
67 substituteable with execute result.")
78 substituteable with execute result.")
68
79
69 def update_cell_prompt(self, result):
80 def update_cell_prompt(result, blockID=None):
70 """Subclass may override to update the input prompt for a block.
81 """Subclass may override to update the input prompt for a block.
71 Since this method will be called as a
82 Since this method will be called as a
72 twisted.internet.defer.Deferred's callback,
83 twisted.internet.defer.Deferred's callback/errback,
73 implementations should return result when finished.
84 implementations should return result when finished.
74
85
75 NB: result is a failure if the execute returned a failre.
86 Result is a result dict in case of success, and a
76 To get the blockID, you should do something like::
87 twisted.python.util.failure.Failure in case of an error
77 if(isinstance(result, twisted.python.failure.Failure)):
78 blockID = result.blockID
79 else:
80 blockID = result['blockID']
81 """
88 """
82
89
83 pass
90 pass
84
91
85 def render_result(self, result):
92
93 def render_result(result):
86 """Render the result of an execute call. Implementors may choose the
94 """Render the result of an execute call. Implementors may choose the
87 method of rendering.
95 method of rendering.
88 For example, a notebook-style frontend might render a Chaco plot
96 For example, a notebook-style frontend might render a Chaco plot
@@ -90,6 +98,7 b' class IFrontEnd(zi.Interface):'
90
98
91 Parameters:
99 Parameters:
92 result : dict (result of IEngineBase.execute )
100 result : dict (result of IEngineBase.execute )
101 blockID = result['blockID']
93
102
94 Result:
103 Result:
95 Output of frontend rendering
104 Output of frontend rendering
@@ -97,22 +106,24 b' class IFrontEnd(zi.Interface):'
97
106
98 pass
107 pass
99
108
100 def render_error(self, failure):
109 def render_error(failure):
101 """Subclasses must override to render the failure. Since this method
110 """Subclasses must override to render the failure. Since this method
102 ill be called as a twisted.internet.defer.Deferred's callback,
111 will be called as a twisted.internet.defer.Deferred's callback,
103 implementations should return result when finished.
112 implementations should return result when finished.
113
114 blockID = failure.blockID
104 """
115 """
105
116
106 pass
117 pass
107
118
108
119
109 def input_prompt(result={}):
120 def input_prompt(number=''):
110 """Returns the input prompt by subsituting into
121 """Returns the input prompt by subsituting into
111 self.input_prompt_template
122 self.input_prompt_template
112 """
123 """
113 pass
124 pass
114
125
115 def output_prompt(result):
126 def output_prompt(number=''):
116 """Returns the output prompt by subsituting into
127 """Returns the output prompt by subsituting into
117 self.output_prompt_template
128 self.output_prompt_template
118 """
129 """
@@ -159,9 +170,6 b' class FrontEndBase(object):'
159 - How do we handle completions?
170 - How do we handle completions?
160 """
171 """
161
172
162 zi.implements(IFrontEnd)
163 zi.classProvides(IFrontEndFactory)
164
165 history_cursor = 0
173 history_cursor = 0
166
174
167 current_indent_level = 0
175 current_indent_level = 0
@@ -171,24 +179,20 b' class FrontEndBase(object):'
171 output_prompt_template = string.Template(rc.prompt_out)
179 output_prompt_template = string.Template(rc.prompt_out)
172 continuation_prompt_template = string.Template(rc.prompt_in2)
180 continuation_prompt_template = string.Template(rc.prompt_in2)
173
181
174 def __init__(self, engine=None, history=None):
182 def __init__(self, shell=None, history=None):
175 assert(engine==None or IEngineCore.providedBy(engine))
183 self.shell = shell
176 self.engine = IEngineCore(engine)
177 if history is None:
184 if history is None:
178 self.history = FrontEndHistory(input_cache=[''])
185 self.history = FrontEndHistory(input_cache=[''])
179 else:
186 else:
180 self.history = history
187 self.history = history
181
188
182
189
183 def input_prompt(self, result={}):
190 def input_prompt(self, number=''):
184 """Returns the current input prompt
191 """Returns the current input prompt
185
192
186 It would be great to use ipython1.core.prompts.Prompt1 here
193 It would be great to use ipython1.core.prompts.Prompt1 here
187 """
194 """
188
195 return self.input_prompt_template.safe_substitute({'number':number})
189 result.setdefault('number','')
190
191 return self.input_prompt_template.safe_substitute(result)
192
196
193
197
194 def continuation_prompt(self):
198 def continuation_prompt(self):
@@ -196,10 +200,10 b' class FrontEndBase(object):'
196
200
197 return self.continuation_prompt_template.safe_substitute()
201 return self.continuation_prompt_template.safe_substitute()
198
202
199 def output_prompt(self, result):
203 def output_prompt(self, number=''):
200 """Returns the output prompt for result"""
204 """Returns the output prompt for result"""
201
205
202 return self.output_prompt_template.safe_substitute(result)
206 return self.output_prompt_template.safe_substitute({'number':number})
203
207
204
208
205 def is_complete(self, block):
209 def is_complete(self, block):
@@ -239,7 +243,7 b' class FrontEndBase(object):'
239
243
240
244
241 def execute(self, block, blockID=None):
245 def execute(self, block, blockID=None):
242 """Execute the block and return result.
246 """Execute the block and return the result.
243
247
244 Parameters:
248 Parameters:
245 block : {str, AST}
249 block : {str, AST}
@@ -252,32 +256,41 b' class FrontEndBase(object):'
252 """
256 """
253
257
254 if(not self.is_complete(block)):
258 if(not self.is_complete(block)):
255 return Failure(Exception("Block is not compilable"))
259 raise Exception("Block is not compilable")
256
260
257 if(blockID == None):
261 if(blockID == None):
258 blockID = uuid.uuid4() #random UUID
262 blockID = uuid.uuid4() #random UUID
259
263
260 d = self.engine.execute(block)
264 try:
261 d.addCallback(self._add_history, block=block)
265 result = self.shell.execute(block)
262 d.addBoth(self._add_block_id, blockID)
266 except Exception,e:
263 d.addBoth(self.update_cell_prompt)
267 e = self._add_block_id_for_failure(e, blockID=blockID)
264 d.addCallbacks(self.render_result, errback=self.render_error)
268 e = self.update_cell_prompt(e, blockID=blockID)
269 e = self.render_error(e)
270 else:
271 result = self._add_block_id_for_result(result, blockID=blockID)
272 result = self.update_cell_prompt(result, blockID=blockID)
273 result = self.render_result(result)
265
274
266 return d
275 return result
267
276
268
277
269 def _add_block_id(self, result, blockID):
278 def _add_block_id_for_result(self, result, blockID):
270 """Add the blockID to result or failure. Unfortunatley, we have to
279 """Add the blockID to result or failure. Unfortunatley, we have to
271 treat failures differently than result dicts.
280 treat failures differently than result dicts.
272 """
281 """
273
282
274 if(isinstance(result, Failure)):
283 result['blockID'] = blockID
275 result.blockID = blockID
276 else:
277 result['blockID'] = blockID
278
284
279 return result
285 return result
280
286
287 def _add_block_id_for_failure(self, failure, blockID):
288 """_add_block_id_for_failure"""
289
290 failure.blockID = blockID
291 return failure
292
293
281 def _add_history(self, result, block=None):
294 def _add_history(self, result, block=None):
282 """Add block to the history"""
295 """Add block to the history"""
283
296
@@ -313,20 +326,11 b' class FrontEndBase(object):'
313 # Subclasses probably want to override these methods...
326 # Subclasses probably want to override these methods...
314 ###
327 ###
315
328
316 def update_cell_prompt(self, result):
329 def update_cell_prompt(self, result, blockID=None):
317 """Subclass may override to update the input prompt for a block.
330 """Subclass may override to update the input prompt for a block.
318 Since this method will be called as a
331 Since this method will be called as a
319 twisted.internet.defer.Deferred's callback, implementations should
332 twisted.internet.defer.Deferred's callback, implementations should
320 return result when finished.
333 return result when finished.
321
322 NB: result is a failure if the execute returned a failre.
323 To get the blockID, you should do something like::
324 if(isinstance(result, twisted.python.failure.Failure)):
325 blockID = result.blockID
326 else:
327 blockID = result['blockID']
328
329
330 """
334 """
331
335
332 return result
336 return result
@@ -344,9 +348,60 b' class FrontEndBase(object):'
344 def render_error(self, failure):
348 def render_error(self, failure):
345 """Subclasses must override to render the failure. Since this method
349 """Subclasses must override to render the failure. Since this method
346 will be called as a twisted.internet.defer.Deferred's callback,
350 will be called as a twisted.internet.defer.Deferred's callback,
347 implementations should return result when finished."""
351 implementations should return result when finished.
352 """
348
353
349 return failure
354 return failure
350
355
351
356
352
357
358 class AsyncFrontEndBase(FrontEndBase):
359 """
360 Overrides FrontEndBase to wrap execute in a deferred result.
361 All callbacks are made as callbacks on the deferred result.
362 """
363
364 implements(IFrontEnd)
365 classProvides(IFrontEndFactory)
366
367 def __init__(self, engine=None, history=None):
368 assert(engine==None or IEngineCore.providedBy(engine))
369 self.engine = IEngineCore(engine)
370 if history is None:
371 self.history = FrontEndHistory(input_cache=[''])
372 else:
373 self.history = history
374
375
376 def execute(self, block, blockID=None):
377 """Execute the block and return the deferred result.
378
379 Parameters:
380 block : {str, AST}
381 blockID : any
382 Caller may provide an ID to identify this block.
383 result['blockID'] := blockID
384
385 Result:
386 Deferred result of self.interpreter.execute
387 """
388
389 if(not self.is_complete(block)):
390 return Failure(Exception("Block is not compilable"))
391
392 if(blockID == None):
393 blockID = uuid.uuid4() #random UUID
394
395 d = self.engine.execute(block)
396 d.addCallback(self._add_history, block=block)
397 d.addCallbacks(self._add_block_id_for_result,
398 errback=self._add_block_id_for_failure,
399 callbackArgs=(blockID,),
400 errbackArgs=(blockID,))
401 d.addBoth(self.update_cell_prompt, blockID=blockID)
402 d.addCallbacks(self.render_result,
403 errback=self.render_error)
404
405 return d
406
407
@@ -19,7 +19,7 b' import unittest'
19 from IPython.frontend import frontendbase
19 from IPython.frontend import frontendbase
20 from IPython.kernel.engineservice import EngineService
20 from IPython.kernel.engineservice import EngineService
21
21
22 class FrontEndCallbackChecker(frontendbase.FrontEndBase):
22 class FrontEndCallbackChecker(frontendbase.AsyncFrontEndBase):
23 """FrontEndBase subclass for checking callbacks"""
23 """FrontEndBase subclass for checking callbacks"""
24 def __init__(self, engine=None, history=None):
24 def __init__(self, engine=None, history=None):
25 super(FrontEndCallbackChecker, self).__init__(engine=engine,
25 super(FrontEndCallbackChecker, self).__init__(engine=engine,
@@ -28,7 +28,7 b' class FrontEndCallbackChecker(frontendbase.FrontEndBase):'
28 self.renderResultCalled = False
28 self.renderResultCalled = False
29 self.renderErrorCalled = False
29 self.renderErrorCalled = False
30
30
31 def update_cell_prompt(self, result):
31 def update_cell_prompt(self, result, blockID=None):
32 self.updateCalled = True
32 self.updateCalled = True
33 return result
33 return result
34
34
@@ -44,7 +44,7 b' class FrontEndCallbackChecker(frontendbase.FrontEndBase):'
44
44
45
45
46
46
47 class TestFrontendBase(unittest.TestCase):
47 class TestAsyncFrontendBase(unittest.TestCase):
48 def setUp(self):
48 def setUp(self):
49 """Setup the EngineService and FrontEndBase"""
49 """Setup the EngineService and FrontEndBase"""
50
50
@@ -53,7 +53,7 b' class TestFrontendBase(unittest.TestCase):'
53
53
54 def test_implements_IFrontEnd(self):
54 def test_implements_IFrontEnd(self):
55 assert(frontendbase.IFrontEnd.implementedBy(
55 assert(frontendbase.IFrontEnd.implementedBy(
56 frontendbase.FrontEndBase))
56 frontendbase.AsyncFrontEndBase))
57
57
58
58
59 def test_is_complete_returns_False_for_incomplete_block(self):
59 def test_is_complete_returns_False_for_incomplete_block(self):
@@ -1137,14 +1137,41 b' class SList(list):'
1137 res.append(" ".join(lineparts))
1137 res.append(" ".join(lineparts))
1138
1138
1139 return res
1139 return res
1140
1140 def sort(self,field= None, nums = False):
1141
1141 """ sort by specified fields (see fields())
1142
1142
1143 Example::
1144 a.sort(1, nums = True)
1145
1146 Sorts a by second field, in numerical order (so that 21 > 3)
1147
1148 """
1143
1149
1150 #decorate, sort, undecorate
1151 if field is not None:
1152 dsu = [[SList([line]).fields(field), line] for line in self]
1153 else:
1154 dsu = [[line, line] for line in self]
1155 if nums:
1156 for i in range(len(dsu)):
1157 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
1158 try:
1159 n = int(numstr)
1160 except ValueError:
1161 n = 0;
1162 dsu[i][0] = n
1163
1164
1165 dsu.sort()
1166 return SList([t[1] for t in dsu])
1144
1167
1145 def print_slist(arg):
1168 def print_slist(arg):
1146 """ Prettier (non-repr-like) and more informative printer for SList """
1169 """ Prettier (non-repr-like) and more informative printer for SList """
1147 print "SList (.p, .n, .l, .s, .grep(), .fields() available). Value:"
1170 print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
1171 if hasattr(arg, 'hideonce') and arg.hideonce:
1172 arg.hideonce = False
1173 return
1174
1148 nlprint(arg)
1175 nlprint(arg)
1149
1176
1150 print_slist = result_display.when_type(SList)(print_slist)
1177 print_slist = result_display.when_type(SList)(print_slist)
@@ -168,8 +168,7 b' def startMsg(control_host,control_port=10105):'
168 print 'For interactive use, you can make a MultiEngineClient with:'
168 print 'For interactive use, you can make a MultiEngineClient with:'
169 print
169 print
170 print 'from IPython.kernel import client'
170 print 'from IPython.kernel import client'
171 print "mec = client.MultiEngineClient((%r,%s))" % \
171 print "mec = client.MultiEngineClient()"
172 (control_host,control_port)
173 print
172 print
174 print 'You can then cleanly stop the cluster from IPython using:'
173 print 'You can then cleanly stop the cluster from IPython using:'
175 print
174 print
@@ -191,16 +190,18 b' def clusterLocal(opt,arg):'
191 logfile = pjoin(logdir_base,'ipcluster-')
190 logfile = pjoin(logdir_base,'ipcluster-')
192
191
193 print 'Starting controller:',
192 print 'Starting controller:',
194 controller = Popen(['ipcontroller','--logfile',logfile])
193 controller = Popen(['ipcontroller','--logfile',logfile,'-x','-y'])
195 print 'Controller PID:',controller.pid
194 print 'Controller PID:',controller.pid
196
195
197 print 'Starting engines: ',
196 print 'Starting engines: ',
198 time.sleep(3)
197 time.sleep(5)
199
198
200 englogfile = '%s%s-' % (logfile,controller.pid)
199 englogfile = '%s%s-' % (logfile,controller.pid)
201 mpi = opt.mpi
200 mpi = opt.mpi
202 if mpi: # start with mpi - killing the engines with sigterm will not work if you do this
201 if mpi: # start with mpi - killing the engines with sigterm will not work if you do this
203 engines = [Popen(['mpirun', '-np', str(opt.n), 'ipengine', '--mpi', mpi, '--logfile',englogfile])]
202 engines = [Popen(['mpirun', '-np', str(opt.n), 'ipengine', '--mpi',
203 mpi, '--logfile',englogfile])]
204 # engines = [Popen(['mpirun', '-np', str(opt.n), 'ipengine', '--mpi', mpi])]
204 else: # do what we would normally do
205 else: # do what we would normally do
205 engines = [ Popen(['ipengine','--logfile',englogfile])
206 engines = [ Popen(['ipengine','--logfile',englogfile])
206 for i in range(opt.n) ]
207 for i in range(opt.n) ]
@@ -58,12 +58,14 b' def start_engine():'
58 kernel_config = kernel_config_manager.get_config_obj()
58 kernel_config = kernel_config_manager.get_config_obj()
59 core_config = core_config_manager.get_config_obj()
59 core_config = core_config_manager.get_config_obj()
60
60
61
61 # Execute the mpi import statement that needs to call MPI_Init
62 # Execute the mpi import statement that needs to call MPI_Init
63 global mpi
62 mpikey = kernel_config['mpi']['default']
64 mpikey = kernel_config['mpi']['default']
63 mpi_import_statement = kernel_config['mpi'].get(mpikey, None)
65 mpi_import_statement = kernel_config['mpi'].get(mpikey, None)
64 if mpi_import_statement is not None:
66 if mpi_import_statement is not None:
65 try:
67 try:
66 exec mpi_import_statement in locals(), globals()
68 exec mpi_import_statement in globals()
67 except:
69 except:
68 mpi = None
70 mpi = None
69 else:
71 else:
@@ -3,13 +3,8 b''
3
3
4 Importing this module should give you the implementations that are correct
4 Importing this module should give you the implementations that are correct
5 for your operation system, from platutils_PLATFORMNAME module.
5 for your operation system, from platutils_PLATFORMNAME module.
6
7 $Id: ipstruct.py 1005 2006-01-12 08:39:26Z fperez $
8
9
10 """
6 """
11
7
12
13 #*****************************************************************************
8 #*****************************************************************************
14 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
15 #
10 #
@@ -21,15 +16,32 b' from IPython import Release'
21 __author__ = '%s <%s>' % Release.authors['Ville']
16 __author__ = '%s <%s>' % Release.authors['Ville']
22 __license__ = Release.license
17 __license__ = Release.license
23
18
24 import os,sys
19 import os
20 import sys
25
21
22 # Import the platform-specific implementations
26 if os.name == 'posix':
23 if os.name == 'posix':
27 from platutils_posix import *
24 import platutils_posix as _platutils
28 elif sys.platform == 'win32':
25 elif sys.platform == 'win32':
29 from platutils_win32 import *
26 import platutils_win32 as _platutils
30 else:
27 else:
31 from platutils_dummy import *
28 import platutils_dummy as _platutils
32 import warnings
29 import warnings
33 warnings.warn("Platutils not available for platform '%s', some features may be missing" %
30 warnings.warn("Platutils not available for platform '%s', some features may be missing" %
34 os.name)
31 os.name)
35 del warnings
32 del warnings
33
34
35 # Functionality that's logically common to all platforms goes here, each
36 # platform-specific module only provides the bits that are OS-dependent.
37
38 def freeze_term_title():
39 _platutils.ignore_termtitle = True
40
41
42 def set_term_title(title):
43 """Set terminal title using the necessary platform-dependent calls."""
44
45 if _platutils.ignore_termtitle:
46 return
47 _platutils.set_term_title(title)
@@ -3,13 +3,8 b''
3
3
4 This has empty implementation of the platutils functions, used for
4 This has empty implementation of the platutils functions, used for
5 unsupported operating systems.
5 unsupported operating systems.
6
7 $Id: ipstruct.py 1005 2006-01-12 08:39:26Z fperez $
8
9
10 """
6 """
11
7
12
13 #*****************************************************************************
8 #*****************************************************************************
14 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
15 #
10 #
@@ -21,9 +16,9 b' from IPython import Release'
21 __author__ = '%s <%s>' % Release.authors['Ville']
16 __author__ = '%s <%s>' % Release.authors['Ville']
22 __license__ = Release.license
17 __license__ = Release.license
23
18
19 # This variable is part of the expected API of the module:
20 ignore_termtitle = True
24
21
25 def _dummy(*args,**kw):
22 def set_term_title(*args,**kw):
23 """Dummy no-op."""
26 pass
24 pass
27
28 set_term_title = _dummy
29
@@ -3,12 +3,8 b''
3
3
4 Importing this module directly is not portable - rather, import platutils
4 Importing this module directly is not portable - rather, import platutils
5 to use these functions in platform agnostic fashion.
5 to use these functions in platform agnostic fashion.
6
7 $Id: ipstruct.py 1005 2006-01-12 08:39:26Z fperez $
8
9 """
6 """
10
7
11
12 #*****************************************************************************
8 #*****************************************************************************
13 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
14 #
10 #
@@ -31,9 +27,6 b' def _dummy_op(*a, **b):'
31 def _set_term_title_xterm(title):
27 def _set_term_title_xterm(title):
32 """ Change virtual terminal title in xterm-workalikes """
28 """ Change virtual terminal title in xterm-workalikes """
33
29
34 if ignore_termtitle:
35 return
36
37 sys.stdout.write('\033]%d;%s\007' % (0,title))
30 sys.stdout.write('\033]%d;%s\007' % (0,title))
38
31
39
32
@@ -41,7 +34,3 b" if os.environ.get('TERM','') == 'xterm':"
41 set_term_title = _set_term_title_xterm
34 set_term_title = _set_term_title_xterm
42 else:
35 else:
43 set_term_title = _dummy_op
36 set_term_title = _dummy_op
44
45 def freeze_term_title():
46 global ignore_termtitle
47 ignore_termtitle = True
@@ -3,12 +3,8 b''
3
3
4 Importing this module directly is not portable - rather, import platutils
4 Importing this module directly is not portable - rather, import platutils
5 to use these functions in platform agnostic fashion.
5 to use these functions in platform agnostic fashion.
6
7 $Id: ipstruct.py 1005 2006-01-12 08:39:26Z fperez $
8
9 """
6 """
10
7
11
12 #*****************************************************************************
8 #*****************************************************************************
13 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
14 #
10 #
@@ -22,35 +18,30 b' __license__ = Release.license'
22
18
23 import os
19 import os
24
20
25 ignore_termtitle = 0
21 ignore_termtitle = False
26
22
27 try:
23 try:
28 import ctypes
24 import ctypes
29 SetConsoleTitleW=ctypes.windll.kernel32.SetConsoleTitleW
25
30 SetConsoleTitleW.argtypes=[ctypes.c_wchar_p]
26 SetConsoleTitleW = ctypes.windll.kernel32.SetConsoleTitleW
31 def _set_term_title(title):
27 SetConsoleTitleW.argtypes = [ctypes.c_wchar_p]
32 """ Set terminal title using the ctypes"""
28
29 def set_term_title(title):
30 """Set terminal title using ctypes to access the Win32 APIs."""
33 SetConsoleTitleW(title)
31 SetConsoleTitleW(title)
34
32
35 except ImportError:
33 except ImportError:
36 def _set_term_title(title):
34 def set_term_title(title):
37 """ Set terminal title using the 'title' command """
35 """Set terminal title using the 'title' command."""
38 curr=os.getcwd()
36 global ignore_termtitle
39 os.chdir("C:") #Cannot be on network share when issuing system commands
37
40 ret = os.system("title " + title)
38 try:
41 os.chdir(curr)
39 # Cannot be on network share when issuing system commands
40 curr = os.getcwd()
41 os.chdir("C:")
42 ret = os.system("title " + title)
43 finally:
44 os.chdir(curr)
42 if ret:
45 if ret:
43 ignore_termtitle = 1
46 # non-zero return code signals error, don't try again
44
47 ignore_termtitle = True
45 def set_term_title(title):
46 """ Set terminal title using the 'title' command """
47 global ignore_termtitle
48
49 if ignore_termtitle:
50 return
51 _set_term_title(title)
52
53 def freeze_term_title():
54 global ignore_termtitle
55 ignore_termtitle = 1
56
1 NO CONTENT: file renamed from IPython/testing/ipdoctest.py to IPython/testing/attic/ipdoctest.py
NO CONTENT: file renamed from IPython/testing/ipdoctest.py to IPython/testing/attic/ipdoctest.py
1 NO CONTENT: file renamed from IPython/testing/parametric.py to IPython/testing/attic/parametric.py
NO CONTENT: file renamed from IPython/testing/parametric.py to IPython/testing/attic/parametric.py
1 NO CONTENT: file renamed from IPython/testing/tcommon.py to IPython/testing/attic/tcommon.py
NO CONTENT: file renamed from IPython/testing/tcommon.py to IPython/testing/attic/tcommon.py
1 NO CONTENT: file renamed from IPython/testing/testTEMPLATE.py to IPython/testing/attic/testTEMPLATE.py
NO CONTENT: file renamed from IPython/testing/testTEMPLATE.py to IPython/testing/attic/testTEMPLATE.py
1 NO CONTENT: file renamed from IPython/testing/tstTEMPLATE_doctest.py to IPython/testing/attic/tstTEMPLATE_doctest.py
NO CONTENT: file renamed from IPython/testing/tstTEMPLATE_doctest.py to IPython/testing/attic/tstTEMPLATE_doctest.py
1 NO CONTENT: file renamed from IPython/testing/tstTEMPLATE_doctest.txt to IPython/testing/attic/tstTEMPLATE_doctest.txt
NO CONTENT: file renamed from IPython/testing/tstTEMPLATE_doctest.txt to IPython/testing/attic/tstTEMPLATE_doctest.txt
@@ -1,6 +1,20 b''
1 """Utilities for testing code.
1 """DEPRECATED - use IPython.testing.util instead.
2
3 Utilities for testing code.
2 """
4 """
3
5
6 #############################################################################
7
8 # This was old testing code we never really used in IPython. The pieces of
9 # testing machinery from snakeoil that were good have already been merged into
10 # the nose plugin, so this can be taken away soon. Leave a warning for now,
11 # we'll remove it in a later release (around 0.10 or so).
12 from warnings import warn
13 warn('This will be removed soon. Use IPython.testing.util instead',
14 DeprecationWarning)
15
16 #############################################################################
17
4 # Required modules and packages
18 # Required modules and packages
5
19
6 # Standard Python lib
20 # Standard Python lib
@@ -36,7 +50,7 b' def test_path(path):'
36
50
37 This finds the correct path of the test package on disk, and prepends it
51 This finds the correct path of the test package on disk, and prepends it
38 to the input path."""
52 to the input path."""
39
53
40 return os.path.join(TEST_PATH,path)
54 return os.path.join(TEST_PATH,path)
41
55
42 def fullPath(startPath,files):
56 def fullPath(startPath,files):
@@ -55,7 +69,7 b' def fullPath(startPath,files):'
55 One or more files.
69 One or more files.
56
70
57 :Examples:
71 :Examples:
58
72
59 >>> fullPath('/foo/bar.py',['a.txt','b.txt'])
73 >>> fullPath('/foo/bar.py',['a.txt','b.txt'])
60 ['/foo/a.txt', '/foo/b.txt']
74 ['/foo/a.txt', '/foo/b.txt']
61
75
@@ -66,7 +80,7 b' def fullPath(startPath,files):'
66 >>> fullPath('/foo','a.txt')
80 >>> fullPath('/foo','a.txt')
67 ['/a.txt']
81 ['/a.txt']
68 """
82 """
69
83
70 files = utils.list_strings(files)
84 files = utils.list_strings(files)
71 base = os.path.split(startPath)[0]
85 base = os.path.split(startPath)[0]
72 return [ os.path.join(base,f) for f in files ]
86 return [ os.path.join(base,f) for f in files ]
@@ -3,40 +3,15 b''
3 =========================================
3 =========================================
4
4
5 The way doctest loads these, the entire document is applied as a single test
5 The way doctest loads these, the entire document is applied as a single test
6 rather than multiple individual ones, unfortunately.
6 rather than multiple individual ones, unfortunately::
7
7
8
9 Auto-generated tests
10 ====================
11
12
13 ----------------------------------------------------------------------------
14
15 Begin included file tst_tools_utils_doctest2.py::
16
17 # Setup - all imports are done in tcommon
18 >>> from IPython.testing import tcommon
19 >>> from IPython.testing.tcommon import *
20
21 # Doctest code begins here
22 >>> from IPython.tools import utils
8 >>> from IPython.tools import utils
23
9
24 # Some other tests for utils
10 # Some other tests for utils
25
11
26 >>> utils.marquee('Testing marquee')
12 >>> utils.marquee('Testing marquee')
27 '****************************** Testing marquee ******************************'
13 '****************************** Testing marquee ******************************'
28
14
29 >>> utils.marquee('Another test',30,'.')
15 >>> utils.marquee('Another test',30,'.')
30 '........ Another test ........'
16 '........ Another test ........'
31
32
33 End included file tst_tools_utils_doctest2.py
34
35 ----------------------------------------------------------------------------
36
37
38
39 Manually generated tests
40 ========================
41
17
42 These are one-off tests written by hand, copied from an interactive prompt.
@@ -16,7 +16,6 b' graft IPython/tools'
16 graft docs
16 graft docs
17 exclude docs/\#*
17 exclude docs/\#*
18 exclude docs/man/*.1
18 exclude docs/man/*.1
19 exclude docs/ChangeLog.*
20
19
21 # There seems to be no way of excluding whole subdirectories, other than
20 # There seems to be no way of excluding whole subdirectories, other than
22 # manually excluding all their subdirs. distutils really is horrible...
21 # manually excluding all their subdirs. distutils really is horrible...
@@ -9,7 +9,7 b''
9 (defconst ipython-version "$Revision: 2927 $"
9 (defconst ipython-version "$Revision: 2927 $"
10 "VC version number.")
10 "VC version number.")
11
11
12 ;;; Commentary
12 ;;; Commentary
13 ;; This library makes all the functionality python-mode has when running with
13 ;; This library makes all the functionality python-mode has when running with
14 ;; the normal python-interpreter available for ipython, too. It also enables a
14 ;; the normal python-interpreter available for ipython, too. It also enables a
15 ;; persistent py-shell command history across sessions (if you exit python
15 ;; persistent py-shell command history across sessions (if you exit python
@@ -31,13 +31,20 b''
31 ;; To start an interactive ipython session run `py-shell' with ``M-x py-shell``
31 ;; To start an interactive ipython session run `py-shell' with ``M-x py-shell``
32 ;; (or the default keybinding ``C-c C-!``).
32 ;; (or the default keybinding ``C-c C-!``).
33 ;;
33 ;;
34 ;; You can customize the arguments passed to the IPython instance at startup by
35 ;; setting the ``py-python-command-args`` variable. For example, to start
36 ;; always in ``pylab`` mode with hardcoded light-background colors, you can
37 ;; use::
38 ;;
39 ;; (setq py-python-command-args '("-pylab" "-colors" "LightBG"))
40 ;;
41 ;;
34 ;; NOTE: This mode is currently somewhat alpha and although I hope that it
42 ;; NOTE: This mode is currently somewhat alpha and although I hope that it
35 ;; will work fine for most cases, doing certain things (like the
43 ;; will work fine for most cases, doing certain things (like the
36 ;; autocompletion and a decent scheme to switch between python interpreters)
44 ;; autocompletion and a decent scheme to switch between python interpreters)
37 ;; properly will also require changes to ipython that will likely have to wait
45 ;; properly will also require changes to ipython that will likely have to wait
38 ;; for a larger rewrite scheduled some time in the future.
46 ;; for a larger rewrite scheduled some time in the future.
39 ;;
47 ;;
40 ;; Also note that you currently NEED THE CVS VERSION OF PYTHON.EL.
41 ;;
48 ;;
42 ;; Further note that I don't know whether this runs under windows or not and
49 ;; Further note that I don't know whether this runs under windows or not and
43 ;; that if it doesn't I can't really help much, not being afflicted myself.
50 ;; that if it doesn't I can't really help much, not being afflicted myself.
@@ -46,14 +53,15 b''
46 ;; Hints for effective usage
53 ;; Hints for effective usage
47 ;; -------------------------
54 ;; -------------------------
48 ;;
55 ;;
49 ;; - IMO the best feature by far of the ipython/emacs combo is how much easier it
56 ;; - IMO the best feature by far of the ipython/emacs combo is how much easier
50 ;; makes it to find and fix bugs thanks to the ``%pdb on``/ pdbtrack combo. Try
57 ;; it makes it to find and fix bugs thanks to the ``%pdb on or %debug``/
51 ;; it: first in the ipython to shell do ``%pdb on`` then do something that will
58 ;; pdbtrack combo. Try it: first in the ipython to shell do ``%pdb on`` then
52 ;; raise an exception (FIXME nice example) -- and be amazed how easy it is to
59 ;; do something that will raise an exception (FIXME nice example), or type
53 ;; inspect the live objects in each stack frames and to jump to the
60 ;; ``%debug`` after the exception has been raised. YOu'll be amazed at how
54 ;; corresponding sourcecode locations as you walk up and down the stack trace
61 ;; easy it is to inspect the live objects in each stack frames and to jump to
55 ;; (even without ``%pdb on`` you can always use ``C-c -`` (`py-up-exception')
62 ;; the corresponding sourcecode locations as you walk up and down the stack
56 ;; to jump to the corresponding source code locations).
63 ;; trace (even without ``%pdb on`` you can always use ``C-c -``
64 ;; (`py-up-exception') to jump to the corresponding source code locations).
57 ;;
65 ;;
58 ;; - emacs gives you much more powerful commandline editing and output searching
66 ;; - emacs gives you much more powerful commandline editing and output searching
59 ;; capabilities than ipython-standalone -- isearch is your friend if you
67 ;; capabilities than ipython-standalone -- isearch is your friend if you
@@ -65,9 +73,9 b''
65 ;; ipython, you can change ``meta p`` etc. for ``control p``)::
73 ;; ipython, you can change ``meta p`` etc. for ``control p``)::
66 ;;
74 ;;
67 ;; (require 'comint)
75 ;; (require 'comint)
68 ;; (define-key comint-mode-map [(meta p)]
76 ;; (define-key comint-mode-map [(meta p)]
69 ;; 'comint-previous-matching-input-from-input)
77 ;; 'comint-previous-matching-input-from-input)
70 ;; (define-key comint-mode-map [(meta n)]
78 ;; (define-key comint-mode-map [(meta n)]
71 ;; 'comint-next-matching-input-from-input)
79 ;; 'comint-next-matching-input-from-input)
72 ;; (define-key comint-mode-map [(control meta n)]
80 ;; (define-key comint-mode-map [(control meta n)]
73 ;; 'comint-next-input)
81 ;; 'comint-next-input)
@@ -79,8 +87,8 b''
79 ;; variables comes later).
87 ;; variables comes later).
80 ;;
88 ;;
81 ;; Please send comments and feedback to the ipython-list
89 ;; Please send comments and feedback to the ipython-list
82 ;; (<ipython-user@scipy.net>) where I (a.s.) or someone else will try to
90 ;; (<ipython-user@scipy.org>) where I (a.s.) or someone else will try to
83 ;; answer them (it helps if you specify your emacs version, OS etc;
91 ;; answer them (it helps if you specify your emacs version, OS etc;
84 ;; familiarity with <http://www.catb.org/~esr/faqs/smart-questions.html> might
92 ;; familiarity with <http://www.catb.org/~esr/faqs/smart-questions.html> might
85 ;; speed up things further).
93 ;; speed up things further).
86 ;;
94 ;;
@@ -106,10 +114,10 b''
106 ;; - neither::
114 ;; - neither::
107 ;;
115 ;;
108 ;; (py-shell "-c print 'FOOBAR'")
116 ;; (py-shell "-c print 'FOOBAR'")
109 ;;
117 ;;
110 ;; nor::
118 ;; nor::
111 ;;
119 ;;
112 ;; (let ((py-python-command-args (append py-python-command-args
120 ;; (let ((py-python-command-args (append py-python-command-args
113 ;; '("-c" "print 'FOOBAR'"))))
121 ;; '("-c" "print 'FOOBAR'"))))
114 ;; (py-shell))
122 ;; (py-shell))
115 ;;
123 ;;
@@ -127,7 +135,7 b''
127
135
128 (defcustom ipython-command "ipython"
136 (defcustom ipython-command "ipython"
129 "*Shell command used to start ipython."
137 "*Shell command used to start ipython."
130 :type 'string
138 :type 'string
131 :group 'python)
139 :group 'python)
132
140
133 ;; Users can set this to nil
141 ;; Users can set this to nil
@@ -138,7 +146,7 b''
138 (defvar ipython-backup-of-py-python-command nil
146 (defvar ipython-backup-of-py-python-command nil
139 "HACK")
147 "HACK")
140
148
141
149
142 (defvar ipython-de-input-prompt-regexp "\\(?:
150 (defvar ipython-de-input-prompt-regexp "\\(?:
143 In \\[[0-9]+\\]: *.*
151 In \\[[0-9]+\\]: *.*
144 ----+> \\(.*
152 ----+> \\(.*
@@ -181,16 +189,16 b' the second for a \'normal\' command, and the third for a multiline command.")'
181 ;;XXX this is really just a cheap hack, it only completes symbols in the
189 ;;XXX this is really just a cheap hack, it only completes symbols in the
182 ;;interactive session -- useful nonetheless.
190 ;;interactive session -- useful nonetheless.
183 (define-key py-mode-map [(meta tab)] 'ipython-complete)
191 (define-key py-mode-map [(meta tab)] 'ipython-complete)
184
192
185 )
193 )
186 (add-hook 'py-shell-hook 'ipython-shell-hook)
194 (add-hook 'py-shell-hook 'ipython-shell-hook)
187 ;; Regular expression that describes tracebacks for IPython in context and
195 ;; Regular expression that describes tracebacks for IPython in context and
188 ;; verbose mode.
196 ;; verbose mode.
189
197
190 ;;Adapt python-mode settings for ipython.
198 ;;Adapt python-mode settings for ipython.
191 ;; (this works for %xmode 'verbose' or 'context')
199 ;; (this works for %xmode 'verbose' or 'context')
192
200
193 ;; XXX putative regexps for syntax errors; unfortunately the
201 ;; XXX putative regexps for syntax errors; unfortunately the
194 ;; current python-mode traceback-line-re scheme is too primitive,
202 ;; current python-mode traceback-line-re scheme is too primitive,
195 ;; so it's either matching syntax errors, *or* everything else
203 ;; so it's either matching syntax errors, *or* everything else
196 ;; (XXX: should ask Fernando for a change)
204 ;; (XXX: should ask Fernando for a change)
@@ -200,20 +208,20 b' the second for a \'normal\' command, and the third for a multiline command.")'
200 (setq py-traceback-line-re
208 (setq py-traceback-line-re
201 "\\(^[^\t >].+?\\.py\\).*\n +[0-9]+[^\00]*?\n-+> \\([0-9]+\\)+")
209 "\\(^[^\t >].+?\\.py\\).*\n +[0-9]+[^\00]*?\n-+> \\([0-9]+\\)+")
202
210
203
211
204 ;; Recognize the ipython pdb, whose prompt is 'ipdb>' or 'ipydb>'
212 ;; Recognize the ipython pdb, whose prompt is 'ipdb>' or 'ipydb>'
205 ;;instead of '(Pdb)'
213 ;;instead of '(Pdb)'
206 (setq py-pdbtrack-input-prompt "\n[(<]*[Ii]?[Pp]y?db[>)]+ ")
214 (setq py-pdbtrack-input-prompt "\n[(<]*[Ii]?[Pp]y?db[>)]+ ")
207 (setq pydb-pydbtrack-input-prompt "\n[(]*ipydb[>)]+ ")
215 (setq pydb-pydbtrack-input-prompt "\n[(]*ipydb[>)]+ ")
208
216
209 (setq py-shell-input-prompt-1-regexp "^In \\[[0-9]+\\]: *"
217 (setq py-shell-input-prompt-1-regexp "^In \\[[0-9]+\\]: *"
210 py-shell-input-prompt-2-regexp "^ [.][.][.]+: *" )
218 py-shell-input-prompt-2-regexp "^ [.][.][.]+: *" )
211 ;; select a suitable color-scheme
219 ;; select a suitable color-scheme
212 (unless (member "-colors" py-python-command-args)
220 (unless (member "-colors" py-python-command-args)
213 (setq py-python-command-args
221 (setq py-python-command-args
214 (nconc py-python-command-args
222 (nconc py-python-command-args
215 (list "-colors"
223 (list "-colors"
216 (cond
224 (cond
217 ((eq frame-background-mode 'dark)
225 ((eq frame-background-mode 'dark)
218 "Linux")
226 "Linux")
219 ((eq frame-background-mode 'light)
227 ((eq frame-background-mode 'light)
@@ -253,7 +261,7 b' buffer already exists."'
253
261
254 (defadvice py-execute-region (around py-execute-buffer-ensure-process)
262 (defadvice py-execute-region (around py-execute-buffer-ensure-process)
255 "HACK: if `py-shell' is not active or ASYNC is explicitly desired, fall back
263 "HACK: if `py-shell' is not active or ASYNC is explicitly desired, fall back
256 to python instead of ipython."
264 to python instead of ipython."
257 (let ((py-which-shell (if (and (comint-check-proc "*Python*") (not async))
265 (let ((py-which-shell (if (and (comint-check-proc "*Python*") (not async))
258 py-python-command
266 py-python-command
259 ipython-backup-of-py-python-command)))
267 ipython-backup-of-py-python-command)))
@@ -267,14 +275,14 b' be used in doctests. Example:'
267
275
268
276
269 In [1]: import sys
277 In [1]: import sys
270
278
271 In [2]: sys.stdout.write 'Hi!\n'
279 In [2]: sys.stdout.write 'Hi!\n'
272 ------> sys.stdout.write ('Hi!\n')
280 ------> sys.stdout.write ('Hi!\n')
273 Hi!
281 Hi!
274
282
275 In [3]: 3 + 4
283 In [3]: 3 + 4
276 Out[3]: 7
284 Out[3]: 7
277
285
278 gets converted to:
286 gets converted to:
279
287
280 >>> import sys
288 >>> import sys
@@ -288,7 +296,7 b' gets converted to:'
288 ;(message (format "###DEBUG s:%de:%d" start end))
296 ;(message (format "###DEBUG s:%de:%d" start end))
289 (save-excursion
297 (save-excursion
290 (save-match-data
298 (save-match-data
291 ;; replace ``In [3]: bla`` with ``>>> bla`` and
299 ;; replace ``In [3]: bla`` with ``>>> bla`` and
292 ;; ``... : bla`` with ``... bla``
300 ;; ``... : bla`` with ``... bla``
293 (goto-char start)
301 (goto-char start)
294 (while (re-search-forward ipython-de-input-prompt-regexp end t)
302 (while (re-search-forward ipython-de-input-prompt-regexp end t)
@@ -302,7 +310,7 b' gets converted to:'
302 (while (re-search-forward ipython-de-output-prompt-regexp end t)
310 (while (re-search-forward ipython-de-output-prompt-regexp end t)
303 (replace-match "" t nil)))))
311 (replace-match "" t nil)))))
304
312
305 (defvar ipython-completion-command-string
313 (defvar ipython-completion-command-string
306 "print ';'.join(__IP.Completer.all_completions('%s')) #PYTHON-MODE SILENT\n"
314 "print ';'.join(__IP.Completer.all_completions('%s')) #PYTHON-MODE SILENT\n"
307 "The string send to ipython to query for all possible completions")
315 "The string send to ipython to query for all possible completions")
308
316
@@ -332,19 +340,19 b' in the current *Python* session."'
332 (completion-table nil)
340 (completion-table nil)
333 completion
341 completion
334 (comint-output-filter-functions
342 (comint-output-filter-functions
335 (append comint-output-filter-functions
343 (append comint-output-filter-functions
336 '(ansi-color-filter-apply
344 '(ansi-color-filter-apply
337 (lambda (string)
345 (lambda (string)
338 ;(message (format "DEBUG filtering: %s" string))
346 ;(message (format "DEBUG filtering: %s" string))
339 (setq ugly-return (concat ugly-return string))
347 (setq ugly-return (concat ugly-return string))
340 (delete-region comint-last-output-start
348 (delete-region comint-last-output-start
341 (process-mark (get-buffer-process (current-buffer)))))))))
349 (process-mark (get-buffer-process (current-buffer)))))))))
342 ;(message (format "#DEBUG pattern: '%s'" pattern))
350 ;(message (format "#DEBUG pattern: '%s'" pattern))
343 (process-send-string python-process
351 (process-send-string python-process
344 (format ipython-completion-command-string pattern))
352 (format ipython-completion-command-string pattern))
345 (accept-process-output python-process)
353 (accept-process-output python-process)
346 ;(message (format "DEBUG return: %s" ugly-return))
354 ;(message (format "DEBUG return: %s" ugly-return))
347 (setq completions
355 (setq completions
348 (split-string (substring ugly-return 0 (position ?\n ugly-return)) sep))
356 (split-string (substring ugly-return 0 (position ?\n ugly-return)) sep))
349 (setq completion-table (loop for str in completions
357 (setq completion-table (loop for str in completions
350 collect (list str nil)))
358 collect (list str nil)))
@@ -376,22 +384,22 b' in the current *Python* session."'
376 ;; to let ipython have the complete line, so that context can be used
384 ;; to let ipython have the complete line, so that context can be used
377 ;; to do things like filename completion etc.
385 ;; to do things like filename completion etc.
378 (beg (save-excursion (skip-chars-backward "a-z0-9A-Z_./" (point-at-bol))
386 (beg (save-excursion (skip-chars-backward "a-z0-9A-Z_./" (point-at-bol))
379 (point)))
387 (point)))
380 (end (point))
388 (end (point))
381 (pattern (buffer-substring-no-properties beg end))
389 (pattern (buffer-substring-no-properties beg end))
382 (completions nil)
390 (completions nil)
383 (completion-table nil)
391 (completion-table nil)
384 completion
392 completion
385 (comint-preoutput-filter-functions
393 (comint-preoutput-filter-functions
386 (append comint-preoutput-filter-functions
394 (append comint-preoutput-filter-functions
387 '(ansi-color-filter-apply
395 '(ansi-color-filter-apply
388 (lambda (string)
396 (lambda (string)
389 (setq ugly-return (concat ugly-return string))
397 (setq ugly-return (concat ugly-return string))
390 "")))))
398 "")))))
391 (process-send-string python-process
399 (process-send-string python-process
392 (format ipython-completion-command-string pattern))
400 (format ipython-completion-command-string pattern))
393 (accept-process-output python-process)
401 (accept-process-output python-process)
394 (setq completions
402 (setq completions
395 (split-string (substring ugly-return 0 (position ?\n ugly-return)) sep))
403 (split-string (substring ugly-return 0 (position ?\n ugly-return)) sep))
396 ;(message (format "DEBUG completions: %S" completions))
404 ;(message (format "DEBUG completions: %S" completions))
397 (setq completion-table (loop for str in completions
405 (setq completion-table (loop for str in completions
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
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