From jython-checkins at python.org Sat May 5 08:34:13 2018 From: jython-checkins at python.org (jeff.allen) Date: Sat, 05 May 2018 12:34:13 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Trivial_reformatting_to_Py?= =?utf-8?q?SystemState_=28whitespace_and_comments=29=2E?= Message-ID: <20180505123413.1.7BEE95416EA1F276@mg.python.org> https://hg.python.org/jython/rev/6b912cfd485a changeset: 8159:6b912cfd485a user: Jeff Allen date: Fri May 04 09:02:01 2018 +0100 summary: Trivial reformatting to PySystemState (whitespace and comments). Some coding standard conformance ahead of substantive changes. Also, beefed up the Javadoc to getNativePlatform, partly because it's more portable than defending the comments against the formatter. files: src/org/python/core/PySystemState.java | 325 +++++++----- 1 files changed, 182 insertions(+), 143 deletions(-) diff --git a/src/org/python/core/PySystemState.java b/src/org/python/core/PySystemState.java --- a/src/org/python/core/PySystemState.java +++ b/src/org/python/core/PySystemState.java @@ -32,8 +32,6 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.jar.JarEntry; import java.util.jar.JarFile; -import jnr.posix.util.Platform; -import com.carrotsearch.sizeof.RamUsageEstimator; import org.python.Version; import org.python.core.adapter.ClassicPyObjectAdapter; @@ -45,13 +43,17 @@ import org.python.modules.Setup; import org.python.util.Generic; +import com.carrotsearch.sizeof.RamUsageEstimator; + +import jnr.posix.util.Platform; + /** * The "sys" module. */ // xxx Many have lamented, this should really be a module! // but it will require some refactoring to see this wish come true. -public class PySystemState extends PyObject implements AutoCloseable, - ClassDictInit, Closeable, Traverseproc { +public class PySystemState extends PyObject + implements AutoCloseable, ClassDictInit, Closeable, Traverseproc { public static final String PYTHON_CACHEDIR = "python.cachedir"; public static final String PYTHON_CACHEDIR_SKIP = "python.cachedir.skip"; @@ -65,8 +67,8 @@ public static final PyString version = new PyString(Version.getVersion()); - public static final PyTuple subversion = new PyTuple(new PyString("Jython"), Py.newString(""), - Py.newString("")); + public static final PyTuple subversion = + new PyTuple(new PyString("Jython"), Py.newString(""), Py.newString("")); public static final int hexversion = ((Version.PY_MAJOR_VERSION << 24) | (Version.PY_MINOR_VERSION << 16) | (Version.PY_MICRO_VERSION << 8) @@ -89,22 +91,21 @@ public final static Class flags = Options.class; - public final static PyTuple _mercurial = new PyTuple( - Py.newString("Jython"), - Py.newString(Version.getHGIdentifier()), - Py.newString(Version.getHGVersion())); + public final static PyTuple _mercurial = new PyTuple(Py.newString("Jython"), + Py.newString(Version.getHGIdentifier()), Py.newString(Version.getHGVersion())); /** * The copyright notice for this release. */ - public static final PyObject copyright = Py.newString( - "Copyright (c) 2000-2017 Jython Developers.\n" + "All rights reserved.\n\n" + - "Copyright (c) 2000 BeOpen.com.\n" + "All Rights Reserved.\n\n" + - "Copyright (c) 2000 The Apache Software Foundation.\n" + "All rights reserved.\n\n" + - "Copyright (c) 1995-2000 Corporation for National Research Initiatives.\n" - + "All Rights Reserved.\n\n" + - "Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.\n" - + "All Rights Reserved."); + public static final PyObject copyright = + Py.newString("Copyright (c) 2000-2017 Jython Developers.\n" + "All rights reserved.\n\n" + + "Copyright (c) 2000 BeOpen.com.\n" + "All Rights Reserved.\n\n" + + "Copyright (c) 2000 The Apache Software Foundation.\n" + + "All rights reserved.\n\n" + + "Copyright (c) 1995-2000 Corporation for National Research Initiatives.\n" + + "All Rights Reserved.\n\n" + + "Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.\n" + + "All Rights Reserved."); private static Map builtinNames; public static PyTuple builtin_module_names = null; @@ -213,8 +214,8 @@ importLock = new ReentrantLock(); syspathJavaLoader = new SyspathJavaLoader(imp.getParentClassLoader()); - argv = (PyList)defaultArgv.repeat(1); - path = (PyList)defaultPath.repeat(1); + argv = (PyList) defaultArgv.repeat(1); + path = (PyList) defaultPath.repeat(1); path.append(Py.newString(JavaImporter.JAVA_IMPORT_PATH_ENTRY)); path.append(Py.newString(ClasspathPyImporter.PYCLASSPATH_PREFIX)); executable = defaultExecutable; @@ -269,39 +270,39 @@ } private static void checkReadOnly(String name) { - if (name == "__dict__" || name == "__class__" || name == "registry" - || name == "exec_prefix" || name == "packageManager") { + if (name == "__dict__" || name == "__class__" || name == "registry" || name == "exec_prefix" + || name == "packageManager") { throw Py.TypeError("readonly attribute"); } } private static void checkMustExist(String name) { - if (name == "__dict__" || name == "__class__" || name == "registry" - || name == "exec_prefix" || name == "platform" || name == "packageManager" - || name == "builtins" || name == "warnoptions") { + if (name == "__dict__" || name == "__class__" || name == "registry" || name == "exec_prefix" + || name == "platform" || name == "packageManager" || name == "builtins" + || name == "warnoptions") { throw Py.TypeError("readonly attribute"); } } /** * Initialise the encoding of sys.stdin, sys.stdout, and - * sys.stderr, and their error handling policy, from registry variables. - * Under the console app util.jython, values reflect PYTHONIOENCODING if not overridden. - * Note that the encoding must name a Python codec, as in codecs.encode(). + * sys.stderr, and their error handling policy, from registry variables. Under the + * console app util.jython, values reflect PYTHONIOENCODING if not overridden. Note that the + * encoding must name a Python codec, as in codecs.encode(). */ private void initEncoding() { // Two registry variables, counterparts to PYTHONIOENCODING = [encoding][:errors] String encoding = registry.getProperty(PYTHON_IO_ENCODING); String errors = registry.getProperty(PYTHON_IO_ERRORS); - if (encoding==null) { + if (encoding == null) { // We still don't have an explicit selection for this: match the console. encoding = Py.getConsole().getEncoding(); } - ((PyFile)stdin).setEncoding(encoding, errors); - ((PyFile)stdout).setEncoding(encoding, errors); - ((PyFile)stderr).setEncoding(encoding, "backslashreplace"); + ((PyFile) stdin).setEncoding(encoding, errors); + ((PyFile) stdout).setEncoding(encoding, errors); + ((PyFile) stderr).setEncoding(encoding, "backslashreplace"); } @Deprecated @@ -480,7 +481,7 @@ if (ts.tracefunc == null) { return Py.None; } else { - return ((PythonTraceFunction)ts.tracefunc).tracefunc; + return ((PythonTraceFunction) ts.tracefunc).tracefunc; } } @@ -498,7 +499,7 @@ if (ts.profilefunc == null) { return Py.None; } else { - return ((PythonTraceFunction)ts.profilefunc).tracefunc; + return ((PythonTraceFunction) ts.profilefunc).tracefunc; } } @@ -523,11 +524,14 @@ return FILE_SYSTEM_ENCODING; } + /* get and setcheckinterval really do nothing, but it helps when some code tries to use these */ + public PyInteger getcheckinterval() { + return new PyInteger(checkinterval); + } - /* get and setcheckinterval really do nothing, but it helps when some code tries to use these */ - public PyInteger getcheckinterval() { return new PyInteger(checkinterval); } - - public void setcheckinterval(int interval) { checkinterval = interval; } + public void setcheckinterval(int interval) { + checkinterval = interval; + } /** * Change the current working directory to the specified path. @@ -671,8 +675,8 @@ } /** - * Return the Windows drive letter from the start of the path, upper case, or 0 if - * the path does not start X: where X is a letter. + * Return the Windows drive letter from the start of the path, upper case, or 0 if the path does + * not start X: where X is a letter. * * @param path to examine * @return drive letter or char 0 if no drive letter @@ -685,13 +689,13 @@ return Character.toUpperCase(pathDrive); } } - return (char)0; + return (char) 0; } /** * Return the Windows UNC share name from the start of the path, or null if the - * path is not of Windows UNC type. The path has to be formed with Windows-backslashes: - * slashes '/' are not accepted as a substitute here. + * path is not of Windows UNC type. The path has to be formed with Windows-backslashes: slashes + * '/' are not accepted as a substitute here. * * @param path to examine * @return share name or null @@ -807,27 +811,61 @@ } /** - * Emulates CPython's way to name sys.platform. + * Emulates CPython's way to name sys.platform. Works according to this table: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
SystemValue
Linux (2.x and 3.x)linux2
Windowswin32
Windows/Cygwincygwin
Mac OS Xdarwin
OS/2os2
OS/2 EMXos2emx
RiscOSriscos
AtheOSatheos
+ * */ public static String getNativePlatform() { - /* Works according to this table: - System Value - -------------------------- - Linux (2.x and 3.x) linux2 - Windows win32 - Windows/Cygwin cygwin - Mac OS X darwin - OS/2 os2 - OS/2 EMX os2emx - RiscOS riscos - AtheOS atheos - */ String osname = System.getProperty("os.name"); - if (osname.equals("Linux")) return "linux2"; - if (osname.equals("Mac OS X")) return "darwin"; - if (osname.toLowerCase().contains("cygwin")) return "cygwin"; - if (osname.startsWith("Windows")) return "win32"; - return osname.replaceAll("[\\s/]", "").toLowerCase(); + if (osname.equals("Linux")) { + return "linux2"; + } else if (osname.equals("Mac OS X")) { + return "darwin"; + } else if (osname.toLowerCase().contains("cygwin")) { + return "cygwin"; + } else if (osname.startsWith("Windows")) { + return "win32"; + } else { + return osname.replaceAll("[\\s/]", "").toLowerCase(); + } } private static void initRegistry(Properties preProperties, Properties postProperties, @@ -880,9 +918,9 @@ } /* - * The console encoding is the one used by line-editing consoles to decode on the OS side and - * encode on the Python side. It must be a Java codec name, so any relationship to - * python.io.encoding is dubious. + * The console encoding is the one used by line-editing consoles to decode on the OS side + * and encode on the Python side. It must be a Java codec name, so any relationship to + * python.io.encoding is dubious. */ if (!registry.containsKey(PYTHON_CONSOLE_ENCODING)) { String encoding = getPlatformEncoding(); @@ -922,7 +960,7 @@ try { Method encodingMethod = java.io.Console.class.getDeclaredMethod("encoding"); encodingMethod.setAccessible(true); // private static method - encoding = (String)encodingMethod.invoke(Console.class); + encoding = (String) encodingMethod.invoke(Console.class); } catch (Exception e) { // ignore any exception } @@ -975,7 +1013,8 @@ initialize(null, null); } - public static synchronized void initialize(Properties preProperties, Properties postProperties) { + public static synchronized void initialize(Properties preProperties, + Properties postProperties) { initialize(preProperties, postProperties, new String[] {""}); } @@ -1003,7 +1042,8 @@ try { ClassLoader context = Thread.currentThread().getContextClassLoader(); if (context != null) { - if (initialize(preProperties, postProperties, argv, classLoader, adapter, context)) { + if (initialize(preProperties, postProperties, argv, classLoader, adapter, + context)) { return; } } else { @@ -1048,8 +1088,8 @@ ClassLoader initializerClassLoader) { InputStream in = initializerClassLoader.getResourceAsStream(INITIALIZER_SERVICE); if (in == null) { - Py.writeDebug("initializer", "'" + INITIALIZER_SERVICE + "' not found on " - + initializerClassLoader); + Py.writeDebug("initializer", + "'" + INITIALIZER_SERVICE + "' not found on " + initializerClassLoader); return false; } BufferedReader r = new BufferedReader(new InputStreamReader(in, Charset.forName("UTF-8"))); @@ -1057,8 +1097,8 @@ try { className = r.readLine(); } catch (IOException e) { - Py.writeWarning("initializer", "Failed reading '" + INITIALIZER_SERVICE + "' from " - + initializerClassLoader); + Py.writeWarning("initializer", + "Failed reading '" + INITIALIZER_SERVICE + "' from " + initializerClassLoader); e.printStackTrace(System.err); return false; } @@ -1066,16 +1106,16 @@ try { initializer = initializerClassLoader.loadClass(className); } catch (ClassNotFoundException e) { - Py.writeWarning("initializer", "Specified initializer class '" + className - + "' not found, continuing"); + Py.writeWarning("initializer", + "Specified initializer class '" + className + "' not found, continuing"); return false; } try { - ((JythonInitializer)initializer.newInstance()).initialize(pre, post, argv, + ((JythonInitializer) initializer.newInstance()).initialize(pre, post, argv, sysClassLoader, adapter); } catch (Exception e) { - Py.writeWarning("initializer", "Failed initializing with class '" + className - + "', continuing"); + Py.writeWarning("initializer", + "Failed initializing with class '" + className + "', continuing"); e.printStackTrace(System.err); return false; } @@ -1105,7 +1145,7 @@ // other initializations initBuiltins(registry); -// initStaticFields(); + // initStaticFields(); // Initialize the path (and add system defaults) defaultPath = initPath(registry, standalone, jarFileName); @@ -1148,14 +1188,14 @@ } else if (Version.PY_RELEASE_LEVEL == 0xAA) { s = "snapshot"; } else { - throw new RuntimeException("Illegal value for PY_RELEASE_LEVEL: " - + Version.PY_RELEASE_LEVEL); + throw new RuntimeException( + "Illegal value for PY_RELEASE_LEVEL: " + Version.PY_RELEASE_LEVEL); } - return new PyVersionInfo( - Py.newInteger(Version.PY_MAJOR_VERSION), - Py.newInteger(Version.PY_MINOR_VERSION), - Py.newInteger(Version.PY_MICRO_VERSION), - Py.newString(s), + return new PyVersionInfo(// + Py.newInteger(Version.PY_MAJOR_VERSION), // + Py.newInteger(Version.PY_MINOR_VERSION), // + Py.newInteger(Version.PY_MICRO_VERSION), // + Py.newString(s), // Py.newInteger(Version.PY_RELEASE_SERIAL)); } @@ -1299,10 +1339,9 @@ /** * Convenience method wrapping {@link Py#writeWarning(String, String)} to issue a warning - * message something like: - * "console: Failed to load 'org.python.util.ReadlineConsole': msg.". It's only a warning - * because the interpreter will fall back to a plain console, but it is useful to know exactly - * why it didn't work. + * message something like: "console: Failed to load 'org.python.util.ReadlineConsole': + * msg.". It's only a warning because the interpreter will fall back to a plain console, + * but it is useful to know exactly why it didn't work. * * @param consoleName console class name we're trying to initialise * @param msg specific cause of the failure @@ -1560,11 +1599,14 @@ } @Override - public void close() { cleanup(); } + public void close() { + cleanup(); + } public static class PySystemStateCloser { - private final Set> resourceClosers = Collections.synchronizedSet(new LinkedHashSet>()); + private final Set> resourceClosers = + Collections.synchronizedSet(new LinkedHashSet>()); private volatile boolean isCleanup = false; private final Thread shutdownHook; @@ -1619,13 +1661,14 @@ // Re-enable the management of resource closers isCleanup = false; } + private synchronized void runClosers() { // resourceClosers can be null in some strange cases if (resourceClosers != null) { /* - * Although a Set, the container iterates in the order closers were added. Make a Deque - * of it and deal from the top. - */ + * Although a Set, the container iterates in the order closers were added. Make a + * Deque of it and deal from the top. + */ LinkedList> rc = new LinkedList>(resourceClosers); Iterator> iter = rc.descendingIterator(); @@ -1643,7 +1686,8 @@ // Python scripts expect that files are closed upon an orderly cleanup of the VM. private Thread initShutdownCloser() { try { - Thread shutdownHook = new Thread(new ShutdownCloser(this), "Jython Shutdown Closer"); + Thread shutdownHook = + new Thread(new ShutdownCloser(this), "Jython Shutdown Closer"); Runtime.getRuntime().addShutdownHook(shutdownHook); return shutdownHook; } catch (SecurityException se) { @@ -1653,6 +1697,7 @@ } private class ShutdownCloser implements Runnable { + PySystemStateCloser closer = null; public ShutdownCloser(PySystemStateCloser closer) { @@ -1672,18 +1717,17 @@ } /** - * Backed as follows: - * Windows: cmd.exe /C ver (part after "Windows") - * Other: uname -v + * Attempt to find the OS version. The mechanism on Windows is to extract it from + * the result of cmd.exe /C ver, and otherwise (assumed Unix-like OS) + * to use uname -v. */ public static String getSystemVersionString() { try { String uname_sysver; boolean win = System.getProperty("os.name").startsWith("Windows"); - Process p = Runtime.getRuntime().exec( - win ? "cmd.exe /C ver" : "uname -v"); - java.io.BufferedReader br = new java.io.BufferedReader( - new java.io.InputStreamReader(p.getInputStream())); + Process p = Runtime.getRuntime().exec(win ? "cmd.exe /C ver" : "uname -v"); + java.io.BufferedReader br = + new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream())); uname_sysver = br.readLine(); while (uname_sysver != null && uname_sysver.length() == 0) { uname_sysver = br.readLine(); @@ -1715,7 +1759,6 @@ } } - /* Traverseproc implementation */ @Override public int traverse(Visitproc visit, Object arg) { @@ -1869,17 +1912,15 @@ @Override public boolean refersDirectlyTo(PyObject ob) { - return ob != null && (ob == argv || ob == modules || ob == path - || ob == warnoptions || ob == builtins || ob == platform - || ob == meta_path || ob == path_hooks || ob == path_importer_cache - || ob == ps1 || ob == ps2 || ob == executable || ob == stdout - || ob == stderr || ob == stdin || ob == __stdout__ || ob == __stderr__ - || ob == __stdin__ || ob == __displayhook__ || ob == __excepthook__ - || ob == last_value || ob == last_type || ob == last_traceback - || ob ==__name__ || ob == __dict__); + return ob != null && (ob == argv || ob == modules || ob == path || ob == warnoptions + || ob == builtins || ob == platform || ob == meta_path || ob == path_hooks + || ob == path_importer_cache || ob == ps1 || ob == ps2 || ob == executable + || ob == stdout || ob == stderr || ob == stdin || ob == __stdout__ + || ob == __stderr__ || ob == __stdin__ || ob == __displayhook__ + || ob == __excepthook__ || ob == last_value || ob == last_type + || ob == last_traceback || ob == __name__ || ob == __dict__); } - /** * Helper abstracting common code from {@link ShutdownCloser#run()} and * {@link PySystemStateCloser#cleanup()} to close resources (such as still-open files). The @@ -1998,16 +2039,15 @@ @Override public PyString __repr__() { - return (PyString) Py.newString( - TYPE.fastGetName() + "(" + - "max=%r, max_exp=%r, max_10_exp=%r, min=%r, min_exp=%r, min_10_exp=%r, "+ - "dig=%r, mant_dig=%r, epsilon=%r, radix=%r, rounds=%r)").__mod__(this); + return (PyString) Py.newString(TYPE.fastGetName() + "(" + + "max=%r, max_exp=%r, max_10_exp=%r, min=%r, min_exp=%r, min_10_exp=%r, " + + "dig=%r, mant_dig=%r, epsilon=%r, radix=%r, rounds=%r)").__mod__(this); } - - /* Note for Traverseproc implementation: - * We needn't visit the fields, because they are also represented as tuple elements - * in the parent class. So deferring to super-implementation is sufficient. + /* + * Note for Traverseproc implementation: We needn't visit the fields, because they are also + * represented as tuple elements in the parent class. So deferring to super-implementation is + * sufficient. */ } @@ -2035,15 +2075,15 @@ @Override public PyString __repr__() { - return (PyString) Py.newString( - TYPE.fastGetName() + "(" + - "bits_per_digit=%r, sizeof_digit=%r)").__mod__(this); + return (PyString) Py + .newString(TYPE.fastGetName() + "(" + "bits_per_digit=%r, sizeof_digit=%r)") + .__mod__(this); } - - /* Note for Traverseproc implementation: - * We needn't visit the fields, because they are also represented as tuple elements - * in the parent class. So deferring to super-implementation is sufficient. + /* + * Note for Traverseproc implementation: We needn't visit the fields, because they are also + * represented as tuple elements in the parent class. So deferring to super-implementation is + * sufficient. */ } @@ -2074,38 +2114,37 @@ int minor = Integer.parseInt(sys_ver[1]); int build = Integer.parseInt(sys_ver[2]); if (major > 6) { - major = 6; minor = 2; build = 9200; + major = 6; + minor = 2; + build = 9200; } else if (major == 6 && minor > 2) { - minor = 2; build = 9200; + minor = 2; + build = 9200; } // emulate deprecation behavior of GetVersionEx: - return new WinVersion( - Py.newInteger(major), // major + return new WinVersion(Py.newInteger(major), // major Py.newInteger(minor), // minor Py.newInteger(build), // build Py.newInteger(2), // platform Py.EmptyString); // service_pack } catch (Exception e) { - return new WinVersion(Py.EmptyString, Py.EmptyString, - Py.EmptyString, Py.EmptyString, Py.EmptyString); + return new WinVersion(Py.EmptyString, Py.EmptyString, Py.EmptyString, Py.EmptyString, + Py.EmptyString); } } @Override public PyString __repr__() { - return (PyString) Py.newString( - TYPE.fastGetName() + "(major=%r, minor=%r, build=%r, " + - "platform=%r, service_pack=%r)").__mod__(this); + return (PyString) Py.newString(TYPE.fastGetName() + "(major=%r, minor=%r, build=%r, " + + "platform=%r, service_pack=%r)").__mod__(this); } - - /* Note for traverseproc implementation: - * We needn't visit the fields, because they are also represented as tuple elements - * in the parent class. So deferring to super-implementation is sufficient. + /* + * Note for traverseproc implementation: We needn't visit the fields, because they are also + * represented as tuple elements in the parent class. So deferring to super-implementation is + * sufficient. * - * (In CPython sys.getwindowsversion can have some keyword-only elements. So far - * we don't support these here. If that changes, an actual traverseproc implementation - * might be required. + * (In CPython sys.getwindowsversion can have some keyword-only elements. So far we don't + * support these here. If that changes, an actual traverseproc implementation might be required. */ } - -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat May 5 08:34:14 2018 From: jython-checkins at python.org (jeff.allen) Date: Sat, 05 May 2018 12:34:14 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Determine_console_encoding?= =?utf-8?q?_without_private_method_access_=28fixes_=232659=29?= Message-ID: <20180505123414.1.4246CCE773EBDAAA@mg.python.org> https://hg.python.org/jython/rev/9185f0a117f0 changeset: 8160:9185f0a117f0 user: Jeff Allen date: Sat May 05 12:03:43 2018 +0100 summary: Determine console encoding without private method access (fixes #2659) This change removes the reflective access to private method Console.encoding() to which Java 9 objects, simplifing the determination of encoding a little. We do not fall back to "file.encoding" as a guess, but on a hard-coded "utf-8". Use of chcp was contributed by Oti Humbel. Use of "locale charmap" awaits test on Unix-like platforms (check the Java property python.console.encoding). Sub-process management is factored out of getSystemVersionString for shared use. files: NEWS | 1 + src/org/python/core/PySystemState.java | 139 +++++++----- 2 files changed, 79 insertions(+), 61 deletions(-) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ Developement tip Bugs fixed + - [ 2659 ] Determine console encoding without access violation (Java 9) - [ 2662 ] IllegalAccessException accessing public abstract method via PyReflectedFunction - [ 2501 ] JAVA_STACK doesn't work (fixed for Windows launcher only) - [ 1866 ] Parser does not have mismatch token error messages caught by BaseRecognizer diff --git a/src/org/python/core/PySystemState.java b/src/org/python/core/PySystemState.java --- a/src/org/python/core/PySystemState.java +++ b/src/org/python/core/PySystemState.java @@ -13,7 +13,6 @@ import java.lang.ref.WeakReference; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; import java.security.AccessControlException; @@ -32,6 +31,8 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.python.Version; import org.python.core.adapter.ClassicPyObjectAdapter; @@ -923,10 +924,7 @@ * python.io.encoding is dubious. */ if (!registry.containsKey(PYTHON_CONSOLE_ENCODING)) { - String encoding = getPlatformEncoding(); - if (encoding != null) { - registry.put(PYTHON_CONSOLE_ENCODING, encoding); - } + registry.put(PYTHON_CONSOLE_ENCODING, getConsoleEncoding()); } // Set up options from registry @@ -934,37 +932,43 @@ } /** - * Return the encoding of the underlying platform, if we can work it out by any means at all. + * Try to determine the console encoding from the platform, if necessary using a sub-process to + * enquire. If everything fails, assume UTF-8. * - * @return the encoding of the underlying platform + * @return the console encoding (and never {@code null}) */ - private static String getPlatformEncoding() { - // first try to grab the Console encoding - String encoding = getConsoleEncoding(); - if (encoding == null) { - try { - // Not quite the console encoding (differs on Windows) - encoding = System.getProperty("file.encoding"); - } catch (SecurityException se) { - // ignore, can't do anything about it + private static String getConsoleEncoding() { + + // From Java 8 onwards, the answer may already be to hand in the registry: + String encoding = System.getProperty("sun.stdout.encoding"); + + if (encoding != null) { + return encoding; + + } else if (System.getProperty("os.name").startsWith("Windows")) { + // Go via the Windows code page built-in command "chcp". + String output = getCommandResult("cmd", "/c", "chcp"); + /* + * The output will be like "Active code page: 850" or maybe "Aktive Codepage: 1252." or + * "?? ?? ???: 949". Assume the first number with 2 or more digits is the code page. + */ + final Pattern DIGITS_PATTERN = Pattern.compile("[1-9]\\d+"); + Matcher matcher = DIGITS_PATTERN.matcher(output); + if (matcher.find()) { + return "cp".concat(output.substring(matcher.start(), matcher.end())); + } + + } else { + // Try a Unix-like "locale charmap". + String output = getCommandResult("locale", "charmap"); + // The result of "locale charmap" is just the charmap name ~ Charset or codec name. + if (output.length() > 0) { + return output; } } - return encoding; - } - /** - * @return the console encoding; can be null - */ - private static String getConsoleEncoding() { - String encoding = null; - try { - Method encodingMethod = java.io.Console.class.getDeclaredMethod("encoding"); - encodingMethod.setAccessible(true); // private static method - encoding = (String) encodingMethod.invoke(Console.class); - } catch (Exception e) { - // ignore any exception - } - return encoding; + // If we land here it is because we found no answer, and we will assume UTF-8. + return "utf-8"; } /** @@ -1717,46 +1721,59 @@ } /** - * Attempt to find the OS version. The mechanism on Windows is to extract it from - * the result of cmd.exe /C ver, and otherwise (assumed Unix-like OS) - * to use uname -v. + * Attempt to find the OS version. The mechanism on Windows is to extract it from the result of + * cmd.exe /C ver, and otherwise (assumed Unix-like OS) to use + * uname -v. */ public static String getSystemVersionString() { + if (System.getProperty("os.name").startsWith("Windows")) { + String ver = getCommandResult("cmd.exe", "/c", "ver"); + int start = ver.toLowerCase().indexOf("version "); + if (start != -1) { + start += 8; + int end = ver.length(); + if (ver.endsWith("]")) { + --end; + } + ver = ver.substring(start, end); + } + return ver; + } else { + return getCommandResult("uname", "-v"); + } + } + + /** + * Run a command as a sub-process and return as the result the first line of output that consist + * of more than white space. It returns "" on any kind of error. + * + * @param command as strings (as for ProcessBuilder) + * @return the first line with content, or "" + */ + private static String getCommandResult(String... command) { + String result = "", line = null; + ProcessBuilder pb = new ProcessBuilder(command); try { - String uname_sysver; - boolean win = System.getProperty("os.name").startsWith("Windows"); - Process p = Runtime.getRuntime().exec(win ? "cmd.exe /C ver" : "uname -v"); + Process p = pb.start(); java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream())); - uname_sysver = br.readLine(); - while (uname_sysver != null && uname_sysver.length() == 0) { - uname_sysver = br.readLine(); - } - // to end the process sanely in case we deal with some - // implementation that emits additional new-lines: - while (br.readLine() != null) { - ; + // We read to the end-of-stream in case the sub-process cannot end cleanly without. + while ((line = br.readLine()) != null) { + if (line.length() > 0 && result.length() == 0) { + // This is the first line with content (maybe). + result = line.trim(); + } } br.close(); + // Now we wait for the sub-process to terminate nicely. if (p.waitFor() != 0) { - // No fallback for sysver available - uname_sysver = ""; + // Bad exit status: don't take the result. + result = ""; } - if (win && uname_sysver.length() > 0) { - int start = uname_sysver.toLowerCase().indexOf("version "); - if (start != -1) { - start += 8; - int end = uname_sysver.length(); - if (uname_sysver.endsWith("]")) { - --end; - } - uname_sysver = uname_sysver.substring(start, end); - } - } - return uname_sysver; - } catch (Exception e) { - return ""; + } catch (IOException | InterruptedException | SecurityException e) { + result = ""; } + return result; } /* Traverseproc implementation */ -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat May 5 16:44:44 2018 From: jython-checkins at python.org (jeff.allen) Date: Sat, 05 May 2018 20:44:44 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_JNR_Posix_and_FFI_j?= =?utf-8?q?ars=2E_Contributes_to_=232656=2E?= Message-ID: <20180505204444.1.BDB2F066CCF33220@mg.python.org> https://hg.python.org/jython/rev/6bdc6cb2401f changeset: 8161:6bdc6cb2401f user: Jeff Allen date: Sat May 05 20:05:08 2018 +0100 summary: Update JNR Posix and FFI jars. Contributes to #2656. This helps a with suppressing warning messages about illegal reflective access, upsetting fewer of the tests that examine output from a subprocess. files: build.xml | 12 ++++++------ extlibs/jffi-1.2.15.jar | Bin extlibs/jffi-1.2.16.jar | Bin extlibs/jnr-ffi-2.1.5.jar | Bin extlibs/jnr-ffi-2.1.7.jar | Bin extlibs/jnr-posix-3.0.41.jar | Bin extlibs/jnr-posix-3.0.44.jar | Bin 7 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -154,11 +154,11 @@ - + - + - + @@ -603,10 +603,10 @@ - - + + - + diff --git a/extlibs/jffi-1.2.15.jar b/extlibs/jffi-1.2.15.jar deleted file mode 100644 index 0a100f9742d3e84700417890dc3b9ebb1ca35538..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/jffi-1.2.16.jar b/extlibs/jffi-1.2.16.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e253de5b1088af0042921ec07c507add06e5f858 GIT binary patch [stripped] diff --git a/extlibs/jnr-ffi-2.1.5.jar b/extlibs/jnr-ffi-2.1.5.jar deleted file mode 100644 index 0ada90e99e8da8e25cdd32ef72bde55f602349f2..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/jnr-ffi-2.1.7.jar b/extlibs/jnr-ffi-2.1.7.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..23d7e51a9fa8850123ae31025680f074db289861 GIT binary patch [stripped] diff --git a/extlibs/jnr-posix-3.0.41.jar b/extlibs/jnr-posix-3.0.41.jar deleted file mode 100644 index a5f72ca042cf9e7d87fb0f46b8cef8470dbe8938..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/jnr-posix-3.0.44.jar b/extlibs/jnr-posix-3.0.44.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2435a0d267ad23bea132f9cba6c845e0b5f211cf GIT binary patch [stripped] -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon May 7 08:12:21 2018 From: jython-checkins at python.org (jeff.allen) Date: Mon, 07 May 2018 12:12:21 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_Netty_jars_to_4=2E1?= =?utf-8?q?=2E24=2E_Contributes_to_=232656=2E?= Message-ID: <20180507121221.1.8AE372FBE9D28538@mg.python.org> https://hg.python.org/jython/rev/ead1cae7f8de changeset: 8162:ead1cae7f8de user: Jeff Allen date: Mon May 07 12:13:28 2018 +0100 summary: Update Netty jars to 4.1.24. Contributes to #2656. Eliminates warning messages about illegal reflective access. See also https://github.com/netty/netty/issues/7254 files: build.xml | 24 +++++----- extlibs/netty-buffer-4.1.11.Final.jar | Bin extlibs/netty-buffer-4.1.24.Final.jar | Bin extlibs/netty-codec-4.1.11.Final.jar | Bin extlibs/netty-codec-4.1.24.Final.jar | Bin extlibs/netty-common-4.1.11.Final.jar | Bin extlibs/netty-common-4.1.24.Final.jar | Bin extlibs/netty-handler-4.1.11.Final.jar | Bin extlibs/netty-handler-4.1.24.Final.jar | Bin extlibs/netty-resolver-4.1.11.Final.jar | Bin extlibs/netty-resolver-4.1.24.Final.jar | Bin extlibs/netty-transport-4.1.11.Final.jar | Bin extlibs/netty-transport-4.1.24.Final.jar | Bin 13 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -161,12 +161,12 @@ - - - - - - + + + + + + @@ -566,17 +566,17 @@ - + - + - + - + - + - + diff --git a/extlibs/netty-buffer-4.1.11.Final.jar b/extlibs/netty-buffer-4.1.11.Final.jar deleted file mode 100644 index 28d32ae3217b108d5f18e6b4c7f9b1a138963556..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/netty-buffer-4.1.24.Final.jar b/extlibs/netty-buffer-4.1.24.Final.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c309e99ca606f1cccbd5ab11dcd0f898b14a7857 GIT binary patch [stripped] diff --git a/extlibs/netty-codec-4.1.11.Final.jar b/extlibs/netty-codec-4.1.11.Final.jar deleted file mode 100644 index 4e6c46b275dd8a053804768779c1c72e54cc6449..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/netty-codec-4.1.24.Final.jar b/extlibs/netty-codec-4.1.24.Final.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6ca8e3da4601f3efe2d42686d7fca85bd9e73032 GIT binary patch [stripped] diff --git a/extlibs/netty-common-4.1.11.Final.jar b/extlibs/netty-common-4.1.11.Final.jar deleted file mode 100644 index c1db5980b47cf3db66b97591c8ded843f12bd12a..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/netty-common-4.1.24.Final.jar b/extlibs/netty-common-4.1.24.Final.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a5f89c8bf5b5bdac7396a610c480f379c3462049 GIT binary patch [stripped] diff --git a/extlibs/netty-handler-4.1.11.Final.jar b/extlibs/netty-handler-4.1.11.Final.jar deleted file mode 100644 index 19c510eada2ebb2ce3ae6508caa762407f48d742..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/netty-handler-4.1.24.Final.jar b/extlibs/netty-handler-4.1.24.Final.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e3e90ce2e140d02af44e3f1a8823ab1cb91bcfd2 GIT binary patch [stripped] diff --git a/extlibs/netty-resolver-4.1.11.Final.jar b/extlibs/netty-resolver-4.1.11.Final.jar deleted file mode 100644 index 41340f7b49e7df18e8a609697992da38ff07b95f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/netty-resolver-4.1.24.Final.jar b/extlibs/netty-resolver-4.1.24.Final.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fcbab834e3147319b489403e82aac7d0e8c0960f GIT binary patch [stripped] diff --git a/extlibs/netty-transport-4.1.11.Final.jar b/extlibs/netty-transport-4.1.11.Final.jar deleted file mode 100644 index 59843cf314ebcb8f0ea7c5025a45a9c9cd1c6f10..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/netty-transport-4.1.24.Final.jar b/extlibs/netty-transport-4.1.24.Final.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..63ad9edfc2052b1c41533b46d121e927c6f1e39f GIT binary patch [stripped] -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue May 8 18:16:18 2018 From: jython-checkins at python.org (jeff.allen) Date: Tue, 08 May 2018 22:16:18 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Avoid_private_member_acces?= =?utf-8?q?s_in_subprocess=2Epy=2E_Contributes_to_=232656=2E?= Message-ID: <20180508221618.1.5ACFE9B6C0107401@mg.python.org> https://hg.python.org/jython/rev/61eda8fd9356 changeset: 8163:61eda8fd9356 user: Jeff Allen date: Tue May 08 22:18:18 2018 +0100 summary: Avoid private member access in subprocess.py. Contributes to #2656. In Java 9, Process has a pid() method so we no longer have to setAccessible(). files: Lib/subprocess.py | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -432,6 +432,7 @@ import java.io.FileNotFoundException import java.lang.IllegalArgumentException import java.lang.IllegalThreadStateException + import java.lang.Process import java.lang.ProcessBuilder import java.lang.System import java.lang.Thread @@ -1417,7 +1418,12 @@ else: return field - if os._name not in _win_oses: + if hasattr(java.lang.Process, "pid"): # Java 9 onwards + + def _get_pid(self, pid_field=None): + return self._process.pid() + + elif os._name not in _win_oses: def _get_pid(self, pid_field='pid'): field = self._get_private_field(self._process, pid_field) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri May 18 14:18:10 2018 From: jython-checkins at python.org (jeff.allen) Date: Fri, 18 May 2018 18:18:10 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Clarify_contract_of_Py=2Ei?= =?utf-8?q?sInteractive_and_use_it_in_util=2Ejython=2Erun=28=29?= Message-ID: <20180518181810.1.F166A1102465950D@mg.python.org> https://hg.python.org/jython/rev/44ac35e36677 changeset: 8164:44ac35e36677 user: Jeff Allen date: Fri May 18 18:41:49 2018 +0100 summary: Clarify contract of Py.isInteractive and use it in util.jython.run() Change motivated by #2656, we avoid a warning in interactive mode but not yet for file arguments. See also #2686. files: src/org/python/core/Py.java | 44 +++++++++++--------- src/org/python/util/jython.java | 17 +++++-- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/org/python/core/Py.java b/src/org/python/core/Py.java --- a/src/org/python/core/Py.java +++ b/src/org/python/core/Py.java @@ -1726,31 +1726,37 @@ } /** - * Check (using the {@link POSIX} library and jnr-posix library) whether we are in - * an interactive environment. Amongst other things, this affects the type of console that may - * be legitimately installed during system initialisation. Note that the result may vary - * according to whether a jnr-posix native library is found along - * java.library.path, or the pure Java fall-back is used. + * Determine whether standard input is an interactive stream. This is not the same as + * deciding whether the interpreter is or should be in interactive mode. Amongst other things, + * this affects the type of console that may be legitimately installed during system + * initialisation. + *

+ * If the Java system property {@code python.launcher.tty} is defined and equal to {@code true} + * or {@code false}, then that provides the result. This property is normally supplied by the + * launcher. In the absence of this certainty, we try to find outusing {@code isatty()} in the + * Posix emulation library. Note that the result may vary according to whether a + * jnr-posix native library is found along java.library.path, or the + * pure Java fall-back is used. * - * @return true if (we think) we are in an interactive environment + * @return true if (we think) standard input is an interactive stream */ public static boolean isInteractive() { - // python.launcher.tty is authoratative; see http://bugs.jython.org/issue2325 - String isTTY = System.getProperty("python.launcher.tty"); - if (isTTY != null && isTTY.equals("true")) { - return true; + String tty = System.getProperty("python.launcher.tty"); + if (tty != null) { + // python.launcher.tty is authoritative; see http://bugs.jython.org/issue2325 + tty = tty.toLowerCase(); + if (tty.equals("true")) { + return true; + } else if (tty.equals("false")) { + return false; + } } - if (isTTY != null && isTTY.equals("false")) { - return false; - } - // Decide if System.in is interactive + // Base decision on whether System.in is interactive according to OS try { POSIX posix = POSIXFactory.getPOSIX(); - FileDescriptor in = FileDescriptor.in; - return posix.isatty(in); - } catch (SecurityException ex) { - return false; - } + return posix.isatty(FileDescriptor.in); + } catch (SecurityException ex) {} + return false; } private static final String IMPORT_SITE_ERROR = "" diff --git a/src/org/python/util/jython.java b/src/org/python/util/jython.java --- a/src/org/python/util/jython.java +++ b/src/org/python/util/jython.java @@ -219,6 +219,7 @@ } public static void run(String[] args) { + // Parse the command line options CommandLineOptions opts = new CommandLineOptions(); if (!opts.parse(args)) { @@ -249,10 +250,13 @@ addDefault(preProperties, PySystemState.PYTHON_IO_ERRORS, spec[1]); } + // If/when we interact with standard input, will we use a line-editing console? + boolean stdinIsInteractive = Py.isInteractive(); + // Decide if System.in is interactive if (!opts.fixInteractive || opts.interactive) { // The options suggest System.in is interactive: but only if isatty() agrees - opts.interactive = Py.isInteractive(); + opts.interactive = stdinIsInteractive; if (opts.interactive) { // Set the default console type if nothing else has addDefault(preProperties, "python.console", PYTHON_CONSOLE_CLASS); @@ -517,9 +521,12 @@ class CommandLineOptions { public String filename; - public boolean jar, interactive, notice; + public boolean jar, notice; public boolean runCommand, runModule; - public boolean fixInteractive; + /** True unless a file, module, jar, or command argument awaits execution. */ + public boolean interactive = true; + /** Eventually go interactive: reflects the -i ("inspect") flag. */ + public boolean fixInteractive = false; public boolean help, version; public String[] argv; public Properties properties; @@ -531,8 +538,8 @@ public CommandLineOptions() { filename = null; - jar = fixInteractive = false; - interactive = notice = true; + jar = false; + notice = true; runModule = false; properties = new Properties(); help = version = false; -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun May 20 14:14:58 2018 From: jython-checkins at python.org (jeff.allen) Date: Sun, 20 May 2018 18:14:58 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Make_the_calendar_used_by_?= =?utf-8?q?the_time_module_Gregorian_proleptic=2E?= Message-ID: <20180520181458.1.1EE5DC5082CD2CB0@mg.python.org> https://hg.python.org/jython/rev/db9b69e4e8ef changeset: 8165:db9b69e4e8ef user: Tom Bech date: Sun May 20 17:24:18 2018 +0100 summary: Make the calendar used by the time module Gregorian proleptic. Change to match CPython behaviour. files: src/org/python/modules/time/Time.java | 17 +++++++++----- 1 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/org/python/modules/time/Time.java b/src/org/python/modules/time/Time.java --- a/src/org/python/modules/time/Time.java +++ b/src/org/python/modules/time/Time.java @@ -226,12 +226,15 @@ } private static GregorianCalendar _tupletocal(PyTuple tup) { - return new GregorianCalendar(item(tup, 0), - item(tup, 1), - item(tup, 2), - item(tup, 3), - item(tup, 4), - item(tup, 5)); + GregorianCalendar gc = new GregorianCalendar(item(tup, 0), + item(tup, 1), + item(tup, 2), + item(tup, 3), + item(tup, 4), + item(tup, 5)); + + gc.setGregorianChange(new Date(Long.MIN_VALUE)); + return gc; } public static double mktime(PyTuple tup) { @@ -254,6 +257,8 @@ protected static PyTimeTuple _timefields(double secs, TimeZone tz) { GregorianCalendar cal = new GregorianCalendar(tz); cal.clear(); + cal.setGregorianChange(new Date(Long.MIN_VALUE)); + secs = secs * 1000; if (secs < Long.MIN_VALUE || secs > Long.MAX_VALUE) { throw Py.ValueError("timestamp out of range for platform time_t"); -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun May 20 14:14:58 2018 From: jython-checkins at python.org (jeff.allen) Date: Sun, 20 May 2018 18:14:58 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_a_test_for_Gregorian_p?= =?utf-8?q?roleptic_interpretation_in_time_module=2E?= Message-ID: <20180520181458.1.57402507EF24F8A5@mg.python.org> https://hg.python.org/jython/rev/b8ce85eacfda changeset: 8166:b8ce85eacfda user: Jeff Allen date: Sun May 20 18:41:41 2018 +0100 summary: Add a test for Gregorian proleptic interpretation in time module. Add test to test_time (which need not be Jython-specific) and update it with recent changes to test_time in CPython stdlib. Also, acknowledge Tom Bech as contributor of the related patch. files: ACKNOWLEDGMENTS | 5 +++-- Lib/test/test_time.py | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -3,7 +3,7 @@ Jython: Python for the Java Platform -Copyright (c) 2000-2017 Jython Developers. +Copyright (c) 2000-2018 Jython Developers. All rights reserved. Copyright (c) 2000 BeOpen.com. @@ -31,7 +31,7 @@ * Jar Jar Links, licensed under the Apache 2.0 License from Tonic Systems * Java Native Runtime, licensed under the Common Public License * JLine2, licensed under a BSD license -* JUnit, licenseed under Eclipse Public License 1.0 from the JUnit project +* JUnit, licensed under Eclipse Public License 1.0 from the JUnit project * Mock Runner, licensed under the Apache 1.1 license * Netty 4, licensed under the Apache 2.0 license from the Netty project * PyPy datetime module, licensed under the MIT License from the PyPy project @@ -179,6 +179,7 @@ James Mudd Mat Booth Alex Gaman + Tom Bech Local Variables: mode: indented-text diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -1,4 +1,7 @@ +# A version of the CPython stdlib test/test_time.py modified for Jython +# from test import test_support +import os import time import unittest @@ -238,6 +241,27 @@ t = time.gmtime() self.assertEqual(tuple(t), t) + EXAMPLES = { + 1526823094 : (2018, 5, 20, 13, 31, 34, 6, 140, 0), # recently + 1442224245.0 : (2015, 9, 14, 9, 50, 45, 0, 257, 0), # gravity + 768232800 : (1994, 5, 6, 14, 0, 0, 4, 126, 0), # tunnel + } + + if os.name=='posix' or os.name=='java': + # Times before 1970 are supported. + EXAMPLES.update({ + -14182940.0 : (1969, 7, 20, 20, 17, 40, 6, 201, 0), # moon + -6857222400 : (1752, 9, 14, 0, 0, 0, 3, 258, 0), # Gregorian (UK/US) + -6857222400 - 1 : (1752, 9, 13, 23, 59, 59, 2, 257, 0), + -12219292800 : (1582, 10, 15, 0, 0, 0, 4, 288, 0), # Gregorian (first adopters) + -12219292800 - 1 : (1582, 10, 14, 23, 59, 59, 3, 287, 0), + }) + + def test_gmtime_examples(self): + for seconds, ref in TimeTestCase.EXAMPLES.iteritems(): + t = time.gmtime(seconds) + self.assertEqual(tuple(t), ref) + def test_localtime_without_arg(self): lt0 = time.localtime() lt1 = time.localtime(None) -- Repository URL: https://hg.python.org/jython