From a36c8d5b0e660e57d2a3051d06670780c1e75c97 2008-09-14 22:13:51 From: Gael Varoquaux Date: 2008-09-14 22:13:51 Subject: [PATCH] Replace all use of the ast module with the codeop module, and all use of the uuid module with the IPython.external.guid module. Add tests for the is_complete method. --- diff --git a/IPython/frontend/asyncfrontendbase.py b/IPython/frontend/asyncfrontendbase.py index a35366f..78afa18 100644 --- a/IPython/frontend/asyncfrontendbase.py +++ b/IPython/frontend/asyncfrontendbase.py @@ -14,7 +14,7 @@ __docformat__ = "restructuredtext en" #------------------------------------------------------------------------------- # Imports #------------------------------------------------------------------------------- -import uuid +from IPython.external import guid from zope.interface import Interface, Attribute, implements, classProvides @@ -59,7 +59,7 @@ class AsyncFrontEndBase(FrontEndBase): return Failure(Exception("Block is not compilable")) if(blockID == None): - blockID = uuid.uuid4() #random UUID + blockID = guid.generate() d = self.engine.execute(block) d.addCallback(self._add_history, block=block) diff --git a/IPython/frontend/cocoa/cocoa_frontend.py b/IPython/frontend/cocoa/cocoa_frontend.py index 63b765c..349e794 100644 --- a/IPython/frontend/cocoa/cocoa_frontend.py +++ b/IPython/frontend/cocoa/cocoa_frontend.py @@ -26,7 +26,7 @@ __docformat__ = "restructuredtext en" import sys import objc -import uuid +from IPython.external import guid from Foundation import NSObject, NSMutableArray, NSMutableDictionary,\ NSLog, NSNotificationCenter, NSMakeRange,\ @@ -361,7 +361,7 @@ class IPythonCocoaController(NSObject, AsyncFrontEndBase): def next_block_ID(self): - return uuid.uuid4() + return guid.generate() def new_cell_block(self): """A new CellBlock at the end of self.textView.textStorage()""" diff --git a/IPython/frontend/frontendbase.py b/IPython/frontend/frontendbase.py index 71e6482..3ae6e78 100644 --- a/IPython/frontend/frontendbase.py +++ b/IPython/frontend/frontendbase.py @@ -21,76 +21,8 @@ __docformat__ = "restructuredtext en" # Imports #------------------------------------------------------------------------------- import string - -try: - import _ast -except ImportError: - # Python 2.4 hackish workaround. - class bunch: pass - _ast = bunch() - _ast.PyCF_ONLY_AST = 1024 - - - -try: - import uuid -except ImportError: - # Python 2.4 hackish workaround. - class UUID: - def __init__(self,bytes): - version = 4 - int = long(('%02x'*16) % tuple(map(ord, bytes)), 16) - # Set the variant to RFC 4122. - int &= ~(0xc000 << 48L) - int |= 0x8000 << 48L - # Set the version number. - int &= ~(0xf000 << 64L) - int |= version << 76L - self.__dict__['int'] = int - - def __cmp__(self, other): - if isinstance(other, UUID): - return cmp(self.int, other.int) - return NotImplemented - - def __hash__(self): - return hash(self.int) - - def __int__(self): - return self.int - - def __repr__(self): - return 'UUID(%r)' % str(self) - - def __setattr__(self, name, value): - raise TypeError('UUID objects are immutable') - - def __str__(self): - hex = '%032x' % self.int - return '%s-%s-%s-%s-%s' % ( - hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:]) - - def get_bytes(self): - bytes = '' - for shift in range(0, 128, 8): - bytes = chr((self.int >> shift) & 0xff) + bytes - return bytes - - bytes = property(get_bytes) - - - def _u4(): - "Fake random uuid" - - import random - bytes = [chr(random.randrange(256)) for i in range(16)] - return UUID(bytes) - - class bunch: pass - uuid = bunch() - uuid.uuid4 = _u4 - del _u4 - +import codeop +from IPython.external import guid from IPython.frontend.zopeinterface import ( @@ -201,11 +133,7 @@ class IFrontEnd(Interface): pass - def compile_ast(block): - """Compiles block to an _ast.AST""" - - pass - + def get_history_previous(current_block): """Returns the block previous in the history. Saves currentBlock if the history_cursor is currently at the end of the input history""" @@ -287,28 +215,14 @@ class FrontEndBase(object): """ try: - ast = self.compile_ast(block) + is_complete = codeop.compile_command(block.rstrip() + '\n\n', + "", "exec") except: return False lines = block.split('\n') - return (len(lines)==1 or str(lines[-1])=='') - - - def compile_ast(self, block): - """Compile block to an AST - - Parameters: - block : str - - Result: - AST - - Throws: - Exception if block cannot be compiled - """ - - return compile(block, "", "exec", _ast.PyCF_ONLY_AST) + return ((is_complete is not None) + and (len(lines)==1 or str(lines[-1])=='')) def execute(self, block, blockID=None): @@ -328,7 +242,7 @@ class FrontEndBase(object): raise Exception("Block is not compilable") if(blockID == None): - blockID = uuid.uuid4() #random UUID + blockID = guid.generate() try: result = self.shell.execute(block) diff --git a/IPython/frontend/tests/test_asyncfrontendbase.py b/IPython/frontend/tests/test_asyncfrontendbase.py new file mode 100644 index 0000000..617456e --- /dev/null +++ b/IPython/frontend/tests/test_asyncfrontendbase.py @@ -0,0 +1,155 @@ +# encoding: utf-8 + +"""This file contains unittests for the frontendbase module.""" + +__docformat__ = "restructuredtext en" + +#--------------------------------------------------------------------------- +# Copyright (C) 2008 The IPython Development Team +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#--------------------------------------------------------------------------- + +#--------------------------------------------------------------------------- +# Imports +#--------------------------------------------------------------------------- + +import unittest + +try: + from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase + from IPython.frontend import frontendbase + from IPython.kernel.engineservice import EngineService +except ImportError: + import nose + raise nose.SkipTest("This test requires zope.interface, Twisted and Foolscap") + +from IPython.testing.decorators import skip + +class FrontEndCallbackChecker(AsyncFrontEndBase): + """FrontEndBase subclass for checking callbacks""" + def __init__(self, engine=None, history=None): + super(FrontEndCallbackChecker, self).__init__(engine=engine, + history=history) + self.updateCalled = False + self.renderResultCalled = False + self.renderErrorCalled = False + + def update_cell_prompt(self, result, blockID=None): + self.updateCalled = True + return result + + def render_result(self, result): + self.renderResultCalled = True + return result + + + def render_error(self, failure): + self.renderErrorCalled = True + return failure + + + + +class TestAsyncFrontendBase(unittest.TestCase): + def setUp(self): + """Setup the EngineService and FrontEndBase""" + + self.fb = FrontEndCallbackChecker(engine=EngineService()) + + def test_implements_IFrontEnd(self): + assert(frontendbase.IFrontEnd.implementedBy( + AsyncFrontEndBase)) + + def test_is_complete_returns_False_for_incomplete_block(self): + """""" + + block = """def test(a):""" + + assert(self.fb.is_complete(block) == False) + + def test_is_complete_returns_True_for_complete_block(self): + """""" + + block = """def test(a): pass""" + + assert(self.fb.is_complete(block)) + + block = """a=3""" + + assert(self.fb.is_complete(block)) + + 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 checkFailureID(self, failure, expected=""): + assert(failure.blockID == expected) + + + def test_callbacks_added_to_execute(self): + """test that + update_cell_prompt + render_result + + are added to execute request + """ + + d = self.fb.execute("10+10") + d.addCallback(self.checkCallbacks) + + def checkCallbacks(self, result): + assert(self.fb.updateCalled) + assert(self.fb.renderResultCalled) + + @skip("This test fails and lead to an unhandled error in a Deferred.") + def test_error_callback_added_to_execute(self): + """test that render_error called on execution error""" + + d = self.fb.execute("raise Exception()") + d.addCallback(self.checkRenderError) + + def checkRenderError(self, result): + assert(self.fb.renderErrorCalled) + + def test_history_returns_expected_block(self): + """Make sure history browsing doesn't fail""" + + blocks = ["a=1","a=2","a=3"] + for b in blocks: + d = self.fb.execute(b) + + # d is now the deferred for the last executed block + d.addCallback(self.historyTests, blocks) + + + def historyTests(self, result, blocks): + """historyTests""" + + assert(len(blocks) >= 3) + assert(self.fb.get_history_previous("") == blocks[-2]) + assert(self.fb.get_history_previous("") == blocks[-3]) + assert(self.fb.get_history_next() == blocks[-2]) + + + def test_history_returns_none_at_startup(self): + """test_history_returns_none_at_startup""" + + assert(self.fb.get_history_previous("")==None) + assert(self.fb.get_history_next()==None) + + diff --git a/IPython/frontend/tests/test_frontendbase.py b/IPython/frontend/tests/test_frontendbase.py index 617456e..f3f4e5a 100644 --- a/IPython/frontend/tests/test_frontendbase.py +++ b/IPython/frontend/tests/test_frontendbase.py @@ -1,155 +1,32 @@ # encoding: utf-8 - -"""This file contains unittests for the frontendbase module.""" +""" +Test the basic functionality of frontendbase. +""" __docformat__ = "restructuredtext en" -#--------------------------------------------------------------------------- -# Copyright (C) 2008 The IPython Development Team -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#--------------------------------------------------------------------------- - -#--------------------------------------------------------------------------- -# Imports -#--------------------------------------------------------------------------- - -import unittest - -try: - from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase - from IPython.frontend import frontendbase - from IPython.kernel.engineservice import EngineService -except ImportError: - import nose - raise nose.SkipTest("This test requires zope.interface, Twisted and Foolscap") - -from IPython.testing.decorators import skip - -class FrontEndCallbackChecker(AsyncFrontEndBase): - """FrontEndBase subclass for checking callbacks""" - def __init__(self, engine=None, history=None): - super(FrontEndCallbackChecker, self).__init__(engine=engine, - history=history) - self.updateCalled = False - self.renderResultCalled = False - self.renderErrorCalled = False - - def update_cell_prompt(self, result, blockID=None): - self.updateCalled = True - return result - - def render_result(self, result): - self.renderResultCalled = True - return result - - - def render_error(self, failure): - self.renderErrorCalled = True - return failure - - +#------------------------------------------------------------------------------- +# Copyright (C) 2008 The IPython Development Team +# +# Distributed under the terms of the BSD License. The full license is +# in the file COPYING, distributed as part of this software. +#------------------------------------------------------------------------------- + +from IPython.frontend.frontendbase import FrontEndBase + +def test_iscomplete(): + """ Check that is_complete works. + """ + f = FrontEndBase() + assert f.is_complete('(a + a)') + assert not f.is_complete('(a + a') + assert f.is_complete('1') + assert not f.is_complete('1 + ') + assert not f.is_complete('1 + \n\n') + assert f.is_complete('if True:\n print 1\n') + assert not f.is_complete('if True:\n print 1') + assert f.is_complete('def f():\n print 1\n') + +if __name__ == '__main__': + test_iscomplete() - -class TestAsyncFrontendBase(unittest.TestCase): - def setUp(self): - """Setup the EngineService and FrontEndBase""" - - self.fb = FrontEndCallbackChecker(engine=EngineService()) - - def test_implements_IFrontEnd(self): - assert(frontendbase.IFrontEnd.implementedBy( - AsyncFrontEndBase)) - - def test_is_complete_returns_False_for_incomplete_block(self): - """""" - - block = """def test(a):""" - - assert(self.fb.is_complete(block) == False) - - def test_is_complete_returns_True_for_complete_block(self): - """""" - - block = """def test(a): pass""" - - assert(self.fb.is_complete(block)) - - block = """a=3""" - - assert(self.fb.is_complete(block)) - - 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 checkFailureID(self, failure, expected=""): - assert(failure.blockID == expected) - - - def test_callbacks_added_to_execute(self): - """test that - update_cell_prompt - render_result - - are added to execute request - """ - - d = self.fb.execute("10+10") - d.addCallback(self.checkCallbacks) - - def checkCallbacks(self, result): - assert(self.fb.updateCalled) - assert(self.fb.renderResultCalled) - - @skip("This test fails and lead to an unhandled error in a Deferred.") - def test_error_callback_added_to_execute(self): - """test that render_error called on execution error""" - - d = self.fb.execute("raise Exception()") - d.addCallback(self.checkRenderError) - - def checkRenderError(self, result): - assert(self.fb.renderErrorCalled) - - def test_history_returns_expected_block(self): - """Make sure history browsing doesn't fail""" - - blocks = ["a=1","a=2","a=3"] - for b in blocks: - d = self.fb.execute(b) - - # d is now the deferred for the last executed block - d.addCallback(self.historyTests, blocks) - - - def historyTests(self, result, blocks): - """historyTests""" - - assert(len(blocks) >= 3) - assert(self.fb.get_history_previous("") == blocks[-2]) - assert(self.fb.get_history_previous("") == blocks[-3]) - assert(self.fb.get_history_next() == blocks[-2]) - - - def test_history_returns_none_at_startup(self): - """test_history_returns_none_at_startup""" - - assert(self.fb.get_history_previous("")==None) - assert(self.fb.get_history_next()==None) - -