From: <cg...@us...> - 2007-07-15 05:10:02
|
Revision: 3298 http://svn.sourceforge.net/jython/?rev=3298&view=rev Author: cgroves Date: 2007-07-14 22:09:58 -0700 (Sat, 14 Jul 2007) Log Message: ----------- merge -r 3261:3284 and merge -r 3285:HEAD sans version changes to build.xml and PySystemState.java Modified Paths: -------------- branches/2.3/Lib/select.py branches/2.3/Lib/socket.py branches/2.3/Lib/test/output/test_socket branches/2.3/Lib/test/test_select.py branches/2.3/Lib/test/test_socket.py branches/2.3/NEWS branches/2.3/README.txt branches/2.3/bugtests/test001.py branches/2.3/bugtests/test258.py branches/2.3/src/org/python/core/Py.java branches/2.3/src/org/python/core/PySystemState.java branches/2.3/src/org/python/core/imp.java branches/2.3/src/org/python/modules/errno.java branches/2.3/src/org/python/parser/TreeBuilder.java branches/2.3/src/org/python/util/jython.java Added Paths: ----------- branches/2.3/Lib/test/test_poll.py branches/2.3/bugtests/test400/ branches/2.3/bugtests/test400/x/ branches/2.3/bugtests/test400/x/__init__.py branches/2.3/bugtests/test400.py Removed Paths: ------------- branches/2.3/bugtests/test400/x/ branches/2.3/bugtests/test400/x/__init__.py Modified: branches/2.3/Lib/select.py =================================================================== --- branches/2.3/Lib/select.py 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/Lib/select.py 2007-07-15 05:09:58 UTC (rev 3298) @@ -9,8 +9,33 @@ import socket +try: + import errno + ERRNO_EINVAL = errno.EINVAL + ERRNO_ENOTSOCK = errno.ENOTSOCK + ERRNO_ESOCKISBLOCKING = errno.ESOCKISBLOCKING +except ImportError: + ERRNO_EINVAL = 22 + ERRNO_ENOTSOCK = 88 + ERRNO_ESOCKISBLOCKING = 20000 + class error(Exception): pass +ALL = None + +_exception_map = { + +# (<javaexception>, <circumstance>) : lambda: <code that raises the python equivalent> + +(java.nio.channels.IllegalBlockingModeException, ALL) : lambda exc: error(ERRNO_ESOCKISBLOCKING, 'socket must be in non-blocking mode'), +} + +def _map_exception(exc, circumstance=ALL): + try: + return _exception_map[(exc.__class__, circumstance)](exc) + except KeyError: + return error(-1, 'Unmapped java exception: %s' % exc.toString()) + POLLIN = 1 POLLOUT = 2 @@ -37,7 +62,7 @@ return socket_object.getchannel() except: return None - raise error("Object '%s' is not watchable" % socket_object, 10038) + raise error("Object '%s' is not watchable" % socket_object, ERRNO_ENOTSOCK) def _register_channel(self, socket_object, channel, mask): jmask = 0 @@ -65,49 +90,66 @@ self.unconnected_sockets = temp_list def register(self, socket_object, mask = POLLIN|POLLOUT|POLLPRI): - channel = self._getselectable(socket_object) - if channel is None: - # The socket is not yet connected, and thus has no channel - # Add it to a pending list, and return - self.unconnected_sockets.append( (socket_object, mask) ) - return - self._register_channel(socket_object, channel, mask) + try: + channel = self._getselectable(socket_object) + if channel is None: + # The socket is not yet connected, and thus has no channel + # Add it to a pending list, and return + self.unconnected_sockets.append( (socket_object, mask) ) + return + self._register_channel(socket_object, channel, mask) + except java.lang.Exception, jlx: + raise _map_exception(jlx) def unregister(self, socket_object): - channel = self._getselectable(socket_object) - self.chanmap[channel][1].cancel() - del self.chanmap[channel] + try: + channel = self._getselectable(socket_object) + self.chanmap[channel][1].cancel() + del self.chanmap[channel] + except java.lang.Exception, jlx: + raise _map_exception(jlx) - def _dopoll(self, timeout=None): + def _dopoll(self, timeout): if timeout is None or timeout < 0: self.selector.select() - elif timeout == 0: - self.selector.selectNow() else: - # No multiplication required: both cpython and java use millisecond timeouts - self.selector.select(timeout) + try: + timeout = int(timeout) + if timeout == 0: + self.selector.selectNow() + else: + # No multiplication required: both cpython and java use millisecond timeouts + self.selector.select(timeout) + except ValueError, vx: + raise error("poll timeout must be a number of milliseconds or None", ERRNO_EINVAL) # The returned selectedKeys cannot be used from multiple threads! return self.selector.selectedKeys() def poll(self, timeout=None): - self._check_unconnected_sockets() - selectedkeys = self._dopoll(timeout) - results = [] - for k in selectedkeys.iterator(): - jmask = k.readyOps() - pymask = 0 - if jmask & OP_READ: pymask |= POLLIN - if jmask & OP_WRITE: pymask |= POLLOUT - if jmask & OP_ACCEPT: pymask |= POLLIN - if jmask & OP_CONNECT: pymask |= POLLOUT - # Now return the original userobject, and the return event mask - results.append( (self.chanmap[k.channel()][0], pymask) ) - return results + try: + self._check_unconnected_sockets() + selectedkeys = self._dopoll(timeout) + results = [] + for k in selectedkeys.iterator(): + jmask = k.readyOps() + pymask = 0 + if jmask & OP_READ: pymask |= POLLIN + if jmask & OP_WRITE: pymask |= POLLOUT + if jmask & OP_ACCEPT: pymask |= POLLIN + if jmask & OP_CONNECT: pymask |= POLLOUT + # Now return the original userobject, and the return event mask + results.append( (self.chanmap[k.channel()][0], pymask) ) + return results + except java.lang.Exception, jlx: + raise _map_exception(jlx) def close(self): - for k in self.selector.keys(): - k.cancel() - self.selector.close() + try: + for k in self.selector.keys(): + k.cancel() + self.selector.close() + except java.lang.Exception, jlx: + raise _map_exception(jlx) def _calcselecttimeoutvalue(value): if value is None: @@ -117,7 +159,7 @@ except Exception, x: raise TypeError("Select timeout value must be a number or None") if value < 0: - raise error("Select timeout value cannot be negative", 10022) + raise error("Select timeout value cannot be negative", ERRNO_EINVAL) if floatvalue < 0.000001: return 0 return int(floatvalue * 1000) # Convert to milliseconds Modified: branches/2.3/Lib/socket.py =================================================================== --- branches/2.3/Lib/socket.py 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/Lib/socket.py 2007-07-15 05:09:58 UTC (rev 3298) @@ -35,26 +35,30 @@ import java.net.InetSocketAddress import java.net.Socket import java.net.SocketTimeoutException +import java.net.UnknownHostException import java.nio.ByteBuffer import java.nio.channels.DatagramChannel import java.nio.channels.IllegalBlockingModeException import java.nio.channels.ServerSocketChannel import java.nio.channels.SocketChannel +import java.nio.channels.UnresolvedAddressException import javax.net.ssl.SSLSocketFactory import org.python.core.PyFile try: import errno - ERRNO_EWOULDBLOCK = errno.EWOULDBLOCK - ERRNO_EACCES = errno.EACCES - ERRNO_ECONNREFUSED = errno.ECONNREFUSED - ERRNO_EINPROGRESS = errno.EINPROGRESS + ERRNO_EWOULDBLOCK = errno.EWOULDBLOCK + ERRNO_EACCES = errno.EACCES + ERRNO_ECONNREFUSED = errno.ECONNREFUSED + ERRNO_EINPROGRESS = errno.EINPROGRESS + ERRNO_EGETADDRINFOFAILED = errno.EGETADDRINFOFAILED except ImportError: # Support jython 2.1 - ERRNO_EWOULDBLOCK = 11 - ERRNO_EACCES = 13 - ERRNO_ECONNREFUSED = 111 - ERRNO_EINPROGRESS = 115 + ERRNO_EWOULDBLOCK = 11 + ERRNO_EACCES = 13 + ERRNO_ECONNREFUSED = 111 + ERRNO_EINPROGRESS = 115 + ERRNO_EGETADDRINFOFAILED = 20001 class error(Exception): pass class herror(error): pass @@ -63,31 +67,28 @@ ALL = None -exception_map = { +_exception_map = { # (<javaexception>, <circumstance>) : lambda: <code that raises the python equivalent> (java.io.InterruptedIOException, ALL) : lambda exc: timeout('timed out'), (java.net.BindException, ALL) : lambda exc: error(ERRNO_EACCES, 'Permission denied'), -(java.net.ConnectException, ALL) : lambda exc: error( (ERRNO_ECONNREFUSED, 'Connection refused') ), +(java.net.ConnectException, ALL) : lambda exc: error(ERRNO_ECONNREFUSED, 'Connection refused'), (java.net.SocketTimeoutException, ALL) : lambda exc: timeout('timed out'), +(java.net.UnknownHostException, ALL) : lambda exc: gaierror(ERRNO_EGETADDRINFOFAILED, 'getaddrinfo failed'), +(java.nio.channels.UnresolvedAddressException, ALL) : lambda exc: gaierror(ERRNO_EGETADDRINFOFAILED, 'getaddrinfo failed'), } def would_block_error(exc=None): return error( (ERRNO_EWOULDBLOCK, 'The socket operation could not complete without blocking') ) -def map_exception(exc, circumstance=ALL): +def _map_exception(exc, circumstance=ALL): try: -# print "Mapping exception: %s" % str(exc) - return exception_map[(exc.__class__, circumstance)](exc) + return _exception_map[(exc.__class__, circumstance)](exc) except KeyError: - return error('Unmapped java exception: %s' % exc.toString()) + return error(-1, 'Unmapped java exception: %s' % exc.toString()) -exception_map.update({ - (java.nio.channels.IllegalBlockingModeException, ALL) : would_block_error, - }) - MODE_BLOCKING = 'block' MODE_NONBLOCKING = 'nonblock' MODE_TIMEOUT = 'timeout' @@ -125,8 +126,8 @@ if self.mode == MODE_NONBLOCKING: self.jchannel.configureBlocking(0) if self.mode == MODE_TIMEOUT: - # self.channel.configureBlocking(0) - self.jsocket.setSoTimeout(int(timeout*1000)) + self._timeout_millis = int(timeout*1000) + self.jsocket.setSoTimeout(self._timeout_millis) def close1(self): self.jsocket.close() @@ -175,7 +176,10 @@ def connect(self, host, port): self.host = host self.port = port - self.jchannel.connect(java.net.InetSocketAddress(self.host, self.port)) + if self.mode == MODE_TIMEOUT: + self.jsocket.connect(java.net.InetSocketAddress(self.host, self.port), self._timeout_millis) + else: + self.jchannel.connect(java.net.InetSocketAddress(self.host, self.port)) def finish_connect(self): return self.jchannel.finishConnect() @@ -208,7 +212,7 @@ new_cli_sock = self.jsocket.accept() return _client_socket_impl(new_cli_sock) except java.lang.Exception, jlx: - raise map_exception(jlx) + raise _map_exception(jlx) def close(self): _nio_impl.close(self) @@ -284,10 +288,16 @@ return name def gethostname(): - return java.net.InetAddress.getLocalHost().getHostName() + try: + return java.net.InetAddress.getLocalHost().getHostName() + except java.lang.Exception, jlx: + raise _map_exception(jlx) def gethostbyname(name): - return java.net.InetAddress.getByName(name).getHostAddress() + try: + return java.net.InetAddress.getByName(name).getHostAddress() + except java.lang.Exception, jlx: + raise _map_exception(jlx) def gethostbyaddr(name): names, addrs = _gethostbyaddr(name) @@ -433,7 +443,7 @@ self.sock_impl = _server_socket_impl(host, port, backlog, self.reuse_addr) self._config() except java.lang.Exception, jlx: - raise map_exception(jlx) + raise _map_exception(jlx) # # The following has information on a java.lang.NullPointerException problem I'm having @@ -453,7 +463,7 @@ cliconn._setup(new_sock) return cliconn, new_sock.getpeername() except java.lang.Exception, jlx: - raise map_exception(jlx) + raise _map_exception(jlx) def _get_host_port(self, addr): host, port = _unpack_address_tuple(addr) @@ -471,9 +481,8 @@ self.sock_impl.bind(bind_host, bind_port) self._config() # Configure timeouts, etc, now that the socket exists self.sock_impl.connect(host, port) - self._setup(self.sock_impl) except java.lang.Exception, jlx: - raise map_exception(jlx) + raise _map_exception(jlx) def connect(self, addr): "This signifies a client socket" @@ -510,7 +519,7 @@ data = data[:m] return data.tostring() except java.lang.Exception, jlx: - raise map_exception(jlx) + raise _map_exception(jlx) def recvfrom(self, n): return self.recv(n), None @@ -702,7 +711,7 @@ bytes = bytes[:m] return bytes.tostring(), (host, port) except java.lang.Exception, jlx: - raise map_exception(jlx) + raise _map_exception(jlx) def recv(self, n): try: @@ -715,7 +724,7 @@ bytes = bytes[:m] return bytes.tostring() except java.lang.Exception, jlx: - raise map_exception(jlx) + raise _map_exception(jlx) def getsockname(self): assert self.sock_impl Modified: branches/2.3/Lib/test/output/test_socket =================================================================== --- branches/2.3/Lib/test/output/test_socket 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/Lib/test/output/test_socket 2007-07-15 05:09:58 UTC (rev 3298) @@ -1,2 +1 @@ test_socket -socket.error Copied: branches/2.3/Lib/test/test_poll.py (from rev 3264, trunk/jython/Lib/test/test_poll.py) =================================================================== --- branches/2.3/Lib/test/test_poll.py (rev 0) +++ branches/2.3/Lib/test/test_poll.py 2007-07-15 05:09:58 UTC (rev 3298) @@ -0,0 +1,3 @@ +from test_support import TestSkipped + +raise TestSkipped, 'test_poll currently not supported in Jython' Modified: branches/2.3/Lib/test/test_select.py =================================================================== --- branches/2.3/Lib/test/test_select.py 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/Lib/test/test_select.py 2007-07-15 05:09:58 UTC (rev 3298) @@ -7,7 +7,9 @@ except NameError: class object: pass -import socket, select +import errno +import select +import socket import os import sys @@ -116,55 +118,65 @@ self.failIf(s in rfd) self.failIf(s in wfd) -def check_server_running_on_localhost_port(port_number): - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - s.connect( ('localhost', port_number) ) - s.close() - except: - return 0 - return 1 - class TestPollClientSocket(unittest.TestCase): def testEventConstants(self): for event_name in ['IN', 'OUT', 'PRI', 'ERR', 'HUP', 'NVAL', ]: self.failUnless(hasattr(select, 'POLL%s' % event_name)) + def testUnregisterRaisesKeyError(self): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + poll_object = select.poll() + try: + poll_object.unregister(s) + except KeyError: + pass + else: + self.fail("Unregistering socket that is not registered should have raised KeyError") + +# +# using the test_socket thread based server/client management, for convenience. +# + +import test_socket + +class ThreadedPollClientSocket(test_socket.ThreadedTCPSocketTest): + def testSocketRegisteredBeforeConnected(self): - # You MUST be running a server on port 80 for this one to work - if not check_server_running_on_localhost_port(80): - print "Unable to run testSocketRegisteredBeforeConnected: no server on port 80" - return - sockets = [socket.socket(socket.AF_INET, socket.SOCK_STREAM) for x in range(5)] - timeout = 1 # Can't wait forever + self.cli_conn = self.serv.accept() + + def _testSocketRegisteredBeforeConnected(self): + timeout = 1000 # milliseconds poll_object = select.poll() - for s in sockets: - # Register the sockets before they are connected - poll_object.register(s, select.POLLOUT) + # Register the socket before it is connected + poll_object.register(self.cli, select.POLLOUT) result_list = poll_object.poll(timeout) result_sockets = [r[0] for r in result_list] - for s in sockets: - self.failIf(s in result_sockets) - # Now connect the sockets, but DO NOT register them again - for s in sockets: - s.setblocking(0) - s.connect( ('localhost', 80) ) - # Now poll again, to see if the poll object has recognised that the sockets are now connected + self.failIf(self.cli in result_sockets, "Unconnected client socket should not have been selectable") + # Now connect the socket, but DO NOT register it again + self.cli.setblocking(0) + self.cli.connect( (test_socket.HOST, test_socket.PORT) ) + # Now poll again, to check that the poll object has recognised that the socket is now connected result_list = poll_object.poll(timeout) result_sockets = [r[0] for r in result_list] - for s in sockets: - self.failUnless(s in result_sockets) + self.failUnless(self.cli in result_sockets, "Connected client socket should have been selectable") - def testUnregisterRaisesKeyError(self): - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + def testSocketMustBeNonBlocking(self): + self.cli_conn = self.serv.accept() + + def _testSocketMustBeNonBlocking(self): + self.cli.setblocking(1) + self.cli.connect( (test_socket.HOST, test_socket.PORT) ) + timeout = 1000 # milliseconds poll_object = select.poll() try: - poll_object.unregister(s) - except KeyError: - pass + poll_object.register(self.cli) + except select.error, se: + self.failUnlessEqual(se[0], errno.ESOCKISBLOCKING) + except Exception, x: + self.fail("Registering blocking socket should have raised select.error, not %s" % str(x)) else: - self.fail("Unregistering socket that is not registered should have raised KeyError") + self.fail("Registering blocking socket should have raised select.error") class TestPipes(unittest.TestCase): @@ -202,6 +214,7 @@ TestSelectInvalidParameters, TestSelectClientSocket, TestPollClientSocket, + ThreadedPollClientSocket, ] if sys.platform[:4] != 'java': tests.append(TestPipes) Modified: branches/2.3/Lib/test/test_socket.py =================================================================== --- branches/2.3/Lib/test/test_socket.py 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/Lib/test/test_socket.py 2007-07-15 05:09:58 UTC (rev 3298) @@ -7,6 +7,7 @@ import unittest #from test import test_support +import errno import socket import select import time @@ -710,7 +711,7 @@ def _testConnectWithLocalBind(self): # Testing blocking connect with local bind - self.cli.settimeout(10) + self.cli.settimeout(1) self.cli.bind( (HOST, PORT-1) ) self.cli.connect((HOST, PORT)) bound_host, bound_port = self.cli.getsockname() @@ -885,6 +886,22 @@ if not ok: self.fail("accept() returned success when we did not expect it") +class TCPClientTimeoutTest(ThreadedTCPSocketTest): + + def testTCPClientTimeout(self): + pass # i.e. do not accept + + def _testTCPClientTimeout(self): + try: + self.cli.settimeout(0.1) + self.cli.connect( (HOST, PORT) ) + except socket.timeout, st: + pass + except Exception, x: + self.fail("Client socket timeout should have raised socket.timeout, not %s" % str(x)) + else: + self.fail("Client socket timeout should have raised socket.timeout") + # # AMAK: 20070307 # Corrected the superclass of UDPTimeoutTest @@ -921,6 +938,59 @@ self.assert_(issubclass(socket.gaierror, socket.error)) self.assert_(issubclass(socket.timeout, socket.error)) +class TestJythonExceptions(unittest.TestCase): + + def testHostNotFound(self): + try: + socket.gethostbyname("doesnotexist") + except socket.gaierror, gaix: + self.failUnlessEqual(gaix[0], errno.EGETADDRINFOFAILED) + except Exception, x: + self.fail("Get host name for non-existent host raised wrong exception: %s" % x) + + def testConnectionRefused(self): + try: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + # This port should not be open at this time + s.connect( (HOST, PORT) ) + except socket.error, se: + self.failUnlessEqual(se[0], errno.ECONNREFUSED) + except Exception, x: + self.fail("Connection to non-existent host/port raised wrong exception: %s" % x) + else: + self.fail("Socket (%s,%s) should not have been listening at this time" % (HOST, PORT)) + + def testBindException(self): + # First bind to the target port + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind( (HOST, PORT) ) + s.listen() + try: + try: + # And then try to bind again + t = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + t.bind( (HOST, PORT) ) + t.listen() + except socket.error, se: + self.failUnlessEqual(se[0], errno.EACCES) + except Exception, x: + self.fail("Binding to already bound host/port raised wrong exception: %s" % x) + else: + self.fail("Binding to already bound host/port should have raised exception") + finally: + s.close() + + def testUnresolvedAddress(self): + try: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect( ('non.existent.server', PORT) ) + except socket.gaierror, gaix: + self.failUnlessEqual(gaix[0], errno.EGETADDRINFOFAILED) + except Exception, x: + self.fail("Get host name for non-existent host raised wrong exception: %s" % x) + else: + self.fail("Get host name for non-existent host should have raised exception") + class TestAddressParameters: def testBindNonTupleEndpointRaisesTypeError(self): @@ -962,6 +1032,7 @@ GeneralModuleTests, BasicTCPTest, TCPTimeoutTest, + TCPClientTimeoutTest, TestExceptions, TestTCPAddressParameters, TestUDPAddressParameters, @@ -976,6 +1047,8 @@ ] if hasattr(socket, "socketpair"): tests.append(BasicSocketPairTest) + if sys.platform[:4] == 'java': + tests.append(TestJythonExceptions) suites = [unittest.makeSuite(klass, 'test') for klass in tests] main_suite = unittest.TestSuite(suites) runner = unittest.TextTestRunner(verbosity=100) Modified: branches/2.3/NEWS =================================================================== --- branches/2.3/NEWS 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/NEWS 2007-07-15 05:09:58 UTC (rev 3298) @@ -1,11 +1,34 @@ Jython NEWS +Jython 2.2 rc2 + Bugs fixed + - [ 931129 ] jython -jar some-path/test.jar fails + - [ 1719528 ] -c doesn't put the empty string in sys.path + - [ 1746957 ] Weird 'uu' prefix for unicode + - [ 1747092 ] Failed imports should not be "cached" + - [ 1742770 ] urllib.urlopen('http://inv') -> UnknownHostException + - [ 1745068 ] select gives confusing message when given blocking sockets + - [ 1744775 ] umlauts displayed incorrectly in installer + - timeouts on socket client connects were not being honoured + - a float could not be passed as milliseconds to select.poll.poll + Jython 2.2 rc1 + New features + - Completely rewritten socket module and new select module using java.nio + which allows the use of SSL and non-blocking sockets. + - Explicit imports of Java classes like 'from java.net import URL' or + 'import java.net.URL' work with package scanning disabled. Bugs fixed - [ 1708080 ] float("1d") -> 1.0 (not ValueError as expected) - [ 1661700 ] os.path.abspath raises IOException if drive not accessible - [ 1662689 ] os.path.abspath eliminates symlinks - [ 1717498 ] os.path.splitdrive does nothing for Windows drives + - [ 1622207 ] _weakref.ref(o) only works if the argument is hasheable + - [ 1735864 ] Parser not threadsafe + - [ 1722306 ] OverflowError in UDP Socket Implementation + - [ 1348645 ] socket.py send() requires too many arguments + - [ 998602 ] urllib : https request does not work + - [ 621180 ] module socket _udpsocket close bug Jython 2.2 beta2 New features Modified: branches/2.3/README.txt =================================================================== --- branches/2.3/README.txt 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/README.txt 2007-07-15 05:09:58 UTC (rev 3298) @@ -1,7 +1,7 @@ -Welcome to Jython 2.2b2 +Welcome to Jython 2.2rc2 ======================= -This is the second beta release towards the 2.2 version of Jython. It +This is the second release candidate of the 2.2 version of Jython. It contains all of the new features for the 2.2 release: - new-style classes - Java List integration @@ -11,18 +11,20 @@ - __future__ division - support for running on modern JVMs - a new installer + - ssl and non-blocking support for socket -In addition to these major features, many bugs have been fixed from 2.2b1. See -the NEWS file for a more complete list of changes. +In addition to these major features, several bugs have been fixed from 2.2rc1. +See the NEWS file for a more complete list of changes. -The release was compiled on Windows XP with JDK 6 but it should run on +The release was compiled on Mac OS X with JDK 5 but it should run on 1.4.2+. -This release exists to solicit feedback about any bugs or missing -features; if you can provide it, it is greatly appreciated. Bug -reports can be created at http://jython.org/bugs whereas more general -questions can be sent to the Jython-dev mailing list, -jy...@li.... +This release is intended to find any major bugs before releasing 2.2. If none +are found, this will become the 2.2 release. If you can run this and check for +bugs, it will be greatly appreciated. Bug reports can be created at +http://jython.org/bugs whereas more general questions can be sent to the +Jython-users mailing list, jyt...@li.... -The current plan calls for a release candiate in a few weeks, and if it proves -stable, the final release of 2.2 a few weeks after that. +If this release proves stable, the final release of 2.2 will be in a couple +weeks. If not, successive release candidates will be made until all the major +bugs are ironed out. Modified: branches/2.3/bugtests/test001.py =================================================================== --- branches/2.3/bugtests/test001.py 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/bugtests/test001.py 2007-07-15 05:09:58 UTC (rev 3298) @@ -11,5 +11,5 @@ support.compare(str(v.size), "<java function size") -if type(v.size) != BuiltinFunctionType: - raise support.TestError('Wrong type for v.size' + `type(v.size)`) +if not callable(v.size): + raise support.TestError('v.size should be callable') Modified: branches/2.3/bugtests/test258.py =================================================================== --- branches/2.3/bugtests/test258.py 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/bugtests/test258.py 2007-07-15 05:09:58 UTC (rev 3298) @@ -8,7 +8,7 @@ import sys -if not sys.modules.has_key('test258m1'): - raise support.TestError, "Module should exists in sys.modules" +if sys.modules.has_key('test258m1'): + raise support.TestError, "Module should not exist in sys.modules" Copied: branches/2.3/bugtests/test400 (from rev 3297, trunk/jython/bugtests/test400) Copied: branches/2.3/bugtests/test400/x (from rev 3297, trunk/jython/bugtests/test400/x) Deleted: branches/2.3/bugtests/test400/x/__init__.py =================================================================== Copied: branches/2.3/bugtests/test400/x/__init__.py (from rev 3297, trunk/jython/bugtests/test400/x/__init__.py) =================================================================== Copied: branches/2.3/bugtests/test400.py (from rev 3297, trunk/jython/bugtests/test400.py) =================================================================== --- branches/2.3/bugtests/test400.py (rev 0) +++ branches/2.3/bugtests/test400.py 2007-07-15 05:09:58 UTC (rev 3298) @@ -0,0 +1,10 @@ +import support + +try: + import x + raise support.TestError, "x shouldn't be on sys.path until after this" +except: + pass +import sys +sys.path.append('test400') +import x Modified: branches/2.3/src/org/python/core/Py.java =================================================================== --- branches/2.3/src/org/python/core/Py.java 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/src/org/python/core/Py.java 2007-07-15 05:09:58 UTC (rev 3298) @@ -1556,20 +1556,32 @@ * @see ClassicPyObjectAdapter - default PyObjectAdapter type */ public static PyObject java2py(Object o) { - return adapter.adapt(o); + return getAdapter().adapt(o); } /** * @return the ExtensiblePyObjectAdapter used by java2py. */ public static ExtensiblePyObjectAdapter getAdapter(){ + if(adapter == null) { + adapter = new ClassicPyObjectAdapter(); + } return adapter; } + /** + * Set the ExtensiblePyObjectAdapter used by java2py. + * + * @param adapter The new ExtensiblePyObjectAdapter + */ + protected static void setAdapter(ExtensiblePyObjectAdapter adapter) { + Py.adapter = adapter; + } + /** * Handles wrapping Java objects in PyObject to expose them to jython. */ - protected static ExtensiblePyObjectAdapter adapter; + private static ExtensiblePyObjectAdapter adapter; public static PyObject makeClass(String name, PyObject[] bases, PyCode code, PyObject doc) Modified: branches/2.3/src/org/python/core/PySystemState.java =================================================================== --- branches/2.3/src/org/python/core/PySystemState.java 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/src/org/python/core/PySystemState.java 2007-07-15 05:09:58 UTC (rev 3298) @@ -459,7 +459,7 @@ } initialized = true; - Py.adapter = adapter; + Py.setAdapter(adapter); boolean standalone = false; String jarFileName = getJarFileName(); if (jarFileName != null) { Modified: branches/2.3/src/org/python/core/imp.java =================================================================== --- branches/2.3/src/org/python/core/imp.java 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/src/org/python/core/imp.java 2007-07-15 05:09:58 UTC (rev 3298) @@ -233,8 +233,13 @@ if (c instanceof PyTableCode) { code = (PyTableCode) c; } - PyFrame f = new PyFrame(code, module.__dict__, module.__dict__, null); - code.call(f); + try { + PyFrame f = new PyFrame(code, module.__dict__, module.__dict__, null); + code.call(f); + } catch (RuntimeException t) { + Py.getSystemState().modules.__delitem__(name.intern()); + throw t; + } if(moduleLocation != null) { module.__setattr__("__file__", new PyString(moduleLocation)); @@ -651,13 +656,14 @@ } else { firstName = name.substring(0, dot); } - StringBuffer parentNameBuffer = new StringBuffer( - pkgMod != null ? pkgName : ""); + StringBuffer parentNameBuffer = new StringBuffer(pkgMod != null ? pkgName : ""); PyObject topMod = import_next(pkgMod, parentNameBuffer, firstName, name, fromlist); if (topMod == Py.None || topMod == null) { - if (topMod == null) { - modules.__setitem__(parentNameBuffer.toString().intern(), - Py.None); + // Add None to sys.modules for submodule or subpackage names that aren't found, but + // leave top-level entries out. This allows them to be tried again if another + // import attempt is made after they've been added to sys.path. + if (topMod == null && pkgMod != null) { + modules.__setitem__(parentNameBuffer.toString().intern(), Py.None); } parentNameBuffer = new StringBuffer(""); // could throw ImportError Modified: branches/2.3/src/org/python/modules/errno.java =================================================================== --- branches/2.3/src/org/python/modules/errno.java 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/src/org/python/modules/errno.java 2007-07-15 05:09:58 UTC (rev 3298) @@ -137,6 +137,10 @@ public static final int EREMOTEIO = 121; public static final int EDQUOT = 122; + // AMAK: Starting a new series of jython specific error numbers + public static final int ESOCKISBLOCKING = 20000; + public static final int EGETADDRINFOFAILED = 20001; + public static final PyObject errorcode = new PyDictionary(); private static final PyObject strerror = new PyDictionary(); @@ -264,6 +268,9 @@ addcode(dict, EREMOTEIO, "EREMOTEIO", "Remote I/O error"); addcode(dict, EDQUOT, "EDQUOT", "Disk quota exceeded"); + // AMAK: starting a new series of jython specific errors + addcode(dict, ESOCKISBLOCKING, "ESOCKISBLOCKING", "Socket is in blocking mode"); + addcode(dict, EGETADDRINFOFAILED, "EGETADDRINFOFAILED", "getaddrinfo failed"); } public static PyObject strerror(PyObject error) { Modified: branches/2.3/src/org/python/parser/TreeBuilder.java =================================================================== --- branches/2.3/src/org/python/parser/TreeBuilder.java 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/src/org/python/parser/TreeBuilder.java 2007-07-15 05:09:58 UTC (rev 3298) @@ -86,7 +86,21 @@ return nodes[id]; } - + /** + * @return the image of the SimpleNode as a String, not throwing a NullPointerException when image is null + * @param n The SimpleNode + */ + public static String getImageAsString(SimpleNode n) { + String imageAsString; + Object image = n.getImage(); + if (image == null) { + imageAsString = "Incomplete node"; + } else { + imageAsString = image.toString(); + } + return imageAsString; + } + public SimpleNode closeNode(SimpleNode n, int arity) throws Exception { exprType value; exprType[] exprs; @@ -102,13 +116,13 @@ return new Expression(makeExpr()); case JJTNAME: - return new Name(n.getImage().toString(), Name.Load); + return new Name(getImageAsString(n), Name.Load); case JJTNUM: return new Num((PyObject) n.getImage()); case JJTSTRING: - return new Str(n.getImage().toString()); + return new Str(getImageAsString(n)); case JJTUNICODE: - return new Unicode(n.getImage().toString()); + return new Unicode(getImageAsString(n)); case JJTSUITE: stmtType[] stmts = new stmtType[arity]; Modified: branches/2.3/src/org/python/util/jython.java =================================================================== --- branches/2.3/src/org/python/util/jython.java 2007-07-14 03:23:56 UTC (rev 3297) +++ branches/2.3/src/org/python/util/jython.java 2007-07-15 05:09:58 UTC (rev 3298) @@ -47,6 +47,15 @@ throw Py.ValueError("jar file missing '__run__.py'"); PyStringMap locals = new PyStringMap(); + + // Stripping the stuff before the last File.separator fixes Bug + // #931129 by keeping illegal characters out of the generated + // proxy class name + int beginIndex; + if ((beginIndex = filename.lastIndexOf(File.separator)) != -1) { + filename = filename.substring(beginIndex + 1); + } + locals.__setitem__("__name__", new PyString(filename)); locals.__setitem__("zipfile", Py.java2py(zip)); @@ -159,14 +168,6 @@ } } - if (opts.command != null) { - try { - interp.exec(opts.command); - } catch (Throwable t) { - Py.printException(t); - } - } - // was there a filename on the command line? if (opts.filename != null) { String path = new java.io.File(opts.filename).getParent(); @@ -204,6 +205,14 @@ // was given, sys.path[0] will have gotten filled in with the // dir of the argument filename. Py.getSystemState().path.insert(0, new PyString("")); + + if (opts.command != null) { + try { + interp.exec(opts.command); + } catch (Throwable t) { + Py.printException(t); + } + } } if (opts.interactive) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |