From: <pj...@us...> - 2008-07-17 00:29:55
|
Revision: 4957 http://jython.svn.sourceforge.net/jython/?rev=4957&view=rev Author: pjenvey Date: 2008-07-17 00:29:54 +0000 (Thu, 17 Jul 2008) Log Message: ----------- allow passing unicode hostnames to socket.connect Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2008-07-16 02:13:48 UTC (rev 4956) +++ trunk/jython/Lib/socket.py 2008-07-17 00:29:54 UTC (rev 4957) @@ -639,11 +639,17 @@ # which include flowinfo and scope_id. # To be upgraded in synch with getaddrinfo error_message = "Address must be a tuple of (hostname, port)" - if type(address_tuple) is not type( () ) \ - or type(address_tuple[0]) is not type("") \ - or type(address_tuple[1]) is not type(0): + if not isinstance(address_tuple, tuple) or \ + not isinstance(address_tuple[0], basestring) or \ + not isinstance(address_tuple[1], (int, long)): raise TypeError(error_message) - hostname = address_tuple[0].strip() + hostname = address_tuple[0] + if isinstance(hostname, unicode): + # XXX: Should be encode('idna') (See CPython + # socketmodule::getsockaddrarg), but Jython's idna support is + # currently broken + hostname = hostname.encode() + hostname = hostname.strip() if hostname == "<broadcast>": if for_tx: hostname = "255.255.255.255" Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2008-07-16 02:13:48 UTC (rev 4956) +++ trunk/jython/Lib/test/test_socket.py 2008-07-17 00:29:54 UTC (rev 4957) @@ -1436,6 +1436,14 @@ def setUp(self): self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +class UnicodeTest(ThreadedTCPSocketTest): + + def testUnicodeHostname(self): + pass + + def _testUnicodeHostname(self): + self.cli.connect((unicode(HOST), PORT)) + def test_main(): tests = [ GeneralModuleTests, @@ -1457,7 +1465,8 @@ PrivateFileObjectTestCase, UnbufferedFileObjectClassTestCase, LineBufferedFileObjectClassTestCase, - SmallBufferedFileObjectClassTestCase + SmallBufferedFileObjectClassTestCase, + UnicodeTest ] if hasattr(socket, "socketpair"): tests.append(BasicSocketPairTest) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nr...@us...> - 2008-08-29 19:58:09
|
Revision: 5269 http://jython.svn.sourceforge.net/jython/?rev=5269&view=rev Author: nriley Date: 2008-08-29 19:58:06 +0000 (Fri, 29 Aug 2008) Log Message: ----------- Raise ImportError when attempting to import pwd, grp modules on Windows. Fixes test_tarfile. Modified Paths: -------------- trunk/jython/Lib/grp.py trunk/jython/Lib/pwd.py Modified: trunk/jython/Lib/grp.py =================================================================== --- trunk/jython/Lib/grp.py 2008-08-29 19:56:54 UTC (rev 5268) +++ trunk/jython/Lib/grp.py 2008-08-29 19:58:06 UTC (rev 5269) @@ -17,9 +17,12 @@ __all__ = ['getgrgid', 'getgrnam', 'getgrall'] -from os import _posix +from os import _name, _posix from java.lang import NullPointerException +if _name == 'nt': + raise ImportError, 'grp module not supported on Windows' + class struct_group(tuple): """ grp.struct_group: Results from getgr*() routines. Modified: trunk/jython/Lib/pwd.py =================================================================== --- trunk/jython/Lib/pwd.py 2008-08-29 19:56:54 UTC (rev 5268) +++ trunk/jython/Lib/pwd.py 2008-08-29 19:58:06 UTC (rev 5269) @@ -10,9 +10,12 @@ __all__ = ['getpwuid', 'getpwnam', 'getpwall'] -from os import _posix +from os import _name, _posix from java.lang import NullPointerException +if _name == 'nt': + raise ImportError, 'pwd module not supported on Windows' + class struct_passwd(tuple): """ pwd.struct_passwd: Results from getpw*() routines. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2008-09-13 18:10:01
|
Revision: 5324 http://jython.svn.sourceforge.net/jython/?rev=5324&view=rev Author: amak Date: 2008-09-13 18:09:58 +0000 (Sat, 13 Sep 2008) Log Message: ----------- Checking in fixes for 3 bugs http://bugs.jython.org/issue1119 - socket module has no attribute SO_ERROR http://bugs.jython.org/issue1120 - invalid socket shutdown gives AssertionError, should be "transport endpoint not connected" socket.error http://bugs.jython.org/issue1121 - listening socket shutdown expects the wrong kind of socket Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2008-09-13 17:04:58 UTC (rev 5323) +++ trunk/jython/Lib/socket.py 2008-09-13 18:09:58 UTC (rev 5324) @@ -149,7 +149,7 @@ __all__ = ['AF_UNSPEC', 'AF_INET', 'AF_INET6', 'AI_PASSIVE', 'SOCK_DGRAM', 'SOCK_RAW', 'SOCK_RDM', 'SOCK_SEQPACKET', 'SOCK_STREAM', 'SOL_SOCKET', - 'SO_BROADCAST', 'SO_KEEPALIVE', 'SO_LINGER', 'SO_OOBINLINE', + 'SO_BROADCAST', 'SO_ERROR', 'SO_KEEPALIVE', 'SO_LINGER', 'SO_OOBINLINE', 'SO_RCVBUF', 'SO_REUSEADDR', 'SO_SNDBUF', 'SO_TIMEOUT', 'TCP_NODELAY', 'SocketType', 'error', 'herror', 'gaierror', 'timeout', 'getfqdn', 'gethostbyaddr', 'gethostbyname', 'gethostname', @@ -183,6 +183,23 @@ TCP_NODELAY = 256 +# Options with negative constants are not supported +# They are being added here so that code that refers to them +# will not break with an AttributeError + +SO_ACCEPTCONN = -1 +SO_DEBUG = -2 +SO_DONTROUTE = -4 +SO_ERROR = -8 +SO_EXCLUSIVEADDRUSE = -16 +SO_RCVLOWAT = -32 +SO_RCVTIMEO = -64 +SO_REUSEPORT = -128 +SO_SNDLOWAT = -256 +SO_SNDTIMEO = -512 +SO_TYPE = -1024 +SO_USELOOPBACK = -2048 + class _nio_impl: timeout = None @@ -240,12 +257,16 @@ def shutdownInput(self): try: self.jsocket.shutdownInput() + except AttributeError, ax: + raise error(errno.ENOTCONN, "Transport endpoint is not connected") except java.lang.Exception, jlx: raise _map_exception(jlx) def shutdownOutput(self): try: self.jsocket.shutdownOutput() + except AttributeError, ax: + raise error(errno.ENOTCONN, "Transport endpoint is not connected") except java.lang.Exception, jlx: raise _map_exception(jlx) @@ -806,8 +827,9 @@ raise _map_exception(jlx) def shutdown(self, how): + if not self.sock_impl: + raise error(errno.ENOTCONN, "Transport endpoint is not connected") assert how in (SHUT_RD, SHUT_WR, SHUT_RDWR) - assert self.sock_impl if how in (SHUT_RD, SHUT_RDWR): self.sock_impl.shutdownInput() if how in (SHUT_WR, SHUT_RDWR): Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2008-09-13 17:04:58 UTC (rev 5323) +++ trunk/jython/Lib/test/test_socket.py 2008-09-13 18:09:58 UTC (rev 5324) @@ -567,8 +567,10 @@ else: self.fail("Setting unsupported option should have raised an exception") +class TestSupportedOptions(TestSocketOptions): + def testSO_BROADCAST(self): - self.test_udp = 1 ; + self.test_udp = 1 self._testOption(socket.SO_BROADCAST, [0, 1]) def testSO_KEEPALIVE(self): @@ -612,28 +614,49 @@ self.test_tcp_client = 1 self._testOption(socket.TCP_NODELAY, [0, 1]) -class AsYetUnsupportedOptions: +class TestUnsupportedOptions(TestSocketOptions): - def testSO_ACCEPTCONN(self): pass - def testSO_DEBUG(self): pass - def testSO_DONTROUTE(self): pass - def testSO_ERROR(self): pass + def testSO_ACCEPTCONN(self): + self.failUnless(hasattr(socket, 'SO_ACCEPTCONN')) + + def testSO_DEBUG(self): + self.failUnless(hasattr(socket, 'SO_DEBUG')) + + def testSO_DONTROUTE(self): + self.failUnless(hasattr(socket, 'SO_DONTROUTE')) + + def testSO_ERROR(self): + self.failUnless(hasattr(socket, 'SO_ERROR')) + def testSO_EXCLUSIVEADDRUSE(self): # this is an MS specific option that will not be appearing on java # http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6421091 # http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6402335 - pass - def testSO_RCVLOWAT(self): pass - def testSO_RCVTIMEO(self): pass + self.failUnless(hasattr(socket, 'SO_EXCLUSIVEADDRUSE')) + + def testSO_RCVLOWAT(self): + self.failUnless(hasattr(socket, 'SO_RCVLOWAT')) + + def testSO_RCVTIMEO(self): + self.failUnless(hasattr(socket, 'SO_RCVTIMEO')) + def testSO_REUSEPORT(self): # not yet supported on java # http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6432031 - pass - def testSO_SNDLOWAT(self): pass - def testSO_SNDTIMEO(self): pass - def testSO_TYPE(self): pass - def testSO_USELOOPBACK(self): pass + self.failUnless(hasattr(socket, 'SO_REUSEPORT')) + def testSO_SNDLOWAT(self): + self.failUnless(hasattr(socket, 'SO_SNDLOWAT')) + + def testSO_SNDTIMEO(self): + self.failUnless(hasattr(socket, 'SO_SNDTIMEO')) + + def testSO_TYPE(self): + self.failUnless(hasattr(socket, 'SO_TYPE')) + + def testSO_USELOOPBACK(self): + self.failUnless(hasattr(socket, 'SO_USELOOPBACK')) + class BasicTCPTest(SocketConnectedTest): def __init__(self, methodName='runTest'): @@ -1441,15 +1464,43 @@ def _testUnicodeHostname(self): self.cli.connect((unicode(HOST), PORT)) - + +class TestInvalidUsage(unittest.TestCase): + + def setUp(self): + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + def testShutdownIOOnListener(self): + self.socket.listen() # socket is now a server socket + try: + self.socket.shutdown(socket.SHUT_RDWR) + except socket.error, se: + self.failUnlessEqual(se[0], errno.ENOTCONN, "Shutdown on listening socket should have raised errno.ENOTCONN, not %s" % str(se[0])) + except Exception, x: + self.fail("Shutdown on listening socket should have raised socket exception, not %s" % str(x)) + else: + self.fail("Shutdown on listening socket should have raised socket exception") + + def testShutdownOnUnconnectedSocket(self): + try: + self.socket.shutdown(socket.SHUT_RDWR) + except socket.error, se: + self.failUnlessEqual(se[0], errno.ENOTCONN, "Shutdown on unconnected socket should have raised errno.ENOTCONN, not %s" % str(se[0])) + except Exception, x: + self.fail("Shutdown on unconnected socket should have raised socket exception, not %s" % str(x)) + else: + self.fail("Shutdown on unconnected socket should have raised socket exception") + def test_main(): tests = [ GeneralModuleTests, - TestSocketOptions, + TestSupportedOptions, + TestUnsupportedOptions, BasicTCPTest, TCPTimeoutTest, TCPClientTimeoutTest, TestExceptions, + TestInvalidUsage, TestTCPAddressParameters, TestUDPAddressParameters, BasicUDPTest, @@ -1464,7 +1515,7 @@ UnbufferedFileObjectClassTestCase, LineBufferedFileObjectClassTestCase, SmallBufferedFileObjectClassTestCase, - UnicodeTest + UnicodeTest, ] if hasattr(socket, "socketpair"): tests.append(BasicSocketPairTest) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2008-09-13 18:31:11
|
Revision: 5325 http://jython.svn.sourceforge.net/jython/?rev=5325&view=rev Author: amak Date: 2008-09-13 18:31:07 +0000 (Sat, 13 Sep 2008) Log Message: ----------- Change of mind on behaviour when shutting down server sockets. Instead to raising an exception, best to let the failure pass silently, as cpython does. http://bugs.jython.org/issue1121 Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2008-09-13 18:09:58 UTC (rev 5324) +++ trunk/jython/Lib/socket.py 2008-09-13 18:31:07 UTC (rev 5325) @@ -258,7 +258,7 @@ try: self.jsocket.shutdownInput() except AttributeError, ax: - raise error(errno.ENOTCONN, "Transport endpoint is not connected") + pass # Fail silently server sockets except java.lang.Exception, jlx: raise _map_exception(jlx) @@ -266,7 +266,7 @@ try: self.jsocket.shutdownOutput() except AttributeError, ax: - raise error(errno.ENOTCONN, "Transport endpoint is not connected") + pass # Fail silently server sockets except java.lang.Exception, jlx: raise _map_exception(jlx) Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2008-09-13 18:09:58 UTC (rev 5324) +++ trunk/jython/Lib/test/test_socket.py 2008-09-13 18:31:07 UTC (rev 5325) @@ -1474,12 +1474,10 @@ self.socket.listen() # socket is now a server socket try: self.socket.shutdown(socket.SHUT_RDWR) - except socket.error, se: - self.failUnlessEqual(se[0], errno.ENOTCONN, "Shutdown on listening socket should have raised errno.ENOTCONN, not %s" % str(se[0])) except Exception, x: - self.fail("Shutdown on listening socket should have raised socket exception, not %s" % str(x)) + self.fail("Shutdown on listening socket should not have raised socket exception, not %s" % str(x)) else: - self.fail("Shutdown on listening socket should have raised socket exception") + pass def testShutdownOnUnconnectedSocket(self): try: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2008-09-25 21:12:35
|
Revision: 5348 http://jython.svn.sourceforge.net/jython/?rev=5348&view=rev Author: pjenvey Date: 2008-09-25 21:12:28 +0000 (Thu, 25 Sep 2008) Log Message: ----------- bump tarfile from 2.5.1 to 2.5.2, from: http://svn.python.org/projects/python/branches/release25-maint/Lib tarfile.py@60730 test/test_tarfile.py@60730 Modified Paths: -------------- trunk/jython/Lib/tarfile.py trunk/jython/Lib/test/test_tarfile.py Removed Paths: ------------- trunk/jython/Lib/test/testtar.tar Modified: trunk/jython/Lib/tarfile.py =================================================================== --- trunk/jython/Lib/tarfile.py 2008-09-25 18:52:30 UTC (rev 5347) +++ trunk/jython/Lib/tarfile.py 2008-09-25 21:12:28 UTC (rev 5348) @@ -30,17 +30,13 @@ """Read from and write to tar format archives. """ -# From CPython 2.5.1 with @classmethod decorators replaced and -# TarFile.gzopen changed to not assume CPython reference counting GC -# (make GzipFile close the underlying file) - -__version__ = "$Revision: 53162 $" +__version__ = "$Revision: 60730 $" # $Source$ version = "0.8.0" __author__ = "Lars Gust\xE4bel (la...@gu...)" -__date__ = "$Date: 2006-12-27 21:36:58 +1100 (Wed, 27 Dec 2006) $" -__cvsid__ = "$Id: tarfile.py 53162 2006-12-27 10:36:58Z lars.gustaebel $" +__date__ = "$Date: 2008-02-11 10:36:07 -0800 (Mon, 11 Feb 2008) $" +__cvsid__ = "$Id: tarfile.py 60730 2008-02-11 18:36:07Z lars.gustaebel $" __credits__ = "Gustavo Niemeyer, Niels Gust\xE4bel, Richard Townsend." #--------- @@ -143,13 +139,22 @@ """ return s[:length] + (length - len(s)) * NUL +def nts(s): + """Convert a null-terminated string field to a python string. + """ + # Use the string up to the first null char. + p = s.find("\0") + if p == -1: + return s + return s[:p] + def nti(s): """Convert a number field to a python number. """ # There are two possible encodings for a number field, see # itn() below. if s[0] != chr(0200): - n = int(s.rstrip(NUL + " ") or "0", 8) + n = int(nts(s) or "0", 8) else: n = 0L for i in xrange(len(s) - 1): @@ -865,7 +870,7 @@ def __repr__(self): return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self)) - #@classmethod + @classmethod def frombuf(cls, buf): """Construct a TarInfo object from a 512 byte string buffer. """ @@ -876,7 +881,7 @@ tarinfo = cls() tarinfo.buf = buf - tarinfo.name = buf[0:100].rstrip(NUL) + tarinfo.name = nts(buf[0:100]) tarinfo.mode = nti(buf[100:108]) tarinfo.uid = nti(buf[108:116]) tarinfo.gid = nti(buf[116:124]) @@ -884,12 +889,12 @@ tarinfo.mtime = nti(buf[136:148]) tarinfo.chksum = nti(buf[148:156]) tarinfo.type = buf[156:157] - tarinfo.linkname = buf[157:257].rstrip(NUL) - tarinfo.uname = buf[265:297].rstrip(NUL) - tarinfo.gname = buf[297:329].rstrip(NUL) + tarinfo.linkname = nts(buf[157:257]) + tarinfo.uname = nts(buf[265:297]) + tarinfo.gname = nts(buf[297:329]) tarinfo.devmajor = nti(buf[329:337]) tarinfo.devminor = nti(buf[337:345]) - prefix = buf[345:500].rstrip(NUL) + prefix = nts(buf[345:500]) if prefix and not tarinfo.issparse(): tarinfo.name = prefix + "/" + tarinfo.name @@ -897,7 +902,6 @@ if tarinfo.chksum not in calc_chksums(buf): raise ValueError("invalid header") return tarinfo - frombuf = classmethod(frombuf) def tobuf(self, posix=False): """Return a tar header as a string of 512 byte blocks. @@ -968,7 +972,7 @@ stn(prefix, 155) ] - buf += struct.pack("%ds" % BLOCKSIZE, "".join(parts)) + buf += "".join(parts).ljust(BLOCKSIZE, NUL) chksum = calc_chksums(buf[-BLOCKSIZE:])[0] buf = buf[:-364] + "%06o\0" % chksum + buf[-357:] self.buf = buf @@ -1049,29 +1053,29 @@ can be determined, `mode' is overridden by `fileobj's mode. `fileobj' is not closed, when TarFile is closed. """ - self.name = os.path.abspath(name) - if len(mode) > 1 or mode not in "raw": raise ValueError("mode must be 'r', 'a' or 'w'") self._mode = mode self.mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode] if not fileobj: - fileobj = file(self.name, self.mode) + fileobj = file(name, self.mode) self._extfileobj = False else: - if self.name is None and hasattr(fileobj, "name"): - self.name = os.path.abspath(fileobj.name) + if name is None and hasattr(fileobj, "name"): + name = fileobj.name if hasattr(fileobj, "mode"): self.mode = fileobj.mode self._extfileobj = True + self.name = os.path.abspath(name) if name else None self.fileobj = fileobj # Init datastructures self.closed = False self.members = [] # list of members as TarInfo objects self._loaded = False # flag if all members have been read - self.offset = 0L # current position in the archive file + self.offset = self.fileobj.tell() + # current position in the archive file self.inodes = {} # dictionary caching the inodes of # archive members already added @@ -1107,7 +1111,7 @@ # the super-constructor. A sub-constructor is registered and made available # by adding it to the mapping in OPEN_METH. - #@classmethod + @classmethod def open(cls, name=None, mode="r", fileobj=None, bufsize=20*512): """Open a tar archive for reading, writing or appending. Return an appropriate TarFile class. @@ -1178,18 +1182,16 @@ return cls.taropen(name, mode, fileobj) raise ValueError("undiscernible mode") - open = classmethod(open) - #@classmethod + @classmethod def taropen(cls, name, mode="r", fileobj=None): """Open uncompressed tar archive name for reading or writing. """ if len(mode) > 1 or mode not in "raw": raise ValueError("mode must be 'r', 'a' or 'w'") return cls(name, mode, fileobj) - taropen = classmethod(taropen) - #@classmethod + @classmethod def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9): """Open gzip compressed tar archive name for reading or writing. Appending is not allowed. @@ -1204,19 +1206,17 @@ raise CompressionError("gzip module is not available") if fileobj is None: - fileobj = gzip.GzipFile(name, mode, compresslevel) - else: - fileobj = gzip.GzipFile(name, mode, compresslevel, fileobj) + fileobj = file(name, mode + "b") try: - t = cls.taropen(name, mode, fileobj) + t = cls.taropen(name, mode, + gzip.GzipFile(name, mode, compresslevel, fileobj)) except IOError: raise ReadError("not a gzip file") t._extfileobj = False return t - gzopen = classmethod(gzopen) - #@classmethod + @classmethod def bz2open(cls, name, mode="r", fileobj=None, compresslevel=9): """Open bzip2 compressed tar archive name for reading or writing. Appending is not allowed. @@ -1240,7 +1240,6 @@ raise ReadError("not a bzip2 file") t._extfileobj = False return t - bz2open = classmethod(bz2open) # All *open() methods are registered here. OPEN_METH = { @@ -1519,15 +1518,11 @@ for tarinfo in members: if tarinfo.isdir(): - # Extract directory with a safe mode, so that - # all files below can be extracted as well. - try: - os.makedirs(os.path.join(path, tarinfo.name), 0777) - except EnvironmentError: - pass + # Extract directories with a safe mode. directories.append(tarinfo) - else: - self.extract(tarinfo, path) + tarinfo = copy.copy(tarinfo) + tarinfo.mode = 0700 + self.extract(tarinfo, path) # Reverse sort directories. directories.sort(lambda a, b: cmp(a.name, b.name)) @@ -1535,11 +1530,11 @@ # Set correct owner, mtime and filemode on directories. for tarinfo in directories: - path = os.path.join(path, tarinfo.name) + dirpath = os.path.join(path, tarinfo.name) try: - self.chown(tarinfo, path) - self.utime(tarinfo, path) - self.chmod(tarinfo, path) + self.chown(tarinfo, dirpath) + self.utime(tarinfo, dirpath) + self.chmod(tarinfo, dirpath) except ExtractError, e: if self.errorlevel > 1: raise @@ -1632,19 +1627,9 @@ # Create all upper directories. upperdirs = os.path.dirname(targetpath) if upperdirs and not os.path.exists(upperdirs): - ti = TarInfo() - ti.name = upperdirs - ti.type = DIRTYPE - ti.mode = 0777 - ti.mtime = tarinfo.mtime - ti.uid = tarinfo.uid - ti.gid = tarinfo.gid - ti.uname = tarinfo.uname - ti.gname = tarinfo.gname - try: - self._extract_member(ti, ti.name) - except: - pass + # Create directories that are not part of the archive with + # default permissions. + os.makedirs(upperdirs) if tarinfo.islnk() or tarinfo.issym(): self._dbg(1, "%s -> %s" % (tarinfo.name, tarinfo.linkname)) @@ -1680,7 +1665,9 @@ """Make a directory called targetpath. """ try: - os.mkdir(targetpath) + # Use a safe mode for the directory, the real mode is set + # later in _extract_member(). + os.mkdir(targetpath, 0700) except EnvironmentError, e: if e.errno != errno.EEXIST: raise @@ -1852,7 +1839,7 @@ tarinfo.type = DIRTYPE # Directory names should have a '/' at the end. - if tarinfo.isdir(): + if tarinfo.isdir() and not tarinfo.name.endswith("/"): tarinfo.name += "/" self.members.append(tarinfo) @@ -1914,9 +1901,9 @@ # the longname information. next.offset = tarinfo.offset if tarinfo.type == GNUTYPE_LONGNAME: - next.name = buf.rstrip(NUL) + next.name = nts(buf) elif tarinfo.type == GNUTYPE_LONGLINK: - next.linkname = buf.rstrip(NUL) + next.linkname = nts(buf) return next Modified: trunk/jython/Lib/test/test_tarfile.py =================================================================== --- trunk/jython/Lib/test/test_tarfile.py 2008-09-25 18:52:30 UTC (rev 5347) +++ trunk/jython/Lib/test/test_tarfile.py 2008-09-25 21:12:28 UTC (rev 5348) @@ -9,9 +9,6 @@ from test import test_support -# From CPython 2.5.1, with a change to tarname() to use the correct -# tempdir when the testtar path name is relative (due to regrtest) - # Check for our compression modules. try: import gzip @@ -29,12 +26,12 @@ testtar = path("testtar.tar") tempdir = os.path.join(tempfile.gettempdir(), "testtar" + os.extsep + "dir") tempname = test_support.TESTFN -membercount = 12 +membercount = 13 def tarname(comp=""): if not comp: return testtar - return os.path.join(dirname(), "%s%s%s" % (testtar, os.extsep, comp)) + return os.path.join(tempdir, "%s%s%s" % (testtar, os.extsep, comp)) def dirname(): if not os.path.exists(tempdir): @@ -194,6 +191,47 @@ except: pass + def test_dirtype(self): + for tarinfo in self.tar: + if tarinfo.isdir(): + self.assert_(tarinfo.name.endswith("/")) + self.assert_(not tarinfo.name[:-1].endswith("/")) + + def test_extractall(self): + # Test if extractall() correctly restores directory permissions + # and times (see issue1735). + if sys.platform == "win32": + # Win32 has no support for utime() on directories or + # fine grained permissions. + return + + fobj = StringIO.StringIO() + tar = tarfile.open(fileobj=fobj, mode="w:") + for name in ("foo", "foo/bar"): + tarinfo = tarfile.TarInfo(name) + tarinfo.type = tarfile.DIRTYPE + tarinfo.mtime = 07606136617 + tarinfo.mode = 0755 + tar.addfile(tarinfo) + tar.close() + fobj.seek(0) + + TEMPDIR = os.path.join(dirname(), "extract-test") + tar = tarfile.open(fileobj=fobj) + tar.extractall(TEMPDIR) + for tarinfo in tar.getmembers(): + path = os.path.join(TEMPDIR, tarinfo.name) + self.assertEqual(tarinfo.mode, os.stat(path).st_mode & 0777) + self.assertEqual(tarinfo.mtime, os.path.getmtime(path)) + tar.close() + + def test_star(self): + try: + self.tar.getmember("7-STAR") + except KeyError: + self.fail("finding 7-STAR member failed (mangled prefix?)") + + class ReadStreamTest(ReadTest): sep = "|" @@ -241,14 +279,9 @@ def setUp(self): name = tarname(self.comp) - self.fileobj = open(name, "rb") self.tar = tarfile.open(name, mode=self.mode, - fileobj=self.fileobj) + fileobj=open(name, "rb")) - def tearDown(self): - self.tar.close() - self.fileobj.close() - class ReadAsteriskTest(ReadTest): def setUp(self): @@ -261,6 +294,38 @@ mode = self.mode + self.sep + "*" self.tar = tarfile.open(tarname(self.comp), mode) +class ReadFileobjTest(BaseTest): + + def test_fileobj_with_offset(self): + # Skip the first member and store values from the second member + # of the testtar. + self.tar.next() + t = self.tar.next() + name = t.name + offset = t.offset + data = self.tar.extractfile(t).read() + self.tar.close() + + # Open the testtar and seek to the offset of the second member. + if self.comp == "gz": + _open = gzip.GzipFile + elif self.comp == "bz2": + _open = bz2.BZ2File + else: + _open = open + fobj = _open(tarname(self.comp), "rb") + fobj.seek(offset) + + # Test if the tarfile starts with the second member. + self.tar = tarfile.open(tarname(self.comp), "r:", fileobj=fobj) + t = self.tar.next() + self.assertEqual(t.name, name) + # Read to the end of fileobj and test if seeking back to the + # beginning works. + self.tar.getmembers() + self.assertEqual(self.tar.extractfile(t).read(), data, + "seek back did not work") + class WriteTest(BaseTest): mode = 'w' @@ -464,7 +529,6 @@ self.assert_(tarinfo.name == member.name and \ tarinfo.linkname == member.linkname, \ "unable to read longname member") - tar.close() def test_longname_1023(self): self._test(("longnam/" * 127) + "longnam") @@ -626,6 +690,8 @@ comp = "gz" class ReadStreamAsteriskTestGzip(ReadStreamAsteriskTest): comp = "gz" +class ReadFileobjTestGzip(ReadFileobjTest): + comp = "gz" # Filemode test cases @@ -635,15 +701,35 @@ self.assertEqual(tarfile.filemode(07111), '---s--s--t') class OpenFileobjTest(BaseTest): - # Test for SF bug #1496501. def test_opener(self): + # Test for SF bug #1496501. fobj = StringIO.StringIO("foo\n") try: - tarfile.open("", "r", fileobj=fobj) + tarfile.open("", mode="r", fileobj=fobj) except tarfile.ReadError: self.assertEqual(fobj.tell(), 0, "fileobj's position has moved") + def test_no_name_argument(self): + fobj = open(testtar, "rb") + tar = tarfile.open(fileobj=fobj, mode="r") + self.assertEqual(tar.name, os.path.abspath(fobj.name)) + + def test_no_name_attribute(self): + data = open(testtar, "rb").read() + fobj = StringIO.StringIO(data) + self.assertRaises(AttributeError, getattr, fobj, "name") + tar = tarfile.open(fileobj=fobj, mode="r") + self.assertEqual(tar.name, None) + + def test_empty_name_attribute(self): + data = open(testtar, "rb").read() + fobj = StringIO.StringIO(data) + fobj.name = "" + tar = tarfile.open(fileobj=fobj, mode="r") + self.assertEqual(tar.name, None) + + if bz2: # Bzip2 TestCases class ReadTestBzip2(ReadTestGzip): @@ -662,6 +748,8 @@ comp = "bz2" class ReadStreamAsteriskTestBzip2(ReadStreamAsteriskTest): comp = "bz2" + class ReadFileobjTestBzip2(ReadFileobjTest): + comp = "bz2" # If importing gzip failed, discard the Gzip TestCases. if not gzip: @@ -695,6 +783,7 @@ ReadDetectFileobjTest, ReadAsteriskTest, ReadStreamAsteriskTest, + ReadFileobjTest, WriteTest, Write100Test, WriteSize0Test, @@ -712,7 +801,8 @@ ReadTestGzip, ReadStreamTestGzip, WriteTestGzip, WriteStreamTestGzip, ReadDetectTestGzip, ReadDetectFileobjTestGzip, - ReadAsteriskTestGzip, ReadStreamAsteriskTestGzip + ReadAsteriskTestGzip, ReadStreamAsteriskTestGzip, + ReadFileobjTestGzip ]) if bz2: @@ -720,7 +810,8 @@ ReadTestBzip2, ReadStreamTestBzip2, WriteTestBzip2, WriteStreamTestBzip2, ReadDetectTestBzip2, ReadDetectFileobjTestBzip2, - ReadAsteriskTestBzip2, ReadStreamAsteriskTestBzip2 + ReadAsteriskTestBzip2, ReadStreamAsteriskTestBzip2, + ReadFileobjTestBzip2 ]) try: test_support.run_unittest(*tests) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2008-09-25 21:16:36
|
Revision: 5349 http://jython.svn.sourceforge.net/jython/?rev=5349&view=rev Author: pjenvey Date: 2008-09-25 21:16:30 +0000 (Thu, 25 Sep 2008) Log Message: ----------- reapply previous tarfile modifications: o don't assume a reference counting GC o ensure all file handles are closed to avoid os.remove problems on windows o always use the tempdir, even when testtar is a relative path (it is when ran via the regrtest) Modified Paths: -------------- trunk/jython/Lib/tarfile.py trunk/jython/Lib/test/test_tarfile.py Modified: trunk/jython/Lib/tarfile.py =================================================================== --- trunk/jython/Lib/tarfile.py 2008-09-25 21:12:28 UTC (rev 5348) +++ trunk/jython/Lib/tarfile.py 2008-09-25 21:16:30 UTC (rev 5349) @@ -1205,12 +1205,10 @@ except (ImportError, AttributeError): raise CompressionError("gzip module is not available") - if fileobj is None: - fileobj = file(name, mode + "b") + fileobj = gzip.GzipFile(name, mode, compresslevel, fileobj) try: - t = cls.taropen(name, mode, - gzip.GzipFile(name, mode, compresslevel, fileobj)) + t = cls.taropen(name, mode, fileobj) except IOError: raise ReadError("not a gzip file") t._extfileobj = False Modified: trunk/jython/Lib/test/test_tarfile.py =================================================================== --- trunk/jython/Lib/test/test_tarfile.py 2008-09-25 21:12:28 UTC (rev 5348) +++ trunk/jython/Lib/test/test_tarfile.py 2008-09-25 21:16:30 UTC (rev 5349) @@ -31,7 +31,7 @@ def tarname(comp=""): if not comp: return testtar - return os.path.join(tempdir, "%s%s%s" % (testtar, os.extsep, comp)) + return os.path.join(dirname(), "%s%s%s" % (testtar, os.extsep, comp)) def dirname(): if not os.path.exists(tempdir): @@ -279,9 +279,14 @@ def setUp(self): name = tarname(self.comp) + self.fileobj = open(name, "rb") self.tar = tarfile.open(name, mode=self.mode, - fileobj=open(name, "rb")) + fileobj=self.fileobj) + def tearDown(self): + self.tar.close() + self.fileobj.close() + class ReadAsteriskTest(ReadTest): def setUp(self): @@ -529,6 +534,7 @@ self.assert_(tarinfo.name == member.name and \ tarinfo.linkname == member.linkname, \ "unable to read longname member") + tar.close() def test_longname_1023(self): self._test(("longnam/" * 127) + "longnam") This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2008-10-14 23:08:57
|
Revision: 5393 http://jython.svn.sourceforge.net/jython/?rev=5393&view=rev Author: pjenvey Date: 2008-10-14 23:08:45 +0000 (Tue, 14 Oct 2008) Log Message: ----------- o fix the socket hostname functions returning unicode hostnames instead of strs. was causing test_wsgiref to fail on environments where socket.getfqdn('localhost') != 'localhost' o fix getaddrinfo default family and handling of bad familys Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2008-10-14 19:28:28 UTC (rev 5392) +++ trunk/jython/Lib/socket.py 2008-10-14 23:08:45 UTC (rev 5393) @@ -81,6 +81,7 @@ import org.python.core.io.DatagramSocketIO import org.python.core.io.ServerSocketIO import org.python.core.io.SocketIO +from org.python.core.util.StringUtil import asPyString class error(Exception): pass class herror(error): pass @@ -464,8 +465,8 @@ names = [] addrs = [] for addr in addresses: - names.append(addr.getHostName()) - addrs.append(addr.getHostAddress()) + names.append(asPyString(addr.getHostName())) + addrs.append(asPyString(addr.getHostAddress())) return (names, addrs) def getfqdn(name=None): @@ -487,13 +488,13 @@ def gethostname(): try: - return java.net.InetAddress.getLocalHost().getHostName() + return asPyString(java.net.InetAddress.getLocalHost().getHostName()) except java.lang.Exception, jlx: raise _map_exception(jlx) def gethostbyname(name): try: - return java.net.InetAddress.getByName(name).getHostAddress() + return asPyString(java.net.InetAddress.getByName(name).getHostAddress()) except java.lang.Exception, jlx: raise _map_exception(jlx) @@ -523,10 +524,10 @@ else: return _udpsocket() -def getaddrinfo(host, port, family=None, socktype=None, proto=0, flags=None): +def getaddrinfo(host, port, family=AF_INET, socktype=None, proto=0, flags=None): try: if not family in [AF_INET, AF_INET6, AF_UNSPEC]: - raise NotSupportedError() + raise gaierror(errno.EIO, 'ai_family not supported') filter_fns = [] filter_fns.append({ AF_INET: lambda x: isinstance(x, java.net.Inet4Address), @@ -541,7 +542,9 @@ if len([f for f in filter_fns if f(a)]): family = {java.net.Inet4Address: AF_INET, java.net.Inet6Address: AF_INET6}[a.getClass()] # TODO: Include flowinfo and scopeid in a 4-tuple for IPv6 addresses - results.append( (family, socktype, proto, a.getCanonicalHostName(), (a.getHostAddress(), port)) ) + canonname = asPyString(a.getCanonicalHostName()) + sockname = asPyString(a.getHostAddress()) + results.append((family, socktype, proto, canonname, (sockname, port))) return results except java.lang.Exception, jlx: raise _map_exception(jlx) Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2008-10-14 19:28:28 UTC (rev 5392) +++ trunk/jython/Lib/test/test_socket.py 2008-10-14 23:08:45 UTC (rev 5393) @@ -274,8 +274,10 @@ def testHostnameRes(self): # Testing hostname resolution mechanisms hostname = socket.gethostname() + self.assert_(isinstance(hostname, str)) try: ip = socket.gethostbyname(hostname) + self.assert_(isinstance(ip, str)) except socket.error: # Probably name lookup wasn't set up right; skip this test self.fail("Probably name lookup wasn't set up right; skip testHostnameRes.gethostbyname") @@ -283,15 +285,35 @@ self.assert_(ip.find('.') >= 0, "Error resolving host to ip.") try: hname, aliases, ipaddrs = socket.gethostbyaddr(ip) + self.assert_(isinstance(hname, str)) + for hosts in aliases, ipaddrs: + self.assert_(all(isinstance(host, str) for host in hosts)) except socket.error: # Probably a similar problem as above; skip this test self.fail("Probably name lookup wasn't set up right; skip testHostnameRes.gethostbyaddr") return all_host_names = [hostname, hname] + aliases fqhn = socket.getfqdn() + self.assert_(isinstance(fqhn, str)) if not fqhn in all_host_names: self.fail("Error testing host resolution mechanisms.") + def testGetAddrInfo(self): + try: + socket.getaddrinfo(HOST, PORT, 9999) + except socket.gaierror, gaix: + self.failUnlessEqual(gaix[0], errno.EIO) + except Exception, x: + self.fail("getaddrinfo with bad family raised wrong exception: %s" % x) + else: + self.fail("getaddrinfo with bad family should have raised exception") + + addrinfos = socket.getaddrinfo(HOST, PORT) + for addrinfo in addrinfos: + family, socktype, proto, canonname, sockaddr = addrinfo + self.assert_(isinstance(canonname, str)) + self.assert_(isinstance(sockaddr[0], str)) + def testRefCountGetNameInfo(self): # Testing reference count for getnameinfo import sys This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2008-10-20 20:01:24
|
Revision: 5483 http://jython.svn.sourceforge.net/jython/?rev=5483&view=rev Author: pjenvey Date: 2008-10-20 20:01:14 +0000 (Mon, 20 Oct 2008) Log Message: ----------- make sock.listen() explicitly require the backlog argument to match CPython Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2008-10-20 17:19:57 UTC (rev 5482) +++ trunk/jython/Lib/socket.py 2008-10-20 20:01:14 UTC (rev 5483) @@ -699,7 +699,7 @@ _unpack_address_tuple(addr) self.local_addr = addr - def listen(self, backlog=50): + def listen(self, backlog): "This signifies a server socket" try: assert not self.sock_impl Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2008-10-20 17:19:57 UTC (rev 5482) +++ trunk/jython/Lib/test/test_socket.py 2008-10-20 20:01:14 UTC (rev 5483) @@ -543,7 +543,7 @@ # First listen on a server socket, so that the connection won't be refused. server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_sock.bind( (HOST, PORT) ) - server_sock.listen() + server_sock.listen(50) # Now do the tests sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._testSetAndGetOption(sock, option, values) @@ -564,7 +564,7 @@ self._testSetAndGetOption(sock, option, values) # now bind and listen on the socket i.e. cause the implementation socket to be created sock.bind( (HOST, PORT) ) - sock.listen() + sock.listen(50) self.failUnlessEqual(sock.getsockopt(socket.SOL_SOCKET, option), values[-1], \ "Option value '%s'='%s' did not propagate to implementation socket" % (option, values[-1])) self._testSetAndGetOption(sock, option, values) @@ -1410,12 +1410,12 @@ def testBindException(self): # First bind to the target port self.s.bind( (HOST, PORT) ) - self.s.listen() + self.s.listen(50) try: # And then try to bind again t = socket.socket(socket.AF_INET, socket.SOCK_STREAM) t.bind( (HOST, PORT) ) - t.listen() + t.listen(50) except socket.error, se: self.failUnlessEqual(se[0], errno.EADDRINUSE) except Exception, x: @@ -1493,7 +1493,7 @@ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) def testShutdownIOOnListener(self): - self.socket.listen() # socket is now a server socket + self.socket.listen(50) # socket is now a server socket try: self.socket.shutdown(socket.SHUT_RDWR) except Exception, x: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2008-10-26 21:13:54
|
Revision: 5513 http://jython.svn.sourceforge.net/jython/?rev=5513&view=rev Author: pjenvey Date: 2008-10-26 21:13:51 +0000 (Sun, 26 Oct 2008) Log Message: ----------- workaround Jython ASTisms Modified Paths: -------------- trunk/jython/Lib/ast.py trunk/jython/Lib/test/test_ast.py Modified: trunk/jython/Lib/ast.py =================================================================== --- trunk/jython/Lib/ast.py 2008-10-26 19:55:08 UTC (rev 5512) +++ trunk/jython/Lib/ast.py 2008-10-26 21:13:51 UTC (rev 5513) @@ -25,10 +25,35 @@ :copyright: Copyright 2008 by Armin Ronacher. :license: Python License. """ +import sys from _ast import * from _ast import __version__ +if sys.platform.startswith('java'): + import array + ast_list = array.ArrayType + + def get_class_name(t): + result = t.__class__.__name__ + if result in ("expr_contextType", + "boolopType", + "unaryopType", + "cmpopType", + "operatorType"): + result = str(t) + if result == "AugLoad": + result = "Load" + elif result == "AugStore": + result = "Store" + elif result.endswith("Type"): + result = result[:-4] + return result +else: + ast_list = list + get_class_name = lambda node: node.__class__.__name__ + + def parse(expr, filename='<unknown>', mode='exec'): """ Parse an expression into an AST node. @@ -80,7 +105,7 @@ def _format(node): if isinstance(node, AST): fields = [(a, _format(b)) for a, b in iter_fields(node)] - rv = '%s(%s' % (node.__class__.__name__, ', '.join( + rv = '%s(%s' % (get_class_name(node), ', '.join( ('%s=%s' % field for field in fields) if annotate_fields else (b for a, b in fields) @@ -90,11 +115,11 @@ rv += ', '.join('%s=%s' % (a, _format(getattr(node, a))) for a in node._attributes) return rv + ')' - elif isinstance(node, list): + elif isinstance(node, ast_list): return '[%s]' % ', '.join(_format(x) for x in node) return repr(node) if not isinstance(node, AST): - raise TypeError('expected AST, got %r' % node.__class__.__name__) + raise TypeError('expected AST, got %r' % get_class_name(node)) return _format(node) @@ -168,7 +193,7 @@ for name, field in iter_fields(node): if isinstance(field, AST): yield field - elif isinstance(field, list): + elif isinstance(field, ast_list): for item in field: if isinstance(item, AST): yield item @@ -181,7 +206,7 @@ will be raised. """ if not isinstance(node, (FunctionDef, ClassDef, Module)): - raise TypeError("%r can't have docstrings" % node.__class__.__name__) + raise TypeError("%r can't have docstrings" % get_class_name(node)) if node.body and isinstance(node.body[0], Expr) and \ isinstance(node.body[0].value, Str): if clean: @@ -226,14 +251,14 @@ def visit(self, node): """Visit a node.""" - method = 'visit_' + node.__class__.__name__ + method = 'visit_' + get_class_name(node) visitor = getattr(self, method, self.generic_visit) return visitor(node) def generic_visit(self, node): """Called if no explicit visitor function exists for a node.""" for field, value in iter_fields(node): - if isinstance(value, list): + if isinstance(value, ast_list): for item in value: if isinstance(item, AST): self.visit(item) @@ -280,7 +305,7 @@ def generic_visit(self, node): for field, old_value in iter_fields(node): old_value = getattr(node, field, None) - if isinstance(old_value, list): + if isinstance(old_value, ast_list): new_values = [] for value in old_value: if isinstance(value, AST): Modified: trunk/jython/Lib/test/test_ast.py =================================================================== --- trunk/jython/Lib/test/test_ast.py 2008-10-26 19:55:08 UTC (rev 5512) +++ trunk/jython/Lib/test/test_ast.py 2008-10-26 21:13:51 UTC (rev 5513) @@ -1,6 +1,6 @@ #Taken and modified from CPython's release25-maint branch, revision 62446. import sys,os, itertools -import _ast +import ast def get_class_name(t): result = t.__class__.__name__ @@ -146,11 +146,11 @@ def test_order(ast_node, parent_pos): - if (not isinstance(ast_node, _ast.AST) + if (not isinstance(ast_node, ast.AST) or not hasattr(ast_node, '_fields') or ast_node._fields == None): return - if isinstance(ast_node, (_ast.expr, _ast.stmt, _ast.excepthandler)): + if isinstance(ast_node, (ast.expr, ast.stmt, ast.excepthandler)): node_pos = (ast_node.lineno, ast_node.col_offset) assert node_pos >= parent_pos, (node_pos, parent_pos) parent_pos = (ast_node.lineno, ast_node.col_offset) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2008-10-27 17:35:48
|
Revision: 5521 http://jython.svn.sourceforge.net/jython/?rev=5521&view=rev Author: amak Date: 2008-10-27 17:35:45 +0000 (Mon, 27 Oct 2008) Log Message: ----------- Adding support for address manipulation functions inet_pton, inet_ntop, inet_aton and inet_ntoa. Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2008-10-27 17:02:39 UTC (rev 5520) +++ trunk/jython/Lib/socket.py 2008-10-27 17:35:45 UTC (rev 5521) @@ -580,6 +580,33 @@ def ntohs(x): return x def ntohl(x): return x +def inet_pton(family, ip_string): + try: + ia = java.net.InetAddress.getByName(ip_string) + bytes = [] + for byte in ia.getAddress(): + if byte < 0: + bytes.append(byte+256) + else: + bytes.append(byte) + return "".join([chr(byte) for byte in bytes]) + except java.lang.Exception, jlx: + raise _map_exception(jlx) + +def inet_ntop(family, packed_ip): + try: + jByteArray = jarray.array(packed_ip, 'b') + ia = java.net.InetAddress.getByAddress(jByteArray) + return ia.getHostAddress() + except java.lang.Exception, jlx: + raise _map_exception(jlx) + +def inet_aton(ip_string): + return inet_pton(AF_INET, ip_string) + +def inet_ntoa(packed_ip): + return inet_ntop(AF_INET, packed_ip) + class _nonblocking_api_mixin: timeout = _defaulttimeout Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2008-10-27 17:02:39 UTC (rev 5520) +++ trunk/jython/Lib/test/test_socket.py 2008-10-27 17:35:45 UTC (rev 5521) @@ -477,8 +477,11 @@ return f = lambda a: inet_ntop(AF_INET6, a) - self.assertEquals('::', f('\x00' * 16)) - self.assertEquals('::1', f('\x00' * 15 + '\x01')) +# self.assertEquals('::', f('\x00' * 16)) +# self.assertEquals('::1', f('\x00' * 15 + '\x01')) + # java.net.InetAddress always return the full unabbreviated form + self.assertEquals('0:0:0:0:0:0:0:0', f('\x00' * 16)) + self.assertEquals('0:0:0:0:0:0:0:1', f('\x00' * 15 + '\x01')) self.assertEquals( 'aef:b01:506:1001:ffff:9997:55:170', f('\x0a\xef\x0b\x01\x05\x06\x10\x01\xff\xff\x99\x97\x00\x55\x01\x70') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2008-11-12 02:22:16
|
Revision: 5572 http://jython.svn.sourceforge.net/jython/?rev=5572&view=rev Author: pjenvey Date: 2008-11-12 01:31:02 +0000 (Wed, 12 Nov 2008) Log Message: ----------- more java integration unicode vs str fixes Modified Paths: -------------- trunk/jython/Lib/ntpath.py trunk/jython/Lib/os.py trunk/jython/Lib/posixpath.py Modified: trunk/jython/Lib/ntpath.py =================================================================== --- trunk/jython/Lib/ntpath.py 2008-11-11 23:25:25 UTC (rev 5571) +++ trunk/jython/Lib/ntpath.py 2008-11-12 01:31:02 UTC (rev 5572) @@ -9,6 +9,7 @@ import os import stat import sys +from org.python.core.Py import newString __all__ = ["normcase","isabs","join","splitdrive","split","splitext", "basename","dirname","commonprefix","getsize","getmtime", @@ -493,7 +494,8 @@ if not splitunc(path)[0] and not splitdrive(path)[0]: # cwd lacks a UNC mount point, so it should have a drive # letter (but lacks one): determine it - drive = splitdrive(java.io.File(path).getCanonicalPath())[0] + canon_path = newString(java.io.File(path).getCanonicalPath()) + drive = splitdrive(canon_path)[0] path = join(drive, path) return normpath(path) Modified: trunk/jython/Lib/os.py =================================================================== --- trunk/jython/Lib/os.py 2008-11-11 23:25:25 UTC (rev 5571) +++ trunk/jython/Lib/os.py 2008-11-12 01:31:02 UTC (rev 5572) @@ -237,7 +237,7 @@ Return a string representing the current working directory. """ - return sys.getCurrentWorkingDir() + return asPyString(sys.getCurrentWorkingDir()) def chdir(path): """chdir(path) Modified: trunk/jython/Lib/posixpath.py =================================================================== --- trunk/jython/Lib/posixpath.py 2008-11-11 23:25:25 UTC (rev 5571) +++ trunk/jython/Lib/posixpath.py 2008-11-12 01:31:02 UTC (rev 5572) @@ -14,6 +14,7 @@ import java.io.IOException import os import stat +from org.python.core.Py import newString __all__ = ["normcase","isabs","join","splitdrive","split","splitext", "basename","dirname","commonprefix","getsize","getmtime", @@ -218,8 +219,8 @@ if not os._native_posix: def samefile(f1, f2): """Test whether two pathnames reference the same actual file""" - canon1 = java.io.File(_ensure_str(f1)).getCanonicalPath() - canon2 = java.io.File(_ensure_str(f2)).getCanonicalPath() + canon1 = newString(java.io.File(_ensure_str(f1)).getCanonicalPath()) + canon2 = newString(java.io.File(_ensure_str(f2)).getCanonicalPath()) return canon1 == canon2 else: def samefile(f1, f2): @@ -448,7 +449,7 @@ encounter a path we've seen before (meaning that there's a loop). """ try: - return str(java.io.File(abspath(path)).getCanonicalPath()) + return newString(java.io.File(abspath(path)).getCanonicalPath()) except java.io.IOException: return None else: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2008-11-24 05:01:07
|
Revision: 5629 http://jython.svn.sourceforge.net/jython/?rev=5629&view=rev Author: pjenvey Date: 2008-11-24 05:01:02 +0000 (Mon, 24 Nov 2008) Log Message: ----------- from: http://svn.python.org/projects/python/branches/release25-maint/Lib/zipfile.py@60117 http://svn.python.org/projects/python/branches/release25-maint/Lib/test/test_zipfile.py@46982 Added Paths: ----------- trunk/jython/Lib/test/test_zipfile.py trunk/jython/Lib/zipfile.py Added: trunk/jython/Lib/test/test_zipfile.py =================================================================== --- trunk/jython/Lib/test/test_zipfile.py (rev 0) +++ trunk/jython/Lib/test/test_zipfile.py 2008-11-24 05:01:02 UTC (rev 5629) @@ -0,0 +1,357 @@ +# We can test part of the module without zlib. +try: + import zlib +except ImportError: + zlib = None + +import zipfile, os, unittest, sys, shutil + +from StringIO import StringIO +from tempfile import TemporaryFile + +from test.test_support import TESTFN, run_unittest + +TESTFN2 = TESTFN + "2" + +class TestsWithSourceFile(unittest.TestCase): + def setUp(self): + line_gen = ("Test of zipfile line %d." % i for i in range(0, 1000)) + self.data = '\n'.join(line_gen) + + # Make a source file with some lines + fp = open(TESTFN, "wb") + fp.write(self.data) + fp.close() + + def zipTest(self, f, compression): + # Create the ZIP archive + zipfp = zipfile.ZipFile(f, "w", compression) + zipfp.write(TESTFN, "another"+os.extsep+"name") + zipfp.write(TESTFN, TESTFN) + zipfp.writestr("strfile", self.data) + zipfp.close() + + # Read the ZIP archive + zipfp = zipfile.ZipFile(f, "r", compression) + self.assertEqual(zipfp.read(TESTFN), self.data) + self.assertEqual(zipfp.read("another"+os.extsep+"name"), self.data) + self.assertEqual(zipfp.read("strfile"), self.data) + + # Print the ZIP directory + fp = StringIO() + stdout = sys.stdout + try: + sys.stdout = fp + + zipfp.printdir() + finally: + sys.stdout = stdout + + directory = fp.getvalue() + lines = directory.splitlines() + self.assertEquals(len(lines), 4) # Number of files + header + + self.assert_('File Name' in lines[0]) + self.assert_('Modified' in lines[0]) + self.assert_('Size' in lines[0]) + + fn, date, time, size = lines[1].split() + self.assertEquals(fn, 'another.name') + # XXX: timestamp is not tested + self.assertEquals(size, str(len(self.data))) + + # Check the namelist + names = zipfp.namelist() + self.assertEquals(len(names), 3) + self.assert_(TESTFN in names) + self.assert_("another"+os.extsep+"name" in names) + self.assert_("strfile" in names) + + # Check infolist + infos = zipfp.infolist() + names = [ i.filename for i in infos ] + self.assertEquals(len(names), 3) + self.assert_(TESTFN in names) + self.assert_("another"+os.extsep+"name" in names) + self.assert_("strfile" in names) + for i in infos: + self.assertEquals(i.file_size, len(self.data)) + + # check getinfo + for nm in (TESTFN, "another"+os.extsep+"name", "strfile"): + info = zipfp.getinfo(nm) + self.assertEquals(info.filename, nm) + self.assertEquals(info.file_size, len(self.data)) + + # Check that testzip doesn't raise an exception + zipfp.testzip() + + + zipfp.close() + + + + + def testStored(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.zipTest(f, zipfile.ZIP_STORED) + + if zlib: + def testDeflated(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.zipTest(f, zipfile.ZIP_DEFLATED) + + def testAbsoluteArcnames(self): + zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) + zipfp.write(TESTFN, "/absolute") + zipfp.close() + + zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) + self.assertEqual(zipfp.namelist(), ["absolute"]) + zipfp.close() + + + def tearDown(self): + os.remove(TESTFN) + os.remove(TESTFN2) + +class TestZip64InSmallFiles(unittest.TestCase): + # These tests test the ZIP64 functionality without using large files, + # see test_zipfile64 for proper tests. + + def setUp(self): + self._limit = zipfile.ZIP64_LIMIT + zipfile.ZIP64_LIMIT = 5 + + line_gen = ("Test of zipfile line %d." % i for i in range(0, 1000)) + self.data = '\n'.join(line_gen) + + # Make a source file with some lines + fp = open(TESTFN, "wb") + fp.write(self.data) + fp.close() + + def largeFileExceptionTest(self, f, compression): + zipfp = zipfile.ZipFile(f, "w", compression) + self.assertRaises(zipfile.LargeZipFile, + zipfp.write, TESTFN, "another"+os.extsep+"name") + zipfp.close() + + def largeFileExceptionTest2(self, f, compression): + zipfp = zipfile.ZipFile(f, "w", compression) + self.assertRaises(zipfile.LargeZipFile, + zipfp.writestr, "another"+os.extsep+"name", self.data) + zipfp.close() + + def testLargeFileException(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.largeFileExceptionTest(f, zipfile.ZIP_STORED) + self.largeFileExceptionTest2(f, zipfile.ZIP_STORED) + + def zipTest(self, f, compression): + # Create the ZIP archive + zipfp = zipfile.ZipFile(f, "w", compression, allowZip64=True) + zipfp.write(TESTFN, "another"+os.extsep+"name") + zipfp.write(TESTFN, TESTFN) + zipfp.writestr("strfile", self.data) + zipfp.close() + + # Read the ZIP archive + zipfp = zipfile.ZipFile(f, "r", compression) + self.assertEqual(zipfp.read(TESTFN), self.data) + self.assertEqual(zipfp.read("another"+os.extsep+"name"), self.data) + self.assertEqual(zipfp.read("strfile"), self.data) + + # Print the ZIP directory + fp = StringIO() + stdout = sys.stdout + try: + sys.stdout = fp + + zipfp.printdir() + finally: + sys.stdout = stdout + + directory = fp.getvalue() + lines = directory.splitlines() + self.assertEquals(len(lines), 4) # Number of files + header + + self.assert_('File Name' in lines[0]) + self.assert_('Modified' in lines[0]) + self.assert_('Size' in lines[0]) + + fn, date, time, size = lines[1].split() + self.assertEquals(fn, 'another.name') + # XXX: timestamp is not tested + self.assertEquals(size, str(len(self.data))) + + # Check the namelist + names = zipfp.namelist() + self.assertEquals(len(names), 3) + self.assert_(TESTFN in names) + self.assert_("another"+os.extsep+"name" in names) + self.assert_("strfile" in names) + + # Check infolist + infos = zipfp.infolist() + names = [ i.filename for i in infos ] + self.assertEquals(len(names), 3) + self.assert_(TESTFN in names) + self.assert_("another"+os.extsep+"name" in names) + self.assert_("strfile" in names) + for i in infos: + self.assertEquals(i.file_size, len(self.data)) + + # check getinfo + for nm in (TESTFN, "another"+os.extsep+"name", "strfile"): + info = zipfp.getinfo(nm) + self.assertEquals(info.filename, nm) + self.assertEquals(info.file_size, len(self.data)) + + # Check that testzip doesn't raise an exception + zipfp.testzip() + + + zipfp.close() + + def testStored(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.zipTest(f, zipfile.ZIP_STORED) + + + if zlib: + def testDeflated(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.zipTest(f, zipfile.ZIP_DEFLATED) + + def testAbsoluteArcnames(self): + zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED, allowZip64=True) + zipfp.write(TESTFN, "/absolute") + zipfp.close() + + zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) + self.assertEqual(zipfp.namelist(), ["absolute"]) + zipfp.close() + + + def tearDown(self): + zipfile.ZIP64_LIMIT = self._limit + os.remove(TESTFN) + os.remove(TESTFN2) + +class PyZipFileTests(unittest.TestCase): + def testWritePyfile(self): + zipfp = zipfile.PyZipFile(TemporaryFile(), "w") + fn = __file__ + if fn.endswith('.pyc') or fn.endswith('.pyo'): + fn = fn[:-1] + + zipfp.writepy(fn) + + bn = os.path.basename(fn) + self.assert_(bn not in zipfp.namelist()) + self.assert_(bn + 'o' in zipfp.namelist() or bn + 'c' in zipfp.namelist()) + zipfp.close() + + + zipfp = zipfile.PyZipFile(TemporaryFile(), "w") + fn = __file__ + if fn.endswith('.pyc') or fn.endswith('.pyo'): + fn = fn[:-1] + + zipfp.writepy(fn, "testpackage") + + bn = "%s/%s"%("testpackage", os.path.basename(fn)) + self.assert_(bn not in zipfp.namelist()) + self.assert_(bn + 'o' in zipfp.namelist() or bn + 'c' in zipfp.namelist()) + zipfp.close() + + def testWritePythonPackage(self): + import email + packagedir = os.path.dirname(email.__file__) + + zipfp = zipfile.PyZipFile(TemporaryFile(), "w") + zipfp.writepy(packagedir) + + # Check for a couple of modules at different levels of the hieararchy + names = zipfp.namelist() + self.assert_('email/__init__.pyo' in names or 'email/__init__.pyc' in names) + self.assert_('email/mime/text.pyo' in names or 'email/mime/text.pyc' in names) + + def testWritePythonDirectory(self): + os.mkdir(TESTFN2) + try: + fp = open(os.path.join(TESTFN2, "mod1.py"), "w") + fp.write("print 42\n") + fp.close() + + fp = open(os.path.join(TESTFN2, "mod2.py"), "w") + fp.write("print 42 * 42\n") + fp.close() + + fp = open(os.path.join(TESTFN2, "mod2.txt"), "w") + fp.write("bla bla bla\n") + fp.close() + + zipfp = zipfile.PyZipFile(TemporaryFile(), "w") + zipfp.writepy(TESTFN2) + + names = zipfp.namelist() + self.assert_('mod1.pyc' in names or 'mod1.pyo' in names) + self.assert_('mod2.pyc' in names or 'mod2.pyo' in names) + self.assert_('mod2.txt' not in names) + + finally: + shutil.rmtree(TESTFN2) + + + +class OtherTests(unittest.TestCase): + def testCloseErroneousFile(self): + # This test checks that the ZipFile constructor closes the file object + # it opens if there's an error in the file. If it doesn't, the traceback + # holds a reference to the ZipFile object and, indirectly, the file object. + # On Windows, this causes the os.unlink() call to fail because the + # underlying file is still open. This is SF bug #412214. + # + fp = open(TESTFN, "w") + fp.write("this is not a legal zip file\n") + fp.close() + try: + zf = zipfile.ZipFile(TESTFN) + except zipfile.BadZipfile: + os.unlink(TESTFN) + + def testNonExistentFileRaisesIOError(self): + # make sure we don't raise an AttributeError when a partially-constructed + # ZipFile instance is finalized; this tests for regression on SF tracker + # bug #403871. + + # The bug we're testing for caused an AttributeError to be raised + # when a ZipFile instance was created for a file that did not + # exist; the .fp member was not initialized but was needed by the + # __del__() method. Since the AttributeError is in the __del__(), + # it is ignored, but the user should be sufficiently annoyed by + # the message on the output that regression will be noticed + # quickly. + self.assertRaises(IOError, zipfile.ZipFile, TESTFN) + + def testClosedZipRaisesRuntimeError(self): + # Verify that testzip() doesn't swallow inappropriate exceptions. + data = StringIO() + zipf = zipfile.ZipFile(data, mode="w") + zipf.writestr("foo.txt", "O, for a Muse of Fire!") + zipf.close() + + # This is correct; calling .read on a closed ZipFile should throw + # a RuntimeError, and so should calling .testzip. An earlier + # version of .testzip would swallow this exception (and any other) + # and report that the first file in the archive was corrupt. + self.assertRaises(RuntimeError, zipf.testzip) + +def test_main(): + run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests, PyZipFileTests) + #run_unittest(TestZip64InSmallFiles) + +if __name__ == "__main__": + test_main() Added: trunk/jython/Lib/zipfile.py =================================================================== --- trunk/jython/Lib/zipfile.py (rev 0) +++ trunk/jython/Lib/zipfile.py 2008-11-24 05:01:02 UTC (rev 5629) @@ -0,0 +1,900 @@ +""" +Read and write ZIP files. +""" +import struct, os, time, sys +import binascii, cStringIO + +try: + import zlib # We may need its compression method +except ImportError: + zlib = None + +__all__ = ["BadZipfile", "error", "ZIP_STORED", "ZIP_DEFLATED", "is_zipfile", + "ZipInfo", "ZipFile", "PyZipFile", "LargeZipFile" ] + +class BadZipfile(Exception): + pass + + +class LargeZipFile(Exception): + """ + Raised when writing a zipfile, the zipfile requires ZIP64 extensions + and those extensions are disabled. + """ + +error = BadZipfile # The exception raised by this module + +ZIP64_LIMIT= (1 << 31) - 1 + +# constants for Zip file compression methods +ZIP_STORED = 0 +ZIP_DEFLATED = 8 +# Other ZIP compression methods not supported + +# Here are some struct module formats for reading headers +structEndArchive = "<4s4H2LH" # 9 items, end of archive, 22 bytes +stringEndArchive = "PK\005\006" # magic number for end of archive record +structCentralDir = "<4s4B4HlLL5HLL"# 19 items, central directory, 46 bytes +stringCentralDir = "PK\001\002" # magic number for central directory +structFileHeader = "<4s2B4HlLL2H" # 12 items, file header record, 30 bytes +stringFileHeader = "PK\003\004" # magic number for file header +structEndArchive64Locator = "<4slql" # 4 items, locate Zip64 header, 20 bytes +stringEndArchive64Locator = "PK\x06\x07" # magic token for locator header +structEndArchive64 = "<4sqhhllqqqq" # 10 items, end of archive (Zip64), 56 bytes +stringEndArchive64 = "PK\x06\x06" # magic token for Zip64 header + + +# indexes of entries in the central directory structure +_CD_SIGNATURE = 0 +_CD_CREATE_VERSION = 1 +_CD_CREATE_SYSTEM = 2 +_CD_EXTRACT_VERSION = 3 +_CD_EXTRACT_SYSTEM = 4 # is this meaningful? +_CD_FLAG_BITS = 5 +_CD_COMPRESS_TYPE = 6 +_CD_TIME = 7 +_CD_DATE = 8 +_CD_CRC = 9 +_CD_COMPRESSED_SIZE = 10 +_CD_UNCOMPRESSED_SIZE = 11 +_CD_FILENAME_LENGTH = 12 +_CD_EXTRA_FIELD_LENGTH = 13 +_CD_COMMENT_LENGTH = 14 +_CD_DISK_NUMBER_START = 15 +_CD_INTERNAL_FILE_ATTRIBUTES = 16 +_CD_EXTERNAL_FILE_ATTRIBUTES = 17 +_CD_LOCAL_HEADER_OFFSET = 18 + +# indexes of entries in the local file header structure +_FH_SIGNATURE = 0 +_FH_EXTRACT_VERSION = 1 +_FH_EXTRACT_SYSTEM = 2 # is this meaningful? +_FH_GENERAL_PURPOSE_FLAG_BITS = 3 +_FH_COMPRESSION_METHOD = 4 +_FH_LAST_MOD_TIME = 5 +_FH_LAST_MOD_DATE = 6 +_FH_CRC = 7 +_FH_COMPRESSED_SIZE = 8 +_FH_UNCOMPRESSED_SIZE = 9 +_FH_FILENAME_LENGTH = 10 +_FH_EXTRA_FIELD_LENGTH = 11 + +def is_zipfile(filename): + """Quickly see if file is a ZIP file by checking the magic number.""" + try: + fpin = open(filename, "rb") + endrec = _EndRecData(fpin) + fpin.close() + if endrec: + return True # file has correct magic number + except IOError: + pass + return False + +def _EndRecData64(fpin, offset, endrec): + """ + Read the ZIP64 end-of-archive records and use that to update endrec + """ + locatorSize = struct.calcsize(structEndArchive64Locator) + fpin.seek(offset - locatorSize, 2) + data = fpin.read(locatorSize) + sig, diskno, reloff, disks = struct.unpack(structEndArchive64Locator, data) + if sig != stringEndArchive64Locator: + return endrec + + if diskno != 0 or disks != 1: + raise BadZipfile("zipfiles that span multiple disks are not supported") + + # Assume no 'zip64 extensible data' + endArchiveSize = struct.calcsize(structEndArchive64) + fpin.seek(offset - locatorSize - endArchiveSize, 2) + data = fpin.read(endArchiveSize) + sig, sz, create_version, read_version, disk_num, disk_dir, \ + dircount, dircount2, dirsize, diroffset = \ + struct.unpack(structEndArchive64, data) + if sig != stringEndArchive64: + return endrec + + # Update the original endrec using data from the ZIP64 record + endrec[1] = disk_num + endrec[2] = disk_dir + endrec[3] = dircount + endrec[4] = dircount2 + endrec[5] = dirsize + endrec[6] = diroffset + return endrec + + +def _EndRecData(fpin): + """Return data from the "End of Central Directory" record, or None. + + The data is a list of the nine items in the ZIP "End of central dir" + record followed by a tenth item, the file seek offset of this record.""" + fpin.seek(-22, 2) # Assume no archive comment. + filesize = fpin.tell() + 22 # Get file size + data = fpin.read() + if data[0:4] == stringEndArchive and data[-2:] == "\000\000": + endrec = struct.unpack(structEndArchive, data) + endrec = list(endrec) + endrec.append("") # Append the archive comment + endrec.append(filesize - 22) # Append the record start offset + if endrec[-4] == -1 or endrec[-4] == 0xffffffff: + return _EndRecData64(fpin, -22, endrec) + return endrec + # Search the last END_BLOCK bytes of the file for the record signature. + # The comment is appended to the ZIP file and has a 16 bit length. + # So the comment may be up to 64K long. We limit the search for the + # signature to a few Kbytes at the end of the file for efficiency. + # also, the signature must not appear in the comment. + END_BLOCK = min(filesize, 1024 * 4) + fpin.seek(filesize - END_BLOCK, 0) + data = fpin.read() + start = data.rfind(stringEndArchive) + if start >= 0: # Correct signature string was found + endrec = struct.unpack(structEndArchive, data[start:start+22]) + endrec = list(endrec) + comment = data[start+22:] + if endrec[7] == len(comment): # Comment length checks out + # Append the archive comment and start offset + endrec.append(comment) + endrec.append(filesize - END_BLOCK + start) + if endrec[-4] == -1 or endrec[-4] == 0xffffffff: + return _EndRecData64(fpin, - END_BLOCK + start, endrec) + return endrec + return # Error, return None + + +class ZipInfo (object): + """Class with attributes describing each file in the ZIP archive.""" + + __slots__ = ( + 'orig_filename', + 'filename', + 'date_time', + 'compress_type', + 'comment', + 'extra', + 'create_system', + 'create_version', + 'extract_version', + 'reserved', + 'flag_bits', + 'volume', + 'internal_attr', + 'external_attr', + 'header_offset', + 'CRC', + 'compress_size', + 'file_size', + ) + + def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)): + self.orig_filename = filename # Original file name in archive + + # Terminate the file name at the first null byte. Null bytes in file + # names are used as tricks by viruses in archives. + null_byte = filename.find(chr(0)) + if null_byte >= 0: + filename = filename[0:null_byte] + # This is used to ensure paths in generated ZIP files always use + # forward slashes as the directory separator, as required by the + # ZIP format specification. + if os.sep != "/" and os.sep in filename: + filename = filename.replace(os.sep, "/") + + self.filename = filename # Normalized file name + self.date_time = date_time # year, month, day, hour, min, sec + # Standard values: + self.compress_type = ZIP_STORED # Type of compression for the file + self.comment = "" # Comment for each file + self.extra = "" # ZIP extra data + if sys.platform == 'win32': + self.create_system = 0 # System which created ZIP archive + else: + # Assume everything else is unix-y + self.create_system = 3 # System which created ZIP archive + self.create_version = 20 # Version which created ZIP archive + self.extract_version = 20 # Version needed to extract archive + self.reserved = 0 # Must be zero + self.flag_bits = 0 # ZIP flag bits + self.volume = 0 # Volume number of file header + self.internal_attr = 0 # Internal attributes + self.external_attr = 0 # External file attributes + # Other attributes are set by class ZipFile: + # header_offset Byte offset to the file header + # CRC CRC-32 of the uncompressed file + # compress_size Size of the compressed file + # file_size Size of the uncompressed file + + def FileHeader(self): + """Return the per-file header as a string.""" + dt = self.date_time + dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2] + dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2) + if self.flag_bits & 0x08: + # Set these to zero because we write them after the file data + CRC = compress_size = file_size = 0 + else: + CRC = self.CRC + compress_size = self.compress_size + file_size = self.file_size + + extra = self.extra + + if file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT: + # File is larger than what fits into a 4 byte integer, + # fall back to the ZIP64 extension + fmt = '<hhqq' + extra = extra + struct.pack(fmt, + 1, struct.calcsize(fmt)-4, file_size, compress_size) + file_size = 0xffffffff # -1 + compress_size = 0xffffffff # -1 + self.extract_version = max(45, self.extract_version) + self.create_version = max(45, self.extract_version) + + header = struct.pack(structFileHeader, stringFileHeader, + self.extract_version, self.reserved, self.flag_bits, + self.compress_type, dostime, dosdate, CRC, + compress_size, file_size, + len(self.filename), len(extra)) + return header + self.filename + extra + + def _decodeExtra(self): + # Try to decode the extra field. + extra = self.extra + unpack = struct.unpack + while extra: + tp, ln = unpack('<hh', extra[:4]) + if tp == 1: + if ln >= 24: + counts = unpack('<qqq', extra[4:28]) + elif ln == 16: + counts = unpack('<qq', extra[4:20]) + elif ln == 8: + counts = unpack('<q', extra[4:12]) + elif ln == 0: + counts = () + else: + raise RuntimeError, "Corrupt extra field %s"%(ln,) + + idx = 0 + + # ZIP64 extension (large files and/or large archives) + if self.file_size == -1 or self.file_size == 0xFFFFFFFFL: + self.file_size = counts[idx] + idx += 1 + + if self.compress_size == -1 or self.compress_size == 0xFFFFFFFFL: + self.compress_size = counts[idx] + idx += 1 + + if self.header_offset == -1 or self.header_offset == 0xffffffffL: + old = self.header_offset + self.header_offset = counts[idx] + idx+=1 + + extra = extra[ln+4:] + + +class ZipFile: + """ Class with methods to open, read, write, close, list zip files. + + z = ZipFile(file, mode="r", compression=ZIP_STORED, allowZip64=True) + + file: Either the path to the file, or a file-like object. + If it is a path, the file will be opened and closed by ZipFile. + mode: The mode can be either read "r", write "w" or append "a". + compression: ZIP_STORED (no compression) or ZIP_DEFLATED (requires zlib). + allowZip64: if True ZipFile will create files with ZIP64 extensions when + needed, otherwise it will raise an exception when this would + be necessary. + + """ + + fp = None # Set here since __del__ checks it + + def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=False): + """Open the ZIP file with mode read "r", write "w" or append "a".""" + self._allowZip64 = allowZip64 + self._didModify = False + if compression == ZIP_STORED: + pass + elif compression == ZIP_DEFLATED: + if not zlib: + raise RuntimeError,\ + "Compression requires the (missing) zlib module" + else: + raise RuntimeError, "That compression method is not supported" + self.debug = 0 # Level of printing: 0 through 3 + self.NameToInfo = {} # Find file info given name + self.filelist = [] # List of ZipInfo instances for archive + self.compression = compression # Method of compression + self.mode = key = mode.replace('b', '')[0] + + # Check if we were passed a file-like object + if isinstance(file, basestring): + self._filePassed = 0 + self.filename = file + modeDict = {'r' : 'rb', 'w': 'wb', 'a' : 'r+b'} + self.fp = open(file, modeDict[mode]) + else: + self._filePassed = 1 + self.fp = file + self.filename = getattr(file, 'name', None) + + if key == 'r': + self._GetContents() + elif key == 'w': + pass + elif key == 'a': + try: # See if file is a zip file + self._RealGetContents() + # seek to start of directory and overwrite + self.fp.seek(self.start_dir, 0) + except BadZipfile: # file is not a zip file, just append + self.fp.seek(0, 2) + else: + if not self._filePassed: + self.fp.close() + self.fp = None + raise RuntimeError, 'Mode must be "r", "w" or "a"' + + def _GetContents(self): + """Read the directory, making sure we close the file if the format + is bad.""" + try: + self._RealGetContents() + except BadZipfile: + if not self._filePassed: + self.fp.close() + self.fp = None + raise + + def _RealGetContents(self): + """Read in the table of contents for the ZIP file.""" + fp = self.fp + endrec = _EndRecData(fp) + if not endrec: + raise BadZipfile, "File is not a zip file" + if self.debug > 1: + print endrec + size_cd = endrec[5] # bytes in central directory + offset_cd = endrec[6] # offset of central directory + self.comment = endrec[8] # archive comment + # endrec[9] is the offset of the "End of Central Dir" record + if endrec[9] > ZIP64_LIMIT: + x = endrec[9] - size_cd - 56 - 20 + else: + x = endrec[9] - size_cd + # "concat" is zero, unless zip was concatenated to another file + concat = x - offset_cd + if self.debug > 2: + print "given, inferred, offset", offset_cd, x, concat + # self.start_dir: Position of start of central directory + self.start_dir = offset_cd + concat + fp.seek(self.start_dir, 0) + data = fp.read(size_cd) + fp = cStringIO.StringIO(data) + total = 0 + while total < size_cd: + centdir = fp.read(46) + total = total + 46 + if centdir[0:4] != stringCentralDir: + raise BadZipfile, "Bad magic number for central directory" + centdir = struct.unpack(structCentralDir, centdir) + if self.debug > 2: + print centdir + filename = fp.read(centdir[_CD_FILENAME_LENGTH]) + # Create ZipInfo instance to store file information + x = ZipInfo(filename) + x.extra = fp.read(centdir[_CD_EXTRA_FIELD_LENGTH]) + x.comment = fp.read(centdir[_CD_COMMENT_LENGTH]) + total = (total + centdir[_CD_FILENAME_LENGTH] + + centdir[_CD_EXTRA_FIELD_LENGTH] + + centdir[_CD_COMMENT_LENGTH]) + x.header_offset = centdir[_CD_LOCAL_HEADER_OFFSET] + (x.create_version, x.create_system, x.extract_version, x.reserved, + x.flag_bits, x.compress_type, t, d, + x.CRC, x.compress_size, x.file_size) = centdir[1:12] + x.volume, x.internal_attr, x.external_attr = centdir[15:18] + # Convert date/time code to (year, month, day, hour, min, sec) + x.date_time = ( (d>>9)+1980, (d>>5)&0xF, d&0x1F, + t>>11, (t>>5)&0x3F, (t&0x1F) * 2 ) + + x._decodeExtra() + x.header_offset = x.header_offset + concat + self.filelist.append(x) + self.NameToInfo[x.filename] = x + if self.debug > 2: + print "total", total + + + def namelist(self): + """Return a list of file names in the archive.""" + l = [] + for data in self.filelist: + l.append(data.filename) + return l + + def infolist(self): + """Return a list of class ZipInfo instances for files in the + archive.""" + return self.filelist + + def printdir(self): + """Print a table of contents for the zip file.""" + print "%-46s %19s %12s" % ("File Name", "Modified ", "Size") + for zinfo in self.filelist: + date = "%d-%02d-%02d %02d:%02d:%02d" % zinfo.date_time[:6] + print "%-46s %s %12d" % (zinfo.filename, date, zinfo.file_size) + + def testzip(self): + """Read all the files and check the CRC.""" + for zinfo in self.filelist: + try: + self.read(zinfo.filename) # Check CRC-32 + except BadZipfile: + return zinfo.filename + + + def getinfo(self, name): + """Return the instance of ZipInfo given 'name'.""" + return self.NameToInfo[name] + + def read(self, name): + """Return file bytes (as a string) for name.""" + if self.mode not in ("r", "a"): + raise RuntimeError, 'read() requires mode "r" or "a"' + if not self.fp: + raise RuntimeError, \ + "Attempt to read ZIP archive that was already closed" + zinfo = self.getinfo(name) + filepos = self.fp.tell() + + self.fp.seek(zinfo.header_offset, 0) + + # Skip the file header: + fheader = self.fp.read(30) + if fheader[0:4] != stringFileHeader: + raise BadZipfile, "Bad magic number for file header" + + fheader = struct.unpack(structFileHeader, fheader) + fname = self.fp.read(fheader[_FH_FILENAME_LENGTH]) + if fheader[_FH_EXTRA_FIELD_LENGTH]: + self.fp.read(fheader[_FH_EXTRA_FIELD_LENGTH]) + + if fname != zinfo.orig_filename: + raise BadZipfile, \ + 'File name in directory "%s" and header "%s" differ.' % ( + zinfo.orig_filename, fname) + + bytes = self.fp.read(zinfo.compress_size) + self.fp.seek(filepos, 0) + if zinfo.compress_type == ZIP_STORED: + pass + elif zinfo.compress_type == ZIP_DEFLATED: + if not zlib: + raise RuntimeError, \ + "De-compression requires the (missing) zlib module" + # zlib compress/decompress code by Jeremy Hylton of CNRI + dc = zlib.decompressobj(-15) + bytes = dc.decompress(bytes) + # need to feed in unused pad byte so that zlib won't choke + ex = dc.decompress('Z') + dc.flush() + if ex: + bytes = bytes + ex + else: + raise BadZipfile, \ + "Unsupported compression method %d for file %s" % \ + (zinfo.compress_type, name) + crc = binascii.crc32(bytes) + if crc != zinfo.CRC: + raise BadZipfile, "Bad CRC-32 for file %s" % name + return bytes + + def _writecheck(self, zinfo): + """Check for errors before writing a file to the archive.""" + if zinfo.filename in self.NameToInfo: + if self.debug: # Warning for duplicate names + print "Duplicate name:", zinfo.filename + if self.mode not in ("w", "a"): + raise RuntimeError, 'write() requires mode "w" or "a"' + if not self.fp: + raise RuntimeError, \ + "Attempt to write ZIP archive that was already closed" + if zinfo.compress_type == ZIP_DEFLATED and not zlib: + raise RuntimeError, \ + "Compression requires the (missing) zlib module" + if zinfo.compress_type not in (ZIP_STORED, ZIP_DEFLATED): + raise RuntimeError, \ + "That compression method is not supported" + if zinfo.file_size > ZIP64_LIMIT: + if not self._allowZip64: + raise LargeZipFile("Filesize would require ZIP64 extensions") + if zinfo.header_offset > ZIP64_LIMIT: + if not self._allowZip64: + raise LargeZipFile("Zipfile size would require ZIP64 extensions") + + def write(self, filename, arcname=None, compress_type=None): + """Put the bytes from filename into the archive under the name + arcname.""" + st = os.stat(filename) + mtime = time.localtime(st.st_mtime) + date_time = mtime[0:6] + # Create ZipInfo instance to store file information + if arcname is None: + arcname = filename + arcname = os.path.normpath(os.path.splitdrive(arcname)[1]) + while arcname[0] in (os.sep, os.altsep): + arcname = arcname[1:] + zinfo = ZipInfo(arcname, date_time) + zinfo.external_attr = (st[0] & 0xFFFF) << 16L # Unix attributes + if compress_type is None: + zinfo.compress_type = self.compression + else: + zinfo.compress_type = compress_type + + zinfo.file_size = st.st_size + zinfo.flag_bits = 0x00 + zinfo.header_offset = self.fp.tell() # Start of header bytes + + self._writecheck(zinfo) + self._didModify = True + fp = open(filename, "rb") + # Must overwrite CRC and sizes with correct data later + zinfo.CRC = CRC = 0 + zinfo.compress_size = compress_size = 0 + zinfo.file_size = file_size = 0 + self.fp.write(zinfo.FileHeader()) + if zinfo.compress_type == ZIP_DEFLATED: + cmpr = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, + zlib.DEFLATED, -15) + else: + cmpr = None + while 1: + buf = fp.read(1024 * 8) + if not buf: + break + file_size = file_size + len(buf) + CRC = binascii.crc32(buf, CRC) + if cmpr: + buf = cmpr.compress(buf) + compress_size = compress_size + len(buf) + self.fp.write(buf) + fp.close() + if cmpr: + buf = cmpr.flush() + compress_size = compress_size + len(buf) + self.fp.write(buf) + zinfo.compress_size = compress_size + else: + zinfo.compress_size = file_size + zinfo.CRC = CRC + zinfo.file_size = file_size + # Seek backwards and write CRC and file sizes + position = self.fp.tell() # Preserve current position in file + self.fp.seek(zinfo.header_offset + 14, 0) + self.fp.write(struct.pack("<lLL", zinfo.CRC, zinfo.compress_size, + zinfo.file_size)) + self.fp.seek(position, 0) + self.filelist.append(zinfo) + self.NameToInfo[zinfo.filename] = zinfo + + def writestr(self, zinfo_or_arcname, bytes): + """Write a file into the archive. The contents is the string + 'bytes'. 'zinfo_or_arcname' is either a ZipInfo instance or + the name of the file in the archive.""" + if not isinstance(zinfo_or_arcname, ZipInfo): + zinfo = ZipInfo(filename=zinfo_or_arcname, + date_time=time.localtime(time.time())[:6]) + zinfo.compress_type = self.compression + else: + zinfo = zinfo_or_arcname + zinfo.file_size = len(bytes) # Uncompressed size + zinfo.header_offset = self.fp.tell() # Start of header bytes + self._writecheck(zinfo) + self._didModify = True + zinfo.CRC = binascii.crc32(bytes) # CRC-32 checksum + if zinfo.compress_type == ZIP_DEFLATED: + co = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, + zlib.DEFLATED, -15) + bytes = co.compress(bytes) + co.flush() + zinfo.compress_size = len(bytes) # Compressed size + else: + zinfo.compress_size = zinfo.file_size + zinfo.header_offset = self.fp.tell() # Start of header bytes + self.fp.write(zinfo.FileHeader()) + self.fp.write(bytes) + self.fp.flush() + if zinfo.flag_bits & 0x08: + # Write CRC and file sizes after the file data + self.fp.write(struct.pack("<lLL", zinfo.CRC, zinfo.compress_size, + zinfo.file_size)) + self.filelist.append(zinfo) + self.NameToInfo[zinfo.filename] = zinfo + + def __del__(self): + """Call the "close()" method in case the user forgot.""" + self.close() + + def close(self): + """Close the file, and for mode "w" and "a" write the ending + records.""" + if self.fp is None: + return + + if self.mode in ("w", "a") and self._didModify: # write ending records + count = 0 + pos1 = self.fp.tell() + for zinfo in self.filelist: # write central directory + count = count + 1 + dt = zinfo.date_time + dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2] + dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2) + extra = [] + if zinfo.file_size > ZIP64_LIMIT \ + or zinfo.compress_size > ZIP64_LIMIT: + extra.append(zinfo.file_size) + extra.append(zinfo.compress_size) + file_size = 0xffffffff #-1 + compress_size = 0xffffffff #-1 + else: + file_size = zinfo.file_size + compress_size = zinfo.compress_size + + if zinfo.header_offset > ZIP64_LIMIT: + extra.append(zinfo.header_offset) + header_offset = -1 # struct "l" format: 32 one bits + else: + header_offset = zinfo.header_offset + + extra_data = zinfo.extra + if extra: + # Append a ZIP64 field to the extra's + extra_data = struct.pack( + '<hh' + 'q'*len(extra), + 1, 8*len(extra), *extra) + extra_data + + extract_version = max(45, zinfo.extract_version) + create_version = max(45, zinfo.create_version) + else: + extract_version = zinfo.extract_version + create_version = zinfo.create_version + + centdir = struct.pack(structCentralDir, + stringCentralDir, create_version, + zinfo.create_system, extract_version, zinfo.reserved, + zinfo.flag_bits, zinfo.compress_type, dostime, dosdate, + zinfo.CRC, compress_size, file_size, + len(zinfo.filename), len(extra_data), len(zinfo.comment), + 0, zinfo.internal_attr, zinfo.external_attr, + header_offset) + self.fp.write(centdir) + self.fp.write(zinfo.filename) + self.fp.write(extra_data) + self.fp.write(zinfo.comment) + + pos2 = self.fp.tell() + # Write end-of-zip-archive record + if pos1 > ZIP64_LIMIT: + # Need to write the ZIP64 end-of-archive records + zip64endrec = struct.pack( + structEndArchive64, stringEndArchive64, + 44, 45, 45, 0, 0, count, count, pos2 - pos1, pos1) + self.fp.write(zip64endrec) + + zip64locrec = struct.pack( + structEndArchive64Locator, + stringEndArchive64Locator, 0, pos2, 1) + self.fp.write(zip64locrec) + + # XXX Why is `pos3` computed next? It's never referenced. + pos3 = self.fp.tell() + endrec = struct.pack(structEndArchive, stringEndArchive, + 0, 0, count, count, pos2 - pos1, -1, 0) + self.fp.write(endrec) + + else: + endrec = struct.pack(structEndArchive, stringEndArchive, + 0, 0, count, count, pos2 - pos1, pos1, 0) + self.fp.write(endrec) + self.fp.flush() + if not self._filePassed: + self.fp.close() + self.fp = None + + +class PyZipFile(ZipFile): + """Class to create ZIP archives with Python library files and packages.""" + + def writepy(self, pathname, basename = ""): + """Add all files from "pathname" to the ZIP archive. + + If pathname is a package directory, search the directory and + all package subdirectories recursively for all *.py and enter + the modules into the archive. If pathname is a plain + directory, listdir *.py and enter all modules. Else, pathname + must be a Python *.py file and the module will be put into the + archive. Added modules are always module.pyo or module.pyc. + This method will compile the module.py into module.pyc if + necessary. + """ + dir, name = os.path.split(pathname) + if os.path.isdir(pathname): + initname = os.path.join(pathname, "__init__.py") + if os.path.isfile(initname): + # This is a package directory, add it + if basename: + basename = "%s/%s" % (basename, name) + else: + basename = name + if self.debug: + print "Adding package in", pathname, "as", basename + fname, arcname = self._get_codename(initname[0:-3], basename) + if self.debug: + print "Adding", arcname + self.write(fname, arcname) + dirlist = os.listdir(pathname) + dirlist.remove("__init__.py") + # Add all *.py files and package subdirectories + for filename in dirlist: + path = os.path.join(pathname, filename) + root, ext = os.path.splitext(filename) + if os.path.isdir(path): + if os.path.isfile(os.path.join(path, "__init__.py")): + # This is a package directory, add it + self.writepy(path, basename) # Recursive call + elif ext == ".py": + fname, arcname = self._get_codename(path[0:-3], + basename) + if self.debug: + print "Adding", arcname + self.write(fname, arcname) + else: + # This is NOT a package directory, add its files at top level + if self.debug: + print "Adding files from directory", pathname + for filename in os.listdir(pathname): + path = os.path.join(pathname, filename) + root, ext = os.path.splitext(filename) + if ext == ".py": + fname, arcname = self._get_codename(path[0:-3], + basename) + if self.debug: + print "Adding", arcname + self.write(fname, arcname) + else: + if pathname[-3:] != ".py": + raise RuntimeError, \ + 'Files added with writepy() must end with ".py"' + fname, arcname = self._get_codename(pathname[0:-3], basename) + if self.debug: + print "Adding file", arcname + self.write(fname, arcname) + + def _get_codename(self, pathname, basename): + """Return (filename, archivename) for the path. + + Given a module name path, return the correct file path and + archive name, compiling if necessary. For example, given + /python/lib/string, return (/python/lib/string.pyc, string). + """ + file_py = pathname + ".py" + file_pyc = pathname + ".pyc" + file_pyo = pathname + ".pyo" + if os.path.isfile(file_pyo) and \ + os.stat(file_pyo).st_mtime >= os.stat(file_py).st_mtime: + fname = file_pyo # Use .pyo file + elif not os.path.isfile(file_pyc) or \ + os.stat(file_pyc).st_mtime < os.stat(file_py).st_mtime: + import py_compile + if self.debug: + print "Compiling", file_py + try: + py_compile.compile(file_py, file_pyc, None, True) + except py_compile.PyCompileError,err: + print err.msg + fname = file_pyc + else: + fname = file_pyc + archivename = os.path.split(fname)[1] + if basename: + archivename = "%s/%s" % (basename, archivename) + return (fname, archivename) + + +def main(args = None): + import textwrap + USAGE=textwrap.dedent("""\ + Usage: + zipfile.py -l zipfile.zip # Show listing of a zipfile + zipfile.py -t zipfile.zip # Test if a zipfile is valid + zipfile.py -e zipfile.zip target # Extract zipfile into target dir + zipfile.py -c zipfile.zip src ... # Create zipfile from sources + """) + if args is None: + args = sys.argv[1:] + + if not args or args[0] not in ('-l', '-c', '-e', '-t'): + print USAGE + sys.exit(1) + + if args[0] == '-l': + if len(args) != 2: + print USAGE + sys.exit(1) + zf = ZipFile(args[1], 'r') + zf.printdir() + zf.close() + + elif args[0] == '-t': + if len(args) != 2: + print USAGE + sys.exit(1) + zf = ZipFile(args[1], 'r') + zf.testzip() + print "Done testing" + + elif args[0] == '-e': + if len(args) != 3: + print USAGE + sys.exit(1) + + zf = ZipFile(args[1], 'r') + out = args[2] + for path in zf.namelist(): + if path.startswith('./'): + tgt = os.path.join(out, path[2:]) + else: + tgt = os.path.join(out, path) + + tgtdir = os.path.dirname(tgt) + if not os.path.exists(tgtdir): + os.makedirs(tgtdir) + fp = open(tgt, 'wb') + fp.write(zf.read(path)) + fp.close() + zf.close() + + elif args[0] == '-c': + if len(args) < 3: + print USAGE + sys.exit(1) + + def addToZip(zf, path, zippath): + if os.path.isfile(path): + zf.write(path, zippath, ZIP_DEFLATED) + elif os.path.isdir(path): + for nm in os.listdir(path): + addToZip(zf, + os.path.join(path, nm), os.path.join(zippath, nm)) + # else: ignore + + zf = ZipFile(args[1], 'w', allowZip64=True) + for src in args[2:]: + addToZip(zf, src, os.path.basename(src)) + + zf.close() + +if __name__ == "__main__": + main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2008-11-24 05:02:05
|
Revision: 5630 http://jython.svn.sourceforge.net/jython/?rev=5630&view=rev Author: pjenvey Date: 2008-11-24 05:02:01 +0000 (Mon, 24 Nov 2008) Log Message: ----------- fix PyZipFile to compile to $py.class Modified Paths: -------------- trunk/jython/Lib/test/test_zipfile.py trunk/jython/Lib/zipfile.py Modified: trunk/jython/Lib/test/test_zipfile.py =================================================================== --- trunk/jython/Lib/test/test_zipfile.py 2008-11-24 05:01:02 UTC (rev 5629) +++ trunk/jython/Lib/test/test_zipfile.py 2008-11-24 05:02:01 UTC (rev 5630) @@ -9,7 +9,7 @@ from StringIO import StringIO from tempfile import TemporaryFile -from test.test_support import TESTFN, run_unittest +from test.test_support import TESTFN, is_jython, run_unittest TESTFN2 = TESTFN + "2" @@ -245,12 +245,17 @@ fn = __file__ if fn.endswith('.pyc') or fn.endswith('.pyo'): fn = fn[:-1] + elif fn.endswith('$py.class'): + fn = fn[:-9] + '.py' zipfp.writepy(fn) bn = os.path.basename(fn) self.assert_(bn not in zipfp.namelist()) - self.assert_(bn + 'o' in zipfp.namelist() or bn + 'c' in zipfp.namelist()) + if not is_jython: + self.assert_(bn + 'o' in zipfp.namelist() or bn + 'c' in zipfp.namelist()) + else: + self.assert_(bn[:-3] + '$py.class' in zipfp.namelist()) zipfp.close() @@ -258,12 +263,17 @@ fn = __file__ if fn.endswith('.pyc') or fn.endswith('.pyo'): fn = fn[:-1] + elif fn.endswith('$py.class'): + fn = fn[:-9] + '.py' zipfp.writepy(fn, "testpackage") bn = "%s/%s"%("testpackage", os.path.basename(fn)) self.assert_(bn not in zipfp.namelist()) - self.assert_(bn + 'o' in zipfp.namelist() or bn + 'c' in zipfp.namelist()) + if not is_jython: + self.assert_(bn + 'o' in zipfp.namelist() or bn + 'c' in zipfp.namelist()) + else: + self.assert_(bn[:-3] + '$py.class' in zipfp.namelist()) zipfp.close() def testWritePythonPackage(self): @@ -275,8 +285,12 @@ # Check for a couple of modules at different levels of the hieararchy names = zipfp.namelist() - self.assert_('email/__init__.pyo' in names or 'email/__init__.pyc' in names) - self.assert_('email/mime/text.pyo' in names or 'email/mime/text.pyc' in names) + if not is_jython: + self.assert_('email/__init__.pyo' in names or 'email/__init__.pyc' in names) + self.assert_('email/mime/text.pyo' in names or 'email/mime/text.pyc' in names) + else: + self.assert_('email/__init__$py.class' in names) + self.assert_('email/mime/text$py.class' in names) def testWritePythonDirectory(self): os.mkdir(TESTFN2) @@ -297,8 +311,12 @@ zipfp.writepy(TESTFN2) names = zipfp.namelist() - self.assert_('mod1.pyc' in names or 'mod1.pyo' in names) - self.assert_('mod2.pyc' in names or 'mod2.pyo' in names) + if not is_jython: + self.assert_('mod1.pyc' in names or 'mod1.pyo' in names) + self.assert_('mod2.pyc' in names or 'mod2.pyo' in names) + else: + self.assert_('mod1$py.class' in names) + self.assert_('mod2$py.class' in names) self.assert_('mod2.txt' not in names) finally: Modified: trunk/jython/Lib/zipfile.py =================================================================== --- trunk/jython/Lib/zipfile.py 2008-11-24 05:01:02 UTC (rev 5629) +++ trunk/jython/Lib/zipfile.py 2008-11-24 05:02:01 UTC (rev 5630) @@ -12,6 +12,8 @@ __all__ = ["BadZipfile", "error", "ZIP_STORED", "ZIP_DEFLATED", "is_zipfile", "ZipInfo", "ZipFile", "PyZipFile", "LargeZipFile" ] +is_jython = sys.platform.startswith('java') + class BadZipfile(Exception): pass @@ -800,7 +802,7 @@ /python/lib/string, return (/python/lib/string.pyc, string). """ file_py = pathname + ".py" - file_pyc = pathname + ".pyc" + file_pyc = pathname + (".pyc" if not is_jython else "$py.class") file_pyo = pathname + ".pyo" if os.path.isfile(file_pyo) and \ os.stat(file_pyo).st_mtime >= os.stat(file_py).st_mtime: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2008-12-19 17:02:14
|
Revision: 5782 http://jython.svn.sourceforge.net/jython/?rev=5782&view=rev Author: amak Date: 2008-12-19 17:02:10 +0000 (Fri, 19 Dec 2008) Log Message: ----------- Checking in support for UDP broadcast special constants, including INADDR_ANY and INADDR_BROADCAST. See this bug for details http://bugs.jython.org/issue1043 Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2008-12-19 07:45:01 UTC (rev 5781) +++ trunk/jython/Lib/socket.py 2008-12-19 17:02:10 UTC (rev 5782) @@ -148,17 +148,6 @@ SHUT_WR = 1 SHUT_RDWR = 2 -__all__ = ['AF_UNSPEC', 'AF_INET', 'AF_INET6', 'AI_PASSIVE', 'SOCK_DGRAM', - 'SOCK_RAW', 'SOCK_RDM', 'SOCK_SEQPACKET', 'SOCK_STREAM', 'SOL_SOCKET', - 'SO_BROADCAST', 'SO_ERROR', 'SO_KEEPALIVE', 'SO_LINGER', 'SO_OOBINLINE', - 'SO_RCVBUF', 'SO_REUSEADDR', 'SO_SNDBUF', 'SO_TIMEOUT', 'TCP_NODELAY', - 'SocketType', 'error', 'herror', 'gaierror', 'timeout', - 'getfqdn', 'gethostbyaddr', 'gethostbyname', 'gethostname', - 'socket', 'getaddrinfo', 'getdefaulttimeout', 'setdefaulttimeout', - 'has_ipv6', 'htons', 'htonl', 'ntohs', 'ntohl', - 'SHUT_RD', 'SHUT_WR', 'SHUT_RDWR', - ] - AF_UNSPEC = 0 AF_INET = 2 AF_INET6 = 23 @@ -183,6 +172,9 @@ SO_TIMEOUT = 128 TCP_NODELAY = 256 + +INADDR_ANY = "0.0.0.0" +INADDR_BROADCAST = "255.255.255.255" # Options with negative constants are not supported # They are being added here so that code that refers to them @@ -201,6 +193,18 @@ SO_TYPE = -1024 SO_USELOOPBACK = -2048 +__all__ = ['AF_UNSPEC', 'AF_INET', 'AF_INET6', 'AI_PASSIVE', 'SOCK_DGRAM', + 'SOCK_RAW', 'SOCK_RDM', 'SOCK_SEQPACKET', 'SOCK_STREAM', 'SOL_SOCKET', + 'SO_BROADCAST', 'SO_ERROR', 'SO_KEEPALIVE', 'SO_LINGER', 'SO_OOBINLINE', + 'SO_RCVBUF', 'SO_REUSEADDR', 'SO_SNDBUF', 'SO_TIMEOUT', 'TCP_NODELAY', + 'INADDR_ANY', 'INADDR_BROADCAST', + 'SocketType', 'error', 'herror', 'gaierror', 'timeout', + 'getfqdn', 'gethostbyaddr', 'gethostbyname', 'gethostname', + 'socket', 'getaddrinfo', 'getdefaulttimeout', 'setdefaulttimeout', + 'has_ipv6', 'htons', 'htonl', 'ntohs', 'ntohl', + 'SHUT_RD', 'SHUT_WR', 'SHUT_RDWR', + ] + class _nio_impl: timeout = None @@ -685,7 +689,7 @@ def _get_jsocket(self): return self.sock_impl.jsocket -def _unpack_address_tuple(address_tuple, for_tx=False): +def _unpack_address_tuple(address_tuple): # TODO: Upgrade to support the 4-tuples used for IPv6 addresses # which include flowinfo and scope_id. # To be upgraded in synch with getaddrinfo @@ -701,11 +705,6 @@ # currently broken hostname = hostname.encode() hostname = hostname.strip() - if hostname == "<broadcast>": - if for_tx: - hostname = "255.255.255.255" - else: - hostname = "0.0.0.0" return hostname, address_tuple[1] class _tcpsocket(_nonblocking_api_mixin): @@ -888,7 +887,9 @@ def bind(self, addr): try: assert not self.sock_impl - host, port = _unpack_address_tuple(addr) + host, port = _unpack_address_tuple(addr) + if host == "": + host = INADDR_ANY host_address = java.net.InetAddress.getByName(host) self.sock_impl = _datagram_socket_impl(port, host_address, self.pending_options[SO_REUSEADDR]) self._config() @@ -928,7 +929,9 @@ if not self.sock_impl: self.sock_impl = _datagram_socket_impl() self._config() - host, port = _unpack_address_tuple(addr, True) + host, port = _unpack_address_tuple(addr) + if host == "<broadcast>": + host = INADDR_BROADCAST byte_array = java.lang.String(data).getBytes('iso-8859-1') result = self.sock_impl.sendto(byte_array, host, port, flags) return result Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2008-12-19 07:45:01 UTC (rev 5781) +++ trunk/jython/Lib/test/test_socket.py 2008-12-19 17:02:10 UTC (rev 5782) @@ -873,7 +873,7 @@ self.serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) def testBroadcast(self): - self.serv.bind( ("<broadcast>", self.PORT) ) + self.serv.bind( ("", self.PORT) ) msg = self.serv.recv(len(EIGHT_BIT_MSG)) self.assertEqual(msg, EIGHT_BIT_MSG) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2008-12-21 22:28:33
|
Revision: 5783 http://jython.svn.sourceforge.net/jython/?rev=5783&view=rev Author: amak Date: 2008-12-21 22:28:30 +0000 (Sun, 21 Dec 2008) Log Message: ----------- 1. Fixed a bug whereby timeouts were not being honoured when recv()ing (http://bugs.jython.com/issue1154) 2. Fixed another (previously unreported) bug that resulted in an exception when switching from non-blocking to timeout mode. Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2008-12-19 17:02:10 UTC (rev 5782) +++ trunk/jython/Lib/socket.py 2008-12-21 22:28:30 UTC (rev 5783) @@ -6,8 +6,6 @@ XXX Restrictions: - Only INET sockets -- No asynchronous behavior -- No socket options - Can't do a very good gethostbyaddr() right... AMAK: 20050527: added socket timeouts AMAK: 20070515: Added non-blocking (asynchronous) support @@ -210,16 +208,6 @@ timeout = None mode = MODE_BLOCKING - def read(self, buf): - bytebuf = java.nio.ByteBuffer.wrap(buf) - count = self.jchannel.read(bytebuf) - return count - - def write(self, buf): - bytebuf = java.nio.ByteBuffer.wrap(buf) - count = self.jchannel.write(bytebuf) - return count - def getpeername(self): return (self.jsocket.getInetAddress().getHostAddress(), self.jsocket.getPort() ) @@ -230,6 +218,7 @@ if self.mode == MODE_NONBLOCKING: self.jchannel.configureBlocking(0) if self.mode == MODE_TIMEOUT: + self.jchannel.configureBlocking(1) self._timeout_millis = int(timeout*1000) self.jsocket.setSoTimeout(self._timeout_millis) @@ -321,6 +310,36 @@ def finish_connect(self): return self.jchannel.finishConnect() + def _do_read_net(self, buf): + # Need two separate implementations because the java.nio APIs do not support timeouts + return self.jsocket.getInputStream().read(buf) + + def _do_read_nio(self, buf): + bytebuf = java.nio.ByteBuffer.wrap(buf) + count = self.jchannel.read(bytebuf) + return count + + def _do_write_net(self, buf): + self.jsocket.getOutputStream().write(buf) + return len(buf) + + def _do_write_nio(self, buf): + bytebuf = java.nio.ByteBuffer.wrap(buf) + count = self.jchannel.write(bytebuf) + return count + + def read(self, buf): + if self.mode == MODE_TIMEOUT: + return self._do_read_net(buf) + else: + return self._do_read_nio(buf) + + def write(self, buf): + if self.mode == MODE_TIMEOUT: + return self._do_write_net(buf) + else: + return self._do_write_nio(buf) + class _server_socket_impl(_nio_impl): options = { @@ -824,6 +843,8 @@ if self.sock_impl.jchannel.isConnectionPending(): self.sock_impl.jchannel.finishConnect() numwritten = self.sock_impl.write(s) + if numwritten == 0 and self.mode == MODE_NONBLOCKING: + raise would_block_error() return numwritten except java.lang.Exception, jlx: raise _map_exception(jlx) Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2008-12-19 17:02:10 UTC (rev 5782) +++ trunk/jython/Lib/test/test_socket.py 2008-12-21 22:28:30 UTC (rev 5783) @@ -714,6 +714,16 @@ def _testRecv(self): self.serv_conn.send(MSG) + def testRecvTimeoutMode(self): + # Do this test in timeout mode, because the code path is different + self.cli_conn.settimeout(10) + msg = self.cli_conn.recv(1024) + self.assertEqual(msg, MSG) + + def _testRecvTimeoutMode(self): + self.serv_conn.settimeout(10) + self.serv_conn.send(MSG) + def testOverFlowRecv(self): # Testing receive in chunks over TCP seg1 = self.cli_conn.recv(len(MSG) - 3) @@ -1270,14 +1280,14 @@ bufsize = 2 # Exercise the buffering code -class TCPTimeoutTest(SocketTCPTest): +class TCPServerTimeoutTest(SocketTCPTest): - def testTCPTimeout(self): + def testAcceptTimeout(self): def raise_timeout(*args, **kwargs): self.serv.settimeout(1.0) self.serv.accept() self.failUnlessRaises(socket.timeout, raise_timeout, - "Error generating a timeout exception (TCP)") + "TCP socket accept failed to generate a timeout exception (TCP)") def testTimeoutZero(self): ok = False @@ -1293,9 +1303,9 @@ if not ok: self.fail("accept() returned success when we did not expect it") -class TCPClientTimeoutTest(unittest.TestCase): +class TCPClientTimeoutTest(SocketTCPTest): - def testClientTimeout(self): + def testConnectTimeout(self): cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM) cli.settimeout(0.1) host = '192.168.192.168' @@ -1310,8 +1320,45 @@ socket.timeout. This tries to connect to %s in the assumption that it isn't used, but if it is on your network this failure is bogus.''' % host) - + def testRecvTimeout(self): + def raise_timeout(*args, **kwargs): + cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + cli_sock.connect( (HOST, PORT) ) + cli_sock.settimeout(1) + cli_sock.recv(1024) + self.failUnlessRaises(socket.timeout, raise_timeout, + "TCP socket recv failed to generate a timeout exception (TCP)") + # Disable this test, but leave it present for documentation purposes + # socket timeouts only work for read and accept, not for write + # http://java.sun.com/j2se/1.4.2/docs/api/java/net/SocketTimeoutException.html + def estSendTimeout(self): + def raise_timeout(*args, **kwargs): + cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + cli_sock.connect( (HOST, PORT) ) + # First fill the socket + cli_sock.settimeout(1) + sent = 0 + while True: + bytes_sent = cli_sock.send(MSG) + sent += bytes_sent + self.failUnlessRaises(socket.timeout, raise_timeout, + "TCP socket send failed to generate a timeout exception (TCP)") + + def testSwitchModes(self): + cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + cli_sock.connect( (HOST, PORT) ) + # set non-blocking mode + cli_sock.setblocking(0) + # then set timeout mode + cli_sock.settimeout(1) + try: + cli_sock.send(MSG) + except Exception, x: + self.fail("Switching mode from non-blocking to timeout raised exception: %s" % x) + else: + pass + # # AMAK: 20070307 # Corrected the superclass of UDPTimeoutTest @@ -1539,7 +1586,7 @@ TestSupportedOptions, TestUnsupportedOptions, BasicTCPTest, - TCPTimeoutTest, + TCPServerTimeoutTest, TCPClientTimeoutTest, TestExceptions, TestInvalidUsage, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2008-12-24 02:22:17
|
Revision: 5796 http://jython.svn.sourceforge.net/jython/?rev=5796&view=rev Author: pjenvey Date: 2008-12-24 01:47:07 +0000 (Wed, 24 Dec 2008) Log Message: ----------- correct issue # reference, small cleanup Modified Paths: -------------- trunk/jython/Lib/os.py trunk/jython/Lib/test/test_builtin_jy.py Modified: trunk/jython/Lib/os.py =================================================================== --- trunk/jython/Lib/os.py 2008-12-23 19:56:53 UTC (rev 5795) +++ trunk/jython/Lib/os.py 2008-12-24 01:47:07 UTC (rev 5796) @@ -564,7 +564,7 @@ floor = long(seconds) except TypeError: raise TypeError('an integer is required') - if floor < _time_t.MIN_VALUE or floor > _time_t.MAX_VALUE: + if not _time_t.MIN_VALUE <= floor <= _time_t.MAX_VALUE: raise OverflowError('long int too large to convert to int') # usec can't exceed 1000000 Modified: trunk/jython/Lib/test/test_builtin_jy.py =================================================================== --- trunk/jython/Lib/test/test_builtin_jy.py 2008-12-23 19:56:53 UTC (rev 5795) +++ trunk/jython/Lib/test/test_builtin_jy.py 2008-12-24 01:47:07 UTC (rev 5796) @@ -17,7 +17,7 @@ self.assert_(not hasattr(Foo(), 'bar')) def test_dir(self): - # for http://bugs.jython.org/issue1063 + # for http://bugs.jython.org/issue1196 class Foo(object): def __getattribute__(self, name): return name This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <zy...@us...> - 2008-12-29 02:22:09
|
Revision: 5803 http://jython.svn.sourceforge.net/jython/?rev=5803&view=rev Author: zyasoft Date: 2008-12-29 01:30:27 +0000 (Mon, 29 Dec 2008) Log Message: ----------- Supports timeit. Ignore NotImplementedError when attempting to disable gc, along with some rudimentary unit tests extracted from the docs of timeit. Modified Paths: -------------- trunk/jython/Lib/timeit.py Added Paths: ----------- trunk/jython/Lib/test/test_timeit.py Added: trunk/jython/Lib/test/test_timeit.py =================================================================== --- trunk/jython/Lib/test/test_timeit.py (rev 0) +++ trunk/jython/Lib/test/test_timeit.py 2008-12-29 01:30:27 UTC (rev 5803) @@ -0,0 +1,37 @@ +import timeit +import unittest +import test.test_support + +# some uninspired unit tests extracted from the docs for timeit; +# changed number=10000 so we don't spend too much time testing this +# module in the regrtest + +class TestTimeit(unittest.TestCase): + + def test_oct(self): + timing = timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit(number=10000) + self.assertTrue(timing > 0.) + timing_vector = timeit.Timer('for i in xrange(10): oct(i)').repeat(number=10000) + self.assertEqual(len(timing_vector), 3) + self.assertTrue(min(timing_vector) > 0.) + + def test_str(self): + s = """\ + try: + str.__nonzero__ + except AttributeError: + pass + """ + t = timeit.Timer(stmt=s) + self.assertTrue(t.timeit(number=10000) > 0.) + + timing_vector = t.repeat(number=10000, repeat=10) + self.assertEqual(len(timing_vector), 10) + self.assertTrue(min(timing_vector) > 0.) + + +def test_main(): + test.test_support.run_unittest(TestTimeit) + +if __name__ == "__main__": + test_main() Modified: trunk/jython/Lib/timeit.py =================================================================== --- trunk/jython/Lib/timeit.py 2008-12-29 01:28:24 UTC (rev 5802) +++ trunk/jython/Lib/timeit.py 2008-12-29 01:30:27 UTC (rev 5803) @@ -157,7 +157,10 @@ else: it = [None] * number gcold = gc.isenabled() - gc.disable() + try: + gc.disable() + except NotImplementedError: + pass # ignore on platforms like Jython timing = self.inner(it, self.timer) if gcold: gc.enable() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <zy...@us...> - 2008-12-29 06:59:02
|
Revision: 5805 http://jython.svn.sourceforge.net/jython/?rev=5805&view=rev Author: zyasoft Date: 2008-12-29 06:59:00 +0000 (Mon, 29 Dec 2008) Log Message: ----------- Added signal support per http://bugs.jython.org/issue1074, with signal.py based on the patch submitted by Glyph Lefkowitz. One significant difference is that it introspects the signal constants through the API provided by sun.misc.Signals - no support for Constantine actually needed here. Also added os.kill, os.wait, and os.waitpid if running on posix. This should help with our Twisted support, among other packages. Modified Paths: -------------- trunk/jython/Lib/os.py trunk/jython/Lib/test/regrtest.py Added Paths: ----------- trunk/jython/Lib/signal.py trunk/jython/Lib/test/test_signal.py Modified: trunk/jython/Lib/os.py =================================================================== --- trunk/jython/Lib/os.py 2008-12-29 05:45:42 UTC (rev 5804) +++ trunk/jython/Lib/os.py 2008-12-29 06:59:00 UTC (rev 5805) @@ -41,6 +41,7 @@ 'write']) import errno +import jarray import java.lang.System import time import stat as _stat @@ -993,6 +994,45 @@ Call the system call setsid().""" return _posix.setsid() + # This implementation of fork partially works on + # Jython. Diagnosing what works, what doesn't, and fixing it is + # left for another day. In any event, this would only be + # marginally useful. + + # def fork(): + # """fork() -> pid + # + # Fork a child process. + # Return 0 to child process and PID of child to parent process.""" + # return _posix.fork() + + def kill(pid, sig): + """kill(pid, sig) + + Kill a process with a signal.""" + return _posix.kill(pid, sig) + + def wait(): + """wait() -> (pid, status) + + Wait for completion of a child process.""" + + status = jarray.zeros(1, 'i') + res_pid = _posix.wait(status) + if res_pid == -1: + raise OSError(status[0], strerror(status[0])) + return res_pid, status[0] + + def waitpid(pid, options): + """waitpid(pid, options) -> (pid, status) + + Wait for completion of a given child process.""" + status = jarray.zeros(1, 'i') + res_pid = _posix.waitpid(pid, status, options) + if res_pid == -1: + raise OSError(status[0], strerror(status[0])) + return res_pid, status[0] + def getpid(): """getpid() -> pid @@ -1029,7 +1069,6 @@ return fileno.isatty() -import jarray from java.security import SecureRandom urandom_source = None Added: trunk/jython/Lib/signal.py =================================================================== --- trunk/jython/Lib/signal.py (rev 0) +++ trunk/jython/Lib/signal.py 2008-12-29 06:59:00 UTC (rev 5805) @@ -0,0 +1,239 @@ +""" + This module provides mechanisms to use signal handlers in Python. + + Functions: + + signal(sig,action) -- set the action for a given signal (done) + pause(sig) -- wait until a signal arrives [Unix only] + alarm(seconds) -- cause SIGALRM after a specified time [Unix only] + getsignal(sig) -- get the signal action for a given signal + default_int_handler(action) -- default SIGINT handler (done, but acts string) + + Constants: + + SIG_DFL -- used to refer to the system default handler + SIG_IGN -- used to ignore the signal + NSIG -- number of defined signals + + SIGINT, SIGTERM, etc. -- signal numbers + + *** IMPORTANT NOTICES *** + A signal handler function is called with two arguments: + the first is the signal number, the second is the interrupted stack frame. + + According to http://java.sun.com/products/jdk/faq/faq-sun-packages.html + 'writing java programs that rely on sun.* is risky: they are not portable, and are not supported.' + + However, in Jython, like Python, we let you decide what makes + sense for your application. If sun.misc.Signal is not available, + an ImportError is raised. +""" + + +try: + import sun.misc.Signal +except ImportError: + raise ImportError("signal module requires sun.misc.Signal, which is not available on this platform") + +import java.util.concurrent +import os +import sun.misc.SignalHandler +import sys +import threading +import time +from java.lang import IllegalArgumentException + +debug = 0 + +def _init_signals(): + # install signals by checking for standard names + # using IllegalArgumentException to diagnose + + possible_signals = """ + SIGABRT + SIGALRM + SIGBUS + SIGCHLD + SIGCONT + SIGFPE + SIGHUP + SIGILL + SIGINFO + SIGINT + SIGIOT + SIGKILL + SIGPIPE + SIGPOLL + SIGPROF + SIGQUIT + SIGSEGV + SIGSTOP + SIGSYS + SIGTERM + SIGTRAP + SIGTSTP + SIGTTIN + SIGTTOU + SIGURG + SIGUSR1 + SIGUSR2 + SIGVTALRM + SIGWINCH + SIGXCPU + SIGXFSZ + """.split() + + _module = __import__(__name__) + signals = {} + signals_by_name = {} + for signal_name in possible_signals: + try: + java_signal = sun.misc.Signal(signal_name[3:]) + except IllegalArgumentException: + continue + + signal_number = java_signal.getNumber() + signals[signal_number] = java_signal + signals_by_name[signal_name] = java_signal + setattr(_module, signal_name, signal_number) # install as a module constant + return signals + +_signals = _init_signals() +NSIG = max(_signals.iterkeys()) + 1 +SIG_DFL = sun.misc.SignalHandler.SIG_DFL # default system handler +SIG_IGN = sun.misc.SignalHandler.SIG_IGN # handler to ignore a signal + +class JythonSignalHandler(sun.misc.SignalHandler): + def __init__(self, action): + self.action = action + + def handle(self, signal): + # passing a frame here probably don't make sense in a threaded system, + # but perhaps revisit + self.action(signal.getNumber(), None) + +def signal(sig, action): + """ + signal(sig, action) -> action + + Set the action for the given signal. The action can be SIG_DFL, + SIG_IGN, or a callable Python object. The previous action is + returned. See getsignal() for possible return values. + + *** IMPORTANT NOTICE *** + A signal handler function is called with two arguments: + the first is the signal number, the second is the interrupted stack frame. + """ + # maybe keep a weak ref map of handlers we have returned? + + try: + signal = _signals[sig] + except KeyError: + raise ValueError("signal number out of range") + + if callable(action): + prev = sun.misc.Signal.handle(signal, JythonSignalHandler(action)) + elif action in (SIG_IGN, SIG_DFL) or isinstance(action, sun.misc.SignalHandler): + prev = sun.misc.Signal.handle(signal, action) + else: + raise TypeError("signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object") + + if isinstance(prev, JythonSignalHandler): + return prev.action + else: + return prev + + +# dangerous! don't use! +def getsignal(sig): + """getsignal(sig) -> action + + Return the current action for the given signal. The return value can be: + SIG_IGN -- if the signal is being ignored + SIG_DFL -- if the default action for the signal is in effect + None -- if an unknown handler is in effect + anything else -- the callable Python object used as a handler + + Note for Jython: this function is NOT threadsafe. The underlying + Java support only enables getting the current signal handler by + setting a new one. So this is completely prone to race conditions. + """ + try: + signal = _signals[sig] + except KeyError: + raise ValueError("signal number out of range") + current = sun.misc.Signal.handle(signal, SIG_DFL) + sun.misc.Signal.handle(signal, current) # and reinstall + + if isinstance(current, JythonSignalHandler): + return current.action + else: + return current + +def default_int_handler(sig, frame): + """ + default_int_handler(...) + + The default handler for SIGINT installed by Python. + It raises KeyboardInterrupt. + """ + raise KeyboardInterrupt + +def pause(): + raise NotImplementedError + +_alarm_timer_holder = java.util.concurrent.atomic.AtomicReference() + +def _alarm_handler(sig, frame): + print "Alarm clock" + os._exit(0) + +# install a default alarm handler, the one we get by default doesn't +# work terribly well since it throws a bus error (at least on OS X)! +try: + SIGALRM + signal(SIGALRM, _alarm_handler) +except NameError: + pass + +class _Alarm(object): + def __init__(self, interval, task): + self.interval = interval + self.task = task + self.scheduled = None + self.timer = threading.Timer(self.interval, self.task) + + def start(self): + self.timer.start() + self.scheduled = time.time() + self.interval + + def cancel(self): + self.timer.cancel() + now = time.time() + if self.scheduled and self.scheduled > now: + return self.scheduled - now + else: + return 0 + +def alarm(time): + try: + SIGALRM + except NameError: + raise NotImplementedError("alarm not implemented on this platform") + + def raise_alarm(): + sun.misc.Signal.raise(_signals[SIGALRM]) + + if time > 0: + new_alarm_timer = _Alarm(time, raise_alarm) + else: + new_alarm_timer = None + old_alarm_timer = _alarm_timer_holder.getAndSet(new_alarm_timer) + if old_alarm_timer: + scheduled = int(old_alarm_timer.cancel()) + else: + scheduled = 0 + + if new_alarm_timer: + new_alarm_timer.start() + return scheduled Modified: trunk/jython/Lib/test/regrtest.py =================================================================== --- trunk/jython/Lib/test/regrtest.py 2008-12-29 05:45:42 UTC (rev 5804) +++ trunk/jython/Lib/test/regrtest.py 2008-12-29 06:59:00 UTC (rev 5805) @@ -1430,7 +1430,6 @@ test_resource test_rgbimg test_scriptpackages - test_signal test_socket_ssl test_socketserver test_sqlite Added: trunk/jython/Lib/test/test_signal.py =================================================================== --- trunk/jython/Lib/test/test_signal.py (rev 0) +++ trunk/jython/Lib/test/test_signal.py 2008-12-29 06:59:00 UTC (rev 5805) @@ -0,0 +1,403 @@ +# based on test_signal.py from +# http://svn.python.org/projects/python/trunk/Lib/test/test_signal.py@62194 +# due to the fact that this version is modular enough to readily run +# on Jython. +# +# most tests are disabled due to lack of 2.6 support in our signal +# module (WakeupSignalTests, SiginterruptTest, ItimerTest) and no +# os.pipe/os.fork (InterProcessSignalTests). It would seem possible to +# remedy the latter by just using subprocess. + +from __future__ import with_statement +import unittest +from test import test_support +from contextlib import closing, nested +import gc +import pickle +import select +import signal +import subprocess +import traceback +import sys, os, time, errno + +if sys.platform[:3] in ('win', 'os2') or sys.platform == 'riscos': + raise test_support.TestSkipped("Can't test signal on %s" % \ + sys.platform) + + +class HandlerBCalled(Exception): + pass + + +def exit_subprocess(): + """Use os._exit(0) to exit the current subprocess. + + Otherwise, the test catches the SystemExit and continues executing + in parallel with the original test, so you wind up with an + exponential number of tests running concurrently. + """ + os._exit(0) + + +def ignoring_eintr(__func, *args, **kwargs): + try: + return __func(*args, **kwargs) + except EnvironmentError, e: + if e.errno != errno.EINTR: + raise + return None + + +class InterProcessSignalTests(unittest.TestCase): + MAX_DURATION = 20 # Entire test should last at most 20 sec. + + def setUp(self): + self.using_gc = gc.isenabled() + #gc.disable() + + def tearDown(self): + if self.using_gc: + gc.enable() + + def format_frame(self, frame, limit=None): + return ''.join(traceback.format_stack(frame, limit=limit)) + + def handlerA(self, signum, frame): + self.a_called = True + if test_support.verbose: + print "handlerA invoked from signal %s at:\n%s" % ( + signum, self.format_frame(frame, limit=1)) + + def handlerB(self, signum, frame): + self.b_called = True + if test_support.verbose: + print "handlerB invoked from signal %s at:\n%s" % ( + signum, self.format_frame(frame, limit=1)) + raise HandlerBCalled(signum, self.format_frame(frame)) + + def wait(self, child): + """Wait for child to finish, ignoring EINTR.""" + while True: + try: + child.wait() + return + except OSError, e: + if e.errno != errno.EINTR: + raise + + def run_test(self): + # Install handlers. This function runs in a sub-process, so we + # don't worry about re-setting the default handlers. + signal.signal(signal.SIGHUP, self.handlerA) + signal.signal(signal.SIGUSR1, self.handlerB) + signal.signal(signal.SIGUSR2, signal.SIG_IGN) + signal.signal(signal.SIGALRM, signal.default_int_handler) + + # Variables the signals will modify: + self.a_called = False + self.b_called = False + + # Let the sub-processes know who to send signals to. + pid = os.getpid() + if test_support.verbose: + print "test runner's pid is", pid + + child = ignoring_eintr(subprocess.Popen, ['kill', '-HUP', str(pid)]) + if child: + self.wait(child) + if not self.a_called: + time.sleep(1) # Give the signal time to be delivered. + self.assertTrue(self.a_called) + self.assertFalse(self.b_called) + self.a_called = False + + # Make sure the signal isn't delivered while the previous + # Popen object is being destroyed, because __del__ swallows + # exceptions. + del child + try: + child = subprocess.Popen(['kill', '-USR1', str(pid)]) + # This wait should be interrupted by the signal's exception. + self.wait(child) + time.sleep(1) # Give the signal time to be delivered. + self.fail('HandlerBCalled exception not thrown') + except HandlerBCalled: + self.assertTrue(self.b_called) + self.assertFalse(self.a_called) + if test_support.verbose: + print "HandlerBCalled exception caught" + + child = ignoring_eintr(subprocess.Popen, ['kill', '-USR2', str(pid)]) + if child: + self.wait(child) # Nothing should happen. + + try: + signal.alarm(1) + # The race condition in pause doesn't matter in this case, + # since alarm is going to raise a KeyboardException, which + # will skip the call. + signal.pause() + # But if another signal arrives before the alarm, pause + # may return early. + time.sleep(1) + except KeyboardInterrupt: + if test_support.verbose: + print "KeyboardInterrupt (the alarm() went off)" + except: + self.fail("Some other exception woke us from pause: %s" % + traceback.format_exc()) + else: + self.fail("pause returned of its own accord, and the signal" + " didn't arrive after another second.") + + def test_main(self): + # This function spawns a child process to insulate the main + # test-running process from all the signals. It then + # communicates with that child process over a pipe and + # re-raises information about any exceptions the child + # throws. The real work happens in self.run_test(). + os_done_r, os_done_w = os.pipe() + with nested(closing(os.fdopen(os_done_r)), + closing(os.fdopen(os_done_w, 'w'))) as (done_r, done_w): + child = os.fork() + if child == 0: + # In the child process; run the test and report results + # through the pipe. + try: + done_r.close() + # Have to close done_w again here because + # exit_subprocess() will skip the enclosing with block. + with closing(done_w): + try: + self.run_test() + except: + pickle.dump(traceback.format_exc(), done_w) + else: + pickle.dump(None, done_w) + except: + print 'Uh oh, raised from pickle.' + traceback.print_exc() + finally: + exit_subprocess() + + done_w.close() + # Block for up to MAX_DURATION seconds for the test to finish. + r, w, x = select.select([done_r], [], [], self.MAX_DURATION) + if done_r in r: + tb = pickle.load(done_r) + if tb: + self.fail(tb) + else: + os.kill(child, signal.SIGKILL) + self.fail('Test deadlocked after %d seconds.' % + self.MAX_DURATION) + + +class BasicSignalTests(unittest.TestCase): + def trivial_signal_handler(self, *args): + pass + + def test_out_of_range_signal_number_raises_error(self): + self.assertRaises(ValueError, signal.getsignal, 4242) + + self.assertRaises(ValueError, signal.signal, 4242, + self.trivial_signal_handler) + + def test_setting_signal_handler_to_none_raises_error(self): + self.assertRaises(TypeError, signal.signal, + signal.SIGUSR1, None) + + def test_getsignal(self): + hup = signal.signal(signal.SIGHUP, self.trivial_signal_handler) + self.assertEquals(signal.getsignal(signal.SIGHUP), + self.trivial_signal_handler) + signal.signal(signal.SIGHUP, hup) + self.assertEquals(signal.getsignal(signal.SIGHUP), hup) + + +class WakeupSignalTests(unittest.TestCase): + TIMEOUT_FULL = 10 + TIMEOUT_HALF = 5 + + def test_wakeup_fd_early(self): + import select + + signal.alarm(1) + before_time = time.time() + # We attempt to get a signal during the sleep, + # before select is called + time.sleep(self.TIMEOUT_FULL) + mid_time = time.time() + self.assert_(mid_time - before_time < self.TIMEOUT_HALF) + select.select([self.read], [], [], self.TIMEOUT_FULL) + after_time = time.time() + self.assert_(after_time - mid_time < self.TIMEOUT_HALF) + + def test_wakeup_fd_during(self): + import select + + signal.alarm(1) + before_time = time.time() + # We attempt to get a signal during the select call + self.assertRaises(select.error, select.select, + [self.read], [], [], self.TIMEOUT_FULL) + after_time = time.time() + self.assert_(after_time - before_time < self.TIMEOUT_HALF) + + def setUp(self): + import fcntl + + self.alrm = signal.signal(signal.SIGALRM, lambda x,y:None) + self.read, self.write = os.pipe() + flags = fcntl.fcntl(self.write, fcntl.F_GETFL, 0) + flags = flags | os.O_NONBLOCK + fcntl.fcntl(self.write, fcntl.F_SETFL, flags) + self.old_wakeup = signal.set_wakeup_fd(self.write) + + def tearDown(self): + signal.set_wakeup_fd(self.old_wakeup) + os.close(self.read) + os.close(self.write) + signal.signal(signal.SIGALRM, self.alrm) + +class SiginterruptTest(unittest.TestCase): + signum = signal.SIGUSR1 + def readpipe_interrupted(self, cb): + r, w = os.pipe() + ppid = os.getpid() + pid = os.fork() + + oldhandler = signal.signal(self.signum, lambda x,y: None) + cb() + if pid==0: + # child code: sleep, kill, sleep. and then exit, + # which closes the pipe from which the parent process reads + try: + time.sleep(0.2) + os.kill(ppid, self.signum) + time.sleep(0.2) + finally: + exit_subprocess() + + try: + os.close(w) + + try: + d=os.read(r, 1) + return False + except OSError, err: + if err.errno != errno.EINTR: + raise + return True + finally: + signal.signal(self.signum, oldhandler) + os.waitpid(pid, 0) + + def test_without_siginterrupt(self): + i=self.readpipe_interrupted(lambda: None) + self.assertEquals(i, True) + + def test_siginterrupt_on(self): + i=self.readpipe_interrupted(lambda: signal.siginterrupt(self.signum, 1)) + self.assertEquals(i, True) + + def test_siginterrupt_off(self): + i=self.readpipe_interrupted(lambda: signal.siginterrupt(self.signum, 0)) + self.assertEquals(i, False) + +class ItimerTest(unittest.TestCase): + def setUp(self): + self.hndl_called = False + self.hndl_count = 0 + self.itimer = None + self.old_alarm = signal.signal(signal.SIGALRM, self.sig_alrm) + + def tearDown(self): + signal.signal(signal.SIGALRM, self.old_alarm) + if self.itimer is not None: # test_itimer_exc doesn't change this attr + # just ensure that itimer is stopped + signal.setitimer(self.itimer, 0) + + def sig_alrm(self, *args): + self.hndl_called = True + if test_support.verbose: + print("SIGALRM handler invoked", args) + + def sig_vtalrm(self, *args): + self.hndl_called = True + + if self.hndl_count > 3: + # it shouldn't be here, because it should have been disabled. + raise signal.ItimerError("setitimer didn't disable ITIMER_VIRTUAL " + "timer.") + elif self.hndl_count == 3: + # disable ITIMER_VIRTUAL, this function shouldn't be called anymore + signal.setitimer(signal.ITIMER_VIRTUAL, 0) + if test_support.verbose: + print("last SIGVTALRM handler call") + + self.hndl_count += 1 + + if test_support.verbose: + print("SIGVTALRM handler invoked", args) + + def sig_prof(self, *args): + self.hndl_called = True + signal.setitimer(signal.ITIMER_PROF, 0) + + if test_support.verbose: + print("SIGPROF handler invoked", args) + + def test_itimer_exc(self): + # XXX I'm assuming -1 is an invalid itimer, but maybe some platform + # defines it ? + self.assertRaises(signal.ItimerError, signal.setitimer, -1, 0) + # Negative times are treated as zero on some platforms. + if 0: + self.assertRaises(signal.ItimerError, + signal.setitimer, signal.ITIMER_REAL, -1) + + def test_itimer_real(self): + self.itimer = signal.ITIMER_REAL + signal.setitimer(self.itimer, 1.0) + if test_support.verbose: + print("\ncall pause()...") + signal.pause() + + self.assertEqual(self.hndl_called, True) + + def test_itimer_virtual(self): + self.itimer = signal.ITIMER_VIRTUAL + signal.signal(signal.SIGVTALRM, self.sig_vtalrm) + signal.setitimer(self.itimer, 0.3, 0.2) + + for i in xrange(100000000): + if signal.getitimer(self.itimer) == (0.0, 0.0): + break # sig_vtalrm handler stopped this itimer + + # virtual itimer should be (0.0, 0.0) now + self.assertEquals(signal.getitimer(self.itimer), (0.0, 0.0)) + # and the handler should have been called + self.assertEquals(self.hndl_called, True) + + def test_itimer_prof(self): + self.itimer = signal.ITIMER_PROF + signal.signal(signal.SIGPROF, self.sig_prof) + signal.setitimer(self.itimer, 0.2, 0.2) + + for i in xrange(100000000): + if signal.getitimer(self.itimer) == (0.0, 0.0): + break # sig_prof handler stopped this itimer + + # profiling itimer should be (0.0, 0.0) now + self.assertEquals(signal.getitimer(self.itimer), (0.0, 0.0)) + # and the handler should have been called + self.assertEqual(self.hndl_called, True) + +def test_main(): + test_support.run_unittest(BasicSignalTests) #, InterProcessSignalTests) + # ignore these 2.6 tests: WakeupSignalTests, SiginterruptTest, ItimerTest + + +if __name__ == "__main__": + test_main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2009-01-05 19:47:31
|
Revision: 5854 http://jython.svn.sourceforge.net/jython/?rev=5854&view=rev Author: amak Date: 2009-01-05 19:47:25 +0000 (Mon, 05 Jan 2009) Log Message: ----------- Fixed a bug where connect timeouts were not being honoured when set through socket.setdefaulttimeout() http://bugs.jython.org/issue1218 Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2009-01-05 19:06:58 UTC (rev 5853) +++ trunk/jython/Lib/socket.py 2009-01-05 19:47:25 UTC (rev 5854) @@ -632,12 +632,14 @@ class _nonblocking_api_mixin: - timeout = _defaulttimeout mode = MODE_BLOCKING reference_count = 0 close_lock = threading.Lock() def __init__(self): + self.timeout = _defaulttimeout + if self.timeout is not None: + self.mode = MODE_TIMEOUT self.pending_options = { SO_REUSEADDR: 0, } @@ -791,7 +793,7 @@ self.sock_impl.bind(bind_host, bind_port, self.pending_options[SO_REUSEADDR]) self._config() # Configure timeouts, etc, now that the socket exists self.sock_impl.connect(host, port) - except java.lang.Exception, jlx: + except java.lang.Exception, jlx: raise _map_exception(jlx) def connect(self, addr): Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2009-01-05 19:06:58 UTC (rev 5853) +++ trunk/jython/Lib/test/test_socket.py 2009-01-05 19:47:25 UTC (rev 5854) @@ -1320,6 +1320,23 @@ socket.timeout. This tries to connect to %s in the assumption that it isn't used, but if it is on your network this failure is bogus.''' % host) + def testConnectDefaultTimeout(self): + _saved_timeout = socket.getdefaulttimeout() + socket.setdefaulttimeout(0.1) + cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + host = '192.168.192.168' + try: + cli.connect((host, 5000)) + 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. This tries to connect to %s in the assumption that it isn't +used, but if it is on your network this failure is bogus.''' % host) + socket.setdefaulttimeout(_saved_timeout) + def testRecvTimeout(self): def raise_timeout(*args, **kwargs): cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <zy...@us...> - 2009-01-17 18:31:10
|
Revision: 5938 http://jython.svn.sourceforge.net/jython/?rev=5938&view=rev Author: zyasoft Date: 2009-01-17 18:31:06 +0000 (Sat, 17 Jan 2009) Log Message: ----------- Fixes #1217 where we report the underlying Java error (java.util.zip.DataFormatException) instead of the standard Python one (zlib.error). This also helps support PyAMF on Jython. Thanks Nick Joyce for the patch. Modified Paths: -------------- trunk/jython/Lib/test/test_zlib.py trunk/jython/Lib/zlib.py Modified: trunk/jython/Lib/test/test_zlib.py =================================================================== --- trunk/jython/Lib/test/test_zlib.py 2009-01-17 18:12:57 UTC (rev 5937) +++ trunk/jython/Lib/test/test_zlib.py 2009-01-17 18:31:06 UTC (rev 5938) @@ -81,6 +81,8 @@ self.assertRaises(ValueError, zlib.decompressobj().flush, 0) self.assertRaises(ValueError, zlib.decompressobj().flush, -1) + def test_decompress_badinput(self): + self.assertRaises(zlib.error, zlib.decompress, 'foo') class CompressTestCase(unittest.TestCase): Modified: trunk/jython/Lib/zlib.py =================================================================== --- trunk/jython/Lib/zlib.py 2009-01-17 18:12:57 UTC (rev 5937) +++ trunk/jython/Lib/zlib.py 2009-01-17 18:31:06 UTC (rev 5938) @@ -15,7 +15,7 @@ """ import jarray, binascii -from java.util.zip import Adler32, Deflater, Inflater +from java.util.zip import Adler32, Deflater, Inflater, DataFormatException from java.lang import Long, String from cStringIO import StringIO @@ -66,8 +66,8 @@ def decompress(string, wbits=0, bufsize=16384): inflater = Inflater(wbits < 0) inflater.setInput(string) + return _get_inflate_data(inflater) - class compressobj: # all jython uses wbits for is deciding whether to skip the header if it's negative @@ -152,22 +152,26 @@ s = StringIO() while not deflater.finished(): l = deflater.deflate(buf) + if l == 0: break s.write(String(buf, 0, 0, l)) s.seek(0) return s.read() - def _get_inflate_data(inflater, max_length=0): buf = jarray.zeros(1024, 'b') s = StringIO() total = 0 while not inflater.finished(): - if max_length: - l = inflater.inflate(buf, 0, min(1024, max_length - total)) - else: - l = inflater.inflate(buf) + try: + if max_length: + l = inflater.inflate(buf, 0, min(1024, max_length - total)) + else: + l = inflater.inflate(buf) + except DataFormatException, e: + raise error(str(e)) + if l == 0: break This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2009-01-23 23:40:54
|
Revision: 5965 http://jython.svn.sourceforge.net/jython/?rev=5965&view=rev Author: pjenvey Date: 2009-01-23 23:40:46 +0000 (Fri, 23 Jan 2009) Log Message: ----------- more java.lang.Strings to regular str instead of unicode Modified Paths: -------------- trunk/jython/Lib/os.py trunk/jython/Lib/platform.py Modified: trunk/jython/Lib/os.py =================================================================== --- trunk/jython/Lib/os.py 2009-01-23 15:30:09 UTC (rev 5964) +++ trunk/jython/Lib/os.py 2009-01-23 23:40:46 UTC (rev 5965) @@ -83,9 +83,9 @@ """ os_name = sys.registry.getProperty('python.os') if os_name: - return str(os_name) + return asPyString(os_name) - os_name = str(java.lang.System.getProperty('os.name')) + os_name = asPyString(java.lang.System.getProperty('os.name')) os_type = None for type, (patterns, shell_commands) in _os_map.iteritems(): for pattern in patterns: Modified: trunk/jython/Lib/platform.py =================================================================== --- trunk/jython/Lib/platform.py 2009-01-23 15:30:09 UTC (rev 5964) +++ trunk/jython/Lib/platform.py 2009-01-23 23:40:46 UTC (rev 5965) @@ -624,8 +624,9 @@ def _java_getprop(name,default): from java.lang import System + from org.python.core.Py import newString try: - return System.getProperty(name) + return newString(System.getProperty(name)) except: return default This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2009-01-28 16:06:23
|
Revision: 5992 http://jython.svn.sourceforge.net/jython/?rev=5992&view=rev Author: amak Date: 2009-01-28 16:05:59 +0000 (Wed, 28 Jan 2009) Log Message: ----------- Fix and unit test for bug 1244. Problem letting system choose the port for binding UDP socket http://bugs.jython.org/issue1244 Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2009-01-27 05:06:54 UTC (rev 5991) +++ trunk/jython/Lib/socket.py 2009-01-28 16:05:59 UTC (rev 5992) @@ -384,7 +384,7 @@ def __init__(self, port=None, address=None, reuse_addr=0): self.jchannel = java.nio.channels.DatagramChannel.open() self.jsocket = self.jchannel.socket() - if port: + if port is not None: if address is not None: local_address = java.net.InetSocketAddress(address, port) else: Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2009-01-27 05:06:54 UTC (rev 5991) +++ trunk/jython/Lib/test/test_socket.py 2009-01-28 16:05:59 UTC (rev 5992) @@ -813,7 +813,22 @@ def _testDup(self): self.serv_conn.send(MSG) self.serv_conn.send('and ' + MSG) + +class UDPBindTest(unittest.TestCase): + + HOST = HOST + PORT = PORT + def setUp(self): + self.sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) + + def testBindEphemeral(self): + self.sock.bind( (self.HOST, 0) ) # let system choose a free port + self.failUnless(self.sock.getsockname()[1] != 0, "Binding to port zero should have allocated an ephemeral port number") + + def tearDown(self): + self.sock.close() + class BasicUDPTest(ThreadedUDPSocketTest): def __init__(self, methodName='runTest'): @@ -1609,6 +1624,7 @@ TestInvalidUsage, TestTCPAddressParameters, TestUDPAddressParameters, + UDPBindTest, BasicUDPTest, UDPTimeoutTest, NonBlockingTCPTests, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2009-01-29 17:59:13
|
Revision: 6001 http://jython.svn.sourceforge.net/jython/?rev=6001&view=rev Author: amak Date: 2009-01-29 17:59:04 +0000 (Thu, 29 Jan 2009) Log Message: ----------- Re-arranging the socket shutdown methods. TCP client sockets can shutdown their input streams, but this is not appropriate for either TCP server sockets or UDP sockets, which don't have input and output streams. For these latter two types, the shutdown method should have the same effect as the close method, and thus the shutdown method is a no-op for these types. I have documented this difference between cpython and jython on the wiki. This should finally resolve bug 1121: listening socket shutdown expects the wrong kind of socket http://bugs.jython.org/issue1121 Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2009-01-29 17:41:00 UTC (rev 6000) +++ trunk/jython/Lib/socket.py 2009-01-29 17:59:04 UTC (rev 6001) @@ -248,22 +248,6 @@ def close(self): self.jsocket.close() - def shutdownInput(self): - try: - self.jsocket.shutdownInput() - except AttributeError, ax: - pass # Fail silently server sockets - except java.lang.Exception, jlx: - raise _map_exception(jlx) - - def shutdownOutput(self): - try: - self.jsocket.shutdownOutput() - except AttributeError, ax: - pass # Fail silently server sockets - except java.lang.Exception, jlx: - raise _map_exception(jlx) - def getchannel(self): return self.jchannel @@ -340,6 +324,12 @@ else: return self._do_write_nio(buf) + def shutdown(self, how): + if how in (SHUT_RD, SHUT_RDWR): + self.jsocket.shutdownInput() + if how in (SHUT_WR, SHUT_RDWR): + self.jsocket.shutdownOutput() + class _server_socket_impl(_nio_impl): options = { @@ -371,6 +361,13 @@ new_cli_sock = self.jsocket.accept() return _client_socket_impl(new_cli_sock) + def shutdown(self, how): + # This is no-op on java, for server sockets. + # What the user wants to achieve is achieved by calling close() on + # java/jython. But we can't call that here because that would then + # later cause the user explicit close() call to fail + pass + class _datagram_socket_impl(_nio_impl): options = { @@ -406,6 +403,13 @@ """ self.jchannel.disconnect() + def shutdown(self, how): + # This is no-op on java, for datagram sockets. + # What the user wants to achieve is achieved by calling close() on + # java/jython. But we can't call that here because that would then + # later cause the user explicit close() call to fail + pass + def _do_send_net(self, byte_array, socket_address, flags): # Need two separate implementations because the java.nio APIs do not support timeouts num_bytes = len(byte_array) @@ -689,6 +693,22 @@ except java.lang.Exception, jlx: raise _map_exception(jlx) + def shutdown(self, how): + assert how in (SHUT_RD, SHUT_WR, SHUT_RDWR) + if not self.sock_impl: + raise error(errno.ENOTCONN, "Transport endpoint is not connected") + try: + self.sock_impl.shutdown(how) + except java.lang.Exception, jlx: + raise _map_exception(jlx) + + def close(self): + try: + if self.sock_impl: + self.sock_impl.close() + except java.lang.Exception, jlx: + raise _map_exception(jlx) + def _config(self): assert self.mode in _permitted_modes if self.sock_impl: @@ -878,15 +898,6 @@ except java.lang.Exception, jlx: raise _map_exception(jlx) - def shutdown(self, how): - if not self.sock_impl: - raise error(errno.ENOTCONN, "Transport endpoint is not connected") - assert how in (SHUT_RD, SHUT_WR, SHUT_RDWR) - if how in (SHUT_RD, SHUT_RDWR): - self.sock_impl.shutdownInput() - if how in (SHUT_WR, SHUT_RDWR): - self.sock_impl.shutdownOutput() - def close(self): try: if self.istream: @@ -1015,13 +1026,6 @@ def __del__(self): self.close() - def close(self): - try: - if self.sock_impl: - self.sock_impl.close() - except java.lang.Exception, jlx: - raise _map_exception(jlx) - _socketmethods = ( 'bind', 'connect', 'connect_ex', 'fileno', 'listen', 'getpeername', 'getsockname', 'getsockopt', 'setsockopt', Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2009-01-29 17:41:00 UTC (rev 6000) +++ trunk/jython/Lib/test/test_socket.py 2009-01-29 17:59:04 UTC (rev 6001) @@ -822,10 +822,20 @@ def setUp(self): self.sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) + def testBindSpecific(self): + self.sock.bind( (self.HOST, self.PORT) ) # Use a specific port + actual_port = self.sock.getsockname()[1] + self.failUnless(actual_port == self.PORT, + "Binding to specific port number should have returned same number: %d != %d" % (actual_port, self.PORT)) + def testBindEphemeral(self): self.sock.bind( (self.HOST, 0) ) # let system choose a free port self.failUnless(self.sock.getsockname()[1] != 0, "Binding to port zero should have allocated an ephemeral port number") + def testShutdown(self): + self.sock.bind( (self.HOST, self.PORT) ) + self.sock.shutdown(socket.SHUT_RDWR) + def tearDown(self): self.sock.close() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2009-04-03 06:06:53
|
Revision: 6154 http://jython.svn.sourceforge.net/jython/?rev=6154&view=rev Author: pjenvey Date: 2009-04-03 06:06:39 +0000 (Fri, 03 Apr 2009) Log Message: ----------- o rewrite popen2/os.{popen,system} to use subprocess. fixes popen2 deadlocking o bump test_communicate_pipe_buf to a larger size as per #1124's test o deprecate javashell which is no longer used thanks Pekka Klarck fixes #1124 Modified Paths: -------------- trunk/jython/Lib/javashell.py trunk/jython/Lib/os.py trunk/jython/Lib/popen2.py trunk/jython/Lib/test/test_subprocess.py Modified: trunk/jython/Lib/javashell.py =================================================================== --- trunk/jython/Lib/javashell.py 2009-04-03 06:02:36 UTC (rev 6153) +++ trunk/jython/Lib/javashell.py 2009-04-03 06:06:39 UTC (rev 6154) @@ -20,8 +20,11 @@ import subprocess import sys import types +import warnings +warnings.warn('The javashell module is deprecated. Use the subprocess module.', + DeprecationWarning, 2) -__all__ = [ "shellexecute", "environ", "putenv", "getenv" ] +__all__ = ["shellexecute"] def __warn( *args ): print " ".join( [str( arg ) for arg in args ]) Modified: trunk/jython/Lib/os.py =================================================================== --- trunk/jython/Lib/os.py 2009-04-03 06:02:36 UTC (rev 6153) +++ trunk/jython/Lib/os.py 2009-04-03 06:06:39 UTC (rev 6154) @@ -727,27 +727,28 @@ except: raise OSError(errno.EBADF, strerror(errno.EBADF)) -# Provide lazy popen*, and system objects -# Do these lazily, as most jython programs don't need them, -# and they are very expensive to initialize - -def system( *args, **kwargs ): +def system(command): """system(command) -> exit_status Execute the command (a string) in a subshell. """ - # allow lazy import of popen2 and javashell - import popen2 - return popen2.system( *args, **kwargs ) + import subprocess + return subprocess.call(command, shell=True) -def popen( *args, **kwargs ): +def popen(command, mode='r', bufsize=-1): """popen(command [, mode='r' [, bufsize]]) -> pipe Open a pipe to/from a command returning a file object. """ - # allow lazy import of popen2 and javashell - import popen2 - return popen2.popen( *args, **kwargs ) + import subprocess + if mode == 'r': + return subprocess.Popen(command, bufsize=bufsize, shell=True, + stdout=subprocess.PIPE).stdout + elif mode == 'w': + return subprocess.Popen(command, bufsize=bufsize, shell=True, + stdin=subprocess.PIPE).stdin + else: + raise OSError(errno.EINVAL, strerror(errno.EINVAL)) # os module versions of the popen# methods have different return value # order than popen2 functions Modified: trunk/jython/Lib/popen2.py =================================================================== --- trunk/jython/Lib/popen2.py 2009-04-03 06:02:36 UTC (rev 6153) +++ trunk/jython/Lib/popen2.py 2009-04-03 06:06:39 UTC (rev 6154) @@ -7,27 +7,15 @@ """ import os +import subprocess import sys __all__ = ["popen2", "popen3", "popen4"] -try: - MAXFD = os.sysconf('SC_OPEN_MAX') -except (AttributeError, ValueError): - MAXFD = 256 +MAXFD = subprocess.MAXFD +_active = subprocess._active +_cleanup = subprocess._cleanup -_active = [] - -def _cleanup(): - for inst in _active[:]: - if inst.poll(_deadstate=sys.maxint) >= 0: - try: - _active.remove(inst) - except ValueError: - # This can happen if two threads create a new Popen instance. - # It's harmless that it was already removed, so ignore. - pass - class Popen3: """Class representing a child process. Normally instances are created by the factory functions popen2() and popen3().""" @@ -44,73 +32,36 @@ process. The default is false. If the 'bufsize' parameter is specified, it specifies the size of the I/O buffers to/from the child process.""" - _cleanup() + stderr = subprocess.PIPE if capturestderr else None + PIPE = subprocess.PIPE + self._popen = subprocess.Popen(cmd, bufsize=bufsize, shell=True, + stdin=PIPE, stdout=PIPE, stderr=stderr) + self._setup(cmd) + + def _setup(self, cmd): + """Setup the Popen attributes.""" self.cmd = cmd - p2cread, p2cwrite = os.pipe() - c2pread, c2pwrite = os.pipe() - if capturestderr: - errout, errin = os.pipe() - self.pid = os.fork() - if self.pid == 0: - # Child - os.dup2(p2cread, 0) - os.dup2(c2pwrite, 1) - if capturestderr: - os.dup2(errin, 2) - self._run_child(cmd) - os.close(p2cread) - self.tochild = os.fdopen(p2cwrite, 'w', bufsize) - os.close(c2pwrite) - self.fromchild = os.fdopen(c2pread, 'r', bufsize) - if capturestderr: - os.close(errin) - self.childerr = os.fdopen(errout, 'r', bufsize) - else: - self.childerr = None + self.pid = self._popen.pid + self.tochild = self._popen.stdin + self.fromchild = self._popen.stdout + self.childerr = self._popen.stderr def __del__(self): - # In case the child hasn't been waited on, check if it's done. - self.poll(_deadstate=sys.maxint) - if self.sts < 0: - if _active is not None: - # Child is still running, keep us alive until we can wait on it. - _active.append(self) + self._popen.__del__() - def _run_child(self, cmd): - if isinstance(cmd, basestring): - cmd = ['/bin/sh', '-c', cmd] - for i in xrange(3, MAXFD): - try: - os.close(i) - except OSError: - pass - try: - os.execvp(cmd[0], cmd) - finally: - os._exit(1) - def poll(self, _deadstate=None): """Return the exit status of the child process if it has finished, or -1 if it hasn't finished yet.""" if self.sts < 0: - try: - pid, sts = os.waitpid(self.pid, os.WNOHANG) - # pid will be 0 if self.pid hasn't terminated - if pid == self.pid: - self.sts = sts - except os.error: - if _deadstate is not None: - self.sts = _deadstate + result = self._popen.poll(_deadstate) + if result is not None: + self.sts = result return self.sts def wait(self): """Wait for and return the exit status of the child process.""" if self.sts < 0: - pid, sts = os.waitpid(self.pid, 0) - # This used to be a test, but it is believed to be - # always true, so I changed it to an assertion - mvl - assert pid == self.pid - self.sts = sts + self.sts = self._popen.wait() return self.sts @@ -118,21 +69,11 @@ childerr = None def __init__(self, cmd, bufsize=-1): - _cleanup() - self.cmd = cmd - p2cread, p2cwrite = os.pipe() - c2pread, c2pwrite = os.pipe() - self.pid = os.fork() - if self.pid == 0: - # Child - os.dup2(p2cread, 0) - os.dup2(c2pwrite, 1) - os.dup2(c2pwrite, 2) - self._run_child(cmd) - os.close(p2cread) - self.tochild = os.fdopen(p2cwrite, 'w', bufsize) - os.close(c2pwrite) - self.fromchild = os.fdopen(c2pread, 'r', bufsize) + PIPE = subprocess.PIPE + self._popen = subprocess.Popen(cmd, bufsize=bufsize, shell=True, + stdin=PIPE, stdout=PIPE, + stderr=subprocess.STDOUT) + self._setup(cmd) if sys.platform[:3] == "win" or sys.platform == "os2emx": @@ -207,7 +148,7 @@ assert not _active, "Active pipes when test starts " + repr([c.cmd for c in _active]) cmd = "cat" teststr = "ab cd\n" - if os.name == "nt": + if os.name in ("nt", "java"): cmd = "more" # "more" doesn't act the same way across Windows flavors, # sometimes adding an extra newline at the start or the Modified: trunk/jython/Lib/test/test_subprocess.py =================================================================== --- trunk/jython/Lib/test/test_subprocess.py 2009-04-03 06:02:36 UTC (rev 6153) +++ trunk/jython/Lib/test/test_subprocess.py 2009-04-03 06:06:39 UTC (rev 6154) @@ -323,8 +323,10 @@ # communicate() with writes larger than pipe_buf # This test will probably deadlock rather than fail, if # communicate() does not work properly. - if mswindows or jython: + if mswindows: pipe_buf = 512 + elif jython: + pipe_buf = 16384 else: x, y = os.pipe() pipe_buf = os.fpathconf(x, "PC_PIPE_BUF") This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2009-04-04 15:15:23
|
Revision: 6159 http://jython.svn.sourceforge.net/jython/?rev=6159&view=rev Author: amak Date: 2009-04-04 15:15:16 +0000 (Sat, 04 Apr 2009) Log Message: ----------- Re-arranging the way that options are handled: some options are at a level different to SOL_SOCKET, namely TCP_NODELAY, which is at level IPPROTO_TCP, which is now supported. Fixes 1191: socket.IPPROTO_TCP=6 missing constant for socket module http://bugs.jython.org/issue1191 Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2009-04-04 04:11:53 UTC (rev 6158) +++ trunk/jython/Lib/socket.py 2009-04-04 15:15:16 UTC (rev 6159) @@ -159,6 +159,8 @@ SOCK_SEQPACKET = 5 # not supported SOL_SOCKET = 0xFFFF +IPPROTO_TCP = 6 +IPPROTO_UDP = 17 SO_BROADCAST = 1 SO_KEEPALIVE = 2 @@ -195,7 +197,7 @@ 'SOCK_RAW', 'SOCK_RDM', 'SOCK_SEQPACKET', 'SOCK_STREAM', 'SOL_SOCKET', 'SO_BROADCAST', 'SO_ERROR', 'SO_KEEPALIVE', 'SO_LINGER', 'SO_OOBINLINE', 'SO_RCVBUF', 'SO_REUSEADDR', 'SO_SNDBUF', 'SO_TIMEOUT', 'TCP_NODELAY', - 'INADDR_ANY', 'INADDR_BROADCAST', + 'INADDR_ANY', 'INADDR_BROADCAST', 'IPPROTO_TCP', 'IPPROTO_UDP', 'SocketType', 'error', 'herror', 'gaierror', 'timeout', 'getfqdn', 'gethostbyaddr', 'gethostbyname', 'gethostname', 'socket', 'getaddrinfo', 'getdefaulttimeout', 'setdefaulttimeout', @@ -222,9 +224,9 @@ self._timeout_millis = int(timeout*1000) self.jsocket.setSoTimeout(self._timeout_millis) - def getsockopt(self, option): - if self.options.has_key(option): - result = getattr(self.jsocket, "get%s" % self.options[option])() + def getsockopt(self, level, option): + if self.options.has_key( (level, option) ): + result = getattr(self.jsocket, "get%s" % self.options[ (level, option) ])() if option == SO_LINGER: if result == -1: enabled, linger_time = 0, 0 @@ -233,17 +235,17 @@ return struct.pack('ii', enabled, linger_time) return result else: - raise error(errno.ENOPROTOOPT, "Option not supported on socket(%s): %d" % (str(self.jsocket), option)) + raise error(errno.ENOPROTOOPT, "Level %d option not supported on socket(%s): %d" % (level, str(self.jsocket), option)) - def setsockopt(self, option, value): - if self.options.has_key(option): + def setsockopt(self, level, option, value): + if self.options.has_key( (level, option) ): if option == SO_LINGER: values = struct.unpack('ii', value) self.jsocket.setSoLinger(*values) else: - getattr(self.jsocket, "set%s" % self.options[option])(value) + getattr(self.jsocket, "set%s" % self.options[ (level, option) ])(value) else: - raise error(errno.ENOPROTOOPT, "Option not supported on socket(%s): %d" % (str(self.jsocket), option)) + raise error(errno.ENOPROTOOPT, "Level %d option not supported on socket(%s): %d" % (level, str(self.jsocket), option)) def close(self): self.jsocket.close() @@ -256,15 +258,15 @@ class _client_socket_impl(_nio_impl): - options = { - SO_KEEPALIVE: 'KeepAlive', - SO_LINGER: 'SoLinger', - SO_OOBINLINE: 'OOBInline', - SO_RCVBUF: 'ReceiveBufferSize', - SO_REUSEADDR: 'ReuseAddress', - SO_SNDBUF: 'SendBufferSize', - SO_TIMEOUT: 'SoTimeout', - TCP_NODELAY: 'TcpNoDelay', + options = { + (SOL_SOCKET, SO_KEEPALIVE): 'KeepAlive', + (SOL_SOCKET, SO_LINGER): 'SoLinger', + (SOL_SOCKET, SO_OOBINLINE): 'OOBInline', + (SOL_SOCKET, SO_RCVBUF): 'ReceiveBufferSize', + (SOL_SOCKET, SO_REUSEADDR): 'ReuseAddress', + (SOL_SOCKET, SO_SNDBUF): 'SendBufferSize', + (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout', + (IPPROTO_TCP, TCP_NODELAY): 'TcpNoDelay', } def __init__(self, socket=None): @@ -332,10 +334,10 @@ class _server_socket_impl(_nio_impl): - options = { - SO_RCVBUF: 'ReceiveBufferSize', - SO_REUSEADDR: 'ReuseAddress', - SO_TIMEOUT: 'SoTimeout', + options = { + (SOL_SOCKET, SO_RCVBUF): 'ReceiveBufferSize', + (SOL_SOCKET, SO_REUSEADDR): 'ReuseAddress', + (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout', } def __init__(self, host, port, backlog, reuse_addr): @@ -370,12 +372,12 @@ class _datagram_socket_impl(_nio_impl): - options = { - SO_BROADCAST: 'Broadcast', - SO_RCVBUF: 'ReceiveBufferSize', - SO_REUSEADDR: 'ReuseAddress', - SO_SNDBUF: 'SendBufferSize', - SO_TIMEOUT: 'SoTimeout', + options = { + (SOL_SOCKET, SO_BROADCAST): 'Broadcast', + (SOL_SOCKET, SO_RCVBUF): 'ReceiveBufferSize', + (SOL_SOCKET, SO_REUSEADDR): 'ReuseAddress', + (SOL_SOCKET, SO_SNDBUF): 'SendBufferSize', + (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout', } def __init__(self, port=None, address=None, reuse_addr=0): @@ -542,13 +544,16 @@ # Same situation as above raise NotImplementedError("getprotobyname not yet supported on jython.") -def _realsocket(family = AF_INET, type = SOCK_STREAM, flags=0): - assert family == AF_INET - assert type in (SOCK_DGRAM, SOCK_STREAM) - assert flags == 0 +def _realsocket(family = AF_INET, type = SOCK_STREAM, protocol=0): + assert family == AF_INET, "Only AF_INET sockets are currently supported on jython" + assert type in (SOCK_DGRAM, SOCK_STREAM), "Only SOCK_STREAM and SOCK_DGRAM sockets are currently supported on jython" if type == SOCK_STREAM: + if protocol != 0: + assert protocol == IPPROTO_TCP, "Only IPPROTO_TCP supported on SOCK_STREAM sockets" return _tcpsocket() else: + if protocol != 0: + assert protocol == IPPROTO_UDP, "Only IPPROTO_UDP supported on SOCK_DGRAM sockets" return _udpsocket() def getaddrinfo(host, port, family=AF_INET, socktype=None, proto=0, flags=None): @@ -645,7 +650,7 @@ if self.timeout is not None: self.mode = MODE_TIMEOUT self.pending_options = { - SO_REUSEADDR: 0, + (SOL_SOCKET, SO_REUSEADDR): 0, } def gettimeout(self): @@ -674,22 +679,20 @@ return self.mode == MODE_BLOCKING def setsockopt(self, level, optname, value): - if level != SOL_SOCKET: return try: if self.sock_impl: - self.sock_impl.setsockopt(optname, value) + self.sock_impl.setsockopt(level, optname, value) else: - self.pending_options[optname] = value + self.pending_options[ (level, optname) ] = value except java.lang.Exception, jlx: raise _map_exception(jlx) def getsockopt(self, level, optname): - if level != SOL_SOCKET: return try: if self.sock_impl: - return self.sock_impl.getsockopt(optname) + return self.sock_impl.getsockopt(level, optname) else: - return self.pending_options.get(optname, None) + return self.pending_options.get( (level, optname), None) except java.lang.Exception, jlx: raise _map_exception(jlx) @@ -713,9 +716,9 @@ assert self.mode in _permitted_modes if self.sock_impl: self.sock_impl.config(self.mode, self.timeout) - for k in self.pending_options.keys(): - if k != SO_REUSEADDR: - self.sock_impl.setsockopt(k, self.pending_options[k]) + for level, optname in self.pending_options.keys(): + if optname != SO_REUSEADDR: + self.sock_impl.setsockopt(level, optname, self.pending_options[ (level, optname) ]) def getchannel(self): if not self.sock_impl: @@ -775,7 +778,7 @@ host, port = _unpack_address_tuple(self.local_addr) else: host, port = "", 0 - self.sock_impl = _server_socket_impl(host, port, backlog, self.pending_options[SO_REUSEADDR]) + self.sock_impl = _server_socket_impl(host, port, backlog, self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ]) self._config() except java.lang.Exception, jlx: raise _map_exception(jlx) @@ -790,7 +793,7 @@ if not new_sock: raise would_block_error() cliconn = _tcpsocket() - cliconn.pending_options[SO_REUSEADDR] = new_sock.jsocket.getReuseAddress() + cliconn.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ] = new_sock.jsocket.getReuseAddress() cliconn.sock_impl = new_sock cliconn._setup() return cliconn, new_sock.getpeername() @@ -810,7 +813,7 @@ self.sock_impl = _client_socket_impl() if self.local_addr: # Has the socket been bound to a local address? bind_host, bind_port = _unpack_address_tuple(self.local_addr) - self.sock_impl.bind(bind_host, bind_port, self.pending_options[SO_REUSEADDR]) + self.sock_impl.bind(bind_host, bind_port, self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ]) self._config() # Configure timeouts, etc, now that the socket exists self.sock_impl.connect(host, port) except java.lang.Exception, jlx: @@ -925,7 +928,7 @@ if host == "": host = INADDR_ANY host_address = java.net.InetAddress.getByName(host) - self.sock_impl = _datagram_socket_impl(port, host_address, self.pending_options[SO_REUSEADDR]) + self.sock_impl = _datagram_socket_impl(port, host_address, self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ]) self._config() except java.lang.Exception, jlx: raise _map_exception(jlx) Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2009-04-04 04:11:53 UTC (rev 6158) +++ trunk/jython/Lib/test/test_socket.py 2009-04-04 15:15:16 UTC (rev 6159) @@ -528,29 +528,29 @@ class TestSocketOptions(unittest.TestCase): - def setUp(self): + def setUp(self): self.test_udp = self.test_tcp_client = self.test_tcp_server = 0 - def _testSetAndGetOption(self, sock, option, values): + def _testSetAndGetOption(self, sock, level, option, values): for expected_value in values: - sock.setsockopt(socket.SOL_SOCKET, option, expected_value) - retrieved_value = sock.getsockopt(socket.SOL_SOCKET, option) + sock.setsockopt(level, option, expected_value) + retrieved_value = sock.getsockopt(level, option) self.failUnlessEqual(retrieved_value, expected_value, \ - "Retrieved option(%s) value %s != %s(value set)" % (option, retrieved_value, expected_value)) + "Retrieved option(%s, %s) value %s != %s(value set)" % (level, option, retrieved_value, expected_value)) - def _testUDPOption(self, option, values): + def _testUDPOption(self, level, option, values): try: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - self._testSetAndGetOption(sock, option, values) + self._testSetAndGetOption(sock, level, option, values) # now bind the socket i.e. cause the implementation socket to be created sock.bind( (HOST, PORT) ) - self.failUnlessEqual(sock.getsockopt(socket.SOL_SOCKET, option), values[-1], \ - "Option value '%s'='%s' did not propagate to implementation socket" % (option, values[-1]) ) - self._testSetAndGetOption(sock, option, values) + self.failUnlessEqual(sock.getsockopt(level, option), values[-1], \ + "Option value '(%s, %s)'='%s' did not propagate to implementation socket" % (level, option, values[-1]) ) + self._testSetAndGetOption(sock, level, option, values) finally: sock.close() - def _testTCPClientOption(self, option, values): + def _testTCPClientOption(self, level, option, values): sock = None try: # First listen on a server socket, so that the connection won't be refused. @@ -559,7 +559,7 @@ server_sock.listen(50) # Now do the tests sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self._testSetAndGetOption(sock, option, values) + self._testSetAndGetOption(sock, level, option, values) # now connect the socket i.e. cause the implementation socket to be created # First bind, so that the SO_REUSEADDR setting propagates sock.bind( (HOST, PORT+1) ) @@ -571,39 +571,39 @@ # establishing a connection. seems it will be *at least* # the values we test (which are rather small) on # BSDs. may need to relax this on other platforms also - self.assert_(sock.getsockopt(socket.SOL_SOCKET, option) >= values[-1], msg) + self.assert_(sock.getsockopt(level, option) >= values[-1], msg) else: - self.failUnlessEqual(sock.getsockopt(socket.SOL_SOCKET, option), values[-1], msg) - self._testSetAndGetOption(sock, option, values) + self.failUnlessEqual(sock.getsockopt(level, option), values[-1], msg) + self._testSetAndGetOption(sock, level, option, values) finally: server_sock.close() if sock: sock.close() - def _testTCPServerOption(self, option, values): + def _testTCPServerOption(self, level, option, values): try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self._testSetAndGetOption(sock, option, values) + self._testSetAndGetOption(sock, level, option, values) # now bind and listen on the socket i.e. cause the implementation socket to be created sock.bind( (HOST, PORT) ) sock.listen(50) - self.failUnlessEqual(sock.getsockopt(socket.SOL_SOCKET, option), values[-1], \ - "Option value '%s'='%s' did not propagate to implementation socket" % (option, values[-1])) - self._testSetAndGetOption(sock, option, values) + self.failUnlessEqual(sock.getsockopt(level, option), values[-1], \ + "Option value '(%s,%s)'='%s' did not propagate to implementation socket" % (level, option, values[-1])) + self._testSetAndGetOption(sock, level, option, values) finally: sock.close() - def _testOption(self, option, values): + def _testOption(self, level, option, values): for flag, func in [ (self.test_udp, self._testUDPOption), (self.test_tcp_server, self._testTCPServerOption), (self.test_tcp_client, self._testTCPClientOption), ]: if flag: - func(option, values) + func(level, option, values) else: try: - func(option, values) + func(level, option, values) except socket.error, se: self.failUnlessEqual(se[0], errno.ENOPROTOOPT, "Wrong errno from unsupported option exception: %d" % se[0]) except Exception, x: @@ -613,50 +613,50 @@ class TestSupportedOptions(TestSocketOptions): - def testSO_BROADCAST(self): + def testSO_BROADCAST(self): self.test_udp = 1 - self._testOption(socket.SO_BROADCAST, [0, 1]) + self._testOption(socket.SOL_SOCKET, socket.SO_BROADCAST, [0, 1]) def testSO_KEEPALIVE(self): self.test_tcp_client = 1 - self._testOption(socket.SO_KEEPALIVE, [0, 1]) + self._testOption(socket.SOL_SOCKET, socket.SO_KEEPALIVE, [0, 1]) def testSO_LINGER(self): self.test_tcp_client = 1 off = struct.pack('ii', 0, 0) on_2_seconds = struct.pack('ii', 1, 2) - self._testOption(socket.SO_LINGER, [off, on_2_seconds]) + self._testOption(socket.SOL_SOCKET, socket.SO_LINGER, [off, on_2_seconds]) def testSO_OOBINLINE(self): self.test_tcp_client = 1 - self._testOption(socket.SO_OOBINLINE, [0, 1]) + self._testOption(socket.SOL_SOCKET, socket.SO_OOBINLINE, [0, 1]) def testSO_RCVBUF(self): self.test_udp = 1 self.test_tcp_client = 1 self.test_tcp_server = 1 - self._testOption(socket.SO_RCVBUF, [1024, 4096, 16384]) + self._testOption(socket.SOL_SOCKET, socket.SO_RCVBUF, [1024, 4096, 16384]) def testSO_REUSEADDR(self): self.test_udp = 1 self.test_tcp_client = 1 self.test_tcp_server = 1 - self._testOption(socket.SO_REUSEADDR, [0, 1]) + self._testOption(socket.SOL_SOCKET, socket.SO_REUSEADDR, [0, 1]) def testSO_SNDBUF(self): self.test_udp = 1 self.test_tcp_client = 1 - self._testOption(socket.SO_SNDBUF, [1024, 4096, 16384]) + self._testOption(socket.SOL_SOCKET, socket.SO_SNDBUF, [1024, 4096, 16384]) def testSO_TIMEOUT(self): self.test_udp = 1 self.test_tcp_client = 1 self.test_tcp_server = 1 - self._testOption(socket.SO_TIMEOUT, [0, 1, 1000]) + self._testOption(socket.SOL_SOCKET, socket.SO_TIMEOUT, [0, 1, 1000]) def testTCP_NODELAY(self): self.test_tcp_client = 1 - self._testOption(socket.TCP_NODELAY, [0, 1]) + self._testOption(socket.IPPROTO_TCP, socket.TCP_NODELAY, [0, 1]) class TestUnsupportedOptions(TestSocketOptions): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |