You can subscribe to this list here.
2000 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
(107) |
Dec
(67) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(76) |
Feb
(125) |
Mar
(72) |
Apr
(13) |
May
(18) |
Jun
(12) |
Jul
(129) |
Aug
(47) |
Sep
(1) |
Oct
(36) |
Nov
(128) |
Dec
(124) |
2002 |
Jan
(59) |
Feb
|
Mar
(14) |
Apr
(14) |
May
(72) |
Jun
(9) |
Jul
(3) |
Aug
(5) |
Sep
(18) |
Oct
(65) |
Nov
(28) |
Dec
(12) |
2003 |
Jan
(10) |
Feb
(2) |
Mar
(4) |
Apr
(33) |
May
(21) |
Jun
(9) |
Jul
(29) |
Aug
(34) |
Sep
(4) |
Oct
(8) |
Nov
(15) |
Dec
(4) |
2004 |
Jan
(26) |
Feb
(12) |
Mar
(11) |
Apr
(9) |
May
(7) |
Jun
|
Jul
(5) |
Aug
|
Sep
(3) |
Oct
(7) |
Nov
(1) |
Dec
(10) |
2005 |
Jan
(2) |
Feb
(72) |
Mar
(16) |
Apr
(39) |
May
(48) |
Jun
(97) |
Jul
(57) |
Aug
(13) |
Sep
(16) |
Oct
(24) |
Nov
(100) |
Dec
(24) |
2006 |
Jan
(15) |
Feb
(34) |
Mar
(33) |
Apr
(31) |
May
(79) |
Jun
(64) |
Jul
(41) |
Aug
(64) |
Sep
(31) |
Oct
(46) |
Nov
(55) |
Dec
(37) |
2007 |
Jan
(32) |
Feb
(61) |
Mar
(11) |
Apr
(58) |
May
(46) |
Jun
(30) |
Jul
(94) |
Aug
(93) |
Sep
(86) |
Oct
(69) |
Nov
(125) |
Dec
(177) |
2008 |
Jan
(169) |
Feb
(97) |
Mar
(74) |
Apr
(113) |
May
(120) |
Jun
(334) |
Jul
(215) |
Aug
(237) |
Sep
(72) |
Oct
(189) |
Nov
(126) |
Dec
(160) |
2009 |
Jan
(180) |
Feb
(45) |
Mar
(98) |
Apr
(140) |
May
(151) |
Jun
(71) |
Jul
(107) |
Aug
(119) |
Sep
(73) |
Oct
(121) |
Nov
(14) |
Dec
(6) |
2010 |
Jan
(13) |
Feb
(9) |
Mar
(10) |
Apr
(64) |
May
(3) |
Jun
(16) |
Jul
(7) |
Aug
(23) |
Sep
(17) |
Oct
(37) |
Nov
(5) |
Dec
(8) |
2011 |
Jan
(10) |
Feb
(11) |
Mar
(77) |
Apr
(11) |
May
(2) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <fwi...@us...> - 2011-03-12 19:30:42
|
Revision: 7217 http://jython.svn.sourceforge.net/jython/?rev=7217&view=rev Author: fwierzbicki Date: 2011-03-12 19:30:30 +0000 (Sat, 12 Mar 2011) Log Message: ----------- from: http://svn.python.org/projects/python/branches/release26-maint/Lib/warnings.py@88766 Modified Paths: -------------- trunk/jython/Lib/warnings.py Modified: trunk/jython/Lib/warnings.py =================================================================== --- trunk/jython/Lib/warnings.py 2011-03-12 18:54:26 UTC (rev 7216) +++ trunk/jython/Lib/warnings.py 2011-03-12 19:30:30 UTC (rev 7217) @@ -3,145 +3,43 @@ # Note: function level imports should *not* be used # in this module as it may cause import lock deadlock. # See bug 683658. -import sys, types import linecache +import sys +import types __all__ = ["warn", "showwarning", "formatwarning", "filterwarnings", - "resetwarnings"] + "resetwarnings", "catch_warnings"] -# filters contains a sequence of filter 5-tuples -# The components of the 5-tuple are: -# - an action: error, ignore, always, default, module, or once -# - a compiled regex that must match the warning message -# - a class representing the warning category -# - a compiled regex that must match the module that is being warned -# - a line number for the line being warning, or 0 to mean any line -# If either if the compiled regexs are None, match anything. -filters = [] -defaultaction = "default" -onceregistry = {} -def warn(message, category=None, stacklevel=1): - """Issue a warning, or maybe ignore it or raise an exception.""" - # Check if message is already a Warning object - if isinstance(message, Warning): - category = message.__class__ - # Check category argument - if category is None: - category = UserWarning - assert issubclass(category, Warning) - # Get context information - try: - caller = sys._getframe(stacklevel) - except ValueError: - globals = sys.__dict__ - lineno = 1 - else: - globals = caller.f_globals - lineno = caller.f_lineno - if '__name__' in globals: - module = globals['__name__'] - else: - module = "<string>" - filename = globals.get('__file__') - if filename: - fnl = filename.lower() - if fnl.endswith((".pyc", ".pyo")): - filename = filename[:-1] - elif fnl.endswith("$py.class"): - filename = filename[:-9] + '.py' - else: - if module == "__main__": - try: - filename = sys.argv[0] - except AttributeError: - # embedded interpreters don't have sys.argv, see bug #839151 - filename = '__main__' - if not filename: - filename = module - registry = globals.setdefault("__warningregistry__", {}) - warn_explicit(message, category, filename, lineno, module, registry, - globals) +def warnpy3k(message, category=None, stacklevel=1): + """Issue a deprecation warning for Python 3.x related changes. -def warn_explicit(message, category, filename, lineno, - module=None, registry=None, module_globals=None): - if module is None: - module = filename or "<unknown>" - if module[-3:].lower() == ".py": - module = module[:-3] # XXX What about leading pathname? - if registry is None: - registry = {} - if isinstance(message, Warning): - text = str(message) - category = message.__class__ - else: - text = message - message = category(message) - key = (text, category, lineno) - # Quick test for common case - if registry.get(key): - return - # Search the filters - for item in filters: - action, msg, cat, mod, ln = item - if ((msg is None or msg.match(text)) and - issubclass(category, cat) and - (mod is None or mod.match(module)) and - (ln == 0 or lineno == ln)): - break - else: - action = defaultaction - # Early exit actions - if action == "ignore": - registry[key] = 1 - return + Warnings are omitted unless Python is started with the -3 option. + """ + if sys.py3kwarning: + if category is None: + category = DeprecationWarning + warn(message, category, stacklevel+1) - # Prime the linecache for formatting, in case the - # "file" is actually in a zipfile or something. - linecache.getlines(filename, module_globals) - - if action == "error": - raise message - # Other actions - if action == "once": - registry[key] = 1 - oncekey = (text, category) - if onceregistry.get(oncekey): - return - onceregistry[oncekey] = 1 - elif action == "always": - pass - elif action == "module": - registry[key] = 1 - altkey = (text, category, 0) - if registry.get(altkey): - return - registry[altkey] = 1 - elif action == "default": - registry[key] = 1 - else: - # Unrecognized actions are errors - raise RuntimeError( - "Unrecognized action (%r) in warnings.filters:\n %s" % - (action, item)) - # Print message and context - showwarning(message, category, filename, lineno) - -def showwarning(message, category, filename, lineno, file=None): +def _show_warning(message, category, filename, lineno, file=None, line=None): """Hook to write a warning to a file; replace if you like.""" if file is None: file = sys.stderr try: - file.write(formatwarning(message, category, filename, lineno)) + file.write(formatwarning(message, category, filename, lineno, line)) except IOError: pass # the file (probably stderr) is invalid - this warning gets lost. +# Keep a working version around in case the deprecation of the old API is +# triggered. +showwarning = _show_warning -def formatwarning(message, category, filename, lineno): +def formatwarning(message, category, filename, lineno, line=None): """Function to format a warning the standard way.""" s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message) - line = linecache.getline(filename, lineno).strip() + line = linecache.getline(filename, lineno) if line is None else line if line: - s = s + " " + line + "\n" + line = line.strip() + s += " %s\n" % line return s def filterwarnings(action, message="", category=Warning, module="", lineno=0, @@ -260,7 +158,245 @@ raise _OptionError("invalid warning category: %r" % (category,)) return cat + +# Code typically replaced by _warnings +def warn(message, category=None, stacklevel=1): + """Issue a warning, or maybe ignore it or raise an exception.""" + # Check if message is already a Warning object + if isinstance(message, Warning): + category = message.__class__ + # Check category argument + if category is None: + category = UserWarning + assert issubclass(category, Warning) + # Get context information + try: + caller = sys._getframe(stacklevel) + except ValueError: + globals = sys.__dict__ + lineno = 1 + else: + globals = caller.f_globals + lineno = caller.f_lineno + if '__name__' in globals: + module = globals['__name__'] + else: + module = "<string>" + filename = globals.get('__file__') + if filename: + fnl = filename.lower() + if fnl.endswith((".pyc", ".pyo")): + filename = filename[:-1] + else: + if module == "__main__": + try: + filename = sys.argv[0] + except AttributeError: + # embedded interpreters don't have sys.argv, see bug #839151 + filename = '__main__' + if not filename: + filename = module + registry = globals.setdefault("__warningregistry__", {}) + warn_explicit(message, category, filename, lineno, module, registry, + globals) + +def warn_explicit(message, category, filename, lineno, + module=None, registry=None, module_globals=None): + lineno = int(lineno) + if module is None: + module = filename or "<unknown>" + if module[-3:].lower() == ".py": + module = module[:-3] # XXX What about leading pathname? + if registry is None: + registry = {} + if isinstance(message, Warning): + text = str(message) + category = message.__class__ + else: + text = message + message = category(message) + key = (text, category, lineno) + # Quick test for common case + if registry.get(key): + return + # Search the filters + for item in filters: + action, msg, cat, mod, ln = item + if ((msg is None or msg.match(text)) and + issubclass(category, cat) and + (mod is None or mod.match(module)) and + (ln == 0 or lineno == ln)): + break + else: + action = defaultaction + # Early exit actions + if action == "ignore": + registry[key] = 1 + return + + # Prime the linecache for formatting, in case the + # "file" is actually in a zipfile or something. + linecache.getlines(filename, module_globals) + + if action == "error": + raise message + # Other actions + if action == "once": + registry[key] = 1 + oncekey = (text, category) + if onceregistry.get(oncekey): + return + onceregistry[oncekey] = 1 + elif action == "always": + pass + elif action == "module": + registry[key] = 1 + altkey = (text, category, 0) + if registry.get(altkey): + return + registry[altkey] = 1 + elif action == "default": + registry[key] = 1 + else: + # Unrecognized actions are errors + raise RuntimeError( + "Unrecognized action (%r) in warnings.filters:\n %s" % + (action, item)) + # Warn if showwarning() does not support the 'line' argument. + # Don't use 'inspect' as it relies on an extension module, which break the + # build thanks to 'warnings' being imported by setup.py. + fxn_code = None + if hasattr(showwarning, 'func_code'): + fxn_code = showwarning.func_code + elif hasattr(showwarning, '__func__'): + fxn_code = showwarning.__func__.func_code + if fxn_code: + args = fxn_code.co_varnames[:fxn_code.co_argcount] + CO_VARARGS = 0x4 + if 'line' not in args and not fxn_code.co_flags & CO_VARARGS: + showwarning_msg = ("functions overriding warnings.showwarning() " + "must support the 'line' argument") + if message == showwarning_msg: + _show_warning(message, category, filename, lineno) + else: + warn(showwarning_msg, DeprecationWarning) + # Print message and context + showwarning(message, category, filename, lineno) + + +class WarningMessage(object): + + """Holds the result of a single showwarning() call.""" + + _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file", + "line") + + def __init__(self, message, category, filename, lineno, file=None, + line=None): + local_values = locals() + for attr in self._WARNING_DETAILS: + setattr(self, attr, local_values[attr]) + self._category_name = category.__name__ if category else None + + def __str__(self): + return ("{message : %r, category : %r, filename : %r, lineno : %s, " + "line : %r}" % (self.message, self._category_name, + self.filename, self.lineno, self.line)) + + +class catch_warnings(object): + + """A context manager that copies and restores the warnings filter upon + exiting the context. + + The 'record' argument specifies whether warnings should be captured by a + custom implementation of warnings.showwarning() and be appended to a list + returned by the context manager. Otherwise None is returned by the context + manager. The objects appended to the list are arguments whose attributes + mirror the arguments to showwarning(). + + The 'module' argument is to specify an alternative module to the module + named 'warnings' and imported under that name. This argument is only useful + when testing the warnings module itself. + + """ + + def __init__(self, record=False, module=None): + """Specify whether to record warnings and if an alternative module + should be used other than sys.modules['warnings']. + + For compatibility with Python 3.0, please consider all arguments to be + keyword-only. + + """ + self._record = record + self._module = sys.modules['warnings'] if module is None else module + self._entered = False + + def __repr__(self): + args = [] + if self._record: + args.append("record=True") + if self._module is not sys.modules['warnings']: + args.append("module=%r" % self._module) + name = type(self).__name__ + return "%s(%s)" % (name, ", ".join(args)) + + def __enter__(self): + if self._entered: + raise RuntimeError("Cannot enter %r twice" % self) + self._entered = True + self._filters = self._module.filters + self._module.filters = self._filters[:] + self._showwarning = self._module.showwarning + if self._record: + log = [] + def showwarning(*args, **kwargs): + log.append(WarningMessage(*args, **kwargs)) + self._module.showwarning = showwarning + return log + else: + return None + + def __exit__(self, *exc_info): + if not self._entered: + raise RuntimeError("Cannot exit %r without entering first" % self) + self._module.filters = self._filters + self._module.showwarning = self._showwarning + + +# filters contains a sequence of filter 5-tuples +# The components of the 5-tuple are: +# - an action: error, ignore, always, default, module, or once +# - a compiled regex that must match the warning message +# - a class representing the warning category +# - a compiled regex that must match the module that is being warned +# - a line number for the line being warning, or 0 to mean any line +# If either if the compiled regexs are None, match anything. +_warnings_defaults = False +try: + from _warnings import (filters, default_action, once_registry, + warn, warn_explicit) + defaultaction = default_action + onceregistry = once_registry + _warnings_defaults = True +except ImportError: + filters = [] + defaultaction = "default" + onceregistry = {} + + # Module initialization _processoptions(sys.warnoptions) -simplefilter("ignore", category=PendingDeprecationWarning, append=1) -simplefilter("ignore", category=ImportWarning, append=1) +if not _warnings_defaults: + simplefilter("ignore", category=PendingDeprecationWarning, append=1) + simplefilter("ignore", category=ImportWarning, append=1) + bytes_warning = sys.flags.bytes_warning + if bytes_warning > 1: + bytes_action = "error" + elif bytes_warning: + bytes_action = "default" + else: + bytes_action = "ignore" + simplefilter(bytes_action, category=BytesWarning, append=1) +del _warnings_defaults This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fwi...@us...> - 2011-03-12 18:54:37
|
Revision: 7216 http://jython.svn.sourceforge.net/jython/?rev=7216&view=rev Author: fwierzbicki Date: 2011-03-12 18:54:26 +0000 (Sat, 12 Mar 2011) Log Message: ----------- Fixes (not all of them good) to get test_support working for Jython. Modified Paths: -------------- trunk/jython/Lib/test/test_support.py Modified: trunk/jython/Lib/test/test_support.py =================================================================== --- trunk/jython/Lib/test/test_support.py 2011-03-12 18:46:20 UTC (rev 7215) +++ trunk/jython/Lib/test/test_support.py 2011-03-12 18:54:26 UTC (rev 7216) @@ -207,7 +207,34 @@ on Windows), it will be set on the socket. This will prevent anyone else from bind()'ing to our host/port for the duration of the test. """ - if sock.family == socket.AF_INET and sock.type == socket.SOCK_STREAM: + + #XXX: This section is probably wrong as I (Frank Wierzbicki) don't really + # understand it, but I needed this to get the asynchat tests running + # again. + if is_jython: + # Find some random ports that hopefully no one is listening on. + # Ideally each test would clean up after itself and not continue + # listening on any ports. However, this isn't the case. The last port + # (0) is a stop-gap that asks the O/S to assign a port. Whenever the + # warning message below is printed, the test that is listening on the + # port should be fixed to close the socket at the end of the test. + # Another reason why we can't use a port is another process (possibly + # another instance of the test suite) is using the same port. + + for port in [54321, 9907, 10243, 32999, 0]: + try: + sock.bind((host, port)) + if port == 0: + port = sock.getsockname()[1] + return port + except socket.error, (err, msg): + if err != errno.EADDRINUSE: + raise + print >>sys.__stderr__, \ + ' WARNING: failed to listen on port %d, trying another' % port + raise TestFailed, 'unable to find port to listen on' + + elif sock.family == socket.AF_INET and sock.type == socket.SOCK_STREAM: if hasattr(socket, 'SO_REUSEADDR'): if sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) == 1: raise TestFailed("tests should never set the SO_REUSEADDR " \ @@ -248,7 +275,25 @@ have_unicode = False is_jython = sys.platform.startswith('java') +if is_jython: + def make_jar_classloader(jar): + import os + from java.net import URL, URLClassLoader + url = URL('jar:file:%s!/' % jar) + if os._name == 'nt': + # URLJarFiles keep a cached open file handle to the jar even + # after this ClassLoader is GC'ed, disallowing Windows tests + # from removing the jar file from disk when finished with it + conn = url.openConnection() + if conn.getDefaultUseCaches(): + # XXX: Globally turn off jar caching: this stupid + # instance method actually toggles a static flag. Need a + # better fix + conn.setDefaultUseCaches(False) + + return URLClassLoader([url]) + # Filename used for testing if os.name == 'java': # Jython disallows @ in module names @@ -857,6 +902,8 @@ def threading_setup(): import threading + if is_jython: + return len(threading._active), 0 return len(threading._active), len(threading._limbo) def threading_cleanup(num_active, num_limbo): @@ -869,10 +916,11 @@ count += 1 time.sleep(0.1) - count = 0 - while len(threading._limbo) != num_limbo and count < _MAX_COUNT: - count += 1 - time.sleep(0.1) + if not is_jython: + count = 0 + while len(threading._limbo) != num_limbo and count < _MAX_COUNT: + count += 1 + time.sleep(0.1) def reap_children(): """Use this function at the end of test_main() whenever sub-processes This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fwi...@us...> - 2011-03-12 18:46:32
|
Revision: 7215 http://jython.svn.sourceforge.net/jython/?rev=7215&view=rev Author: fwierzbicki Date: 2011-03-12 18:46:20 +0000 (Sat, 12 Mar 2011) Log Message: ----------- from: http://svn.python.org/projects/python/branches/release26-maint/Lib/test/test_support.py@88766 Modified Paths: -------------- trunk/jython/Lib/test/test_support.py Modified: trunk/jython/Lib/test/test_support.py =================================================================== --- trunk/jython/Lib/test/test_support.py 2011-03-12 18:41:56 UTC (rev 7214) +++ trunk/jython/Lib/test/test_support.py 2011-03-12 18:46:20 UTC (rev 7215) @@ -1,11 +1,31 @@ """Supporting definitions for the Python regression tests.""" if __name__ != 'test.test_support': - raise ImportError, 'test_support must be imported from the test package' + raise ImportError('test_support must be imported from the test package') +import contextlib +import errno +import socket import sys -import time +import os +import shutil +import warnings +import unittest +import re +__all__ = ["Error", "TestFailed", "TestSkipped", "ResourceDenied", "import_module", + "verbose", "use_resources", "max_memuse", "record_original_stdout", + "get_original_stdout", "unload", "unlink", "rmtree", "forget", + "is_resource_enabled", "requires", "find_unused_port", "bind_port", + "fcmp", "have_unicode", "is_jython", "TESTFN", "HOST", "FUZZ", + "findfile", "verify", "vereq", "sortdict", "check_syntax_error", + "open_urlresource", "check_warnings", "_check_py3k_warnings", + "CleanImport", "EnvironmentVarGuard", "captured_output", + "captured_stdout", "TransientResource", "transient_internet", + "run_with_locale", "set_memlimit", "bigmemtest", "bigaddrspacetest", + "BasicTestRunner", "run_unittest", "run_doctest", "threading_setup", + "threading_cleanup", "reap_children"] + class Error(Exception): """Base class for regression test exceptions.""" @@ -30,11 +50,25 @@ and unexpected skips. """ +def import_module(name, deprecated=False): + """Import the module to be tested, raising TestSkipped if it is not + available.""" + with warnings.catch_warnings(): + if deprecated: + warnings.filterwarnings("ignore", ".+ (module|package)", + DeprecationWarning) + try: + module = __import__(name, level=0) + except ImportError: + raise TestSkipped("No module named " + name) + else: + return module + verbose = 1 # Flag set to 0 by regrtest.py use_resources = None # Flag set to [] by regrtest.py -junit_xml_dir = None # Option set by regrtest.py max_memuse = 0 # Disable bigmem tests (they will still be run with # small sizes, to make sure they work.) +real_max_memuse = 0 # _original_stdout is meant to hold stdout at the time regrtest began. # This may be "the real" stdout, or IDLE's emulation of stdout, or whatever. @@ -54,17 +88,23 @@ pass def unlink(filename): - import os try: os.unlink(filename) except OSError: pass +def rmtree(path): + try: + shutil.rmtree(path) + except OSError, e: + # Unix returns ENOENT, Windows returns ESRCH. + if e.errno not in (errno.ENOENT, errno.ESRCH): + raise + def forget(modname): '''"Forget" a module was ever imported by removing it from sys.modules and deleting any .pyc and .pyo files.''' unload(modname) - import os for dirname in sys.path: unlink(os.path.join(dirname, modname + os.extsep + 'pyc')) # Deleting the .pyo file cannot be within the 'try' for the .pyc since @@ -91,80 +131,124 @@ msg = "Use of the `%s' resource not enabled" % resource raise ResourceDenied(msg) -def bind_port(sock, host='', preferred_port=54321): - """Try to bind the sock to a port. If we are running multiple - tests and we don't try multiple ports, the test can fails. This - makes the test more robust.""" +HOST = 'localhost' - import socket, errno +def find_unused_port(family=socket.AF_INET, socktype=socket.SOCK_STREAM): + """Returns an unused port that should be suitable for binding. This is + achieved by creating a temporary socket with the same family and type as + the 'sock' parameter (default is AF_INET, SOCK_STREAM), and binding it to + the specified host address (defaults to 0.0.0.0) with the port set to 0, + eliciting an unused ephemeral port from the OS. The temporary socket is + then closed and deleted, and the ephemeral port is returned. - # Find some random ports that hopefully no one is listening on. - # Ideally each test would clean up after itself and not continue listening - # on any ports. However, this isn't the case. The last port (0) is - # a stop-gap that asks the O/S to assign a port. Whenever the warning - # message below is printed, the test that is listening on the port should - # be fixed to close the socket at the end of the test. - # Another reason why we can't use a port is another process (possibly - # another instance of the test suite) is using the same port. - for port in [preferred_port, 9907, 10243, 32999, 0]: - try: - sock.bind((host, port)) - if port == 0: - port = sock.getsockname()[1] - return port - except socket.error, (err, msg): - if err != errno.EADDRINUSE: - raise - print >>sys.__stderr__, \ - ' WARNING: failed to listen on port %d, trying another' % port - raise TestFailed, 'unable to find port to listen on' + Either this method or bind_port() should be used for any tests where a + server socket needs to be bound to a particular port for the duration of + the test. Which one to use depends on whether the calling code is creating + a python socket, or if an unused port needs to be provided in a constructor + or passed to an external program (i.e. the -accept argument to openssl's + s_server mode). Always prefer bind_port() over find_unused_port() where + possible. Hard coded ports should *NEVER* be used. As soon as a server + socket is bound to a hard coded port, the ability to run multiple instances + of the test simultaneously on the same host is compromised, which makes the + test a ticking time bomb in a buildbot environment. On Unix buildbots, this + may simply manifest as a failed test, which can be recovered from without + intervention in most cases, but on Windows, the entire python process can + completely and utterly wedge, requiring someone to log in to the buildbot + and manually kill the affected process. + (This is easy to reproduce on Windows, unfortunately, and can be traced to + the SO_REUSEADDR socket option having different semantics on Windows versus + Unix/Linux. On Unix, you can't have two AF_INET SOCK_STREAM sockets bind, + listen and then accept connections on identical host/ports. An EADDRINUSE + socket.error will be raised at some point (depending on the platform and + the order bind and listen were called on each socket). + + However, on Windows, if SO_REUSEADDR is set on the sockets, no EADDRINUSE + will ever be raised when attempting to bind two identical host/ports. When + accept() is called on each socket, the second caller's process will steal + the port from the first caller, leaving them both in an awkwardly wedged + state where they'll no longer respond to any signals or graceful kills, and + must be forcibly killed via OpenProcess()/TerminateProcess(). + + The solution on Windows is to use the SO_EXCLUSIVEADDRUSE socket option + instead of SO_REUSEADDR, which effectively affords the same semantics as + SO_REUSEADDR on Unix. Given the propensity of Unix developers in the Open + Source world compared to Windows ones, this is a common mistake. A quick + look over OpenSSL's 0.9.8g source shows that they use SO_REUSEADDR when + openssl.exe is called with the 's_server' option, for example. See + http://bugs.python.org/issue2550 for more info. The following site also + has a very thorough description about the implications of both REUSEADDR + and EXCLUSIVEADDRUSE on Windows: + http://msdn2.microsoft.com/en-us/library/ms740621(VS.85).aspx) + + XXX: although this approach is a vast improvement on previous attempts to + elicit unused ports, it rests heavily on the assumption that the ephemeral + port returned to us by the OS won't immediately be dished back out to some + other process when we close and delete our temporary socket but before our + calling code has a chance to bind the returned port. We can deal with this + issue if/when we come across it.""" + tempsock = socket.socket(family, socktype) + port = bind_port(tempsock) + tempsock.close() + del tempsock + return port + +def bind_port(sock, host=HOST): + """Bind the socket to a free port and return the port number. Relies on + ephemeral ports in order to ensure we are using an unbound port. This is + important as many tests may be running simultaneously, especially in a + buildbot environment. This method raises an exception if the sock.family + is AF_INET and sock.type is SOCK_STREAM, *and* the socket has SO_REUSEADDR + or SO_REUSEPORT set on it. Tests should *never* set these socket options + for TCP/IP sockets. The only case for setting these options is testing + multicasting via multiple UDP sockets. + + Additionally, if the SO_EXCLUSIVEADDRUSE socket option is available (i.e. + on Windows), it will be set on the socket. This will prevent anyone else + from bind()'ing to our host/port for the duration of the test. + """ + if sock.family == socket.AF_INET and sock.type == socket.SOCK_STREAM: + if hasattr(socket, 'SO_REUSEADDR'): + if sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) == 1: + raise TestFailed("tests should never set the SO_REUSEADDR " \ + "socket option on TCP/IP sockets!") + if hasattr(socket, 'SO_REUSEPORT'): + if sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT) == 1: + raise TestFailed("tests should never set the SO_REUSEPORT " \ + "socket option on TCP/IP sockets!") + if hasattr(socket, 'SO_EXCLUSIVEADDRUSE'): + sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1) + + sock.bind((host, 0)) + port = sock.getsockname()[1] + return port + FUZZ = 1e-6 def fcmp(x, y): # fuzzy comparison function - if type(x) == type(0.0) or type(y) == type(0.0): + if isinstance(x, float) or isinstance(y, float): try: - x, y = coerce(x, y) fuzz = (abs(x) + abs(y)) * FUZZ if abs(x-y) <= fuzz: return 0 except: pass - elif type(x) == type(y) and type(x) in (type(()), type([])): + elif type(x) == type(y) and isinstance(x, (tuple, list)): for i in range(min(len(x), len(y))): outcome = fcmp(x[i], y[i]) if outcome != 0: return outcome - return cmp(len(x), len(y)) - return cmp(x, y) + return (len(x) > len(y)) - (len(x) < len(y)) + return (x > y) - (x < y) try: unicode - have_unicode = 1 + have_unicode = True except NameError: - have_unicode = 0 + have_unicode = False is_jython = sys.platform.startswith('java') -if is_jython: - def make_jar_classloader(jar): - import os - from java.net import URL, URLClassLoader - url = URL('jar:file:%s!/' % jar) - if os._name == 'nt': - # URLJarFiles keep a cached open file handle to the jar even - # after this ClassLoader is GC'ed, disallowing Windows tests - # from removing the jar file from disk when finished with it - conn = url.openConnection() - if conn.getDefaultUseCaches(): - # XXX: Globally turn off jar caching: this stupid - # instance method actually toggles a static flag. Need a - # better fix - conn.setDefaultUseCaches(False) - - return URLClassLoader([url]) - -import os # Filename used for testing if os.name == 'java': # Jython disallows @ in module names @@ -227,13 +311,12 @@ if fp is not None: fp.close() unlink(TESTFN) -del os, fp +del fp def findfile(file, here=__file__): """Try to find a file on sys.path and the working directory. If it is not found the argument passed to the function is returned (this does not necessarily signal failure; could still be the legitimate path).""" - import os if os.path.isabs(file): return file path = sys.path @@ -265,7 +348,7 @@ """ if not (a == b): - raise TestFailed, "%r == %r" % (a, b) + raise TestFailed("%r == %r" % (a, b)) def sortdict(dict): "Like repr(dict), but in sorted order." @@ -275,18 +358,30 @@ withcommas = ", ".join(reprpairs) return "{%s}" % withcommas -def check_syntax(statement): +def make_bad_fd(): + """ + Create an invalid file descriptor by opening and closing a file and return + its fd. + """ + file = open(TESTFN, "wb") try: - compile(statement, '<string>', 'exec') + return file.fileno() + finally: + file.close() + unlink(TESTFN) + +def check_syntax_error(testcase, statement): + try: + compile(statement, '<test string>', 'exec') except SyntaxError: pass else: - print 'Missing SyntaxError: "%s"' % statement + testcase.fail('Missing SyntaxError: "%s"' % statement) def open_urlresource(url): - import urllib, urlparse - import os.path + import urlparse, urllib2 + requires('urlfetch') filename = urlparse.urlparse(url)[2].split('/')[-1] # '/': it's URL! for path in [os.path.curdir, os.path.pardir]: @@ -294,11 +389,250 @@ if os.path.exists(fn): return open(fn) - requires('urlfetch') print >> get_original_stdout(), '\tfetching %s ...' % url - fn, _ = urllib.urlretrieve(url, filename) - return open(fn) + f = urllib2.urlopen(url, timeout=15) + try: + with open(filename, "wb") as out: + s = f.read() + while s: + out.write(s) + s = f.read() + finally: + f.close() + return open(filename) + +class WarningsRecorder(object): + """Convenience wrapper for the warnings list returned on + entry to the warnings.catch_warnings() context manager. + """ + def __init__(self, warnings_list): + self._warnings = warnings_list + self._last = 0 + + def __getattr__(self, attr): + if len(self._warnings) > self._last: + return getattr(self._warnings[-1], attr) + elif attr in warnings.WarningMessage._WARNING_DETAILS: + return None + raise AttributeError("%r has no attribute %r" % (self, attr)) + + @property + def warnings(self): + return self._warnings[self._last:] + + def reset(self): + self._last = len(self._warnings) + + +def _filterwarnings(filters, quiet=False): + """Catch the warnings, then check if all the expected + warnings have been raised and re-raise unexpected warnings. + If 'quiet' is True, only re-raise the unexpected warnings. + """ + # Clear the warning registry of the calling module + # in order to re-raise the warnings. + frame = sys._getframe(2) + registry = frame.f_globals.get('__warningregistry__') + if registry: + registry.clear() + with warnings.catch_warnings(record=True) as w: + # Set filter "always" to record all warnings. Because + # test_warnings swap the module, we need to look up in + # the sys.modules dictionary. + sys.modules['warnings'].simplefilter("always") + yield WarningsRecorder(w) + # Filter the recorded warnings + reraise = [warning.message for warning in w] + missing = [] + for msg, cat in filters: + seen = False + for exc in reraise[:]: + message = str(exc) + # Filter out the matching messages + if (re.match(msg, message, re.I) and + issubclass(exc.__class__, cat)): + seen = True + reraise.remove(exc) + if not seen and not quiet: + # This filter caught nothing + missing.append((msg, cat.__name__)) + if reraise: + raise AssertionError("unhandled warning %r" % reraise[0]) + if missing: + raise AssertionError("filter (%r, %s) did not catch any warning" % + missing[0]) + + +...@co...ntextmanager +def check_warnings(*filters, **kwargs): + """Context manager to silence warnings. + + Accept 2-tuples as positional arguments: + ("message regexp", WarningCategory) + + Optional argument: + - if 'quiet' is True, it does not fail if a filter catches nothing + (default True without argument, + default False if some filters are defined) + + Without argument, it defaults to: + check_warnings(("", Warning), quiet=True) + """ + quiet = kwargs.get('quiet') + if not filters: + filters = (("", Warning),) + # Preserve backward compatibility + if quiet is None: + quiet = True + return _filterwarnings(filters, quiet) + + +...@co...ntextmanager +def _check_py3k_warnings(*filters, **kwargs): + """Context manager to silence py3k warnings. + + Accept 2-tuples as positional arguments: + ("message regexp", WarningCategory) + + Optional argument: + - if 'quiet' is True, it does not fail if a filter catches nothing + (default False) + + Without argument, it defaults to: + _check_py3k_warnings(("", DeprecationWarning), quiet=False) + """ + if sys.py3kwarning: + if not filters: + filters = (("", DeprecationWarning),) + else: + # It should not raise any py3k warning + filters = () + return _filterwarnings(filters, kwargs.get('quiet')) + + +class CleanImport(object): + """Context manager to force import to return a new module reference. + + This is useful for testing module-level behaviours, such as + the emission of a DeprecationWarning on import. + + Use like this: + + with CleanImport("foo"): + __import__("foo") # new reference + """ + + def __init__(self, *module_names): + self.original_modules = sys.modules.copy() + for module_name in module_names: + if module_name in sys.modules: + module = sys.modules[module_name] + # It is possible that module_name is just an alias for + # another module (e.g. stub for modules renamed in 3.x). + # In that case, we also need delete the real module to clear + # the import cache. + if module.__name__ != module_name: + del sys.modules[module.__name__] + del sys.modules[module_name] + + def __enter__(self): + return self + + def __exit__(self, *ignore_exc): + sys.modules.update(self.original_modules) + + +class EnvironmentVarGuard(object): + + """Class to help protect the environment variable properly. Can be used as + a context manager.""" + + def __init__(self): + self._changed = {} + + def set(self, envvar, value): + # Remember the initial value on the first access + if envvar not in self._changed: + self._changed[envvar] = os.environ.get(envvar) + os.environ[envvar] = value + + def unset(self, envvar): + # Remember the initial value on the first access + if envvar not in self._changed: + self._changed[envvar] = os.environ.get(envvar) + if envvar in os.environ: + del os.environ[envvar] + + def __enter__(self): + return self + + def __exit__(self, *ignore_exc): + for (k, v) in self._changed.items(): + if v is None: + if k in os.environ: + del os.environ[k] + else: + os.environ[k] = v + + +class TransientResource(object): + + """Raise ResourceDenied if an exception is raised while the context manager + is in effect that matches the specified exception and attributes.""" + + def __init__(self, exc, **kwargs): + self.exc = exc + self.attrs = kwargs + + def __enter__(self): + return self + + def __exit__(self, type_=None, value=None, traceback=None): + """If type_ is a subclass of self.exc and value has attributes matching + self.attrs, raise ResourceDenied. Otherwise let the exception + propagate (if any).""" + if type_ is not None and issubclass(self.exc, type_): + for attr, attr_value in self.attrs.iteritems(): + if not hasattr(value, attr): + break + if getattr(value, attr) != attr_value: + break + else: + raise ResourceDenied("an optional resource is not available") + + +def transient_internet(): + """Return a context manager that raises ResourceDenied when various issues + with the Internet connection manifest themselves as exceptions.""" + time_out = TransientResource(IOError, errno=errno.ETIMEDOUT) + socket_peer_reset = TransientResource(socket.error, errno=errno.ECONNRESET) + ioerror_peer_reset = TransientResource(IOError, errno=errno.ECONNRESET) + return contextlib.nested(time_out, socket_peer_reset, ioerror_peer_reset) + + +...@co...ntextmanager +def captured_output(stream_name): + """Run the 'with' statement body using a StringIO object in place of a + specific attribute on the sys module. + Example use (with 'stream_name=stdout'):: + + with captured_stdout() as s: + print "hello" + assert s.getvalue() == "hello" + """ + import StringIO + orig_stdout = getattr(sys, stream_name) + setattr(sys, stream_name, StringIO.StringIO()) + try: + yield getattr(sys, stream_name) + finally: + setattr(sys, stream_name, orig_stdout) + +def captured_stdout(): + return captured_output("stdout") + + #======================================================================= # Decorator for running a function in a different locale, correctly resetting # it afterwards. @@ -343,16 +677,13 @@ _1M = 1024*1024 _1G = 1024 * _1M _2G = 2 * _1G +_4G = 4 * _1G -# Hack to get at the maximum value an internal index can take. -class _Dummy: - def __getslice__(self, i, j): - return j -MAX_Py_ssize_t = _Dummy()[:] +MAX_Py_ssize_t = sys.maxsize def set_memlimit(limit): - import re global max_memuse + global real_max_memuse sizes = { 'k': 1024, 'm': _1M, @@ -364,6 +695,7 @@ if m is None: raise ValueError('Invalid memory limit %r' % (limit,)) memlimit = int(float(m.group(1)) * sizes[m.group(3).lower()]) + real_max_memuse = memlimit if memlimit > MAX_Py_ssize_t: memlimit = MAX_Py_ssize_t if memlimit < _2G - 1: @@ -376,7 +708,7 @@ 'minsize' is the minimum useful size for the test (in arbitrary, test-interpreted units.) 'memuse' is the number of 'bytes per size' for the test, or a good estimate of it. 'overhead' specifies fixed overhead, - independant of the testsize, and defaults to 5Mb. + independent of the testsize, and defaults to 5Mb. The decorator tries to guess a good value for 'size' and passes it to the decorated test function. If minsize * memuse is more than the @@ -409,6 +741,27 @@ return wrapper return decorator +def precisionbigmemtest(size, memuse, overhead=5*_1M): + def decorator(f): + def wrapper(self): + if not real_max_memuse: + maxsize = 5147 + else: + maxsize = size + + if real_max_memuse and real_max_memuse < maxsize * memuse: + if verbose: + sys.stderr.write("Skipping %s because of memory " + "constraint\n" % (f.__name__,)) + return + + return f(self, maxsize) + wrapper.size = size + wrapper.memuse = memuse + wrapper.overhead = overhead + return wrapper + return decorator + def bigaddrspacetest(f): """Decorator for tests that fill the address space.""" def wrapper(self): @@ -421,11 +774,8 @@ return wrapper #======================================================================= -# Preliminary PyUNIT integration. +# unittest integration. -import unittest - - class BasicTestRunner: def run(self, test): result = unittest.TestResult() @@ -433,31 +783,9 @@ return result -def run_suite(suite, testclass=None): - """Run all TestCases in their own individual TestSuite""" - if not junit_xml_dir: - # Splitting tests apart slightly changes the handling of the - # TestFailed message - return _run_suite(suite, testclass) - - failed = False - for test in suite: - suite = unittest.TestSuite() - suite.addTest(test) - try: - _run_suite(suite, testclass) - except TestFailed, e: - if not failed: - failed = e - if failed: - raise failed - -def _run_suite(suite, testclass=None): +def _run_suite(suite): """Run tests from a unittest.TestSuite-derived class.""" - if junit_xml_dir: - from junit_xml import JUnitXMLTestRunner - runner = JUnitXMLTestRunner(junit_xml_dir) - elif verbose: + if verbose: runner = unittest.TextTestRunner(sys.stdout, verbosity=2) else: runner = BasicTestRunner() @@ -469,28 +797,27 @@ elif len(result.failures) == 1 and not result.errors: err = result.failures[0][1] else: - if testclass is None: - msg = "errors occurred; run in verbose mode for details" - else: - msg = "errors occurred in %s.%s" \ - % (testclass.__module__, testclass.__name__) - raise TestFailed(msg) + err = "multiple errors occurred" + if not verbose: + err += "; run in verbose mode for details" raise TestFailed(err) def run_unittest(*classes): """Run tests from unittest.TestCase-derived classes.""" + valid_types = (unittest.TestSuite, unittest.TestCase) suite = unittest.TestSuite() for cls in classes: - if isinstance(cls, (unittest.TestSuite, unittest.TestCase)): + if isinstance(cls, str): + if cls in sys.modules: + suite.addTest(unittest.findTestCases(sys.modules[cls])) + else: + raise ValueError("str arguments must be keys in sys.modules") + elif isinstance(cls, valid_types): suite.addTest(cls) else: suite.addTest(unittest.makeSuite(cls)) - if len(classes)==1: - testclass = classes[0] - else: - testclass = None - run_suite(suite, testclass) + _run_suite(suite) #======================================================================= @@ -515,36 +842,12 @@ # output shouldn't be compared by regrtest. save_stdout = sys.stdout sys.stdout = get_original_stdout() - - if junit_xml_dir: - from junit_xml import Tee, write_doctest - save_stderr = sys.stderr - sys.stdout = stdout = Tee(sys.stdout) - sys.stderr = stderr = Tee(sys.stderr) - try: - start = time.time() - try: - f, t = doctest.testmod(module, verbose=verbosity) - except: - took = time.time() - start - if junit_xml_dir: - write_doctest(junit_xml_dir, module.__name__, took, 'error', - sys.exc_info(), stdout.getvalue(), - stderr.getvalue()) - raise - took = time.time() - start + f, t = doctest.testmod(module, verbose=verbosity) if f: - if junit_xml_dir: - write_doctest(junit_xml_dir, module.__name__, took, 'failure', - stdout=stdout.getvalue(), - stderr=stderr.getvalue()) raise TestFailed("%d of %d doctests failed" % (f, t)) finally: sys.stdout = save_stdout - if junit_xml_dir: - write_doctest(junit_xml_dir, module.__name__, took, - stdout=stdout.getvalue(), stderr=stderr.getvalue()) if verbose: print 'doctest (%s) ... %d tests with zero failures' % (module.__name__, t) return f, t @@ -554,7 +857,7 @@ def threading_setup(): import threading - return len(threading._active), 0 + return len(threading._active), len(threading._limbo) def threading_cleanup(num_active, num_limbo): import threading @@ -566,6 +869,11 @@ count += 1 time.sleep(0.1) + count = 0 + while len(threading._limbo) != num_limbo and count < _MAX_COUNT: + count += 1 + time.sleep(0.1) + def reap_children(): """Use this function at the end of test_main() whenever sub-processes are started. This will help ensure that no extra children (zombies) @@ -575,7 +883,6 @@ # Reap all our dead child processes so we don't leave zombies around. # These hog resources and might be causing some of the buildbots to die. - import os if hasattr(os, 'waitpid'): any_process = -1 while True: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fwi...@us...> - 2011-03-12 18:42:08
|
Revision: 7214 http://jython.svn.sourceforge.net/jython/?rev=7214&view=rev Author: fwierzbicki Date: 2011-03-12 18:41:56 +0000 (Sat, 12 Mar 2011) Log Message: ----------- from: http://svn.python.org/projects/python/branches/release26-maint/Lib/test/test_grammar@88766 Added Paths: ----------- trunk/jython/Lib/test/test_grammar.py Added: trunk/jython/Lib/test/test_grammar.py =================================================================== --- trunk/jython/Lib/test/test_grammar.py (rev 0) +++ trunk/jython/Lib/test/test_grammar.py 2011-03-12 18:41:56 UTC (rev 7214) @@ -0,0 +1,967 @@ +# Python test set -- part 1, grammar. +# This just tests whether the parser accepts them all. + +# NOTE: When you run this test as a script from the command line, you +# get warnings about certain hex/oct constants. Since those are +# issued by the parser, you can't suppress them by adding a +# filterwarnings() call to this module. Therefore, to shut up the +# regression test, the filterwarnings() call has been added to +# regrtest.py. + +from test.test_support import (run_unittest, check_syntax_error, + _check_py3k_warnings) +import unittest +import sys +# testing import * +from sys import * + +class TokenTests(unittest.TestCase): + + def testBackslash(self): + # Backslash means line continuation: + x = 1 \ + + 1 + self.assertEquals(x, 2, 'backslash for line continuation') + + # Backslash does not means continuation in comments :\ + x = 0 + self.assertEquals(x, 0, 'backslash ending comment') + + def testPlainIntegers(self): + self.assertEquals(0xff, 255) + self.assertEquals(0377, 255) + self.assertEquals(2147483647, 017777777777) + # "0x" is not a valid literal + self.assertRaises(SyntaxError, eval, "0x") + from sys import maxint + if maxint == 2147483647: + self.assertEquals(-2147483647-1, -020000000000) + # XXX -2147483648 + self.assert_(037777777777 > 0) + self.assert_(0xffffffff > 0) + for s in '2147483648', '040000000000', '0x100000000': + try: + x = eval(s) + except OverflowError: + self.fail("OverflowError on huge integer literal %r" % s) + elif maxint == 9223372036854775807: + self.assertEquals(-9223372036854775807-1, -01000000000000000000000) + self.assert_(01777777777777777777777 > 0) + self.assert_(0xffffffffffffffff > 0) + for s in '9223372036854775808', '02000000000000000000000', \ + '0x10000000000000000': + try: + x = eval(s) + except OverflowError: + self.fail("OverflowError on huge integer literal %r" % s) + else: + self.fail('Weird maxint value %r' % maxint) + + def testLongIntegers(self): + x = 0L + x = 0l + x = 0xffffffffffffffffL + x = 0xffffffffffffffffl + x = 077777777777777777L + x = 077777777777777777l + x = 123456789012345678901234567890L + x = 123456789012345678901234567890l + + def testFloats(self): + x = 3.14 + x = 314. + x = 0.314 + # XXX x = 000.314 + x = .314 + x = 3e14 + x = 3E14 + x = 3e-14 + x = 3e+14 + x = 3.e14 + x = .3e14 + x = 3.1e4 + + def testStringLiterals(self): + x = ''; y = ""; self.assert_(len(x) == 0 and x == y) + x = '\''; y = "'"; self.assert_(len(x) == 1 and x == y and ord(x) == 39) + x = '"'; y = "\""; self.assert_(len(x) == 1 and x == y and ord(x) == 34) + x = "doesn't \"shrink\" does it" + y = 'doesn\'t "shrink" does it' + self.assert_(len(x) == 24 and x == y) + x = "does \"shrink\" doesn't it" + y = 'does "shrink" doesn\'t it' + self.assert_(len(x) == 24 and x == y) + x = """ +The "quick" +brown fox +jumps over +the 'lazy' dog. +""" + y = '\nThe "quick"\nbrown fox\njumps over\nthe \'lazy\' dog.\n' + self.assertEquals(x, y) + y = ''' +The "quick" +brown fox +jumps over +the 'lazy' dog. +''' + self.assertEquals(x, y) + y = "\n\ +The \"quick\"\n\ +brown fox\n\ +jumps over\n\ +the 'lazy' dog.\n\ +" + self.assertEquals(x, y) + y = '\n\ +The \"quick\"\n\ +brown fox\n\ +jumps over\n\ +the \'lazy\' dog.\n\ +' + self.assertEquals(x, y) + + +class GrammarTests(unittest.TestCase): + + # single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE + # XXX can't test in a script -- this rule is only used when interactive + + # file_input: (NEWLINE | stmt)* ENDMARKER + # Being tested as this very moment this very module + + # expr_input: testlist NEWLINE + # XXX Hard to test -- used only in calls to input() + + def testEvalInput(self): + # testlist ENDMARKER + x = eval('1, 0 or 1') + + def testFuncdef(self): + ### 'def' NAME parameters ':' suite + ### parameters: '(' [varargslist] ')' + ### varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME] + ### | ('**'|'*' '*') NAME) + ### | fpdef ['=' test] (',' fpdef ['=' test])* [','] + ### fpdef: NAME | '(' fplist ')' + ### fplist: fpdef (',' fpdef)* [','] + ### arglist: (argument ',')* (argument | *' test [',' '**' test] | '**' test) + ### argument: [test '='] test # Really [keyword '='] test + def f1(): pass + f1() + f1(*()) + f1(*(), **{}) + def f2(one_argument): pass + def f3(two, arguments): pass + # Silence Py3k warning + exec('def f4(two, (compound, (argument, list))): pass') + exec('def f5((compound, first), two): pass') + self.assertEquals(f2.func_code.co_varnames, ('one_argument',)) + self.assertEquals(f3.func_code.co_varnames, ('two', 'arguments')) + if sys.platform.startswith('java'): + self.assertEquals(f4.func_code.co_varnames, + ('two', '(compound, (argument, list))', 'compound', 'argument', + 'list',)) + self.assertEquals(f5.func_code.co_varnames, + ('(compound, first)', 'two', 'compound', 'first')) + else: + self.assertEquals(f4.func_code.co_varnames, + ('two', '.1', 'compound', 'argument', 'list')) + self.assertEquals(f5.func_code.co_varnames, + ('.0', 'two', 'compound', 'first')) + def a1(one_arg,): pass + def a2(two, args,): pass + def v0(*rest): pass + def v1(a, *rest): pass + def v2(a, b, *rest): pass + # Silence Py3k warning + exec('def v3(a, (b, c), *rest): return a, b, c, rest') + + f1() + f2(1) + f2(1,) + f3(1, 2) + f3(1, 2,) + f4(1, (2, (3, 4))) + v0() + v0(1) + v0(1,) + v0(1,2) + v0(1,2,3,4,5,6,7,8,9,0) + v1(1) + v1(1,) + v1(1,2) + v1(1,2,3) + v1(1,2,3,4,5,6,7,8,9,0) + v2(1,2) + v2(1,2,3) + v2(1,2,3,4) + v2(1,2,3,4,5,6,7,8,9,0) + v3(1,(2,3)) + v3(1,(2,3),4) + v3(1,(2,3),4,5,6,7,8,9,0) + + # ceval unpacks the formal arguments into the first argcount names; + # thus, the names nested inside tuples must appear after these names. + if sys.platform.startswith('java'): + self.assertEquals(v3.func_code.co_varnames, ('a', '(b, c)', 'rest', 'b', 'c')) + else: + self.assertEquals(v3.func_code.co_varnames, ('a', '.1', 'rest', 'b', 'c')) + self.assertEquals(v3(1, (2, 3), 4), (1, 2, 3, (4,))) + def d01(a=1): pass + d01() + d01(1) + d01(*(1,)) + d01(**{'a':2}) + def d11(a, b=1): pass + d11(1) + d11(1, 2) + d11(1, **{'b':2}) + def d21(a, b, c=1): pass + d21(1, 2) + d21(1, 2, 3) + d21(*(1, 2, 3)) + d21(1, *(2, 3)) + d21(1, 2, *(3,)) + d21(1, 2, **{'c':3}) + def d02(a=1, b=2): pass + d02() + d02(1) + d02(1, 2) + d02(*(1, 2)) + d02(1, *(2,)) + d02(1, **{'b':2}) + d02(**{'a': 1, 'b': 2}) + def d12(a, b=1, c=2): pass + d12(1) + d12(1, 2) + d12(1, 2, 3) + def d22(a, b, c=1, d=2): pass + d22(1, 2) + d22(1, 2, 3) + d22(1, 2, 3, 4) + def d01v(a=1, *rest): pass + d01v() + d01v(1) + d01v(1, 2) + d01v(*(1, 2, 3, 4)) + d01v(*(1,)) + d01v(**{'a':2}) + def d11v(a, b=1, *rest): pass + d11v(1) + d11v(1, 2) + d11v(1, 2, 3) + def d21v(a, b, c=1, *rest): pass + d21v(1, 2) + d21v(1, 2, 3) + d21v(1, 2, 3, 4) + d21v(*(1, 2, 3, 4)) + d21v(1, 2, **{'c': 3}) + def d02v(a=1, b=2, *rest): pass + d02v() + d02v(1) + d02v(1, 2) + d02v(1, 2, 3) + d02v(1, *(2, 3, 4)) + d02v(**{'a': 1, 'b': 2}) + def d12v(a, b=1, c=2, *rest): pass + d12v(1) + d12v(1, 2) + d12v(1, 2, 3) + d12v(1, 2, 3, 4) + d12v(*(1, 2, 3, 4)) + d12v(1, 2, *(3, 4, 5)) + d12v(1, *(2,), **{'c': 3}) + def d22v(a, b, c=1, d=2, *rest): pass + d22v(1, 2) + d22v(1, 2, 3) + d22v(1, 2, 3, 4) + d22v(1, 2, 3, 4, 5) + d22v(*(1, 2, 3, 4)) + d22v(1, 2, *(3, 4, 5)) + d22v(1, *(2, 3), **{'d': 4}) + # Silence Py3k warning + exec('def d31v((x)): pass') + exec('def d32v((x,)): pass') + d31v(1) + d32v((1,)) + + # keyword arguments after *arglist + def f(*args, **kwargs): + return args, kwargs + self.assertEquals(f(1, x=2, *[3, 4], y=5), ((1, 3, 4), + {'x':2, 'y':5})) + self.assertRaises(SyntaxError, eval, "f(1, *(2,3), 4)") + self.assertRaises(SyntaxError, eval, "f(1, x=2, *(3,4), x=5)") + + # Check ast errors in *args and *kwargs + check_syntax_error(self, "f(*g(1=2))") + check_syntax_error(self, "f(**g(1=2))") + + def testLambdef(self): + ### lambdef: 'lambda' [varargslist] ':' test + l1 = lambda : 0 + self.assertEquals(l1(), 0) + l2 = lambda : a[d] # XXX just testing the expression + l3 = lambda : [2 < x for x in [-1, 3, 0L]] + self.assertEquals(l3(), [0, 1, 0]) + l4 = lambda x = lambda y = lambda z=1 : z : y() : x() + self.assertEquals(l4(), 1) + l5 = lambda x, y, z=2: x + y + z + self.assertEquals(l5(1, 2), 5) + self.assertEquals(l5(1, 2, 3), 6) + check_syntax_error(self, "lambda x: x = 2") + check_syntax_error(self, "lambda (None,): None") + + ### stmt: simple_stmt | compound_stmt + # Tested below + + def testSimpleStmt(self): + ### simple_stmt: small_stmt (';' small_stmt)* [';'] + x = 1; pass; del x + def foo(): + # verify statments that end with semi-colons + x = 1; pass; del x; + foo() + + ### small_stmt: expr_stmt | print_stmt | pass_stmt | del_stmt | flow_stmt | import_stmt | global_stmt | access_stmt | exec_stmt + # Tested below + + def testExprStmt(self): + # (exprlist '=')* exprlist + 1 + 1, 2, 3 + x = 1 + x = 1, 2, 3 + x = y = z = 1, 2, 3 + x, y, z = 1, 2, 3 + abc = a, b, c = x, y, z = xyz = 1, 2, (3, 4) + + check_syntax_error(self, "x + 1 = 1") + check_syntax_error(self, "a + 1 = b + 2") + + def testPrintStmt(self): + # 'print' (test ',')* [test] + import StringIO + + # Can't test printing to real stdout without comparing output + # which is not available in unittest. + save_stdout = sys.stdout + sys.stdout = StringIO.StringIO() + + print 1, 2, 3 + print 1, 2, 3, + print + print 0 or 1, 0 or 1, + print 0 or 1 + + # 'print' '>>' test ',' + print >> sys.stdout, 1, 2, 3 + print >> sys.stdout, 1, 2, 3, + print >> sys.stdout + print >> sys.stdout, 0 or 1, 0 or 1, + print >> sys.stdout, 0 or 1 + + # test printing to an instance + class Gulp: + def write(self, msg): pass + + gulp = Gulp() + print >> gulp, 1, 2, 3 + print >> gulp, 1, 2, 3, + print >> gulp + print >> gulp, 0 or 1, 0 or 1, + print >> gulp, 0 or 1 + + # test print >> None + def driver(): + oldstdout = sys.stdout + sys.stdout = Gulp() + try: + tellme(Gulp()) + tellme() + finally: + sys.stdout = oldstdout + + # we should see this once + def tellme(file=sys.stdout): + print >> file, 'hello world' + + driver() + + # we should not see this at all + def tellme(file=None): + print >> file, 'goodbye universe' + + driver() + + self.assertEqual(sys.stdout.getvalue(), '''\ +1 2 3 +1 2 3 +1 1 1 +1 2 3 +1 2 3 +1 1 1 +hello world +''') + sys.stdout = save_stdout + + # syntax errors + check_syntax_error(self, 'print ,') + check_syntax_error(self, 'print >> x,') + + def testDelStmt(self): + # 'del' exprlist + abc = [1,2,3] + x, y, z = abc + xyz = x, y, z + + del abc + del x, y, (z, xyz) + + def testPassStmt(self): + # 'pass' + pass + + # flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt + # Tested below + + def testBreakStmt(self): + # 'break' + while 1: break + + def testContinueStmt(self): + # 'continue' + i = 1 + while i: i = 0; continue + + msg = "" + while not msg: + msg = "ok" + try: + continue + msg = "continue failed to continue inside try" + except: + msg = "continue inside try called except block" + if msg != "ok": + self.fail(msg) + + msg = "" + while not msg: + msg = "finally block not called" + try: + continue + finally: + msg = "ok" + if msg != "ok": + self.fail(msg) + + def test_break_continue_loop(self): + # This test warrants an explanation. It is a test specifically for SF bugs + # #463359 and #462937. The bug is that a 'break' statement executed or + # exception raised inside a try/except inside a loop, *after* a continue + # statement has been executed in that loop, will cause the wrong number of + # arguments to be popped off the stack and the instruction pointer reset to + # a very small number (usually 0.) Because of this, the following test + # *must* written as a function, and the tracking vars *must* be function + # arguments with default values. Otherwise, the test will loop and loop. + + def test_inner(extra_burning_oil = 1, count=0): + big_hippo = 2 + while big_hippo: + count += 1 + try: + if extra_burning_oil and big_hippo == 1: + extra_burning_oil -= 1 + break + big_hippo -= 1 + continue + except: + raise + if count > 2 or big_hippo != 1: + self.fail("continue then break in try/except in loop broken!") + test_inner() + + def testReturn(self): + # 'return' [testlist] + def g1(): return + def g2(): return 1 + g1() + x = g2() + check_syntax_error(self, "class foo:return 1") + + def testYield(self): + check_syntax_error(self, "class foo:yield 1") + + def testRaise(self): + # 'raise' test [',' test] + try: raise RuntimeError, 'just testing' + except RuntimeError: pass + try: raise KeyboardInterrupt + except KeyboardInterrupt: pass + + def testImport(self): + # 'import' dotted_as_names + import sys + import time, sys + # 'from' dotted_name 'import' ('*' | '(' import_as_names ')' | import_as_names) + from time import time + from time import (time) + # not testable inside a function, but already done at top of the module + # from sys import * + from sys import path, argv + from sys import (path, argv) + from sys import (path, argv,) + + def testGlobal(self): + # 'global' NAME (',' NAME)* + global a + global a, b + global one, two, three, four, five, six, seven, eight, nine, ten + + def testExec(self): + # 'exec' expr ['in' expr [',' expr]] + z = None + del z + exec 'z=1+1\n' + if z != 2: self.fail('exec \'z=1+1\'\\n') + del z + exec 'z=1+1' + if z != 2: self.fail('exec \'z=1+1\'') + z = None + del z + import types + if hasattr(types, "UnicodeType"): + exec r"""if 1: + exec u'z=1+1\n' + if z != 2: self.fail('exec u\'z=1+1\'\\n') + del z + exec u'z=1+1' + if z != 2: self.fail('exec u\'z=1+1\'')""" + g = {} + exec 'z = 1' in g + if '__builtins__' in g: del g['__builtins__'] + if g != {'z': 1}: self.fail('exec \'z = 1\' in g') + g = {} + l = {} + + import warnings + warnings.filterwarnings("ignore", "global statement", module="<string>") + exec 'global a; a = 1; b = 2' in g, l + if '__builtins__' in g: del g['__builtins__'] + if '__builtins__' in l: del l['__builtins__'] + if (g, l) != ({'a':1}, {'b':2}): + self.fail('exec ... in g (%s), l (%s)' %(g,l)) + + def testAssert(self): + # assert_stmt: 'assert' test [',' test] + assert 1 + assert 1, 1 + assert lambda x:x + assert 1, lambda x:x+1 + try: + assert 0, "msg" + except AssertionError, e: + self.assertEquals(e.args[0], "msg") + else: + if __debug__: + self.fail("AssertionError not raised by assert 0") + + ### compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef + # Tested below + + def testIf(self): + # 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] + if 1: pass + if 1: pass + else: pass + if 0: pass + elif 0: pass + if 0: pass + elif 0: pass + elif 0: pass + elif 0: pass + else: pass + + def testWhile(self): + # 'while' test ':' suite ['else' ':' suite] + while 0: pass + while 0: pass + else: pass + + # Issue1920: "while 0" is optimized away, + # ensure that the "else" clause is still present. + x = 0 + while 0: + x = 1 + else: + x = 2 + self.assertEquals(x, 2) + + def testFor(self): + # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] + for i in 1, 2, 3: pass + for i, j, k in (): pass + else: pass + class Squares: + def __init__(self, max): + self.max = max + self.sofar = [] + def __len__(self): return len(self.sofar) + def __getitem__(self, i): + if not 0 <= i < self.max: raise IndexError + n = len(self.sofar) + while n <= i: + self.sofar.append(n*n) + n = n+1 + return self.sofar[i] + n = 0 + for x in Squares(10): n = n+x + if n != 285: + self.fail('for over growing sequence') + + result = [] + for x, in [(1,), (2,), (3,)]: + result.append(x) + self.assertEqual(result, [1, 2, 3]) + + def testTry(self): + ### try_stmt: 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite] + ### | 'try' ':' suite 'finally' ':' suite + ### except_clause: 'except' [expr [('as' | ',') expr]] + try: + 1/0 + except ZeroDivisionError: + pass + else: + pass + try: 1/0 + except EOFError: pass + except TypeError as msg: pass + except RuntimeError, msg: pass + except: pass + else: pass + try: 1/0 + except (EOFError, TypeError, ZeroDivisionError): pass + try: 1/0 + except (EOFError, TypeError, ZeroDivisionError), msg: pass + try: pass + finally: pass + + def testSuite(self): + # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT + if 1: pass + if 1: + pass + if 1: + # + # + # + pass + pass + # + pass + # + + def testTest(self): + ### and_test ('or' and_test)* + ### and_test: not_test ('and' not_test)* + ### not_test: 'not' not_test | comparison + if not 1: pass + if 1 and 1: pass + if 1 or 1: pass + if not not not 1: pass + if not 1 and 1 and 1: pass + if 1 and 1 or 1 and 1 and 1 or not 1 and 1: pass + + def testComparison(self): + ### comparison: expr (comp_op expr)* + ### comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not' + if 1: pass + x = (1 == 1) + if 1 == 1: pass + if 1 != 1: pass + if 1 < 1: pass + if 1 > 1: pass + if 1 <= 1: pass + if 1 >= 1: pass + if 1 is 1: pass + if 1 is not 1: pass + if 1 in (): pass + if 1 not in (): pass + if 1 < 1 > 1 == 1 >= 1 <= 1 != 1 in 1 not in 1 is 1 is not 1: pass + # Silence Py3k warning + if eval('1 <> 1'): pass + if eval('1 < 1 > 1 == 1 >= 1 <= 1 <> 1 != 1 in 1 not in 1 is 1 is not 1'): pass + + def testBinaryMaskOps(self): + x = 1 & 1 + x = 1 ^ 1 + x = 1 | 1 + + def testShiftOps(self): + x = 1 << 1 + x = 1 >> 1 + x = 1 << 1 >> 1 + + def testAdditiveOps(self): + x = 1 + x = 1 + 1 + x = 1 - 1 - 1 + x = 1 - 1 + 1 - 1 + 1 + + def testMultiplicativeOps(self): + x = 1 * 1 + x = 1 / 1 + x = 1 % 1 + x = 1 / 1 * 1 % 1 + + def testUnaryOps(self): + x = +1 + x = -1 + x = ~1 + x = ~1 ^ 1 & 1 | 1 & 1 ^ -1 + x = -1*1/1 + 1*1 - ---1*1 + + def testSelectors(self): + ### trailer: '(' [testlist] ')' | '[' subscript ']' | '.' NAME + ### subscript: expr | [expr] ':' [expr] + + import sys, time + c = sys.path[0] + x = time.time() + x = sys.modules['time'].time() + a = '01234' + c = a[0] + c = a[-1] + s = a[0:5] + s = a[:5] + s = a[0:] + s = a[:] + s = a[-5:] + s = a[:-1] + s = a[-4:-3] + # A rough test of SF bug 1333982. http://python.org/sf/1333982 + # The testing here is fairly incomplete. + # Test cases should include: commas with 1 and 2 colons + d = {} + d[1] = 1 + d[1,] = 2 + d[1,2] = 3 + d[1,2,3] = 4 + L = list(d) + L.sort() + self.assertEquals(str(L), '[1, (1,), (1, 2), (1, 2, 3)]') + + def testAtoms(self): + ### atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING + ### dictmaker: test ':' test (',' test ':' test)* [','] + + x = (1) + x = (1 or 2 or 3) + x = (1 or 2 or 3, 2, 3) + + x = [] + x = [1] + x = [1 or 2 or 3] + x = [1 or 2 or 3, 2, 3] + x = [] + + x = {} + x = {'one': 1} + x = {'one': 1,} + x = {'one' or 'two': 1 or 2} + x = {'one': 1, 'two': 2} + x = {'one': 1, 'two': 2,} + x = {'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6} + + # Silence Py3k warning + x = eval('`x`') + x = eval('`1 or 2 or 3`') + self.assertEqual(eval('`1,2`'), '(1, 2)') + + x = x + x = 'x' + x = 123 + + ### exprlist: expr (',' expr)* [','] + ### testlist: test (',' test)* [','] + # These have been exercised enough above + + def testClassdef(self): + # 'class' NAME ['(' [testlist] ')'] ':' suite + class B: pass + class B2(): pass + class C1(B): pass + class C2(B): pass + class D(C1, C2, B): pass + class C: + def meth1(self): pass + def meth2(self, arg): pass + def meth3(self, a1, a2): pass + # decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE + # decorators: decorator+ + # decorated: decorators (classdef | funcdef) + def class_decorator(x): + x.decorated = True + return x + @class_decorator + class G: + pass + self.assertEqual(G.decorated, True) + + def testListcomps(self): + # list comprehension tests + nums = [1, 2, 3, 4, 5] + strs = ["Apple", "Banana", "Coconut"] + spcs = [" Apple", " Banana ", "Coco nut "] + + self.assertEqual([s.strip() for s in spcs], ['Apple', 'Banana', 'Coco nut']) + self.assertEqual([3 * x for x in nums], [3, 6, 9, 12, 15]) + self.assertEqual([x for x in nums if x > 2], [3, 4, 5]) + self.assertEqual([(i, s) for i in nums for s in strs], + [(1, 'Apple'), (1, 'Banana'), (1, 'Coconut'), + (2, 'Apple'), (2, 'Banana'), (2, 'Coconut'), + (3, 'Apple'), (3, 'Banana'), (3, 'Coconut'), + (4, 'Apple'), (4, 'Banana'), (4, 'Coconut'), + (5, 'Apple'), (5, 'Banana'), (5, 'Coconut')]) + self.assertEqual([(i, s) for i in nums for s in [f for f in strs if "n" in f]], + [(1, 'Banana'), (1, 'Coconut'), (2, 'Banana'), (2, 'Coconut'), + (3, 'Banana'), (3, 'Coconut'), (4, 'Banana'), (4, 'Coconut'), + (5, 'Banana'), (5, 'Coconut')]) + self.assertEqual([(lambda a:[a**i for i in range(a+1)])(j) for j in range(5)], + [[1], [1, 1], [1, 2, 4], [1, 3, 9, 27], [1, 4, 16, 64, 256]]) + + def test_in_func(l): + return [None < x < 3 for x in l if x > 2] + + self.assertEqual(test_in_func(nums), [False, False, False]) + + def test_nested_front(): + self.assertEqual([[y for y in [x, x + 1]] for x in [1,3,5]], + [[1, 2], [3, 4], [5, 6]]) + + test_nested_front() + + check_syntax_error(self, "[i, s for i in nums for s in strs]") + check_syntax_error(self, "[x if y]") + + suppliers = [ + (1, "Boeing"), + (2, "Ford"), + (3, "Macdonalds") + ] + + parts = [ + (10, "Airliner"), + (20, "Engine"), + (30, "Cheeseburger") + ] + + suppart = [ + (1, 10), (1, 20), (2, 20), (3, 30) + ] + + x = [ + (sname, pname) + for (sno, sname) in suppliers + for (pno, pname) in parts + for (sp_sno, sp_pno) in suppart + if sno == sp_sno and pno == sp_pno + ] + + self.assertEqual(x, [('Boeing', 'Airliner'), ('Boeing', 'Engine'), ('Ford', 'Engine'), + ('Macdonalds', 'Cheeseburger')]) + + def testGenexps(self): + # generator expression tests + g = ([x for x in range(10)] for x in range(1)) + self.assertEqual(g.next(), [x for x in range(10)]) + try: + g.next() + self.fail('should produce StopIteration exception') + except StopIteration: + pass + + a = 1 + try: + g = (a for d in a) + g.next() + self.fail('should produce TypeError') + except TypeError: + pass + + self.assertEqual(list((x, y) for x in 'abcd' for y in 'abcd'), [(x, y) for x in 'abcd' for y in 'abcd']) + self.assertEqual(list((x, y) for x in 'ab' for y in 'xy'), [(x, y) for x in 'ab' for y in 'xy']) + + a = [x for x in range(10)] + b = (x for x in (y for y in a)) + self.assertEqual(sum(b), sum([x for x in range(10)])) + + self.assertEqual(sum(x**2 for x in range(10)), sum([x**2 for x in range(10)])) + self.assertEqual(sum(x*x for x in range(10) if x%2), sum([x*x for x in range(10) if x%2])) + self.assertEqual(sum(x for x in (y for y in range(10))), sum([x for x in range(10)])) + self.assertEqual(sum(x for x in (y for y in (z for z in range(10)))), sum([x for x in range(10)])) + self.assertEqual(sum(x for x in [y for y in (z for z in range(10))]), sum([x for x in range(10)])) + self.assertEqual(sum(x for x in (y for y in (z for z in range(10) if True)) if True), sum([x for x in range(10)])) + self.assertEqual(sum(x for x in (y for y in (z for z in range(10) if True) if False) if True), 0) + check_syntax_error(self, "foo(x for x in range(10), 100)") + check_syntax_error(self, "foo(100, x for x in range(10))") + + def testComprehensionSpecials(self): + # test for outmost iterable precomputation + x = 10; g = (i for i in range(x)); x = 5 + self.assertEqual(len(list(g)), 10) + + # This should hold, since we're only precomputing outmost iterable. + x = 10; t = False; g = ((i,j) for i in range(x) if t for j in range(x)) + x = 5; t = True; + self.assertEqual([(i,j) for i in range(10) for j in range(5)], list(g)) + + # Grammar allows multiple adjacent 'if's in listcomps and genexps, + # even though it's silly. Make sure it works (ifelse broke this.) + self.assertEqual([ x for x in range(10) if x % 2 if x % 3 ], [1, 5, 7]) + self.assertEqual(list(x for x in range(10) if x % 2 if x % 3), [1, 5, 7]) + + # verify unpacking single element tuples in listcomp/genexp. + self.assertEqual([x for x, in [(4,), (5,), (6,)]], [4, 5, 6]) + self.assertEqual(list(x for x, in [(7,), (8,), (9,)]), [7, 8, 9]) + + def testIfElseExpr(self): + # Test ifelse expressions in various cases + def _checkeval(msg, ret): + "helper to check that evaluation of expressions is done correctly" + print x + return ret + + self.assertEqual([ x() for x in lambda: True, lambda: False if x() ], [True]) + self.assertEqual([ x() for x in (lambda: True, lambda: False) if x() ], [True]) + self.assertEqual([ x(False) for x in (lambda x: False if x else True, lambda x: True if x else False) if x(False) ], [True]) + self.assertEqual((5 if 1 else _checkeval("check 1", 0)), 5) + self.assertEqual((_checkeval("check 2", 0) if 0 else 5), 5) + self.assertEqual((5 and 6 if 0 else 1), 1) + self.assertEqual(((5 and 6) if 0 else 1), 1) + self.assertEqual((5 and (6 if 1 else 1)), 6) + self.assertEqual((0 or _checkeval("check 3", 2) if 0 else 3), 3) + self.assertEqual((1 or _checkeval("check 4", 2) if 1 else _checkeval("check 5", 3)), 1) + self.assertEqual((0 or 5 if 1 else _checkeval("check 6", 3)), 5) + self.assertEqual((not 5 if 1 else 1), False) + self.assertEqual((not 5 if 0 else 1), 1) + self.assertEqual((6 + 1 if 1 else 2), 7) + self.assertEqual((6 - 1 if 1 else 2), 5) + self.assertEqual((6 * 2 if 1 else 4), 12) + self.assertEqual((6 / 2 if 1 else 3), 3) + self.assertEqual((6 < 4 if 0 else 2), 2) + + +def test_main(): + with _check_py3k_warnings( + ("backquote not supported", SyntaxWarning), + ("tuple parameter unpacking has been removed", SyntaxWarning), + ("parenthesized argument names are invalid", SyntaxWarning), + ("classic int division", DeprecationWarning), + (".+ not supported in 3.x", DeprecationWarning)): + run_unittest(TokenTests, GrammarTests) + +if __name__ == '__main__': + test_main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fwi...@us...> - 2011-03-12 16:58:24
|
Revision: 7213 http://jython.svn.sourceforge.net/jython/?rev=7213&view=rev Author: fwierzbicki Date: 2011-03-12 16:58:16 +0000 (Sat, 12 Mar 2011) Log Message: ----------- from: http://svn.python.org/projects/python/branches/release26-maint/Lib/robotparser.py@88766 http://svn.python.org/projects/python/branches/release26-maint/Lib/test/test_robotparser.py@88766 Added Paths: ----------- trunk/jython/Lib/robotparser.py trunk/jython/Lib/test/test_robotparser.py Added: trunk/jython/Lib/robotparser.py =================================================================== --- trunk/jython/Lib/robotparser.py (rev 0) +++ trunk/jython/Lib/robotparser.py 2011-03-12 16:58:16 UTC (rev 7213) @@ -0,0 +1,217 @@ +""" robotparser.py + + Copyright (C) 2000 Bastian Kleineidam + + You can choose between two licenses when using this package: + 1) GNU GPLv2 + 2) PSF license for Python 2.2 + + The robots.txt Exclusion Protocol is implemented as specified in + http://info.webcrawler.com/mak/projects/robots/norobots-rfc.html +""" +import urlparse +import urllib + +__all__ = ["RobotFileParser"] + + +class RobotFileParser: + """ This class provides a set of methods to read, parse and answer + questions about a single robots.txt file. + + """ + + def __init__(self, url=''): + self.entries = [] + self.default_entry = None + self.disallow_all = False + self.allow_all = False + self.set_url(url) + self.last_checked = 0 + + def mtime(self): + """Returns the time the robots.txt file was last fetched. + + This is useful for long-running web spiders that need to + check for new robots.txt files periodically. + + """ + return self.last_checked + + def modified(self): + """Sets the time the robots.txt file was last fetched to the + current time. + + """ + import time + self.last_checked = time.time() + + def set_url(self, url): + """Sets the URL referring to a robots.txt file.""" + self.url = url + self.host, self.path = urlparse.urlparse(url)[1:3] + + def read(self): + """Reads the robots.txt URL and feeds it to the parser.""" + opener = URLopener() + f = opener.open(self.url) + lines = [line.strip() for line in f] + f.close() + self.errcode = opener.errcode + if self.errcode in (401, 403): + self.disallow_all = True + elif self.errcode >= 400: + self.allow_all = True + elif self.errcode == 200 and lines: + self.parse(lines) + + def _add_entry(self, entry): + if "*" in entry.useragents: + # the default entry is considered last + if self.default_entry is None: + # the first default entry wins + self.default_entry = entry + else: + self.entries.append(entry) + + def parse(self, lines): + """parse the input lines from a robots.txt file. + We allow that a user-agent: line is not preceded by + one or more blank lines.""" + # states: + # 0: start state + # 1: saw user-agent line + # 2: saw an allow or disallow line + state = 0 + linenumber = 0 + entry = Entry() + + for line in lines: + linenumber += 1 + if not line: + if state == 1: + entry = Entry() + state = 0 + elif state == 2: + self._add_entry(entry) + entry = Entry() + state = 0 + # remove optional comment and strip line + i = line.find('#') + if i >= 0: + line = line[:i] + line = line.strip() + if not line: + continue + line = line.split(':', 1) + if len(line) == 2: + line[0] = line[0].strip().lower() + line[1] = urllib.unquote(line[1].strip()) + if line[0] == "user-agent": + if state == 2: + self._add_entry(entry) + entry = Entry() + entry.useragents.append(line[1]) + state = 1 + elif line[0] == "disallow": + if state != 0: + entry.rulelines.append(RuleLine(line[1], False)) + state = 2 + elif line[0] == "allow": + if state != 0: + entry.rulelines.append(RuleLine(line[1], True)) + state = 2 + if state == 2: + self._add_entry(entry) + + + def can_fetch(self, useragent, url): + """using the parsed robots.txt decide if useragent can fetch url""" + if self.disallow_all: + return False + if self.allow_all: + return True + # search for given user agent matches + # the first match counts + url = urllib.quote(urlparse.urlparse(urllib.unquote(url))[2]) or "/" + for entry in self.entries: + if entry.applies_to(useragent): + return entry.allowance(url) + # try the default entry last + if self.default_entry: + return self.default_entry.allowance(url) + # agent not found ==> access granted + return True + + + def __str__(self): + return ''.join([str(entry) + "\n" for entry in self.entries]) + + +class RuleLine: + """A rule line is a single "Allow:" (allowance==True) or "Disallow:" + (allowance==False) followed by a path.""" + def __init__(self, path, allowance): + if path == '' and not allowance: + # an empty value means allow all + allowance = True + self.path = urllib.quote(path) + self.allowance = allowance + + def applies_to(self, filename): + return self.path == "*" or filename.startswith(self.path) + + def __str__(self): + return (self.allowance and "Allow" or "Disallow") + ": " + self.path + + +class Entry: + """An entry has one or more user-agents and zero or more rulelines""" + def __init__(self): + self.useragents = [] + self.rulelines = [] + + def __str__(self): + ret = [] + for agent in self.useragents: + ret.extend(["User-agent: ", agent, "\n"]) + for line in self.rulelines: + ret.extend([str(line), "\n"]) + return ''.join(ret) + + def applies_to(self, useragent): + """check if this entry applies to the specified agent""" + # split the name token and make it lower case + useragent = useragent.split("/")[0].lower() + for agent in self.useragents: + if agent == '*': + # we have the catch-all agent + return True + agent = agent.lower() + if agent in useragent: + return True + return False + + def allowance(self, filename): + """Preconditions: + - our agent applies to this entry + - filename is URL decoded""" + for line in self.rulelines: + if line.applies_to(filename): + return line.allowance + return True + +class URLopener(urllib.FancyURLopener): + def __init__(self, *args): + urllib.FancyURLopener.__init__(self, *args) + self.errcode = 200 + + def prompt_user_passwd(self, host, realm): + ## If robots.txt file is accessible only with a password, + ## we act as if the file wasn't there. + return None, None + + def http_error_default(self, url, fp, errcode, errmsg, headers): + self.errcode = errcode + return urllib.FancyURLopener.http_error_default(self, url, fp, errcode, + errmsg, headers) Added: trunk/jython/Lib/test/test_robotparser.py =================================================================== --- trunk/jython/Lib/test/test_robotparser.py (rev 0) +++ trunk/jython/Lib/test/test_robotparser.py 2011-03-12 16:58:16 UTC (rev 7213) @@ -0,0 +1,236 @@ +import unittest, StringIO, robotparser +from test import test_support + +class RobotTestCase(unittest.TestCase): + def __init__(self, index, parser, url, good, agent): + unittest.TestCase.__init__(self) + if good: + self.str = "RobotTest(%d, good, %s)" % (index, url) + else: + self.str = "RobotTest(%d, bad, %s)" % (index, url) + self.parser = parser + self.url = url + self.good = good + self.agent = agent + + def runTest(self): + if isinstance(self.url, tuple): + agent, url = self.url + else: + url = self.url + agent = self.agent + if self.good: + self.failUnless(self.parser.can_fetch(agent, url)) + else: + self.failIf(self.parser.can_fetch(agent, url)) + + def __str__(self): + return self.str + +tests = unittest.TestSuite() + +def RobotTest(index, robots_txt, good_urls, bad_urls, + agent="test_robotparser"): + + lines = StringIO.StringIO(robots_txt).readlines() + parser = robotparser.RobotFileParser() + parser.parse(lines) + for url in good_urls: + tests.addTest(RobotTestCase(index, parser, url, 1, agent)) + for url in bad_urls: + tests.addTest(RobotTestCase(index, parser, url, 0, agent)) + +# Examples from http://www.robotstxt.org/wc/norobots.html (fetched 2002) + +# 1. +doc = """ +User-agent: * +Disallow: /cyberworld/map/ # This is an infinite virtual URL space +Disallow: /tmp/ # these will soon disappear +Disallow: /foo.html +""" + +good = ['/','/test.html'] +bad = ['/cyberworld/map/index.html','/tmp/xxx','/foo.html'] + +RobotTest(1, doc, good, bad) + +# 2. +doc = """ +# robots.txt for http://www.example.com/ + +User-agent: * +Disallow: /cyberworld/map/ # This is an infinite virtual URL space + +# Cybermapper knows where to go. +User-agent: cybermapper +Disallow: + +""" + +good = ['/','/test.html',('cybermapper','/cyberworld/map/index.html')] +bad = ['/cyberworld/map/index.html'] + +RobotTest(2, doc, good, bad) + +# 3. +doc = """ +# go away +User-agent: * +Disallow: / +""" + +good = [] +bad = ['/cyberworld/map/index.html','/','/tmp/'] + +RobotTest(3, doc, good, bad) + +# Examples from http://www.robotstxt.org/wc/norobots-rfc.html (fetched 2002) + +# 4. +doc = """ +User-agent: figtree +Disallow: /tmp +Disallow: /a%3cd.html +Disallow: /a%2fb.html +Disallow: /%7ejoe/index.html +""" + +good = [] # XFAIL '/a/b.html' +bad = ['/tmp','/tmp.html','/tmp/a.html', + '/a%3cd.html','/a%3Cd.html','/a%2fb.html', + '/~joe/index.html' + ] + +RobotTest(4, doc, good, bad, 'figtree') +RobotTest(5, doc, good, bad, 'FigTree Robot libwww-perl/5.04') + +# 6. +doc = """ +User-agent: * +Disallow: /tmp/ +Disallow: /a%3Cd.html +Disallow: /a/b.html +Disallow: /%7ejoe/index.html +""" + +good = ['/tmp',] # XFAIL: '/a%2fb.html' +bad = ['/tmp/','/tmp/a.html', + '/a%3cd.html','/a%3Cd.html',"/a/b.html", + '/%7Ejoe/index.html'] + +RobotTest(6, doc, good, bad) + +# From bug report #523041 + +# 7. +doc = """ +User-Agent: * +Disallow: /. +""" + +good = ['/foo.html'] +bad = [] # Bug report says "/" should be denied, but that is not in the RFC + +RobotTest(7, doc, good, bad) + +# From Google: http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=40364 + +# 8. +doc = """ +User-agent: Googlebot +Allow: /folder1/myfile.html +Disallow: /folder1/ +""" + +good = ['/folder1/myfile.html'] +bad = ['/folder1/anotherfile.html'] + +RobotTest(8, doc, good, bad, agent="Googlebot") + +# 9. This file is incorrect because "Googlebot" is a substring of +# "Googlebot-Mobile", so test 10 works just like test 9. +doc = """ +User-agent: Googlebot +Disallow: / + +User-agent: Googlebot-Mobile +Allow: / +""" + +good = [] +bad = ['/something.jpg'] + +RobotTest(9, doc, good, bad, agent="Googlebot") + +good = [] +bad = ['/something.jpg'] + +RobotTest(10, doc, good, bad, agent="Googlebot-Mobile") + +# 11. Get the order correct. +doc = """ +User-agent: Googlebot-Mobile +Allow: / + +User-agent: Googlebot +Disallow: / +""" + +good = [] +bad = ['/something.jpg'] + +RobotTest(11, doc, good, bad, agent="Googlebot") + +good = ['/something.jpg'] +bad = [] + +RobotTest(12, doc, good, bad, agent="Googlebot-Mobile") + + +# 13. Google also got the order wrong in #8. You need to specify the +# URLs from more specific to more general. +doc = """ +User-agent: Googlebot +Allow: /folder1/myfile.html +Disallow: /folder1/ +""" + +good = ['/folder1/myfile.html'] +bad = ['/folder1/anotherfile.html'] + +RobotTest(13, doc, good, bad, agent="googlebot") + + +# 14. For issue #4108 (obey first * entry) +doc = """ +User-agent: * +Disallow: /some/path + +User-agent: * +Disallow: /another/path +""" + +good = ['/another/path'] +bad = ['/some/path'] + +RobotTest(14, doc, good, bad) + + +class TestCase(unittest.TestCase): + def runTest(self): + test_support.requires('network') + # whole site is password-protected. + url = 'http://mueblesmoraleda.com' + parser = robotparser.RobotFileParser() + parser.set_url(url) + parser.read() + self.assertEqual(parser.can_fetch("*", url+"/robots.txt"), False) + +def test_main(): + test_support.run_unittest(tests) + TestCase().run() + +if __name__=='__main__': + test_support.verbose = 1 + test_main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2011-03-11 23:28:44
|
Revision: 7212 http://jython.svn.sourceforge.net/jython/?rev=7212&view=rev Author: pjenvey Date: 2011-03-11 23:28:37 +0000 (Fri, 11 Mar 2011) Log Message: ----------- Merged revisions 7210 via svnmerge from https://jython.svn.sourceforge.net/svnroot/jython/trunk ........ r7210 | pjenvey | 2011-03-11 16:23:50 -0500 (Fri, 11 Mar 2011) | 2 lines skip these on our older FreeBSD 6.2 buildbot as it has spotty IPV6 support ........ Modified Paths: -------------- branches/Release_2_5maint/jython/Lib/test/test_socket.py Property Changed: ---------------- branches/Release_2_5maint/ branches/Release_2_5maint/jython/ Property changes on: branches/Release_2_5maint ___________________________________________________________________ Modified: svnmerge-integrated - /trunk:1-7207 + /trunk:1-7207,7210 Added: svn:mergeinfo + /trunk:7210 Property changes on: branches/Release_2_5maint/jython ___________________________________________________________________ Modified: svn:mergeinfo - /branches/jsr223:6285-6565 /branches/newstyle-java-types:5564-5663,5666-5729 + /branches/jsr223:6285-6565 /branches/newstyle-java-types:5564-5663,5666-5729 /trunk/jython:7210 Modified: branches/Release_2_5maint/jython/Lib/test/test_socket.py =================================================================== --- branches/Release_2_5maint/jython/Lib/test/test_socket.py 2011-03-11 23:22:38 UTC (rev 7211) +++ branches/Release_2_5maint/jython/Lib/test/test_socket.py 2011-03-11 23:28:37 UTC (rev 7212) @@ -1510,7 +1510,12 @@ self.failUnlessEqual(str(ipv4_address_tuple), "('127.0.0.1', 80)") self.failUnlessEqual(repr(ipv4_address_tuple), "('127.0.0.1', 80)") - ipv6_address_tuple = socket.getaddrinfo("localhost", 80, socket.AF_INET6, socket.SOCK_STREAM, 0, 0)[0][4] + addrinfo = socket.getaddrinfo("localhost", 80, socket.AF_INET6, socket.SOCK_STREAM, 0, 0) + if not addrinfo and is_bsd: + # older FreeBSDs may have spotty IPV6 Java support (at least + # our FreeBSD 6.2 buildbot does) + return + ipv6_address_tuple = addrinfo[0][4] self.failUnless (ipv6_address_tuple[0] in ["::1", "0:0:0:0:0:0:0:1"]) self.failUnlessEqual(ipv6_address_tuple[1], 80) self.failUnlessEqual(ipv6_address_tuple[2], 0) @@ -1536,7 +1541,11 @@ self.failUnlessEqual(sockaddr.port, 80) def testIPV6AddressesFromGetAddrInfo(self): - local_addr = socket.getaddrinfo("localhost", 80, socket.AF_INET6, socket.SOCK_STREAM, 0, 0)[0][4] + addrinfo = socket.getaddrinfo("localhost", 80, socket.AF_INET6, socket.SOCK_STREAM, 0, 0) + if not addrinfo and is_bsd: + # older FreeBSDs may have spotty IPV6 Java support + return + local_addr = addrinfo[0][4] sockaddr = socket._get_jsockaddr(local_addr) self.failUnless(isinstance(sockaddr, java.net.InetSocketAddress), "_get_jsockaddr returned wrong type: '%s'" % str(type(sockaddr))) self.failUnless(sockaddr.address.hostAddress in ["::1", "0:0:0:0:0:0:0:1"]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2011-03-11 23:22:44
|
Revision: 7211 http://jython.svn.sourceforge.net/jython/?rev=7211&view=rev Author: pjenvey Date: 2011-03-11 23:22:38 +0000 (Fri, 11 Mar 2011) Log Message: ----------- Initialized merge tracking via "svnmerge" with revisions "1-7207" from https://jython.svn.sourceforge.net/svnroot/jython/trunk Property Changed: ---------------- branches/Release_2_5maint/ Property changes on: branches/Release_2_5maint ___________________________________________________________________ Added: svnmerge-integrated + /trunk:1-7207 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2011-03-11 21:23:58
|
Revision: 7210 http://jython.svn.sourceforge.net/jython/?rev=7210&view=rev Author: pjenvey Date: 2011-03-11 21:23:50 +0000 (Fri, 11 Mar 2011) Log Message: ----------- skip these on our older FreeBSD 6.2 buildbot as it has spotty IPV6 support Modified Paths: -------------- trunk/jython/Lib/test/test_socket.py Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2011-03-11 20:40:07 UTC (rev 7209) +++ trunk/jython/Lib/test/test_socket.py 2011-03-11 21:23:50 UTC (rev 7210) @@ -1510,7 +1510,12 @@ self.failUnlessEqual(str(ipv4_address_tuple), "('127.0.0.1', 80)") self.failUnlessEqual(repr(ipv4_address_tuple), "('127.0.0.1', 80)") - ipv6_address_tuple = socket.getaddrinfo("localhost", 80, socket.AF_INET6, socket.SOCK_STREAM, 0, 0)[0][4] + addrinfo = socket.getaddrinfo("localhost", 80, socket.AF_INET6, socket.SOCK_STREAM, 0, 0) + if not addrinfo and is_bsd: + # older FreeBSDs may have spotty IPV6 Java support (at least + # our FreeBSD 6.2 buildbot does) + return + ipv6_address_tuple = addrinfo[0][4] self.failUnless (ipv6_address_tuple[0] in ["::1", "0:0:0:0:0:0:0:1"]) self.failUnlessEqual(ipv6_address_tuple[1], 80) self.failUnlessEqual(ipv6_address_tuple[2], 0) @@ -1536,7 +1541,11 @@ self.failUnlessEqual(sockaddr.port, 80) def testIPV6AddressesFromGetAddrInfo(self): - local_addr = socket.getaddrinfo("localhost", 80, socket.AF_INET6, socket.SOCK_STREAM, 0, 0)[0][4] + addrinfo = socket.getaddrinfo("localhost", 80, socket.AF_INET6, socket.SOCK_STREAM, 0, 0) + if not addrinfo and is_bsd: + # older FreeBSDs may have spotty IPV6 Java support + return + local_addr = addrinfo[0][4] sockaddr = socket._get_jsockaddr(local_addr) self.failUnless(isinstance(sockaddr, java.net.InetSocketAddress), "_get_jsockaddr returned wrong type: '%s'" % str(type(sockaddr))) self.failUnless(sockaddr.address.hostAddress in ["::1", "0:0:0:0:0:0:0:1"]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2011-03-11 20:40:13
|
Revision: 7209 http://jython.svn.sourceforge.net/jython/?rev=7209&view=rev Author: pjenvey Date: 2011-03-11 20:40:07 +0000 (Fri, 11 Mar 2011) Log Message: ----------- bump version to 2.6 Modified Paths: -------------- trunk/jython/build.xml Modified: trunk/jython/build.xml =================================================================== --- trunk/jython/build.xml 2011-03-11 20:24:05 UTC (rev 7208) +++ trunk/jython/build.xml 2011-03-11 20:40:07 UTC (rev 7209) @@ -123,12 +123,12 @@ <property name="PY_RELEASE_LEVEL_SNAPSHOT" value="170"/> <!-- 0xAA --> <!-- The current version info --> - <property name="jython.version" value="2.5.2"/> - <property name="jython.version.noplus" value="2.5.2"/> + <property name="jython.version" value="2.6a0+"/> + <property name="jython.version.noplus" value="2.6a0"/> <property name="jython.major_version" value="2"/> - <property name="jython.minor_version" value="5"/> - <property name="jython.micro_version" value="2"/> - <property name="jython.release_level" value="${PY_RELEASE_LEVEL_FINAL}"/> + <property name="jython.minor_version" value="6"/> + <property name="jython.micro_version" value="0"/> + <property name="jython.release_level" value="${PY_RELEASE_LEVEL_ALPHA}"/> <property name="jython.release_serial" value="0"/> <condition property="do.snapshot.build"> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2011-03-11 20:24:11
|
Revision: 7208 http://jython.svn.sourceforge.net/jython/?rev=7208&view=rev Author: pjenvey Date: 2011-03-11 20:24:05 +0000 (Fri, 11 Mar 2011) Log Message: ----------- create a 2.5 maintenance branch Added Paths: ----------- branches/Release_2_5maint/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <otm...@us...> - 2011-03-02 23:25:26
|
Revision: 7207 http://jython.svn.sourceforge.net/jython/?rev=7207&view=rev Author: otmarhumbel Date: 2011-03-02 23:25:20 +0000 (Wed, 02 Mar 2011) Log Message: ----------- website preparation for 2.5.2 final Modified Paths: -------------- trunk/website/index.txt trunk/website/jysite.py trunk/website/redirects/constants.txt trunk/website/redirects/downloads.txt trunk/website/redirects/latest.txt Modified: trunk/website/index.txt =================================================================== --- trunk/website/index.txt 2011-03-02 21:54:23 UTC (rev 7206) +++ trunk/website/index.txt 2011-03-02 23:25:20 UTC (rev 7207) @@ -4,11 +4,14 @@ Latest News ~~~~~~~~~~~ +**Jython 2.5.2 Has Been Released** (March 3, 2011) + +The Jython development team is proud to announce the final 2.5.2 release! For a complete listing of changes, please visit the `Release Notes`_. + **Jython 2.5.2 RC 4 Has Been Released** (February 15, 2011) The Jython development team would like to announce the release of 2.5.2 Release Candidate 4. For a complete listing of changes, please visit the `Release Notes`_. - **Jython 2.5.2 RC 3 Has Been Released** (January 11, 2011) The Jython development team would like to announce the release of 2.5.2 Release Candidate 3. For a complete listing of changes, please visit the `Release Notes`_. @@ -102,7 +105,7 @@ .. _this post: http://blog.springpython.webfactional.com/2009/10/15/see-how-spring-python-works-with-jython/ .. _Release Notes: http://www.jython.org/latest.html .. _the bug tracker: http://bugs.jython.org -.. _download the installer by clicking here: http://sourceforge.net/projects/jython/files/jython-dev/2.5.2rc4/jython_installer-2.5.2rc4.jar/download +.. _download the installer by clicking here: http://sourceforge.net/projects/jython/files/jython/2.5.2/jython_installer-2.5.2.jar/download Modified: trunk/website/jysite.py =================================================================== --- trunk/website/jysite.py 2011-03-02 21:54:23 UTC (rev 7206) +++ trunk/website/jysite.py 2011-03-02 23:25:20 UTC (rev 7207) @@ -80,9 +80,9 @@ buffer.append('<a href="./" ><img class="logoImage" alt="Jython" style="border: 0px; padding-top: 20px; position:absolute; left: 35px" src="css/jython.png" title="Jython"></a>') buffer.append('</div>') buffer.append('<div class="latest_release" style="position:absolute; color:#000; width:180px; top: 15px; right: 30px; padding:0px 10px 10px 30px; font-size:11px; background:url(\'css/latest_release_bg.png\') no-repeat">') - buffer.append('<p style="top: 25px; color:#000">Latest release - 2.5.2 - RC 4<br/>') + buffer.append('<p style="top: 25px; color:#000">Latest release - 2.5.2<br/>') buffer.append('<a style="color:#000" href="latest.html">View Release Notes</a><br/>') - buffer.append('Download: <a style="color:#000" href="http://sourceforge.net/projects/jython/files/jython-dev/2.5.2rc4/jython_installer-2.5.2rc4.jar/download">.jar</a>') + buffer.append('Download: <a style="color:#000" href="http://sourceforge.net/projects/jython/files/jython/2.5.2/jython_installer-2.5.2.jar/download">.jar</a>') buffer.append('</div>') buffer.append('<div class="searchbox">') Modified: trunk/website/redirects/constants.txt =================================================================== --- trunk/website/redirects/constants.txt 2011-03-02 21:54:23 UTC (rev 7206) +++ trunk/website/redirects/constants.txt 2011-03-02 23:25:20 UTC (rev 7207) @@ -1,3 +1,3 @@ -.. |stable.installer.jar| replace:: jython_installer-2.2.1.jar +.. |stable.installer.jar| replace:: jython_installer-2.5.2.jar -.. _stable.download: http://downloads.sourceforge.net/jython/jython_installer-2.2.1.jar +.. _stable.download: http://sourceforge.net/projects/jython/files/jython/2.5.2/jython_installer-2.5.2.jar/download Modified: trunk/website/redirects/downloads.txt =================================================================== --- trunk/website/redirects/downloads.txt 2011-03-02 21:54:23 UTC (rev 7206) +++ trunk/website/redirects/downloads.txt 2011-03-02 23:25:20 UTC (rev 7207) @@ -1,14 +1,15 @@ Downloads --------- -The current version of Jython is 2.5.2 - Release Candidate 4, please use the link below to download the Java installer. +The current version of Jython is 2.5.2. +Please use the link below to download the Java installer. Once downloaded, please double-click on the JAR file to start the installation process. You may also want to read the `Installation instructions`_ or the `Release Notes`_. -`Download Jython 2.5.2`_ RC 4 +`Download Jython 2.5.2`_ -- MD5: ``63967bbbd53f8e60c860aa1b11cf3cb8`` -- SHA1: ``3b20e32bbdbe4dc8a4e3b49d173af897e1ee9cb0`` +- MD5: ``7c7d9abd8985df480edeacd27ed9dcd5`` +- SHA1: ``d4534a691edf40aa1d51723dfe3e22db1e39b432`` Previous Releases ----------------- @@ -28,7 +29,7 @@ - MD5: ``774543534bef2d68247953882237d448`` - SHA1: ``6fea1e8985af955fc843789e2d60fcfc38a76fd8`` -.. _Download Jython 2.5.2: http://sourceforge.net/projects/jython/files/jython-dev/2.5.2rc4/jython_installer-2.5.2rc4.jar/download +.. _Download Jython 2.5.2: http://sourceforge.net/projects/jython/files/jython/2.5.2/jython_installer-2.5.2.jar/download .. _Jython 2.5.1: http://sourceforge.net/projects/jython/files/jython/2.5.1/jython_installer-2.5.1.jar/download .. _Jython 2.5.0: http://sourceforge.net/projects/jython/files/jython/2.5.0/jython_installer-2.5.0.jar/download .. _Jython 2.2.1: http://sourceforge.net/projects/jython/files/jython/jython_installer-2.2.1.jar Modified: trunk/website/redirects/latest.txt =================================================================== --- trunk/website/redirects/latest.txt 2011-03-02 21:54:23 UTC (rev 7206) +++ trunk/website/redirects/latest.txt 2011-03-02 23:25:20 UTC (rev 7207) @@ -3,6 +3,19 @@ The following features have been added and bugs have been repaired for 2.5.2. For a look at the complete roadmap for Jython along with links for the PEPs and other information, please look at the `roadmap`_: +New Features +------------ + - The socket module now includes ipv6 support + - The socket module now also includes Internationalized Domain Names (RFC 3490) support on Java 6 + - Performance improvements around method invocation. 2.5.2 runs the richards benchmark 3x faster and the pystone benchmark 20% faster than 2.5.1 + - The posix/nt module was rewritten in Java and the performance of its often performance-critical stat function has significantly improved + - Improved OSError errno messages on Windows + - Slightly improved startup time (ongoing Issue #1380) + - Better readline module emulation (required for IPython support) + - Python functions can be directly passed to Java methods that take a single method interface (such as Callable or Runnable) + - Add google indexer (by Yin Wang and Steve Yegge) + + Bugs Fixed ---------- This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <otm...@us...> - 2011-03-02 21:54:29
|
Revision: 7206 http://jython.svn.sourceforge.net/jython/?rev=7206&view=rev Author: otmarhumbel Date: 2011-03-02 21:54:23 +0000 (Wed, 02 Mar 2011) Log Message: ----------- more news updates for 2.5.2 final (thanks to pjenvey) Modified Paths: -------------- tags/Release_2_5_2/jython/NEWS Modified: tags/Release_2_5_2/jython/NEWS =================================================================== --- tags/Release_2_5_2/jython/NEWS 2011-03-02 20:15:14 UTC (rev 7205) +++ tags/Release_2_5_2/jython/NEWS 2011-03-02 21:54:23 UTC (rev 7206) @@ -11,6 +11,10 @@ - [ 1210 ] Lib/socket.py doesn't allow IPv6 sockets and fails with an AssertionError - [ 1700 ] "virtualenv is not compatible" to 2.5.2rc3 - [ 1701 ] Files are not flushed properly when opened from the EDT (partial fix) + New Features + - The socket module now includes ipv6 support + - The socket module now also includes Internationalized Domain + Names (RFC 3490) support on Java 6 Jython 2.5.2rc3 Bugs Fixed @@ -153,9 +157,19 @@ during Django or Pylons development mode reloading) - Fix pickling of collections.defaultdict objects - Fix the cmath module to accept objects implementing the __float__ method - - Add google indexer (by Yin Wang and Steve Yegge) + New Features + - Performance improvements around method invocation. 2.5.2 runs + the richards benchmark 3x faster and the pystone benchmark 20% + faster than 2.5.1 + - The posix/nt module was rewritten in Java and the performance of + its often performance-critical stat function has significantly + improved + - Improved OSError errno messages on Windows + - Slightly improved startup time (ongoing Issue #1380) + - better readline module emulation (required for IPython support) - Python functions can be directly passed to Java methods that take a single method interface (such as Callable or Runnable) + - Add google indexer (by Yin Wang and Steve Yegge) Jython 2.5.1rc3 Bugs Fixed This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2011-03-02 20:15:20
|
Revision: 7205 http://jython.svn.sourceforge.net/jython/?rev=7205&view=rev Author: pjenvey Date: 2011-03-02 20:15:14 +0000 (Wed, 02 Mar 2011) Log Message: ----------- more news updates for 2.5.2 final Modified Paths: -------------- trunk/jython/NEWS Modified: trunk/jython/NEWS =================================================================== --- trunk/jython/NEWS 2011-03-01 22:03:18 UTC (rev 7204) +++ trunk/jython/NEWS 2011-03-02 20:15:14 UTC (rev 7205) @@ -11,6 +11,10 @@ - [ 1210 ] Lib/socket.py doesn't allow IPv6 sockets and fails with an AssertionError - [ 1700 ] "virtualenv is not compatible" to 2.5.2rc3 - [ 1701 ] Files are not flushed properly when opened from the EDT (partial fix) + New Features + - The socket module now includes ipv6 support + - The socket module now also includes Internationalized Domain + Names (RFC 3490) support on Java 6 Jython 2.5.2rc3 Bugs Fixed @@ -153,9 +157,19 @@ during Django or Pylons development mode reloading) - Fix pickling of collections.defaultdict objects - Fix the cmath module to accept objects implementing the __float__ method - - Add google indexer (by Yin Wang and Steve Yegge) + New Features + - Performance improvements around method invocation. 2.5.2 runs + the richards benchmark 3x faster and the pystone benchmark 20% + faster than 2.5.1 + - The posix/nt module was rewritten in Java and the performance of + its often performance-critical stat function has significantly + improved + - Improved OSError errno messages on Windows + - Slightly improved startup time (ongoing Issue #1380) + - better readline module emulation (required for IPython support) - Python functions can be directly passed to Java methods that take a single method interface (such as Callable or Runnable) + - Add google indexer (by Yin Wang and Steve Yegge) Jython 2.5.1rc3 Bugs Fixed This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <otm...@us...> - 2011-03-01 22:03:24
|
Revision: 7204 http://jython.svn.sourceforge.net/jython/?rev=7204&view=rev Author: otmarhumbel Date: 2011-03-01 22:03:18 +0000 (Tue, 01 Mar 2011) Log Message: ----------- tagging 2.5.2 final Added Paths: ----------- tags/Release_2_5_2/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <otm...@us...> - 2011-03-01 21:54:19
|
Revision: 7203 http://jython.svn.sourceforge.net/jython/?rev=7203&view=rev Author: otmarhumbel Date: 2011-03-01 21:54:13 +0000 (Tue, 01 Mar 2011) Log Message: ----------- prepare for 2.5.2 final Modified Paths: -------------- trunk/jython/NEWS trunk/jython/README.txt trunk/jython/build.xml Modified: trunk/jython/NEWS =================================================================== --- trunk/jython/NEWS 2011-02-15 21:39:44 UTC (rev 7202) +++ trunk/jython/NEWS 2011-03-01 21:54:13 UTC (rev 7203) @@ -1,5 +1,8 @@ Jython NEWS +Jython 2.5.2 + same as 2.5.2rc4 + Jython 2.5.2rc4 Bugs Fixed - [ 1667 ] thread.local subclasses with constructor params fail Modified: trunk/jython/README.txt =================================================================== --- trunk/jython/README.txt 2011-02-15 21:39:44 UTC (rev 7202) +++ trunk/jython/README.txt 2011-03-01 21:54:13 UTC (rev 7203) @@ -1,9 +1,8 @@ -Welcome to Jython 2.5.2 rc4 -=========================== +Welcome to Jython 2.5.2 +======================= -This is the fourth release candidate of the 2.5.2 version of Jython. -It contains the fixes of the blocker bugs since 2.5.2 rc3. -We still believe that this is the last release candidate before the final 2.5.2 release! +This is the final 2.5.2 release of Jython. +It contains the fixes of the blocker bugs since 2.5.2 release candidate 3. This release fixes bugs related to resource leaks, Java integration, and a number of other issues. See the NEWS file for more details. In Modified: trunk/jython/build.xml =================================================================== --- trunk/jython/build.xml 2011-02-15 21:39:44 UTC (rev 7202) +++ trunk/jython/build.xml 2011-03-01 21:54:13 UTC (rev 7203) @@ -123,13 +123,13 @@ <property name="PY_RELEASE_LEVEL_SNAPSHOT" value="170"/> <!-- 0xAA --> <!-- The current version info --> - <property name="jython.version" value="2.5.2rc4"/> - <property name="jython.version.noplus" value="2.5.2rc4"/> + <property name="jython.version" value="2.5.2"/> + <property name="jython.version.noplus" value="2.5.2"/> <property name="jython.major_version" value="2"/> <property name="jython.minor_version" value="5"/> <property name="jython.micro_version" value="2"/> - <property name="jython.release_level" value="${PY_RELEASE_LEVEL_GAMMA}"/> - <property name="jython.release_serial" value="4"/> + <property name="jython.release_level" value="${PY_RELEASE_LEVEL_FINAL}"/> + <property name="jython.release_serial" value="0"/> <condition property="do.snapshot.build"> <isset property="snapshot.revision" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2011-02-15 21:39:51
|
Revision: 7202 http://jython.svn.sourceforge.net/jython/?rev=7202&view=rev Author: amak Date: 2011-02-15 21:39:44 +0000 (Tue, 15 Feb 2011) Log Message: ----------- Some simple docstring and line-endings changes Modified Paths: -------------- trunk/jython/Lib/select.py trunk/jython/Lib/socket.py Modified: trunk/jython/Lib/select.py =================================================================== --- trunk/jython/Lib/select.py 2011-02-14 23:40:19 UTC (rev 7201) +++ trunk/jython/Lib/select.py 2011-02-15 21:39:44 UTC (rev 7202) @@ -1,260 +1,262 @@ -""" -AMAK: 20070515: New select implementation that uses java.nio -""" - -import java.nio.channels.SelectableChannel -import java.nio.channels.SelectionKey -import java.nio.channels.Selector -from java.nio.channels.SelectionKey import OP_ACCEPT, OP_CONNECT, OP_WRITE, OP_READ - -import errno -import os -import Queue -import socket - -class error(Exception): pass - -ALL = None - -_exception_map = { - -# (<javaexception>, <circumstance>) : lambda: <code that raises the python equivalent> - -(java.nio.channels.IllegalBlockingModeException, ALL) : error(errno.ESOCKISBLOCKING, 'socket must be in non-blocking mode'), -} - -def _map_exception(exc, circumstance=ALL): - try: - mapped_exception = _exception_map[(exc.__class__, circumstance)] - mapped_exception.java_exception = exc - return mapped_exception - except KeyError: - return error(-1, 'Unmapped java exception: <%s:%s>' % (exc.toString(), circumstance)) - -POLLIN = 1 -POLLOUT = 2 - -# The following event types are completely ignored on jython -# Java does not support them, AFAICT -# They are declared only to support code compatibility with cpython - -POLLPRI = 4 -POLLERR = 8 -POLLHUP = 16 -POLLNVAL = 32 - -def _getselectable(selectable_object): - try: - channel = selectable_object.getchannel() - except: - try: - channel = selectable_object.fileno().getChannel() - except: - raise TypeError("Object '%s' is not watchable" % selectable_object, - errno.ENOTSOCK) - - if channel and not isinstance(channel, java.nio.channels.SelectableChannel): - raise TypeError("Object '%s' is not watchable" % selectable_object, - errno.ENOTSOCK) - return channel - -class poll: - - def __init__(self): - self.selector = java.nio.channels.Selector.open() - self.chanmap = {} - self.unconnected_sockets = [] - - def _register_channel(self, socket_object, channel, mask): - jmask = 0 - if mask & POLLIN: - # Note that OP_READ is NOT a valid event on server socket channels. - if channel.validOps() & OP_ACCEPT: - jmask = OP_ACCEPT - else: - jmask = OP_READ - if mask & POLLOUT: - if channel.validOps() & OP_WRITE: - jmask |= OP_WRITE - if channel.validOps() & OP_CONNECT: - jmask |= OP_CONNECT - selectionkey = channel.register(self.selector, jmask) - self.chanmap[channel] = (socket_object, selectionkey) - - def _check_unconnected_sockets(self): - temp_list = [] - for socket_object, mask in self.unconnected_sockets: - channel = _getselectable(socket_object) - if channel is not None: - self._register_channel(socket_object, channel, mask) - else: - temp_list.append( (socket_object, mask) ) - self.unconnected_sockets = temp_list - - def register(self, socket_object, mask = POLLIN|POLLOUT|POLLPRI): - try: - channel = _getselectable(socket_object) - if channel is None: - # The socket is not yet connected, and thus has no channel - # Add it to a pending list, and return - self.unconnected_sockets.append( (socket_object, mask) ) - return - self._register_channel(socket_object, channel, mask) - except java.lang.Exception, jlx: - raise _map_exception(jlx) - - def unregister(self, socket_object): - try: - channel = _getselectable(socket_object) - self.chanmap[channel][1].cancel() - del self.chanmap[channel] - except java.lang.Exception, jlx: - raise _map_exception(jlx) - - def _dopoll(self, timeout): - if timeout is None or timeout < 0: - self.selector.select() - else: - try: - timeout = int(timeout) - if not timeout: - self.selector.selectNow() - else: - # No multiplication required: both cpython and java use millisecond timeouts - self.selector.select(timeout) - except ValueError, vx: - raise error("poll timeout must be a number of milliseconds or None", errno.EINVAL) - # The returned selectedKeys cannot be used from multiple threads! - return self.selector.selectedKeys() - - def poll(self, timeout=None): - try: - self._check_unconnected_sockets() - selectedkeys = self._dopoll(timeout) - results = [] - for k in selectedkeys.iterator(): - jmask = k.readyOps() - pymask = 0 - if jmask & OP_READ: pymask |= POLLIN - if jmask & OP_WRITE: pymask |= POLLOUT - if jmask & OP_ACCEPT: pymask |= POLLIN - if jmask & OP_CONNECT: pymask |= POLLOUT - # Now return the original userobject, and the return event mask - results.append( (self.chanmap[k.channel()][0], pymask) ) - return results - except java.lang.Exception, jlx: - raise _map_exception(jlx) - - def _deregister_all(self): - try: - for k in self.selector.keys(): - k.cancel() - # Keys are not actually removed from the selector until the next select operation. - self.selector.selectNow() - except java.lang.Exception, jlx: - raise _map_exception(jlx) - - def close(self): - try: - self._deregister_all() - self.selector.close() - except java.lang.Exception, jlx: - raise _map_exception(jlx) - -def _calcselecttimeoutvalue(value): - if value is None: - return None - try: - floatvalue = float(value) - except Exception, x: - raise TypeError("Select timeout value must be a number or None") - if value < 0: - raise error("Select timeout value cannot be negative", errno.EINVAL) - if floatvalue < 0.000001: - return 0 - return int(floatvalue * 1000) # Convert to milliseconds - -# This cache for poll objects is required because of a bug in java on MS Windows -# http://bugs.jython.org/issue1291 - -class poll_object_cache: - - def __init__(self): - self.is_windows = os._name == 'nt' - if self.is_windows: - self.poll_object_queue = Queue.Queue() - import atexit - atexit.register(self.finalize) - - def get_poll_object(self): - if not self.is_windows: - return poll() - try: - return self.poll_object_queue.get(False) - except Queue.Empty: - return poll() - - def release_poll_object(self, pobj): - if self.is_windows: - pobj._deregister_all() - self.poll_object_queue.put(pobj) - else: - pobj.close() - - def finalize(self): - if self.is_windows: - while True: - try: - p = self.poll_object_queue.get(False) - p.close() - except Queue.Empty: - return - -_poll_object_cache = poll_object_cache() - -def native_select(read_fd_list, write_fd_list, outofband_fd_list, timeout=None): - timeout = _calcselecttimeoutvalue(timeout) - # First create a poll object to do the actual watching. - pobj = _poll_object_cache.get_poll_object() - try: - registered_for_read = {} - # Check the read list - for fd in read_fd_list: - pobj.register(fd, POLLIN) - registered_for_read[fd] = 1 - # And now the write list - for fd in write_fd_list: - if fd in registered_for_read: - # registering a second time overwrites the first - pobj.register(fd, POLLIN|POLLOUT) - else: - pobj.register(fd, POLLOUT) - results = pobj.poll(timeout) - # Now start preparing the results - read_ready_list, write_ready_list, oob_ready_list = [], [], [] - for fd, mask in results: - if mask & POLLIN: - read_ready_list.append(fd) - if mask & POLLOUT: - write_ready_list.append(fd) - return read_ready_list, write_ready_list, oob_ready_list - finally: - _poll_object_cache.release_poll_object(pobj) - -select = native_select - -def cpython_compatible_select(read_fd_list, write_fd_list, outofband_fd_list, timeout=None): - # First turn all sockets to non-blocking - # keeping track of which ones have changed - modified_channels = [] - try: - for socket_list in [read_fd_list, write_fd_list, outofband_fd_list]: - for s in socket_list: - channel = _getselectable(s) - if channel.isBlocking(): - modified_channels.append(channel) - channel.configureBlocking(0) - return native_select(read_fd_list, write_fd_list, outofband_fd_list, timeout) - finally: - for channel in modified_channels: - channel.configureBlocking(1) +""" +This is an select module for use on JVMs > 1.5. +It is documented, along with known issues and workarounds, on the jython wiki. +http://wiki.python.org/jython/SelectModule +""" + +import java.nio.channels.SelectableChannel +import java.nio.channels.SelectionKey +import java.nio.channels.Selector +from java.nio.channels.SelectionKey import OP_ACCEPT, OP_CONNECT, OP_WRITE, OP_READ + +import errno +import os +import Queue +import socket + +class error(Exception): pass + +ALL = None + +_exception_map = { + +# (<javaexception>, <circumstance>) : lambda: <code that raises the python equivalent> + +(java.nio.channels.IllegalBlockingModeException, ALL) : error(errno.ESOCKISBLOCKING, 'socket must be in non-blocking mode'), +} + +def _map_exception(exc, circumstance=ALL): + try: + mapped_exception = _exception_map[(exc.__class__, circumstance)] + mapped_exception.java_exception = exc + return mapped_exception + except KeyError: + return error(-1, 'Unmapped java exception: <%s:%s>' % (exc.toString(), circumstance)) + +POLLIN = 1 +POLLOUT = 2 + +# The following event types are completely ignored on jython +# Java does not support them, AFAICT +# They are declared only to support code compatibility with cpython + +POLLPRI = 4 +POLLERR = 8 +POLLHUP = 16 +POLLNVAL = 32 + +def _getselectable(selectable_object): + try: + channel = selectable_object.getchannel() + except: + try: + channel = selectable_object.fileno().getChannel() + except: + raise TypeError("Object '%s' is not watchable" % selectable_object, + errno.ENOTSOCK) + + if channel and not isinstance(channel, java.nio.channels.SelectableChannel): + raise TypeError("Object '%s' is not watchable" % selectable_object, + errno.ENOTSOCK) + return channel + +class poll: + + def __init__(self): + self.selector = java.nio.channels.Selector.open() + self.chanmap = {} + self.unconnected_sockets = [] + + def _register_channel(self, socket_object, channel, mask): + jmask = 0 + if mask & POLLIN: + # Note that OP_READ is NOT a valid event on server socket channels. + if channel.validOps() & OP_ACCEPT: + jmask = OP_ACCEPT + else: + jmask = OP_READ + if mask & POLLOUT: + if channel.validOps() & OP_WRITE: + jmask |= OP_WRITE + if channel.validOps() & OP_CONNECT: + jmask |= OP_CONNECT + selectionkey = channel.register(self.selector, jmask) + self.chanmap[channel] = (socket_object, selectionkey) + + def _check_unconnected_sockets(self): + temp_list = [] + for socket_object, mask in self.unconnected_sockets: + channel = _getselectable(socket_object) + if channel is not None: + self._register_channel(socket_object, channel, mask) + else: + temp_list.append( (socket_object, mask) ) + self.unconnected_sockets = temp_list + + def register(self, socket_object, mask = POLLIN|POLLOUT|POLLPRI): + try: + channel = _getselectable(socket_object) + if channel is None: + # The socket is not yet connected, and thus has no channel + # Add it to a pending list, and return + self.unconnected_sockets.append( (socket_object, mask) ) + return + self._register_channel(socket_object, channel, mask) + except java.lang.Exception, jlx: + raise _map_exception(jlx) + + def unregister(self, socket_object): + try: + channel = _getselectable(socket_object) + self.chanmap[channel][1].cancel() + del self.chanmap[channel] + except java.lang.Exception, jlx: + raise _map_exception(jlx) + + def _dopoll(self, timeout): + if timeout is None or timeout < 0: + self.selector.select() + else: + try: + timeout = int(timeout) + if not timeout: + self.selector.selectNow() + else: + # No multiplication required: both cpython and java use millisecond timeouts + self.selector.select(timeout) + except ValueError, vx: + raise error("poll timeout must be a number of milliseconds or None", errno.EINVAL) + # The returned selectedKeys cannot be used from multiple threads! + return self.selector.selectedKeys() + + def poll(self, timeout=None): + try: + self._check_unconnected_sockets() + selectedkeys = self._dopoll(timeout) + results = [] + for k in selectedkeys.iterator(): + jmask = k.readyOps() + pymask = 0 + if jmask & OP_READ: pymask |= POLLIN + if jmask & OP_WRITE: pymask |= POLLOUT + if jmask & OP_ACCEPT: pymask |= POLLIN + if jmask & OP_CONNECT: pymask |= POLLOUT + # Now return the original userobject, and the return event mask + results.append( (self.chanmap[k.channel()][0], pymask) ) + return results + except java.lang.Exception, jlx: + raise _map_exception(jlx) + + def _deregister_all(self): + try: + for k in self.selector.keys(): + k.cancel() + # Keys are not actually removed from the selector until the next select operation. + self.selector.selectNow() + except java.lang.Exception, jlx: + raise _map_exception(jlx) + + def close(self): + try: + self._deregister_all() + self.selector.close() + except java.lang.Exception, jlx: + raise _map_exception(jlx) + +def _calcselecttimeoutvalue(value): + if value is None: + return None + try: + floatvalue = float(value) + except Exception, x: + raise TypeError("Select timeout value must be a number or None") + if value < 0: + raise error("Select timeout value cannot be negative", errno.EINVAL) + if floatvalue < 0.000001: + return 0 + return int(floatvalue * 1000) # Convert to milliseconds + +# This cache for poll objects is required because of a bug in java on MS Windows +# http://bugs.jython.org/issue1291 + +class poll_object_cache: + + def __init__(self): + self.is_windows = os._name == 'nt' + if self.is_windows: + self.poll_object_queue = Queue.Queue() + import atexit + atexit.register(self.finalize) + + def get_poll_object(self): + if not self.is_windows: + return poll() + try: + return self.poll_object_queue.get(False) + except Queue.Empty: + return poll() + + def release_poll_object(self, pobj): + if self.is_windows: + pobj._deregister_all() + self.poll_object_queue.put(pobj) + else: + pobj.close() + + def finalize(self): + if self.is_windows: + while True: + try: + p = self.poll_object_queue.get(False) + p.close() + except Queue.Empty: + return + +_poll_object_cache = poll_object_cache() + +def native_select(read_fd_list, write_fd_list, outofband_fd_list, timeout=None): + timeout = _calcselecttimeoutvalue(timeout) + # First create a poll object to do the actual watching. + pobj = _poll_object_cache.get_poll_object() + try: + registered_for_read = {} + # Check the read list + for fd in read_fd_list: + pobj.register(fd, POLLIN) + registered_for_read[fd] = 1 + # And now the write list + for fd in write_fd_list: + if fd in registered_for_read: + # registering a second time overwrites the first + pobj.register(fd, POLLIN|POLLOUT) + else: + pobj.register(fd, POLLOUT) + results = pobj.poll(timeout) + # Now start preparing the results + read_ready_list, write_ready_list, oob_ready_list = [], [], [] + for fd, mask in results: + if mask & POLLIN: + read_ready_list.append(fd) + if mask & POLLOUT: + write_ready_list.append(fd) + return read_ready_list, write_ready_list, oob_ready_list + finally: + _poll_object_cache.release_poll_object(pobj) + +select = native_select + +def cpython_compatible_select(read_fd_list, write_fd_list, outofband_fd_list, timeout=None): + # First turn all sockets to non-blocking + # keeping track of which ones have changed + modified_channels = [] + try: + for socket_list in [read_fd_list, write_fd_list, outofband_fd_list]: + for s in socket_list: + channel = _getselectable(s) + if channel.isBlocking(): + modified_channels.append(channel) + channel.configureBlocking(0) + return native_select(read_fd_list, write_fd_list, outofband_fd_list, timeout) + finally: + for channel in modified_channels: + channel.configureBlocking(1) Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2011-02-14 23:40:19 UTC (rev 7201) +++ trunk/jython/Lib/socket.py 2011-02-15 21:39:44 UTC (rev 7202) @@ -1,16 +1,7 @@ """ -This is an updated socket module for use on JVMs > 1.4; it is derived from the -old jython socket module. -The primary extra it provides is non-blocking support. - -XXX Restrictions: - -- Only INET sockets -- Can't do a very good gethostbyaddr() right... -AMAK: 20050527: added socket timeouts -AMAK: 20070515: Added non-blocking (asynchronous) support -AMAK: 20070515: Added client-side SSL support -AMAK: 20080513: Added support for options +This is an updated socket module for use on JVMs > 1.5; it is derived from the old jython socket module. +It is documented, along with known issues and workarounds, on the jython wiki. +http://wiki.python.org/jython/NewSocketModule """ _defaulttimeout = None This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <otm...@us...> - 2011-02-14 23:40:25
|
Revision: 7201 http://jython.svn.sourceforge.net/jython/?rev=7201&view=rev Author: otmarhumbel Date: 2011-02-14 23:40:19 +0000 (Mon, 14 Feb 2011) Log Message: ----------- website preparation for 2.5.2rc4 Modified Paths: -------------- trunk/website/index.txt trunk/website/jysite.py trunk/website/redirects/downloads.txt trunk/website/redirects/latest.txt Modified: trunk/website/index.txt =================================================================== --- trunk/website/index.txt 2011-02-14 22:27:53 UTC (rev 7200) +++ trunk/website/index.txt 2011-02-14 23:40:19 UTC (rev 7201) @@ -4,6 +4,11 @@ Latest News ~~~~~~~~~~~ +**Jython 2.5.2 RC 4 Has Been Released** (February 15, 2011) + +The Jython development team would like to announce the release of 2.5.2 Release Candidate 4. For a complete listing of changes, please visit the `Release Notes`_. + + **Jython 2.5.2 RC 3 Has Been Released** (January 11, 2011) The Jython development team would like to announce the release of 2.5.2 Release Candidate 3. For a complete listing of changes, please visit the `Release Notes`_. @@ -97,7 +102,7 @@ .. _this post: http://blog.springpython.webfactional.com/2009/10/15/see-how-spring-python-works-with-jython/ .. _Release Notes: http://www.jython.org/latest.html .. _the bug tracker: http://bugs.jython.org -.. _download the installer by clicking here: http://sourceforge.net/projects/jython/files/jython-dev/2.5.2rc3/jython_installer-2.5.2rc3.jar/download +.. _download the installer by clicking here: http://sourceforge.net/projects/jython/files/jython-dev/2.5.2rc4/jython_installer-2.5.2rc4.jar/download Modified: trunk/website/jysite.py =================================================================== --- trunk/website/jysite.py 2011-02-14 22:27:53 UTC (rev 7200) +++ trunk/website/jysite.py 2011-02-14 23:40:19 UTC (rev 7201) @@ -80,9 +80,9 @@ buffer.append('<a href="./" ><img class="logoImage" alt="Jython" style="border: 0px; padding-top: 20px; position:absolute; left: 35px" src="css/jython.png" title="Jython"></a>') buffer.append('</div>') buffer.append('<div class="latest_release" style="position:absolute; color:#000; width:180px; top: 15px; right: 30px; padding:0px 10px 10px 30px; font-size:11px; background:url(\'css/latest_release_bg.png\') no-repeat">') - buffer.append('<p style="top: 25px; color:#000">Latest release - 2.5.2 - RC 3<br/>') + buffer.append('<p style="top: 25px; color:#000">Latest release - 2.5.2 - RC 4<br/>') buffer.append('<a style="color:#000" href="latest.html">View Release Notes</a><br/>') - buffer.append('Download: <a style="color:#000" href="http://sourceforge.net/projects/jython/files/jython-dev/2.5.2rc3/jython_installer-2.5.2rc3.jar/download">.jar</a>') + buffer.append('Download: <a style="color:#000" href="http://sourceforge.net/projects/jython/files/jython-dev/2.5.2rc4/jython_installer-2.5.2rc4.jar/download">.jar</a>') buffer.append('</div>') buffer.append('<div class="searchbox">') Modified: trunk/website/redirects/downloads.txt =================================================================== --- trunk/website/redirects/downloads.txt 2011-02-14 22:27:53 UTC (rev 7200) +++ trunk/website/redirects/downloads.txt 2011-02-14 23:40:19 UTC (rev 7201) @@ -1,14 +1,14 @@ Downloads --------- -The current version of Jython is 2.5.2 - Release Candidate 3, please use the link below to download the Java installer. +The current version of Jython is 2.5.2 - Release Candidate 4, please use the link below to download the Java installer. Once downloaded, please double-click on the JAR file to start the installation process. You may also want to read the `Installation instructions`_ or the `Release Notes`_. -`Download Jython 2.5.2`_ RC 3 +`Download Jython 2.5.2`_ RC 4 -- MD5: ``4ffedc964ce01b0be9cb4793550311be`` -- SHA1: ``547c424a119661ed1901079ff8f4e45af7d57b56`` +- MD5: ``63967bbbd53f8e60c860aa1b11cf3cb8`` +- SHA1: ``3b20e32bbdbe4dc8a4e3b49d173af897e1ee9cb0`` Previous Releases ----------------- @@ -28,7 +28,7 @@ - MD5: ``774543534bef2d68247953882237d448`` - SHA1: ``6fea1e8985af955fc843789e2d60fcfc38a76fd8`` -.. _Download Jython 2.5.2: http://sourceforge.net/projects/jython/files/jython-dev/2.5.2rc3/jython_installer-2.5.2rc3.jar/download +.. _Download Jython 2.5.2: http://sourceforge.net/projects/jython/files/jython-dev/2.5.2rc4/jython_installer-2.5.2rc4.jar/download .. _Jython 2.5.1: http://sourceforge.net/projects/jython/files/jython/2.5.1/jython_installer-2.5.1.jar/download .. _Jython 2.5.0: http://sourceforge.net/projects/jython/files/jython/2.5.0/jython_installer-2.5.0.jar/download .. _Jython 2.2.1: http://sourceforge.net/projects/jython/files/jython/jython_installer-2.2.1.jar Modified: trunk/website/redirects/latest.txt =================================================================== --- trunk/website/redirects/latest.txt 2011-02-14 22:27:53 UTC (rev 7200) +++ trunk/website/redirects/latest.txt 2011-02-14 23:40:19 UTC (rev 7201) @@ -6,6 +6,15 @@ Bugs Fixed ---------- +2.5.2-rc4 +~~~~~~~~~ + - [ 1667 ] thread.local subclasses with constructor params fail + - [ 1698 ] warnings module fails under JSR-223 + - [ 1697 ] Wrong error message when http connection can not be established + - [ 1210 ] Lib/socket.py doesn't allow IPv6 sockets and fails with an AssertionError + - [ 1700 ] "virtualenv is not compatible" to 2.5.2rc3 + - [ 1701 ] Files are not flushed properly when opened from the EDT (partial fix) + 2.5.2-rc3 ~~~~~~~~~ - [ 1674 ] PDB crashes under the JSR-223 scripting engine This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <otm...@us...> - 2011-02-14 22:27:59
|
Revision: 7200 http://jython.svn.sourceforge.net/jython/?rev=7200&view=rev Author: otmarhumbel Date: 2011-02-14 22:27:53 +0000 (Mon, 14 Feb 2011) Log Message: ----------- tagging 2.5.2rc4 Added Paths: ----------- tags/Release_2_5_2rc4/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <otm...@us...> - 2011-02-14 22:09:55
|
Revision: 7199 http://jython.svn.sourceforge.net/jython/?rev=7199&view=rev Author: otmarhumbel Date: 2011-02-14 22:09:48 +0000 (Mon, 14 Feb 2011) Log Message: ----------- prepare for 2.5.2rc4 Modified Paths: -------------- trunk/jython/NEWS trunk/jython/README.txt trunk/jython/build.xml Modified: trunk/jython/NEWS =================================================================== --- trunk/jython/NEWS 2011-02-13 20:49:57 UTC (rev 7198) +++ trunk/jython/NEWS 2011-02-14 22:09:48 UTC (rev 7199) @@ -1,12 +1,13 @@ Jython NEWS -Jython 2.5.2 +Jython 2.5.2rc4 Bugs Fixed - [ 1667 ] thread.local subclasses with constructor params fail - [ 1698 ] warnings module fails under JSR-223 - [ 1697 ] Wrong error message when http connection can not be established - [ 1210 ] Lib/socket.py doesn't allow IPv6 sockets and fails with an AssertionError - [ 1700 ] "virtualenv is not compatible" to 2.5.2rc3 + - [ 1701 ] Files are not flushed properly when opened from the EDT (partial fix) Jython 2.5.2rc3 Bugs Fixed Modified: trunk/jython/README.txt =================================================================== --- trunk/jython/README.txt 2011-02-13 20:49:57 UTC (rev 7198) +++ trunk/jython/README.txt 2011-02-14 22:09:48 UTC (rev 7199) @@ -1,9 +1,9 @@ -Welcome to Jython 2.5.2 rc3 +Welcome to Jython 2.5.2 rc4 =========================== -This is the third release candidate of the 2.5.2 version of Jython. -It contains the most important bug fixes since 2.5.2 rc2. -We believe that this is the last release candidate before the final 2.5.2 release! +This is the fourth release candidate of the 2.5.2 version of Jython. +It contains the fixes of the blocker bugs since 2.5.2 rc3. +We still believe that this is the last release candidate before the final 2.5.2 release! This release fixes bugs related to resource leaks, Java integration, and a number of other issues. See the NEWS file for more details. In Modified: trunk/jython/build.xml =================================================================== --- trunk/jython/build.xml 2011-02-13 20:49:57 UTC (rev 7198) +++ trunk/jython/build.xml 2011-02-14 22:09:48 UTC (rev 7199) @@ -123,13 +123,13 @@ <property name="PY_RELEASE_LEVEL_SNAPSHOT" value="170"/> <!-- 0xAA --> <!-- The current version info --> - <property name="jython.version" value="2.5.2rc3"/> - <property name="jython.version.noplus" value="2.5.2rc3"/> + <property name="jython.version" value="2.5.2rc4"/> + <property name="jython.version.noplus" value="2.5.2rc4"/> <property name="jython.major_version" value="2"/> <property name="jython.minor_version" value="5"/> <property name="jython.micro_version" value="2"/> <property name="jython.release_level" value="${PY_RELEASE_LEVEL_GAMMA}"/> - <property name="jython.release_serial" value="3"/> + <property name="jython.release_serial" value="4"/> <condition property="do.snapshot.build"> <isset property="snapshot.revision" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2011-02-13 20:50:04
|
Revision: 7198 http://jython.svn.sourceforge.net/jython/?rev=7198&view=rev Author: amak Date: 2011-02-13 20:49:57 +0000 (Sun, 13 Feb 2011) Log Message: ----------- Checking in support for Internationalized Domain Names (RFC 3490), plus unit-tests for same. This new support only works on Java 6. The new feature and workarounds for Java 5 are documented on the jython wiki. http://wiki.python.org/jython/NewSocketModule Partially fixes http://bugs.jython.org/issue1153 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 2011-02-12 01:50:38 UTC (rev 7197) +++ trunk/jython/Lib/socket.py 2011-02-13 20:49:57 UTC (rev 7198) @@ -161,6 +161,17 @@ exception.java_exception = exc return exception +_feature_support_map = { + 'ipv6': True, + 'idna': False, + 'tipc': False, +} + +def supports(feature, *args): + if len(args) == 1: + _feature_support_map[feature] = args[0] + return _feature_support_map.get(feature, False) + MODE_BLOCKING = 'block' MODE_NONBLOCKING = 'nonblock' MODE_TIMEOUT = 'timeout' @@ -591,6 +602,36 @@ assert protocol == IPPROTO_UDP, "Only IPPROTO_UDP supported on SOCK_DGRAM sockets" return _udpsocket() +# +# Attempt to provide IDNA (RFC 3490) support. +# +# Try java.net.IDN, built into java 6 +# + +idna_libraries = [ + ('java.net.IDN', 'toASCII', java.lang.IllegalArgumentException) +] + +for idna_lib, idna_fn_name, exc in idna_libraries: + try: + m = __import__(idna_lib, globals(), locals(), [idna_fn_name]) + idna_fn = getattr(m, idna_fn_name) + def _encode_idna(name): + try: + return idna_fn(name) + except exc: + raise UnicodeEncodeError(name) + supports('idna', True) + break + except (AttributeError, ImportError), e: + pass +else: + _encode_idna = lambda x: x.encode("ascii") + +# +# Define data structures to support IPV4 and IPV6. +# + class _ip_address_t: pass class _ipv4_address_t(_ip_address_t): @@ -668,10 +709,7 @@ if hostname is None: return java.net.InetSocketAddress(port) 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 = _encode_idna(hostname) if len(address_object) == 4: # There is no way to get a Inet6Address: Inet6Address.getByName() simply calls # InetAddress.getByName,() which also returns Inet4Address objects @@ -701,6 +739,8 @@ }[family]) if host == "": host = java.net.InetAddress.getLocalHost().getHostName() + if isinstance(host, unicode): + host = _encode_idna(host) passive_mode = flags is not None and flags & AI_PASSIVE canonname_mode = flags is not None and flags & AI_CANONNAME results = [] Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2011-02-12 01:50:38 UTC (rev 7197) +++ trunk/jython/Lib/test/test_socket.py 2011-02-13 20:49:57 UTC (rev 7198) @@ -1742,6 +1742,47 @@ def _testUnicodeHostname(self): self.cli.connect((unicode(self.HOST), self.PORT)) +class IDNATest(unittest.TestCase): + + def testGetAddrInfoIDNAHostname(self): + idna_domain = u"al\u00e1n.com" + if socket.supports('idna'): + try: + addresses = socket.getaddrinfo(idna_domain, 80) + self.failUnless(len(addresses) > 0, "No addresses returned for test IDNA domain '%s'" % repr(idna_domain)) + except Exception, x: + self.fail("Unexpected exception raised for socket.getaddrinfo(%s)" % repr(idna_domain)) + else: + try: + socket.getaddrinfo(idna_domain, 80) + except UnicodeEncodeError: + pass + except Exception, x: + self.fail("Non ascii domain '%s' should have raised UnicodeEncodeError, not %s" % (repr(idna_domain), str(x))) + else: + self.fail("Non ascii domain '%s' should have raised UnicodeEncodeError: no exception raised" % repr(idna_domain)) + + def testAddrTupleIDNAHostname(self): + idna_domain = u"al\u00e1n.com" + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + if socket.supports('idna'): + try: + s.bind( (idna_domain, 80) ) + except socket.error: + # We're not worried about socket errors, i.e. bind problems, etc. + pass + except Exception, x: + self.fail("Unexpected exception raised for socket.bind(%s)" % repr(idna_domain)) + else: + try: + s.bind( (idna_domain, 80) ) + except UnicodeEncodeError: + pass + except Exception, x: + self.fail("Non ascii domain '%s' should have raised UnicodeEncodeError, not %s" % (repr(idna_domain), str(x))) + else: + self.fail("Non ascii domain '%s' should have raised UnicodeEncodeError: no exception raised" % repr(idna_domain)) + class TestInvalidUsage(unittest.TestCase): def setUp(self): @@ -1793,6 +1834,7 @@ LineBufferedFileObjectClassTestCase, SmallBufferedFileObjectClassTestCase, UnicodeTest, + IDNATest, ] if hasattr(socket, "socketpair"): tests.append(BasicSocketPairTest) @@ -1804,7 +1846,6 @@ # Need some way to discover the network setup on the test machine if False: tests.append(UDPBroadcastTest) -# tests = [TestJython_get_jsockaddr] suites = [unittest.makeSuite(klass, 'test') for klass in tests] test_support.run_suite(unittest.TestSuite(suites)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2011-02-12 01:50:44
|
Revision: 7197 http://jython.svn.sourceforge.net/jython/?rev=7197&view=rev Author: pjenvey Date: 2011-02-12 01:50:38 +0000 (Sat, 12 Feb 2011) Log Message: ----------- ensure files are closed on close() even after PySystemState.cleanup has been called. this is an evil situation to be calling python code in, but it doesn't hurt us to close the file anyway and this partly fixes #1701 Modified Paths: -------------- trunk/jython/src/org/python/core/PyFile.java Modified: trunk/jython/src/org/python/core/PyFile.java =================================================================== --- trunk/jython/src/org/python/core/PyFile.java 2011-02-11 14:11:26 UTC (rev 7196) +++ trunk/jython/src/org/python/core/PyFile.java 2011-02-12 01:50:38 UTC (rev 7197) @@ -590,9 +590,8 @@ /** For closing directly */ public void close() { - if (sys.unregisterCloser(this)) { - file.close(); - } + sys.unregisterCloser(this); + file.close(); sys = null; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2011-02-11 14:11:32
|
Revision: 7196 http://jython.svn.sourceforge.net/jython/?rev=7196&view=rev Author: amak Date: 2011-02-11 14:11:26 +0000 (Fri, 11 Feb 2011) Log Message: ----------- Adding repr methods to the internal address tuple types, so that they are more user friendly. Finalizes http://bugs.jython.org/issue1697 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 2011-02-08 01:16:53 UTC (rev 7195) +++ trunk/jython/Lib/socket.py 2011-02-11 14:11:26 UTC (rev 7196) @@ -591,11 +591,8 @@ assert protocol == IPPROTO_UDP, "Only IPPROTO_UDP supported on SOCK_DGRAM sockets" return _udpsocket() -class _ip_address_t: +class _ip_address_t: pass - def __str__(self): - return "('%s', %d)" % (self.sockaddr, self.port) - class _ipv4_address_t(_ip_address_t): def __init__(self, sockaddr, port, jaddress): @@ -614,6 +611,11 @@ def __len__(self): return 2 + def __str__(self): + return "('%s', %d)" % (self.sockaddr, self.port) + + __repr__ = __str__ + class _ipv6_address_t(_ip_address_t): def __init__(self, sockaddr, port, jaddress): @@ -636,6 +638,11 @@ def __len__(self): return 4 + def __str__(self): + return "('%s', %d, 0, %d)" % (self.sockaddr, self.port, self.jaddress.scopeId) + + __repr__ = __str__ + def _get_jsockaddr(address_object, for_udp=False): if address_object is None: return java.net.InetSocketAddress(0) # Let the system pick an ephemeral port Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2011-02-08 01:16:53 UTC (rev 7195) +++ trunk/jython/Lib/test/test_socket.py 2011-02-11 14:11:26 UTC (rev 7196) @@ -1508,6 +1508,7 @@ self.failUnlessEqual(ipv4_address_tuple[1], 80) self.failUnlessRaises(IndexError, lambda: ipv4_address_tuple[2]) self.failUnlessEqual(str(ipv4_address_tuple), "('127.0.0.1', 80)") + self.failUnlessEqual(repr(ipv4_address_tuple), "('127.0.0.1', 80)") ipv6_address_tuple = socket.getaddrinfo("localhost", 80, socket.AF_INET6, socket.SOCK_STREAM, 0, 0)[0][4] self.failUnless (ipv6_address_tuple[0] in ["::1", "0:0:0:0:0:0:0:1"]) @@ -1519,7 +1520,10 @@ except IndexError: self.fail("Failed to retrieve third element of ipv6 4-tuple") self.failUnlessRaises(IndexError, lambda: ipv6_address_tuple[4]) - self.failUnless(str(ipv6_address_tuple) in ["('::1', 80)", "('0:0:0:0:0:0:0:1', 80)"]) + # These str/repr tests may fail on some systems: the scope element of the tuple may be non-zero + # In this case, we'll have to change the test to use .startswith() or .split() to exclude the scope element + self.failUnless(str(ipv6_address_tuple) in ["('::1', 80, 0, 0)", "('0:0:0:0:0:0:0:1', 80, 0, 0)"]) + self.failUnless(repr(ipv6_address_tuple) in ["('::1', 80, 0, 0)", "('0:0:0:0:0:0:0:1', 80, 0, 0)"]) class TestJython_get_jsockaddr(unittest.TestCase): "These tests are specific to jython: they test a key internal routine" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2011-02-08 01:17:00
|
Revision: 7195 http://jython.svn.sourceforge.net/jython/?rev=7195&view=rev Author: pjenvey Date: 2011-02-08 01:16:53 +0000 (Tue, 08 Feb 2011) Log Message: ----------- cleanup generics around PySystemStateCloser, PySystemState.unregisterCloser doesn't need synchronization Modified Paths: -------------- trunk/jython/src/org/python/core/PyFile.java trunk/jython/src/org/python/core/PySystemState.java Modified: trunk/jython/src/org/python/core/PyFile.java =================================================================== --- trunk/jython/src/org/python/core/PyFile.java 2011-02-05 01:23:12 UTC (rev 7194) +++ trunk/jython/src/org/python/core/PyFile.java 2011-02-08 01:16:53 UTC (rev 7195) @@ -574,7 +574,7 @@ * be called during shutdown, so we can't use it. It's vital that this Closer has no * reference to the PyFile it's closing so the PyFile remains garbage collectable. */ - private static class Closer implements Callable { + private static class Closer implements Callable<Void> { /** * The underlying file @@ -588,8 +588,7 @@ sys.registerCloser(this); } - // For closing directly - + /** For closing directly */ public void close() { if (sys.unregisterCloser(this)) { file.close(); @@ -597,9 +596,8 @@ sys = null; } - // For closing as part of a shutdown process - - public Object call() { + /** For closing as part of a shutdown process */ + public Void call() { file.close(); sys = null; return null; Modified: trunk/jython/src/org/python/core/PySystemState.java =================================================================== --- trunk/jython/src/org/python/core/PySystemState.java 2011-02-05 01:23:12 UTC (rev 7194) +++ trunk/jython/src/org/python/core/PySystemState.java 2011-02-08 01:16:53 UTC (rev 7195) @@ -155,8 +155,10 @@ // Automatically close resources associated with a PySystemState when they get GCed private final PySystemStateCloser closer; - private static final ReferenceQueue systemStateQueue = new ReferenceQueue<PySystemState>(); - private static final ConcurrentMap<WeakReference<PySystemState>, PySystemStateCloser> sysClosers = Generic.concurrentMap(); + private static final ReferenceQueue<PySystemState> systemStateQueue = + new ReferenceQueue<PySystemState>(); + private static final ConcurrentMap<WeakReference<PySystemState>, + PySystemStateCloser> sysClosers = Generic.concurrentMap(); public PySystemState() { initialize(); @@ -1286,11 +1288,11 @@ return f; } - public void registerCloser(Callable resourceCloser) { + public void registerCloser(Callable<Void> resourceCloser) { closer.registerCloser(resourceCloser); } - public synchronized boolean unregisterCloser(Callable resourceCloser) { + public boolean unregisterCloser(Callable<Void> resourceCloser) { return closer.unregisterCloser(resourceCloser); } @@ -1300,32 +1302,33 @@ private static class PySystemStateCloser { - private final Set<Callable> resourceClosers = new LinkedHashSet<Callable>(); + private final Set<Callable<Void>> resourceClosers = new LinkedHashSet<Callable<Void>>(); private volatile boolean isCleanup = false; private final Thread shutdownHook; private PySystemStateCloser(PySystemState sys) { shutdownHook = initShutdownCloser(); - WeakReference<PySystemState> ref = new WeakReference(sys, systemStateQueue); + WeakReference<PySystemState> ref = + new WeakReference<PySystemState>(sys, systemStateQueue); sysClosers.put(ref, this); cleanupOtherClosers(); } private static void cleanupOtherClosers() { - Reference<PySystemStateCloser> ref; + Reference<? extends PySystemState> ref; while ((ref = systemStateQueue.poll()) != null) { PySystemStateCloser closer = sysClosers.get(ref); closer.cleanup(); } } - private synchronized void registerCloser(Callable closer) { + private synchronized void registerCloser(Callable<Void> closer) { if (!isCleanup) { resourceClosers.add(closer); } } - private synchronized boolean unregisterCloser(Callable closer) { + private synchronized boolean unregisterCloser(Callable<Void> closer) { return resourceClosers.remove(closer); } @@ -1335,7 +1338,8 @@ } isCleanup = true; - // close this thread so we can unload any associated classloaders in cycle with this instance + // close this thread so we can unload any associated classloaders in cycle + // with this instance if (shutdownHook != null) { try { Runtime.getRuntime().removeShutdownHook(shutdownHook); @@ -1344,7 +1348,7 @@ } } - for (Callable callable : resourceClosers) { + for (Callable<Void> callable : resourceClosers) { try { callable.call(); } catch (Exception e) { @@ -1378,7 +1382,7 @@ // resourceClosers can be null in some strange cases return; } - for (Callable callable : resourceClosers) { + for (Callable<Void> callable : resourceClosers) { try { callable.call(); // side effect of being removed from this set } catch (Exception e) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2011-02-05 01:23:18
|
Revision: 7194 http://jython.svn.sourceforge.net/jython/?rev=7194&view=rev Author: pjenvey Date: 2011-02-05 01:23:12 +0000 (Sat, 05 Feb 2011) Log Message: ----------- remove the unused startCleanupThread Modified Paths: -------------- trunk/jython/src/org/python/core/PySystemState.java Modified: trunk/jython/src/org/python/core/PySystemState.java =================================================================== --- trunk/jython/src/org/python/core/PySystemState.java 2011-02-03 21:56:23 UTC (rev 7193) +++ trunk/jython/src/org/python/core/PySystemState.java 2011-02-05 01:23:12 UTC (rev 7194) @@ -157,9 +157,6 @@ private final PySystemStateCloser closer; private static final ReferenceQueue systemStateQueue = new ReferenceQueue<PySystemState>(); private static final ConcurrentMap<WeakReference<PySystemState>, PySystemStateCloser> sysClosers = Generic.concurrentMap(); -// static { -// startCleanupThread(); -// } public PySystemState() { initialize(); @@ -1301,25 +1298,6 @@ closer.cleanup(); } - private static void startCleanupThread() { - Thread cleanupThread = new Thread(new Runnable() { - public void run() { - while (true) { - try { - Reference<PySystemStateCloser> ref = systemStateQueue.remove(); - PySystemStateCloser closer = sysClosers.get(ref); - closer.cleanup(); - sysClosers.remove(ref); - } catch (InterruptedException ex) { - break; - } - } - } - }); - cleanupThread.setDaemon(true); - cleanupThread.start(); - } - private static class PySystemStateCloser { private final Set<Callable> resourceClosers = new LinkedHashSet<Callable>(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2011-02-03 21:56:30
|
Revision: 7193 http://jython.svn.sourceforge.net/jython/?rev=7193&view=rev Author: amak Date: 2011-02-03 21:56:23 +0000 (Thu, 03 Feb 2011) Log Message: ----------- Checking in more support for IPV6, including support for 4-tuples including scope, etc. Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py trunk/jython/NEWS Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2011-02-02 10:36:55 UTC (rev 7192) +++ trunk/jython/Lib/socket.py 2011-02-03 21:56:23 UTC (rev 7193) @@ -314,26 +314,20 @@ def __init__(self, socket=None): if socket: self.jchannel = socket.getChannel() - self.host = socket.getInetAddress().getHostAddress() - self.port = socket.getPort() else: self.jchannel = java.nio.channels.SocketChannel.open() - self.host = None - self.port = None self.jsocket = self.jchannel.socket() self.socketio = org.python.core.io.SocketIO(self.jchannel, 'rw') - def bind(self, host, port, reuse_addr): + def bind(self, jsockaddr, reuse_addr): self.jsocket.setReuseAddress(reuse_addr) - self.jsocket.bind(java.net.InetSocketAddress(host, port)) + self.jsocket.bind(jsockaddr) - def connect(self, host, port): - self.host = host - self.port = port + def connect(self, jsockaddr): if self.mode == MODE_TIMEOUT: - self.jsocket.connect(java.net.InetSocketAddress(self.host, self.port), self._timeout_millis) + self.jsocket.connect (jsockaddr, self._timeout_millis) else: - self.jchannel.connect(java.net.InetSocketAddress(self.host, self.port)) + self.jchannel.connect(jsockaddr) def finish_connect(self): return self.jchannel.finishConnect() @@ -382,15 +376,11 @@ (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout', } - def __init__(self, host, port, backlog, reuse_addr): + def __init__(self, jsockaddr, backlog, reuse_addr): self.jchannel = java.nio.channels.ServerSocketChannel.open() self.jsocket = self.jchannel.socket() - if host: - bindaddr = java.net.InetSocketAddress(host, port) - else: - bindaddr = java.net.InetSocketAddress(port) self.jsocket.setReuseAddress(reuse_addr) - self.jsocket.bind(bindaddr, backlog) + self.jsocket.bind(jsockaddr, backlog) self.socketio = org.python.core.io.ServerSocketIO(self.jchannel, 'rw') def accept(self): @@ -422,20 +412,16 @@ (SOL_SOCKET, SO_TIMEOUT): 'SoTimeout', } - def __init__(self, port=None, address=None, reuse_addr=0): + def __init__(self, jsockaddr=None, reuse_addr=0): self.jchannel = java.nio.channels.DatagramChannel.open() self.jsocket = self.jchannel.socket() - if port is not None: - if address is not None: - local_address = java.net.InetSocketAddress(address, port) - else: - local_address = java.net.InetSocketAddress(port) + if jsockaddr is not None: self.jsocket.setReuseAddress(reuse_addr) - self.jsocket.bind(local_address) + self.jsocket.bind(jsockaddr) self.socketio = org.python.core.io.DatagramSocketIO(self.jchannel, 'rw') - def connect(self, host, port): - self.jchannel.connect(java.net.InetSocketAddress(host, port)) + def connect(self, jsockaddr): + self.jchannel.connect(jsockaddr) def disconnect(self): """ @@ -469,12 +455,11 @@ bytes_sent = self.jchannel.send(byte_buf, socket_address) return bytes_sent - def sendto(self, byte_array, host, port, flags): - socket_address = java.net.InetSocketAddress(host, port) + def sendto(self, byte_array, jsockaddr, flags): if self.mode == MODE_TIMEOUT: - return self._do_send_net(byte_array, socket_address, flags) + return self._do_send_net(byte_array, jsockaddr, flags) else: - return self._do_send_nio(byte_array, socket_address, flags) + return self._do_send_nio(byte_array, jsockaddr, flags) def send(self, byte_array, flags): if self.mode == MODE_TIMEOUT: @@ -526,8 +511,7 @@ else: return self._do_receive_nio(0, num_bytes, flags) -# For now, we DO NOT have complete IPV6 support. -has_ipv6 = False +has_ipv6 = True # IPV6 FTW! # Name and address functions @@ -607,6 +591,88 @@ assert protocol == IPPROTO_UDP, "Only IPPROTO_UDP supported on SOCK_DGRAM sockets" return _udpsocket() +class _ip_address_t: + + def __str__(self): + return "('%s', %d)" % (self.sockaddr, self.port) + +class _ipv4_address_t(_ip_address_t): + + def __init__(self, sockaddr, port, jaddress): + self.sockaddr = sockaddr + self.port = port + self.jaddress = jaddress + + def __getitem__(self, index): + if 0 == index: + return self.sockaddr + elif 1 == index: + return self.port + else: + raise IndexError() + + def __len__(self): + return 2 + +class _ipv6_address_t(_ip_address_t): + + def __init__(self, sockaddr, port, jaddress): + self.sockaddr = sockaddr + self.port = port + self.jaddress = jaddress + + def __getitem__(self, index): + if 0 == index: + return self.sockaddr + elif 1 == index: + return self.port + elif 2 == index: + return 0 + elif 3 == index: + return self.jaddress.scopeId + else: + raise IndexError() + + def __len__(self): + return 4 + +def _get_jsockaddr(address_object, for_udp=False): + if address_object is None: + return java.net.InetSocketAddress(0) # Let the system pick an ephemeral port + if isinstance(address_object, _ip_address_t): + return java.net.InetSocketAddress(address_object.jaddress, address_object[1]) + error_message = "Address must be a 2-tuple (ipv4: (host, port)) or a 4-tuple (ipv6: (host, port, flow, scope))" + if not isinstance(address_object, tuple) or \ + len(address_object) not in [2,4] or \ + not isinstance(address_object[0], basestring) or \ + not isinstance(address_object[1], (int, long)): + raise TypeError(error_message) + if len(address_object) == 4 and not isinstance(address_object[3], (int, long)): + raise TypeError(error_message) + hostname, port = address_object[0].strip(), address_object[1] + if for_udp: + if hostname == "": + hostname = INADDR_ANY + elif hostname == "<broadcast>": + hostname = INADDR_BROADCAST + else: + if hostname == "": + hostname = None + if hostname is None: + return java.net.InetSocketAddress(port) + if isinstance(hostname, unicode): + # XXX: Should be encode('idna') (See CPython + # socketmodule::getsockaddrarg), but Jython's idna support is + # currently broken + hostname = hostname.encode() + if len(address_object) == 4: + # There is no way to get a Inet6Address: Inet6Address.getByName() simply calls + # InetAddress.getByName,() which also returns Inet4Address objects + # If users want to use IPv6 address, scoped or not, + # they should use getaddrinfo(family=AF_INET6) + pass + return java.net.InetSocketAddress(java.net.InetAddress.getByName(hostname), port) + _ipv4_addresses_only = False def _use_ipv4_addresses_only(value): @@ -639,11 +705,12 @@ else: canonname = asPyString(a.getCanonicalHostName()) if host is None and passive_mode and not canonname_mode: - sockname = INADDR_ANY + sockaddr = INADDR_ANY else: - sockname = asPyString(a.getHostAddress()) + sockaddr = asPyString(a.getHostAddress()) # TODO: Include flowinfo and scopeid in a 4-tuple for IPv6 addresses - results.append((family, socktype, proto, canonname, (sockname, port))) + sock_tuple = {AF_INET : _ipv4_address_t, AF_INET6 : _ipv6_address_t}[family](sockaddr, port, a) + results.append((family, socktype, proto, canonname, sock_tuple)) return results except java.lang.Exception, jlx: raise _map_exception(jlx) @@ -800,24 +867,6 @@ def _get_jsocket(self): return self.sock_impl.jsocket -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 - error_message = "Address must be a tuple of (hostname, port)" - 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] - 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() - return hostname, address_tuple[1] - class _tcpsocket(_nonblocking_api_mixin): sock_impl = None @@ -833,7 +882,7 @@ assert not self.sock_impl assert not self.local_addr # Do the address format check - _unpack_address_tuple(addr) + _get_jsockaddr(addr) self.local_addr = addr def listen(self, backlog): @@ -841,11 +890,7 @@ try: assert not self.sock_impl self.server = 1 - if self.local_addr: - host, port = _unpack_address_tuple(self.local_addr) - else: - host, port = "", 0 - self.sock_impl = _server_socket_impl(host, port, backlog, self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ]) + self.sock_impl = _server_socket_impl(_get_jsockaddr(self.local_addr), backlog, self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ]) self._config() except java.lang.Exception, jlx: raise _map_exception(jlx) @@ -867,22 +912,14 @@ except java.lang.Exception, jlx: raise _map_exception(jlx) - def _get_host_port(self, addr): - host, port = _unpack_address_tuple(addr) - if host == "": - host = java.net.InetAddress.getLocalHost() - return host, port - def _do_connect(self, addr): try: assert not self.sock_impl - host, port = self._get_host_port(addr) 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[ (SOL_SOCKET, SO_REUSEADDR) ]) + self.sock_impl.bind(_get_jsockaddr(self.local_addr), self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ]) self._config() # Configure timeouts, etc, now that the socket exists - self.sock_impl.connect(host, port) + self.sock_impl.connect(_get_jsockaddr(addr)) except java.lang.Exception, jlx: raise _map_exception(jlx) @@ -983,7 +1020,7 @@ class _udpsocket(_nonblocking_api_mixin): sock_impl = None - addr = None + connected = False def __init__(self): _nonblocking_api_mixin.__init__(self) @@ -991,24 +1028,19 @@ def bind(self, addr): try: assert not self.sock_impl - 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[ (SOL_SOCKET, SO_REUSEADDR) ]) + self.sock_impl = _datagram_socket_impl(_get_jsockaddr(addr, True), self.pending_options[ (SOL_SOCKET, SO_REUSEADDR) ]) self._config() except java.lang.Exception, jlx: raise _map_exception(jlx) def _do_connect(self, addr): try: - host, port = _unpack_address_tuple(addr) - assert not self.addr - self.addr = addr + assert not self.connected, "Datagram Socket is already connected" if not self.sock_impl: self.sock_impl = _datagram_socket_impl() self._config() - self.sock_impl.connect(host, port) + self.sock_impl.connect(_get_jsockaddr(addr)) + self.connected = True except java.lang.Exception, jlx: raise _map_exception(jlx) @@ -1029,17 +1061,14 @@ if not self.sock_impl: self.sock_impl = _datagram_socket_impl() self._config() - 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) + result = self.sock_impl.sendto(byte_array, _get_jsockaddr(addr, True), flags) return result except java.lang.Exception, jlx: raise _map_exception(jlx) def send(self, data, flags=None): - if not self.addr: raise error(errno.ENOTCONN, "Socket is not connected") + if not self.connected: raise error(errno.ENOTCONN, "Socket is not connected") byte_array = java.lang.String(data).getBytes('iso-8859-1') return self.sock_impl.send(byte_array, flags) Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2011-02-02 10:36:55 UTC (rev 7192) +++ trunk/jython/Lib/test/test_socket.py 2011-02-03 21:56:23 UTC (rev 7193) @@ -1502,6 +1502,73 @@ doAddressTest(socket.getaddrinfo("localhost", 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, 0)) socket._use_ipv4_addresses_only(False) + def testAddrTupleTypes(self): + ipv4_address_tuple = socket.getaddrinfo("localhost", 80, socket.AF_INET, socket.SOCK_STREAM, 0, 0)[0][4] + self.failUnlessEqual(ipv4_address_tuple[0], "127.0.0.1") + self.failUnlessEqual(ipv4_address_tuple[1], 80) + self.failUnlessRaises(IndexError, lambda: ipv4_address_tuple[2]) + self.failUnlessEqual(str(ipv4_address_tuple), "('127.0.0.1', 80)") + + ipv6_address_tuple = socket.getaddrinfo("localhost", 80, socket.AF_INET6, socket.SOCK_STREAM, 0, 0)[0][4] + self.failUnless (ipv6_address_tuple[0] in ["::1", "0:0:0:0:0:0:0:1"]) + self.failUnlessEqual(ipv6_address_tuple[1], 80) + self.failUnlessEqual(ipv6_address_tuple[2], 0) + # Can't have an expectation for scope + try: + ipv6_address_tuple[3] + except IndexError: + self.fail("Failed to retrieve third element of ipv6 4-tuple") + self.failUnlessRaises(IndexError, lambda: ipv6_address_tuple[4]) + self.failUnless(str(ipv6_address_tuple) in ["('::1', 80)", "('0:0:0:0:0:0:0:1', 80)"]) + +class TestJython_get_jsockaddr(unittest.TestCase): + "These tests are specific to jython: they test a key internal routine" + + def testIPV4AddressesFromGetAddrInfo(self): + local_addr = socket.getaddrinfo("localhost", 80, socket.AF_INET, socket.SOCK_STREAM, 0, 0)[0][4] + sockaddr = socket._get_jsockaddr(local_addr) + self.failUnless(isinstance(sockaddr, java.net.InetSocketAddress), "_get_jsockaddr returned wrong type: '%s'" % str(type(sockaddr))) + self.failUnlessEqual(sockaddr.address.hostAddress, "127.0.0.1") + self.failUnlessEqual(sockaddr.port, 80) + + def testIPV6AddressesFromGetAddrInfo(self): + local_addr = socket.getaddrinfo("localhost", 80, socket.AF_INET6, socket.SOCK_STREAM, 0, 0)[0][4] + sockaddr = socket._get_jsockaddr(local_addr) + self.failUnless(isinstance(sockaddr, java.net.InetSocketAddress), "_get_jsockaddr returned wrong type: '%s'" % str(type(sockaddr))) + self.failUnless(sockaddr.address.hostAddress in ["::1", "0:0:0:0:0:0:0:1"]) + self.failUnlessEqual(sockaddr.port, 80) + + def testAddressesFrom2Tuple(self): + for addr_tuple in [ + ("localhost", 80), + ]: + sockaddr = socket._get_jsockaddr(addr_tuple) + self.failUnless(isinstance(sockaddr, java.net.InetSocketAddress), "_get_jsockaddr returned wrong type: '%s'" % str(type(sockaddr))) + self.failUnless(sockaddr.address.hostAddress in ["127.0.0.1", "::1", "0:0:0:0:0:0:0:1"]) + self.failUnlessEqual(sockaddr.port, 80) + + def testAddressesFrom4Tuple(self): + # This test disabled: cannot construct IPV6 addresses from 4-tuple + return + for addr_tuple in [ + ("localhost", 80, 0, 0), + ]: + sockaddr = socket._get_jsockaddr(addr_tuple) + self.failUnless(isinstance(sockaddr, java.net.InetSocketAddress), "_get_jsockaddr returned wrong type: '%s'" % str(type(sockaddr))) + self.failUnless(isinstance(sockaddr.address, java.net.Inet6Address), "_get_jsockaddr returned wrong address type: '%s'" % str(type(sockaddr.address))) + self.failUnless(sockaddr.address.hostAddress in ["::1", "0:0:0:0:0:0:0:1"]) + self.failUnlessEqual(sockaddr.address.scopeId, 0) + self.failUnlessEqual(sockaddr.port, 80) + + def testSpecialHostnames(self): + for addr_tuple, for_udp, expected_hostname in [ + ( ("", 80), False, socket.INADDR_ANY), + ( ("", 80), True, socket.INADDR_ANY), + ( ("<broadcast>", 80), True, socket.INADDR_BROADCAST), + ]: + sockaddr = socket._get_jsockaddr(addr_tuple, for_udp) + self.failUnlessEqual(sockaddr.hostName, expected_hostname, "_get_jsockaddr returned wrong hostname '%s' for special hostname '%s'" % (sockaddr.hostName, expected_hostname)) + class TestExceptions(unittest.TestCase): def testExceptionTree(self): @@ -1728,10 +1795,12 @@ if sys.platform[:4] == 'java': tests.append(TestJythonTCPExceptions) tests.append(TestJythonUDPExceptions) + tests.append(TestJython_get_jsockaddr) # TODO: Broadcast requires permission, and is blocked by some firewalls # Need some way to discover the network setup on the test machine if False: tests.append(UDPBroadcastTest) +# tests = [TestJython_get_jsockaddr] suites = [unittest.makeSuite(klass, 'test') for klass in tests] test_support.run_suite(unittest.TestSuite(suites)) Modified: trunk/jython/NEWS =================================================================== --- trunk/jython/NEWS 2011-02-02 10:36:55 UTC (rev 7192) +++ trunk/jython/NEWS 2011-02-03 21:56:23 UTC (rev 7193) @@ -5,6 +5,7 @@ - [ 1667 ] thread.local subclasses with constructor params fail - [ 1698 ] warnings module fails under JSR-223 - [ 1697 ] Wrong error message when http connection can not be established + - [ 1210 ] Lib/socket.py doesn't allow IPv6 sockets and fails with an AssertionError - [ 1700 ] "virtualenv is not compatible" to 2.5.2rc3 Jython 2.5.2rc3 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |