diff --git a/IPython/frontend/cocoa/cocoa_frontend.py b/IPython/frontend/cocoa/cocoa_frontend.py index 3c0a46e..77df8ba 100644 --- a/IPython/frontend/cocoa/cocoa_frontend.py +++ b/IPython/frontend/cocoa/cocoa_frontend.py @@ -40,6 +40,7 @@ from IPython.kernel.engineservice import EngineService, ThreadedEngineService from IPython.frontend.frontendbase import FrontEndBase from twisted.internet.threads import blockingCallFromThread +from twisted.python.failure import Failure #------------------------------------------------------------------------------- # Classes to implement the Cocoa frontend @@ -305,8 +306,13 @@ class IPythonCocoaController(NSObject, FrontEndBase): return block[-1] def update_cell_prompt(self, result): - blockID = result['blockID'] - self.insert_text(self.inputPrompt(result=result), + if(isinstance(result, Failure)): + blockID = result.blockID + else: + blockID = result['blockID'] + + + self.insert_text(self.input_prompt(result=result), textRange=NSMakeRange(self.blockRanges[blockID].location,0), scrollToVisible=False ) @@ -321,7 +327,7 @@ class IPythonCocoaController(NSObject, FrontEndBase): #print inputRange,self.currentBlockRange() self.insert_text('\n' + - self.outputPrompt(result) + + self.output_prompt(result) + result.get('display',{}).get('pprint','') + '\n\n', textRange=NSMakeRange(inputRange.location+inputRange.length, 0)) diff --git a/IPython/frontend/frontendbase.py b/IPython/frontend/frontendbase.py index 195f4ce..577bc97 100644 --- a/IPython/frontend/frontendbase.py +++ b/IPython/frontend/frontendbase.py @@ -89,16 +89,16 @@ class IFrontEnd(zi.Interface): pass - def inputPrompt(result={}): + def input_prompt(result={}): """Returns the input prompt by subsituting into self.input_prompt_template""" pass - def outputPrompt(result): + def output_prompt(result): """Returns the output prompt by subsituting into self.output_prompt_template""" pass - def continuationPrompt(): + def continuation_prompt(): """Returns the continuation prompt by subsituting into self.continuation_prompt_template""" pass @@ -157,7 +157,7 @@ class FrontEndBase(object): self.history = history - def inputPrompt(self, result={}): + def input_prompt(self, result={}): """Returns the current input prompt It would be great to use ipython1.core.prompts.Prompt1 here @@ -168,12 +168,12 @@ class FrontEndBase(object): return self.input_prompt_template.safe_substitute(result) - def continuationPrompt(self): + def continuation_prompt(self): """Returns the current continuation prompt""" return self.continuation_prompt_template.safe_substitute() - def outputPrompt(self, result): + def output_prompt(self, result): """Returns the output prompt for result""" return self.output_prompt_template.safe_substitute(result) @@ -234,18 +234,23 @@ class FrontEndBase(object): blockID = uuid.uuid4() #random UUID d = self.engine.execute(block) - d.addCallback(self._add_block_id, blockID) d.addCallback(self._add_history, block=block) - d.addCallback(self.update_cell_prompt) + d.addBoth(self._add_block_id, blockID) + d.addBoth(self.update_cell_prompt) d.addCallbacks(self.render_result, errback=self.render_error) return d def _add_block_id(self, result, blockID): - """Add the blockID to result""" + """Add the blockID to result or failure. Unfortunatley, we have to treat failures + differently than result dicts + """ - result['blockID'] = blockID + if(isinstance(result, Failure)): + result.blockID = blockID + else: + result['blockID'] = blockID return result @@ -287,7 +292,17 @@ class FrontEndBase(object): def update_cell_prompt(self, result): """Subclass may override to update the input prompt for a block. Since this method will be called as a twisted.internet.defer.Deferred's callback, - implementations should return result when finished.""" + implementations should return result when finished. + + NP: result is a failure if the execute returned a failre. To get the blockID, you should + do something like:: + if(isinstance(result, twisted.python.failure.Failure)): + blockID = result.blockID + else: + blockID = result['blockID'] + + + """ return result diff --git a/IPython/frontend/tests/test_frontendbase.py b/IPython/frontend/tests/test_frontendbase.py index 35949c4..d3c265a 100644 --- a/IPython/frontend/tests/test_frontendbase.py +++ b/IPython/frontend/tests/test_frontendbase.py @@ -50,18 +50,18 @@ class TestFrontendBase(unittest.TestCase): self.fb = FrontEndCallbackChecker(engine=EngineService()) - def test_implementsIFrontEnd(self): + def test_implements_IFrontEnd(self): assert(frontendbase.IFrontEnd.implementedBy(frontendbase.FrontEndBase)) - def test_is_completeReturnsFalseForIncompleteBlock(self): + def test_is_complete_returns_False_for_incomplete_block(self): """""" block = """def test(a):""" assert(self.fb.is_complete(block) == False) - def test_is_completeReturnsTrueForCompleteBlock(self): + def test_is_complete_returns_True_for_complete_block(self): """""" block = """def test(a): pass""" @@ -73,18 +73,28 @@ class TestFrontendBase(unittest.TestCase): assert(self.fb.is_complete(block)) - def test_blockIDAddedToResult(self): + def test_blockID_added_to_result(self): block = """3+3""" d = self.fb.execute(block, blockID='TEST_ID') d.addCallback(self.checkBlockID, expected='TEST_ID') + def test_blockID_added_to_failure(self): + block = "raise Exception()" + + d = self.fb.execute(block,blockID='TEST_ID') + d.addErrback(self.checkFailureID, expected='TEST_ID') + def checkBlockID(self, result, expected=""): assert(result['blockID'] == expected) - def test_callbacksAddedToExecuteRequest(self): + def checkFailureID(self, failure, expected=""): + assert(failure.blockID == expected) + + + def test_callbacks_added_to_execute(self): """test that update_cell_prompt render_result @@ -101,7 +111,7 @@ class TestFrontendBase(unittest.TestCase): assert(self.fb.renderResultCalled) - def test_errorCallbackAddedToExecuteRequest(self): + def test_error_callback_added_to_execute(self): """test that render_error called on execution error""" d = self.fb.execute("raise Exception()")