From a2890974aac776fb5339eb672fba5b1881d0d4c0 2008-09-15 01:23:06 From: Fernando Perez Date: 2008-09-15 01:23:06 Subject: [PATCH] Merging in Brian's branch (also pulls Gael's work). These contain the continued work on fixing the release for python 2.4. --- diff --git a/IPython/Release.py b/IPython/Release.py index 06783bf..d2e3bf5 100644 --- a/IPython/Release.py +++ b/IPython/Release.py @@ -34,45 +34,69 @@ else: version = version_base -description = "Tools for interactive development in Python." +description = "An interactive computing environment for Python" long_description = \ """ -IPython provides a replacement for the interactive Python interpreter with -extra functionality. +The goal of IPython is to create a comprehensive environment for +interactive and exploratory computing. To support this goal, IPython +has two main components: -Main features: +* An enhanced interactive Python shell. - * Comprehensive object introspection. +* An architecture for interactive parallel computing. - * Input history, persistent across sessions. +The enhanced interactive Python shell has the following main features: - * Caching of output results during a session with automatically generated - references. +* Comprehensive object introspection. - * Readline based name completion. +* Input history, persistent across sessions. - * Extensible system of 'magic' commands for controlling the environment and - performing many tasks related either to IPython or the operating system. +* Caching of output results during a session with automatically generated + references. - * Configuration system with easy switching between different setups (simpler - than changing $PYTHONSTARTUP environment variables every time). +* Readline based name completion. - * Session logging and reloading. +* Extensible system of 'magic' commands for controlling the environment and + performing many tasks related either to IPython or the operating system. - * Extensible syntax processing for special purpose situations. +* Configuration system with easy switching between different setups (simpler + than changing $PYTHONSTARTUP environment variables every time). - * Access to the system shell with user-extensible alias system. +* Session logging and reloading. - * Easily embeddable in other Python programs. +* Extensible syntax processing for special purpose situations. - * Integrated access to the pdb debugger and the Python profiler. +* Access to the system shell with user-extensible alias system. - The latest development version is always available at the IPython subversion - repository_. +* Easily embeddable in other Python programs and wxPython GUIs. -.. _repository: http://ipython.scipy.org/svn/ipython/ipython/trunk#egg=ipython-dev - """ +* Integrated access to the pdb debugger and the Python profiler. + +The parallel computing architecture has the following main features: + +* Quickly parallelize Python code from an interactive Python/IPython session. + +* A flexible and dynamic process model that be deployed on anything from + multicore workstations to supercomputers. + +* An architecture that supports many different styles of parallelism, from + message passing to task farming. + +* Both blocking and fully asynchronous interfaces. + +* High level APIs that enable many things to be parallelized in a few lines + of code. + +* Share live parallel jobs with other users securely. + +* Dynamically load balanced task farming system. + +* Robust error handling in parallel code. + +The latest development version is always available from IPython's `Launchpad +site `_. +""" license = 'BSD' diff --git a/IPython/config/api.py b/IPython/config/api.py index d394098..6de3d3e 100644 --- a/IPython/config/api.py +++ b/IPython/config/api.py @@ -21,10 +21,6 @@ from os.path import join as pjoin from IPython.genutils import get_home_dir, get_ipython_dir from IPython.external.configobj import ConfigObj -# Traitlets config imports -from IPython.config import traitlets -from IPython.config.config import * -from traitlets import * class ConfigObjManager(object): 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 8821fa8..3ae6e78 100644 --- a/IPython/frontend/frontendbase.py +++ b/IPython/frontend/frontendbase.py @@ -21,83 +21,13 @@ __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 ( Interface, Attribute, - implements, - classProvides ) from IPython.kernel.core.history import FrontEndHistory from IPython.kernel.core.util import Bunch @@ -203,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""" @@ -289,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): @@ -330,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) - - diff --git a/IPython/frontend/zopeinterface.py b/IPython/frontend/zopeinterface.py index 9bb726a..2081be3 100644 --- a/IPython/frontend/zopeinterface.py +++ b/IPython/frontend/zopeinterface.py @@ -16,9 +16,6 @@ __docformat__ = "restructuredtext en" # the file COPYING, distributed as part of this software. #------------------------------------------------------------------------------- -#------------------------------------------------------------------------------- -# Imports -#------------------------------------------------------------------------------- try: from zope.interface import Interface, Attribute, implements, classProvides except ImportError: diff --git a/IPython/kernel/core/tests/test_redirectors.py b/IPython/kernel/core/tests/test_redirectors.py index f9e57f5..27b638d 100644 --- a/IPython/kernel/core/tests/test_redirectors.py +++ b/IPython/kernel/core/tests/test_redirectors.py @@ -16,10 +16,12 @@ __docformat__ = "restructuredtext en" import os from cStringIO import StringIO -from IPython.testing import decorators as testdec +# FIXME: +import nose +import sys +if sys.platform == 'win32': + raise nose.SkipTest("These tests are not reliable under windows") -# FIXME -@testdec.skip("This doesn't work under Windows") def test_redirector(): """ Checks that the redirector can be used to do synchronous capture. """ @@ -40,8 +42,6 @@ def test_redirector(): result2 = "".join("%ic\n%i\n" %(i, i) for i in range(10)) assert result1 == result2 -# FIXME -@testdec.skip("This doesn't work under Windows") def test_redirector_output_trap(): """ This test check not only that the redirector_output_trap does trap the output, but also that it does it in a gready way, that diff --git a/README.txt b/README.txt index a46aaeb..dcda9ef 100644 --- a/README.txt +++ b/README.txt @@ -1,11 +1,11 @@ -=============== -IPython1 README -=============== - -.. contents:: +============== +IPython README +============== Overview ======== -Welcome to IPython. New users should consult our documentation, which can be found -in the docs/source subdirectory. +Welcome to IPython. Our documentation can be found in the docs/source +subdirectory. We also have ``.html`` and ``.pdf`` versions of this +documentation available on the IPython `website `_. + diff --git a/README_Windows.txt b/README_Windows.txt deleted file mode 100644 index 0ad13a7..0000000 --- a/README_Windows.txt +++ /dev/null @@ -1,50 +0,0 @@ -Notes for Windows Users -======================= - -See http://ipython.scipy.org/moin/IpythonOnWindows for up-to-date information -about running IPython on Windows. - - -Requirements ------------- - -IPython runs under (as far as the Windows family is concerned): - -- Windows XP, 2000 (and probably WinNT): works well. It needs: - - * PyWin32: http://sourceforge.net/projects/pywin32/ - - * PyReadline: http://ipython.scipy.org/moin/PyReadline/Intro - - * If you are using Python2.4, this in turn requires Tomas Heller's ctypes - from: http://starship.python.net/crew/theller/ctypes (not needed for Python - 2.5 users, since 2.5 already ships with ctypes). - -- Windows 95/98/ME: I have no idea. It should work, but I can't test. - -- CygWin environments should work, they are basically Posix. - -It needs Python 2.3 or newer. - - -Installation ------------- - -Double-click the supplied .exe installer file. If all goes well, that's all -you need to do. You should now have an IPython entry in your Start Menu. - - -Installation from source distribution -------------------------------------- - -In case the automatic installer does not work for some reason, you can -download the ipython-XXX.tar.gz file, which contains the full IPython source -distribution (the popular WinZip can read .tar.gz files). - -After uncompressing the archive, you can install it at a command terminal just -like any other Python module, by using python setup.py install'. After this -completes, you can run the supplied win32_manual_post_install.py script which -will add the relevant shortcuts to your startup menu. - -Optionally, you may skip installation altogether and just launch "ipython.py" -from the root folder of the extracted source distribution. diff --git a/docs/source/overview.txt b/docs/source/overview.txt index 6ac308d..9ee38cb 100644 --- a/docs/source/overview.txt +++ b/docs/source/overview.txt @@ -14,7 +14,7 @@ However, the interpreter supplied with the standard Python distribution is somewhat limited for extended interactive use. The goal of IPython is to create a comprehensive environment for -interactive and exploratory computing. To support, this goal, IPython +interactive and exploratory computing. To support this goal, IPython has two main components: * An enhanced interactive Python shell. diff --git a/IPython/config/config.py b/sandbox/config.py similarity index 100% rename from IPython/config/config.py rename to sandbox/config.py diff --git a/IPython/config/tests/sample_config.py b/sandbox/sample_config.py similarity index 100% rename from IPython/config/tests/sample_config.py rename to sandbox/sample_config.py diff --git a/IPython/config/tests/test_config.py b/sandbox/test_config.py similarity index 100% rename from IPython/config/tests/test_config.py rename to sandbox/test_config.py diff --git a/IPython/config/traitlets.py b/sandbox/traitlets.py similarity index 100% rename from IPython/config/traitlets.py rename to sandbox/traitlets.py diff --git a/tools/compile.py b/tools/compile.py new file mode 100644 index 0000000..4a08400 --- /dev/null +++ b/tools/compile.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +"""Call the compile script to check that all code we ship compiles correctly. +""" + +import os +import sys + + +vstr = '.'.join(map(str,sys.version_info[:2])) + +stat = os.system('python %s/lib/python%s/compileall.py .' % (sys.prefix,vstr)) + +print +if stat: + print '*** THERE WAS AN ERROR! ***' + print 'See messages above for the actual file that produced it.' +else: + print 'OK' + +sys.exit(stat)