##// END OF EJS Templates
Merged changes from ipython-frontend1. Better error rendering in Cocoa frontend. Refactored frontendbase.FrontEndBase so that FrontEndBase is synchronous and AsynchronousFronEndBase(FrontEndBase) wraps FrontEndBase in Twisted goodness.
Barry Wark -
r1312:06dc07c6 merge
parent child Browse files
Show More
@@ -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 /* Cocoa Frontend Plugin */;
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,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>
@@ -40,7 +40,7 b' from pprint import saferepr'
40
40
41 import IPython
41 import IPython
42 from IPython.kernel.engineservice import ThreadedEngineService
42 from IPython.kernel.engineservice import ThreadedEngineService
43 from IPython.frontend.frontendbase import FrontEndBase
43 from IPython.frontend.frontendbase import AsynchronousFrontEndBase
44
44
45 from twisted.internet.threads import blockingCallFromThread
45 from twisted.internet.threads import blockingCallFromThread
46 from twisted.python.failure import Failure
46 from twisted.python.failure import Failure
@@ -96,14 +96,14 b' class AutoreleasePoolWrappedThreadedEngineService(ThreadedEngineService):'
96 return d
96 return d
97
97
98
98
99 class IPythonCocoaController(NSObject, FrontEndBase):
99 class IPythonCocoaController(NSObject, AsynchronousFrontEndBase):
100 userNS = objc.ivar() #mirror of engine.user_ns (key=>str(value))
100 userNS = objc.ivar() #mirror of engine.user_ns (key=>str(value))
101 waitingForEngine = objc.ivar().bool()
101 waitingForEngine = objc.ivar().bool()
102 textView = objc.IBOutlet()
102 textView = objc.IBOutlet()
103
103
104 def init(self):
104 def init(self):
105 self = super(IPythonCocoaController, self).init()
105 self = super(IPythonCocoaController, self).init()
106 FrontEndBase.__init__(self,
106 AsynchronousFrontEndBase.__init__(self,
107 engine=AutoreleasePoolWrappedThreadedEngineService())
107 engine=AutoreleasePoolWrappedThreadedEngineService())
108 if(self != None):
108 if(self != None):
109 self._common_init()
109 self._common_init()
@@ -29,6 +29,7 b' setup('
29 setup_requires=['py2app'],
29 setup_requires=['py2app'],
30 options=dict(py2app=dict(
30 options=dict(py2app=dict(
31 plist=infoPlist,
31 plist=infoPlist,
32 excludes=['IPython','twisted']
32 site_packages=True,
33 excludes=['IPython','twisted','PyObjCTools']
33 )),
34 )),
34 ) No newline at end of file
35 )
@@ -159,9 +159,6 b' class FrontEndBase(object):'
159 - How do we handle completions?
159 - How do we handle completions?
160 """
160 """
161
161
162 zi.implements(IFrontEnd)
163 zi.classProvides(IFrontEndFactory)
164
165 history_cursor = 0
162 history_cursor = 0
166
163
167 current_indent_level = 0
164 current_indent_level = 0
@@ -171,9 +168,8 b' class FrontEndBase(object):'
171 output_prompt_template = string.Template(rc.prompt_out)
168 output_prompt_template = string.Template(rc.prompt_out)
172 continuation_prompt_template = string.Template(rc.prompt_in2)
169 continuation_prompt_template = string.Template(rc.prompt_in2)
173
170
174 def __init__(self, engine=None, history=None):
171 def __init__(self, shell=None, history=None):
175 assert(engine==None or IEngineCore.providedBy(engine))
172 self.shell = shell
176 self.engine = IEngineCore(engine)
177 if history is None:
173 if history is None:
178 self.history = FrontEndHistory(input_cache=[''])
174 self.history = FrontEndHistory(input_cache=[''])
179 else:
175 else:
@@ -236,7 +232,7 b' class FrontEndBase(object):'
236
232
237
233
238 def execute(self, block, blockID=None):
234 def execute(self, block, blockID=None):
239 """Execute the block and return result.
235 """Execute the block and return the result.
240
236
241 Parameters:
237 Parameters:
242 block : {str, AST}
238 block : {str, AST}
@@ -249,22 +245,23 b' class FrontEndBase(object):'
249 """
245 """
250
246
251 if(not self.is_complete(block)):
247 if(not self.is_complete(block)):
252 return Failure(Exception("Block is not compilable"))
248 raise Exception("Block is not compilable")
253
249
254 if(blockID == None):
250 if(blockID == None):
255 blockID = uuid.uuid4() #random UUID
251 blockID = uuid.uuid4() #random UUID
256
252
257 d = self.engine.execute(block)
253 try:
258 d.addCallback(self._add_history, block=block)
254 result = self.shell.execute(block)
259 d.addCallbacks(self._add_block_id_for_result,
255 except Exception,e:
260 errback=self._add_block_id_for_failure,
256 e = self._add_block_id_for_failure(e, blockID=blockID)
261 callbackArgs=(blockID,),
257 e = self.update_cell_prompt(e, blockID=blockID)
262 errbackArgs=(blockID,))
258 e = self.render_error(e)
263 d.addBoth(self.update_cell_prompt, blockID=blockID)
259 else:
264 d.addCallbacks(self.render_result,
260 result = self._add_block_id_for_result(result, blockID=blockID)
265 errback=self.render_error)
261 result = self.update_cell_prompt(result, blockID=blockID)
262 result = self.render_result(result)
266
263
267 return d
264 return result
268
265
269
266
270 def _add_block_id_for_result(self, result, blockID):
267 def _add_block_id_for_result(self, result, blockID):
@@ -347,3 +344,53 b' class FrontEndBase(object):'
347
344
348
345
349
346
347 class AsynchronousFrontEndBase(FrontEndBase):
348 """
349 Overrides FrontEndBase to wrap execute in a deferred result.
350 All callbacks are made as callbacks on the deferred result.
351 """
352
353 zi.implements(IFrontEnd)
354 zi.classProvides(IFrontEndFactory)
355
356 def __init__(self, engine=None, history=None):
357 assert(engine==None or IEngineCore.providedBy(engine))
358 self.engine = IEngineCore(engine)
359 if history is None:
360 self.history = FrontEndHistory(input_cache=[''])
361 else:
362 self.history = history
363
364
365 def execute(self, block, blockID=None):
366 """Execute the block and return the deferred result.
367
368 Parameters:
369 block : {str, AST}
370 blockID : any
371 Caller may provide an ID to identify this block.
372 result['blockID'] := blockID
373
374 Result:
375 Deferred result of self.interpreter.execute
376 """
377
378 if(not self.is_complete(block)):
379 return Failure(Exception("Block is not compilable"))
380
381 if(blockID == None):
382 blockID = uuid.uuid4() #random UUID
383
384 d = self.engine.execute(block)
385 d.addCallback(self._add_history, block=block)
386 d.addCallbacks(self._add_block_id_for_result,
387 errback=self._add_block_id_for_failure,
388 callbackArgs=(blockID,),
389 errbackArgs=(blockID,))
390 d.addBoth(self.update_cell_prompt, blockID=blockID)
391 d.addCallbacks(self.render_result,
392 errback=self.render_error)
393
394 return d
395
396
@@ -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.AsynchronousFrontEndBase):
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,
@@ -44,7 +44,7 b' class FrontEndCallbackChecker(frontendbase.FrontEndBase):'
44
44
45
45
46
46
47 class TestFrontendBase(unittest.TestCase):
47 class TestAsynchronousFrontendBase(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.AsynchronousFrontEndBase))
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):
General Comments 0
You need to be logged in to leave comments. Login now