From jython-checkins at python.org Wed Apr 1 21:09:41 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 01 Apr 2015 19:09:41 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_bin/jython=2Epy_to_not_?= =?utf-8?q?consume_subcommand_args?= Message-ID: <20150401190936.65769.40149@psf.io> https://hg.python.org/jython/rev/0e249e3bf60a changeset: 7634:0e249e3bf60a user: Jim Baker date: Wed Apr 01 13:05:01 2015 -0600 summary: Fix bin/jython.py to not consume subcommand args Part of fix for http://bugs.jython.org/issue2300 files: src/shell/jython.py | 56 +++++++++++++++++++++++++------- 1 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/shell/jython.py b/src/shell/jython.py --- a/src/shell/jython.py +++ b/src/shell/jython.py @@ -1,14 +1,11 @@ #!/usr/bin/env python2.7 -E # -*- coding: utf-8 -*- -# bin/jython.py -# Launch script for Jython, generally to be compiled by tools like py2exe. -# However it is an alternative to the bin/jython bash script. -# -# Designed to be executed by CPython 2.7, although it may make sense for some -# scenarios to be executed by Jython instead - inside a jar for example. -# -# FIXME consider how to use this to support standalone jython jar +# Launch script for Jython. It may be wrapped as an executable with +# tools like PyInstaller, creating jython.exe, or run directly. The +# installer will make this the default launcher under the name +# bin/jython if CPython 2.7 is available with the above shebang +# invocation. import argparse import glob @@ -24,7 +21,7 @@ is_windows = os.name == "nt" or (os.name == "java" and os._name == "nt") -def make_parser(): +def make_parser(provided_args): parser = argparse.ArgumentParser(description="Jython", add_help=False) parser.add_argument("-D", dest="properties", action="append") parser.add_argument("-J", dest="java", action="append") @@ -33,7 +30,7 @@ parser.add_argument("--help", "-h", action="store_true") parser.add_argument("--print", dest="print_requested", action="store_true") parser.add_argument("--profile", action="store_true") - args, remainder = parser.parse_known_args() + args, remainder = parser.parse_known_args(provided_args) items = args.java or [] args.java = [] @@ -56,7 +53,12 @@ except StopIteration: break if arg == "-cp" or arg == "-classpath": - args.classpath = next(r) + try: + args.classpath = next(r) + if args.classpath.startswith("-"): + parser.error("Invalid classpath for -classpath: %s" % repr(args.classpath)[1:]) + except StopIteration: + parser.error("-classpath requires an argument") else: r2.append(arg) remainder = r2 @@ -70,7 +72,7 @@ args.properties = props args.encoding = args.properties.get("file.encoding", None) - return parser, args, remainder + return parser, args class JythonCommand(object): @@ -279,13 +281,41 @@ """ +def split_launcher_args(args): + it = iter(args) + i = 1 + next(it) + while True: + try: + arg = next(it) + except StopIteration: + break + if arg.startswith("-D") or arg.startswith("-J") or \ + arg in ("--boot", "--jdb", "--help", "--print", "--profile"): + i += 1 + elif arg in ("-cp", "-classpath"): + i += 1 + try: + next(it) + i += 1 + except StopIteration: + break # will be picked up in argparse, where an error will be raised + elif arg == "--": + i += 1 + break + else: + break + return args[:i], args[i:] + + def main(): if sys.stdout.encoding: if sys.stdout.encoding.lower() == "cp65001": sys.exit("""Jython does not support code page 65001 (CP_UTF8). Please try another code page by setting it with the chcp command.""") sys.argv = [arg.decode(sys.stdout.encoding) for arg in sys.argv] - parser, args, jython_args = make_parser() + launcher_args, jython_args = split_launcher_args(sys.argv) + parser, args = make_parser(launcher_args) jython_command = JythonCommand(parser, args, jython_args) command = jython_command.command -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Apr 1 21:19:32 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 01 Apr 2015 19:19:32 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Rebuild_jython=2Eexe_launch?= =?utf-8?q?er_from_jython=2Epy_using_PyInstaller?= Message-ID: <20150401191931.59576.6350@psf.io> https://hg.python.org/jython/rev/2a4d36522fa6 changeset: 7635:2a4d36522fa6 user: Jim Baker date: Wed Apr 01 13:19:26 2015 -0600 summary: Rebuild jython.exe launcher from jython.py using PyInstaller Completes fix of http://bugs.jython.org/issue2300 files: src/shell/jython.exe | Bin 1 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/shell/jython.exe b/src/shell/jython.exe index 6c355cfcca0b46834c948785d323e2d3d93a36cf..61c68b6657c774bb7d40bcbb3d263411490695eb GIT binary patch [stripped] -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Apr 1 21:27:50 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 01 Apr 2015 19:27:50 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_setuptools_wheel_bundle?= =?utf-8?q?d_by_ensurepip_so_it_check_for_Windows_on_Jython?= Message-ID: <20150401192748.7478.44984@psf.io> https://hg.python.org/jython/rev/cbb7baea2f3e changeset: 7636:cbb7baea2f3e user: Jim Baker date: Wed Apr 01 13:27:35 2015 -0600 summary: Fix setuptools wheel bundled by ensurepip so it check for Windows on Jython Now uses https://github.com/jythontools/setuptools, which changes the check so it also accounts for os._name == "nt" to test if on Windows. This fork is temporary, and will be removed in a future release of Jython once this logic has been upstreamed. In addition, for cross-platform compatiblity, the wheel as built as follows: SETUPTOOLS_INSTALL_WINDOWS_SPECIFIC_FILES=1 jpip wheel git+https://github.com/jythontools/setuptools.git Fixes http://bugs.jython.org/issue2298 files: Lib/ensurepip/__init__.py | 2 +- Lib/ensurepip/_bundled/setuptools-11.3.1-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-14.3.2-py2.py3-none-any.whl | Bin 3 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -12,7 +12,7 @@ __all__ = ["version", "bootstrap"] -_SETUPTOOLS_VERSION = "11.3.1" +_SETUPTOOLS_VERSION = "14.3.2" _PIP_VERSION = "1.6" diff --git a/Lib/ensurepip/_bundled/setuptools-11.3.1-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-11.3.1-py2.py3-none-any.whl deleted file mode 100644 index 6892ff89b4f916c40a0044c18d4b41dbf73340e3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-14.3.2-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-14.3.2-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f983456bab03556737d6e04ba0be960a18007641 GIT binary patch [stripped] -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Apr 1 21:32:02 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 01 Apr 2015 19:32:02 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Updates_installer_to_use_jy?= =?utf-8?q?thon=2Eexe=2C_runs_ensurepip_if_selected?= Message-ID: <20150401193159.59580.34665@psf.io> https://hg.python.org/jython/rev/2056e662a1c6 changeset: 7637:2056e662a1c6 user: Jim Baker date: Wed Apr 01 13:31:54 2015 -0600 summary: Updates installer to use jython.exe, runs ensurepip if selected The installer on Windows no longer assumes jython.bat, but instead uses the jyhon.exe native launcher replacement. Now runs jython -m ensurepip if selected. Running ensurepip is now part of the standard installation as well. Fixes http://bugs.jython.org/issue2297 files: installer/src/java/org/python/util/install/ChildProcess.java | 93 ++- installer/src/java/org/python/util/install/ConsoleInstaller.java | 2 + installer/src/java/org/python/util/install/InstallationType.java | 22 +- installer/src/java/org/python/util/install/InstallerCommandLine.java | 1 + installer/src/java/org/python/util/install/JarInstaller.java | 27 +- installer/src/java/org/python/util/install/ProgressListener.java | 2 + installer/src/java/org/python/util/install/ProgressPage.java | 2 + installer/src/java/org/python/util/install/StartScriptGenerator.java | 241 +-------- installer/src/java/org/python/util/install/TextConstants.java | 2 + installer/src/java/org/python/util/install/TextConstants_de.java | 2 + installer/src/java/org/python/util/install/TextKeys.java | 2 + installer/src/java/org/python/util/install/TypePage.java | 12 +- installer/src/java/org/python/util/install/Wizard.java | 9 +- 13 files changed, 157 insertions(+), 260 deletions(-) diff --git a/installer/src/java/org/python/util/install/ChildProcess.java b/installer/src/java/org/python/util/install/ChildProcess.java --- a/installer/src/java/org/python/util/install/ChildProcess.java +++ b/installer/src/java/org/python/util/install/ChildProcess.java @@ -1,8 +1,14 @@ +// FIXME change to ProcessBuilder so we can set environment variables (specifically LC_ALL=C) + package org.python.util.install; import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; /** * Easy start of a child process. @@ -20,16 +26,23 @@ /** * Inner class for reading stdout of the child process and printing it onto the caller's stdout. */ - private class StdoutMonitor extends Thread { + private class OutputMonitor extends Thread { - private StdoutMonitor() {} + private final List output = new ArrayList<>(); + + private final InputStream inputStream; + + public OutputMonitor(InputStream inputStream) { + this.inputStream = inputStream; + } public void run() { - String line = null; - BufferedReader stdout = new BufferedReader(new InputStreamReader(_process.getInputStream())); + String line; + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); try { // blocks until input found or process dead - while ((line = stdout.readLine()) != null) { + while ((line = reader.readLine()) != null) { + output.add(line); if (!isSilent()) { System.out.println(line); } @@ -39,43 +52,20 @@ ioe.printStackTrace(); } } finally { - if (stdout != null) + if (reader != null) try { - stdout.close(); + reader.close(); } catch (IOException e) {} } } + + public List getOutput() { + return output; + } } - /** - * Inner class for reading stderr of the child process and printing it onto the caller's stderr. - */ - private class StderrMonitor extends Thread { - - private StderrMonitor() {} - - public void run() { - String line = null; - BufferedReader stderr = new BufferedReader(new InputStreamReader(_process.getErrorStream())); - try { - // blocks until input found or process dead - while ((line = stderr.readLine()) != null) { - if (!isSilent()) { - System.err.println(line); - } - } - } catch (IOException ioe) { - if (!isSilent()) { - ioe.printStackTrace(); - } - } finally { - if (stderr != null) - try { - stderr.close(); - } catch (IOException e) {} - } - } - } + private List stdout; + private List stderr; /** * Constant indicating no timeout at all. @@ -133,6 +123,11 @@ private boolean _silent = false; /** + * path for current working directory of the child process + */ + private Path _cwd; + + /** * Default constructor */ public ChildProcess() {} @@ -175,6 +170,10 @@ return _command; } + public void setCWD(Path cwd) { _cwd = cwd; } + + public Path getCWD() { return _cwd; } + /** * Set the timeout (how long should the calling process wait for the child). * @@ -267,12 +266,18 @@ // determine start time _startTime = System.currentTimeMillis(); // start the process - _process = Runtime.getRuntime().exec(getCommand()); + ProcessBuilder pb = new ProcessBuilder(); + pb.command(getCommand()); + pb.inheritIO(); + if (getCWD() != null) { + pb.directory(getCWD().toFile()); + } + _process = pb.start(); debugCommand(); // handle stdout and stderr - StdoutMonitor stdoutMonitor = new StdoutMonitor(); + OutputMonitor stdoutMonitor = new OutputMonitor(_process.getInputStream()); stdoutMonitor.start(); - StderrMonitor stderrMonitor = new StderrMonitor(); + OutputMonitor stderrMonitor = new OutputMonitor(_process.getErrorStream()); stderrMonitor.start(); // run the subprocess as long as wanted while (!isTimeout() && isAlive()) { @@ -292,6 +297,8 @@ System.out.println("[ChildProcess] ended itself"); } } + stdout = stdoutMonitor.getOutput(); + stderr = stderrMonitor.getOutput(); } catch (IOException ioe) { if (!isSilent()) { ioe.printStackTrace(); @@ -307,6 +314,14 @@ return _exitValue; } + public List getStdout() { + return stdout; + } + + public List getStderr() { + return stderr; + } + private void setExitValue(int exitValue) { _exitValue = exitValue; } diff --git a/installer/src/java/org/python/util/install/ConsoleInstaller.java b/installer/src/java/org/python/util/install/ConsoleInstaller.java --- a/installer/src/java/org/python/util/install/ConsoleInstaller.java +++ b/installer/src/java/org/python/util/install/ConsoleInstaller.java @@ -606,4 +606,6 @@ public void progressStandalone() { message(getText(C_PACKING_STANDALONE_JAR)); } + + public void progressEnsurepip() { message(getText(C_ENSUREPIP)); } } \ No newline at end of file diff --git a/installer/src/java/org/python/util/install/InstallationType.java b/installer/src/java/org/python/util/install/InstallationType.java --- a/installer/src/java/org/python/util/install/InstallationType.java +++ b/installer/src/java/org/python/util/install/InstallationType.java @@ -6,6 +6,7 @@ private boolean _installDemosAndExamples = true; private boolean _installDocumentation = true; private boolean _installSources = false; + private boolean _ensurepip = true; private boolean _isStandalone = false; public boolean installLibraryModules() { @@ -24,6 +25,10 @@ return _installSources; } + public boolean ensurepip() { + return _ensurepip; + } + public void addLibraryModules() { _installLibraryModules = true; } @@ -56,12 +61,17 @@ _installSources = false; } + public void addEnsurepip() { _ensurepip = true; } + + public void removeEnsurepip() { _ensurepip = false; } + public void setStandalone() { _isStandalone = true; addLibraryModules(); removeDemosAndExamples(); removeDocumentation(); removeSources(); + removeEnsurepip(); } public boolean isStandalone() { @@ -73,23 +83,27 @@ addDemosAndExamples(); addDocumentation(); addSources(); + addEnsurepip(); _isStandalone = false; } public boolean isAll() { - return installLibraryModules() && installDemosAndExamples() && installDocumentation() && installSources(); + return installLibraryModules() && installDemosAndExamples() && + installDocumentation() && installSources() && ensurepip(); } public void setStandard() { addLibraryModules(); addDemosAndExamples(); addDocumentation(); + addEnsurepip(); removeSources(); _isStandalone = false; } public boolean isStandard() { - return installLibraryModules() && installDemosAndExamples() && installDocumentation() && !installSources(); + return installLibraryModules() && installDemosAndExamples() && ensurepip() && + installDocumentation() && !installSources(); } public void setMinimum() { @@ -97,11 +111,13 @@ removeDemosAndExamples(); removeDocumentation(); removeSources(); + removeEnsurepip(); _isStandalone = false; } public boolean isMinimum() { - return !installLibraryModules() && !installDemosAndExamples() && !installDocumentation() && !installSources(); + return !installLibraryModules() && !installDemosAndExamples() && + !ensurepip() && !installDocumentation() && !installSources(); } /** diff --git a/installer/src/java/org/python/util/install/InstallerCommandLine.java b/installer/src/java/org/python/util/install/InstallerCommandLine.java --- a/installer/src/java/org/python/util/install/InstallerCommandLine.java +++ b/installer/src/java/org/python/util/install/InstallerCommandLine.java @@ -20,6 +20,7 @@ protected static final String INEXCLUDE_DEMOS_AND_EXAMPLES = "demo"; protected static final String INEXCLUDE_DOCUMENTATION = "doc"; protected static final String INEXCLUDE_SOURCES = "src"; + protected static final String INEXCLUDE_ENSUREPIP = "ensurepip"; protected static final String CONSOLE_SHORT = "c"; protected static final String CONSOLE_LONG = "console"; diff --git a/installer/src/java/org/python/util/install/JarInstaller.java b/installer/src/java/org/python/util/install/JarInstaller.java --- a/installer/src/java/org/python/util/install/JarInstaller.java +++ b/installer/src/java/org/python/util/install/JarInstaller.java @@ -5,6 +5,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -41,10 +42,11 @@ } /** - * Do the pysical installation: + * Do the physical installation: *
    *
  • unzip the files *
  • generate the start scripts + *
  • run ensurepip if selected *
* * @param targetDirectory @@ -144,6 +146,11 @@ _progressListener.progressStartScripts(); StartScriptGenerator generator = new StartScriptGenerator(targetDirectory, javaHomeHandler); generator.generateStartScripts(); + if (installationType.ensurepip()) { + _progressListener.progressEnsurepip(); + _progressListener.progressChanged(90); // approx + ensurepip(targetDirectory.toPath().resolve("bin")); + } } else { _progressListener.progressStandalone(); File jythonJar = new File(targetDirectory, JYTHON_JAR); @@ -169,6 +176,21 @@ } } + private int ensurepip(Path bindir) { + int errorCode = 0; + try { + String launcher = bindir.resolve("jython").toString(); + String command[] = new String[]{ + launcher, "-m", "ensurepip"}; + ChildProcess childProcess = new ChildProcess(command); + childProcess.setCWD(bindir); + errorCode = childProcess.run(); + } catch (Throwable t) { + errorCode = 1; + } + return errorCode; + } + public void addInstallationListener(InstallationListener installationListener) { if (installationListener != null) { _installationListeners.add(installationListener); @@ -193,6 +215,9 @@ if (installationType.installSources()) { numberOfEntries += 1000; } + if (installationType.ensurepip()) { + numberOfEntries += 2000; + } return numberOfEntries; } diff --git a/installer/src/java/org/python/util/install/ProgressListener.java b/installer/src/java/org/python/util/install/ProgressListener.java --- a/installer/src/java/org/python/util/install/ProgressListener.java +++ b/installer/src/java/org/python/util/install/ProgressListener.java @@ -12,4 +12,6 @@ public void progressStandalone(); + public void progressEnsurepip(); + } \ No newline at end of file diff --git a/installer/src/java/org/python/util/install/ProgressPage.java b/installer/src/java/org/python/util/install/ProgressPage.java --- a/installer/src/java/org/python/util/install/ProgressPage.java +++ b/installer/src/java/org/python/util/install/ProgressPage.java @@ -119,4 +119,6 @@ _progressEntry.setText(getText(PACKING_STANDALONE_JAR)); } + public void progressEnsurepip() { _progressEntry.setText(getText(C_ENSUREPIP)); } + } \ No newline at end of file diff --git a/installer/src/java/org/python/util/install/StartScriptGenerator.java b/installer/src/java/org/python/util/install/StartScriptGenerator.java --- a/installer/src/java/org/python/util/install/StartScriptGenerator.java +++ b/installer/src/java/org/python/util/install/StartScriptGenerator.java @@ -2,68 +2,29 @@ import java.io.File; import java.io.IOException; -import java.text.MessageFormat; -import java.util.Date; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.PosixFilePermissions; + public class StartScriptGenerator { - protected final static int UNIX_FLAVOUR = 10; - - protected final static int WINDOWS_FLAVOUR = 30; - - protected final static int BOTH_FLAVOUR = 50; - - protected final static String WIN_CR_LF; - - private final static String JAVA_HOME = "JAVA_HOME"; - - /** do not hard-wire JYTHON_HOME */ - private final static String JYTHON_HOME_FALLBACK = "JYTHON_HOME_FALLBACK"; - - private final static String JYTHON = "jython"; - - private final static String JYTHON_BAT = "jython.bat"; - static { - int dInt = Integer.parseInt("0d", 16); - int aInt = Integer.parseInt("0a", 16); - WIN_CR_LF = new String(new char[] {(char)dInt, (char)aInt}); - } - private File _targetDirectory; - private JavaHomeHandler _javaHomeHandler; - - private int _flavour; - public StartScriptGenerator(File targetDirectory, JavaHomeHandler javaHomeHandler) { _targetDirectory = targetDirectory; - _javaHomeHandler = javaHomeHandler; - if (Installation.isWindows()) { - setFlavour(WINDOWS_FLAVOUR); - } else { - // everything else defaults to unix at the moment - setFlavour(UNIX_FLAVOUR); - } } - protected void setFlavour(int flavour) { - _flavour = flavour; - if (flavour == WINDOWS_FLAVOUR) { - // check if we should create unix like scripts, too - if (hasUnixlikeShell()) { - _flavour = BOTH_FLAVOUR; - } - } - } - - protected int getFlavour() { - return _flavour; - } - - protected boolean hasUnixlikeShell() { + protected boolean hasCPython27() { int errorCode = 0; try { - String command[] = new String[] {"sh", "-c", "env"}; + String command[] = new String[]{ + "/usr/bin/env", "python2.7", "-E", + "-c", + "import sys; " + + "assert sys.version_info.major == 2 and sys.version_info.minor == 7, " + + "'Need Python 2.7, got %r' % (sys.version_info,)"}; long timeout = 3000; ChildProcess childProcess = new ChildProcess(command, timeout); childProcess.setDebug(false); @@ -76,169 +37,23 @@ } protected final void generateStartScripts() throws IOException { - File bin = new File(getTargetDirectory(), "bin"); - File bin_jython = new File(bin, JYTHON); - switch(getFlavour()){ - case BOTH_FLAVOUR: - writeToTargetDir(JYTHON_BAT, getJythonScript(WINDOWS_FLAVOUR)); - FileHelper.makeExecutable(writeToTargetDir(JYTHON, getJythonScript(BOTH_FLAVOUR))); - FileHelper.makeExecutable(bin_jython); - break; - case WINDOWS_FLAVOUR: - writeToTargetDir(JYTHON_BAT, getJythonScript(WINDOWS_FLAVOUR)); - // delete the *nix script in /bin dir - bin_jython.delete(); - break; - default: - FileHelper.makeExecutable(writeToTargetDir(JYTHON, getJythonScript(UNIX_FLAVOUR))); - FileHelper.makeExecutable(bin_jython); - // delete the windows script in /bin dir - File bin_jython_bat = new File(bin, JYTHON_BAT); - bin_jython_bat.delete(); - break; + Path bindir = _targetDirectory.toPath().resolve("bin"); + if (Installation.isWindows()) { + Files.delete(bindir.resolve("jython")); + Files.delete(bindir.resolve("jython.py")); + } + else { + if (hasCPython27()) { + Files.move(bindir.resolve("jython.py"), bindir.resolve("jython"), + StandardCopyOption.REPLACE_EXISTING); + } else { + Files.delete(bindir.resolve("jython.py")); + } + Files.delete(bindir.resolve("jython.exe")); + Files.delete(bindir.resolve("python27.dll")); + Files.setPosixFilePermissions(bindir.resolve("jython"), + PosixFilePermissions.fromString("rwxr-xr-x")); // 0755 } } - /** - * only protected for unit test use - */ - protected final String getJythonScript(int flavour) throws IOException { - if (flavour == WINDOWS_FLAVOUR) { - return getStartScript(getWindowsJythonTemplate()) + readFromFile(JYTHON_BAT); - } else { - return getStartScript(getUnixJythonTemplate()) + readFromFile(JYTHON); - } - } - - /** - * These placeholders are valid for all private methods: - * - * {0} : current date
- * {1} : user.name
- * {2} : target directory
- */ - private String getStartScript(String template) throws IOException { - String parameters[] = new String[4]; - parameters[0] = new Date().toString(); - parameters[1] = System.getProperty("user.name"); - parameters[2] = getTargetDirectory().getCanonicalPath(); - return MessageFormat.format(template, (Object[])parameters); - } - - /** - * placeholders: - * - * @see getStartScript - */ - private String getWindowsJythonTemplate() { - StringBuilder builder = getWindowsHeaderTemplate(); - builder.append("set "); - builder.append(JAVA_HOME); - builder.append("="); - if (_javaHomeHandler.isValidHome()) { - builder.append("\""); - builder.append(_javaHomeHandler.getHome().getAbsolutePath()); - builder.append("\""); - } - builder.append(WIN_CR_LF); - builder.append("set "); - builder.append(JYTHON_HOME_FALLBACK); - builder.append("=\"{2}\""); - builder.append(WIN_CR_LF); - builder.append(WIN_CR_LF); - return builder.toString(); - } - - /** - * placeholders: - * - * @see getStartScript - */ - private StringBuilder getWindowsHeaderTemplate() { - StringBuilder builder = new StringBuilder(1000); - builder.append("@echo off"); - builder.append(WIN_CR_LF); - builder.append("rem Prevent leak of environment variables"); - builder.append(WIN_CR_LF); - builder.append("setlocal"); - builder.append(WIN_CR_LF); - builder.append("rem This file was generated by the Jython installer"); - builder.append(WIN_CR_LF); - builder.append("rem Created on {0} by {1}"); - builder.append(WIN_CR_LF); - builder.append(WIN_CR_LF); - return builder; - } - - /** - * placeholders: - * - * @see getStartScript - */ - private String getUnixJythonTemplate() { - StringBuilder builder = getUnixHeaderTemplate(); - builder.append(JAVA_HOME); - builder.append("="); - if (_javaHomeHandler.isValidHome()) { - builder.append("\""); - builder.append(_javaHomeHandler.getHome().getAbsolutePath()); - builder.append("\""); - } - builder.append("\n"); - builder.append(JYTHON_HOME_FALLBACK); - builder.append("=\"{2}\"\n"); - builder.append("\n"); - return builder.toString(); - } - - /** - * placeholders: - * - * @see getStartScript - */ - private StringBuilder getUnixHeaderTemplate() { - StringBuilder builder = new StringBuilder(1000); - builder.append("#!/usr/bin/env bash\n"); - builder.append("\n"); - builder.append("# This file was generated by the Jython installer\n"); - builder.append("# Created on {0} by {1}\n"); - builder.append("\n"); - return builder; - } - - /** - * @param fileName - * The short file name, e.g. JYTHON_BAT - * - * @throws IOException - */ - private String readFromFile(String fileName) throws IOException { - // default runtime location - File targetDirectory = getTargetDirectory(); - File file = new File(new File(targetDirectory, "bin"), fileName); - if (!file.exists()) { - // deviation: test time location - file = new File(targetDirectory, fileName); - } - return FileHelper.readAll(file); - } - - /** - * Create (or overwrite) the specified file in the target directory - * - * @param fileName - * The short file name, e.g. JYTHON_BAT - * @param contents - * - * @throws IOException - */ - private File writeToTargetDir(String fileName, String contents) throws IOException { - File file = new File(getTargetDirectory(), fileName); - FileHelper.write(file, contents); - return file; - } - - private File getTargetDirectory() { - return _targetDirectory; - } } diff --git a/installer/src/java/org/python/util/install/TextConstants.java b/installer/src/java/org/python/util/install/TextConstants.java --- a/installer/src/java/org/python/util/install/TextConstants.java +++ b/installer/src/java/org/python/util/install/TextConstants.java @@ -25,6 +25,7 @@ { DOCUMENTATION, "Documentation" }, // installation type { EMPTY_TARGET_DIRECTORY, "Target directory must not be empty" }, // error { ENGLISH, "English" }, // language + { ENSUREPIP, "Install pip and setuptools"}, { ERROR, "Error" }, // error { ERROR_ACCESS_JARFILE, "Error accessing jar file" }, // error { FINISH, "Finish" }, // button @@ -95,6 +96,7 @@ { C_ENTER_TARGET_DIRECTORY, "Please enter the target directory" }, // console { C_ENTER_JAVA_HOME, "Please enter the java home directory (empty for using the current java runtime)" }, // console { C_ENGLISH, "English" }, // language + { C_ENSUREPIP, "Installing pip and setuptools"}, { C_EXCLUDE, "Do you want to exclude parts from the installation ?" }, // installation type { C_GENERATING_START_SCRIPTS, "Generating start scripts ..." }, // progress { C_GERMAN, "German" }, // language diff --git a/installer/src/java/org/python/util/install/TextConstants_de.java b/installer/src/java/org/python/util/install/TextConstants_de.java --- a/installer/src/java/org/python/util/install/TextConstants_de.java +++ b/installer/src/java/org/python/util/install/TextConstants_de.java @@ -25,6 +25,7 @@ { DO_NOT_ACCEPT, "Nein, ich akzeptiere nicht" }, // license { EMPTY_TARGET_DIRECTORY, "Das Zielverzeichnis darf nicht leer sein" }, // error { ENGLISH, "Englisch" }, // language + { ENSUREPIP, "Installieren pip und setuptools"}, { ERROR, "Fehler" }, // error { ERROR_ACCESS_JARFILE, "Problem beim Zugriff auf das jar File" }, // error { FINISH, "Beenden" }, // button @@ -96,6 +97,7 @@ { C_ENTER_TARGET_DIRECTORY, "Bitte geben Sie das Zielverzeichnis ein" }, // console { C_ENTER_JAVA_HOME, "Bitte geben Sie das gewuenschte Java Home Verzeichnis ein (Enter fuer das aktuelle)" }, // console { C_ENGLISH, "Englisch" }, // language + { C_ENSUREPIP, "Installieren pip und setuptools"}, { C_EXCLUDE, "Moechten Sie Teile von der Installation ausschliessen ?" }, // installation type { C_GENERATING_START_SCRIPTS, "Start Scripts werden generiert ..." }, // progress { C_GERMAN, "Deutsch" }, // language diff --git a/installer/src/java/org/python/util/install/TextKeys.java b/installer/src/java/org/python/util/install/TextKeys.java --- a/installer/src/java/org/python/util/install/TextKeys.java +++ b/installer/src/java/org/python/util/install/TextKeys.java @@ -20,6 +20,7 @@ public static final String DO_NOT_ACCEPT = "DO_NOT_ACCEPT"; public static final String EMPTY_TARGET_DIRECTORY = "EMPTY_TARGET_DIRECTORY"; public static final String ENGLISH = "ENGLISH"; + public static final String ENSUREPIP = "ENSUREPIP"; public static final String ERROR = "ERROR"; public static final String ERROR_ACCESS_JARFILE = "ERROR_ACCESS_JARFILE"; public static final String FINISH = "FINISH"; @@ -88,6 +89,7 @@ public static final String C_CONGRATULATIONS = "C_CONGRATULATIONS"; public static final String C_CREATE_DIRECTORY = "C_CREATE_DIRECTORY"; public static final String C_ENGLISH = "C_ENGLISH"; + public static final String C_ENSUREPIP = "C_ENSUREPIP"; public static final String C_ENTER_TARGET_DIRECTORY = "C_ENTER_TARGET_DIRECTORY"; public static final String C_ENTER_JAVA_HOME = "C_ENTER_JAVA_HOME"; public static final String C_EXCLUDE = "C_EXCLUDE"; diff --git a/installer/src/java/org/python/util/install/TypePage.java b/installer/src/java/org/python/util/install/TypePage.java --- a/installer/src/java/org/python/util/install/TypePage.java +++ b/installer/src/java/org/python/util/install/TypePage.java @@ -29,6 +29,7 @@ private JCheckBox _demo; private JCheckBox _doc; private JCheckBox _src; + private JCheckBox _ensurepip; private boolean _firstTime = true; @@ -90,15 +91,20 @@ _src.setEnabled(true); _src.setActionCommand(InstallerCommandLine.INEXCLUDE_SOURCES); _src.addActionListener(typeChangeListener); + _ensurepip = new JCheckBox(); + _ensurepip.setEnabled(true); + _ensurepip.setActionCommand(InstallerCommandLine.INEXCLUDE_ENSUREPIP); + _ensurepip.addActionListener(typeChangeListener); JPanel checkboxPanel = new JPanel(); - GridLayout gridLayout = new GridLayout(5, 1); + GridLayout gridLayout = new GridLayout(6, 1); checkboxPanel.setLayout(gridLayout); checkboxPanel.add(_core); checkboxPanel.add(_mod); checkboxPanel.add(_demo); checkboxPanel.add(_doc); checkboxPanel.add(_src); + checkboxPanel.add(_ensurepip); JPanel panel = new JPanel(); GridBagLayout gridBagLayout = new GridBagLayout(); @@ -178,6 +184,7 @@ _demo.setText(getText(DEMOS_EXAMPLES)); _doc.setText(getText(DOCUMENTATION)); _src.setText(getText(SOURCES)); + _ensurepip.setText(getText(ENSUREPIP)); setCheckboxes(installationType); } @@ -220,6 +227,7 @@ _demo.setEnabled(true); _doc.setEnabled(true); _src.setEnabled(true); + _ensurepip.setEnabled(true); } else { boolean selected = ((JCheckBox) e.getSource()).isSelected(); if (InstallerCommandLine.INEXCLUDE_LIBRARY_MODULES.equals(actionCommand)) { @@ -258,11 +266,13 @@ _demo.setSelected(installationType.installDemosAndExamples()); _doc.setSelected(installationType.installDocumentation()); _src.setSelected(installationType.installSources()); + _ensurepip.setSelected(installationType.ensurepip()); _standaloneButton.setSelected(installationType.isStandalone()); _mod.setEnabled(!installationType.isPredefined()); _demo.setEnabled(!installationType.isPredefined()); _doc.setEnabled(!installationType.isPredefined()); _src.setEnabled(!installationType.isPredefined()); + _ensurepip.setEnabled(!installationType.isPredefined()); } } \ No newline at end of file diff --git a/installer/src/java/org/python/util/install/Wizard.java b/installer/src/java/org/python/util/install/Wizard.java --- a/installer/src/java/org/python/util/install/Wizard.java +++ b/installer/src/java/org/python/util/install/Wizard.java @@ -20,8 +20,11 @@ TypePage typePage = new TypePage(); DirectorySelectionPage directoryPage = new DirectorySelectionPage(jarInfo); directoryPage.setValidator(new DirectorySelectionPageValidator(directoryPage)); - JavaSelectionPage javaPage = new JavaSelectionPage(); - javaPage.setValidator(new JavaSelectionPageValidator(javaPage)); + // 2.7.0rc2 removed JAVA_HOME support from script generation, + // due to jython.exe. May consider re-enabling if we have a good + // strategy for doing so. +// JavaSelectionPage javaPage = new JavaSelectionPage(); +// javaPage.setValidator(new JavaSelectionPageValidator(javaPage)); OverviewPage overviewPage = new OverviewPage(); ProgressPage progressPage = new ProgressPage(jarInfo, autotest); ReadmePage readmePage = new ReadmePage(jarInfo); @@ -31,7 +34,7 @@ this.addPage(licensePage); this.addPage(typePage); this.addPage(directoryPage); - this.addPage(javaPage); +// this.addPage(javaPage); this.addPage(overviewPage); this.addPage(progressPage); this.addPage(readmePage); -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Apr 2 01:57:27 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 01 Apr 2015 23:57:27 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_so_that_custom_installs?= =?utf-8?q?_can_deselect_ensurepip?= Message-ID: <20150401235727.29535.97092@psf.io> https://hg.python.org/jython/rev/537dc308b9a1 changeset: 7638:537dc308b9a1 user: Jim Baker date: Wed Apr 01 15:51:57 2015 -0600 summary: Fix so that custom installs can deselect ensurepip files: installer/src/java/org/python/util/install/ChildProcess.java | 2 - installer/src/java/org/python/util/install/FrameInstaller.java | 17 +++++++-- installer/src/java/org/python/util/install/InstallationType.java | 8 +++- installer/src/java/org/python/util/install/InstallerCommandLine.java | 6 +++ installer/src/java/org/python/util/install/TypePage.java | 6 +++ 5 files changed, 30 insertions(+), 9 deletions(-) diff --git a/installer/src/java/org/python/util/install/ChildProcess.java b/installer/src/java/org/python/util/install/ChildProcess.java --- a/installer/src/java/org/python/util/install/ChildProcess.java +++ b/installer/src/java/org/python/util/install/ChildProcess.java @@ -1,5 +1,3 @@ -// FIXME change to ProcessBuilder so we can set environment variables (specifically LC_ALL=C) - package org.python.util.install; import java.io.BufferedReader; diff --git a/installer/src/java/org/python/util/install/FrameInstaller.java b/installer/src/java/org/python/util/install/FrameInstaller.java --- a/installer/src/java/org/python/util/install/FrameInstaller.java +++ b/installer/src/java/org/python/util/install/FrameInstaller.java @@ -22,6 +22,7 @@ private static final String INEX_DEMO_PROPERTY = "FrameInstaller.demo"; private static final String INEX_DOC_PROPERTY = "FrameInstaller.doc"; private static final String INEX_SRC_PROPERTY = "FrameInstaller.src"; + private static final String INEX_ENSUREPIP_PROPERTY = "FrameInstaller.ensurepip"; private static final String STANDALONE_PROPERTY = "FrameInstaller.standalone"; private static Properties _properties = new Properties(); @@ -97,29 +98,34 @@ protected static InstallationType getInstallationType() { InstallationType installationType = new InstallationType(); - if (Boolean.valueOf(getProperty(STANDALONE_PROPERTY)).booleanValue()) { + if (Boolean.valueOf(getProperty(STANDALONE_PROPERTY))) { installationType.setStandalone(); } - if (Boolean.valueOf(getProperty(INEX_MOD_PROPERTY)).booleanValue()) { + if (Boolean.valueOf(getProperty(INEX_MOD_PROPERTY))) { installationType.addLibraryModules(); } else { installationType.removeLibraryModules(); } - if (Boolean.valueOf(getProperty(INEX_DEMO_PROPERTY)).booleanValue()) { + if (Boolean.valueOf(getProperty(INEX_DEMO_PROPERTY))) { installationType.addDemosAndExamples(); } else { installationType.removeDemosAndExamples(); } - if (Boolean.valueOf(getProperty(INEX_DOC_PROPERTY)).booleanValue()) { + if (Boolean.valueOf(getProperty(INEX_DOC_PROPERTY))) { installationType.addDocumentation(); } else { installationType.removeDocumentation(); } - if (Boolean.valueOf(getProperty(INEX_SRC_PROPERTY)).booleanValue()) { + if (Boolean.valueOf(getProperty(INEX_SRC_PROPERTY))) { installationType.addSources(); } else { installationType.removeSources(); } + if (Boolean.valueOf(getProperty(INEX_ENSUREPIP_PROPERTY))) { + installationType.addEnsurepip(); + } else { + installationType.removeEnsurepip(); + } return installationType; } @@ -129,6 +135,7 @@ setProperty(INEX_DEMO_PROPERTY, Boolean.toString(installationType.installDemosAndExamples())); setProperty(INEX_DOC_PROPERTY, Boolean.toString(installationType.installDocumentation())); setProperty(INEX_SRC_PROPERTY, Boolean.toString(installationType.installSources())); + setProperty(INEX_ENSUREPIP_PROPERTY, Boolean.toString(installationType.ensurepip())); } protected static JavaVersionInfo getJavaVersionInfo() { diff --git a/installer/src/java/org/python/util/install/InstallationType.java b/installer/src/java/org/python/util/install/InstallationType.java --- a/installer/src/java/org/python/util/install/InstallationType.java +++ b/installer/src/java/org/python/util/install/InstallationType.java @@ -61,9 +61,13 @@ _installSources = false; } - public void addEnsurepip() { _ensurepip = true; } + public void addEnsurepip() { + _ensurepip = true; + } - public void removeEnsurepip() { _ensurepip = false; } + public void removeEnsurepip() { + _ensurepip = false; + } public void setStandalone() { _isStandalone = true; diff --git a/installer/src/java/org/python/util/install/InstallerCommandLine.java b/installer/src/java/org/python/util/install/InstallerCommandLine.java --- a/installer/src/java/org/python/util/install/InstallerCommandLine.java +++ b/installer/src/java/org/python/util/install/InstallerCommandLine.java @@ -354,6 +354,9 @@ if (INEXCLUDE_SOURCES.equals(includeParts[i])) { installationType.addSources(); } + if (INEXCLUDE_ENSUREPIP.equals(includeParts[i])) { + installationType.addEnsurepip(); + } } } // remove parts to exclude @@ -372,6 +375,9 @@ if (INEXCLUDE_SOURCES.equals(excludeParts[i])) { installationType.removeSources(); } + if (INEXCLUDE_ENSUREPIP.equals(excludeParts[i])) { + installationType.removeEnsurepip(); + } } } return installationType; diff --git a/installer/src/java/org/python/util/install/TypePage.java b/installer/src/java/org/python/util/install/TypePage.java --- a/installer/src/java/org/python/util/install/TypePage.java +++ b/installer/src/java/org/python/util/install/TypePage.java @@ -254,6 +254,12 @@ } else { installationType.removeSources(); } + } else if (InstallerCommandLine.INEXCLUDE_ENSUREPIP.equals(actionCommand)) { + if (selected) { + installationType.addEnsurepip(); + } else { + installationType.removeEnsurepip(); + } } } FrameInstaller.setInstallationType(installationType); -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Apr 2 05:00:29 2015 From: jython-checkins at python.org (jim.baker) Date: Thu, 02 Apr 2015 03:00:29 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_time=2Estrftime_now_always_?= =?utf-8?q?returns_a_bytestring?= Message-ID: <20150402030027.16507.34830@psf.io> https://hg.python.org/jython/rev/c06821df7422 changeset: 7639:c06821df7422 user: Jim Baker date: Wed Apr 01 21:00:00 2015 -0600 summary: time.strftime now always returns a bytestring Running under certain locales with formats like %c (date+time) or %a (weekday) produces output like "? 3/29 14:55:13 2015" (as seen with ja_JP encoding); "?" is the abbreviated form of Sunday in Japanese. Prior to this commit, Jython would emit this as Unicode, however, Python code that attempts to print timestamps may expect that bytestrings are always produced. Jython 3.x is the correct solution of course. Fixes http://bugs.jython.org/issue2301 files: Lib/test/test_os_jy.py | 13 +++++++++++++ src/org/python/core/Py.java | 9 +++++++++ src/org/python/modules/time/Time.java | 4 ++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_os_jy.py b/Lib/test/test_os_jy.py --- a/Lib/test/test_os_jy.py +++ b/Lib/test/test_os_jy.py @@ -338,6 +338,19 @@ env=newenv), "2015-01-22 00:00:00\n") + def test_strftime_japanese_locale(self): + # Verifies fix of http://bugs.jython.org/issue2301 - produces + # UTF-8 encoded output per what CPython does, rather than Unicode. + # We will revisit in Jython 3.x! + self.get_installed_locales("ja_JP.UTF-8") + self.assertEqual( + subprocess.check_output( + [sys.executable, + "-J-Duser.country=JP", "-J-Duser.language=ja", + "-c", + "import time; print repr(time.strftime('%c', (2015, 3, 29, 14, 55, 13, 6, 88, 0)))"]), + "'\\xe6\\x97\\xa5 3 29 14:55:13 2015'\n") + class SystemTestCase(unittest.TestCase): 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 @@ -660,6 +660,15 @@ } } + public static PyString newStringUTF8(String s) { + if (CharMatcher.ASCII.matchesAllOf(s)) { + // ascii of course is a subset of UTF-8 + return Py.newString(s); + } else { + return Py.newString(codecs.PyUnicode_EncodeUTF8(s, null)); + } + } + public static PyStringMap newStringMap() { // enable lazy bootstrapping (see issue #1671) if (!PyType.hasBuilder(PyStringMap.class)) { 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 @@ -671,7 +671,7 @@ i++; } // FIXME: This have problems with localized data: - // $ LANG=es_ES.UTF-8 jythont -c "import time; print time.strftime('%A')" + // $ LANG=es_ES.UTF-8 jython -c "import time; print time.strftime('%A')" // s?bado // // On the other hand, returning unicode would break some doctests @@ -681,7 +681,7 @@ // os.environ) // // TODO: Check how CPython deals with this problem. - return Py.newStringOrUnicode(s); + return Py.newStringUTF8(s); } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Apr 2 14:52:23 2015 From: jython-checkins at python.org (jim.baker) Date: Thu, 02 Apr 2015 12:52:23 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_German_translation_of_i?= =?utf-8?q?nstalling_pip/setuptools_progress?= Message-ID: <20150402125223.14223.3645@psf.io> https://hg.python.org/jython/rev/ab032edafd1e changeset: 7640:ab032edafd1e user: Jim Baker date: Thu Apr 02 06:52:19 2015 -0600 summary: Fix German translation of installing pip/setuptools progress Thanks to Oti Humbel for pointing out the subtle distinction. files: installer/src/java/org/python/util/install/TextConstants_de.java | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/installer/src/java/org/python/util/install/TextConstants_de.java b/installer/src/java/org/python/util/install/TextConstants_de.java --- a/installer/src/java/org/python/util/install/TextConstants_de.java +++ b/installer/src/java/org/python/util/install/TextConstants_de.java @@ -97,7 +97,7 @@ { C_ENTER_TARGET_DIRECTORY, "Bitte geben Sie das Zielverzeichnis ein" }, // console { C_ENTER_JAVA_HOME, "Bitte geben Sie das gewuenschte Java Home Verzeichnis ein (Enter fuer das aktuelle)" }, // console { C_ENGLISH, "Englisch" }, // language - { C_ENSUREPIP, "Installieren pip und setuptools"}, + { C_ENSUREPIP, "pip und setuptools werden installiert"}, { C_EXCLUDE, "Moechten Sie Teile von der Installation ausschliessen ?" }, // installation type { C_GENERATING_START_SCRIPTS, "Start Scripts werden generiert ..." }, // progress { C_GERMAN, "Deutsch" }, // language -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Apr 2 22:25:08 2015 From: jython-checkins at python.org (jim.baker) Date: Thu, 02 Apr 2015 20:25:08 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_NEWS_for_rc1_and_rc2?= Message-ID: <20150402202508.15221.58868@psf.io> https://hg.python.org/jython/rev/1583d0230fd9 changeset: 7641:1583d0230fd9 user: Jim Baker date: Thu Apr 02 14:24:59 2015 -0600 summary: Update NEWS for rc1 and rc2 files: NEWS | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 48 insertions(+), 0 deletions(-) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -2,6 +2,54 @@ For more details, please see https://hg.python.org/jython +Jython 2.7rc2 + Bugs fixed + - [ 2301 ] time.strftime now always returns a bytestring (fixes pip on Japanese locales) + - [ 2297 ] Updates installer to use jython.exe + - [ 2298 ] Fix setuptools wheel bundled by ensurepip so it check for Windows on Jython + - [ 2300 ] Fix bin/jython.py to not consume subcommand args + New features + - Installer installs pip, setuptools by default, but custom builds can de-select. + Does not change standalone usage. (Runs jython -m ensurepip as last install step.) + - Makes jython.py be the default launcher (as bin/jython) if CPython 2.7 is available. + +Jython 2.7rc1 + Bugs fixed + - [ 1793 ] Fix relative seek in read/write mode via a non-buffered readinto() method + - [ 2282 ] Speed up startup with compiled $py.class files included for standalone, full jars + - [ 1371, 2283, 2296 ] More robustness wrt security managers, python.home, import of non-ascii names + - [ 2068 ] Use position(long) setter to manually update file channel's position post-write. + - [ 2288 ] Posix link and symlink support now uses NIO2 + - [ 2120 ] Use Java instead of JNR for os.chmod, os.mkdir when running on Windows + - [ 2226 ] Matches CPython's re support of what counts as a Unicode whitespace codepoint + - [ 1725 ] Speed up re matching by not executing SRE_STATE#TRACE in the sre regex engine + - Exceptions with non-ascii args should not cause an exception when displayed on console + - [ 2274 ] Remove Jython-specific pythonpath, test_pythonpath; update pwd to support unicode + - [ 2289 ] Ensure core types are Serializable, specifically PyUnicode + - [ 2272 ] Generalize adding special slots (__dict__, __weakref__); adds support for Werkzeug + - [ 2280 ] Avoid deadlock at shutdown with synchronization of PySystemStateCloser, FinalizeTrigger + - [ 2275 ] Upgrade JLine to support keyboard layouts using AltGr (such as Finnish) on Windows + - Improve robustness of socket and SSL support, especially error handling + - time.sleep(0) should always attempt to yield CPU + - [ 2271 ] Restore __tojava__ to datetime.{date, datetime, time} classes + - [ 2084, 1729 ] Robust handling of sun.misc.Signal exceptions across various JVM implementations + - [ 2189 ] Add java_user scheme to support user directory installs + - Fix Popen._internal_poll so that it does not race with j.l.Process finalization + - Fix reflection-based gc-traversion + - [ 1491 ] Windows launcher now uses jython.exe (built with PyInstaller) instead of jython.bat + This means that pip, nosetests, yolk, and other installed tool scripts finally work on Windows + + New features + - Can add a __dict__ slot descriptor to a subclass of Java classes, such as java.util.HashMap + - Directly execute zip files or dirs with top level __main__.py to support wrapper scripts + generated by distlib, part of pip + - Reflection-based traversion is now activated by default as a fallback for ordinary traversion. + This impacts third-party extenders of PyObject. A warning is emitted that suggests next steps + on how to avoid this cost. + - Uses classpath wildcard in jython.py/jython.exe to minimize the launcher command line, + (main benefit is Jython developers on Windows using dev builds) + - Adds new Jython launcher written in Python, bin/jython.py, to be run by CPython 2.7 + Jython 2.7b4 Bugs Fixed - [ 2032 ] Fixed typo in compiler/pycodegen.py -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Apr 2 23:24:30 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Thu, 02 Apr 2015 21:24:30 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Prepare_for_RC2=2E?= Message-ID: <20150402212430.16246.52307@psf.io> https://hg.python.org/jython/rev/2747ce30b81d changeset: 7642:2747ce30b81d user: Frank Wierzbicki date: Thu Apr 02 21:24:25 2015 +0000 summary: Prepare for RC2. files: README.txt | 8 ++++---- build.xml | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -1,11 +1,11 @@ -Welcome to Jython 2.7rc1 -======================= +Welcome to Jython 2.7rc2 +======================== -This is the first release candidate of the 2.7 version of Jython. Thanks to +This is the second release candidate of the 2.7 version of Jython. Thanks to Amobee (http://www.amobee.com/) for sponsoring this release. Thanks to all who contribute to Jython. -Jython 2.7rc1 includes many bug fixes and code stabilization in prep for +Jython 2.7rc2 includes many bug fixes and code stabilization in prep for release candidates. Please see the NEWS file for detailed release notes. diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -84,15 +84,15 @@ - - + + - + -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Apr 2 23:25:22 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Thu, 02 Apr 2015 21:25:22 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Added_tag_v2=2E7rc2_for_cha?= =?utf-8?q?ngeset_2747ce30b81d?= Message-ID: <20150402212522.16511.83288@psf.io> https://hg.python.org/jython/rev/9edabe2dba7c changeset: 7643:9edabe2dba7c user: Frank Wierzbicki date: Thu Apr 02 21:25:18 2015 +0000 summary: Added tag v2.7rc2 for changeset 2747ce30b81d files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -87,3 +87,4 @@ e270e881c84cbe519035c215fde09677362a4953 v2.7b4 17d18c6dde9693129d977affb8ca20406d6a6585 v2.7b4 d9660aa5cc8af0ce8c839b9712301c180cc4803e v2.7rc1 +2747ce30b81db7fd620c3aeb50ca3bfa362ac3c8 v2.7rc2 -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Apr 3 08:09:09 2015 From: jython-checkins at python.org (jim.baker) Date: Fri, 03 Apr 2015 06:09:09 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_NEWS_wording_plus_note_of_r?= =?utf-8?q?emoval_of_alternative_JRE_being_supported_in_script?= Message-ID: <20150403060909.34653.58670@psf.io> https://hg.python.org/jython/rev/c5fa17de6dad changeset: 7645:c5fa17de6dad user: Jim Baker date: Fri Apr 03 00:08:43 2015 -0600 summary: NEWS wording plus note of removal of alternative JRE being supported in script gen files: NEWS | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -5,13 +5,17 @@ Jython 2.7rc2 Bugs fixed - [ 2301 ] time.strftime now always returns a bytestring (fixes pip on Japanese locales) - - [ 2297 ] Updates installer to use jython.exe + - [ 2297 ] Updates Jython installer to use jython.exe - [ 2298 ] Fix setuptools wheel bundled by ensurepip so it check for Windows on Jython - [ 2300 ] Fix bin/jython.py to not consume subcommand args New features - Installer installs pip, setuptools by default, but custom builds can de-select. Does not change standalone usage. (Runs jython -m ensurepip as last install step.) - Makes jython.py be the default launcher (as bin/jython) if CPython 2.7 is available. + Removed support + - Installer no longer supports using an alternative JRE when generating Jython launchers. + Instead just use JAVA_HOME environment variable to select the desired JRE. + (Removed because of the new native launcher, jython.exe, that is now used on Windows.) Jython 2.7rc1 Bugs fixed @@ -34,8 +38,8 @@ - [ 2271 ] Restore __tojava__ to datetime.{date, datetime, time} classes - [ 2084, 1729 ] Robust handling of sun.misc.Signal exceptions across various JVM implementations - [ 2189 ] Add java_user scheme to support user directory installs - - Fix Popen._internal_poll so that it does not race with j.l.Process finalization - - Fix reflection-based gc-traversion + - Fix Popen._internal_poll so that it does not race with java.lang.Process finalization + - Fix reflection-based garbage collection traversal for CPython compatible gc semantics - [ 1491 ] Windows launcher now uses jython.exe (built with PyInstaller) instead of jython.bat This means that pip, nosetests, yolk, and other installed tool scripts finally work on Windows @@ -43,7 +47,7 @@ - Can add a __dict__ slot descriptor to a subclass of Java classes, such as java.util.HashMap - Directly execute zip files or dirs with top level __main__.py to support wrapper scripts generated by distlib, part of pip - - Reflection-based traversion is now activated by default as a fallback for ordinary traversion. + - Reflection-based traversal is now activated by default as a fallback for ordinary traversal. This impacts third-party extenders of PyObject. A warning is emitted that suggests next steps on how to avoid this cost. - Uses classpath wildcard in jython.py/jython.exe to minimize the launcher command line, -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Apr 3 08:09:09 2015 From: jython-checkins at python.org (jim.baker) Date: Fri, 03 Apr 2015 06:09:09 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_command_line_and_con?= =?utf-8?q?sole_installer?= Message-ID: <20150403060909.34669.82999@psf.io> https://hg.python.org/jython/rev/cfbec6541b19 changeset: 7644:cfbec6541b19 user: Jim Baker date: Fri Apr 03 00:08:23 2015 -0600 summary: Update command line and console installer files: installer/src/java/org/python/util/install/ChildProcess.java | 1 - installer/src/java/org/python/util/install/ConsoleInstaller.java | 31 +- installer/src/java/org/python/util/install/FrameInstaller.java | 4 +- installer/src/java/org/python/util/install/InstallerCommandLine.java | 73 +-- installer/src/java/org/python/util/install/driver/GuiAutotest.java | 50 +- installer/src/java/org/python/util/install/driver/NormalVerifier.java | 182 +-------- 6 files changed, 94 insertions(+), 247 deletions(-) diff --git a/installer/src/java/org/python/util/install/ChildProcess.java b/installer/src/java/org/python/util/install/ChildProcess.java --- a/installer/src/java/org/python/util/install/ChildProcess.java +++ b/installer/src/java/org/python/util/install/ChildProcess.java @@ -266,7 +266,6 @@ // start the process ProcessBuilder pb = new ProcessBuilder(); pb.command(getCommand()); - pb.inheritIO(); if (getCWD() != null) { pb.directory(getCWD().toFile()); } diff --git a/installer/src/java/org/python/util/install/ConsoleInstaller.java b/installer/src/java/org/python/util/install/ConsoleInstaller.java --- a/installer/src/java/org/python/util/install/ConsoleInstaller.java +++ b/installer/src/java/org/python/util/install/ConsoleInstaller.java @@ -249,6 +249,8 @@ installationType.addDocumentation(); } else if (InstallerCommandLine.INEXCLUDE_SOURCES.equals(answer)) { installationType.addSources(); + } else if (InstallerCommandLine.INEXCLUDE_ENSUREPIP.equals(answer)) { + installationType.addEnsurepip(); } if (!no.equals(answer)) { message(getText(C_SCHEDULED, answer)); @@ -270,6 +272,8 @@ installationType.removeDocumentation(); } else if (InstallerCommandLine.INEXCLUDE_SOURCES.equals(answer)) { installationType.removeSources(); + } else if (InstallerCommandLine.INEXCLUDE_ENSUREPIP.equals(answer)) { + installationType.removeEnsurepip(); } if (!no.equals(answer)) { message(getText(C_UNSCHEDULED, answer)); @@ -399,29 +403,7 @@ } private JavaHomeHandler determineJavaHome() { - JavaHomeHandler javaHomeHandler = null; - boolean javaFound = false; - while (!javaFound) { - String javaHomeName = question(getText(C_ENTER_JAVA_HOME), null, true, CURRENT_JRE); - // only validate deviations - if (CURRENT_JRE.equals(javaHomeName)) { - javaHomeHandler = new JavaHomeHandler(); - javaFound = true; - } else { - javaHomeHandler = new JavaHomeHandler(javaHomeName); - if (javaHomeHandler.isDeviation()) { - if (!javaHomeHandler.isValidHome()) { - String binDirName = javaHomeName.concat("/bin"); - message(getText(C_NO_JAVA_EXECUTABLE, binDirName)); - } else { - javaFound = true; - } - } else { - javaFound = true; - } - } - } - return javaHomeHandler; + return new JavaHomeHandler(); } private void checkTargetDirectorySilent(File targetDirectory) { @@ -490,6 +472,8 @@ + installationType.installDocumentation()); message(" - " + InstallerCommandLine.INEXCLUDE_SOURCES + ": " + installationType.installSources()); + message(" - " + InstallerCommandLine.INEXCLUDE_ENSUREPIP + ": " + + installationType.ensurepip()); if (javaHomeHandler.isValidHome()) { message(" - JRE: " + javaHomeHandler.getHome().getAbsolutePath()); } else { @@ -537,6 +521,7 @@ answers.add(InstallerCommandLine.INEXCLUDE_DEMOS_AND_EXAMPLES); answers.add(InstallerCommandLine.INEXCLUDE_DOCUMENTATION); answers.add(InstallerCommandLine.INEXCLUDE_SOURCES); + answers.add(InstallerCommandLine.INEXCLUDE_ENSUREPIP); answers.add(getText(C_NO)); return answers; } diff --git a/installer/src/java/org/python/util/install/FrameInstaller.java b/installer/src/java/org/python/util/install/FrameInstaller.java --- a/installer/src/java/org/python/util/install/FrameInstaller.java +++ b/installer/src/java/org/python/util/install/FrameInstaller.java @@ -40,9 +40,7 @@ if (commandLine.hasDirectoryOption()) { setTargetDirectory(commandLine.getTargetDirectory().getAbsolutePath()); } - if (commandLine.hasJavaHomeOption()) { - setJavaHomeHandler(commandLine.getJavaHomeHandler()); - } + setJavaHomeHandler(commandLine.getJavaHomeHandler()); initDefaultJava(); Wizard wizard = new Wizard(jarInfo, autotest); wizard.addWindowListener(new WindowAdapter() { diff --git a/installer/src/java/org/python/util/install/InstallerCommandLine.java b/installer/src/java/org/python/util/install/InstallerCommandLine.java --- a/installer/src/java/org/python/util/install/InstallerCommandLine.java +++ b/installer/src/java/org/python/util/install/InstallerCommandLine.java @@ -36,17 +36,10 @@ private static final String VERBOSE_DESC = "print more output during the installation\n" + "(also valid in GUI and autotest mode)"; - private static final String JRE_SHORT = "j"; - private static final String JRE_LONG = "jre"; - private static final String JRE_DESC = "home directory of the runtime jre or jdk\n" - + "(executables are assumed in the /bin subdirectory)\n" + "select this if you want to run Jython with a\n" - + "different java version than the installation"; - private static final String AUTOTEST_SHORT = "A"; private static final String AUTOTEST_LONG = "autotest"; private static final String AUTOTEST_DESC = "automatic stress tests for the installer\n" - + "most of the other options are ignored\n" + "allowed additional options: '" + VERBOSE_LONG + "', '" - + JRE_LONG + "'"; + + "most of the other options are ignored\n" + "allowed additional options: '" + VERBOSE_LONG; private static final String DIRECTORY_SHORT = "d"; private static final String DIRECTORY_LONG = "directory"; @@ -62,18 +55,23 @@ private static final String STANDALONE_DOCUMENTATION = "install a single, executable .jar,\ncontaining all the modules"; private static final String INEXCLUDE_ARG = "part(s)"; - private static final String INEXCLUDE_PARTS = "more than one of the following is possible:\n" + "- " - + INEXCLUDE_LIBRARY_MODULES + ": library modules\n" + "- " + INEXCLUDE_DEMOS_AND_EXAMPLES - + ": demos and examples\n" + "- " + INEXCLUDE_DOCUMENTATION + ": documentation\n" + "- " - + INEXCLUDE_SOURCES + ": java source code"; + private static final String INEXCLUDE_PARTS = "more than one of the following is possible:\n" + + "- " + INEXCLUDE_LIBRARY_MODULES + ": library modules\n" + + "- " + INEXCLUDE_DEMOS_AND_EXAMPLES + ": demos and examples\n" + + "- " + INEXCLUDE_DOCUMENTATION + ": documentation\n" + + "- " + INEXCLUDE_SOURCES + ": java source code\n" + + "- " + INEXCLUDE_ENSUREPIP + ": install pip and setuptools"; private static final String TYPE_SHORT = "t"; private static final String TYPE_LONG = "type"; private static final String TYPE_ARG = TYPE_LONG; private static final String TYPE_DESC = "installation type\n" + "one of the following types is possible\n" - + "(see also include/exclude parts):\n" + "- " + TYPE_ALL + ": everything (including " + INEXCLUDE_SOURCES - + ")\n" + "- " + TYPE_STANDARD + ": core, " + INEXCLUDE_LIBRARY_MODULES + ", " - + INEXCLUDE_DEMOS_AND_EXAMPLES + ", " + INEXCLUDE_DOCUMENTATION + ",\n"+ TYPE_STANDARD+ " is the default\n" + "- " + TYPE_MINIMUM + ": core\n" + + "(see also include/exclude parts):\n" + + "- " + TYPE_ALL + ": everything (including " + INEXCLUDE_SOURCES + ")\n" + + "- " + TYPE_STANDARD + ": core, " + INEXCLUDE_LIBRARY_MODULES + ", " + + INEXCLUDE_DEMOS_AND_EXAMPLES + ", " + INEXCLUDE_DOCUMENTATION + ", " + INEXCLUDE_ENSUREPIP + "\n" + + TYPE_STANDARD+ " is the default\n" + + "- " + TYPE_MINIMUM + ": core\n" + "- " + TYPE_STANDALONE + ": " + STANDALONE_DOCUMENTATION; private static final String INCLUDE_SHORT = "i"; @@ -92,25 +90,23 @@ private static final String SYNTAX = "\n\tjava -jar jython_version.jar"; private static final String HEADER = "\nNo option at all will start the interactive GUI installer, except:\n" - + "Options respected in GUI mode are '" + DIRECTORY_LONG + "' and '" + JRE_LONG + + "Options respected in GUI mode are '" + DIRECTORY_LONG + "', which serve as default values in the wizard.\n" - + "In non-GUI mode the following options are available:\n."; + + "In non-GUI mode the following options are available:\n"; private static final String SYNTAX_WITHOUT_JAR = "\n\tjava -jar "; private static final String FOOTER = ""; private static final String EXAMPLES = "\nexample of a GUI installation:{0}" + "\n\nexample of a console installation:{0} -" + CONSOLE_SHORT + "\n\nexample of a silent installation:{0} -" + SILENT_SHORT + " -" + DIRECTORY_SHORT + " targetDirectory" - + "\n\nexamples of a silent installation with more options:{0} -" + SILENT_SHORT + " -" + DIRECTORY_SHORT - + " targetDirectory -" + TYPE_SHORT + " " + TYPE_MINIMUM + " -" + INCLUDE_SHORT + " " + INEXCLUDE_SOURCES - + " -" + JRE_SHORT + " javaHome" + "{0} -" + SILENT_SHORT + " -" + DIRECTORY_SHORT + " targetDirectory -" - + TYPE_SHORT + " " + TYPE_STANDARD + " -" + EXCLUDE_SHORT + " " + INEXCLUDE_DEMOS_AND_EXAMPLES + " " - + INEXCLUDE_DOCUMENTATION + "\n\t\t -" + INCLUDE_SHORT + " " + INEXCLUDE_SOURCES + " -" + JRE_SHORT - + " javaHome -" + VERBOSE_SHORT + + "\n\nexamples of a silent installation with more options:{0} -" + SILENT_SHORT + + " -" + DIRECTORY_SHORT + " targetDirectory -" + TYPE_SHORT + " " + TYPE_MINIMUM + + " -" + INCLUDE_SHORT + " " + INEXCLUDE_SOURCES + + "{0} -" + SILENT_SHORT + " -" + DIRECTORY_SHORT + " targetDirectory -" + TYPE_SHORT + " " + TYPE_STANDARD + + " -" + EXCLUDE_SHORT + " " + INEXCLUDE_DEMOS_AND_EXAMPLES + " " + INEXCLUDE_DOCUMENTATION + + " -" + INCLUDE_SHORT + " " + INEXCLUDE_SOURCES + "\n\nexample of an autotest installation into temporary directories:{0} -" + AUTOTEST_SHORT - + "\n\t(make sure you do NOT touch mouse NOR keyboard after hitting enter/return!)" - + "\n\nexample of an autotest installation, using a different jre for the start scripts:{0} -" - + AUTOTEST_SHORT + " -" + JRE_SHORT + " javaHome" + " -" + VERBOSE_SHORT - + "\n\t(make sure you do NOT touch mouse NOR keyboard after hitting enter/return!)"; + + "\n\t(uses java.awt.Robot; make sure you do NOT touch mouse NOR keyboard" + + "\n\t after hitting enter/return!)"; private String[] _args; private Options _options; @@ -270,10 +266,6 @@ return _commandLine.hasOption(EXCLUDE_SHORT) || _commandLine.hasOption(EXCLUDE_LONG); } - public boolean hasJavaHomeOption() { - return _commandLine.hasOption(JRE_SHORT) || _commandLine.hasOption(JRE_LONG); - } - public boolean hasVerboseOption() { return hasVerboseOption(_commandLine); } @@ -309,15 +301,10 @@ } /** - * @return a java home handler for the requested java home directory, or a default handler if no - * java home specified + * @return a a default handler for java home (no longer supports specifying different java home since 2.7rc2 */ public JavaHomeHandler getJavaHomeHandler() { - if (hasJavaHomeOption()) { - return new JavaHomeHandler(_commandLine.getOptionValue(JRE_SHORT)); - } else { return new JavaHomeHandler(); - } } /** @@ -437,11 +424,6 @@ excludeOption.setLongOpt(EXCLUDE_LONG); _options.addOption(excludeOption); - // runtime jre - Option jreOption = new Option(JRE_SHORT, JRE_LONG, true, JRE_DESC); - jreOption.setArgName(DIRECTORY_ARG); - _options.addOption(jreOption); - // verbose Option verboseOption = new Option(VERBOSE_SHORT, VERBOSE_LONG, false, VERBOSE_DESC); _options.addOption(verboseOption); @@ -456,8 +438,11 @@ } private boolean isValidInExcludePart(String part) { - return INEXCLUDE_DEMOS_AND_EXAMPLES.equals(part) || INEXCLUDE_DOCUMENTATION.equals(part) - || INEXCLUDE_LIBRARY_MODULES.equals(part) || INEXCLUDE_SOURCES.equals(part); + return INEXCLUDE_DEMOS_AND_EXAMPLES.equals(part) + || INEXCLUDE_DOCUMENTATION.equals(part) + || INEXCLUDE_LIBRARY_MODULES.equals(part) + || INEXCLUDE_SOURCES.equals(part) + || INEXCLUDE_ENSUREPIP.equals(part); } } diff --git a/installer/src/java/org/python/util/install/driver/GuiAutotest.java b/installer/src/java/org/python/util/install/driver/GuiAutotest.java --- a/installer/src/java/org/python/util/install/driver/GuiAutotest.java +++ b/installer/src/java/org/python/util/install/driver/GuiAutotest.java @@ -71,31 +71,31 @@ * @throws DriverException */ protected void execute() throws DriverException { - try { - _robot = new Robot(); - - System.out.println("waiting 2 seconds for the first gui ... please do not change focus"); - _robot.delay(2000); // initial gui load - - Iterator actionsIterator = _keyActions.iterator(); - while (actionsIterator.hasNext()) { - KeyAction keyAction = (KeyAction) actionsIterator.next(); - setWaiting(keyAction.isWait()); - if (isWaiting()) { - System.out.println("waiting for the installation to finish ..."); - } - while (isWaiting()) { - try { - Thread.sleep(_DEFAULT_DELAY); - } catch (InterruptedException e) { - throw new DriverException(e); - } - } - executeKeyAction(keyAction); - } - } catch (AWTException ae) { - throw new DriverException(ae); - } +// try { +// _robot = new Robot(); +// +// System.out.println("waiting 2 seconds for the first gui ... please do not change focus"); +// _robot.delay(2000); // initial gui load +// +// Iterator actionsIterator = _keyActions.iterator(); +// while (actionsIterator.hasNext()) { +// KeyAction keyAction = (KeyAction) actionsIterator.next(); +// setWaiting(keyAction.isWait()); +// if (isWaiting()) { +// System.out.println("waiting for the installation to finish ..."); +// } +// while (isWaiting()) { +// try { +// Thread.sleep(_DEFAULT_DELAY); +// } catch (InterruptedException e) { +// throw new DriverException(e); +// } +// } +// executeKeyAction(keyAction); +// } +// } catch (AWTException ae) { +// throw new DriverException(ae); +// } } diff --git a/installer/src/java/org/python/util/install/driver/NormalVerifier.java b/installer/src/java/org/python/util/install/driver/NormalVerifier.java --- a/installer/src/java/org/python/util/install/driver/NormalVerifier.java +++ b/installer/src/java/org/python/util/install/driver/NormalVerifier.java @@ -3,32 +3,25 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.io.PrintStream; -import java.text.MessageFormat; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; import java.util.StringTokenizer; import org.python.util.install.ChildProcess; import org.python.util.install.FileHelper; -import org.python.util.install.Installation; -import org.python.util.install.JavaHomeHandler; public class NormalVerifier implements Verifier { protected static final String AUTOTEST_PY = "autotest.py"; - protected static final String JYTHON_TEST = "jython_test"; - private static final String BIN = "bin"; - private static final String BAT_EXTENSION = ".bat"; - private static final String JYTHON_UP = "jython up and running!"; private static final String JYTHON = "jython"; - private static final String TEMPLATE_SUFFIX = ".template"; - private static final String VERIFYING = "verifying"; private File _targetDir; @@ -45,10 +38,6 @@ createTestScriptFile(); // create the test .py script // verify the most simple start of jython works verifyStart(getSimpleCommand()); - if (doShellScriptTests()) { - // verify more complex versions of starting jython - verifyStart(getShellScriptTestCommand()); - } } /** @@ -59,87 +48,9 @@ * if there was a problem getting the target directory path */ protected String[] getSimpleCommand() throws DriverException { - String parentDirName = null; - try { - parentDirName = getTargetDir().getCanonicalPath() + File.separator; - } catch (IOException ioe) { - throw new DriverException(ioe); - } - String[] command = new String[2]; - if (Installation.isWindows()) { - command[0] = parentDirName + JYTHON + BAT_EXTENSION; - } else { - command[0] = parentDirName + JYTHON; - } - command[1] = parentDirName + AUTOTEST_PY; - return command; - } - - /** - * @return The command to test the shell script more deeply - * @throws DriverException - */ - protected final String[] getShellScriptTestCommand() throws DriverException { - // first we have to create the shell script - File testCommandDir = getShellScriptTestCommandDir(); - if (!testCommandDir.exists()) { - if (!testCommandDir.mkdirs()) { - throw new DriverException("unable to create directory " - + testCommandDir.getAbsolutePath()); - } - } - String commandName = JYTHON_TEST; - boolean isWindows = Installation.isWindows(); - if (isWindows) { - commandName = commandName.concat(BAT_EXTENSION); - } - File command = new File(testCommandDir, commandName); - try { - if (!command.exists()) { - command.createNewFile(); - } - FileHelper.write(command, getShellScriptTestContents()); - if (!isWindows) { - FileHelper.makeExecutable(command); - } - return new String[] {command.getCanonicalPath()}; - } catch (Exception e) { - throw new DriverException(e); - } - } - - /** - * @return The contents of the shell test script - * @throws DriverException - */ - protected final String getShellScriptTestContents() throws DriverException { - String contents = ""; - String templateName = JYTHON_TEST; - if (Installation.isWindows()) { - templateName = templateName.concat(BAT_EXTENSION); - } - templateName = templateName.concat(TEMPLATE_SUFFIX); - InputStream inputStream = FileHelper.getRelativeURLAsStream(getClass(), templateName); - if (inputStream != null) { - try { - String template = FileHelper.readAll(inputStream); - String targetDirPath = getTargetDir().getCanonicalPath(); - String upScriptPath = getSimpleCommand()[1]; - JavaHomeHandler javaHomeHandler = new JavaHomeHandler(); - String javaHomeString = ""; - if (javaHomeHandler.isValidHome()) { - javaHomeString = javaHomeHandler.getHome().getAbsolutePath(); - } - contents = MessageFormat.format(template, - targetDirPath, - upScriptPath, - javaHomeString, - VERIFYING); - } catch (Exception e) { - throw new DriverException(e); - } - } - return contents; + return new String[] { + Paths.get(BIN).resolve(JYTHON).toString(), + _targetDir.toPath().resolve(AUTOTEST_PY).toString() }; } /** @@ -148,56 +59,32 @@ * @throws DriverException */ protected final File getShellScriptTestCommandDir() throws DriverException { - String dirName; - try { - dirName = getTargetDir().getCanonicalPath().concat(File.separator).concat(BIN); - return new File(dirName); - } catch (IOException ioe) { - throw new DriverException(ioe); - } + return _targetDir.toPath().resolve(BIN).toFile(); } /** - * Internal method verifying a jython-starting command by capturing the ouptut + * Internal method verifying a jython-starting command by capturing the output * * @param command * * @throws DriverException */ private void verifyStart(String[] command) throws DriverException { - ChildProcess childProcess = new ChildProcess(command); - childProcess.setDebug(true); - ByteArrayOutputStream redirectedErr = new ByteArrayOutputStream(); - ByteArrayOutputStream redirectedOut = new ByteArrayOutputStream(); - int exitValue = 0; - PrintStream oldErr = System.err; - PrintStream oldOut = System.out; - try { - System.setErr(new PrintStream(redirectedErr)); - System.setOut(new PrintStream(redirectedOut)); - exitValue = childProcess.run(); - } finally { - System.setErr(oldErr); - System.setOut(oldOut); - } - // verify the output - String output = null; - String error = null; - try { - redirectedErr.flush(); - redirectedOut.flush(); - String encoding = "US-ASCII"; - output = redirectedOut.toString(encoding); - error = redirectedErr.toString(encoding); - } catch (IOException ioe) { - throw new DriverException(ioe); - } - if (exitValue != 0) { - throw new DriverException("start of jython failed, output:\n" + output + "\nerror:\n" - + error); - } - verifyError(error); - verifyOutput(output); + ChildProcess p = new ChildProcess(command); + p.setDebug(true); + p.setCWD(_targetDir.toPath()); + System.err.println("Verify start: command=" + Arrays.toString(command) + ", cwd=" + p.getCWD()); + int exitValue = p.run(); +// if (exitValue != 0) { +// throw new DriverException("start of jython failed\n" +// + "command: " + Arrays.toString(command) +// + "\ncwd: " + p.getCWD() +// + "\nexit value: " + exitValue +// + "\nstdout: " + p.getStdout() +// + "\nstderr: " + p.getStderr()); +// } + verifyError(p.getStderr()); + verifyOutput(p.getStdout()); } /** @@ -210,14 +97,12 @@ return true; } - private void verifyError(String error) throws DriverException { - StringTokenizer tokenizer = new StringTokenizer(error, "\n"); - while (tokenizer.hasMoreTokens()) { - String line = tokenizer.nextToken(); + private void verifyError(List stderr) throws DriverException { + for (String line : stderr) { if (isExpectedError(line)) { feedback(line); } else { - throw new DriverException(error); + throw new DriverException(stderr.toString()); } } } @@ -226,29 +111,24 @@ boolean expected = false; if (line.startsWith("*sys-package-mgr*")) { expected = true; - } else if (line.indexOf("32 bit") >= 0 && line.indexOf("64 bit") >= 0) { - // OS X incompatibility message when using -A -j java1.6.0 from java1.5.0 - expected = true; } return expected; } - private void verifyOutput(String output) throws DriverException { + private void verifyOutput(List stdout) throws DriverException { boolean started = false; - StringTokenizer tokenizer = new StringTokenizer(output, "\n"); - while (tokenizer.hasMoreTokens()) { - String line = tokenizer.nextToken(); + for (String line : stdout) { if (isExpectedOutput(line)) { feedback(line); if (line.startsWith(JYTHON_UP)) { started = true; } } else { - throw new DriverException(output); + throw new DriverException(stdout.toString()); } } if (!started) { - throw new DriverException("start of jython failed:\n" + output); + throw new DriverException("start of jython failed:\n" + stdout.toString()); } } @@ -282,6 +162,6 @@ } private void feedback(String line) { - System.out.println(line); + System.out.println("feedback " + line); } } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Apr 3 09:02:51 2015 From: jython-checkins at python.org (jim.baker) Date: Fri, 03 Apr 2015 07:02:51 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Do_not_pass_args_in_shebang?= =?utf-8?q?_for_jython=2Epy=2C_because_not_portable?= Message-ID: <20150403070251.27424.7029@psf.io> https://hg.python.org/jython/rev/0213400c518f changeset: 7646:0213400c518f user: Jim Baker date: Fri Apr 03 01:02:45 2015 -0600 summary: Do not pass args in shebang for jython.py, because not portable files: src/shell/jython.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/shell/jython.py b/src/shell/jython.py --- a/src/shell/jython.py +++ b/src/shell/jython.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2.7 -E +#!/usr/bin/env python2.7 # -*- coding: utf-8 -*- # Launch script for Jython. It may be wrapped as an executable with -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Apr 3 18:38:06 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Fri, 03 Apr 2015 16:38:06 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Added_tag_v2=2E7rc2_for_cha?= =?utf-8?q?ngeset_0213400c518f?= Message-ID: <20150403163805.98380.32992@psf.io> https://hg.python.org/jython/rev/913eec7f2e60 changeset: 7647:913eec7f2e60 user: Frank Wierzbicki date: Fri Apr 03 16:38:01 2015 +0000 summary: Added tag v2.7rc2 for changeset 0213400c518f files: .hgtags | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -88,3 +88,5 @@ 17d18c6dde9693129d977affb8ca20406d6a6585 v2.7b4 d9660aa5cc8af0ce8c839b9712301c180cc4803e v2.7rc1 2747ce30b81db7fd620c3aeb50ca3bfa362ac3c8 v2.7rc2 +2747ce30b81db7fd620c3aeb50ca3bfa362ac3c8 v2.7rc2 +0213400c518ff41ef5700d523b08d249d5a00585 v2.7rc2 -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Apr 4 03:19:59 2015 From: jython-checkins at python.org (alex.gronholm) Date: Sat, 04 Apr 2015 01:19:59 +0000 Subject: [Jython-checkins] =?utf-8?b?anl0aG9uOiBGaXhlZCBfX21vZHVsZV9fIG1p?= =?utf-8?q?ssing_from_functions_in_the_time_and_operator_modules?= Message-ID: <20150404011959.98372.89298@psf.io> https://hg.python.org/jython/rev/4722f297d15c changeset: 7648:4722f297d15c user: Alex Gr?nholm date: Sat Apr 04 00:21:31 2015 +0300 summary: Fixed __module__ missing from functions in the time and operator modules (patches by pcmanticore) files: Lib/test/test_operator.py | 11 +++++++++++ Lib/test/test_time.py | 4 ++++ src/org/python/modules/_json/_json.java | 7 +++---- src/org/python/modules/operator.java | 7 +++++++ src/org/python/modules/time/Time.java | 7 +++++++ 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_operator.py b/Lib/test/test_operator.py --- a/Lib/test/test_operator.py +++ b/Lib/test/test_operator.py @@ -1,5 +1,6 @@ import operator import unittest +import inspect from test import test_support @@ -33,6 +34,16 @@ class OperatorTestCase(unittest.TestCase): + def test_missing_module_attribute(self): + skip = {'__subclasshook__', '__new__'} + + def _predicate(member): + return inspect.isbuiltin(member) and member.__name__ not in skip + + objects = inspect.getmembers(operator, predicate=_predicate) + for _, value in objects: + self.assertEqual(value.__module__, "operator", value) + def test_lt(self): self.failUnlessRaises(TypeError, operator.lt) self.failUnlessRaises(TypeError, operator.lt, 1j, 2j) 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 @@ -8,6 +8,10 @@ def setUp(self): self.t = time.time() + def test_missing_module_attribute(self): + self.assertEqual(time.clock.__module__, 'time') + self.assertEqual(time.time.__module__, 'time') + def test_data_attributes(self): time.altzone time.daylight diff --git a/src/org/python/modules/_json/_json.java b/src/org/python/modules/_json/_json.java --- a/src/org/python/modules/_json/_json.java +++ b/src/org/python/modules/_json/_json.java @@ -24,6 +24,7 @@ public class _json implements ClassDictInit { public static final PyString __doc__ = new PyString("Port of _json C module."); + public static final PyObject module = Py.newString("_json"); public static void classDictInit(PyObject dict) { dict.__setitem__("__name__", new PyString("_json")); @@ -83,9 +84,8 @@ } @Override - @ExposedGet(name = "__module__") public PyObject getModule() { - return new PyString("_json"); + return module; } @@ -311,9 +311,8 @@ } @Override - @ExposedGet(name = "__module__") public PyObject getModule() { - return new PyString("_json"); + return module; } @Override diff --git a/src/org/python/modules/operator.java b/src/org/python/modules/operator.java --- a/src/org/python/modules/operator.java +++ b/src/org/python/modules/operator.java @@ -23,6 +23,8 @@ @Untraversable class OperatorFunctions extends PyBuiltinFunctionSet { + public static final PyObject module = Py.newString("operator"); + public OperatorFunctions(String name, int index, int argcount) { this(name, index, argcount, argcount); } @@ -32,6 +34,11 @@ super(name, index, minargs, maxargs); } + @Override + public PyObject getModule() { + return module; + } + public PyObject __call__(PyObject arg1) { switch (index) { case 10: return arg1.__abs__(); 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 @@ -34,10 +34,17 @@ @Untraversable class TimeFunctions extends PyBuiltinFunctionSet { + public static final PyObject module = Py.newString("time"); + public TimeFunctions(String name, int index, int argcount) { super(name, index, argcount); } + @Override + public PyObject getModule() { + return module; + } + public PyObject __call__() { switch (index) { case 0: -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Apr 9 09:28:33 2015 From: jython-checkins at python.org (jeff.allen) Date: Thu, 09 Apr 2015 07:28:33 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_tempfile_module_and_?= =?utf-8?q?its_test_to_lib-python/2=2E7=2E?= Message-ID: <20150409072833.8682.15538@psf.io> https://hg.python.org/jython/rev/f1af0477d30a changeset: 7652:f1af0477d30a user: Jeff Allen date: Tue Apr 07 20:37:18 2015 +0100 summary: Update tempfile module and its test to lib-python/2.7. Selectively merge tempfile and test.test_tempfile from the lib-python directory to Jython Lib, preserving Jython specialisations. files: Lib/tempfile.py | 41 ++- Lib/test/test_tempfile.py | 270 +++++++++++++++++++------ 2 files changed, 225 insertions(+), 86 deletions(-) diff --git a/Lib/tempfile.py b/Lib/tempfile.py --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -29,6 +29,7 @@ # Imports. +import io as _io import os as _os import errno as _errno from random import Random as _Random @@ -170,7 +171,7 @@ if os_name == 'riscos': dirname = _os.getenv('Wimp$ScrapDir') if dirname: dirlist.append(dirname) - elif os_name == "nt": + elif os_name == 'nt': dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ]) else: dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ]) @@ -204,15 +205,18 @@ name = namer.next() filename = _os.path.join(dir, name) try: - fd = _os.open(filename, flags, 0600) - fp = _os.fdopen(fd, 'w') - fp.write('blat') - fp.close() - _os.unlink(filename) - del fp, fd + fd = _os.open(filename, flags, 0o600) + try: + try: + with _io.open(fd, 'wb', closefd=False) as fp: + fp.write(b'blat') + finally: + _os.close(fd) + finally: + _os.unlink(filename) return dir - except (OSError, IOError), e: - if e[0] != _errno.EEXIST: + except (OSError, IOError) as e: + if e.args[0] != _errno.EEXIST: break # no point trying more names in this directory pass raise IOError, (_errno.ENOENT, @@ -558,7 +562,7 @@ return self._file.closed @property - def encoding(self): + def encoding(self): # Jython not CPython return self._file.encoding def fileno(self): @@ -573,14 +577,20 @@ @property def mode(self): - return self._file.mode + try: + return self._file.mode + except AttributeError: + return self._TemporaryFileArgs[0] @property def name(self): - return self._file.name + try: + return self._file.name + except AttributeError: + return None @property - def newlines(self): + def newlines(self): # Jython not CPython return self._file.newlines def next(self): @@ -621,4 +631,7 @@ return rv def xreadlines(self, *args): - return self._file.xreadlines(*args) + try: + return self._file.xreadlines(*args) + except AttributeError: + return iter(self._file.readlines(*args)) diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -1,14 +1,16 @@ -# From Python 2.5.1 # tempfile.py unit tests. import tempfile +import errno +import io import os +import signal +import shutil import sys import re -import errno import warnings import unittest -from test import test_support +from test import test_support as support warnings.filterwarnings("ignore", category=RuntimeWarning, @@ -62,7 +64,7 @@ "file '%s' does not end with '%s'" % (nbase, suf)) nbase = nbase[len(pre):len(nbase)-len(suf)] - self.assert_(self.str_check.match(nbase), + self.assertTrue(self.str_check.match(nbase), "random string '%s' does not match /^[a-zA-Z0-9_-]{6}$/" % nbase) @@ -91,7 +93,7 @@ for key in dict: if key[0] != '_' and key not in expected: unexp.append(key) - self.failUnless(len(unexp) == 0, + self.assertTrue(len(unexp) == 0, "unexpected keys: %s" % unexp) test_classes.append(test_exports) @@ -116,7 +118,7 @@ for i in xrange(TEST_FILES): s = r.next() self.nameCheck(s, '', '', '') - self.failIf(s in dict) + self.assertNotIn(s, dict) dict[s] = 1 def test_supports_iter(self): @@ -132,6 +134,37 @@ except: self.failOnException("iteration") + @unittest.skipUnless(hasattr(os, 'fork'), + "os.fork is required for this test") + def test_process_awareness(self): + # ensure that the random source differs between + # child and parent. + read_fd, write_fd = os.pipe() + pid = None + try: + pid = os.fork() + if not pid: + os.close(read_fd) + os.write(write_fd, next(self.r).encode("ascii")) + os.close(write_fd) + # bypass the normal exit handlers- leave those to + # the parent. + os._exit(0) + parent_value = next(self.r) + child_value = os.read(read_fd, len(parent_value)).decode("ascii") + finally: + if pid: + # best effort to ensure the process can't bleed out + # via any bugs above + try: + os.kill(pid, signal.SIGKILL) + except EnvironmentError: + pass + os.close(read_fd) + os.close(write_fd) + self.assertNotEqual(child_value, parent_value) + + test_classes.append(test__RandomNameSequence) @@ -143,42 +176,84 @@ cand = tempfile._candidate_tempdir_list() - self.failIf(len(cand) == 0) + self.assertFalse(len(cand) == 0) for c in cand: - self.assert_(isinstance(c, basestring), - "%s is not a string" % c) + self.assertIsInstance(c, basestring) def test_wanted_dirs(self): # _candidate_tempdir_list contains the expected directories # Make sure the interesting environment variables are all set. - with test_support.EnvironmentVarGuard() as env: + with support.EnvironmentVarGuard() as env: for envname in 'TMPDIR', 'TEMP', 'TMP': dirname = os.getenv(envname) if not dirname: - env.set(envname, os.path.abspath(envname)) + env[envname] = os.path.abspath(envname) cand = tempfile._candidate_tempdir_list() for envname in 'TMPDIR', 'TEMP', 'TMP': dirname = os.getenv(envname) if not dirname: raise ValueError - self.assert_(dirname in cand) + self.assertIn(dirname, cand) try: dirname = os.getcwd() except (AttributeError, os.error): dirname = os.curdir - self.assert_(dirname in cand) + self.assertIn(dirname, cand) # Not practical to try to verify the presence of OS-specific # paths in this list. test_classes.append(test__candidate_tempdir_list) +# We test _get_default_tempdir some more by testing gettempdir. -# We test _get_default_tempdir by testing gettempdir. +class TestGetDefaultTempdir(TC): + """Test _get_default_tempdir().""" + + def test_no_files_left_behind(self): + # use a private empty directory + our_temp_directory = tempfile.mkdtemp() + try: + # force _get_default_tempdir() to consider our empty directory + def our_candidate_list(): + return [our_temp_directory] + + with support.swap_attr(tempfile, "_candidate_tempdir_list", + our_candidate_list): + # verify our directory is empty after _get_default_tempdir() + tempfile._get_default_tempdir() + self.assertEqual(os.listdir(our_temp_directory), []) + + def raise_OSError(*args, **kwargs): + raise OSError(-1) + + with support.swap_attr(io, "open", raise_OSError): + # test again with failing io.open() + with self.assertRaises(IOError) as cm: + tempfile._get_default_tempdir() + self.assertEqual(cm.exception.errno, errno.ENOENT) + self.assertEqual(os.listdir(our_temp_directory), []) + + open = io.open + def bad_writer(*args, **kwargs): + fp = open(*args, **kwargs) + fp.write = raise_OSError + return fp + + with support.swap_attr(io, "open", bad_writer): + # test again with failing write() + with self.assertRaises(IOError) as cm: + tempfile._get_default_tempdir() + self.assertEqual(cm.exception.errno, errno.ENOENT) + self.assertEqual(os.listdir(our_temp_directory), []) + finally: + shutil.rmtree(our_temp_directory) + +test_classes.append(TestGetDefaultTempdir) class test__get_candidate_names(TC): @@ -187,14 +262,14 @@ def test_retval(self): # _get_candidate_names returns a _RandomNameSequence object obj = tempfile._get_candidate_names() - self.assert_(isinstance(obj, tempfile._RandomNameSequence)) + self.assertIsInstance(obj, tempfile._RandomNameSequence) def test_same_thing(self): # _get_candidate_names always returns the same object a = tempfile._get_candidate_names() b = tempfile._get_candidate_names() - self.assert_(a is b) + self.assertTrue(a is b) test_classes.append(test__get_candidate_names) @@ -268,7 +343,7 @@ def _test_file_mode(self): # _mkstemp_inner creates files with the proper mode if not has_stat: - return # ugh, can't use TestSkipped. + return # ugh, can't use SkipTest. file = self.do_create() mode = stat.S_IMODE(os.stat(file.name).st_mode) @@ -283,9 +358,9 @@ def test_noinherit(self): # _mkstemp_inner file handles are not inherited by child processes if not has_spawnl: - return # ugh, can't use TestSkipped. + return # ugh, can't use SkipTest. - if test_support.verbose: + if support.verbose: v="v" else: v="q" @@ -314,14 +389,14 @@ decorated = sys.executable retval = os.spawnl(os.P_WAIT, sys.executable, decorated, tester, v, fd) - self.failIf(retval < 0, + self.assertFalse(retval < 0, "child process caught fatal signal %d" % -retval) - self.failIf(retval > 0, "child process reports failure %d"%retval) + self.assertFalse(retval > 0, "child process reports failure %d"%retval) def test_textmode(self): # _mkstemp_inner can create files in text mode if not has_textmode: - return # ugh, can't use TestSkipped. + return # ugh, can't use SkipTest. self.do_create(bin=0).write("blat\n") # XXX should test that the file really is a text file @@ -336,8 +411,8 @@ # gettempprefix returns a nonempty prefix string p = tempfile.gettempprefix() - self.assert_(isinstance(p, basestring)) - self.assert_(len(p) > 0) + self.assertIsInstance(p, basestring) + self.assertTrue(len(p) > 0) def test_usable_template(self): # gettempprefix returns a usable prefix string @@ -368,9 +443,9 @@ # gettempdir returns a directory which exists dir = tempfile.gettempdir() - self.assert_(os.path.isabs(dir) or dir == os.curdir, + self.assertTrue(os.path.isabs(dir) or dir == os.curdir, "%s is not an absolute path" % dir) - self.assert_(os.path.isdir(dir), + self.assertTrue(os.path.isdir(dir), "%s is not a directory" % dir) def test_directory_writable(self): @@ -391,7 +466,7 @@ a = tempfile.gettempdir() b = tempfile.gettempdir() - self.assert_(a is b) + self.assertTrue(a is b) def test_case_sensitive(self): # gettempdir should not flatten its case @@ -400,13 +475,13 @@ case_sensitive_tempdir = tempfile.mkdtemp("-Temp") _tempdir, tempfile.tempdir = tempfile.tempdir, None try: - with test_support.EnvironmentVarGuard() as env: + with support.EnvironmentVarGuard() as env: # Fake the first env var which is checked as a candidate env["TMPDIR"] = case_sensitive_tempdir self.assertEqual(tempfile.gettempdir(), case_sensitive_tempdir) finally: tempfile.tempdir = _tempdir - test_support.rmdir(case_sensitive_tempdir) + support.rmdir(case_sensitive_tempdir) test_classes.append(test_gettempdir) @@ -502,7 +577,7 @@ # mkdtemp creates directories with the proper mode if not has_stat: return # ugh, can't use TestSkipped. - if test_support.is_jython and not os._native_posix: + if support.is_jython and not os._native_posix: # Java doesn't support stating files for permissions return @@ -512,7 +587,7 @@ mode &= 0777 # Mask off sticky bits inherited from /tmp expected = 0700 if (sys.platform in ('win32', 'os2emx', 'mac') or - test_support.is_jython and os._name == 'nt'): + support.is_jython and os._name == 'nt'): # There's no distinction among 'user', 'group' and 'world'; # replicate the 'user' bits. user = expected >> 6 @@ -618,7 +693,7 @@ def test_creates_named(self): # NamedTemporaryFile creates files with names f = tempfile.NamedTemporaryFile() - self.failUnless(os.path.exists(f.name), + self.assertTrue(os.path.exists(f.name), "NamedTemporaryFile %s does not exist" % f.name) def test_del_on_close(self): @@ -628,7 +703,7 @@ f = tempfile.NamedTemporaryFile(dir=dir) f.write('blat') f.close() - self.failIf(os.path.exists(f.name), + self.assertFalse(os.path.exists(f.name), "NamedTemporaryFile %s exists after close" % f.name) finally: os.rmdir(dir) @@ -642,7 +717,7 @@ tmp = f.name f.write('blat') f.close() - self.failUnless(os.path.exists(f.name), + self.assertTrue(os.path.exists(f.name), "NamedTemporaryFile %s missing after close" % f.name) finally: if tmp is not None: @@ -663,12 +738,12 @@ def test_context_manager(self): # A NamedTemporaryFile can be used as a context manager with tempfile.NamedTemporaryFile() as f: - self.failUnless(os.path.exists(f.name)) - self.failIf(os.path.exists(f.name)) + self.assertTrue(os.path.exists(f.name)) + self.assertFalse(os.path.exists(f.name)) def use_closed(): with f: pass - self.failUnlessRaises(ValueError, use_closed) + self.assertRaises(ValueError, use_closed) # How to test the mode and bufsize parameters? @@ -691,21 +766,21 @@ def test_basic(self): # SpooledTemporaryFile can create files f = self.do_create() - self.failIf(f._rolled) + self.assertFalse(f._rolled) f = self.do_create(max_size=100, pre="a", suf=".txt") - self.failIf(f._rolled) + self.assertFalse(f._rolled) def test_del_on_close(self): # A SpooledTemporaryFile is deleted when closed dir = tempfile.mkdtemp() try: f = tempfile.SpooledTemporaryFile(max_size=10, dir=dir) - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.write('blat ' * 5) - self.failUnless(f._rolled) + self.assertTrue(f._rolled) filename = f.name f.close() - self.failIf(os.path.exists(filename), + self.assertFalse(os.path.exists(filename), "SpooledTemporaryFile %s exists after close" % filename) finally: os.rmdir(dir) @@ -713,46 +788,74 @@ def test_rewrite_small(self): # A SpooledTemporaryFile can be written to multiple within the max_size f = self.do_create(max_size=30) - self.failIf(f._rolled) + self.assertFalse(f._rolled) for i in range(5): f.seek(0, 0) f.write('x' * 20) - self.failIf(f._rolled) + self.assertFalse(f._rolled) def test_write_sequential(self): # A SpooledTemporaryFile should hold exactly max_size bytes, and roll # over afterward f = self.do_create(max_size=30) - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.write('x' * 20) - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.write('x' * 10) - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.write('x') - self.failUnless(f._rolled) + self.assertTrue(f._rolled) + + def test_writelines(self): + # Verify writelines with a SpooledTemporaryFile + f = self.do_create() + f.writelines((b'x', b'y', b'z')) + f.seek(0) + buf = f.read() + self.assertEqual(buf, b'xyz') + + def test_writelines_sequential(self): + # A SpooledTemporaryFile should hold exactly max_size bytes, and roll + # over afterward + f = self.do_create(max_size=35) + f.writelines((b'x' * 20, b'x' * 10, b'x' * 5)) + self.assertFalse(f._rolled) + f.write(b'x') + self.assertTrue(f._rolled) + + def test_xreadlines(self): + f = self.do_create(max_size=20) + f.write(b'abc\n' * 5) + f.seek(0) + self.assertFalse(f._rolled) + self.assertEqual(list(f.xreadlines()), [b'abc\n'] * 5) + f.write(b'x\ny') + self.assertTrue(f._rolled) + f.seek(0) + self.assertEqual(list(f.xreadlines()), [b'abc\n'] * 5 + [b'x\n', b'y']) def test_sparse(self): # A SpooledTemporaryFile that is written late in the file will extend # when that occurs f = self.do_create(max_size=30) - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.seek(100, 0) - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.write('x') - self.failUnless(f._rolled) + self.assertTrue(f._rolled) def test_fileno(self): # A SpooledTemporaryFile should roll over to a real file on fileno() f = self.do_create(max_size=30) - self.failIf(f._rolled) - self.failUnless(f.fileno() > 0) - self.failUnless(f._rolled) + self.assertFalse(f._rolled) + self.assertTrue(f.fileno() > 0) + self.assertTrue(f._rolled) def test_multiple_close_before_rollover(self): # A SpooledTemporaryFile can be closed many times without error f = tempfile.SpooledTemporaryFile() f.write('abc\n') - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.close() try: f.close() @@ -764,7 +867,7 @@ # A SpooledTemporaryFile can be closed many times without error f = tempfile.SpooledTemporaryFile(max_size=1) f.write('abc\n') - self.failUnless(f._rolled) + self.assertTrue(f._rolled) f.close() try: f.close() @@ -784,46 +887,69 @@ write("a" * 35) write("b" * 35) seek(0, 0) - self.failUnless(read(70) == 'a'*35 + 'b'*35) + self.assertTrue(read(70) == 'a'*35 + 'b'*35) + + def test_properties(self): + f = tempfile.SpooledTemporaryFile(max_size=10) + f.write(b'x' * 10) + self.assertFalse(f._rolled) + self.assertEqual(f.mode, 'w+b') + self.assertIsNone(f.name) + # Jython SpooledTemporaryFile has these properties: + if not support.is_jython: + with self.assertRaises(AttributeError): + f.newlines + with self.assertRaises(AttributeError): + f.encoding + + f.write(b'x') + self.assertTrue(f._rolled) + self.assertEqual(f.mode, 'w+b') + self.assertIsNotNone(f.name) + if not support.is_jython: + with self.assertRaises(AttributeError): + f.newlines + with self.assertRaises(AttributeError): + f.encoding def test_context_manager_before_rollover(self): # A SpooledTemporaryFile can be used as a context manager with tempfile.SpooledTemporaryFile(max_size=1) as f: - self.failIf(f._rolled) - self.failIf(f.closed) - self.failUnless(f.closed) + self.assertFalse(f._rolled) + self.assertFalse(f.closed) + self.assertTrue(f.closed) def use_closed(): with f: pass - self.failUnlessRaises(ValueError, use_closed) + self.assertRaises(ValueError, use_closed) def test_context_manager_during_rollover(self): # A SpooledTemporaryFile can be used as a context manager with tempfile.SpooledTemporaryFile(max_size=1) as f: - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.write('abc\n') f.flush() - self.failUnless(f._rolled) - self.failIf(f.closed) - self.failUnless(f.closed) + self.assertTrue(f._rolled) + self.assertFalse(f.closed) + self.assertTrue(f.closed) def use_closed(): with f: pass - self.failUnlessRaises(ValueError, use_closed) + self.assertRaises(ValueError, use_closed) def test_context_manager_after_rollover(self): # A SpooledTemporaryFile can be used as a context manager f = tempfile.SpooledTemporaryFile(max_size=1) f.write('abc\n') f.flush() - self.failUnless(f._rolled) + self.assertTrue(f._rolled) with f: - self.failIf(f.closed) - self.failUnless(f.closed) + self.assertFalse(f.closed) + self.assertTrue(f.closed) def use_closed(): with f: pass - self.failUnlessRaises(ValueError, use_closed) + self.assertRaises(ValueError, use_closed) test_classes.append(test_SpooledTemporaryFile) @@ -875,11 +1001,11 @@ test_classes.append(test_TemporaryFile) def test_main(): - test_support.run_unittest(*test_classes) + support.run_unittest(*test_classes) if __name__ == "__main__": test_main() - if test_support.is_jython: + if support.is_jython: # XXX: Nudge Java's GC in an attempt to trigger any temp file's # __del__ (cause them to be deleted) that hasn't been called import gc -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Apr 9 09:28:34 2015 From: jython-checkins at python.org (jeff.allen) Date: Thu, 09 Apr 2015 07:28:34 +0000 Subject: [Jython-checkins] =?utf-8?q?jython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_to_trunk?= Message-ID: <20150409072833.3523.3519@psf.io> https://hg.python.org/jython/rev/9525c2e984b6 changeset: 7653:9525c2e984b6 parent: 7648:4722f297d15c parent: 7652:f1af0477d30a user: Jeff Allen date: Thu Apr 09 08:26:47 2015 +0100 summary: Merge to trunk files: Lib/tempfile.py | 51 +- Lib/test/test_tempfile.py | 282 +++++++-- Lib/test/test_zipimport_support.py | 9 +- src/org/python/core/BaseBytes.java | 19 +- src/org/python/core/PyByteArray.java | 113 +-- src/org/python/core/PySequence.java | 80 +- src/org/python/core/SequenceIndexDelegate.java | 9 +- tests/java/org/python/core/BaseBytesTest.java | 92 +- tests/java/org/python/core/PyByteArrayTest.java | 233 +++---- 9 files changed, 496 insertions(+), 392 deletions(-) diff --git a/Lib/tempfile.py b/Lib/tempfile.py --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -29,6 +29,7 @@ # Imports. +import io as _io import os as _os import errno as _errno from random import Random as _Random @@ -160,11 +161,17 @@ dirname = _os.getenv(envname) if dirname: dirlist.append(dirname) + # Real name of OS + if _os.name != 'java': + os_name = _os.name + else: + os_name = _os._name + # Failing that, try OS-specific locations. - if _os.name == 'riscos': + if os_name == 'riscos': dirname = _os.getenv('Wimp$ScrapDir') if dirname: dirlist.append(dirname) - elif _os.name == 'nt': + elif os_name == 'nt': dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ]) else: dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ]) @@ -192,21 +199,24 @@ for dir in dirlist: if dir != _os.curdir: - dir = _os.path.normcase(_os.path.abspath(dir)) + dir = _os.path.abspath(dir) # See CPython Issue 14255 # Try only a few names per directory. for seq in xrange(100): name = namer.next() filename = _os.path.join(dir, name) try: - fd = _os.open(filename, flags, 0600) - fp = _os.fdopen(fd, 'w') - fp.write('blat') - fp.close() - _os.unlink(filename) - del fp, fd + fd = _os.open(filename, flags, 0o600) + try: + try: + with _io.open(fd, 'wb', closefd=False) as fp: + fp.write(b'blat') + finally: + _os.close(fd) + finally: + _os.unlink(filename) return dir - except (OSError, IOError), e: - if e[0] != _errno.EEXIST: + except (OSError, IOError) as e: + if e.args[0] != _errno.EEXIST: break # no point trying more names in this directory pass raise IOError, (_errno.ENOENT, @@ -552,7 +562,7 @@ return self._file.closed @property - def encoding(self): + def encoding(self): # Jython not CPython return self._file.encoding def fileno(self): @@ -567,14 +577,20 @@ @property def mode(self): - return self._file.mode + try: + return self._file.mode + except AttributeError: + return self._TemporaryFileArgs[0] @property def name(self): - return self._file.name + try: + return self._file.name + except AttributeError: + return None @property - def newlines(self): + def newlines(self): # Jython not CPython return self._file.newlines def next(self): @@ -615,4 +631,7 @@ return rv def xreadlines(self, *args): - return self._file.xreadlines(*args) + try: + return self._file.xreadlines(*args) + except AttributeError: + return iter(self._file.readlines(*args)) diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -1,14 +1,16 @@ -# From Python 2.5.1 # tempfile.py unit tests. import tempfile +import errno +import io import os +import signal +import shutil import sys import re -import errno import warnings import unittest -from test import test_support +from test import test_support as support warnings.filterwarnings("ignore", category=RuntimeWarning, @@ -62,7 +64,7 @@ "file '%s' does not end with '%s'" % (nbase, suf)) nbase = nbase[len(pre):len(nbase)-len(suf)] - self.assert_(self.str_check.match(nbase), + self.assertTrue(self.str_check.match(nbase), "random string '%s' does not match /^[a-zA-Z0-9_-]{6}$/" % nbase) @@ -91,7 +93,7 @@ for key in dict: if key[0] != '_' and key not in expected: unexp.append(key) - self.failUnless(len(unexp) == 0, + self.assertTrue(len(unexp) == 0, "unexpected keys: %s" % unexp) test_classes.append(test_exports) @@ -116,7 +118,7 @@ for i in xrange(TEST_FILES): s = r.next() self.nameCheck(s, '', '', '') - self.failIf(s in dict) + self.assertNotIn(s, dict) dict[s] = 1 def test_supports_iter(self): @@ -132,6 +134,37 @@ except: self.failOnException("iteration") + @unittest.skipUnless(hasattr(os, 'fork'), + "os.fork is required for this test") + def test_process_awareness(self): + # ensure that the random source differs between + # child and parent. + read_fd, write_fd = os.pipe() + pid = None + try: + pid = os.fork() + if not pid: + os.close(read_fd) + os.write(write_fd, next(self.r).encode("ascii")) + os.close(write_fd) + # bypass the normal exit handlers- leave those to + # the parent. + os._exit(0) + parent_value = next(self.r) + child_value = os.read(read_fd, len(parent_value)).decode("ascii") + finally: + if pid: + # best effort to ensure the process can't bleed out + # via any bugs above + try: + os.kill(pid, signal.SIGKILL) + except EnvironmentError: + pass + os.close(read_fd) + os.close(write_fd) + self.assertNotEqual(child_value, parent_value) + + test_classes.append(test__RandomNameSequence) @@ -143,42 +176,84 @@ cand = tempfile._candidate_tempdir_list() - self.failIf(len(cand) == 0) + self.assertFalse(len(cand) == 0) for c in cand: - self.assert_(isinstance(c, basestring), - "%s is not a string" % c) + self.assertIsInstance(c, basestring) def test_wanted_dirs(self): # _candidate_tempdir_list contains the expected directories # Make sure the interesting environment variables are all set. - with test_support.EnvironmentVarGuard() as env: + with support.EnvironmentVarGuard() as env: for envname in 'TMPDIR', 'TEMP', 'TMP': dirname = os.getenv(envname) if not dirname: - env.set(envname, os.path.abspath(envname)) + env[envname] = os.path.abspath(envname) cand = tempfile._candidate_tempdir_list() for envname in 'TMPDIR', 'TEMP', 'TMP': dirname = os.getenv(envname) if not dirname: raise ValueError - self.assert_(dirname in cand) + self.assertIn(dirname, cand) try: dirname = os.getcwd() except (AttributeError, os.error): dirname = os.curdir - self.assert_(dirname in cand) + self.assertIn(dirname, cand) # Not practical to try to verify the presence of OS-specific # paths in this list. test_classes.append(test__candidate_tempdir_list) +# We test _get_default_tempdir some more by testing gettempdir. -# We test _get_default_tempdir by testing gettempdir. +class TestGetDefaultTempdir(TC): + """Test _get_default_tempdir().""" + + def test_no_files_left_behind(self): + # use a private empty directory + our_temp_directory = tempfile.mkdtemp() + try: + # force _get_default_tempdir() to consider our empty directory + def our_candidate_list(): + return [our_temp_directory] + + with support.swap_attr(tempfile, "_candidate_tempdir_list", + our_candidate_list): + # verify our directory is empty after _get_default_tempdir() + tempfile._get_default_tempdir() + self.assertEqual(os.listdir(our_temp_directory), []) + + def raise_OSError(*args, **kwargs): + raise OSError(-1) + + with support.swap_attr(io, "open", raise_OSError): + # test again with failing io.open() + with self.assertRaises(IOError) as cm: + tempfile._get_default_tempdir() + self.assertEqual(cm.exception.errno, errno.ENOENT) + self.assertEqual(os.listdir(our_temp_directory), []) + + open = io.open + def bad_writer(*args, **kwargs): + fp = open(*args, **kwargs) + fp.write = raise_OSError + return fp + + with support.swap_attr(io, "open", bad_writer): + # test again with failing write() + with self.assertRaises(IOError) as cm: + tempfile._get_default_tempdir() + self.assertEqual(cm.exception.errno, errno.ENOENT) + self.assertEqual(os.listdir(our_temp_directory), []) + finally: + shutil.rmtree(our_temp_directory) + +test_classes.append(TestGetDefaultTempdir) class test__get_candidate_names(TC): @@ -187,14 +262,14 @@ def test_retval(self): # _get_candidate_names returns a _RandomNameSequence object obj = tempfile._get_candidate_names() - self.assert_(isinstance(obj, tempfile._RandomNameSequence)) + self.assertIsInstance(obj, tempfile._RandomNameSequence) def test_same_thing(self): # _get_candidate_names always returns the same object a = tempfile._get_candidate_names() b = tempfile._get_candidate_names() - self.assert_(a is b) + self.assertTrue(a is b) test_classes.append(test__get_candidate_names) @@ -268,7 +343,7 @@ def _test_file_mode(self): # _mkstemp_inner creates files with the proper mode if not has_stat: - return # ugh, can't use TestSkipped. + return # ugh, can't use SkipTest. file = self.do_create() mode = stat.S_IMODE(os.stat(file.name).st_mode) @@ -283,9 +358,9 @@ def test_noinherit(self): # _mkstemp_inner file handles are not inherited by child processes if not has_spawnl: - return # ugh, can't use TestSkipped. + return # ugh, can't use SkipTest. - if test_support.verbose: + if support.verbose: v="v" else: v="q" @@ -314,14 +389,14 @@ decorated = sys.executable retval = os.spawnl(os.P_WAIT, sys.executable, decorated, tester, v, fd) - self.failIf(retval < 0, + self.assertFalse(retval < 0, "child process caught fatal signal %d" % -retval) - self.failIf(retval > 0, "child process reports failure %d"%retval) + self.assertFalse(retval > 0, "child process reports failure %d"%retval) def test_textmode(self): # _mkstemp_inner can create files in text mode if not has_textmode: - return # ugh, can't use TestSkipped. + return # ugh, can't use SkipTest. self.do_create(bin=0).write("blat\n") # XXX should test that the file really is a text file @@ -336,8 +411,8 @@ # gettempprefix returns a nonempty prefix string p = tempfile.gettempprefix() - self.assert_(isinstance(p, basestring)) - self.assert_(len(p) > 0) + self.assertIsInstance(p, basestring) + self.assertTrue(len(p) > 0) def test_usable_template(self): # gettempprefix returns a usable prefix string @@ -368,9 +443,9 @@ # gettempdir returns a directory which exists dir = tempfile.gettempdir() - self.assert_(os.path.isabs(dir) or dir == os.curdir, + self.assertTrue(os.path.isabs(dir) or dir == os.curdir, "%s is not an absolute path" % dir) - self.assert_(os.path.isdir(dir), + self.assertTrue(os.path.isdir(dir), "%s is not a directory" % dir) def test_directory_writable(self): @@ -391,7 +466,23 @@ a = tempfile.gettempdir() b = tempfile.gettempdir() - self.assert_(a is b) + self.assertTrue(a is b) + + def test_case_sensitive(self): + # gettempdir should not flatten its case + # even on a case-insensitive file system + # See CPython Issue 14255 (back-ported for Jython) + case_sensitive_tempdir = tempfile.mkdtemp("-Temp") + _tempdir, tempfile.tempdir = tempfile.tempdir, None + try: + with support.EnvironmentVarGuard() as env: + # Fake the first env var which is checked as a candidate + env["TMPDIR"] = case_sensitive_tempdir + self.assertEqual(tempfile.gettempdir(), case_sensitive_tempdir) + finally: + tempfile.tempdir = _tempdir + support.rmdir(case_sensitive_tempdir) + test_classes.append(test_gettempdir) @@ -486,7 +577,7 @@ # mkdtemp creates directories with the proper mode if not has_stat: return # ugh, can't use TestSkipped. - if test_support.is_jython and not os._native_posix: + if support.is_jython and not os._native_posix: # Java doesn't support stating files for permissions return @@ -496,7 +587,7 @@ mode &= 0777 # Mask off sticky bits inherited from /tmp expected = 0700 if (sys.platform in ('win32', 'os2emx', 'mac') or - test_support.is_jython and os._name == 'nt'): + support.is_jython and os._name == 'nt'): # There's no distinction among 'user', 'group' and 'world'; # replicate the 'user' bits. user = expected >> 6 @@ -602,7 +693,7 @@ def test_creates_named(self): # NamedTemporaryFile creates files with names f = tempfile.NamedTemporaryFile() - self.failUnless(os.path.exists(f.name), + self.assertTrue(os.path.exists(f.name), "NamedTemporaryFile %s does not exist" % f.name) def test_del_on_close(self): @@ -612,7 +703,7 @@ f = tempfile.NamedTemporaryFile(dir=dir) f.write('blat') f.close() - self.failIf(os.path.exists(f.name), + self.assertFalse(os.path.exists(f.name), "NamedTemporaryFile %s exists after close" % f.name) finally: os.rmdir(dir) @@ -626,7 +717,7 @@ tmp = f.name f.write('blat') f.close() - self.failUnless(os.path.exists(f.name), + self.assertTrue(os.path.exists(f.name), "NamedTemporaryFile %s missing after close" % f.name) finally: if tmp is not None: @@ -647,12 +738,12 @@ def test_context_manager(self): # A NamedTemporaryFile can be used as a context manager with tempfile.NamedTemporaryFile() as f: - self.failUnless(os.path.exists(f.name)) - self.failIf(os.path.exists(f.name)) + self.assertTrue(os.path.exists(f.name)) + self.assertFalse(os.path.exists(f.name)) def use_closed(): with f: pass - self.failUnlessRaises(ValueError, use_closed) + self.assertRaises(ValueError, use_closed) # How to test the mode and bufsize parameters? @@ -675,21 +766,21 @@ def test_basic(self): # SpooledTemporaryFile can create files f = self.do_create() - self.failIf(f._rolled) + self.assertFalse(f._rolled) f = self.do_create(max_size=100, pre="a", suf=".txt") - self.failIf(f._rolled) + self.assertFalse(f._rolled) def test_del_on_close(self): # A SpooledTemporaryFile is deleted when closed dir = tempfile.mkdtemp() try: f = tempfile.SpooledTemporaryFile(max_size=10, dir=dir) - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.write('blat ' * 5) - self.failUnless(f._rolled) + self.assertTrue(f._rolled) filename = f.name f.close() - self.failIf(os.path.exists(filename), + self.assertFalse(os.path.exists(filename), "SpooledTemporaryFile %s exists after close" % filename) finally: os.rmdir(dir) @@ -697,46 +788,74 @@ def test_rewrite_small(self): # A SpooledTemporaryFile can be written to multiple within the max_size f = self.do_create(max_size=30) - self.failIf(f._rolled) + self.assertFalse(f._rolled) for i in range(5): f.seek(0, 0) f.write('x' * 20) - self.failIf(f._rolled) + self.assertFalse(f._rolled) def test_write_sequential(self): # A SpooledTemporaryFile should hold exactly max_size bytes, and roll # over afterward f = self.do_create(max_size=30) - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.write('x' * 20) - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.write('x' * 10) - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.write('x') - self.failUnless(f._rolled) + self.assertTrue(f._rolled) + + def test_writelines(self): + # Verify writelines with a SpooledTemporaryFile + f = self.do_create() + f.writelines((b'x', b'y', b'z')) + f.seek(0) + buf = f.read() + self.assertEqual(buf, b'xyz') + + def test_writelines_sequential(self): + # A SpooledTemporaryFile should hold exactly max_size bytes, and roll + # over afterward + f = self.do_create(max_size=35) + f.writelines((b'x' * 20, b'x' * 10, b'x' * 5)) + self.assertFalse(f._rolled) + f.write(b'x') + self.assertTrue(f._rolled) + + def test_xreadlines(self): + f = self.do_create(max_size=20) + f.write(b'abc\n' * 5) + f.seek(0) + self.assertFalse(f._rolled) + self.assertEqual(list(f.xreadlines()), [b'abc\n'] * 5) + f.write(b'x\ny') + self.assertTrue(f._rolled) + f.seek(0) + self.assertEqual(list(f.xreadlines()), [b'abc\n'] * 5 + [b'x\n', b'y']) def test_sparse(self): # A SpooledTemporaryFile that is written late in the file will extend # when that occurs f = self.do_create(max_size=30) - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.seek(100, 0) - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.write('x') - self.failUnless(f._rolled) + self.assertTrue(f._rolled) def test_fileno(self): # A SpooledTemporaryFile should roll over to a real file on fileno() f = self.do_create(max_size=30) - self.failIf(f._rolled) - self.failUnless(f.fileno() > 0) - self.failUnless(f._rolled) + self.assertFalse(f._rolled) + self.assertTrue(f.fileno() > 0) + self.assertTrue(f._rolled) def test_multiple_close_before_rollover(self): # A SpooledTemporaryFile can be closed many times without error f = tempfile.SpooledTemporaryFile() f.write('abc\n') - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.close() try: f.close() @@ -748,7 +867,7 @@ # A SpooledTemporaryFile can be closed many times without error f = tempfile.SpooledTemporaryFile(max_size=1) f.write('abc\n') - self.failUnless(f._rolled) + self.assertTrue(f._rolled) f.close() try: f.close() @@ -768,46 +887,69 @@ write("a" * 35) write("b" * 35) seek(0, 0) - self.failUnless(read(70) == 'a'*35 + 'b'*35) + self.assertTrue(read(70) == 'a'*35 + 'b'*35) + + def test_properties(self): + f = tempfile.SpooledTemporaryFile(max_size=10) + f.write(b'x' * 10) + self.assertFalse(f._rolled) + self.assertEqual(f.mode, 'w+b') + self.assertIsNone(f.name) + # Jython SpooledTemporaryFile has these properties: + if not support.is_jython: + with self.assertRaises(AttributeError): + f.newlines + with self.assertRaises(AttributeError): + f.encoding + + f.write(b'x') + self.assertTrue(f._rolled) + self.assertEqual(f.mode, 'w+b') + self.assertIsNotNone(f.name) + if not support.is_jython: + with self.assertRaises(AttributeError): + f.newlines + with self.assertRaises(AttributeError): + f.encoding def test_context_manager_before_rollover(self): # A SpooledTemporaryFile can be used as a context manager with tempfile.SpooledTemporaryFile(max_size=1) as f: - self.failIf(f._rolled) - self.failIf(f.closed) - self.failUnless(f.closed) + self.assertFalse(f._rolled) + self.assertFalse(f.closed) + self.assertTrue(f.closed) def use_closed(): with f: pass - self.failUnlessRaises(ValueError, use_closed) + self.assertRaises(ValueError, use_closed) def test_context_manager_during_rollover(self): # A SpooledTemporaryFile can be used as a context manager with tempfile.SpooledTemporaryFile(max_size=1) as f: - self.failIf(f._rolled) + self.assertFalse(f._rolled) f.write('abc\n') f.flush() - self.failUnless(f._rolled) - self.failIf(f.closed) - self.failUnless(f.closed) + self.assertTrue(f._rolled) + self.assertFalse(f.closed) + self.assertTrue(f.closed) def use_closed(): with f: pass - self.failUnlessRaises(ValueError, use_closed) + self.assertRaises(ValueError, use_closed) def test_context_manager_after_rollover(self): # A SpooledTemporaryFile can be used as a context manager f = tempfile.SpooledTemporaryFile(max_size=1) f.write('abc\n') f.flush() - self.failUnless(f._rolled) + self.assertTrue(f._rolled) with f: - self.failIf(f.closed) - self.failUnless(f.closed) + self.assertFalse(f.closed) + self.assertTrue(f.closed) def use_closed(): with f: pass - self.failUnlessRaises(ValueError, use_closed) + self.assertRaises(ValueError, use_closed) test_classes.append(test_SpooledTemporaryFile) @@ -859,11 +1001,11 @@ test_classes.append(test_TemporaryFile) def test_main(): - test_support.run_unittest(*test_classes) + support.run_unittest(*test_classes) if __name__ == "__main__": test_main() - if test_support.is_jython: + if support.is_jython: # XXX: Nudge Java's GC in an attempt to trigger any temp file's # __del__ (cause them to be deleted) that hasn't been called import gc diff --git a/Lib/test/test_zipimport_support.py b/Lib/test/test_zipimport_support.py --- a/Lib/test/test_zipimport_support.py +++ b/Lib/test/test_zipimport_support.py @@ -231,7 +231,6 @@ print data self.assertIn(expected, data) - @unittest.skipIf(is_jython, "FIXME: not working on Jython") def test_pdb_issue4201(self): test_src = textwrap.dedent("""\ def f(): @@ -245,13 +244,17 @@ p = spawn_python(script_name) p.stdin.write('l\n') data = kill_python(p) - self.assertIn(script_name, data) + # bdb/pdb applies normcase to its filename before displaying + # See CPython Issue 14255 (back-ported for Jython) + self.assertIn(os.path.normcase(script_name.encode('utf-8')), data) zip_name, run_name = make_zip_script(d, "test_zip", script_name, '__main__.py') p = spawn_python(zip_name) p.stdin.write('l\n') data = kill_python(p) - self.assertIn(run_name, data) + # bdb/pdb applies normcase to its filename before displaying + # See CPython Issue 14255 (back-ported for Jython) + self.assertIn(os.path.normcase(run_name.encode('utf-8')), data) def test_main(): diff --git a/src/org/python/core/BaseBytes.java b/src/org/python/core/BaseBytes.java --- a/src/org/python/core/BaseBytes.java +++ b/src/org/python/core/BaseBytes.java @@ -736,20 +736,10 @@ */ private class IndexDelegate extends PySequence.DefaultIndexDelegate { - /* + /** * bytearray treats assignment of a zero-length object to a slice as equivalent to deletion, * unlike list, even for an extended slice. */ - // >>> a = range(10) - // >>> b = bytearray(a) - // >>> a[1:6:2] = [] - // Traceback (most recent call last): - // File "", line 1, in - // ValueError: attempt to assign sequence of size 0 to extended slice of size 3 - // >>> b[1:6:2] = [] - // >>> b - // bytearray(b'\x00\x02\x04\x06\x07\x08\t') - // @Override public void checkIdxAndSetSlice(PySlice slice, PyObject value) { if (value.__len__() != 0) { @@ -757,9 +747,14 @@ super.checkIdxAndSetSlice(slice, value); } else { // Treat as deletion - super.checkIdxAndDelItem(slice); + checkIdxAndDelItem(slice); } } + + @Override + protected void delSlice(int[] indices) { + delslice(indices[0], indices[1], indices[2], indices[3]); + } }; /* diff --git a/src/org/python/core/PyByteArray.java b/src/org/python/core/PyByteArray.java --- a/src/org/python/core/PyByteArray.java +++ b/src/org/python/core/PyByteArray.java @@ -676,53 +676,59 @@ } } - /* - * Deletes an element from the sequence (and closes up the gap). - * - * @param index index of the element to delete. - */ @Override protected synchronized void del(int index) { - // XXX Change SequenceIndexDelegate to avoid repeated calls to del(int) for extended slice storageDelete(index, 1); } - /* - * Deletes contiguous sub-sequence (and closes up the gap). - * - * @param start the position of the first element. - * - * @param stop one more than the position of the last element. - */ @Override protected synchronized void delRange(int start, int stop) { storageDelete(start, stop - start); } - /** - * Deletes a simple or extended slice and closes up the gap(s). - * - * @param start the position of the first element. - * @param stop one more than the position of the last element. - * @param step from one element to the next - */ - protected synchronized void delslice(int start, int stop, int step) { + @Override + protected synchronized void delslice(int start, int stop, int step, int n) { + // This will not be possible if this object has buffer exports + resizeCheck(); + if (step == 1) { - // Delete this[start:stop] and closing up the space - storageDelete(start, stop - start); + // Delete this[start:stop] and close up the space. + storageDelete(start, n); + + } else if (step == -1) { + // Also a contiguous case, but start > stop. + storageDelete(stop + 1, n); + } else { - // This is an extended slice which means we are removing isolated elements - int n = sliceLength(start, stop, step); + // This is an extended slice. We will be deleting n isolated elements. + int p, m; - if (n > 0) { - if (step > 0) { - // The first element is x[start] and the last is x[start+(n-1)*step+1] - storageDeleteEx(start, step, n); - } else { - // The first element is x[start+(n-1)*step+1] and the last is x[start] - storageDeleteEx(start + (n - 1) * step + 1, -step, n); + // We delete by copying from high to low memory, whatever the sign of step. + if (step > 1) { + // The lowest numbered element to delete is x[start] + p = start; + m = step - 1; + } else { + // The lowest numbered element to delete is x[start+(n-1)*step]] + p = start + (n - 1) * step; + m = -1 - step; + } + + // Offset p to be a storage index. + p += offset; + + // Copy n-1 blocks blocks of m bytes, each time skipping the byte to be deleted. + for (int i = 1; i < n; i++) { + // Skip q over the one we are deleting + int q = p + i; + // Now copy the m elements that follow. + for (int j = 0; j < m; j++) { + storage[p++] = storage[q++]; } } + + // Close up the gap. Note that for the copy, p was adjusted by the storage offset. + storageDelete(p - offset, n); } } @@ -2654,47 +2660,4 @@ } } - /** - * Delete d elements on a stride of c beginning at index - * a by moving together the surrounding elements. The method manipulates the - * storage array, size and offset, and will allocate a - * new storage array if the deletion is big enough. If the initial storage looks like this: - * - *
-     * |-                               L                                -|
-     *       |-                    s                    -|
-     * |--f--|-----a-----|---------e---------|-----b-----|----------------|
-     * 
- * - * then after the call the (possibly new) storage looks like this: - * - *
-     * |-                   L'                         -|
-     *      |-                s'               -|
-     * |-f'-|-----a-----|---(e-d)---|-----b-----|-------|
-     * 
- * - * where the regions of length a and b=size-(a+e) have been preserved - * and the e intervening elements reduced to e-d elements, by removing - * exactly the elements with indices (relative to the start of valid data) a+k*c - * for k=0...d-1. The effect on this PyByteArray is that: - * - *
-     * this.offset = f'
-     * this.size = s' = a+b
-     * 
- * - * The method does not implement the Python repertoire of slice indices but avoids indexing - * outside the bytearray by silently adjusting a to be within it. Negative d is - * treated as 0 and if d is too large, it is truncated to the array end. - * - * @param a index of hole in byte array - * @param c (>0) step size between the locations of elements to delete - * @param d number to discard (will discard x[a+k*c] for k=0...d-1) - */ - private void storageDeleteEx(int a, int c, int d) { - - // XXX Base this on storageReplace with the same apyget(int) the index is within the bounds of the array. Any other * clients must make the same guarantee. - * + * * @param index index of element to return. * @return the element at the given position in the list. */ @@ -68,8 +68,8 @@ protected abstract PyObject getslice(int start, int stop, int step); /** - * Returns a (concrete subclass of) PySequence that repeats the given sequence, as - * in the implementation of __mul__ for strings. + * Returns a (concrete subclass of) PySequence that repeats the given sequence, as in the + * implementation of __mul__ for strings. * * @param count the number of times to repeat the sequence. * @return this sequence repeated count times. @@ -82,7 +82,7 @@ * called by PySequence in its implementation of {@link #__setitem__} It is guaranteed by * PySequence that when it calls pyset(int) the index is within the bounds of the array. Any * other clients must make the same guarantee. - * + * * @param index index of the element to set. * @param value the value to set this element to. */ @@ -91,45 +91,60 @@ } /** - * Sets the given range of elements according to Python slice assignment semantics. - * If the step size is one, it is a simple slice and the operation is equivalent to - * deleting that slice, then inserting the value at that position, regarding the - * value as a sequence (if possible) or as a single element if it is not a sequence. - * If the step size is not one, but start==stop, it is equivalent to insertion - * at that point. - * If the step size is not one, and start!=stop, the slice defines a certain number - * of elements to be replaced, and the value must be a sequence of exactly that many - * elements (or convertible to such a sequence). - * + * Sets the given range of elements according to Python slice assignment semantics. If the step + * size is one, it is a simple slice and the operation is equivalent to deleting that slice, + * then inserting the value at that position, regarding the value as a sequence (if possible) or + * as a single element if it is not a sequence. If the step size is not one, but + * start==stop, it is equivalent to insertion at that point. If the step size is + * not one, and start!=stop, the slice defines a certain number of elements to be + * replaced, and the value must be a sequence of exactly that many elements (or convertible to + * such a sequence). + * * @param start the position of the first element. * @param stop one more than the position of the last element. * @param step the step size. * @param value an object consistent with the slice assignment */ protected void setslice(int start, int stop, int step, PyObject value) { - throw Py.TypeError(String.format("'%s' object does not support item assignment", - getType().fastGetName())); + throw Py.TypeError(String.format("'%s' object does not support item assignment", getType() + .fastGetName())); } /** * Deletes an element from the sequence (and closes up the gap). - * + * * @param index index of the element to delete. */ protected void del(int index) { - throw Py.TypeError(String.format("'%s' object does not support item deletion", - getType().fastGetName())); + delslice(index, index, 1, 1); // Raises TypeError (for immutable types). } /** * Deletes a contiguous sub-sequence (and closes up the gap). - * + * * @param start the position of the first element. * @param stop one more than the position of the last element. */ protected void delRange(int start, int stop) { - throw Py.TypeError(String.format("'%s' object does not support item deletion", - getType().fastGetName())); + delslice(start, stop, 1, Math.abs(stop - start)); // Raises TypeError (for immutable types). + } + + /** + * Deletes a simple or extended slice and closes up the gap(s). The slice parameters + * [start:stop:step] mean what they would in Python, after application of + * the "end-relative" rules for negative numbers and None. The count n + * is as supplied by {@link PySlice#indicesEx(int)}. This method is unsafe in that slice + * parameters are assumed correct. + * + * @param start the position of the first element. + * @param stop beyond the position of the last element (not necessarily just beyond). + * @param step from one element to the next (positive or negative) + * @param n number of elements to delete + */ + protected void delslice(int start, int stop, int step, int n) { + // Raises TypeError (for immutable types). + throw Py.TypeError(String.format("'%s' object does not support item deletion", getType() + .fastGetName())); } @Override @@ -265,10 +280,9 @@ /** * Compare the specified object/length pairs. * - * @return value >= 0 is the index where the sequences differs. - * -1: reached the end of o1 without a difference - * -2: reached the end of both seqeunces without a difference - * -3: reached the end of o2 without a difference + * @return value >= 0 is the index where the sequences differs. -1: reached the end of o1 + * without a difference -2: reached the end of both seqeunces without a difference -3: + * reached the end of o2 without a difference */ protected static int cmp(PyObject o1, int ol1, PyObject o2, int ol2) { if (ol1 < 0) { @@ -320,9 +334,8 @@ } /** - * Adjusts index such that it's >= 0 and <= __len__. If - * index starts off negative, it's treated as an index from the end of - * the sequence going back to the start. + * Adjusts index such that it's >= 0 and <= __len__. If index starts + * off negative, it's treated as an index from the end of the sequence going back to the start. */ protected int boundToSequence(int index) { int length = __len__(); @@ -514,7 +527,6 @@ delRange(start, stop); } - @Override public PyObject getItem(int idx) { return pyget(idx); diff --git a/src/org/python/core/SequenceIndexDelegate.java b/src/org/python/core/SequenceIndexDelegate.java --- a/src/org/python/core/SequenceIndexDelegate.java +++ b/src/org/python/core/SequenceIndexDelegate.java @@ -109,7 +109,14 @@ } } - private void delSlice(int[] indices) { + /** + * Implement the deletion of a slice. This method is called by + * {@link #checkIdxAndDelItem(PyObject)} when the argument is a {@link PySlice}. The argument is + * the return from {@link PySlice#indicesEx(int)}. + * + * @param indices containing [start, stop, step, count] of the slice to delete + */ + protected void delSlice(int[] indices) { int p = indices[0], step = indices[2], count = indices[3]; if (step > 1) { /* diff --git a/tests/java/org/python/core/BaseBytesTest.java b/tests/java/org/python/core/BaseBytesTest.java --- a/tests/java/org/python/core/BaseBytesTest.java +++ b/tests/java/org/python/core/BaseBytesTest.java @@ -33,7 +33,7 @@ // Constants for array sizes public static final int SMALL = 7; // Less than minimum storage size public static final int MEDIUM = 25; // Medium array size - public static final int LARGE = 10000; // Large enough for performance measurement + public static final int LARGE = 2000; // Large enough for performance measurement public static final int HUGE = 100000; // Serious performance challenge /** @@ -55,7 +55,7 @@ /** * Turn a String into ints, but in the Python byte range, reducing character codes mod 256. - * + * * @param s the string * @return */ @@ -71,7 +71,7 @@ /** * Generate ints at random in the range 0..255. - * + * * @param random the random generator * @param n length of array * @return the array of random values @@ -86,7 +86,7 @@ /** * Generate ints at random in a restricted range. - * + * * @param random the random generator * @param n length of array * @param lo lowest value to generate @@ -104,7 +104,7 @@ /** * Compare expected and result array sections at specified locations and length. - * + * * @param expected reference values (may be null iff len==0) * @param first first value to compare in expected values * @param result bytearray from method under test @@ -114,7 +114,9 @@ static void checkInts(int[] expected, int first, BaseBytes result, int start, int len) { if (len > 0) { int end = first + len; - if (end > expected.length) end = expected.length; + if (end > expected.length) { + end = expected.length; + } for (int i = first, j = start; i < end; i++, j++) { assertEquals("element value", expected[i], result.intAt(j)); } @@ -123,7 +125,7 @@ /** * Compare expected and result array in their entirety. - * + * * @param expected * @param result */ @@ -138,7 +140,7 @@ /** * Compare expected List and result array in their entirety. - * + * * @param expected * @param result */ @@ -157,7 +159,7 @@ /** * Compare expected List and result object in their entirety. - * + * * @param expected * @param result */ @@ -168,7 +170,7 @@ /** * Turn array into Iterable, treating as unsigned (Python-style) bytes, and producing * an abusive mixture of object types. - * + * * @return iterable list */ public static Iterable iterableBytes(int[] source) { @@ -198,7 +200,7 @@ /* * (non-Javadoc) - * + * * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { @@ -206,7 +208,6 @@ random = new Random(20120310L); } - /** * Test method for {@link org.python.core.BaseBytes#init(int)} via MyBytes constructor, and for * {@link org.python.core.BaseBytes#size()}. @@ -274,17 +275,13 @@ */ public void testInit_PyObject() { // A scary set of objects - final PyObject[] brantub = {null, - new PyInteger(5), - new PyString("\u00A0\u00A1\u00A2\u00A3\u00A4"), - getInstance(new int[] {180, 190, 200}), - new PyXRange(1, 301, 50)}; + final PyObject[] brantub = + {null, new PyInteger(5), new PyString("\u00A0\u00A1\u00A2\u00A3\u00A4"), + getInstance(new int[] {180, 190, 200}), new PyXRange(1, 301, 50)}; // The array contents we should obtain - final int[][] prize = { {}, - {0, 0, 0, 0, 0}, - {160, 161, 162, 163, 164}, - {180, 190, 200}, - {1, 51, 101, 151, 201, 251}}; + final int[][] prize = + { {}, {0, 0, 0, 0, 0}, {160, 161, 162, 163, 164}, {180, 190, 200}, + {1, 51, 101, 151, 201, 251}}; // Work down the lists for (int dip = 0; dip < brantub.length; dip++) { int[] aRef = prize[dip]; @@ -359,7 +356,7 @@ /** * Test method for {@link BaseBytes#getslice(int, int, int)}. - * + * * @see PySequence#__getslice__(PyObject, PyObject) */ public void testGetslice() { @@ -480,7 +477,7 @@ a.setslice(start, stop, step, x); System.out.println(toString(a)); fail(String.format("Exception not thrown for setslice(%d,%d,%d,%s)", start, stop, step, - x)); + x)); } catch (PyException pye) { // System.out.println(pye); PyObject b = pye.type; @@ -549,7 +546,7 @@ /** * Create a zero-length Python byte array of explicitly-specified sub-type - * + * * @param type explicit Jython type */ public MyBytes(PyType type) { @@ -565,7 +562,7 @@ /** * Create zero-filled Python byte array of specified size. - * + * * @param size of byte array */ public MyBytes(int size) { @@ -574,7 +571,7 @@ /** * Create from integer array - * + * * @param value */ MyBytes(int[] value) { @@ -583,7 +580,7 @@ /** * Create a new array filled exactly by a copy of the contents of the source byte array. - * + * * @param value of the bytes */ public MyBytes(BaseBytes value) { @@ -593,7 +590,7 @@ /** * Create a new array filled exactly by a copy of the contents of the source. - * + * * @param value source of the bytes (and size) */ public MyBytes(BufferProtocol value) { @@ -604,7 +601,7 @@ /** * Create a new array filled from an iterable of PyObject. The iterable must yield objects * convertible to Python bytes (non-negative integers less than 256 or strings of length 1). - * + * * @param value of the bytes */ public MyBytes(Iterable value) { @@ -615,7 +612,7 @@ /** * Create a new array by encoding a PyString argument to bytes. If the PyString is actually * a PyUnicode, the encoding must be explicitly specified. - * + * * @param arg primary argument from which value is taken * @param encoding name of optional encoding (must be a string type) * @param errors name of optional errors policy (must be a string type) @@ -628,7 +625,7 @@ /** * Create a new array by encoding a PyString argument to bytes. If the PyString is actually * a PyUnicode, the encoding must be explicitly specified. - * + * * @param arg primary argument from which value is taken * @param encoding name of optional encoding (may be null to select the default for this * installation) @@ -658,7 +655,7 @@ * {@link #MyBytes(PyString, String, String)}. If the PyString is actually a PyUnicode, an * encoding must be specified, and using this constructor will throw an exception about * that. - * + * * @param arg primary argument from which value is taken (may be null) * @throws PyException in the same circumstances as bytes(arg), TypeError for non-iterable, * non-integer argument type, and ValueError if iterables do not yield byte @@ -675,7 +672,7 @@ * just one term. It is safe because MyBytes is immutable. But it may not be wise if the * source object is a large array from which only a small part needs to be retained in * memory. - * + * * @param type explicit Jython type * @param start index of first byte to use in source * @param stop 1 + index of last byte to use in source @@ -689,7 +686,7 @@ /** * Returns a PyByteArray that repeats this sequence the given number of times, as in the * implementation of __mul__ for strings. - * + * * @param count the number of times to repeat this. * @return this byte array repeated count times. */ @@ -702,7 +699,7 @@ /** * Returns a range of elements from the sequence. - * + * * @see org.python.core.PySequence#getslice(int, int, int) */ @Override @@ -727,7 +724,7 @@ /** * Return number of elements - * + * * @see org.python.core.PyObject#__len__() */ @Override @@ -776,7 +773,7 @@ /** * Store integer array as bytes: range must be 0..255 inclusive. - * + * * @param value integers to store */ BufferedObject(int[] value) { @@ -823,8 +820,9 @@ // Show in image s[pos:pos+n] (as 2*n characters) private void append(byte[] s, int pos, int n) { - if (pos < 0 || pos + n > s.length) + if (pos < 0 || pos + n > s.length) { return; + } for (int i = 0; i < n; i++) { int c = 0xff & ((int)s[pos + i]); if (c == 0) { @@ -836,7 +834,7 @@ } } - // Show an extent of n bytes (as 2*n charactrs) + // Show an extent of n bytes (as 2*n characters) public void padTo(int n) { while (n > image.length()) { image.append(' '); @@ -845,7 +843,7 @@ /** * Write summary numbers offset [ size ] remainder - * + * * @param b */ public String showSummary(BaseBytes b) { @@ -857,7 +855,7 @@ /** * Make text image of just the buffer boundaries. - * + * * @param b */ public String showExtent(BaseBytes b) { @@ -871,7 +869,7 @@ /** * Make text image of the buffer content and boundaries. - * + * * @param b */ public String showContent(BaseBytes b) { @@ -895,7 +893,7 @@ * struct. buf is an n-dimensional array of Object, implementing the storage of * some Python type, and it is required to access one element of it at an index defined by n * integers in sequence. - * + * * @param n The number of dimensions the memory represents as a multi-dimensional array. * @param buf An n-dimensional array containing the value of the object * @param strides An array of length n giving the number of elements to skip to get to a new @@ -904,7 +902,8 @@ * @param indices An array of n indices indexing the element to retrieve. * @return */ - private static Object getItem(int n, Object buf, int[] strides, int[] suboffsets, int[] indices) { + private static Object + getItem(int n, Object buf, int[] strides, int[] suboffsets, int[] indices) { for (int i = 0; i < n; i++) { Object[] p = (Object[])buf; buf = p[indices[i] * strides[i] + suboffsets[i]]; @@ -916,7 +915,8 @@ * If it was an ndim-dimensional array of byte, we treat it as an (ndim-1)-dimensional array of * byte[] arrays. This method exemplifies getting just one byte. */ - private static byte getByte(int ndim, Object buf, int[] strides, int[] suboffsets, int[] indices) { + private static byte + getByte(int ndim, Object buf, int[] strides, int[] suboffsets, int[] indices) { int n = ndim - 1; byte[] b = (byte[])getItem(n, buf, strides, suboffsets, indices); return b[indices[n] + suboffsets[n]]; diff --git a/tests/java/org/python/core/PyByteArrayTest.java b/tests/java/org/python/core/PyByteArrayTest.java --- a/tests/java/org/python/core/PyByteArrayTest.java +++ b/tests/java/org/python/core/PyByteArrayTest.java @@ -7,7 +7,6 @@ import org.python.util.PythonInterpreter; - /** * JUnit tests for PyByteArray. */ @@ -15,6 +14,7 @@ /** * Constructor required by JUnit. + * * @param name */ public PyByteArrayTest(String name) { @@ -137,7 +137,8 @@ * @param y source of the E data * @param result the result to be tested against A+E+B */ - public static void checkSlice(int na, int nd, int nb, int ne, int[] x, int[] y, BaseBytes result) { + public static void + checkSlice(int na, int nd, int nb, int ne, int[] x, int[] y, BaseBytes result) { // Check the size is right assertEquals("size", na + ne + nb, result.size()); // Check that A is preserved @@ -293,6 +294,7 @@ * * @see org.python.core.BaseBytesTest#setUp() */ + @Override protected void setUp() throws Exception { super.setUp(); } @@ -305,7 +307,7 @@ public void test__getslice__2() { int verbose = 0; // __getslice__() deals with start, stop values also relative to the end. - String ver = "D?rob?e au sang de nos c?urs"; + String ver = "L'un a la pourpre de nos ?mes"; final int L = ver.length(); int[] aRef = toInts(ver); BaseBytes a = getInstance(aRef); @@ -370,11 +372,8 @@ * @param bList reference answer * @param verbose 0..4 control output */ - private void doTest__getslice__2(BaseBytes a, - PyObject pyStart, - PyObject pyStop, - List bList, - int verbose) { + private void doTest__getslice__2(BaseBytes a, PyObject pyStart, PyObject pyStop, + List bList, int verbose) { if (verbose >= 4) { System.out.printf(" __getslice__(%s,%s)\n", pyStart, pyStop); } @@ -519,12 +518,8 @@ * @param bList reference answer * @param verbose 0..4 control output */ - private void doTest__getslice__3(BaseBytes a, - PyObject pyStart, - PyObject pyStop, - PyObject pyStep, - List bList, - int verbose) { + private void doTest__getslice__3(BaseBytes a, PyObject pyStart, PyObject pyStop, + PyObject pyStep, List bList, int verbose) { if (verbose >= 4) { System.out.printf(" __getslice__(%s,%s,%s)\n", pyStart, pyStop, pyStep); } @@ -539,6 +534,7 @@ * Test method for {@link PyByteArray#__setitem__(int,PyObject)}, and through it of * {@link PyByteArray#pyset(int,PyObject)}. */ + @Override public void testPyset() { int verbose = 0; @@ -629,8 +625,8 @@ b.setslice(na, na + nd, 1, e); if (verbose >= 2) { - boolean avAlloc = (b.storage != oldStorage) - && (bRef.length <= oldStorage.length); + boolean avAlloc = + (b.storage != oldStorage) && (bRef.length <= oldStorage.length); if (b.storage.length * 2 < oldStorage.length) { avAlloc = false; } @@ -664,7 +660,7 @@ PyByteArray e = y.getslice(0, ne, 1); if (verbose >= 2) { System.out.printf("setslice(start=%d, stop=%d, step=%d, e[len=%d])\n", - na, na + nd, 1, ne); + na, na + nd, 1, ne); if (verbose >= 3) { System.out.println("u = " + toString(u)); System.out.println("e = " + toString(e)); @@ -714,8 +710,7 @@ } for (int stop : posStop) { - if (stop < start) - { + if (stop < start) { continue; // Skip backwards cases } @@ -732,16 +727,16 @@ for (int n = 0; n <= eRef.length; n++) { // Generate test result and check it doTest__setslice__2(uRef, pyStart, pyStop, eFull, n, eRef, start, stop, - verbose + 2); + verbose + 2); // Repeat same result specifying start relative to end doTest__setslice__2(uRef, pyStart_L, pyStop, eFull, n, eRef, start, stop, - verbose); + verbose); // Repeat same result specifying stop relative to end doTest__setslice__2(uRef, pyStart, pyStop_L, eFull, n, eRef, start, stop, - verbose); + verbose); // Repeat same result specifying start and stop relative to end doTest__setslice__2(uRef, pyStart_L, pyStop_L, eFull, n, eRef, start, stop, - verbose); + verbose); } } } @@ -759,15 +754,8 @@ * @param eRef from which eFull was initialised * @param verbose 0..4 control output */ - private void doTest__setslice__2(int[] uRef, - PyObject pyStart, - PyObject pyStop, - BaseBytes eFull, - int n, - int[] eRef, - int start, - int stop, - int verbose) { + private void doTest__setslice__2(int[] uRef, PyObject pyStart, PyObject pyStop, + BaseBytes eFull, int n, int[] eRef, int start, int stop, int verbose) { PyByteArray u = getInstance(uRef); BaseBytes e = eFull.getslice(0, n, 1); if (verbose >= 4) { @@ -790,6 +778,7 @@ * slice to replace is extended (3-argument slice and step!=0). Note that PySequence checks and * converts arguments first, so we need only test with valid combinations of indices. */ + @Override public void testSetslice3() { int verbose = 0; @@ -820,7 +809,7 @@ BaseBytes e = eFull.getslice(0, n, 1); if (verbose >= 2) { System.out.printf("setslice(start=%d, stop=%d, step=%d, e[len=%d])\n", - start, stop, step, n); + start, stop, step, n); if (verbose >= 3) { System.out.println("u = " + toString(u)); System.out.println("e = " + toString(e)); @@ -855,7 +844,7 @@ BaseBytes e = eFull.getslice(0, n, 1); if (verbose >= 2) { System.out.printf("setslice(start=%d, stop=%d, step=%d, e[len=%d])\n", - start, stop, step, n); + start, stop, step, n); if (verbose >= 3) { System.out.println("u = " + toString(u)); System.out.println("e = " + toString(e)); @@ -913,8 +902,8 @@ PyByteArray u = getInstance(uRef); BaseBytes e = eFull.getslice(0, n, 1); if (verbose >= 2) { - System.out.printf("setslice(%d,%d,%d, e[len=%d])\n", start, stop, step, - n); + System.out.printf("setslice(%d,%d,%d, e[len=%d])\n", // + start, stop, step, n); if (verbose >= 3) { System.out.println("u = " + toString(u)); System.out.println("e = " + toString(e)); @@ -951,8 +940,8 @@ PyByteArray u = getInstance(uRef); BaseBytes e = eFull.getslice(0, n, 1); if (verbose >= 2) { - System.out.printf("setslice(%d,%d,%d, e[len=%d])\n", start, stop, step, - n); + System.out.printf("setslice(%d,%d,%d, e[len=%d])\n", // + start, stop, step, n); if (verbose >= 3) { System.out.println("u = " + toString(u)); System.out.println("e = " + toString(e)); @@ -975,10 +964,10 @@ */ public void testSetsliceTime() { int verbose = 1; - timeSetslice(100, 200, SMALL, 2*SMALL, verbose); - timeSetslice(100, 200, MEDIUM, MEDIUM, verbose); - timeSetslice(1000, 20, LARGE, LARGE/5, verbose); -// timeSetslice(1000, 4, HUGE, HUGE/5, verbose); + timeSetslice(50, 100, SMALL, 2 * SMALL, verbose); + timeSetslice(50, 100, MEDIUM, MEDIUM, verbose); + timeSetslice(500, 20, LARGE, LARGE / 5, verbose); + // timeSetslice(1000, 4, HUGE, HUGE/5, verbose); } /** @@ -1092,12 +1081,8 @@ * @param verbose amount of output * @return elapsed time in nanoseconds for setslice operation on array of objects */ - private long doTimeSetslice(PyByteArray[] u, - int start, - int stop, - BaseBytes e, - BaseBytes x, - int verbose) { + private long doTimeSetslice(PyByteArray[] u, int start, int stop, BaseBytes e, BaseBytes x, + int verbose) { // The call is either to do a time trial (block of test objects) or one test of correctness int repeats = 1; @@ -1147,24 +1132,9 @@ return t; } -// /** -// * Test method for {@link org.python.core.PyByteArray#del(int)}. -// */ -// public void testDel() { -// fail("Not yet implemented"); -// } -// -// /** -// * Test method for {@link org.python.core.PyByteArray#delRange(int, int)}. -// */ -// public void testDelRange() { -// fail("Not yet implemented"); -// } -// - /** - * Test method for {@link org.python.core.PyByteArray#delslice(int,int,int)}, when the - * slice to delete is simple (a contiguous 2-argument slice). + * Test method for {@link org.python.core.PyByteArray#delslice(int,int,int)}, when the slice to + * delete is simple (a contiguous 2-argument slice). */ public void testDelslice2() { int verbose = 0; @@ -1175,39 +1145,38 @@ int[] ndList = {5, 20, 0}; // Slice to delete is small, large or zero int[] nbList = {4, 7, 0}; // Interesting cases: slice is at end, or not at end - for (int nd : ndList) { - for (int na : naList) { - for (int nb : nbList) { - int[] aRef = adbInts(na, nd, nb); - int[] bRef = aebInts(na, 0, nb); + for (int nd : ndList) { + for (int na : naList) { + for (int nb : nbList) { + int[] aRef = adbInts(na, nd, nb); + int[] bRef = aebInts(na, 0, nb); - PyByteArray b = getInstance(aRef); + PyByteArray b = getInstance(aRef); - byte[] oldStorage = b.storage; + byte[] oldStorage = b.storage; - if (verbose >= 2) { - System.out.printf("delslice(%d,%d,%d)\n", - na, na + nd, 1); - if (verbose >= 3) { - System.out.println(toString(b)); - } + if (verbose >= 2) { + System.out.printf("delslice(%d,%d,%d,%d)\n", na, na + nd, 1, nd); + if (verbose >= 3) { + System.out.println(toString(b)); } + } - b.delslice(na, na + nd, 1); + b.delslice(na, na + nd, 1, nd); - if (verbose >= 2) { - // Was there a reallocation? - boolean avAlloc = (b.storage != oldStorage); - // Justified if ... - if (bRef.length * 2 <= oldStorage.length) { - avAlloc = false; - } - System.out.println(toString(b) + (avAlloc ? " avoidable new" : "")); + if (verbose >= 2) { + // Was there a reallocation? + boolean avAlloc = (b.storage != oldStorage); + // Justified if ... + if (bRef.length * 2 <= oldStorage.length) { + avAlloc = false; } - checkInts(bRef, b); + System.out.println(toString(b) + (avAlloc ? " avoidable new" : "")); } + checkInts(bRef, b); } } + } // Deletions at a range of positions and all sizes with random data @@ -1224,21 +1193,21 @@ for (int na = 0; na <= AMAX; na++) { for (int nb : nbList2) { - for (int nd = 0; nd < DMAX; nd++){ - PyByteArray u = x.getslice(0, na + nd + nb, 1); - if (verbose >= 2) { - System.out.printf("delslice(start=%d, stop=%d, step=%d)\n", - na, na + nd, 1); - if (verbose >= 3) { - System.out.println("u = " + toString(u)); - } + for (int nd = 0; nd < DMAX; nd++) { + PyByteArray u = x.getslice(0, na + nd + nb, 1); + if (verbose >= 2) { + System.out.printf("delslice(start=%d, stop=%d, step=%d, n=%d)\n", na, na + + nd, 1, nd); + if (verbose >= 3) { + System.out.println("u = " + toString(u)); } - u.delslice(na, na + nd, 1); - if (verbose >= 1) { - System.out.println("u'= " + toString(u)); - } - checkSlice(na, nd, nb, 0, xInts, null, u); } + u.delslice(na, na + nd, 1, nd); + if (verbose >= 1) { + System.out.println("u'= " + toString(u)); + } + checkSlice(na, nd, nb, 0, xInts, null, u); + } } } } @@ -1260,8 +1229,6 @@ final int[] posStart = new int[] {0, 3, 7, 16, L - 1}; final int[] posStop = new int[] {0, 3, 7, 16, L - 6, L}; -// final int[] posStart = new int[] {16}; -// final int[] posStop = new int[] {L}; for (int start : posStart) { PyObject pyStart, pyStop, pyStart_L, pyStop_L; @@ -1275,8 +1242,7 @@ } for (int stop : posStop) { - if (stop < start) - { + if (stop < start) { continue; // Skip backwards cases } @@ -1311,10 +1277,8 @@ * @param pyStop * @param verbose 0..4 control output */ - private void doTest__delslice__2(int[] uRef, - PyObject pyStart, - PyObject pyStop, - int start, int stop, int verbose) { + private void doTest__delslice__2(int[] uRef, PyObject pyStart, PyObject pyStop, int start, + int stop, int verbose) { PyByteArray u = getInstance(uRef); if (verbose >= 4) { System.out.printf(" __delslice__(%s,%s,1)\n", pyStart, pyStop); @@ -1325,16 +1289,15 @@ if (verbose >= 3) { System.out.println("u'= " + toString(u)); } - int nd = stop-start; - int nb = uRef.length-stop; + int nd = stop - start; + int nb = uRef.length - stop; checkSlice(start, nd, nb, 0, uRef, null, u); } - /** - * Test method for {@link org.python.core.PyByteArray#delslice(int,int,int)}, when the - * slice to delete is extended (3-argument slice and step!=0). Note that PySequence checks and - * converts arguments first, so we need only test with valid combinations of indices. + * Test method for {@link org.python.core.PyByteArray#delslice(int,int,int)}, when the slice to + * delete is extended (3-argument slice and step!=0). Note that PySequence checks and converts + * arguments first, so we need only test with valid combinations of indices. */ public void test__delslice__3() { int verbose = 0; @@ -1342,10 +1305,6 @@ // Need interpreter interp = new PythonInterpreter(); - // Source of assigned values. -// int[] eRef = randomInts(random, MEDIUM, 'A', 'H'); -// BaseBytes eFull = new BaseBytesTest.MyBytes(eRef); - // Forwards cases int[] uRef = randomInts(random, MEDIUM, 'm', 's'); @@ -1370,8 +1329,8 @@ // Now do the test PyByteArray u = getInstance(uRef); if (verbose >= 2) { - System.out.printf("delslice(%d,%d,%d) (%d deletions)\n", - start, stop, step, n); + System.out.printf("__delslice__(%d,%d,%d) (%d deletions)\n", start, + stop, step, n); if (verbose >= 3) { System.out.println("u = " + toString(u)); } @@ -1406,8 +1365,8 @@ // Now do the test PyByteArray u = getInstance(uRef); if (verbose >= 2) { - System.out.printf("delslice(%d,%d,%d) (%d deletions)\n", - start, stop, step, n); + System.out.printf("__delslice__(%d,%d,%d) (%d deletions)\n", start, + stop, step, n); if (verbose >= 3) { System.out.println("u = " + toString(u)); } @@ -1430,9 +1389,9 @@ */ public void testDelsliceTime3() { int verbose = 1; - timeDelslice3(100, 200, SMALL, verbose); - timeDelslice3(100, 200, MEDIUM, verbose); - timeDelslice3(10, 4, LARGE, verbose); + timeDelslice3(50, 100, SMALL, verbose); + timeDelslice3(50, 100, MEDIUM, verbose); + timeDelslice3(20, 4, LARGE, verbose); // timeDelslice3(10, 1, HUGE, verbose); } @@ -1494,10 +1453,10 @@ if (step > 0) { // Deletions available from start location to end of array - n = (xRef.length - start + step-1) / step; + n = (xRef.length - start + step - 1) / step; } else { // Deletions available from start location to beginning of array - n = (start + (-step) ) / (-step); + n = (start + (-step)) / (-step); } // Make objects of the arguments @@ -1554,12 +1513,8 @@ * @param verbose amount of output * @return elapsed time in nanoseconds for delslice operation on array of objects */ - private long doTimeDelslice3(PyByteArray[] u, - PyObject pyStart, - PyObject pyStop, - PyObject pyStep, - BaseBytes x, - int verbose) { + private long doTimeDelslice3(PyByteArray[] u, PyObject pyStart, PyObject pyStop, + PyObject pyStep, BaseBytes x, int verbose) { // The call is either to do a time trial (block of test objects) or one test of correctness int repeats = 1; @@ -1614,41 +1569,49 @@ * with a similar signature. The idea is to override the getInstance() methods to return an * instance of the class actually under test in the derived test. */ + @Override public PyByteArray getInstance(PyType type) { return new PyByteArray(type); } + @Override public PyByteArray getInstance() { return new PyByteArray(); } + @Override public PyByteArray getInstance(int size) { return new PyByteArray(size); } + @Override public PyByteArray getInstance(int[] value) { return new PyByteArray(value); } + @Override public PyByteArray getInstance(BaseBytes source) { return new PyByteArray(source); } + @Override public PyByteArray getInstance(Iterable source) { return new PyByteArray(source); } + @Override public PyByteArray getInstance(PyString arg, PyObject encoding, PyObject errors) { return new PyByteArray(arg, encoding, errors); } + @Override public PyByteArray getInstance(PyString arg, String encoding, String errors) { return new PyByteArray(arg, encoding, errors); } + @Override public PyByteArray getInstance(PyObject arg) throws PyException { return new PyByteArray(arg); } - } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Apr 9 09:28:35 2015 From: jython-checkins at python.org (jeff.allen) Date: Thu, 09 Apr 2015 07:28:35 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Preserve_case_of_temporary_?= =?utf-8?q?directory_path=2E_Partly_addresses_=232307=2E?= Message-ID: <20150409072833.95228.8458@psf.io> https://hg.python.org/jython/rev/e6ca8b2cf467 changeset: 7650:e6ca8b2cf467 user: Jeff Allen date: Mon Apr 06 14:59:39 2015 +0100 summary: Preserve case of temporary directory path. Partly addresses #2307. Module tempfile now returns temporary directory in proper case. (See also CPython issue 14255) files: Lib/tempfile.py | 2 +- Lib/test/test_tempfile.py | 16 ++++++++++++++++ Lib/test/test_zipimport_support.py | 9 ++++++--- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Lib/tempfile.py b/Lib/tempfile.py --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -192,7 +192,7 @@ for dir in dirlist: if dir != _os.curdir: - dir = _os.path.normcase(_os.path.abspath(dir)) + dir = _os.path.abspath(dir) # See CPython Issue 14255 # Try only a few names per directory. for seq in xrange(100): name = namer.next() diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -393,6 +393,22 @@ self.assert_(a is b) + def test_case_sensitive(self): + # gettempdir should not flatten its case + # even on a case-insensitive file system + # See CPython Issue 14255 (back-ported for Jython) + case_sensitive_tempdir = tempfile.mkdtemp("-Temp") + _tempdir, tempfile.tempdir = tempfile.tempdir, None + try: + with test_support.EnvironmentVarGuard() as env: + # Fake the first env var which is checked as a candidate + env["TMPDIR"] = case_sensitive_tempdir + self.assertEqual(tempfile.gettempdir(), case_sensitive_tempdir) + finally: + tempfile.tempdir = _tempdir + test_support.rmdir(case_sensitive_tempdir) + + test_classes.append(test_gettempdir) diff --git a/Lib/test/test_zipimport_support.py b/Lib/test/test_zipimport_support.py --- a/Lib/test/test_zipimport_support.py +++ b/Lib/test/test_zipimport_support.py @@ -231,7 +231,6 @@ print data self.assertIn(expected, data) - @unittest.skipIf(is_jython, "FIXME: not working on Jython") def test_pdb_issue4201(self): test_src = textwrap.dedent("""\ def f(): @@ -245,13 +244,17 @@ p = spawn_python(script_name) p.stdin.write('l\n') data = kill_python(p) - self.assertIn(script_name, data) + # bdb/pdb applies normcase to its filename before displaying + # See CPython Issue 14255 (back-ported for Jython) + self.assertIn(os.path.normcase(script_name.encode('utf-8')), data) zip_name, run_name = make_zip_script(d, "test_zip", script_name, '__main__.py') p = spawn_python(zip_name) p.stdin.write('l\n') data = kill_python(p) - self.assertIn(run_name, data) + # bdb/pdb applies normcase to its filename before displaying + # See CPython Issue 14255 (back-ported for Jython) + self.assertIn(os.path.normcase(run_name.encode('utf-8')), data) def test_main(): -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Apr 9 09:28:36 2015 From: jython-checkins at python.org (jeff.allen) Date: Thu, 09 Apr 2015 07:28:36 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Correct_temporary_directory?= =?utf-8?q?_search_path_on_Windows=2E?= Message-ID: <20150409072833.78078.34609@psf.io> https://hg.python.org/jython/rev/1dff925eb167 changeset: 7651:1dff925eb167 user: Jeff Allen date: Mon Apr 06 18:49:50 2015 +0100 summary: Correct temporary directory search path on Windows. Replace spurious Unix-like paths added when os.name=='java', with the ones appropriate to 'nt'. Affects riscos correspondingly, which seems right, but is untested. files: Lib/tempfile.py | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Lib/tempfile.py b/Lib/tempfile.py --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -160,11 +160,17 @@ dirname = _os.getenv(envname) if dirname: dirlist.append(dirname) + # Real name of OS + if _os.name != 'java': + os_name = _os.name + else: + os_name = _os._name + # Failing that, try OS-specific locations. - if _os.name == 'riscos': + if os_name == 'riscos': dirname = _os.getenv('Wimp$ScrapDir') if dirname: dirlist.append(dirname) - elif _os.name == 'nt': + elif os_name == "nt": dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ]) else: dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ]) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Apr 9 09:28:36 2015 From: jython-checkins at python.org (jeff.allen) Date: Thu, 09 Apr 2015 07:28:36 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Faster_extended_slice_delet?= =?utf-8?q?ion_in_bytearray=2E?= Message-ID: <20150409072833.93218.10630@psf.io> https://hg.python.org/jython/rev/d2824374b29a changeset: 7649:d2824374b29a parent: 7596:cf9ad15fca87 user: Jeff Allen date: Sun Feb 15 20:49:30 2015 +0000 summary: Faster extended slice deletion in bytearray. Replace iterative deletion of single elements (causing repeat copy), with a single-copy strategy approriate to the array implementation. This is a perfromance loose-end in the original implementation. Incidental code cleanup, particularly in JUnit test. files: src/org/python/core/BaseBytes.java | 19 +- src/org/python/core/PyByteArray.java | 113 +--- src/org/python/core/PySequence.java | 80 +- src/org/python/core/SequenceIndexDelegate.java | 9 +- tests/java/org/python/core/BaseBytesTest.java | 92 +- tests/java/org/python/core/PyByteArrayTest.java | 233 ++++----- 6 files changed, 243 insertions(+), 303 deletions(-) diff --git a/src/org/python/core/BaseBytes.java b/src/org/python/core/BaseBytes.java --- a/src/org/python/core/BaseBytes.java +++ b/src/org/python/core/BaseBytes.java @@ -736,20 +736,10 @@ */ private class IndexDelegate extends PySequence.DefaultIndexDelegate { - /* + /** * bytearray treats assignment of a zero-length object to a slice as equivalent to deletion, * unlike list, even for an extended slice. */ - // >>> a = range(10) - // >>> b = bytearray(a) - // >>> a[1:6:2] = [] - // Traceback (most recent call last): - // File "", line 1, in - // ValueError: attempt to assign sequence of size 0 to extended slice of size 3 - // >>> b[1:6:2] = [] - // >>> b - // bytearray(b'\x00\x02\x04\x06\x07\x08\t') - // @Override public void checkIdxAndSetSlice(PySlice slice, PyObject value) { if (value.__len__() != 0) { @@ -757,9 +747,14 @@ super.checkIdxAndSetSlice(slice, value); } else { // Treat as deletion - super.checkIdxAndDelItem(slice); + checkIdxAndDelItem(slice); } } + + @Override + protected void delSlice(int[] indices) { + delslice(indices[0], indices[1], indices[2], indices[3]); + } }; /* diff --git a/src/org/python/core/PyByteArray.java b/src/org/python/core/PyByteArray.java --- a/src/org/python/core/PyByteArray.java +++ b/src/org/python/core/PyByteArray.java @@ -676,53 +676,59 @@ } } - /* - * Deletes an element from the sequence (and closes up the gap). - * - * @param index index of the element to delete. - */ @Override protected synchronized void del(int index) { - // XXX Change SequenceIndexDelegate to avoid repeated calls to del(int) for extended slice storageDelete(index, 1); } - /* - * Deletes contiguous sub-sequence (and closes up the gap). - * - * @param start the position of the first element. - * - * @param stop one more than the position of the last element. - */ @Override protected synchronized void delRange(int start, int stop) { storageDelete(start, stop - start); } - /** - * Deletes a simple or extended slice and closes up the gap(s). - * - * @param start the position of the first element. - * @param stop one more than the position of the last element. - * @param step from one element to the next - */ - protected synchronized void delslice(int start, int stop, int step) { + @Override + protected synchronized void delslice(int start, int stop, int step, int n) { + // This will not be possible if this object has buffer exports + resizeCheck(); + if (step == 1) { - // Delete this[start:stop] and closing up the space - storageDelete(start, stop - start); + // Delete this[start:stop] and close up the space. + storageDelete(start, n); + + } else if (step == -1) { + // Also a contiguous case, but start > stop. + storageDelete(stop + 1, n); + } else { - // This is an extended slice which means we are removing isolated elements - int n = sliceLength(start, stop, step); + // This is an extended slice. We will be deleting n isolated elements. + int p, m; - if (n > 0) { - if (step > 0) { - // The first element is x[start] and the last is x[start+(n-1)*step+1] - storageDeleteEx(start, step, n); - } else { - // The first element is x[start+(n-1)*step+1] and the last is x[start] - storageDeleteEx(start + (n - 1) * step + 1, -step, n); + // We delete by copying from high to low memory, whatever the sign of step. + if (step > 1) { + // The lowest numbered element to delete is x[start] + p = start; + m = step - 1; + } else { + // The lowest numbered element to delete is x[start+(n-1)*step]] + p = start + (n - 1) * step; + m = -1 - step; + } + + // Offset p to be a storage index. + p += offset; + + // Copy n-1 blocks blocks of m bytes, each time skipping the byte to be deleted. + for (int i = 1; i < n; i++) { + // Skip q over the one we are deleting + int q = p + i; + // Now copy the m elements that follow. + for (int j = 0; j < m; j++) { + storage[p++] = storage[q++]; } } + + // Close up the gap. Note that for the copy, p was adjusted by the storage offset. + storageDelete(p - offset, n); } } @@ -2654,47 +2660,4 @@ } } - /** - * Delete d elements on a stride of c beginning at index - * a by moving together the surrounding elements. The method manipulates the - * storage array, size and offset, and will allocate a - * new storage array if the deletion is big enough. If the initial storage looks like this: - * - *
-     * |-                               L                                -|
-     *       |-                    s                    -|
-     * |--f--|-----a-----|---------e---------|-----b-----|----------------|
-     * 
- * - * then after the call the (possibly new) storage looks like this: - * - *
-     * |-                   L'                         -|
-     *      |-                s'               -|
-     * |-f'-|-----a-----|---(e-d)---|-----b-----|-------|
-     * 
- * - * where the regions of length a and b=size-(a+e) have been preserved - * and the e intervening elements reduced to e-d elements, by removing - * exactly the elements with indices (relative to the start of valid data) a+k*c - * for k=0...d-1. The effect on this PyByteArray is that: - * - *
-     * this.offset = f'
-     * this.size = s' = a+b
-     * 
- * - * The method does not implement the Python repertoire of slice indices but avoids indexing - * outside the bytearray by silently adjusting a to be within it. Negative d is - * treated as 0 and if d is too large, it is truncated to the array end. - * - * @param a index of hole in byte array - * @param c (>0) step size between the locations of elements to delete - * @param d number to discard (will discard x[a+k*c] for k=0...d-1) - */ - private void storageDeleteEx(int a, int c, int d) { - - // XXX Base this on storageReplace with the same apyget(int) the index is within the bounds of the array. Any other * clients must make the same guarantee. - * + * * @param index index of element to return. * @return the element at the given position in the list. */ @@ -68,8 +68,8 @@ protected abstract PyObject getslice(int start, int stop, int step); /** - * Returns a (concrete subclass of) PySequence that repeats the given sequence, as - * in the implementation of __mul__ for strings. + * Returns a (concrete subclass of) PySequence that repeats the given sequence, as in the + * implementation of __mul__ for strings. * * @param count the number of times to repeat the sequence. * @return this sequence repeated count times. @@ -82,7 +82,7 @@ * called by PySequence in its implementation of {@link #__setitem__} It is guaranteed by * PySequence that when it calls pyset(int) the index is within the bounds of the array. Any * other clients must make the same guarantee. - * + * * @param index index of the element to set. * @param value the value to set this element to. */ @@ -91,45 +91,60 @@ } /** - * Sets the given range of elements according to Python slice assignment semantics. - * If the step size is one, it is a simple slice and the operation is equivalent to - * deleting that slice, then inserting the value at that position, regarding the - * value as a sequence (if possible) or as a single element if it is not a sequence. - * If the step size is not one, but start==stop, it is equivalent to insertion - * at that point. - * If the step size is not one, and start!=stop, the slice defines a certain number - * of elements to be replaced, and the value must be a sequence of exactly that many - * elements (or convertible to such a sequence). - * + * Sets the given range of elements according to Python slice assignment semantics. If the step + * size is one, it is a simple slice and the operation is equivalent to deleting that slice, + * then inserting the value at that position, regarding the value as a sequence (if possible) or + * as a single element if it is not a sequence. If the step size is not one, but + * start==stop, it is equivalent to insertion at that point. If the step size is + * not one, and start!=stop, the slice defines a certain number of elements to be + * replaced, and the value must be a sequence of exactly that many elements (or convertible to + * such a sequence). + * * @param start the position of the first element. * @param stop one more than the position of the last element. * @param step the step size. * @param value an object consistent with the slice assignment */ protected void setslice(int start, int stop, int step, PyObject value) { - throw Py.TypeError(String.format("'%s' object does not support item assignment", - getType().fastGetName())); + throw Py.TypeError(String.format("'%s' object does not support item assignment", getType() + .fastGetName())); } /** * Deletes an element from the sequence (and closes up the gap). - * + * * @param index index of the element to delete. */ protected void del(int index) { - throw Py.TypeError(String.format("'%s' object does not support item deletion", - getType().fastGetName())); + delslice(index, index, 1, 1); // Raises TypeError (for immutable types). } /** * Deletes a contiguous sub-sequence (and closes up the gap). - * + * * @param start the position of the first element. * @param stop one more than the position of the last element. */ protected void delRange(int start, int stop) { - throw Py.TypeError(String.format("'%s' object does not support item deletion", - getType().fastGetName())); + delslice(start, stop, 1, Math.abs(stop - start)); // Raises TypeError (for immutable types). + } + + /** + * Deletes a simple or extended slice and closes up the gap(s). The slice parameters + * [start:stop:step] mean what they would in Python, after application of + * the "end-relative" rules for negative numbers and None. The count n + * is as supplied by {@link PySlice#indicesEx(int)}. This method is unsafe in that slice + * parameters are assumed correct. + * + * @param start the position of the first element. + * @param stop beyond the position of the last element (not necessarily just beyond). + * @param step from one element to the next (positive or negative) + * @param n number of elements to delete + */ + protected void delslice(int start, int stop, int step, int n) { + // Raises TypeError (for immutable types). + throw Py.TypeError(String.format("'%s' object does not support item deletion", getType() + .fastGetName())); } @Override @@ -265,10 +280,9 @@ /** * Compare the specified object/length pairs. * - * @return value >= 0 is the index where the sequences differs. - * -1: reached the end of o1 without a difference - * -2: reached the end of both seqeunces without a difference - * -3: reached the end of o2 without a difference + * @return value >= 0 is the index where the sequences differs. -1: reached the end of o1 + * without a difference -2: reached the end of both seqeunces without a difference -3: + * reached the end of o2 without a difference */ protected static int cmp(PyObject o1, int ol1, PyObject o2, int ol2) { if (ol1 < 0) { @@ -320,9 +334,8 @@ } /** - * Adjusts index such that it's >= 0 and <= __len__. If - * index starts off negative, it's treated as an index from the end of - * the sequence going back to the start. + * Adjusts index such that it's >= 0 and <= __len__. If index starts + * off negative, it's treated as an index from the end of the sequence going back to the start. */ protected int boundToSequence(int index) { int length = __len__(); @@ -514,7 +527,6 @@ delRange(start, stop); } - @Override public PyObject getItem(int idx) { return pyget(idx); diff --git a/src/org/python/core/SequenceIndexDelegate.java b/src/org/python/core/SequenceIndexDelegate.java --- a/src/org/python/core/SequenceIndexDelegate.java +++ b/src/org/python/core/SequenceIndexDelegate.java @@ -109,7 +109,14 @@ } } - private void delSlice(int[] indices) { + /** + * Implement the deletion of a slice. This method is called by + * {@link #checkIdxAndDelItem(PyObject)} when the argument is a {@link PySlice}. The argument is + * the return from {@link PySlice#indicesEx(int)}. + * + * @param indices containing [start, stop, step, count] of the slice to delete + */ + protected void delSlice(int[] indices) { int p = indices[0], step = indices[2], count = indices[3]; if (step > 1) { /* diff --git a/tests/java/org/python/core/BaseBytesTest.java b/tests/java/org/python/core/BaseBytesTest.java --- a/tests/java/org/python/core/BaseBytesTest.java +++ b/tests/java/org/python/core/BaseBytesTest.java @@ -33,7 +33,7 @@ // Constants for array sizes public static final int SMALL = 7; // Less than minimum storage size public static final int MEDIUM = 25; // Medium array size - public static final int LARGE = 10000; // Large enough for performance measurement + public static final int LARGE = 2000; // Large enough for performance measurement public static final int HUGE = 100000; // Serious performance challenge /** @@ -55,7 +55,7 @@ /** * Turn a String into ints, but in the Python byte range, reducing character codes mod 256. - * + * * @param s the string * @return */ @@ -71,7 +71,7 @@ /** * Generate ints at random in the range 0..255. - * + * * @param random the random generator * @param n length of array * @return the array of random values @@ -86,7 +86,7 @@ /** * Generate ints at random in a restricted range. - * + * * @param random the random generator * @param n length of array * @param lo lowest value to generate @@ -104,7 +104,7 @@ /** * Compare expected and result array sections at specified locations and length. - * + * * @param expected reference values (may be null iff len==0) * @param first first value to compare in expected values * @param result bytearray from method under test @@ -114,7 +114,9 @@ static void checkInts(int[] expected, int first, BaseBytes result, int start, int len) { if (len > 0) { int end = first + len; - if (end > expected.length) end = expected.length; + if (end > expected.length) { + end = expected.length; + } for (int i = first, j = start; i < end; i++, j++) { assertEquals("element value", expected[i], result.intAt(j)); } @@ -123,7 +125,7 @@ /** * Compare expected and result array in their entirety. - * + * * @param expected * @param result */ @@ -138,7 +140,7 @@ /** * Compare expected List and result array in their entirety. - * + * * @param expected * @param result */ @@ -157,7 +159,7 @@ /** * Compare expected List and result object in their entirety. - * + * * @param expected * @param result */ @@ -168,7 +170,7 @@ /** * Turn array into Iterable, treating as unsigned (Python-style) bytes, and producing * an abusive mixture of object types. - * + * * @return iterable list */ public static Iterable iterableBytes(int[] source) { @@ -198,7 +200,7 @@ /* * (non-Javadoc) - * + * * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { @@ -206,7 +208,6 @@ random = new Random(20120310L); } - /** * Test method for {@link org.python.core.BaseBytes#init(int)} via MyBytes constructor, and for * {@link org.python.core.BaseBytes#size()}. @@ -274,17 +275,13 @@ */ public void testInit_PyObject() { // A scary set of objects - final PyObject[] brantub = {null, - new PyInteger(5), - new PyString("\u00A0\u00A1\u00A2\u00A3\u00A4"), - getInstance(new int[] {180, 190, 200}), - new PyXRange(1, 301, 50)}; + final PyObject[] brantub = + {null, new PyInteger(5), new PyString("\u00A0\u00A1\u00A2\u00A3\u00A4"), + getInstance(new int[] {180, 190, 200}), new PyXRange(1, 301, 50)}; // The array contents we should obtain - final int[][] prize = { {}, - {0, 0, 0, 0, 0}, - {160, 161, 162, 163, 164}, - {180, 190, 200}, - {1, 51, 101, 151, 201, 251}}; + final int[][] prize = + { {}, {0, 0, 0, 0, 0}, {160, 161, 162, 163, 164}, {180, 190, 200}, + {1, 51, 101, 151, 201, 251}}; // Work down the lists for (int dip = 0; dip < brantub.length; dip++) { int[] aRef = prize[dip]; @@ -359,7 +356,7 @@ /** * Test method for {@link BaseBytes#getslice(int, int, int)}. - * + * * @see PySequence#__getslice__(PyObject, PyObject) */ public void testGetslice() { @@ -480,7 +477,7 @@ a.setslice(start, stop, step, x); System.out.println(toString(a)); fail(String.format("Exception not thrown for setslice(%d,%d,%d,%s)", start, stop, step, - x)); + x)); } catch (PyException pye) { // System.out.println(pye); PyObject b = pye.type; @@ -549,7 +546,7 @@ /** * Create a zero-length Python byte array of explicitly-specified sub-type - * + * * @param type explicit Jython type */ public MyBytes(PyType type) { @@ -565,7 +562,7 @@ /** * Create zero-filled Python byte array of specified size. - * + * * @param size of byte array */ public MyBytes(int size) { @@ -574,7 +571,7 @@ /** * Create from integer array - * + * * @param value */ MyBytes(int[] value) { @@ -583,7 +580,7 @@ /** * Create a new array filled exactly by a copy of the contents of the source byte array. - * + * * @param value of the bytes */ public MyBytes(BaseBytes value) { @@ -593,7 +590,7 @@ /** * Create a new array filled exactly by a copy of the contents of the source. - * + * * @param value source of the bytes (and size) */ public MyBytes(BufferProtocol value) { @@ -604,7 +601,7 @@ /** * Create a new array filled from an iterable of PyObject. The iterable must yield objects * convertible to Python bytes (non-negative integers less than 256 or strings of length 1). - * + * * @param value of the bytes */ public MyBytes(Iterable value) { @@ -615,7 +612,7 @@ /** * Create a new array by encoding a PyString argument to bytes. If the PyString is actually * a PyUnicode, the encoding must be explicitly specified. - * + * * @param arg primary argument from which value is taken * @param encoding name of optional encoding (must be a string type) * @param errors name of optional errors policy (must be a string type) @@ -628,7 +625,7 @@ /** * Create a new array by encoding a PyString argument to bytes. If the PyString is actually * a PyUnicode, the encoding must be explicitly specified. - * + * * @param arg primary argument from which value is taken * @param encoding name of optional encoding (may be null to select the default for this * installation) @@ -658,7 +655,7 @@ * {@link #MyBytes(PyString, String, String)}. If the PyString is actually a PyUnicode, an * encoding must be specified, and using this constructor will throw an exception about * that. - * + * * @param arg primary argument from which value is taken (may be null) * @throws PyException in the same circumstances as bytes(arg), TypeError for non-iterable, * non-integer argument type, and ValueError if iterables do not yield byte @@ -675,7 +672,7 @@ * just one term. It is safe because MyBytes is immutable. But it may not be wise if the * source object is a large array from which only a small part needs to be retained in * memory. - * + * * @param type explicit Jython type * @param start index of first byte to use in source * @param stop 1 + index of last byte to use in source @@ -689,7 +686,7 @@ /** * Returns a PyByteArray that repeats this sequence the given number of times, as in the * implementation of __mul__ for strings. - * + * * @param count the number of times to repeat this. * @return this byte array repeated count times. */ @@ -702,7 +699,7 @@ /** * Returns a range of elements from the sequence. - * + * * @see org.python.core.PySequence#getslice(int, int, int) */ @Override @@ -727,7 +724,7 @@ /** * Return number of elements - * + * * @see org.python.core.PyObject#__len__() */ @Override @@ -776,7 +773,7 @@ /** * Store integer array as bytes: range must be 0..255 inclusive. - * + * * @param value integers to store */ BufferedObject(int[] value) { @@ -823,8 +820,9 @@ // Show in image s[pos:pos+n] (as 2*n characters) private void append(byte[] s, int pos, int n) { - if (pos < 0 || pos + n > s.length) + if (pos < 0 || pos + n > s.length) { return; + } for (int i = 0; i < n; i++) { int c = 0xff & ((int)s[pos + i]); if (c == 0) { @@ -836,7 +834,7 @@ } } - // Show an extent of n bytes (as 2*n charactrs) + // Show an extent of n bytes (as 2*n characters) public void padTo(int n) { while (n > image.length()) { image.append(' '); @@ -845,7 +843,7 @@ /** * Write summary numbers offset [ size ] remainder - * + * * @param b */ public String showSummary(BaseBytes b) { @@ -857,7 +855,7 @@ /** * Make text image of just the buffer boundaries. - * + * * @param b */ public String showExtent(BaseBytes b) { @@ -871,7 +869,7 @@ /** * Make text image of the buffer content and boundaries. - * + * * @param b */ public String showContent(BaseBytes b) { @@ -895,7 +893,7 @@ * struct. buf is an n-dimensional array of Object, implementing the storage of * some Python type, and it is required to access one element of it at an index defined by n * integers in sequence. - * + * * @param n The number of dimensions the memory represents as a multi-dimensional array. * @param buf An n-dimensional array containing the value of the object * @param strides An array of length n giving the number of elements to skip to get to a new @@ -904,7 +902,8 @@ * @param indices An array of n indices indexing the element to retrieve. * @return */ - private static Object getItem(int n, Object buf, int[] strides, int[] suboffsets, int[] indices) { + private static Object + getItem(int n, Object buf, int[] strides, int[] suboffsets, int[] indices) { for (int i = 0; i < n; i++) { Object[] p = (Object[])buf; buf = p[indices[i] * strides[i] + suboffsets[i]]; @@ -916,7 +915,8 @@ * If it was an ndim-dimensional array of byte, we treat it as an (ndim-1)-dimensional array of * byte[] arrays. This method exemplifies getting just one byte. */ - private static byte getByte(int ndim, Object buf, int[] strides, int[] suboffsets, int[] indices) { + private static byte + getByte(int ndim, Object buf, int[] strides, int[] suboffsets, int[] indices) { int n = ndim - 1; byte[] b = (byte[])getItem(n, buf, strides, suboffsets, indices); return b[indices[n] + suboffsets[n]]; diff --git a/tests/java/org/python/core/PyByteArrayTest.java b/tests/java/org/python/core/PyByteArrayTest.java --- a/tests/java/org/python/core/PyByteArrayTest.java +++ b/tests/java/org/python/core/PyByteArrayTest.java @@ -7,7 +7,6 @@ import org.python.util.PythonInterpreter; - /** * JUnit tests for PyByteArray. */ @@ -15,6 +14,7 @@ /** * Constructor required by JUnit. + * * @param name */ public PyByteArrayTest(String name) { @@ -137,7 +137,8 @@ * @param y source of the E data * @param result the result to be tested against A+E+B */ - public static void checkSlice(int na, int nd, int nb, int ne, int[] x, int[] y, BaseBytes result) { + public static void + checkSlice(int na, int nd, int nb, int ne, int[] x, int[] y, BaseBytes result) { // Check the size is right assertEquals("size", na + ne + nb, result.size()); // Check that A is preserved @@ -293,6 +294,7 @@ * * @see org.python.core.BaseBytesTest#setUp() */ + @Override protected void setUp() throws Exception { super.setUp(); } @@ -305,7 +307,7 @@ public void test__getslice__2() { int verbose = 0; // __getslice__() deals with start, stop values also relative to the end. - String ver = "D?rob?e au sang de nos c?urs"; + String ver = "L'un a la pourpre de nos ?mes"; final int L = ver.length(); int[] aRef = toInts(ver); BaseBytes a = getInstance(aRef); @@ -370,11 +372,8 @@ * @param bList reference answer * @param verbose 0..4 control output */ - private void doTest__getslice__2(BaseBytes a, - PyObject pyStart, - PyObject pyStop, - List bList, - int verbose) { + private void doTest__getslice__2(BaseBytes a, PyObject pyStart, PyObject pyStop, + List bList, int verbose) { if (verbose >= 4) { System.out.printf(" __getslice__(%s,%s)\n", pyStart, pyStop); } @@ -519,12 +518,8 @@ * @param bList reference answer * @param verbose 0..4 control output */ - private void doTest__getslice__3(BaseBytes a, - PyObject pyStart, - PyObject pyStop, - PyObject pyStep, - List bList, - int verbose) { + private void doTest__getslice__3(BaseBytes a, PyObject pyStart, PyObject pyStop, + PyObject pyStep, List bList, int verbose) { if (verbose >= 4) { System.out.printf(" __getslice__(%s,%s,%s)\n", pyStart, pyStop, pyStep); } @@ -539,6 +534,7 @@ * Test method for {@link PyByteArray#__setitem__(int,PyObject)}, and through it of * {@link PyByteArray#pyset(int,PyObject)}. */ + @Override public void testPyset() { int verbose = 0; @@ -629,8 +625,8 @@ b.setslice(na, na + nd, 1, e); if (verbose >= 2) { - boolean avAlloc = (b.storage != oldStorage) - && (bRef.length <= oldStorage.length); + boolean avAlloc = + (b.storage != oldStorage) && (bRef.length <= oldStorage.length); if (b.storage.length * 2 < oldStorage.length) { avAlloc = false; } @@ -664,7 +660,7 @@ PyByteArray e = y.getslice(0, ne, 1); if (verbose >= 2) { System.out.printf("setslice(start=%d, stop=%d, step=%d, e[len=%d])\n", - na, na + nd, 1, ne); + na, na + nd, 1, ne); if (verbose >= 3) { System.out.println("u = " + toString(u)); System.out.println("e = " + toString(e)); @@ -714,8 +710,7 @@ } for (int stop : posStop) { - if (stop < start) - { + if (stop < start) { continue; // Skip backwards cases } @@ -732,16 +727,16 @@ for (int n = 0; n <= eRef.length; n++) { // Generate test result and check it doTest__setslice__2(uRef, pyStart, pyStop, eFull, n, eRef, start, stop, - verbose + 2); + verbose + 2); // Repeat same result specifying start relative to end doTest__setslice__2(uRef, pyStart_L, pyStop, eFull, n, eRef, start, stop, - verbose); + verbose); // Repeat same result specifying stop relative to end doTest__setslice__2(uRef, pyStart, pyStop_L, eFull, n, eRef, start, stop, - verbose); + verbose); // Repeat same result specifying start and stop relative to end doTest__setslice__2(uRef, pyStart_L, pyStop_L, eFull, n, eRef, start, stop, - verbose); + verbose); } } } @@ -759,15 +754,8 @@ * @param eRef from which eFull was initialised * @param verbose 0..4 control output */ - private void doTest__setslice__2(int[] uRef, - PyObject pyStart, - PyObject pyStop, - BaseBytes eFull, - int n, - int[] eRef, - int start, - int stop, - int verbose) { + private void doTest__setslice__2(int[] uRef, PyObject pyStart, PyObject pyStop, + BaseBytes eFull, int n, int[] eRef, int start, int stop, int verbose) { PyByteArray u = getInstance(uRef); BaseBytes e = eFull.getslice(0, n, 1); if (verbose >= 4) { @@ -790,6 +778,7 @@ * slice to replace is extended (3-argument slice and step!=0). Note that PySequence checks and * converts arguments first, so we need only test with valid combinations of indices. */ + @Override public void testSetslice3() { int verbose = 0; @@ -820,7 +809,7 @@ BaseBytes e = eFull.getslice(0, n, 1); if (verbose >= 2) { System.out.printf("setslice(start=%d, stop=%d, step=%d, e[len=%d])\n", - start, stop, step, n); + start, stop, step, n); if (verbose >= 3) { System.out.println("u = " + toString(u)); System.out.println("e = " + toString(e)); @@ -855,7 +844,7 @@ BaseBytes e = eFull.getslice(0, n, 1); if (verbose >= 2) { System.out.printf("setslice(start=%d, stop=%d, step=%d, e[len=%d])\n", - start, stop, step, n); + start, stop, step, n); if (verbose >= 3) { System.out.println("u = " + toString(u)); System.out.println("e = " + toString(e)); @@ -913,8 +902,8 @@ PyByteArray u = getInstance(uRef); BaseBytes e = eFull.getslice(0, n, 1); if (verbose >= 2) { - System.out.printf("setslice(%d,%d,%d, e[len=%d])\n", start, stop, step, - n); + System.out.printf("setslice(%d,%d,%d, e[len=%d])\n", // + start, stop, step, n); if (verbose >= 3) { System.out.println("u = " + toString(u)); System.out.println("e = " + toString(e)); @@ -951,8 +940,8 @@ PyByteArray u = getInstance(uRef); BaseBytes e = eFull.getslice(0, n, 1); if (verbose >= 2) { - System.out.printf("setslice(%d,%d,%d, e[len=%d])\n", start, stop, step, - n); + System.out.printf("setslice(%d,%d,%d, e[len=%d])\n", // + start, stop, step, n); if (verbose >= 3) { System.out.println("u = " + toString(u)); System.out.println("e = " + toString(e)); @@ -975,10 +964,10 @@ */ public void testSetsliceTime() { int verbose = 1; - timeSetslice(100, 200, SMALL, 2*SMALL, verbose); - timeSetslice(100, 200, MEDIUM, MEDIUM, verbose); - timeSetslice(1000, 20, LARGE, LARGE/5, verbose); -// timeSetslice(1000, 4, HUGE, HUGE/5, verbose); + timeSetslice(50, 100, SMALL, 2 * SMALL, verbose); + timeSetslice(50, 100, MEDIUM, MEDIUM, verbose); + timeSetslice(500, 20, LARGE, LARGE / 5, verbose); + // timeSetslice(1000, 4, HUGE, HUGE/5, verbose); } /** @@ -1092,12 +1081,8 @@ * @param verbose amount of output * @return elapsed time in nanoseconds for setslice operation on array of objects */ - private long doTimeSetslice(PyByteArray[] u, - int start, - int stop, - BaseBytes e, - BaseBytes x, - int verbose) { + private long doTimeSetslice(PyByteArray[] u, int start, int stop, BaseBytes e, BaseBytes x, + int verbose) { // The call is either to do a time trial (block of test objects) or one test of correctness int repeats = 1; @@ -1147,24 +1132,9 @@ return t; } -// /** -// * Test method for {@link org.python.core.PyByteArray#del(int)}. -// */ -// public void testDel() { -// fail("Not yet implemented"); -// } -// -// /** -// * Test method for {@link org.python.core.PyByteArray#delRange(int, int)}. -// */ -// public void testDelRange() { -// fail("Not yet implemented"); -// } -// - /** - * Test method for {@link org.python.core.PyByteArray#delslice(int,int,int)}, when the - * slice to delete is simple (a contiguous 2-argument slice). + * Test method for {@link org.python.core.PyByteArray#delslice(int,int,int)}, when the slice to + * delete is simple (a contiguous 2-argument slice). */ public void testDelslice2() { int verbose = 0; @@ -1175,39 +1145,38 @@ int[] ndList = {5, 20, 0}; // Slice to delete is small, large or zero int[] nbList = {4, 7, 0}; // Interesting cases: slice is at end, or not at end - for (int nd : ndList) { - for (int na : naList) { - for (int nb : nbList) { - int[] aRef = adbInts(na, nd, nb); - int[] bRef = aebInts(na, 0, nb); + for (int nd : ndList) { + for (int na : naList) { + for (int nb : nbList) { + int[] aRef = adbInts(na, nd, nb); + int[] bRef = aebInts(na, 0, nb); - PyByteArray b = getInstance(aRef); + PyByteArray b = getInstance(aRef); - byte[] oldStorage = b.storage; + byte[] oldStorage = b.storage; - if (verbose >= 2) { - System.out.printf("delslice(%d,%d,%d)\n", - na, na + nd, 1); - if (verbose >= 3) { - System.out.println(toString(b)); - } + if (verbose >= 2) { + System.out.printf("delslice(%d,%d,%d,%d)\n", na, na + nd, 1, nd); + if (verbose >= 3) { + System.out.println(toString(b)); } + } - b.delslice(na, na + nd, 1); + b.delslice(na, na + nd, 1, nd); - if (verbose >= 2) { - // Was there a reallocation? - boolean avAlloc = (b.storage != oldStorage); - // Justified if ... - if (bRef.length * 2 <= oldStorage.length) { - avAlloc = false; - } - System.out.println(toString(b) + (avAlloc ? " avoidable new" : "")); + if (verbose >= 2) { + // Was there a reallocation? + boolean avAlloc = (b.storage != oldStorage); + // Justified if ... + if (bRef.length * 2 <= oldStorage.length) { + avAlloc = false; } - checkInts(bRef, b); + System.out.println(toString(b) + (avAlloc ? " avoidable new" : "")); } + checkInts(bRef, b); } } + } // Deletions at a range of positions and all sizes with random data @@ -1224,21 +1193,21 @@ for (int na = 0; na <= AMAX; na++) { for (int nb : nbList2) { - for (int nd = 0; nd < DMAX; nd++){ - PyByteArray u = x.getslice(0, na + nd + nb, 1); - if (verbose >= 2) { - System.out.printf("delslice(start=%d, stop=%d, step=%d)\n", - na, na + nd, 1); - if (verbose >= 3) { - System.out.println("u = " + toString(u)); - } + for (int nd = 0; nd < DMAX; nd++) { + PyByteArray u = x.getslice(0, na + nd + nb, 1); + if (verbose >= 2) { + System.out.printf("delslice(start=%d, stop=%d, step=%d, n=%d)\n", na, na + + nd, 1, nd); + if (verbose >= 3) { + System.out.println("u = " + toString(u)); } - u.delslice(na, na + nd, 1); - if (verbose >= 1) { - System.out.println("u'= " + toString(u)); - } - checkSlice(na, nd, nb, 0, xInts, null, u); } + u.delslice(na, na + nd, 1, nd); + if (verbose >= 1) { + System.out.println("u'= " + toString(u)); + } + checkSlice(na, nd, nb, 0, xInts, null, u); + } } } } @@ -1260,8 +1229,6 @@ final int[] posStart = new int[] {0, 3, 7, 16, L - 1}; final int[] posStop = new int[] {0, 3, 7, 16, L - 6, L}; -// final int[] posStart = new int[] {16}; -// final int[] posStop = new int[] {L}; for (int start : posStart) { PyObject pyStart, pyStop, pyStart_L, pyStop_L; @@ -1275,8 +1242,7 @@ } for (int stop : posStop) { - if (stop < start) - { + if (stop < start) { continue; // Skip backwards cases } @@ -1311,10 +1277,8 @@ * @param pyStop * @param verbose 0..4 control output */ - private void doTest__delslice__2(int[] uRef, - PyObject pyStart, - PyObject pyStop, - int start, int stop, int verbose) { + private void doTest__delslice__2(int[] uRef, PyObject pyStart, PyObject pyStop, int start, + int stop, int verbose) { PyByteArray u = getInstance(uRef); if (verbose >= 4) { System.out.printf(" __delslice__(%s,%s,1)\n", pyStart, pyStop); @@ -1325,16 +1289,15 @@ if (verbose >= 3) { System.out.println("u'= " + toString(u)); } - int nd = stop-start; - int nb = uRef.length-stop; + int nd = stop - start; + int nb = uRef.length - stop; checkSlice(start, nd, nb, 0, uRef, null, u); } - /** - * Test method for {@link org.python.core.PyByteArray#delslice(int,int,int)}, when the - * slice to delete is extended (3-argument slice and step!=0). Note that PySequence checks and - * converts arguments first, so we need only test with valid combinations of indices. + * Test method for {@link org.python.core.PyByteArray#delslice(int,int,int)}, when the slice to + * delete is extended (3-argument slice and step!=0). Note that PySequence checks and converts + * arguments first, so we need only test with valid combinations of indices. */ public void test__delslice__3() { int verbose = 0; @@ -1342,10 +1305,6 @@ // Need interpreter interp = new PythonInterpreter(); - // Source of assigned values. -// int[] eRef = randomInts(random, MEDIUM, 'A', 'H'); -// BaseBytes eFull = new BaseBytesTest.MyBytes(eRef); - // Forwards cases int[] uRef = randomInts(random, MEDIUM, 'm', 's'); @@ -1370,8 +1329,8 @@ // Now do the test PyByteArray u = getInstance(uRef); if (verbose >= 2) { - System.out.printf("delslice(%d,%d,%d) (%d deletions)\n", - start, stop, step, n); + System.out.printf("__delslice__(%d,%d,%d) (%d deletions)\n", start, + stop, step, n); if (verbose >= 3) { System.out.println("u = " + toString(u)); } @@ -1406,8 +1365,8 @@ // Now do the test PyByteArray u = getInstance(uRef); if (verbose >= 2) { - System.out.printf("delslice(%d,%d,%d) (%d deletions)\n", - start, stop, step, n); + System.out.printf("__delslice__(%d,%d,%d) (%d deletions)\n", start, + stop, step, n); if (verbose >= 3) { System.out.println("u = " + toString(u)); } @@ -1430,9 +1389,9 @@ */ public void testDelsliceTime3() { int verbose = 1; - timeDelslice3(100, 200, SMALL, verbose); - timeDelslice3(100, 200, MEDIUM, verbose); - timeDelslice3(10, 4, LARGE, verbose); + timeDelslice3(50, 100, SMALL, verbose); + timeDelslice3(50, 100, MEDIUM, verbose); + timeDelslice3(20, 4, LARGE, verbose); // timeDelslice3(10, 1, HUGE, verbose); } @@ -1494,10 +1453,10 @@ if (step > 0) { // Deletions available from start location to end of array - n = (xRef.length - start + step-1) / step; + n = (xRef.length - start + step - 1) / step; } else { // Deletions available from start location to beginning of array - n = (start + (-step) ) / (-step); + n = (start + (-step)) / (-step); } // Make objects of the arguments @@ -1554,12 +1513,8 @@ * @param verbose amount of output * @return elapsed time in nanoseconds for delslice operation on array of objects */ - private long doTimeDelslice3(PyByteArray[] u, - PyObject pyStart, - PyObject pyStop, - PyObject pyStep, - BaseBytes x, - int verbose) { + private long doTimeDelslice3(PyByteArray[] u, PyObject pyStart, PyObject pyStop, + PyObject pyStep, BaseBytes x, int verbose) { // The call is either to do a time trial (block of test objects) or one test of correctness int repeats = 1; @@ -1614,41 +1569,49 @@ * with a similar signature. The idea is to override the getInstance() methods to return an * instance of the class actually under test in the derived test. */ + @Override public PyByteArray getInstance(PyType type) { return new PyByteArray(type); } + @Override public PyByteArray getInstance() { return new PyByteArray(); } + @Override public PyByteArray getInstance(int size) { return new PyByteArray(size); } + @Override public PyByteArray getInstance(int[] value) { return new PyByteArray(value); } + @Override public PyByteArray getInstance(BaseBytes source) { return new PyByteArray(source); } + @Override public PyByteArray getInstance(Iterable source) { return new PyByteArray(source); } + @Override public PyByteArray getInstance(PyString arg, PyObject encoding, PyObject errors) { return new PyByteArray(arg, encoding, errors); } + @Override public PyByteArray getInstance(PyString arg, String encoding, String errors) { return new PyByteArray(arg, encoding, errors); } + @Override public PyByteArray getInstance(PyObject arg) throws PyException { return new PyByteArray(arg); } - } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Apr 10 17:35:58 2015 From: jython-checkins at python.org (jeff.allen) Date: Fri, 10 Apr 2015 15:35:58 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Corrections_to_chdir_for_sp?= =?utf-8?q?ecial_cases=2E_Fixes_=232307=2E?= Message-ID: <20150410153558.798.90143@psf.io> https://hg.python.org/jython/rev/60972a7a26c5 changeset: 7654:60972a7a26c5 user: Jeff Allen date: Fri Apr 10 10:36:38 2015 +0100 summary: Corrections to chdir for special cases. Fixes #2307. In PosixModule.absolutePath() and .chdir() use Path.normalize instead of toRealPath (to preserve DOS names); use Path.resolve() to deal with path '\'. files: src/org/python/modules/posix/PosixModule.java | 29 +++++---- 1 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/org/python/modules/posix/PosixModule.java b/src/org/python/modules/posix/PosixModule.java --- a/src/org/python/modules/posix/PosixModule.java +++ b/src/org/python/modules/posix/PosixModule.java @@ -289,11 +289,7 @@ if (!basicstat(path, absolutePath).isDirectory()) { throw Py.OSError(Errno.ENOTDIR, path); } - try { - Py.getSystemState().setCurrentWorkingDir(absolutePath.toRealPath().toString()); - } catch (IOException ioe) { - throw Py.OSError(ioe); - } + Py.getSystemState().setCurrentWorkingDir(absolutePath.toString()); } public static PyString __doc__chmod = new PyString( @@ -1122,7 +1118,8 @@ } /** - * Return the absolute form of path. + * Return the absolute, normalised form of path, equivalent to Python os.path.abspath(), except + * that it is an error for pathObj to be an empty string or unacceptable in the file system. * * @param pathObj a PyObject, raising a TypeError if an invalid path type * @return an absolute path String @@ -1130,20 +1127,24 @@ private static Path absolutePath(PyObject pathObj) { String pathStr = asPath(pathObj); if (pathStr.equals("")) { - // Otherwise this path will get prefixed with the current working directory, - // which is both wrong and very surprising! + // Returning current working directory would be wrong in our context (chdir, etc.). throw Py.OSError(Errno.ENOENT, pathObj); } try { - Path path = FileSystems.getDefault().getPath(pathStr); + Path path = Paths.get(pathStr); if (!path.isAbsolute()) { - path = FileSystems.getDefault().getPath(Py.getSystemState().getCurrentWorkingDir(), pathStr); + // Relative path: augment from current working directory. + path = Paths.get(Py.getSystemState().getCurrentWorkingDir()).resolve(path); } - return path.toAbsolutePath(); + // Strip redundant navigation a/b/../c -> a/c + return path.normalize(); } catch (java.nio.file.InvalidPathException ex) { - // Thrown on Windows for paths like foo/bar/, where is the literal text, not a metavariable :) - // NOTE: In this case on CPython, Windows throws the Windows-specific internal error WindowsError [Error 123], - // but it seems excessive to duplicate this error hierarchy + /* + * Thrown on Windows for paths like foo/bar/, where is the literal text, + * not a metavariable :) NOTE: CPython, Windows throws the Windows-specific internal + * error WindowsError [Error 123], but it seems excessive to duplicate this error + * hierarchy. + */ throw Py.OSError(Errno.EINVAL, pathObj); } } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Apr 12 05:00:05 2015 From: jython-checkins at python.org (jim.baker) Date: Sun, 12 Apr 2015 03:00:05 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_Stefan_Richthofer_to_AC?= =?utf-8?q?KNOWLEDGMENTS_for_his_contributions?= Message-ID: <20150412030003.113191.46459@psf.io> https://hg.python.org/jython/rev/ea5fe0f38096 changeset: 7655:ea5fe0f38096 user: Jim Baker date: Sat Apr 11 22:59:48 2015 -0400 summary: Add Stefan Richthofer to ACKNOWLEDGMENTS for his contributions files: ACKNOWLEDGMENTS | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -151,6 +151,7 @@ Dieter Vandenbussche Paolo Dina Eliya Sadan + Stefan Richthofer Local Variables: mode: indented-text -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Apr 13 01:24:48 2015 From: jython-checkins at python.org (jeff.allen) Date: Sun, 12 Apr 2015 23:24:48 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_regression_in_chdir_whe?= =?utf-8?q?n_switching_drives=2E?= Message-ID: <20150412232448.129706.2419@psf.io> https://hg.python.org/jython/rev/b14c97e4486c changeset: 7657:b14c97e4486c user: Jeff Allen date: Sun Apr 12 23:44:55 2015 +0100 summary: Fix regression in chdir when switching drives. Fix WindowsChdirTestCase.test_windows_getcwd_ensures_drive_letter in test.test_chdir, completing #2307. (Previously-failing tests pass on both Windows and Linux.) files: src/org/python/modules/posix/PosixModule.java | 16 ++++++--- 1 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/org/python/modules/posix/PosixModule.java b/src/org/python/modules/posix/PosixModule.java --- a/src/org/python/modules/posix/PosixModule.java +++ b/src/org/python/modules/posix/PosixModule.java @@ -1144,12 +1144,18 @@ } try { Path path = Paths.get(pathStr); - if (!path.isAbsolute()) { - // Relative path: augment from current working directory. - path = Paths.get(Py.getSystemState().getCurrentWorkingDir()).resolve(path); + // Relative path: augment from current working directory. + path = Paths.get(Py.getSystemState().getCurrentWorkingDir()).resolve(path); + // In case of a root different from cwd, resolve does not guarantee absolute. + path = path.toAbsolutePath(); + // Strip redundant navigation a/b/../c -> a/c + path = path.normalize(); + // Prevent trailing slash (possibly Java bug), except when '/' or C:\ + pathStr = path.toString(); + if (pathStr.endsWith(path.getFileSystem().getSeparator()) && path.getNameCount()>0) { + path = Paths.get(pathStr.substring(0, pathStr.length()-1)); } - // Strip redundant navigation a/b/../c -> a/c - return path.normalize(); + return path; } catch (java.nio.file.InvalidPathException ex) { /* * Thrown on Windows for paths like foo/bar/, where is the literal text, -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Apr 13 01:24:47 2015 From: jython-checkins at python.org (jeff.allen) Date: Sun, 12 Apr 2015 23:24:47 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Corrections_to_chdir_for_sp?= =?utf-8?q?ecial_cases=2C_fixing_Linux_regression=2E?= Message-ID: <20150412232447.21073.29790@psf.io> https://hg.python.org/jython/rev/3733bc1b2f38 changeset: 7656:3733bc1b2f38 parent: 7654:60972a7a26c5 user: Jeff Allen date: Sun Apr 12 17:39:08 2015 +0100 summary: Corrections to chdir for special cases, fixing Linux regression. On platforms *other* than Windows, us Path.toRealPath in chdir. Fixes regression of on Linux caused by fixing to #2307 for Windows. (Previously-failing tests pass on both Windows and Linux.) files: src/org/python/modules/posix/PosixModule.java | 16 ++++++++- 1 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/org/python/modules/posix/PosixModule.java b/src/org/python/modules/posix/PosixModule.java --- a/src/org/python/modules/posix/PosixModule.java +++ b/src/org/python/modules/posix/PosixModule.java @@ -49,6 +49,7 @@ import org.python.core.PyList; import org.python.core.PyObject; import org.python.core.PyString; +import org.python.core.PySystemState; import org.python.core.PyTuple; import org.python.core.imp; import org.python.core.Untraversable; @@ -284,12 +285,23 @@ "chdir(path)\n\n" + "Change the current working directory to the specified path."); public static void chdir(PyObject path) { + PySystemState sys = Py.getSystemState(); + Path absolutePath = absolutePath(path); // stat raises ENOENT for us if path doesn't exist - Path absolutePath = absolutePath(path); if (!basicstat(path, absolutePath).isDirectory()) { throw Py.OSError(Errno.ENOTDIR, path); } - Py.getSystemState().setCurrentWorkingDir(absolutePath.toString()); + if (os == OS.NT) { + // No symbolic links and preserve dos-like names (e.g. PROGRA~1) + sys.setCurrentWorkingDir(absolutePath.toString()); + } else { + // Resolve symbolic links + try { + sys.setCurrentWorkingDir(absolutePath.toRealPath().toString()); + } catch (IOException ioe) { + throw Py.OSError(ioe); + } + } } public static PyString __doc__chmod = new PyString( -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Apr 13 01:24:48 2015 From: jython-checkins at python.org (jeff.allen) Date: Sun, 12 Apr 2015 23:24:48 +0000 Subject: [Jython-checkins] =?utf-8?q?jython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_recent_chdir_fixes_to_trunk?= Message-ID: <20150412232448.37488.6749@psf.io> https://hg.python.org/jython/rev/b203c503b26d changeset: 7658:b203c503b26d parent: 7655:ea5fe0f38096 parent: 7657:b14c97e4486c user: Jeff Allen date: Mon Apr 13 00:24:36 2015 +0100 summary: Merge recent chdir fixes to trunk files: src/org/python/modules/posix/PosixModule.java | 32 +++++++-- 1 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/org/python/modules/posix/PosixModule.java b/src/org/python/modules/posix/PosixModule.java --- a/src/org/python/modules/posix/PosixModule.java +++ b/src/org/python/modules/posix/PosixModule.java @@ -49,6 +49,7 @@ import org.python.core.PyList; import org.python.core.PyObject; import org.python.core.PyString; +import org.python.core.PySystemState; import org.python.core.PyTuple; import org.python.core.imp; import org.python.core.Untraversable; @@ -284,12 +285,23 @@ "chdir(path)\n\n" + "Change the current working directory to the specified path."); public static void chdir(PyObject path) { + PySystemState sys = Py.getSystemState(); + Path absolutePath = absolutePath(path); // stat raises ENOENT for us if path doesn't exist - Path absolutePath = absolutePath(path); if (!basicstat(path, absolutePath).isDirectory()) { throw Py.OSError(Errno.ENOTDIR, path); } - Py.getSystemState().setCurrentWorkingDir(absolutePath.toString()); + if (os == OS.NT) { + // No symbolic links and preserve dos-like names (e.g. PROGRA~1) + sys.setCurrentWorkingDir(absolutePath.toString()); + } else { + // Resolve symbolic links + try { + sys.setCurrentWorkingDir(absolutePath.toRealPath().toString()); + } catch (IOException ioe) { + throw Py.OSError(ioe); + } + } } public static PyString __doc__chmod = new PyString( @@ -1132,12 +1144,18 @@ } try { Path path = Paths.get(pathStr); - if (!path.isAbsolute()) { - // Relative path: augment from current working directory. - path = Paths.get(Py.getSystemState().getCurrentWorkingDir()).resolve(path); + // Relative path: augment from current working directory. + path = Paths.get(Py.getSystemState().getCurrentWorkingDir()).resolve(path); + // In case of a root different from cwd, resolve does not guarantee absolute. + path = path.toAbsolutePath(); + // Strip redundant navigation a/b/../c -> a/c + path = path.normalize(); + // Prevent trailing slash (possibly Java bug), except when '/' or C:\ + pathStr = path.toString(); + if (pathStr.endsWith(path.getFileSystem().getSeparator()) && path.getNameCount()>0) { + path = Paths.get(pathStr.substring(0, pathStr.length()-1)); } - // Strip redundant navigation a/b/../c -> a/c - return path.normalize(); + return path; } catch (java.nio.file.InvalidPathException ex) { /* * Thrown on Windows for paths like foo/bar/, where is the literal text, -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Apr 13 04:38:15 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Mon, 13 Apr 2015 02:38:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Pull_in_hand_coded_ast_work?= =?utf-8?q?_into_code_gen_in_asdl=5Fantlr=2E?= Message-ID: <20150413023815.21291.74606@psf.io> https://hg.python.org/jython/rev/dd20fa095d72 changeset: 7659:dd20fa095d72 user: Frank Wierzbicki date: Mon Apr 13 02:38:45 2015 +0000 summary: Pull in hand coded ast work into code gen in asdl_antlr. files: ast/asdl_antlr.py | 125 +++++++++- src/org/python/antlr/ast/Assert.java | 1 + src/org/python/antlr/ast/Assign.java | 1 + src/org/python/antlr/ast/Attribute.java | 2 + src/org/python/antlr/ast/AugAssign.java | 1 + src/org/python/antlr/ast/BinOp.java | 1 + src/org/python/antlr/ast/BoolOp.java | 1 + src/org/python/antlr/ast/Break.java | 1 + src/org/python/antlr/ast/Call.java | 1 + src/org/python/antlr/ast/ClassDef.java | 2 + src/org/python/antlr/ast/Compare.java | 1 + src/org/python/antlr/ast/Continue.java | 1 + src/org/python/antlr/ast/Delete.java | 1 + src/org/python/antlr/ast/Dict.java | 1 + src/org/python/antlr/ast/DictComp.java | 1 + src/org/python/antlr/ast/Ellipsis.java | 1 + src/org/python/antlr/ast/ExceptHandler.java | 1 + src/org/python/antlr/ast/Exec.java | 1 + src/org/python/antlr/ast/Expr.java | 1 + src/org/python/antlr/ast/Expression.java | 1 + src/org/python/antlr/ast/ExtSlice.java | 1 + src/org/python/antlr/ast/For.java | 1 + src/org/python/antlr/ast/FunctionDef.java | 2 + src/org/python/antlr/ast/GeneratorExp.java | 1 + src/org/python/antlr/ast/Global.java | 2 + src/org/python/antlr/ast/If.java | 1 + src/org/python/antlr/ast/IfExp.java | 1 + src/org/python/antlr/ast/Import.java | 1 + src/org/python/antlr/ast/ImportFrom.java | 2 + src/org/python/antlr/ast/Index.java | 1 + src/org/python/antlr/ast/Interactive.java | 1 + src/org/python/antlr/ast/Lambda.java | 1 + src/org/python/antlr/ast/List.java | 1 + src/org/python/antlr/ast/ListComp.java | 1 + src/org/python/antlr/ast/Module.java | 1 + src/org/python/antlr/ast/Name.java | 1 + src/org/python/antlr/ast/Num.java | 1 + src/org/python/antlr/ast/Pass.java | 1 + src/org/python/antlr/ast/Print.java | 1 + src/org/python/antlr/ast/Raise.java | 1 + src/org/python/antlr/ast/Repr.java | 1 + src/org/python/antlr/ast/Return.java | 1 + src/org/python/antlr/ast/Set.java | 1 + src/org/python/antlr/ast/SetComp.java | 1 + src/org/python/antlr/ast/Slice.java | 1 + src/org/python/antlr/ast/Str.java | 1 + src/org/python/antlr/ast/Subscript.java | 1 + src/org/python/antlr/ast/Suite.java | 1 + src/org/python/antlr/ast/TryExcept.java | 1 + src/org/python/antlr/ast/TryFinally.java | 1 + src/org/python/antlr/ast/Tuple.java | 1 + src/org/python/antlr/ast/UnaryOp.java | 1 + src/org/python/antlr/ast/VisitorBase.java | 1 + src/org/python/antlr/ast/While.java | 1 + src/org/python/antlr/ast/With.java | 1 + src/org/python/antlr/ast/Yield.java | 1 + src/org/python/antlr/ast/alias.java | 2 + src/org/python/antlr/ast/arguments.java | 1 + src/org/python/antlr/base/excepthandler.java | 1 + src/org/python/antlr/base/expr.java | 1 + src/org/python/antlr/base/mod.java | 1 + src/org/python/antlr/base/slice.java | 1 + src/org/python/antlr/base/stmt.java | 1 + 63 files changed, 185 insertions(+), 8 deletions(-) diff --git a/ast/asdl_antlr.py b/ast/asdl_antlr.py --- a/ast/asdl_antlr.py +++ b/ast/asdl_antlr.py @@ -75,6 +75,7 @@ print >> self.file, 'import org.python.core.PyString;' print >> self.file, 'import org.python.core.PyStringMap;' print >> self.file, 'import org.python.core.PyType;' + print >> self.file, 'import org.python.core.Visitproc;' print >> self.file, 'import org.python.expose.ExposedGet;' print >> self.file, 'import org.python.expose.ExposedMethod;' print >> self.file, 'import org.python.expose.ExposedNew;' @@ -641,7 +642,6 @@ return jtype def indexerSupport(self, name, depth): - self.emit("// Support for indexer below", depth + 1) self.file.write(indexer_support[name]) class VisitorVisitor(EmitVisitor): @@ -707,7 +707,8 @@ VisitorVisitor(outdir)) c.visit(mod) -indexer_support = {"Attribute": """ +indexer_support = {"Attribute": """ // Support for indexer below + private Name attrName; public Name getInternalAttrName() { return attrName; @@ -729,9 +730,11 @@ this.attrName = attr; this.ctx = ctx; } + // End indexer support """, -"ClassDef": """ +"ClassDef": """ // Support for indexer below + private Name nameNode; public Name getInternalNameNode() { return nameNode; @@ -763,9 +766,11 @@ addChild(t); } } + // End indexer support """, -"FunctionDef": """ +"FunctionDef": """ // Support for indexer below + private Name nameNode; public Name getInternalNameNode() { return nameNode; @@ -791,9 +796,11 @@ addChild(t); } } + // End indexer support """, -"Global": """ +"Global": """ // Support for indexer below + private java.util.List nameNodes; public java.util.List getInternalNameNodes() { return nameNodes; @@ -803,9 +810,11 @@ this.names = names; this.nameNodes = nameNodes; } + // End indexer support """, -"ImportFrom": """ +"ImportFrom": """ // Support for indexer below + private java.util.List moduleNames; public java.util.List getInternalModuleNames() { return moduleNames; @@ -831,9 +840,11 @@ } this.level = level; } + // End indexer support """, -"alias": """ +"alias": """ // Support for indexer below + private java.util.List nameNodes; public java.util.List getInternalNameNodes() { return nameNodes; @@ -856,9 +867,11 @@ this.asname = asname.getInternalId(); } } + // End indexer support """, -"arguments": """ +"arguments": """ // Support for indexer below + private Name varargName; public Name getInternalVarargName() { return varargName; @@ -892,8 +905,104 @@ addChild(t); } } + // End indexer support + + + /* Traverseproc implementation */ + @Override + public int traverse(Visitproc visit, Object arg) { + int retVal = super.traverse(visit, arg); + if (retVal != 0) { + return retVal; + } + if (args != null) { + for (PyObject ob: args) { + if (ob != null) { + retVal = visit.visit(ob, arg); + if (retVal != 0) { + return retVal; + } + } + } + } + if (defaults != null) { + for (PyObject ob: defaults) { + if (ob != null) { + retVal = visit.visit(ob, arg); + if (retVal != 0) { + return retVal; + } + } + } + } + return 0; + } + + @Override + public boolean refersDirectlyTo(PyObject ob) { + if (ob == null) { + return false; + } else if (args != null && args.contains(ob)) { + return true; + } else if (defaults != null && defaults.contains(ob)) { + return true; + } else { + return super.refersDirectlyTo(ob); + } + } """, +"keyword": """ + /* Traverseproc implementation */ + @Override + public int traverse(Visitproc visit, Object arg) { + return value != null ? visit.visit(value, arg) : 0; + } + + @Override + public boolean refersDirectlyTo(PyObject ob) { + return ob != null && (ob == value || super.refersDirectlyTo(ob)); + } +""", +"comprehension": """ + /* Traverseproc implementation */ + @Override + public int traverse(Visitproc visit, Object arg) { + int retVal = super.traverse(visit, arg); + if (retVal != 0) { + return retVal; + } + if (iter != null) { + retVal = visit.visit(iter, arg); + if (retVal != 0) { + return retVal; + } + } + if (ifs != null) { + for (PyObject ob: ifs) { + if (ob != null) { + retVal = visit.visit(ob, arg); + if (retVal != 0) { + return retVal; + } + } + } + } + + return target != null ? visit.visit(target, arg) : 0; + } + + @Override + public boolean refersDirectlyTo(PyObject ob) { + if (ob == null) { + return false; + } else if (ifs != null && ifs.contains(ob)) { + return true; + } else { + return ob == iter || ob == target || super.refersDirectlyTo(ob); + } + } +""", } if __name__ == "__main__": diff --git a/src/org/python/antlr/ast/Assert.java b/src/org/python/antlr/ast/Assert.java --- a/src/org/python/antlr/ast/Assert.java +++ b/src/org/python/antlr/ast/Assert.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Assign.java b/src/org/python/antlr/ast/Assign.java --- a/src/org/python/antlr/ast/Assign.java +++ b/src/org/python/antlr/ast/Assign.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Attribute.java b/src/org/python/antlr/ast/Attribute.java --- a/src/org/python/antlr/ast/Attribute.java +++ b/src/org/python/antlr/ast/Attribute.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; @@ -239,4 +240,5 @@ this.attrName = attr; this.ctx = ctx; } + // End indexer support } diff --git a/src/org/python/antlr/ast/AugAssign.java b/src/org/python/antlr/ast/AugAssign.java --- a/src/org/python/antlr/ast/AugAssign.java +++ b/src/org/python/antlr/ast/AugAssign.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/BinOp.java b/src/org/python/antlr/ast/BinOp.java --- a/src/org/python/antlr/ast/BinOp.java +++ b/src/org/python/antlr/ast/BinOp.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/BoolOp.java b/src/org/python/antlr/ast/BoolOp.java --- a/src/org/python/antlr/ast/BoolOp.java +++ b/src/org/python/antlr/ast/BoolOp.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Break.java b/src/org/python/antlr/ast/Break.java --- a/src/org/python/antlr/ast/Break.java +++ b/src/org/python/antlr/ast/Break.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Call.java b/src/org/python/antlr/ast/Call.java --- a/src/org/python/antlr/ast/Call.java +++ b/src/org/python/antlr/ast/Call.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/ClassDef.java b/src/org/python/antlr/ast/ClassDef.java --- a/src/org/python/antlr/ast/ClassDef.java +++ b/src/org/python/antlr/ast/ClassDef.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; @@ -337,4 +338,5 @@ addChild(t); } } + // End indexer support } diff --git a/src/org/python/antlr/ast/Compare.java b/src/org/python/antlr/ast/Compare.java --- a/src/org/python/antlr/ast/Compare.java +++ b/src/org/python/antlr/ast/Compare.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Continue.java b/src/org/python/antlr/ast/Continue.java --- a/src/org/python/antlr/ast/Continue.java +++ b/src/org/python/antlr/ast/Continue.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Delete.java b/src/org/python/antlr/ast/Delete.java --- a/src/org/python/antlr/ast/Delete.java +++ b/src/org/python/antlr/ast/Delete.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Dict.java b/src/org/python/antlr/ast/Dict.java --- a/src/org/python/antlr/ast/Dict.java +++ b/src/org/python/antlr/ast/Dict.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/DictComp.java b/src/org/python/antlr/ast/DictComp.java --- a/src/org/python/antlr/ast/DictComp.java +++ b/src/org/python/antlr/ast/DictComp.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Ellipsis.java b/src/org/python/antlr/ast/Ellipsis.java --- a/src/org/python/antlr/ast/Ellipsis.java +++ b/src/org/python/antlr/ast/Ellipsis.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/ExceptHandler.java b/src/org/python/antlr/ast/ExceptHandler.java --- a/src/org/python/antlr/ast/ExceptHandler.java +++ b/src/org/python/antlr/ast/ExceptHandler.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Exec.java b/src/org/python/antlr/ast/Exec.java --- a/src/org/python/antlr/ast/Exec.java +++ b/src/org/python/antlr/ast/Exec.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Expr.java b/src/org/python/antlr/ast/Expr.java --- a/src/org/python/antlr/ast/Expr.java +++ b/src/org/python/antlr/ast/Expr.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Expression.java b/src/org/python/antlr/ast/Expression.java --- a/src/org/python/antlr/ast/Expression.java +++ b/src/org/python/antlr/ast/Expression.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/ExtSlice.java b/src/org/python/antlr/ast/ExtSlice.java --- a/src/org/python/antlr/ast/ExtSlice.java +++ b/src/org/python/antlr/ast/ExtSlice.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/For.java b/src/org/python/antlr/ast/For.java --- a/src/org/python/antlr/ast/For.java +++ b/src/org/python/antlr/ast/For.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/FunctionDef.java b/src/org/python/antlr/ast/FunctionDef.java --- a/src/org/python/antlr/ast/FunctionDef.java +++ b/src/org/python/antlr/ast/FunctionDef.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; @@ -309,4 +310,5 @@ addChild(t); } } + // End indexer support } diff --git a/src/org/python/antlr/ast/GeneratorExp.java b/src/org/python/antlr/ast/GeneratorExp.java --- a/src/org/python/antlr/ast/GeneratorExp.java +++ b/src/org/python/antlr/ast/GeneratorExp.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Global.java b/src/org/python/antlr/ast/Global.java --- a/src/org/python/antlr/ast/Global.java +++ b/src/org/python/antlr/ast/Global.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; @@ -175,4 +176,5 @@ this.names = names; this.nameNodes = nameNodes; } + // End indexer support } diff --git a/src/org/python/antlr/ast/If.java b/src/org/python/antlr/ast/If.java --- a/src/org/python/antlr/ast/If.java +++ b/src/org/python/antlr/ast/If.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/IfExp.java b/src/org/python/antlr/ast/IfExp.java --- a/src/org/python/antlr/ast/IfExp.java +++ b/src/org/python/antlr/ast/IfExp.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Import.java b/src/org/python/antlr/ast/Import.java --- a/src/org/python/antlr/ast/Import.java +++ b/src/org/python/antlr/ast/Import.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/ImportFrom.java b/src/org/python/antlr/ast/ImportFrom.java --- a/src/org/python/antlr/ast/ImportFrom.java +++ b/src/org/python/antlr/ast/ImportFrom.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; @@ -259,4 +260,5 @@ } this.level = level; } + // End indexer support } diff --git a/src/org/python/antlr/ast/Index.java b/src/org/python/antlr/ast/Index.java --- a/src/org/python/antlr/ast/Index.java +++ b/src/org/python/antlr/ast/Index.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Interactive.java b/src/org/python/antlr/ast/Interactive.java --- a/src/org/python/antlr/ast/Interactive.java +++ b/src/org/python/antlr/ast/Interactive.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Lambda.java b/src/org/python/antlr/ast/Lambda.java --- a/src/org/python/antlr/ast/Lambda.java +++ b/src/org/python/antlr/ast/Lambda.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/List.java b/src/org/python/antlr/ast/List.java --- a/src/org/python/antlr/ast/List.java +++ b/src/org/python/antlr/ast/List.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/ListComp.java b/src/org/python/antlr/ast/ListComp.java --- a/src/org/python/antlr/ast/ListComp.java +++ b/src/org/python/antlr/ast/ListComp.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Module.java b/src/org/python/antlr/ast/Module.java --- a/src/org/python/antlr/ast/Module.java +++ b/src/org/python/antlr/ast/Module.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Name.java b/src/org/python/antlr/ast/Name.java --- a/src/org/python/antlr/ast/Name.java +++ b/src/org/python/antlr/ast/Name.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Num.java b/src/org/python/antlr/ast/Num.java --- a/src/org/python/antlr/ast/Num.java +++ b/src/org/python/antlr/ast/Num.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Pass.java b/src/org/python/antlr/ast/Pass.java --- a/src/org/python/antlr/ast/Pass.java +++ b/src/org/python/antlr/ast/Pass.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Print.java b/src/org/python/antlr/ast/Print.java --- a/src/org/python/antlr/ast/Print.java +++ b/src/org/python/antlr/ast/Print.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Raise.java b/src/org/python/antlr/ast/Raise.java --- a/src/org/python/antlr/ast/Raise.java +++ b/src/org/python/antlr/ast/Raise.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Repr.java b/src/org/python/antlr/ast/Repr.java --- a/src/org/python/antlr/ast/Repr.java +++ b/src/org/python/antlr/ast/Repr.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Return.java b/src/org/python/antlr/ast/Return.java --- a/src/org/python/antlr/ast/Return.java +++ b/src/org/python/antlr/ast/Return.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Set.java b/src/org/python/antlr/ast/Set.java --- a/src/org/python/antlr/ast/Set.java +++ b/src/org/python/antlr/ast/Set.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/SetComp.java b/src/org/python/antlr/ast/SetComp.java --- a/src/org/python/antlr/ast/SetComp.java +++ b/src/org/python/antlr/ast/SetComp.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Slice.java b/src/org/python/antlr/ast/Slice.java --- a/src/org/python/antlr/ast/Slice.java +++ b/src/org/python/antlr/ast/Slice.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Str.java b/src/org/python/antlr/ast/Str.java --- a/src/org/python/antlr/ast/Str.java +++ b/src/org/python/antlr/ast/Str.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Subscript.java b/src/org/python/antlr/ast/Subscript.java --- a/src/org/python/antlr/ast/Subscript.java +++ b/src/org/python/antlr/ast/Subscript.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Suite.java b/src/org/python/antlr/ast/Suite.java --- a/src/org/python/antlr/ast/Suite.java +++ b/src/org/python/antlr/ast/Suite.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/TryExcept.java b/src/org/python/antlr/ast/TryExcept.java --- a/src/org/python/antlr/ast/TryExcept.java +++ b/src/org/python/antlr/ast/TryExcept.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/TryFinally.java b/src/org/python/antlr/ast/TryFinally.java --- a/src/org/python/antlr/ast/TryFinally.java +++ b/src/org/python/antlr/ast/TryFinally.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Tuple.java b/src/org/python/antlr/ast/Tuple.java --- a/src/org/python/antlr/ast/Tuple.java +++ b/src/org/python/antlr/ast/Tuple.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/UnaryOp.java b/src/org/python/antlr/ast/UnaryOp.java --- a/src/org/python/antlr/ast/UnaryOp.java +++ b/src/org/python/antlr/ast/UnaryOp.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/VisitorBase.java b/src/org/python/antlr/ast/VisitorBase.java --- a/src/org/python/antlr/ast/VisitorBase.java +++ b/src/org/python/antlr/ast/VisitorBase.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/While.java b/src/org/python/antlr/ast/While.java --- a/src/org/python/antlr/ast/While.java +++ b/src/org/python/antlr/ast/While.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/With.java b/src/org/python/antlr/ast/With.java --- a/src/org/python/antlr/ast/With.java +++ b/src/org/python/antlr/ast/With.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/Yield.java b/src/org/python/antlr/ast/Yield.java --- a/src/org/python/antlr/ast/Yield.java +++ b/src/org/python/antlr/ast/Yield.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/ast/alias.java b/src/org/python/antlr/ast/alias.java --- a/src/org/python/antlr/ast/alias.java +++ b/src/org/python/antlr/ast/alias.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; @@ -173,4 +174,5 @@ this.asname = asname.getInternalId(); } } + // End indexer support } diff --git a/src/org/python/antlr/ast/arguments.java b/src/org/python/antlr/ast/arguments.java --- a/src/org/python/antlr/ast/arguments.java +++ b/src/org/python/antlr/ast/arguments.java @@ -279,6 +279,7 @@ addChild(t); } } + // End indexer support /* Traverseproc implementation */ diff --git a/src/org/python/antlr/base/excepthandler.java b/src/org/python/antlr/base/excepthandler.java --- a/src/org/python/antlr/base/excepthandler.java +++ b/src/org/python/antlr/base/excepthandler.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/base/expr.java b/src/org/python/antlr/base/expr.java --- a/src/org/python/antlr/base/expr.java +++ b/src/org/python/antlr/base/expr.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/base/mod.java b/src/org/python/antlr/base/mod.java --- a/src/org/python/antlr/base/mod.java +++ b/src/org/python/antlr/base/mod.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/base/slice.java b/src/org/python/antlr/base/slice.java --- a/src/org/python/antlr/base/slice.java +++ b/src/org/python/antlr/base/slice.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; diff --git a/src/org/python/antlr/base/stmt.java b/src/org/python/antlr/base/stmt.java --- a/src/org/python/antlr/base/stmt.java +++ b/src/org/python/antlr/base/stmt.java @@ -17,6 +17,7 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Apr 13 19:56:36 2015 From: jython-checkins at python.org (alex.gronholm) Date: Mon, 13 Apr 2015 17:56:36 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Added_automatic_type_coerci?= =?utf-8?q?on_of_decimal=2EDecimal_to_java=2Elang=2EDouble_and?= Message-ID: <20150413175635.62515.51579@psf.io> https://hg.python.org/jython/rev/d86bf9da41c7 changeset: 7660:d86bf9da41c7 user: Alex Gr?nholm date: Mon Apr 13 13:48:05 2015 -0400 summary: Added automatic type coercion of decimal.Decimal to java.lang.Double and java.lang.Float. Fixes #1670. files: Lib/decimal.py | 12 ++++++++---- Lib/test/test_decimal_jy.py | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Lib/decimal.py b/Lib/decimal.py --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -402,7 +402,7 @@ del sys, MockThreading try: - from java.lang import Object + from java.lang import Object, Float, Double from java.math import BigDecimal from org.python.core import Py except ImportError: @@ -3691,9 +3691,13 @@ # support for Jython __tojava__: def __tojava__(self, java_class): - if java_class not in (BigDecimal, Object): - return Py.NoConversion - return BigDecimal(str(self)) + if java_class is Float: + return Float(str(self)) + if java_class is Double: + return Double(str(self)) + if java_class in (BigDecimal, Object): + return BigDecimal(str(self)) + return Py.NoConversion def _dec_from_triple(sign, coefficient, exponent, special=False): """Create a decimal instance directly, without any validation, diff --git a/Lib/test/test_decimal_jy.py b/Lib/test/test_decimal_jy.py --- a/Lib/test/test_decimal_jy.py +++ b/Lib/test/test_decimal_jy.py @@ -3,17 +3,32 @@ from decimal import Decimal +from java.lang import Float, Double, Object from java.math import BigDecimal class TestJavaDecimal(unittest.TestCase): def test_decimal(self): - self.assertTrue(hasattr(Decimal, "__tojava__")) x = Decimal("1.1") y = x.__tojava__(BigDecimal) self.assertTrue(isinstance(y, BigDecimal)) + def test_object(self): + x = Decimal("1.1") + y = x.__tojava__(Object) + self.assertTrue(isinstance(y, BigDecimal)) + + def test_float(self): + x = Decimal("1.1") + y = x.__tojava__(Float) + self.assertTrue(isinstance(y, Float)) + + def test_double(self): + x = Decimal("1.1") + y = x.__tojava__(Double) + self.assertTrue(isinstance(y, Double)) + if __name__ == '__main__': unittest.main() -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Apr 13 21:44:19 2015 From: jython-checkins at python.org (alex.gronholm) Date: Mon, 13 Apr 2015 19:44:19 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Refreshed_several_networkin?= =?utf-8?q?g_modules_from_CPython_2=2E7=2E9_due_to_CVE-2013-1752?= Message-ID: <20150413194419.800.85347@psf.io> https://hg.python.org/jython/rev/415c4a58078e changeset: 7661:415c4a58078e user: Alex Gr?nholm date: Mon Apr 13 15:41:49 2015 -0400 summary: Refreshed several networking modules from CPython 2.7.9 due to CVE-2013-1752 (fixes #2322) files: lib-python/2.7/ftplib.py | 31 +++++++-- lib-python/2.7/httplib.py | 83 +++++++++++++++++++------- lib-python/2.7/imaplib.py | 19 +++++- lib-python/2.7/nntplib.py | 11 +++- lib-python/2.7/poplib.py | 14 +++- lib-python/2.7/smtplib.py | 51 +++++++++++----- 6 files changed, 157 insertions(+), 52 deletions(-) diff --git a/lib-python/2.7/ftplib.py b/lib-python/2.7/ftplib.py --- a/lib-python/2.7/ftplib.py +++ b/lib-python/2.7/ftplib.py @@ -55,6 +55,8 @@ # The standard FTP server control port FTP_PORT = 21 +# The sizehint parameter passed to readline() calls +MAXLINE = 8192 # Exception raised when an error or invalid response is received @@ -101,6 +103,7 @@ debugging = 0 host = '' port = FTP_PORT + maxline = MAXLINE sock = None file = None welcome = None @@ -180,7 +183,9 @@ # Internal: return one line from the server, stripping CRLF. # Raise EOFError if the connection is closed def getline(self): - line = self.file.readline() + line = self.file.readline(self.maxline + 1) + if len(line) > self.maxline: + raise Error("got more than %d bytes" % self.maxline) if self.debugging > 1: print '*get*', self.sanitize(line) if not line: raise EOFError @@ -432,7 +437,9 @@ conn = self.transfercmd(cmd) fp = conn.makefile('rb') while 1: - line = fp.readline() + line = fp.readline(self.maxline + 1) + if len(line) > self.maxline: + raise Error("got more than %d bytes" % self.maxline) if self.debugging > 2: print '*retr*', repr(line) if not line: break @@ -454,7 +461,7 @@ blocksize: The maximum data size to read from fp and send over the connection at once. [default: 8192] callback: An optional single parameter callable that is called on - on each block of data after it is sent. [default: None] + each block of data after it is sent. [default: None] rest: Passed to transfercmd(). [default: None] Returns: @@ -477,7 +484,7 @@ cmd: A STOR command. fp: A file-like object with a readline() method. callback: An optional single parameter callable that is called on - on each line after it is sent. [default: None] + each line after it is sent. [default: None] Returns: The response code. @@ -485,7 +492,9 @@ self.voidcmd('TYPE A') conn = self.transfercmd(cmd) while 1: - buf = fp.readline() + buf = fp.readline(self.maxline + 1) + if len(buf) > self.maxline: + raise Error("got more than %d bytes" % self.maxline) if not buf: break if buf[-2:] != CRLF: if buf[-1] in CRLF: buf = buf[:-1] @@ -710,7 +719,9 @@ fp = conn.makefile('rb') try: while 1: - line = fp.readline() + line = fp.readline(self.maxline + 1) + if len(line) > self.maxline: + raise Error("got more than %d bytes" % self.maxline) if self.debugging > 2: print '*retr*', repr(line) if not line: break @@ -748,7 +759,9 @@ conn = self.transfercmd(cmd) try: while 1: - buf = fp.readline() + buf = fp.readline(self.maxline + 1) + if len(buf) > self.maxline: + raise Error("got more than %d bytes" % self.maxline) if not buf: break if buf[-2:] != CRLF: if buf[-1] in CRLF: buf = buf[:-1] @@ -905,7 +918,9 @@ fp = open(filename, "r") in_macro = 0 while 1: - line = fp.readline() + line = fp.readline(self.maxline + 1) + if len(line) > self.maxline: + raise Error("got more than %d bytes" % self.maxline) if not line: break if in_macro and line.strip(): macro_lines.append(line) diff --git a/lib-python/2.7/httplib.py b/lib-python/2.7/httplib.py --- a/lib-python/2.7/httplib.py +++ b/lib-python/2.7/httplib.py @@ -215,6 +215,10 @@ # maximal line length when calling readline(). _MAXLINE = 65536 +# maximum amount of headers accepted +_MAXHEADERS = 100 + + class HTTPMessage(mimetools.Message): def addheader(self, key, value): @@ -271,6 +275,8 @@ elif self.seekable: tell = self.fp.tell while True: + if len(hlist) > _MAXHEADERS: + raise HTTPException("got more than %d headers" % _MAXHEADERS) if tell: try: startofline = tell() @@ -565,7 +571,7 @@ # connection, and the user is reading more bytes than will be provided # (for example, reading in 1k chunks) s = self.fp.read(amt) - if not s: + if not s and amt: # Ideally, we would raise IncompleteRead if the content-length # wasn't satisfied, but it might break compatibility. self.close() @@ -700,17 +706,33 @@ self._tunnel_host = None self._tunnel_port = None self._tunnel_headers = {} - - self._set_hostport(host, port) if strict is not None: self.strict = strict + (self.host, self.port) = self._get_hostport(host, port) + + # This is stored as an instance variable to allow unittests + # to replace with a suitable mock + self._create_connection = socket.create_connection + def set_tunnel(self, host, port=None, headers=None): - """ Sets up the host and the port for the HTTP CONNECT Tunnelling. + """ Set up host and port for HTTP CONNECT tunnelling. + + In a connection that uses HTTP Connect tunneling, the host passed to the + constructor is used as proxy server that relays all communication to the + endpoint passed to set_tunnel. This is done by sending a HTTP CONNECT + request to the proxy server when the connection is established. + + This method must be called before the HTML connection has been + established. The headers argument should be a mapping of extra HTTP headers to send with the CONNECT request. """ + # Verify if this is required. + if self.sock: + raise RuntimeError("Can't setup tunnel for established connection.") + self._tunnel_host = host self._tunnel_port = port if headers: @@ -718,7 +740,7 @@ else: self._tunnel_headers.clear() - def _set_hostport(self, host, port): + def _get_hostport(self, host, port): if port is None: i = host.rfind(':') j = host.rfind(']') # ipv6 addresses have [...] @@ -735,15 +757,14 @@ port = self.default_port if host and host[0] == '[' and host[-1] == ']': host = host[1:-1] - self.host = host - self.port = port + return (host, port) def set_debuglevel(self, level): self.debuglevel = level def _tunnel(self): - self._set_hostport(self._tunnel_host, self._tunnel_port) - self.send("CONNECT %s:%d HTTP/1.0\r\n" % (self.host, self.port)) + (host, port) = self._get_hostport(self._tunnel_host, self._tunnel_port) + self.send("CONNECT %s:%d HTTP/1.0\r\n" % (host, port)) for header, value in self._tunnel_headers.iteritems(): self.send("%s: %s\r\n" % (header, value)) self.send("\r\n") @@ -768,8 +789,8 @@ def connect(self): """Connect to the host and port specified in __init__.""" - self.sock = socket.create_connection((self.host,self.port), - self.timeout, self.source_address) + self.sock = self._create_connection((self.host,self.port), + self.timeout, self.source_address) if self._tunnel_host: self._tunnel() @@ -907,17 +928,24 @@ netloc_enc = netloc.encode("idna") self.putheader('Host', netloc_enc) else: + if self._tunnel_host: + host = self._tunnel_host + port = self._tunnel_port + else: + host = self.host + port = self.port + try: - host_enc = self.host.encode("ascii") + host_enc = host.encode("ascii") except UnicodeEncodeError: - host_enc = self.host.encode("idna") + host_enc = host.encode("idna") # Wrap the IPv6 Host Header with [] (RFC 2732) if host_enc.find(':') >= 0: host_enc = "[" + host_enc + "]" - if self.port == self.default_port: + if port == self.default_port: self.putheader('Host', host_enc) else: - self.putheader('Host', "%s:%s" % (host_enc, self.port)) + self.putheader('Host', "%s:%s" % (host_enc, port)) # note: we are assuming that clients will not attempt to set these # headers since *this* library must deal with the @@ -1159,21 +1187,29 @@ def __init__(self, host, port=None, key_file=None, cert_file=None, strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, - source_address=None): + source_address=None, context=None): HTTPConnection.__init__(self, host, port, strict, timeout, source_address) self.key_file = key_file self.cert_file = cert_file + if context is None: + context = ssl._create_default_https_context() + if key_file or cert_file: + context.load_cert_chain(cert_file, key_file) + self._context = context def connect(self): "Connect to a host on a given (SSL) port." - sock = socket.create_connection((self.host, self.port), - self.timeout, self.source_address) + HTTPConnection.connect(self) + if self._tunnel_host: - self.sock = sock - self._tunnel() - self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file) + server_hostname = self._tunnel_host + else: + server_hostname = self.host + + self.sock = self._context.wrap_socket(self.sock, + server_hostname=server_hostname) __all__.append("HTTPSConnection") @@ -1188,14 +1224,15 @@ _connection_class = HTTPSConnection def __init__(self, host='', port=None, key_file=None, cert_file=None, - strict=None): + strict=None, context=None): # provide a default host, pass the X509 cert info # urf. compensate for bad input. if port == 0: port = None self._setup(self._connection_class(host, port, key_file, - cert_file, strict)) + cert_file, strict, + context=context)) # we never actually use these for anything, but we keep them # here for compatibility with post-1.5.2 CVS. diff --git a/lib-python/2.7/imaplib.py b/lib-python/2.7/imaplib.py --- a/lib-python/2.7/imaplib.py +++ b/lib-python/2.7/imaplib.py @@ -35,6 +35,15 @@ IMAP4_SSL_PORT = 993 AllowedVersions = ('IMAP4REV1', 'IMAP4') # Most recent first +# Maximal line length when calling readline(). This is to prevent +# reading arbitrary length lines. RFC 3501 and 2060 (IMAP 4rev1) +# don't specify a line length. RFC 2683 however suggests limiting client +# command lines to 1000 octets and server command lines to 8000 octets. +# We have selected 10000 for some extra margin and since that is supposedly +# also what UW and Panda IMAP does. +_MAXLINE = 10000 + + # Commands Commands = { @@ -237,7 +246,10 @@ def readline(self): """Read line from remote.""" - return self.file.readline() + line = self.file.readline(_MAXLINE + 1) + if len(line) > _MAXLINE: + raise self.error("got more than %d bytes" % _MAXLINE) + return line def send(self, data): @@ -990,6 +1002,11 @@ del self.tagged_commands[tag] return result + # If we've seen a BYE at this point, the socket will be + # closed, so report the BYE now. + + self._check_bye() + # Some have reported "unexpected response" exceptions. # Note that ignoring them here causes loops. # Instead, send me details of the unexpected response and diff --git a/lib-python/2.7/nntplib.py b/lib-python/2.7/nntplib.py --- a/lib-python/2.7/nntplib.py +++ b/lib-python/2.7/nntplib.py @@ -37,6 +37,13 @@ "error_reply","error_temp","error_perm","error_proto", "error_data",] +# maximal line length when calling readline(). This is to prevent +# reading arbitrary length lines. RFC 3977 limits NNTP line length to +# 512 characters, including CRLF. We have selected 2048 just to be on +# the safe side. +_MAXLINE = 2048 + + # Exceptions raised when an error or invalid response is received class NNTPError(Exception): """Base class for all nntplib exceptions""" @@ -200,7 +207,9 @@ def getline(self): """Internal: return one line from the server, stripping CRLF. Raise EOFError if the connection is closed.""" - line = self.file.readline() + line = self.file.readline(_MAXLINE + 1) + if len(line) > _MAXLINE: + raise NNTPDataError('line too long') if self.debugging > 1: print '*get*', repr(line) if not line: raise EOFError diff --git a/lib-python/2.7/poplib.py b/lib-python/2.7/poplib.py --- a/lib-python/2.7/poplib.py +++ b/lib-python/2.7/poplib.py @@ -32,6 +32,12 @@ LF = '\n' CRLF = CR+LF +# maximal line length when calling readline(). This is to prevent +# reading arbitrary length lines. RFC 1939 limits POP3 line length to +# 512 characters, including CRLF. We have selected 2048 just to be on +# the safe side. +_MAXLINE = 2048 + class POP3: @@ -103,7 +109,9 @@ # Raise error_proto('-ERR EOF') if the connection is closed. def _getline(self): - line = self.file.readline() + line = self.file.readline(_MAXLINE + 1) + if len(line) > _MAXLINE: + raise error_proto('line too long') if self._debugging > 1: print '*get*', repr(line) if not line: raise error_proto('-ERR EOF') octets = len(line) @@ -321,7 +329,7 @@ hostname - the hostname of the pop3 over ssl server port - port number - keyfile - PEM formatted file that countains your private key + keyfile - PEM formatted file that contains your private key certfile - PEM formatted certificate chain file See the methods of the parent class POP3 for more documentation. @@ -365,6 +373,8 @@ match = renewline.match(self.buffer) while not match: self._fillBuffer() + if len(self.buffer) > _MAXLINE: + raise error_proto('line too long') match = renewline.match(self.buffer) line = match.group(0) self.buffer = renewline.sub('' ,self.buffer, 1) diff --git a/lib-python/2.7/smtplib.py b/lib-python/2.7/smtplib.py --- a/lib-python/2.7/smtplib.py +++ b/lib-python/2.7/smtplib.py @@ -57,6 +57,7 @@ SMTP_PORT = 25 SMTP_SSL_PORT = 465 CRLF = "\r\n" +_MAXLINE = 8192 # more than 8 times larger than RFC 821, 4.5.3 OLDSTYLE_AUTH = re.compile(r"auth=(.*)", re.I) @@ -179,10 +180,14 @@ def __init__(self, sslobj): self.sslobj = sslobj - def readline(self): + def readline(self, size=-1): + if size < 0: + size = None str = "" chr = None while chr != "\n": + if size is not None and len(str) >= size: + break chr = self.sslobj.read(1) if not chr: break @@ -237,10 +242,12 @@ If specified, `host' is the name of the remote host to which to connect. If specified, `port' specifies the port to which to connect. - By default, smtplib.SMTP_PORT is used. An SMTPConnectError is raised - if the specified `host' doesn't respond correctly. If specified, - `local_hostname` is used as the FQDN of the local host. By default, - the local hostname is found using socket.getfqdn(). + By default, smtplib.SMTP_PORT is used. If a host is specified the + connect method is called, and if it returns anything other than a + success code an SMTPConnectError is raised. If specified, + `local_hostname` is used as the FQDN of the local host for the + HELO/EHLO command. Otherwise, the local hostname is found using + socket.getfqdn(). """ self.timeout = timeout @@ -276,12 +283,12 @@ """ self.debuglevel = debuglevel - def _get_socket(self, port, host, timeout): + def _get_socket(self, host, port, timeout): # This makes it simpler for SMTP_SSL to use the SMTP connect code # and just alter the socket connection bit. if self.debuglevel > 0: print>>stderr, 'connect:', (host, port) - return socket.create_connection((port, host), timeout) + return socket.create_connection((host, port), timeout) def connect(self, host='localhost', port=0): """Connect to a host on a given port. @@ -351,7 +358,7 @@ self.file = self.sock.makefile('rb') while 1: try: - line = self.file.readline() + line = self.file.readline(_MAXLINE + 1) except socket.error as e: self.close() raise SMTPServerDisconnected("Connection unexpectedly closed: " @@ -361,6 +368,8 @@ raise SMTPServerDisconnected("Connection unexpectedly closed") if self.debuglevel > 0: print>>stderr, 'reply:', repr(line) + if len(line) > _MAXLINE: + raise SMTPResponseException(500, "Line too long.") resp.append(line[4:].strip()) code = line[:3] # Check that the error code is syntactically correct. @@ -752,18 +761,25 @@ def quit(self): """Terminate the SMTP session.""" res = self.docmd("quit") + # A new EHLO is required after reconnecting with connect() + self.ehlo_resp = self.helo_resp = None + self.esmtp_features = {} + self.does_esmtp = False self.close() return res if _have_ssl: class SMTP_SSL(SMTP): - """ This is a subclass derived from SMTP that connects over an SSL encrypted - socket (to use this class you need a socket module that was compiled with SSL - support). If host is not specified, '' (the local host) is used. If port is - omitted, the standard SMTP-over-SSL port (465) is used. keyfile and certfile - are also optional - they can contain a PEM formatted private key and - certificate chain file for the SSL connection. + """ This is a subclass derived from SMTP that connects over an SSL + encrypted socket (to use this class you need a socket module that was + compiled with SSL support). If host is not specified, '' (the local + host) is used. If port is omitted, the standard SMTP-over-SSL port + (465) is used. local_hostname has the same meaning as it does in the + SMTP class. keyfile and certfile are also optional - they can contain + a PEM formatted private key and certificate chain file for the SSL + connection. + """ default_port = SMTP_SSL_PORT @@ -794,9 +810,10 @@ """LMTP - Local Mail Transfer Protocol The LMTP protocol, which is very similar to ESMTP, is heavily based - on the standard SMTP client. It's common to use Unix sockets for LMTP, - so our connect() method must support that as well as a regular - host:port server. To specify a Unix socket, you must use an absolute + on the standard SMTP client. It's common to use Unix sockets for + LMTP, so our connect() method must support that as well as a regular + host:port server. local_hostname has the same meaning as it does in + the SMTP class. To specify a Unix socket, you must use an absolute path as the host, starting with a '/'. Authentication is supported, using the regular SMTP mechanism. When -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Apr 14 01:19:53 2015 From: jython-checkins at python.org (alex.gronholm) Date: Mon, 13 Apr 2015 23:19:53 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Reverted_httplib_to_an_earl?= =?utf-8?q?ier_version?= Message-ID: <20150413231953.46650.70416@psf.io> https://hg.python.org/jython/rev/2e19fbf8ac38 changeset: 7662:2e19fbf8ac38 user: Alex Gr?nholm date: Mon Apr 13 19:19:09 2015 -0400 summary: Reverted httplib to an earlier version The latest version requires changes to the ssl module which we can't implemented yet. files: lib-python/2.7/httplib.py | 25 ++---- lib-python/2.7/test/test_httplib.py | 63 +++++++++++++++- 2 files changed, 66 insertions(+), 22 deletions(-) diff --git a/lib-python/2.7/httplib.py b/lib-python/2.7/httplib.py --- a/lib-python/2.7/httplib.py +++ b/lib-python/2.7/httplib.py @@ -1187,29 +1187,21 @@ def __init__(self, host, port=None, key_file=None, cert_file=None, strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, - source_address=None, context=None): + source_address=None): HTTPConnection.__init__(self, host, port, strict, timeout, source_address) self.key_file = key_file self.cert_file = cert_file - if context is None: - context = ssl._create_default_https_context() - if key_file or cert_file: - context.load_cert_chain(cert_file, key_file) - self._context = context def connect(self): "Connect to a host on a given (SSL) port." - HTTPConnection.connect(self) - + sock = self._create_connection((self.host, self.port), + self.timeout, self.source_address) if self._tunnel_host: - server_hostname = self._tunnel_host - else: - server_hostname = self.host - - self.sock = self._context.wrap_socket(self.sock, - server_hostname=server_hostname) + self.sock = sock + self._tunnel() + self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file) __all__.append("HTTPSConnection") @@ -1224,15 +1216,14 @@ _connection_class = HTTPSConnection def __init__(self, host='', port=None, key_file=None, cert_file=None, - strict=None, context=None): + strict=None): # provide a default host, pass the X509 cert info # urf. compensate for bad input. if port == 0: port = None self._setup(self._connection_class(host, port, key_file, - cert_file, strict, - context=context)) + cert_file, strict)) # we never actually use these for anything, but we keep them # here for compatibility with post-1.5.2 CVS. diff --git a/lib-python/2.7/test/test_httplib.py b/lib-python/2.7/test/test_httplib.py --- a/lib-python/2.7/test/test_httplib.py +++ b/lib-python/2.7/test/test_httplib.py @@ -13,10 +13,12 @@ HOST = test_support.HOST class FakeSocket: - def __init__(self, text, fileclass=StringIO.StringIO): + def __init__(self, text, fileclass=StringIO.StringIO, host=None, port=None): self.text = text self.fileclass = fileclass self.data = '' + self.host = host + self.port = port def sendall(self, data): self.data += ''.join(data) @@ -26,6 +28,9 @@ raise httplib.UnimplementedFileMode() return self.fileclass(self.text) + def close(self): + pass + class EPipeSocket(FakeSocket): def __init__(self, text, pipe_trigger): @@ -123,7 +128,7 @@ conn.sock = FakeSocket(None) conn.putrequest('GET','/') conn.putheader('Content-length',42) - self.assertTrue('Content-length: 42' in conn._buffer) + self.assertIn('Content-length: 42', conn._buffer) def test_ipv6host_header(self): # Default host header on IPv6 transaction should wrapped by [] if @@ -153,6 +158,8 @@ sock = FakeSocket(body) resp = httplib.HTTPResponse(sock) resp.begin() + self.assertEqual(resp.read(0), '') # Issue #20007 + self.assertFalse(resp.isclosed()) self.assertEqual(resp.read(), 'Text') self.assertTrue(resp.isclosed()) @@ -255,6 +262,13 @@ if resp.read() != "": self.fail("Did not expect response from HEAD request") + def test_too_many_headers(self): + headers = '\r\n'.join('Header%d: foo' % i for i in xrange(200)) + '\r\n' + text = ('HTTP/1.1 200 OK\r\n' + headers) + s = FakeSocket(text) + r = httplib.HTTPResponse(s) + self.assertRaises(httplib.HTTPException, r.begin) + def test_send_file(self): expected = 'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \ 'Accept-Encoding: identity\r\nContent-Length:' @@ -464,7 +478,7 @@ HTTPConnection and into the socket. ''' # default -- use global socket timeout - self.assertTrue(socket.getdefaulttimeout() is None) + self.assertIsNone(socket.getdefaulttimeout()) socket.setdefaulttimeout(30) try: httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT) @@ -475,7 +489,7 @@ httpConn.close() # no timeout -- do not use global socket default - self.assertTrue(socket.getdefaulttimeout() is None) + self.assertIsNone(socket.getdefaulttimeout()) socket.setdefaulttimeout(30) try: httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT, @@ -524,9 +538,48 @@ self.fail("Port incorrectly parsed: %s != %s" % (p, c.host)) +class TunnelTests(TestCase): + def test_connect(self): + response_text = ( + 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT + 'HTTP/1.1 200 OK\r\n' # Reply to HEAD + 'Content-Length: 42\r\n\r\n' + ) + + def create_connection(address, timeout=None, source_address=None): + return FakeSocket(response_text, host=address[0], port=address[1]) + + conn = httplib.HTTPConnection('proxy.com') + conn._create_connection = create_connection + + # Once connected, we should not be able to tunnel anymore + conn.connect() + self.assertRaises(RuntimeError, conn.set_tunnel, 'destination.com') + + # But if close the connection, we are good. + conn.close() + conn.set_tunnel('destination.com') + conn.request('HEAD', '/', '') + + self.assertEqual(conn.sock.host, 'proxy.com') + self.assertEqual(conn.sock.port, 80) + self.assertTrue('CONNECT destination.com' in conn.sock.data) + self.assertTrue('Host: destination.com' in conn.sock.data) + + self.assertTrue('Host: proxy.com' not in conn.sock.data) + + conn.close() + + conn.request('PUT', '/', '') + self.assertEqual(conn.sock.host, 'proxy.com') + self.assertEqual(conn.sock.port, 80) + self.assertTrue('CONNECT destination.com' in conn.sock.data) + self.assertTrue('Host: destination.com' in conn.sock.data) + + def test_main(verbose=None): test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest, - HTTPSTimeoutTest, SourceAddressTest) + HTTPSTimeoutTest, SourceAddressTest, TunnelTests) if __name__ == '__main__': test_main() -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Apr 14 03:57:35 2015 From: jython-checkins at python.org (jim.baker) Date: Tue, 14 Apr 2015 01:57:35 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Bump_copyright_date_to_incl?= =?utf-8?q?ude_2015?= Message-ID: <20150414015735.66513.25850@psf.io> https://hg.python.org/jython/rev/f40431630fb9 changeset: 7663:f40431630fb9 user: Jim Baker date: Mon Apr 13 21:57:26 2015 -0400 summary: Bump copyright date to include 2015 files: src/org/python/core/PySystemState.java | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -101,7 +101,7 @@ */ public static final PyObject copyright = Py.newString( - "Copyright (c) 2000-2014 Jython Developers.\n" + "All rights reserved.\n\n" + + "Copyright (c) 2000-2015 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" -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Apr 14 03:58:36 2015 From: jython-checkins at python.org (jim.baker) Date: Tue, 14 Apr 2015 01:58:36 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_NEWS_cleanup?= Message-ID: <20150414015835.46662.58265@psf.io> https://hg.python.org/jython/rev/4661224ebb13 changeset: 7664:4661224ebb13 user: Jim Baker date: Mon Apr 13 21:58:32 2015 -0400 summary: NEWS cleanup files: NEWS | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -6,7 +6,7 @@ Bugs fixed - [ 2301 ] time.strftime now always returns a bytestring (fixes pip on Japanese locales) - [ 2297 ] Updates Jython installer to use jython.exe - - [ 2298 ] Fix setuptools wheel bundled by ensurepip so it check for Windows on Jython + - [ 2298 ] Fix setuptools wheel bundled by ensurepip so it checks for Windows on Jython - [ 2300 ] Fix bin/jython.py to not consume subcommand args New features - Installer installs pip, setuptools by default, but custom builds can de-select. @@ -146,9 +146,9 @@ - [ 1497 ] ast classes do not have appropiate base classes - [ 1980 ] ast.Eq, ast.Gt, ast.GtE, ast.In, ast.Is, ast.IsNot, ast.Lt, ast.LtE, ast.NotEq and ast.NotIn should be subclasses of ast.cmpop - [ 1981 ] ast.And and ast.Or should be subclasses of ast.boolop + - [ 1591 ] Interactive interpreter stuck on '...' loop New Features - [ 1896215 ] findResource(s) for SyspathJavaLoader - - [ 1591 ] Interactive interpreter stuck on '...' loop - Added socket reboot work, using Netty 4 to fully support socket, select, and ssl API Jython 2.7b2 @@ -174,6 +174,8 @@ New Features - Command line option -E (ignore environment variables) - Environment variable PYTHONIOENCODING, and corresponding registry items + Removed support + - No longer supports Java 6; the minimum version is now Java 7 Jython 2.7b1 Bugs Fixed -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Apr 14 04:31:28 2015 From: jython-checkins at python.org (jim.baker) Date: Tue, 14 Apr 2015 02:31:28 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_beta_3_work_for_NEWS?= Message-ID: <20150414023127.96139.78199@psf.io> https://hg.python.org/jython/rev/8bf6feb2ac2b changeset: 7665:8bf6feb2ac2b user: Jim Baker date: Mon Apr 13 22:31:23 2015 -0400 summary: Add beta 3 work for NEWS files: NEWS | 51 ++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 49 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -142,13 +142,60 @@ Jython 2.7b3 Bugs Fixed - [ 2225 ] Jython+django-jython - no module named site - - [ 2108 ] Cannot set attribute to instances of AST/PythonTree (blocks pyflakes) - [ 1497 ] ast classes do not have appropiate base classes - [ 1980 ] ast.Eq, ast.Gt, ast.GtE, ast.In, ast.Is, ast.IsNot, ast.Lt, ast.LtE, ast.NotEq and ast.NotIn should be subclasses of ast.cmpop - [ 1981 ] ast.And and ast.Or should be subclasses of ast.boolop + - [ 2130 ] Fix max such that any raised ValueError uses the correct error message text + - [ 2180 ] default encoding is not UTF-8 + - [ 2094, 2147, 2174 ] Fix bugs in select.poll, threadpool group closing, and SSL handshaking + - [ 2178 ] Update Apache Commons Compression to 1.8.1 for jar-complete builds + - [ 2176 ] Fix bz2.BZ2File.read so it reads the number of requested bytes + - [ 2028 ] Implement unicode._formatter_parser and unicode._formatter_parser + - [ 1747 ] Synchonize runClosers upon shutdown + - [ 1898 ] Support subprocess termination vs terminate/kill methods + - [ 2096 ] Fix subprocess construction such that handles are inherited if not set + - [ 2123 ] Preserve original name of console encoding + - [ 1728 ] Make PyDictionary#equals() more robust, similar to PyTuple and PyList + - [ 2040 ] Ensure that bz2 decompression has enough data to decode + - [ 2146 ] Fix xrange compliance - [ 1591 ] Interactive interpreter stuck on '...' loop + - [ 1982 ] Modify enumerate such that it can it work with arbitrarily long integers + - [ 2155 ] Enable IP address objects to be used as tuples + - [ 1991 ] Subclassed itertools classes can now chain, and be iterated by Java code + - [ 2062 ] os.write accepts objects having the buffer API + - [ 1949 ] Update collections.deque to 2.7 compliance, and is now threadsafe + - [ 1066 ] Add CJK codecs, as well as other codecs available in Java but not in Jython directly + - [ 2112 ] time.strptime now uses _strptime.py + - [ 2123 ] Use Java codec throughout parser (not sometimes a Python one) + - [ 2078 ] Fix tuple creation for inet6 addresses, and support for bound inet4 socket local address + - [ 2088 ] Fix defaultdict so that derived classes __missing__ methods are not ignored + - [ 2108 ] Cannot set attribute to instances of AST/PythonTree (blocks pyflakes) + - [ 1982 ] builtin function enumerate() should support an optional 'start' argument + - [ 1896215 ] findResource(s) for SyspathJavaLoader + - [ 2140 ] Raise ValueError on args of invalid domain for math.sqrt, math.log + - [ 2119 ] Updated *Derived.java classes as generated by src/templates/gderived.py. + - [ 2087 ] Updated defaultdict to use LoadingCache idiom instead of deprecated ComputingMap + - [ 2133 ] Fix memory leak by doing computed loads only with __getitem__ in defaultdict + - Full bz2 support + - Fix the struct module so that struct.Struct class can be derived from. + + Work on resource cleanup + + - RefReaperThread is now a Runnable to avoid ClassLoader resource leaks + - ShutdownCloser is now a Runnable to avoid subclass audit issues under a SecurityManager + - Remove shadowing of mutable statics in PySystemState, instead make them instance variables + - Fix PySystemState such that it supports AutoCloseable, Closeable + + Potentially backwards breaking changes + + - Fix ThreadState so that Jython runtime can be unloaded, using Object[1] indirection + - Use weakkey/weakvalue when caching ThreadState for a given thread, instead of using ThreadLocal + - recursion_count is now more approximate, because not all entry/exit pairs are tracked + - By default, site module is imported when using PythonInterpreter + Use -Dpython.import.site=false (as of RC1) to not import site at all + New Features - - [ 1896215 ] findResource(s) for SyspathJavaLoader + - Added socket reboot work, using Netty 4 to fully support socket, select, and ssl API Jython 2.7b2 -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Apr 14 05:17:26 2015 From: jython-checkins at python.org (jim.baker) Date: Tue, 14 Apr 2015 03:17:26 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Java=27s_weakly_consistent_?= =?utf-8?q?iteration_of_ConcurrentMap_is_compatible_with_mutation?= Message-ID: <20150414031725.96157.63639@psf.io> https://hg.python.org/jython/rev/5064a5c5b1a3 changeset: 7666:5064a5c5b1a3 user: Jim Baker date: Mon Apr 13 23:17:20 2015 -0400 summary: Java's weakly consistent iteration of ConcurrentMap is compatible with mutation So no need to throw a RuntimeError as seen in CPython when mutating a dict while iterating over it. We could special case for dict-like objects that are subclassing PyDictionary for implementation, however, it seems better to relax in general as we already do for java.lang.Map objects. Fixes http://bugs.jython.org/issue2326 files: Lib/test/test_dict.py | 3 +-- NEWS | 4 ++++ src/org/python/core/PyDictionary.java | 8 -------- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -405,11 +405,10 @@ x.fail = True self.assertRaises(Exc, d.pop, x) + @unittest.skipIf(test_support.is_jython, "Weakly consistent iteration is compatible with mutation") def test_mutatingiteration(self): # changing dict size during iteration d = self._make_dict({}) - if isinstance(d, Map): - raise unittest.SkipTest("java.util.Map objects do not raise exceptions if mutated over iteration") d[1] = 1 with self.assertRaises(RuntimeError): for i in d: diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ For more details, please see https://hg.python.org/jython +Jython 2.7rc3 + Bugs fixed + - [ 2326 ] Java's weakly consistent iteration of ConcurrentMap is compatible with mutation + Jython 2.7rc2 Bugs fixed - [ 2301 ] time.strftime now always returns a bytestring (fixes pip on Japanese locales) diff --git a/src/org/python/core/PyDictionary.java b/src/org/python/core/PyDictionary.java --- a/src/org/python/core/PyDictionary.java +++ b/src/org/python/core/PyDictionary.java @@ -16,13 +16,11 @@ import java.util.concurrent.ConcurrentHashMap; import org.python.expose.ExposedClassMethod; -import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedType; import org.python.expose.MethodType; import org.python.util.Generic; -import org.python.core.BaseDictionaryView; /** @@ -786,9 +784,6 @@ @Override public PyObject __iternext__() { - if (getMap().size() != size) { - throw Py.RuntimeError("dictionary changed size during iteration"); - } if (!iterator.hasNext()) { return null; } @@ -809,9 +804,6 @@ @Override public PyObject __iternext__() { - if (getMap().size() != size) { - throw Py.RuntimeError("dictionary changed size during iteration"); - } if (!iterator.hasNext()) { return null; } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Apr 14 16:19:51 2015 From: jython-checkins at python.org (alex.gronholm) Date: Tue, 14 Apr 2015 14:19:51 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fixed_direct_calls_to_=5F?= =?utf-8?q?=5Fpow=5F=5F=28=29_on_int=2C_long_and_float_with_a_modulo_of_No?= =?utf-8?q?ne?= Message-ID: <20150414141950.111162.16240@psf.io> https://hg.python.org/jython/rev/41d761a58a53 changeset: 7667:41d761a58a53 user: Alex Gr?nholm date: Tue Apr 14 10:18:50 2015 -0400 summary: Fixed direct calls to __pow__() on int, long and float with a modulo of None returning NotImplemented (fixes #2171) files: Lib/test/test_float_jy.py | 5 +++-- Lib/test/test_int_jy.py | 5 +++++ Lib/test/test_long_jy.py | 6 ++++++ src/org/python/core/PyFloat.java | 5 ++++- src/org/python/core/PyInteger.java | 13 +++++-------- src/org/python/core/PyLong.java | 5 ++++- 6 files changed, 27 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_float_jy.py b/Lib/test/test_float_jy.py --- a/Lib/test/test_float_jy.py +++ b/Lib/test/test_float_jy.py @@ -99,8 +99,9 @@ class Foo(object): def __rpow__(self, other): return other ** 2 - # regression in 2.5 alphas - self.assertEqual(4.0 ** Foo(), 16.0) + + self.assertEqual(4.0 ** Foo(), 16.0) # regression in 2.5 alphas + self.assertEqual((4.0).__pow__(2, None), 16.0) def test_faux(self): class F(object): diff --git a/Lib/test/test_int_jy.py b/Lib/test/test_int_jy.py --- a/Lib/test/test_int_jy.py +++ b/Lib/test/test_int_jy.py @@ -11,6 +11,11 @@ def test_type_matches(self): self.assert_(isinstance(1, types.IntType)) + def test_int_pow(self): + self.assertEquals(pow(10, 10, None), 10000000000L) + self.assertEquals(int.__pow__(10, 10, None), 10000000000L) + self.assertEquals((10).__pow__(10, None), 10000000000L) + def test_main(): test_support.run_unittest(IntTestCase) diff --git a/Lib/test/test_long_jy.py b/Lib/test/test_long_jy.py --- a/Lib/test/test_long_jy.py +++ b/Lib/test/test_long_jy.py @@ -26,6 +26,12 @@ # http://bugs.jython.org/issue1828 self.assertTrue(bool(MyLong(42))) + def test_long_pow(self): + self.assertEquals(pow(10L, 10L, None), 10000000000L) + self.assertEquals(long.__pow__(10L, 10L, None), 10000000000L) + self.assertEquals((10L).__pow__(10L, None), 10000000000L) + self.assertEquals((10L).__pow__(10, None), 10000000000L) + def test_main(): test_support.run_unittest(LongTestCase) diff --git a/src/org/python/core/PyFloat.java b/src/org/python/core/PyFloat.java --- a/src/org/python/core/PyFloat.java +++ b/src/org/python/core/PyFloat.java @@ -736,7 +736,10 @@ final PyObject float___pow__(PyObject right, PyObject modulo) { if (!canCoerce(right)) { return null; - } else if (modulo != null) { + } + + modulo = (modulo == Py.None) ? null : modulo; + if (modulo != null) { throw Py.TypeError("pow() 3rd argument not allowed unless all arguments are integers"); } else { return _pow(getValue(), coerce(right)); diff --git a/src/org/python/core/PyInteger.java b/src/org/python/core/PyInteger.java --- a/src/org/python/core/PyInteger.java +++ b/src/org/python/core/PyInteger.java @@ -575,6 +575,7 @@ return null; } + modulo = (modulo == Py.None) ? null : modulo; if (modulo != null && !canCoerce(modulo)) { return null; } @@ -582,21 +583,17 @@ return _pow(getValue(), coerce(right), modulo, this, right); } - public PyObject __rpow__(PyObject left, PyObject modulo) { + @Override + public PyObject __rpow__(PyObject left) { if (!canCoerce(left)) { return null; } - - if (modulo != null && !canCoerce(modulo)) { - return null; - } - - return _pow(coerce(left), getValue(), modulo, left, this); + return _pow(coerce(left), getValue(), null, left, this); } @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.int___rpow___doc) final PyObject int___rpow__(PyObject left) { - return __rpow__(left, null); + return __rpow__(left); } private static PyObject _pow(int value, int pow, PyObject modulo,// diff --git a/src/org/python/core/PyLong.java b/src/org/python/core/PyLong.java --- a/src/org/python/core/PyLong.java +++ b/src/org/python/core/PyLong.java @@ -660,9 +660,11 @@ return null; } - if (modulo != null && !canCoerce(right)) { + modulo = (modulo == Py.None) ? null : modulo; + if (modulo != null && !canCoerce(modulo)) { return null; } + return _pow(getValue(), coerce(right), modulo, this, right); } @@ -676,6 +678,7 @@ if (!canCoerce(left)) { return null; } + return _pow(coerce(left), getValue(), null, left, this); } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Apr 14 21:35:11 2015 From: jython-checkins at python.org (stefan.richthofer) Date: Tue, 14 Apr 2015 19:35:11 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fixed_some_Traverseproc-rel?= =?utf-8?q?ated_warnings_in_=5Fjason_and_jffi=2E?= Message-ID: <20150414193511.21295.16315@psf.io> https://hg.python.org/jython/rev/ecc46d56964a changeset: 7668:ecc46d56964a user: Stefan Richthofer date: Tue Apr 14 21:35:05 2015 +0200 summary: Fixed some Traverseproc-related warnings in _jason and jffi. files: src/org/python/core/Traverseproc.java | 586 ++++++----- src/org/python/modules/_json/_json.java | 3 + src/org/python/modules/jffi/CType.java | 2 + 3 files changed, 300 insertions(+), 291 deletions(-) diff --git a/src/org/python/core/Traverseproc.java b/src/org/python/core/Traverseproc.java --- a/src/org/python/core/Traverseproc.java +++ b/src/org/python/core/Traverseproc.java @@ -267,372 +267,376 @@ *
* org.python.core:
* __builtin__:
- * BuiltinFunctions - no refs, untraversable
- * ImportFunction - no refs, untraversable
- * SortedFunction - no refs, untraversable
- * AllFunction - no refs, untraversable
- * AnyFunction - no refs, untraversable
- * FormatFunction - no refs, untraversable
- * PrintFunction - no refs, untraversable
- * MaxFunction - no refs, untraversable
- * MinFunction - no refs, untraversable
- * RoundFunction - no refs, untraversable
- * CompileFunction - no refs, untraversable
- * OpenFunction - no refs, untraversable
- * NextFunction - no refs, untraversable
- * BinFunction - no refs, untraversable
- * AstList - Traverseproc
- * BaseBytes - no refs, untraversable
- * BaseDictionaryView - Traverseproc
- * BaseSet - Traverseproc
- * ClasspathPyImporter - no refs, untraversable
- * ContextGuard: - no PyObject
- * ContextCode - Traverseproc
- * GeneratorContextManager - Traverseproc
- * exceptions - no refs, untraversable
- * BoundStaticJavaMethod - no refs, untraversable
- * JavaImporter - no refs, untraversable
+ * BuiltinFunctions - no refs, untraversable
+ * ImportFunction - no refs, untraversable
+ * SortedFunction - no refs, untraversable
+ * AllFunction - no refs, untraversable
+ * AnyFunction - no refs, untraversable
+ * FormatFunction - no refs, untraversable
+ * PrintFunction - no refs, untraversable
+ * MaxFunction - no refs, untraversable
+ * MinFunction - no refs, untraversable
+ * RoundFunction - no refs, untraversable
+ * CompileFunction - no refs, untraversable
+ * OpenFunction - no refs, untraversable
+ * NextFunction - no refs, untraversable
+ * BinFunction - no refs, untraversable
+ * AstList - Traverseproc
+ * BaseBytes - no refs, untraversable
+ * BaseDictionaryView - Traverseproc
+ * BaseSet - Traverseproc
+ * ClasspathPyImporter - no refs, untraversable
+ * ContextGuard: - no PyObject
+ * ContextCode - Traverseproc
+ * GeneratorContextManager - Traverseproc
+ * exceptions - no refs, untraversable
+ * BoundStaticJavaMethod - no refs, untraversable
+ * JavaImporter - no refs, untraversable
* JavaProxyList:
- * ListMethod - no refs, untraversable (extends PyBuiltinMethodNarrow)
- * ListMulProxyClass - no refs, untraversable
+ * ListMethod - no refs, untraversable (extends PyBuiltinMethodNarrow)
+ * ListMulProxyClass - no refs, untraversable
* JavaProxyMap:
- * MapMethod - no refs, untraversable (extends PyBuiltinMethodNarrow)
- * MapClassMethod - no refs, untraversable (extends PyBuiltinClassMethodNarrow)
+ * MapMethod - no refs, untraversable (extends PyBuiltinMethodNarrow)
+ * MapClassMethod - no refs, untraversable (extends PyBuiltinClassMethodNarrow)
* JavaProxySet:
- * SetMethod - no refs, untraversable (extends PyBuiltinMethodNarrow)
- * SetMethodVarargs - no refs, untraversable (extends SetMethod)
- * CopyMethod - no refs, untraversable
- * IsSubsetMethod - no refs, untraversable
- * IsSupersetMethod - no refs, untraversable
+ * SetMethod - no refs, untraversable (extends PyBuiltinMethodNarrow)
+ * SetMethodVarargs - no refs, untraversable (extends SetMethod)
+ * CopyMethod - no refs, untraversable
+ * IsSubsetMethod - no refs, untraversable
+ * IsSupersetMethod - no refs, untraversable
* Py:
- * JavaCode - Traverseproc
- * JavaFunc - no refs, untraversable
- * Py2kBuffer - no refs, untraversable
- * PyArray - Traverseproc, traverses via reflection
- * PyBaseCode - no refs, abstract class
- * PyBaseException - Traverseproc
- * PyBaseString - no refs, abstract class
- * PyBeanEvent - no refs, untraversable
- * PyBeanEventProperty - no refs, untraversable
- * PyBeanProperty - no refs, untraversable
- * PyBoolean - no refs, untraversable
- * PyBuffer - no PyObject
- * PyBuiltinCallable - no refs, untraversable
- * PyBuiltinClassMethodNarrow - no refs, abstract class
- * PyBuiltinFunction - no refs, untraversable
- * PyBuiltinFunctionNarrow - no refs, untraversable
- * PyBuiltinFunctionSet - no refs, untraversable
- * PyBuiltinMethod - Traverseproc
- * PyBuiltinMethodNarrow - no refs, abstract class
- * PyBuiltinMethodSet - Traverseproc
- * PyByteArray - no refs, untraversable
- * PyBytecode - Traverseproc
- * PyStackWhy - no refs, untraversable
- * PyStackException - Traverseproc
- * PyTryBlock - no refs, untraversable
- * PyCallIter - Traverseproc (with call to super)
- * PyCell - Traverseproc
- * PyClass - Traverseproc
- * PyClassMethod - Traverseproc
- * PyClassMethodDescr - no refs, untraversable
- * PyCode - no refs, abstract class
- * PyComplex - no refs, untraversable
- * PyCompoundCallable - Traverseproc
- * PyDataDescr - no refs, untraversable
- * PyDescriptor - Traverseproc
- * PyDictionary - Traverseproc
- * ValuesIter - no refs, extends PyIterator
- * ItemsIter - no refs, extends PyIterator
- * PyMapKeyValSet - no PyObject
- * PyMapEntrySet - no PyObject
- * PyDictProxy - Traverseproc
- * PyEllipsis - no refs, untraversable
- * PyEnumerate - Traverseproc
- * PyFastSequenceIter - Traverseproc
- * PyFile - Traverseproc
- * PyFileReader - no refs, untraversable
- * PyFileWriter - no refs, untraversable
- * PyFloat - no refs, untraversable
- * PyFrame - Traverseproc
- * PyFunction - Traverseproc
- * PyGenerator - Traverseproc (with call to super)
- * PyIndentationError - no PyObject
- * PyInstance - Traverseproc
- * PyInteger - no refs, untraversable
- * PyIterator - Traverseproc
- * PyJavaPackage - Traverseproc
- * PyJavaType - Traverseproc (with call to super)
- * EnumerationIter - no refs, extends PyIterator
- * ComparableMethod - no refs, abstract class
- * PyList - Traverseproc
- * PyLong - no refs, untraversable
- * PyMemoryView - Traverseproc
- * PyMethod - Traverseproc
- * PyMethodDescr - Traverseproc
- * PyModule - Traverseproc
- * PyNewWrapper - Traverseproc
- * PyNone - no refs, untraversable
- * PyNotImplemented - no refs, untraversable
- * PyObject - no refs (objtype is special case)
- * PyIdentityTuple - Traverseproc
- * PyOverridableNew - no refs, abstract class
- * PyProperty - Traverseproc
- * PyReflectedConstructor - no refs, untraversable
- * PyReflectedField - no refs, untraversable
- * PyReflectedFunction - Traverseproc
- * PyReversedIterator - Traverseproc (with call to super)
- * PySequence - no refs, abstract class (default Traverseproc implementation)
- * PySequenceIter - Traverseproc (with call to super)
- * PySequenceList - no refs, abstract class
- * PySingleton - no refs, untraversable
- * PySlice - Traverseproc
- * PySlot - no refs, untraversable
- * PyStaticMethod - Traverseproc
- * PyString - no refs, untraversable (assuming baseBuffer is not a PyObject)
- * PyStringMap - Traverseproc
- * StringMapIter - no refs, extends PyIterator, abstract class
- * ItemsIter - no refs, extends StringMapIter
- * KeysIter - no refs, extends StringMapIter
- * ValuesIter - no refs, extends StringMapIter
- * PySuper - Traverseproc
- * PySyntaxError - no PyObject
- * PySystemState - Traverseproc
- * PySystemStateFunctions - no refs, untraversable
- * PyAttributeDeleted - no refs, untraversable
- * FloatInfo - Traverseproc
- * LongInfo - Traverseproc
- * PyTableCode - no refs, untraversable
- * PyTraceback - Traverseproc
- * PyTuple - Traverseproc
- * PyType - Traverseproc
- * PyUnicode - no refs, untraversable
- * PyXRange - no refs, untraversable
- * PyXRangeIter - no refs, extends PyIterator
- * SyspathArchive - no refs, untraversable
+ * JavaCode - Traverseproc
+ * JavaFunc - no refs, untraversable
+ * Py2kBuffer - no refs, untraversable
+ * PyArray - Traverseproc, traverses via reflection
+ * PyBaseCode - no refs, abstract class
+ * PyBaseException - Traverseproc
+ * PyBaseString - no refs, abstract class
+ * PyBeanEvent - no refs, untraversable
+ * PyBeanEventProperty - no refs, untraversable
+ * PyBeanProperty - no refs, untraversable
+ * PyBoolean - no refs, untraversable
+ * PyBuffer - no PyObject
+ * PyBuiltinCallable - no refs, untraversable
+ * PyBuiltinClassMethodNarrow - no refs, abstract class
+ * PyBuiltinFunction - no refs, untraversable
+ * PyBuiltinFunctionNarrow - no refs, untraversable
+ * PyBuiltinFunctionSet - no refs, untraversable
+ * PyBuiltinMethod - Traverseproc
+ * PyBuiltinMethodNarrow - no refs, abstract class
+ * PyBuiltinMethodSet - Traverseproc
+ * PyByteArray - no refs, untraversable
+ * PyBytecode - Traverseproc
+ * PyStackWhy - no refs, untraversable
+ * PyStackException - Traverseproc
+ * PyTryBlock - no refs, untraversable
+ * PyCallIter - Traverseproc (with call to super)
+ * PyCell - Traverseproc
+ * PyClass - Traverseproc
+ * PyClassMethod - Traverseproc
+ * PyClassMethodDescr - no refs, untraversable
+ * PyCode - no refs, abstract class
+ * PyComplex - no refs, untraversable
+ * PyCompoundCallable - Traverseproc
+ * PyDataDescr - no refs, untraversable
+ * PyDescriptor - Traverseproc
+ * PyDictionary - Traverseproc
+ * ValuesIter - no refs, extends PyIterator
+ * ItemsIter - no refs, extends PyIterator
+ * PyMapKeyValSet - no PyObject
+ * PyMapEntrySet - no PyObject
+ * PyDictProxy - Traverseproc
+ * PyEllipsis - no refs, untraversable
+ * PyEnumerate - Traverseproc
+ * PyFastSequenceIter - Traverseproc
+ * PyFile - Traverseproc
+ * PyFileReader - no refs, untraversable
+ * PyFileWriter - no refs, untraversable
+ * PyFloat - no refs, untraversable
+ * PyFrame - Traverseproc
+ * PyFunction - Traverseproc
+ * PyGenerator - Traverseproc (with call to super)
+ * PyIndentationError - no PyObject
+ * PyInstance - Traverseproc
+ * PyInteger - no refs, untraversable
+ * PyIterator - Traverseproc
+ * PyJavaPackage - Traverseproc
+ * PyJavaType - Traverseproc (with call to super)
+ * EnumerationIter - no refs, extends PyIterator
+ * ComparableMethod - no refs, abstract class
+ * PyList - Traverseproc
+ * PyLong - no refs, untraversable
+ * PyMemoryView - Traverseproc
+ * PyMethod - Traverseproc
+ * PyMethodDescr - Traverseproc
+ * PyModule - Traverseproc
+ * PyNewWrapper - Traverseproc
+ * PyNone - no refs, untraversable
+ * PyNotImplemented - no refs, untraversable
+ * PyObject - no refs (objtype is special case)
+ * PyIdentityTuple - Traverseproc
+ * PyOverridableNew - no refs, abstract class
+ * PyProperty - Traverseproc
+ * PyReflectedConstructor - no refs, untraversable
+ * PyReflectedField - no refs, untraversable
+ * PyReflectedFunction - Traverseproc
+ * PyReversedIterator - Traverseproc (with call to super)
+ * PySequence - no refs, abstract class (default Traverseproc implementation)
+ * PySequenceIter - Traverseproc (with call to super)
+ * PySequenceList - no refs, abstract class
+ * PySingleton - no refs, untraversable
+ * PySlice - Traverseproc
+ * PySlot - no refs, untraversable
+ * PyStaticMethod - Traverseproc
+ * PyString - no refs, untraversable (assuming baseBuffer is not a PyObject)
+ * PyStringMap - Traverseproc
+ * StringMapIter - no refs, extends PyIterator, abstract class
+ * ItemsIter - no refs, extends StringMapIter
+ * KeysIter - no refs, extends StringMapIter
+ * ValuesIter - no refs, extends StringMapIter
+ * PySuper - Traverseproc
+ * PySyntaxError - no PyObject
+ * PySystemState - Traverseproc
+ * PySystemStateFunctions - no refs, untraversable
+ * PyAttributeDeleted - no refs, untraversable
+ * FloatInfo - Traverseproc
+ * LongInfo - Traverseproc
+ * PyTableCode - no refs, untraversable
+ * PyTraceback - Traverseproc
+ * PyTuple - Traverseproc
+ * PyType - Traverseproc
+ * PyUnicode - no refs, untraversable
+ * PyXRange - no refs, untraversable
+ * PyXRangeIter - no refs, extends PyIterator
+ * SyspathArchive - no refs, untraversable
*
* org.python.core.stringlib:
- * FieldNameIterator - no refs, traverses via reflection
- * MarkupIterator - no refs, untraversable
+ * FieldNameIterator - no refs, traverses via reflection
+ * MarkupIterator - no refs, untraversable
*
* org.python.core.util:
- * importer - no refs, abstract class
+ * importer - no refs, abstract class
*
* org.python.jsr223:
- * PyScriptEngineScope - no refs, untraversable
- * ScopeIterator - Traverseproc
+ * PyScriptEngineScope - no refs, untraversable
+ * ScopeIterator - Traverseproc
*
* org.python.modules:
* _codecs:
- * EncodingMap - no refs, untraversable
+ * EncodingMap - no refs, untraversable
* _hashlib:
- * Hash - no refs, untraversable
+ * Hash - no refs, untraversable
* _marshal:
- * Marshaller - Traverseproc
- * Unmarshaller - Traverseproc
+ * Marshaller - Traverseproc
+ * Unmarshaller - Traverseproc
* cStringIO:
- * StringIO - no refs, extends PyIterator
+ * StringIO - no refs, extends PyIterator
* operator:
- * OperatorFunctions - no refs, untraversable
- * operator - no refs, untraversable
- * PyAttrGetter - Traverseproc
- * PyItemGetter - Traverseproc
- * PyMethodCaller - Traverseproc
- * PyStruct - no refs, untraversable
+ * OperatorFunctions - no refs, untraversable
+ * operator - no refs, untraversable
+ * PyAttrGetter - Traverseproc
+ * PyItemGetter - Traverseproc
+ * PyMethodCaller - Traverseproc
+ * PyStruct - no refs, untraversable
* synchronize:
- * SynchronizedCallable - Traverseproc
+ * SynchronizedCallable - Traverseproc
*
* org.python.modules._collections:
- * PyDefaultDict - Traverseproc (with call to super)
- * PyDeque - Traverseproc (assuming, Nodes can't build cycles)
- * PyDequeIter - Traverseproc (with call to super)
+ * PyDefaultDict - Traverseproc (with call to super)
+ * PyDeque - Traverseproc (assuming, Nodes can't build cycles)
+ * PyDequeIter - Traverseproc (with call to super)
*
* org.python.modules._csv:
- * PyDialect - no refs, untraversable
- * PyReader - Traverseproc (with call to super)
- * PyWriter - Traverseproc
+ * PyDialect - no refs, untraversable
+ * PyReader - Traverseproc (with call to super)
+ * PyWriter - Traverseproc
*
* org.python.modules._functools:
- * PyPartial - Traverseproc
+ * PyPartial - Traverseproc
*
* org.python.modules._io:
- * PyFileIO - no refs, untraversable (there is a final PyString + * PyFileIO - no refs, untraversable (there is a final PyString * "mode" that is guaranteed to be a PyString and no subclass; as such it needs not be * traversed since it cannot have refs itself)
- * PyIOBase - Traverseproc
- * PyRawIOBase - no refs, extends PyIOBase
+ * PyIOBase - Traverseproc
+ * PyRawIOBase - no refs, extends PyIOBase
*
* org.python.modules._json:
- * Encoder - Traverseproc
- * Scanner - Traverseproc
+ * Encoder - Traverseproc
+ * Scanner - Traverseproc
+ * _json: + * ScanstringFunction - no refs, untraversable
+ * EncodeBasestringAsciiFunction - no refs, untraversable
*
* org.python.modules._jythonlib:
- * dict_builder - Traverseproc
+ * dict_builder - Traverseproc
*
* org.python.modules._threading:
- * Condition - Traverseproc
- * Lock - no refs, untraversable
+ * Condition - Traverseproc
+ * Lock - no refs, untraversable
*
* org.python.modules._weakref:
- * AbstractReference - Traverseproc
- * ReferenceType - no refs, extends AbstractReference
- * ProxyType - no refs, extends AbstractReference
- * CallableProxyType - no refs, extends ProxyType
+ * AbstractReference - Traverseproc
+ * ReferenceType - no refs, extends AbstractReference
+ * ProxyType - no refs, extends AbstractReference
+ * CallableProxyType - no refs, extends ProxyType
*
* org.python.modules.bz2:
- * PyBZ2Compressor - no refs, untraversable
- * PyBZ2Decompressor - Traverseproc
- * PyBZ2File - no refs, untraversable
- * BZ2FileIterator - no refs, extends PyIterator
+ * PyBZ2Compressor - no refs, untraversable
+ * PyBZ2Decompressor - Traverseproc
+ * PyBZ2File - no refs, untraversable
+ * BZ2FileIterator - no refs, extends PyIterator
*
* org.python.modules.itertools:
- * chain - Traverseproc (with call to super)
- * combinations - Traverseproc (with call to super)
- * combinationsWithReplacement - Traverseproc (with call to super)
- * compress - Traverseproc (with call to super)
- * count - Traverseproc (with call to super)
- * cycle - Traverseproc (with call to super)
- * dropwhile - Traverseproc (with call to super)
- * groupby - Traverseproc (with call to super)
- * ifilter - Traverseproc (with call to super)
- * ifiIterfalse - Traverseproc (with call to super)
- * imap - Traverseproc (with call to super)
- * islice - Traverseproc (with call to super)
+ * chain - Traverseproc (with call to super)
+ * combinations - Traverseproc (with call to super)
+ * combinationsWithReplacement - Traverseproc (with call to super)
+ * compress - Traverseproc (with call to super)
+ * count - Traverseproc (with call to super)
+ * cycle - Traverseproc (with call to super)
+ * dropwhile - Traverseproc (with call to super)
+ * groupby - Traverseproc (with call to super)
+ * ifilter - Traverseproc (with call to super)
+ * ifiIterfalse - Traverseproc (with call to super)
+ * imap - Traverseproc (with call to super)
+ * islice - Traverseproc (with call to super)
* itertools:
- * ItertoolsIterator - no refs, extends PyIterator, abstract class
- * FilterIterator - Traverseproc, extends ItertoolsIterator
- * WhileIterator - Traverseproc, extends ItertoolsIterator - * izip - Traverseproc (with call to super)
- * izipLongest - Traverseproc (with call to super)
- * permutations - Traverseproc (with call to super)
- * product - Traverseproc (with call to super)
- * PyTeeIterator - Traverseproc (with call to super)
- * repeat - Traverseproc (with call to super)
- * starmap - Traverseproc (with call to super)
- * takewhile - Traverseproc (with call to super)
+ * ItertoolsIterator - no refs, extends PyIterator, abstract class
+ * FilterIterator - Traverseproc, extends ItertoolsIterator
+ * WhileIterator - Traverseproc, extends ItertoolsIterator + * izip - Traverseproc (with call to super)
+ * izipLongest - Traverseproc (with call to super)
+ * permutations - Traverseproc (with call to super)
+ * product - Traverseproc (with call to super)
+ * PyTeeIterator - Traverseproc (with call to super)
+ * repeat - Traverseproc (with call to super)
+ * starmap - Traverseproc (with call to super)
+ * takewhile - Traverseproc (with call to super)
*
* org.python.modules.jffi:
- * ArrayCData - Traverseproc (with call to super; maybe check referenceMemory field whether it extends PyObject)
- * ArrayIter - no refs, extends PyIterator
- * BasePointer - no refs, abstract class
- * ByReference - no refs, untraversable (maybe check memory field whether it extends PyObject)
- * CData - Traverseproc (maybe check referenceMemory field whether it extends PyObject)
- * CType - no refs, abstract class
- * DynamicLibrary - no refs, untraversable
+ * ArrayCData - Traverseproc (with call to super; maybe check referenceMemory field whether it extends PyObject)
+ * ArrayIter - no refs, extends PyIterator
+ * BasePointer - no refs, abstract class
+ * ByReference - no refs, untraversable (maybe check memory field whether it extends PyObject)
+ * CData - Traverseproc (maybe check referenceMemory field whether it extends PyObject)
+ * CType - no refs, abstract class
+ * Builtin - no refs, untraversable
+ * DynamicLibrary - no refs, untraversable
* StructLayout:
- * Field - Traverseproc
+ * Field - Traverseproc
*
* org.python.modules.posix:
* PosixModule:
- * FstatFunction - no refs, untraversable
- * LstatFunction - no refs, untraversable
- * StatFunction - no refs, untraversable
- * WindowsStatFunction - no refs, untraversable
- * PyStatResult - Traverseproc (with call to super)
+ * FstatFunction - no refs, untraversable
+ * LstatFunction - no refs, untraversable
+ * StatFunction - no refs, untraversable
+ * WindowsStatFunction - no refs, untraversable
+ * PyStatResult - Traverseproc (with call to super)
*
* org.python.modules.random:
- * PyRandom - no refs, untraversable
+ * PyRandom - no refs, untraversable
*
* org.python.modules.sre:
- * MatchObject - Traverseproc
- * PatternObject - Traverseproc
- * ScannerObject - Traverseproc
+ * MatchObject - Traverseproc
+ * PatternObject - Traverseproc
+ * ScannerObject - Traverseproc
*
* org.python.modules.thread:
- * PyLocal - Traverseproc
- * PyLock - no refs, untraversable
+ * PyLocal - Traverseproc
+ * PyLock - no refs, untraversable
*
* org.python.modules.time:
- * PyTimeTuple - Traverseproc (with call to super)
+ * PyTimeTuple - Traverseproc (with call to super)
* Time:
- * TimeFunctions - no refs, untraversable
+ * TimeFunctions - no refs, untraversable
*
* org.python.modules.zipimport:
- * zipimporter - Traverseproc
+ * zipimporter - Traverseproc
*
* org.python.util:
- * InteractiveInterpreter - no PyObject
+ * InteractiveInterpreter - no PyObject
*
* com.ziclix.python.sql:
- * DBApiType - no refs, untraversable
- * PyConnection - Traverseproc
- * ConnectionFunc - no refs, extends PyBuiltinMethodSet
- * PyCursor - Traverseproc
- * CursorFunc - no refs, extends PyBuiltinMethodSet
- * PyExtendedCursor - no refs, extends PyCursor
- * ExtendedCursorFunc - no refs, extends PyBuiltinMethodSet
- * PyStatement - Traverseproc (because Object sql could be a PyObject or Traverseproc)
- * zxJDBC - no refs, untraversable
- * zxJDBCFunc - no refs, untraversable
+ * DBApiType - no refs, untraversable
+ * PyConnection - Traverseproc
+ * ConnectionFunc - no refs, extends PyBuiltinMethodSet
+ * PyCursor - Traverseproc
+ * CursorFunc - no refs, extends PyBuiltinMethodSet
+ * PyExtendedCursor - no refs, extends PyCursor
+ * ExtendedCursorFunc - no refs, extends PyBuiltinMethodSet
+ * PyStatement - Traverseproc (because Object sql could be a PyObject or Traverseproc)
+ * zxJDBC - no refs, untraversable
+ * zxJDBCFunc - no refs, untraversable
*
* com.ziclix.python.sql.connect:
- * Connect - no refs, untraversable
- * Connectx - no refs, untraversable
- * Lookup - no refs, untraversable
+ * Connect - no refs, untraversable
+ * Connectx - no refs, untraversable
+ * Lookup - no refs, untraversable
*
* com.ziclix.python.sql.util:
- * BCP - Traverseproc
- * BCPFunc - no refs, extends PyBuiltinMethodSet
+ * BCP - Traverseproc
+ * BCPFunc - no refs, extends PyBuiltinMethodSet
*
* org.python.antlr:
* AnalyzingParser:
- * AnalyzerTreeAdaptor - no PyObject
- * AST - no refs, untraversable
- * PythonErrorNode - no refs, extends PythonTree
- * PythonTree - Traverseproc
+ * AnalyzerTreeAdaptor - no PyObject
+ * AST - no refs, untraversable
+ * PythonErrorNode - no refs, extends PythonTree
+ * PythonTree - Traverseproc
*
* org.python.antlr.ast:
- * alias - no refs, extends PythonTree
- * arguments - Traverseproc (with call to super)
- * comprehension - Traverseproc (with call to super)
- * keyword - Traverseproc (with call to super)
+ * alias - no refs, extends PythonTree
+ * arguments - Traverseproc (with call to super)
+ * comprehension - Traverseproc (with call to super)
+ * keyword - Traverseproc (with call to super)
*
* org.python.antlr.base:
- * boolop - no refs, extends PythonTree
- * cmpop - no refs, extends PythonTree
- * excepthandler - no refs, extends PythonTree
- * expr_context - no refs, extends PythonTree
- * expr - no refs, extends PythonTree
- * mod - no refs, extends PythonTree
- * operator - no refs, extends PythonTree
- * slice - no refs, extends PythonTree
- * stmt - no refs, extends PythonTree
- * unaryop - no refs, extends PythonTree
+ * boolop - no refs, extends PythonTree
+ * cmpop - no refs, extends PythonTree
+ * excepthandler - no refs, extends PythonTree
+ * expr_context - no refs, extends PythonTree
+ * expr - no refs, extends PythonTree
+ * mod - no refs, extends PythonTree
+ * operator - no refs, extends PythonTree
+ * slice - no refs, extends PythonTree
+ * stmt - no refs, extends PythonTree
+ * unaryop - no refs, extends PythonTree
*
* org.python.antlr.op:
- * Add - no refs, extends PythonTree
- * And - no refs, extends PythonTree
- * AugLoad - no refs, extends PythonTree
- * AugStore - no refs, extends PythonTree
- * BitAnd - no refs, extends PythonTree
- * BitOr - no refs, extends PythonTree
- * BitXor - no refs, extends PythonTree
- * Del - no refs, extends PythonTree
- * Div - no refs, extends PythonTree
- * Eq - no refs, extends PythonTree
- * FloorDiv - no refs, extends PythonTree
- * Gt - no refs, extends PythonTree
- * GtE - no refs, extends PythonTree
- * In - no refs, extends PythonTree
- * Invert - no refs, extends PythonTree
- * Is - no refs, extends PythonTree
- * IsNot - no refs, extends PythonTree
- * Load - no refs, extends PythonTree
- * LShift - no refs, extends PythonTree
- * Lt - no refs, extends PythonTree
- * LtE - no refs, extends PythonTree
- * Mod - no refs, extends PythonTree
- * Mult - no refs, extends PythonTree
- * Not - no refs, extends PythonTree
- * NotEq - no refs, extends PythonTree
- * NotIn - no refs, extends PythonTree
- * Or - no refs, extends PythonTree
- * Param - no refs, extends PythonTree
- * Pow - no refs, extends PythonTree
- * RShift - no refs, extends PythonTree
- * Store - no refs, extends PythonTree
- * Sub - no refs, extends PythonTree
- * UAdd - no refs, extends PythonTree
- * USub - no refs, extends PythonTree
+ * Add - no refs, extends PythonTree
+ * And - no refs, extends PythonTree
+ * AugLoad - no refs, extends PythonTree
+ * AugStore - no refs, extends PythonTree
+ * BitAnd - no refs, extends PythonTree
+ * BitOr - no refs, extends PythonTree
+ * BitXor - no refs, extends PythonTree
+ * Del - no refs, extends PythonTree
+ * Div - no refs, extends PythonTree
+ * Eq - no refs, extends PythonTree
+ * FloorDiv - no refs, extends PythonTree
+ * Gt - no refs, extends PythonTree
+ * GtE - no refs, extends PythonTree
+ * In - no refs, extends PythonTree
+ * Invert - no refs, extends PythonTree
+ * Is - no refs, extends PythonTree
+ * IsNot - no refs, extends PythonTree
+ * Load - no refs, extends PythonTree
+ * LShift - no refs, extends PythonTree
+ * Lt - no refs, extends PythonTree
+ * LtE - no refs, extends PythonTree
+ * Mod - no refs, extends PythonTree
+ * Mult - no refs, extends PythonTree
+ * Not - no refs, extends PythonTree
+ * NotEq - no refs, extends PythonTree
+ * NotIn - no refs, extends PythonTree
+ * Or - no refs, extends PythonTree
+ * Param - no refs, extends PythonTree
+ * Pow - no refs, extends PythonTree
+ * RShift - no refs, extends PythonTree
+ * Store - no refs, extends PythonTree
+ * Sub - no refs, extends PythonTree
+ * UAdd - no refs, extends PythonTree
+ * USub - no refs, extends PythonTree
*

* @see org.python.core.Untraversable * @see org.python.core.Visitproc diff --git a/src/org/python/modules/_json/_json.java b/src/org/python/modules/_json/_json.java --- a/src/org/python/modules/_json/_json.java +++ b/src/org/python/modules/_json/_json.java @@ -11,6 +11,7 @@ import org.python.core.PyTuple; import org.python.core.PyUnicode; import org.python.core.codecs; +import org.python.core.Untraversable; import org.python.expose.ExposedGet; import java.util.Iterator; @@ -78,6 +79,7 @@ } } + @Untraversable static class ScanstringFunction extends PyBuiltinFunctionNarrow { ScanstringFunction() { super("scanstring", 2, 4, "scanstring"); @@ -305,6 +307,7 @@ return new PyTuple(Py.EmptyUnicode.join(chunks), Py.newInteger(end)); } + @Untraversable static class EncodeBasestringAsciiFunction extends PyBuiltinFunctionNarrow { EncodeBasestringAsciiFunction() { super("encode_basestring_ascii", 1, 1, "encode_basestring_ascii"); diff --git a/src/org/python/modules/jffi/CType.java b/src/org/python/modules/jffi/CType.java --- a/src/org/python/modules/jffi/CType.java +++ b/src/org/python/modules/jffi/CType.java @@ -7,6 +7,7 @@ import org.python.core.PyNewWrapper; import org.python.core.PyObject; import org.python.core.PyType; +import org.python.core.Untraversable; import org.python.expose.ExposeAsSuperclass; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; @@ -81,6 +82,7 @@ return t; } + @Untraversable static final class Builtin extends CType implements ExposeAsSuperclass { public Builtin(NativeType type) { super(type, MemoryOp.getMemoryOp(type)); -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Apr 15 17:09:14 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 15 Apr 2015 15:09:14 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_index_computation_for_S?= =?utf-8?q?tringBuilder_after_seek_back_in_cStringIO?= Message-ID: <20150415150913.65840.30998@psf.io> https://hg.python.org/jython/rev/ce136d0b598f changeset: 7669:ce136d0b598f user: Jim Baker date: Wed Apr 15 11:09:09 2015 -0400 summary: Fix index computation for StringBuilder after seek back in cStringIO Also updates test_StringIO to latest, then reapply Jython-specific FIXME for subsequent work. Fixes http://bugs.jython.org/issue2324 files: Lib/test/test_StringIO.py | 48 ++++++++++++++- Lib/test/test_StringIO_jy.py | 11 +++ src/org/python/modules/cStringIO.java | 4 +- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_StringIO.py b/Lib/test/test_StringIO.py --- a/Lib/test/test_StringIO.py +++ b/Lib/test/test_StringIO.py @@ -5,6 +5,7 @@ import cStringIO import types import array +import sys from test import test_support @@ -27,6 +28,8 @@ eq = self.assertEqual self.assertRaises(TypeError, self._fp.seek) eq(self._fp.read(10), self._line[:10]) + eq(self._fp.read(0), '') + eq(self._fp.readline(0), '') eq(self._fp.readline(), self._line[10:] + '\n') eq(len(self._fp.readlines(60)), 2) self._fp.seek(0) @@ -105,6 +108,45 @@ self._fp.close() self.assertRaises(ValueError, self._fp.getvalue) + @test_support.bigmemtest(test_support._2G + 2**26, memuse=2.001) + def test_reads_from_large_stream(self, size): + linesize = 2**26 # 64 MiB + lines = ['x' * (linesize - 1) + '\n'] * (size // linesize) + \ + ['y' * (size % linesize)] + f = self.MODULE.StringIO(''.join(lines)) + for i, expected in enumerate(lines): + line = f.read(len(expected)) + self.assertEqual(len(line), len(expected)) + self.assertEqual(line, expected) + self.assertEqual(f.read(), '') + f.seek(0) + for i, expected in enumerate(lines): + line = f.readline() + self.assertEqual(len(line), len(expected)) + self.assertEqual(line, expected) + self.assertEqual(f.readline(), '') + f.seek(0) + self.assertEqual(f.readlines(), lines) + self.assertEqual(f.readlines(), []) + f.seek(0) + self.assertEqual(f.readlines(size), lines) + self.assertEqual(f.readlines(), []) + + # In worst case cStringIO requires 2 + 1 + 1/2 + 1/2**2 + ... = 4 + # bytes per input character. + @test_support.bigmemtest(test_support._2G, memuse=4) + def test_writes_to_large_stream(self, size): + s = 'x' * 2**26 # 64 MiB + f = self.MODULE.StringIO() + n = size + while n > len(s): + f.write(s) + n -= len(s) + s = None + f.write('x' * n) + self.assertEqual(len(f.getvalue()), size) + + class TestStringIO(TestGenericStringIO): MODULE = StringIO @@ -153,8 +195,10 @@ self.assertEqual(s, 'abcde') self.assertEqual(type(s), str) - # This cStringIO/StringIO difference seems CPython specific to me... - if not test_support.is_jython: + if not test_support.is_jython: # FIXME re-enable in a future release + # On Jython, this should raise UnicodeEncodeError, however, we + # have to do more work on preventing inadvertent mixing of Unicode + # into String-supporting objects like StringBuilder self.assertRaises(UnicodeEncodeError, self.MODULE.StringIO, u'\xf4') diff --git a/Lib/test/test_StringIO_jy.py b/Lib/test/test_StringIO_jy.py --- a/Lib/test/test_StringIO_jy.py +++ b/Lib/test/test_StringIO_jy.py @@ -28,6 +28,17 @@ f.write("uvwxyz") self.assertEqual(f.getvalue(), 'abcdef\x00\x00\x00\x00uvwxyz') + def test_write_seek_back_then_write(self): + # http://bugs.jython.org/issue2324 + s = "abcdef" + for i in xrange(len(s)): + f = cStringIO.StringIO() + f.write(s) + f.seek(i) + f.write("x" * 47) + self.assertEqual(f.getvalue(), s[:i] + ("x" * 47)) + + class TestGetValueAfterClose(unittest.TestCase): # This test, or something like it, should be really be pushed upstream diff --git a/src/org/python/modules/cStringIO.java b/src/org/python/modules/cStringIO.java --- a/src/org/python/modules/cStringIO.java +++ b/src/org/python/modules/cStringIO.java @@ -372,8 +372,8 @@ if (spos < slen) { if (newpos > slen) { - buf.replace(spos, slen - spos, s); - buf.append(s.substring(slen)); + buf.replace(spos, slen, s); + buf.append(s.substring(slen - spos)); slen = newpos; } else { buf.replace(spos, spos + s.length(), s); -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Apr 15 21:02:30 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 15 Apr 2015 19:02:30 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Enable_piping_input_into_Jy?= =?utf-8?q?thon_without_getting_extraneous_prompt_output?= Message-ID: <20150415190230.21067.83203@psf.io> https://hg.python.org/jython/rev/cc3e787c0a7c changeset: 7671:cc3e787c0a7c user: Jason Madden date: Wed Apr 15 15:01:34 2015 -0400 summary: Enable piping input into Jython without getting extraneous prompt output Previously Jython would display prompt (sys.ps1, sys.ps2) on stdout Fixes http://bugs.jython.org/issue2325 files: ACKNOWLEDGMENTS | 1 + src/org/python/core/Py.java | 4 ++++ src/org/python/util/InteractiveConsole.java | 4 +++- src/org/python/util/jython.java | 9 +++++++-- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -152,6 +152,7 @@ Paolo Dina Eliya Sadan Stefan Richthofer + Jason Madden Local Variables: mode: indented-text 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 @@ -1533,10 +1533,14 @@ * @return true if (we think) we are in an interactive environment */ 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; } + if (isTTY != null && isTTY.equals("false")) { + return false; + } // Decide if System.in is interactive try { POSIX posix = POSIXFactory.getPOSIX(); diff --git a/src/org/python/util/InteractiveConsole.java b/src/org/python/util/InteractiveConsole.java --- a/src/org/python/util/InteractiveConsole.java +++ b/src/org/python/util/InteractiveConsole.java @@ -146,7 +146,9 @@ if (!exc.match(Py.EOFError)) { throw exc; } - write("\n"); + if (banner != null) { + write("\n"); + } break; } catch (Throwable t) { // catch jline.console.UserInterruptException, rethrow as a KeyboardInterrupt 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 @@ -408,11 +408,16 @@ if (opts.fixInteractive || (opts.filename == null && opts.command == null)) { // Go interactive with the console: the parser needs to know the encoding. String encoding = Py.getConsole().getEncoding(); - // Run the interpreter interactively try { interp.cflags.encoding = encoding; - interp.interact(null, null); + if (!opts.interactive) { + // Don't print prompts. http://bugs.jython.org/issue2325 + interp._interact(null, null); + } + else { + interp.interact(null, null); + } } catch (Throwable t) { Py.printException(t); } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Apr 15 21:02:31 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 15 Apr 2015 19:02:31 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Test_for_fixing_http=3A//bu?= =?utf-8?q?gs=2Ejython=2Eorg/issue2325?= Message-ID: <20150415190230.108180.32674@psf.io> https://hg.python.org/jython/rev/d20cd699c7bf changeset: 7670:d20cd699c7bf user: Jim Baker date: Wed Apr 15 15:00:12 2015 -0400 summary: Test for fixing http://bugs.jython.org/issue2325 files: Lib/test/test_sys_jy.py | 16 ++++++++++++++-- 1 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_sys_jy.py b/Lib/test/test_sys_jy.py --- a/Lib/test/test_sys_jy.py +++ b/Lib/test/test_sys_jy.py @@ -242,6 +242,8 @@ self.assertEqual(check(0xa2, "cp850"), "\xbd") class SysArgvTest(unittest.TestCase): + + @unittest.skipIf(os._name == "nt", "FIXME should work on Windows") def test_unicode_argv(self): """Unicode roundtrips successfully through sys.argv arguments""" zhongwen = u'\u4e2d\u6587' @@ -259,14 +261,24 @@ # captured by test_doctest, however, it would be ideal to add # pexpect tests (using CPython). - def test_prompts_not_defined_if_not_interactive(self): + def test_prompts_not_defined_if_noninteractive(self): p = subprocess.Popen( [sys.executable, '-c', 'import sys;' \ 'print hasattr(sys, "ps1");' \ 'print hasattr(sys, "ps2");'], stdout=subprocess.PIPE) - self.assertEqual(''.join(p.stdout.read().split()), 'FalseFalse') + self.assertEqual(p.stdout.read(), + os.linesep.join(['False', 'False', ''])) + + def test_prompts_not_printed_if_noninteractive(self): + p = subprocess.Popen( + [sys.executable], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + self.assertEqual(p.communicate('print 47'), + ('47' + os.linesep, None)) + def test_main(): test_support.run_unittest( -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Apr 16 00:34:23 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 15 Apr 2015 22:34:23 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_stack_overflow_due_to_h?= =?utf-8?q?ow_proxies_for_Java_classes_resolve_super_method_in?= Message-ID: <20150415223423.108174.3629@psf.io> https://hg.python.org/jython/rev/95d09ba14aa7 changeset: 7672:95d09ba14aa7 user: Jim Baker date: Wed Apr 15 18:34:17 2015 -0400 summary: Fix stack overflow due to how proxies for Java classes resolve super method in Java For a Python class extending a Java class and/or interfaces, the MRO contains a proxy (PyJavaType) so that Java can call back into Python. However, because the proxy is in the MRO, it participates in super lookup, and this was breaking because during super calls, the referred Python code would refer to this proxy, which would refer back to Python, generating a stack overflow. So break out of this infinite loop by ignoring this entry for super purposes. The use of the super__ prefix parallels the workaround seen in PyReflectedFunction. Fixes http://bugs.jython.org/issue1540 files: Lib/test/test_java_subclasses.py | 31 ++++++++++++++++++- src/org/python/core/PyType.java | 20 +++++++++++- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_java_subclasses.py b/Lib/test/test_java_subclasses.py --- a/Lib/test/test_java_subclasses.py +++ b/Lib/test/test_java_subclasses.py @@ -7,7 +7,7 @@ from java.lang import (Boolean, Class, ClassLoader, Comparable,Integer, Object, Runnable, String, Thread, ThreadGroup) -from java.util import AbstractList, Date, Hashtable, HashSet, Vector +from java.util import AbstractList, ArrayList, Date, Hashtable, HashSet, Vector from java.util.concurrent import Callable, Executors from java.awt import Color, Component, Dimension, Rectangle @@ -433,6 +433,32 @@ C().call() +class SuperIsSuperTest(unittest.TestCase): + # Testing how the vision described in Raymond Hettinger's blog + # https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ + # - super in Python is really next-method - can be merged with + # Java's super, which is a conventional super that dispatches up + # the class inheritance hierarchy + + def test_super_dispatches_through_proxy(self): + # Verify fix for http://bugs.jython.org/issue1540 + + class MyList(ArrayList): + + def get(self, index): + return super(MyList, self).get(index) + + def toString(self): + return "MyList<<<" + super(MyList, self).toString() + ">>>" + + my_list = MyList([0, 1, 2, 3, 4, 5]) + self.assertEqual(my_list.get(5), 5) + self.assertEqual( + str(my_list), + "MyList<<<[0, 1, 2, 3, 4, 5]>>>") + self.assertEqual(my_list.size(), 6) + + def test_main(): test_support.run_unittest( InterfaceTest, @@ -442,7 +468,8 @@ AbstractOnSyspathTest, ContextClassloaderTest, MetaClassTest, - AbstractMethodTest) + AbstractMethodTest, + SuperIsSuperTest) if __name__ == '__main__': diff --git a/src/org/python/core/PyType.java b/src/org/python/core/PyType.java --- a/src/org/python/core/PyType.java +++ b/src/org/python/core/PyType.java @@ -1285,6 +1285,7 @@ } public PyObject super_lookup(PyType ref, String name) { + String lookupName; // the method name to lookup PyObject[] mro = this.mro; if (mro == null) { return null; @@ -1296,11 +1297,26 @@ } i++; for (; i < mro.length; i++) { + if (mro[i] instanceof PyJavaType) { + // The MRO contains this proxy for classes extending a Java class and/or + // interfaces, but the proxy points back to this starting Python class. + // So break out of this infinite loop by ignoring this entry for super purposes. + // The use of super__ parallels the workaround seen in PyReflectedFunction + // Fixes http://bugs.jython.org/issue1540 + if(!name.startsWith("super__")) { + lookupName = "super__" + name; + } else { + lookupName = name; + } + } else { + lookupName = name; + } PyObject dict = mro[i].fastGetDict(); if (dict != null) { - PyObject obj = dict.__finditem__(name); - if (obj != null) + PyObject obj = dict.__finditem__(lookupName); + if (obj != null) { return obj; + } } } return null; -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Apr 17 06:56:33 2015 From: jython-checkins at python.org (jim.baker) Date: Fri, 17 Apr 2015 04:56:33 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Additional_testing_of_what_?= =?utf-8?q?methods_are_called_when_subclassed?= Message-ID: <20150417045633.15809.81205@psf.io> https://hg.python.org/jython/rev/1c420dee2a19 changeset: 7673:1c420dee2a19 user: Jim Baker date: Thu Apr 16 22:56:28 2015 -0600 summary: Additional testing of what methods are called when subclassed Some simple test combinations of constructors along with static vs non static factories for verifying the right method in a class is called. Although written to understand issues around http://bugs.jython.org/issue2104, these tests do not result any failures. files: Lib/test/test_java_subclasses.py | 101 ++++++++++++- tests/java/javatests/Inheritance.java | 17 ++ tests/java/javatests/InheritanceA.java | 26 +++ tests/java/javatests/InheritanceB.java | 33 ++++ tests/java/javatests/InheritanceC.java | 33 ++++ 5 files changed, 208 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_java_subclasses.py b/Lib/test/test_java_subclasses.py --- a/Lib/test/test_java_subclasses.py +++ b/Lib/test/test_java_subclasses.py @@ -6,7 +6,7 @@ from test import test_support from java.lang import (Boolean, Class, ClassLoader, Comparable,Integer, Object, Runnable, String, - Thread, ThreadGroup) + Thread, ThreadGroup, UnsupportedOperationException) from java.util import AbstractList, ArrayList, Date, Hashtable, HashSet, Vector from java.util.concurrent import Callable, Executors @@ -15,6 +15,8 @@ from javax.swing.table import AbstractTableModel from org.python.tests import BeanInterface, Callbacker, Coercions, OwnMethodCaller +from javatests import InheritanceA, InheritanceB, InheritanceC, InheritanceD + class InterfaceTest(unittest.TestCase): def test_java_calling_python_interface_implementation(self): @@ -459,6 +461,100 @@ self.assertEqual(my_list.size(), 6) +class HierarchyTest(unittest.TestCase): + + # Attempt to expand upon the inheritance hierarchy described as + # being a bug in http://bugs.jython.org/issue2104, but this test + # currently only confirms existing behavior. + + def assertB(self, b2, level, cls): + self.assertIsInstance(b2, cls) + self.assertEqual(b2.whoAmI(), level) + self.assertEqual(b2.staticWhoAmI(), level) + self.assertEqual(b2.root(), "A") + self.assertEqual(b2.staticRoot(), "A") + self.assertEqual(b2.everyOther(), "A") + self.assertEqual(b2.notInAbstract(), "B") + + def test_b(self): + b = InheritanceB() + self.assertB(b.replicateMe(), "B", InheritanceB) + self.assertB(b.build(), "B", InheritanceB) + with self.assertRaises(UnsupportedOperationException): + b.replicateParent() + with self.assertRaises(UnsupportedOperationException): + b.buildParent() + + def assertC(self, c2, level, cls): + self.assertIsInstance(c2, cls) + self.assertEqual(c2.whoAmI(), level) + self.assertEqual(c2.staticWhoAmI(), level) + self.assertEqual(c2.root(), "A") + self.assertEqual(c2.staticRoot(), "A") + self.assertEqual(c2.everyOther(), + "C" if isinstance(c2, InheritanceC) else "A") + self.assertEqual(c2.notInAbstract(), "B") + + def test_c(self): + c = InheritanceC() + self.assertC(c.replicateMe(), "C", InheritanceC) + self.assertC(c.replicateParent(), "B", InheritanceB) + self.assertC(c.build(), "C", InheritanceC) + self.assertC(c.buildParent(), "B", InheritanceB) + + def assertD(self, d2, level, cls): + self.assertIsInstance(d2, cls) + self.assertEqual(d2.whoAmI(), level) + self.assertEqual(d2.staticWhoAmI(), level) + self.assertEqual(d2.root(), "A") + self.assertEqual(d2.staticRoot(), "A") + self.assertEqual(d2.everyOther(), "C") + self.assertEqual(d2.notInAbstract(), "B") + + def test_d(self): + d = InheritanceD() + self.assertD(d.replicateMe(), "D", InheritanceD) + self.assertD(d.replicateParent(), "C", InheritanceC) + self.assertD(d.build(), "D", InheritanceD) + self.assertD(d.buildParent(), "C", InheritanceC) + + def assertE(self, e2, level, cls, tested): + self.assertIsInstance(e2, cls) + self.assertEqual(e2.whoAmI(), level) + self.assertEqual(e2.staticWhoAmI(), level) + self.assertEqual(e2.root(), "A") + self.assertEqual(e2.staticRoot(), "A") + self.assertEqual(e2.everyOther(), + "E" if isinstance(e2, tested) else "C") + self.assertEqual(e2.notInAbstract(), "B") + + def test_e(self): + class E(InheritanceD): + def replicateMe(self): + return E() + def replicateParent(self): + return InheritanceD() + @staticmethod + def build(): + return E() + @staticmethod + def buildParent(): + return InheritanceD() + def whoAmI(self): + return "E" + @staticmethod + def staticWhoAmI(): + return "E" + def everyOther(self): + return "E" + + e = E() + self.assertE(e.replicateMe(), "E", E, E) + self.assertE(e.replicateParent(), "D", InheritanceD, E) + self.assertE(e.build(), "E", E, E) + self.assertE(e.buildParent(), "D", InheritanceD, E) + + def test_main(): test_support.run_unittest( InterfaceTest, @@ -469,7 +565,8 @@ ContextClassloaderTest, MetaClassTest, AbstractMethodTest, - SuperIsSuperTest) + SuperIsSuperTest, + HierarchyTest) if __name__ == '__main__': diff --git a/tests/java/javatests/Inheritance.java b/tests/java/javatests/Inheritance.java new file mode 100644 --- /dev/null +++ b/tests/java/javatests/Inheritance.java @@ -0,0 +1,17 @@ +// Inheritance*.java are used to test for http://bugs.jython.org/issue2104 +// +// However this inheritance hierarchy as constructed is still not +// sufficient to reproduce the issue raised by Jorgo Bakker and Jaime +// Saiz, so need to figure out a patch that does reproduce the problem +// before we can commit even what appears to be a trivial bug fix. + +package javatests; + +public interface Inheritance { + Inheritance replicateMe(); + Inheritance replicateParent(); + String whoAmI(); + String root(); + String notInAbstract(); + String everyOther(); +} diff --git a/tests/java/javatests/InheritanceA.java b/tests/java/javatests/InheritanceA.java new file mode 100644 --- /dev/null +++ b/tests/java/javatests/InheritanceA.java @@ -0,0 +1,26 @@ +package javatests; + +public abstract class InheritanceA implements Inheritance { + + public String whoAmI() { + return "A"; + } + + public String root() { + return "A"; + } + + public String everyOther() { + return "A"; + } + + public static String staticWhoAmI() { + return "A"; + } + + public static String staticRoot() { + return "A"; + } + +} + diff --git a/tests/java/javatests/InheritanceB.java b/tests/java/javatests/InheritanceB.java new file mode 100644 --- /dev/null +++ b/tests/java/javatests/InheritanceB.java @@ -0,0 +1,33 @@ +package javatests; + +public class InheritanceB extends InheritanceA { + + public Inheritance replicateMe() { + return new InheritanceB(); + } + + public Inheritance replicateParent() { + throw new UnsupportedOperationException("parent is abstract"); + } + + public static Inheritance build() { + return new InheritanceB(); + } + + public static Inheritance buildParent() { + throw new UnsupportedOperationException("parent is abstract"); + } + + public String whoAmI() { + return "B"; + } + + public String notInAbstract() { + return "B"; + } + + public static String staticWhoAmI() { + return "B"; + } + +} diff --git a/tests/java/javatests/InheritanceC.java b/tests/java/javatests/InheritanceC.java new file mode 100644 --- /dev/null +++ b/tests/java/javatests/InheritanceC.java @@ -0,0 +1,33 @@ +package javatests; + +public class InheritanceC extends InheritanceB { + + public Inheritance replicateMe() { + return new InheritanceC(); + } + + public Inheritance replicateParent() { + return new InheritanceB(); + } + + public static Inheritance build() { + return new InheritanceC(); + } + + public static Inheritance buildParent() { + return new InheritanceB(); + } + + public String whoAmI() { + return "C"; + } + + public String everyOther() { + return "C"; + } + + public static String staticWhoAmI() { + return "C"; + } + +} -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Apr 19 17:15:13 2015 From: jython-checkins at python.org (jim.baker) Date: Sun, 19 Apr 2015 15:15:13 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fixes_pickling_issues_in_ob?= =?utf-8?b?amVjdC5fX3JlZHVjZV9fIGFuZCBjUGlja2xlLntsb2FkLCBsb2Fkc30=?= Message-ID: <20150419151513.27902.71732@psf.io> https://hg.python.org/jython/rev/74811340dfe3 changeset: 7675:74811340dfe3 user: Jason Madden date: Sun Apr 19 09:15:05 2015 -0600 summary: Fixes pickling issues in object.__reduce__ and cPickle.{load, loads} Uses a common helper method to prevent infinite recursion when a Python object implements __reduce__ and sometimes calls object.__reduce__. Trying to do it all in __reduce__ex__ caused this problem. Now throws correct Python errors if attempting to load pickled data that has been corrupted in certain ways, including truncation and bad ops/stack. Completes fix for http://bugs.jython.org/issue2323 files: src/org/python/core/PyObject.java | 29 ++++++++++++---- src/org/python/modules/cPickle.java | 17 +++++++-- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/org/python/core/PyObject.java b/src/org/python/core/PyObject.java --- a/src/org/python/core/PyObject.java +++ b/src/org/python/core/PyObject.java @@ -125,7 +125,7 @@ throw Py.TypeError(String.format("Can't instantiate abstract class %s with abstract " + "methods %s", subtype.fastGetName(), methods)); } - + return new_.for_type == subtype ? new PyObject() : new PyObjectDerived(subtype); } @@ -3950,6 +3950,25 @@ } /** + * A common helper method, use to prevent infinite recursion + * when a Python object implements __reduce__ and sometimes calls + * object.__reduce__. Trying to do it all in __reduce__ex__ caused + # this problem. See http://bugs.jython.org/issue2323. + */ + private PyObject commonReduce(int proto) { + PyObject res; + + if (proto >= 2) { + res = reduce_2(); + } else { + PyObject copyreg = __builtin__.__import__("copy_reg", null, null, Py.EmptyTuple); + PyObject copyreg_reduce = copyreg.__findattr__("_reduce_ex"); + res = copyreg_reduce.__call__(this, new PyInteger(proto)); + } + return res; + } + + /** * Used for pickling. Default implementation calls object___reduce__. * * @return a tuple of (class, tuple) @@ -3960,7 +3979,7 @@ @ExposedMethod(doc = BuiltinDocs.object___reduce___doc) final PyObject object___reduce__() { - return object___reduce_ex__(0); + return commonReduce(0); } /** Used for pickling. If the subclass specifies __reduce__, it will @@ -3987,12 +4006,8 @@ if (clsreduce != objreduce) { res = this.__reduce__(); - } else if (arg >= 2) { - res = reduce_2(); } else { - PyObject copyreg = __builtin__.__import__("copy_reg", null, null, Py.EmptyTuple); - PyObject copyreg_reduce = copyreg.__findattr__("_reduce_ex"); - res = copyreg_reduce.__call__(this, new PyInteger(arg)); + res = commonReduce(arg); } return res; } diff --git a/src/org/python/modules/cPickle.java b/src/org/python/modules/cPickle.java --- a/src/org/python/modules/cPickle.java +++ b/src/org/python/modules/cPickle.java @@ -610,7 +610,6 @@ return dumps(object, 0); } - /** * Shorthand function which pickles and returns the string representation. * @param object a data object which should be pickled. @@ -623,7 +622,6 @@ return file.getvalue(); } - /** * Shorthand function which unpickles a object from the file and returns * the new object. @@ -633,7 +631,16 @@ * @return a new object. */ public static Object load(PyObject file) { - return new Unpickler(file).load(); + try { + return new Unpickler(file).load(); + } + catch (ArrayIndexOutOfBoundsException e) { + // invalid data, bad stack + throw Py.IndexError(e.getMessage()); + } catch (StringIndexOutOfBoundsException e) { + // short data + throw Py.EOFError(e.getMessage()); + } } @@ -646,13 +653,13 @@ */ public static Object loads(PyObject str) { cStringIO.StringIO file = cStringIO.StringIO(str.toString()); - return new Unpickler(file).load(); + return load(file); } // Factory for creating PyIOFile representation. - + /** * The Pickler object * @see cPickle#Pickler(PyObject) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Apr 19 17:15:13 2015 From: jython-checkins at python.org (jim.baker) Date: Sun, 19 Apr 2015 15:15:13 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_pickle_tests_to_late?= =?utf-8?q?st_and_repatch_for_Jython?= Message-ID: <20150419151513.21355.81632@psf.io> https://hg.python.org/jython/rev/72a33dee5f95 changeset: 7674:72a33dee5f95 user: Jim Baker date: Sun Apr 19 09:05:18 2015 -0600 summary: Update pickle tests to latest and repatch for Jython All pickle tests should eventually pass in a future release of Jython. Most notably the tests that are currently failing are for cPickle: exact float representations, dynamic classes, and list pickling. Part of the fix for http://bugs.jython.org/issue2323 files: Lib/test/pickletester.py | 69 +++++- Lib/test/test_cpickle.py | 51 ++++- Lib/test/test_xpickle.py | 288 +++++++++++++++++++++++++++ 3 files changed, 391 insertions(+), 17 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -6,7 +6,8 @@ import pickletools import copy_reg -from test.test_support import TestFailed, have_unicode, TESTFN, is_jython +from test.test_support import (TestFailed, have_unicode, TESTFN, _2G, _1M, + precisionbigmemtest, is_jython) # Tests that try a number of pickle protocols should have a # for proto in protocols: @@ -124,6 +125,21 @@ class use_metaclass(object): __metaclass__ = metaclass +class pickling_metaclass(type): + def __eq__(self, other): + return (type(self) == type(other) and + self.reduce_args == other.reduce_args) + + def __reduce__(self): + return (create_dynamic_class, self.reduce_args) + + __hash__ = None + +def create_dynamic_class(name, bases): + result = pickling_metaclass(name, bases, dict()) + result.reduce_args = (name, bases) + return result + # DATA0 .. DATA2 are the pickles we expect under the various protocols, for # the object returned by create_data(). @@ -487,10 +503,10 @@ i = C() i.attr = i for proto in protocols: - s = self.dumps(i, 2) + s = self.dumps(i, proto) x = self.loads(s) self.assertEqual(dir(x), dir(i)) - self.assertTrue(x.attr is x) + self.assertIs(x.attr, x) def test_recursive_multi(self): l = [] @@ -574,8 +590,6 @@ self.assertEqual(n, got) # Try a monster. This is quadratic-time in protos 0 & 1, so don't # bother with those. - if is_jython:#see http://jython.org/bugs/1754225 - return nbase = long("deadbeeffeedface", 16) nbase += nbase << 1000000 for n in nbase, -nbase: @@ -583,7 +597,6 @@ got = self.loads(p) self.assertEqual(n, got) - @unittest.skip("FIXME: not working.") def test_float(self): test_values = [0.0, 4.94e-324, 1e-310, 7e-308, 6.626e-34, 0.1, 0.5, 3.14, 263.44582062374053, 6.022e23, 1e30] @@ -612,6 +625,14 @@ b = self.loads(s) self.assertEqual(a.__class__, b.__class__) + def test_dynamic_class(self): + a = create_dynamic_class("my_dynamic_class", (object,)) + copy_reg.pickle(pickling_metaclass, pickling_metaclass.__reduce__) + for proto in protocols: + s = self.dumps(a, proto) + b = self.loads(s) + self.assertEqual(a, b) + def test_structseq(self): import time import os @@ -906,7 +927,6 @@ y = self.loads(s) self.assertEqual(y._proto, proto) - @unittest.skip("FIXME: max recursion") def test_reduce_calls_base(self): for proto in protocols: x = REX_five() @@ -953,7 +973,7 @@ "Failed protocol %d: %r != %r" % (proto, obj, loaded)) - @unittest.skip("FIXME: not working.") + @unittest.skipIf(is_jython, "FIXME: not working on Jython") def test_attribute_name_interning(self): # Test that attribute names of pickled objects are interned when # unpickling. @@ -1082,7 +1102,6 @@ # Of course this needs to be changed when HIGHEST_PROTOCOL changes. self.assertEqual(self.module.HIGHEST_PROTOCOL, 2) - @unittest.skip("FIXME: not working.") def test_callapi(self): f = cStringIO.StringIO() # With and without keyword arguments @@ -1093,12 +1112,11 @@ self.module.Pickler(f, -1) self.module.Pickler(f, protocol=-1) - @unittest.skip("FIXME: not working.") def test_incomplete_input(self): s = StringIO.StringIO("X''.") self.assertRaises(EOFError, self.module.load, s) - @unittest.skip("FIXME: not working.") + @unittest.skipIf(is_jython, "FIXME: not working on Jython, do similar patch for http://bugs.python.org/issue7128") def test_restricted(self): # issue7128: cPickle failed in restricted mode builtins = {self.module.__name__: self.module, @@ -1108,7 +1126,6 @@ exec teststr in {'__builtins__': builtins}, d d['f']() - @unittest.skip("FIXME: not working.") def test_bad_input(self): # Test issue4298 s = '\x58\0\0\0\x54' @@ -1266,3 +1283,31 @@ f.write(pickled2) f.seek(0) self.assertEqual(unpickler.load(), data2) + +class BigmemPickleTests(unittest.TestCase): + + # Memory requirements: 1 byte per character for input strings, 1 byte + # for pickled data, 1 byte for unpickled strings, 1 byte for internal + # buffer and 1 byte of free space for resizing of internal buffer. + + @precisionbigmemtest(size=_2G + 100*_1M, memuse=5) + def test_huge_strlist(self, size): + chunksize = 2**20 + data = [] + while size > chunksize: + data.append('x' * chunksize) + size -= chunksize + chunksize += 1 + data.append('y' * size) + + try: + for proto in protocols: + try: + pickled = self.dumps(data, proto) + res = self.loads(pickled) + self.assertEqual(res, data) + finally: + res = None + pickled = None + finally: + data = None diff --git a/Lib/test/test_cpickle.py b/Lib/test/test_cpickle.py --- a/Lib/test/test_cpickle.py +++ b/Lib/test/test_cpickle.py @@ -4,7 +4,27 @@ from test.pickletester import AbstractPickleTests, AbstractPickleModuleTests from test import test_support -class cPickleTests(AbstractPickleTests, AbstractPickleModuleTests): + +class ApproxFloat(unittest.TestCase): + # FIXME for Jython: remove this class - and its use from bases in + # subsequent test classes - when we can guarantee that floats that + # are pickled by cPickle are exact in the same way they are on + # CPython + + def test_float(self): + from test.pickletester import protocols + + test_values = [0.0, 4.94e-324, 1e-310, 7e-308, 6.626e-34, 0.1, 0.5, + 3.14, 263.44582062374053, 6.022e23, 1e30] + test_values = test_values + [-x for x in test_values] + for proto in protocols: + for value in test_values: + pickle = self.dumps(value, proto) + got = self.loads(pickle) + self.assertAlmostEqual(value, got) + + +class cPickleTests(ApproxFloat, AbstractPickleTests, AbstractPickleModuleTests): def setUp(self): self.dumps = cPickle.dumps @@ -13,7 +33,16 @@ error = cPickle.BadPickleGet module = cPickle -class cPicklePicklerTests(AbstractPickleTests): + @unittest.skipIf(test_support.is_jython, "FIXME: not working on Jython") + def test_callapi(self): + pass + + @unittest.skipIf(test_support.is_jython, "FIXME: not working on Jython") + def test_dynamic_class(self): + pass + + +class cPicklePicklerTests(ApproxFloat, AbstractPickleTests): def dumps(self, arg, proto=0): f = StringIO() @@ -29,6 +58,11 @@ error = cPickle.BadPickleGet + @unittest.skipIf(test_support.is_jython, "FIXME: not working on Jython") + def test_dynamic_class(self): + pass + + class cPickleListPicklerTests(AbstractPickleTests): def dumps(self, arg, proto=0): @@ -43,7 +77,7 @@ error = cPickle.BadPickleGet -class cPickleFastPicklerTests(AbstractPickleTests): +class cPickleFastPicklerTests(ApproxFloat, AbstractPickleTests): def dumps(self, arg, proto=0): f = StringIO() @@ -91,6 +125,11 @@ b = self.loads(self.dumps(a)) self.assertEqual(a, b) + @unittest.skipIf(test_support.is_jython, "FIXME: not working on Jython") + def test_dynamic_class(self): + pass + + def test_main(): tests = [ cPickleTests, @@ -99,13 +138,15 @@ cPickleFastPicklerTests ] if test_support.is_jython: - # XXX: Jython doesn't support list based picklers + # FIXME Jython currently doesn't support list based picklers tests.remove(cPickleListPicklerTests) - # XXX: These don't cause exceptions on Jython + # FIXME these cause NullPointerException on Jython del cPickleFastPicklerTests.test_recursive_list del cPickleFastPicklerTests.test_recursive_inst del cPickleFastPicklerTests.test_recursive_dict del cPickleFastPicklerTests.test_recursive_multi + + test_support.run_unittest(*tests) if __name__ == "__main__": diff --git a/Lib/test/test_xpickle.py b/Lib/test/test_xpickle.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_xpickle.py @@ -0,0 +1,288 @@ +# test_pickle dumps and loads pickles via pickle.py. +# test_cpickle does the same, but via the cPickle module. +# This test covers the other two cases, making pickles with one module and +# loading them via the other. It also tests backwards compatibility with +# previous version of Python by bouncing pickled objects through Python 2.4 +# and Python 2.5 running this file. + +import cPickle +import os +import os.path +import pickle +import subprocess +import sys +import types +import unittest + +from test import test_support + +# Most distro-supplied Pythons don't include the tests +# or test support files, and some don't include a way to get these back even if +# you're will to install extra packages (like Ubuntu). Doing things like this +# "provides" a pickletester module for older versions of Python that may be +# installed without it. Note that one other design for this involves messing +# with sys.path, which is less precise. +mod_path = os.path.abspath(os.path.join(os.path.dirname(__file__), + "pickletester.py")) +pickletester = types.ModuleType("test.pickletester") +exec compile(open(mod_path).read(), mod_path, 'exec') in pickletester.__dict__ +AbstractPickleTests = pickletester.AbstractPickleTests +if pickletester.__name__ in sys.modules: + raise RuntimeError("Did not expect to find test.pickletester loaded") +sys.modules[pickletester.__name__] = pickletester + + +class ApproxFloat(unittest.TestCase): + # FIXME for Jython: remove this class - and its use from bases in + # subsequent test classes - when we can guarantee that floats that + # are pickled by cPickle are exact in the same way they are on + # CPython + + def test_float(self): + from test.pickletester import protocols + + test_values = [0.0, 4.94e-324, 1e-310, 7e-308, 6.626e-34, 0.1, 0.5, + 3.14, 263.44582062374053, 6.022e23, 1e30] + test_values = test_values + [-x for x in test_values] + for proto in protocols: + for value in test_values: + pickle = self.dumps(value, proto) + got = self.loads(pickle) + self.assertAlmostEqual(value, got) + + +class DumpCPickle_LoadPickle(ApproxFloat, AbstractPickleTests): + + error = KeyError + + def dumps(self, arg, proto=0, fast=False): + # Ignore fast + return cPickle.dumps(arg, proto) + + def loads(self, buf): + # Ignore fast + return pickle.loads(buf) + + @unittest.skipIf(test_support.is_jython, "FIXME: not working on Jython") + def test_dynamic_class(self): + pass + + +class DumpPickle_LoadCPickle(AbstractPickleTests): + + error = cPickle.BadPickleGet + + def dumps(self, arg, proto=0, fast=False): + # Ignore fast + return pickle.dumps(arg, proto) + + def loads(self, buf): + # Ignore fast + return cPickle.loads(buf) + +def have_python_version(name): + """Check whether the given name is a valid Python binary and has + test.test_support. + + This respects your PATH. + + Args: + name: short string name of a Python binary such as "python2.4". + + Returns: + True if the name is valid, False otherwise. + """ + return os.system(name + " -c 'import test.test_support'") == 0 + + +class AbstractCompatTests(AbstractPickleTests): + + module = None + python = None + error = None + + def setUp(self): + self.assertTrue(self.python) + self.assertTrue(self.module) + self.assertTrue(self.error) + + def send_to_worker(self, python, obj, proto): + """Bounce a pickled object through another version of Python. + + This will pickle the object, send it to a child process where it will be + unpickled, then repickled and sent back to the parent process. + + Args: + python: the name of the Python binary to start. + obj: object to pickle. + proto: pickle protocol number to use. + + Returns: + The pickled data received from the child process. + """ + # Prevent the subprocess from picking up invalid .pyc files. + target = __file__ + if target[-1] in ("c", "o"): + target = target[:-1] + + data = self.module.dumps((proto, obj), proto) + worker = subprocess.Popen([python, target, "worker"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = worker.communicate(data) + if worker.returncode != 0: + raise RuntimeError(stderr) + return stdout + + def dumps(self, arg, proto=0, fast=False): + return self.send_to_worker(self.python, arg, proto) + + def loads(self, input): + return self.module.loads(input) + + # These tests are disabled because they require some special setup + # on the worker that's hard to keep in sync. + def test_global_ext1(self): + pass + + def test_global_ext2(self): + pass + + def test_global_ext4(self): + pass + + # This is a cut-down version of pickletester's test_float. Backwards + # compatibility for the values in for_bin_protos was explicitly broken in + # r68903 to fix a bug. + def test_float(self): + for_bin_protos = [4.94e-324, 1e-310] + neg_for_bin_protos = [-x for x in for_bin_protos] + test_values = [0.0, 7e-308, 6.626e-34, 0.1, 0.5, + 3.14, 263.44582062374053, 6.022e23, 1e30] + test_proto0_values = test_values + [-x for x in test_values] + test_values = test_proto0_values + for_bin_protos + neg_for_bin_protos + + for value in test_proto0_values: + pickle = self.dumps(value, 0) + got = self.loads(pickle) + self.assertEqual(value, got) + + for proto in pickletester.protocols[1:]: + for value in test_values: + pickle = self.dumps(value, proto) + got = self.loads(pickle) + self.assertEqual(value, got) + + # Backwards compatibility was explicitly broken in r67934 to fix a bug. + def test_unicode_high_plane(self): + pass + + # This tests a fix that's in 2.7 only + def test_dynamic_class(self): + pass + + if test_support.have_unicode: + # This is a cut-down version of pickletester's test_unicode. Backwards + # compatibility was explicitly broken in r67934 to fix a bug. + def test_unicode(self): + endcases = [u'', u'<\\u>', u'<\\\u1234>', u'<\n>', u'<\\>'] + for proto in pickletester.protocols: + for u in endcases: + p = self.dumps(u, proto) + u2 = self.loads(p) + self.assertEqual(u2, u) + + +def run_compat_test(python_name): + return (test_support.is_resource_enabled("xpickle") and + have_python_version(python_name)) + + +# Test backwards compatibility with Python 2.4. +if not run_compat_test("python2.4"): + class CPicklePython24Compat(unittest.TestCase): + pass +else: + class CPicklePython24Compat(AbstractCompatTests): + + module = cPickle + python = "python2.4" + error = cPickle.BadPickleGet + + # Disable these tests for Python 2.4. Making them pass would require + # nontrivially monkeypatching the pickletester module in the worker. + def test_reduce_calls_base(self): + pass + + def test_reduce_ex_calls_base(self): + pass + +class PicklePython24Compat(CPicklePython24Compat): + + module = pickle + error = KeyError + + +# Test backwards compatibility with Python 2.5. +if not run_compat_test("python2.5"): + class CPicklePython25Compat(unittest.TestCase): + pass +else: + class CPicklePython25Compat(AbstractCompatTests): + + module = cPickle + python = "python2.5" + error = cPickle.BadPickleGet + +class PicklePython25Compat(CPicklePython25Compat): + + module = pickle + error = KeyError + + +# Test backwards compatibility with Python 2.6. +if not run_compat_test("python2.6"): + class CPicklePython26Compat(unittest.TestCase): + pass +else: + class CPicklePython26Compat(AbstractCompatTests): + + module = cPickle + python = "python2.6" + error = cPickle.BadPickleGet + +class PicklePython26Compat(CPicklePython26Compat): + + module = pickle + error = KeyError + + +def worker_main(in_stream, out_stream): + message = cPickle.load(in_stream) + protocol, obj = message + cPickle.dump(obj, out_stream, protocol) + + +def test_main(): + if not test_support.is_resource_enabled("xpickle"): + print >>sys.stderr, "test_xpickle -- skipping backwards compat tests." + print >>sys.stderr, "Use 'regrtest.py -u xpickle' to run them." + sys.stderr.flush() + + test_support.run_unittest( + DumpCPickle_LoadPickle, + DumpPickle_LoadCPickle, + CPicklePython24Compat, + CPicklePython25Compat, + CPicklePython26Compat, + PicklePython24Compat, + PicklePython25Compat, + PicklePython26Compat, + ) + +if __name__ == "__main__": + if "worker" in sys.argv: + worker_main(sys.stdin, sys.stdout) + else: + test_main() -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Apr 19 17:51:45 2015 From: jython-checkins at python.org (jim.baker) Date: Sun, 19 Apr 2015 15:51:45 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_threading=2ELock_to_sup?= =?utf-8?q?port_non-reentrant_semantics?= Message-ID: <20150419155145.6579.73642@psf.io> https://hg.python.org/jython/rev/0e103b371f5a changeset: 7676:0e103b371f5a user: Jason Madden date: Sun Apr 19 09:51:35 2015 -0600 summary: Fix threading.Lock to support non-reentrant semantics Jython previously supported threading.Lock by wrapping java.util.concurrent.ReentrantLock, much like threading.RLock. However, such reentrant locks cannot support the release by threads other than the one that acquired it, contrary to what CPython both documents and implements. Fix by using an underlying lock based on java.util.concurrent.locks.AbstractQueuedSynchronizer, following the example code in the documentation for that class. Fixes http://bugs.jython.org/issue1861 files: Lib/test/lock_tests.py | 31 +--- src/org/python/modules/_threading/Condition.java | 24 +- src/org/python/modules/_threading/Lock.java | 75 ++++++++- src/org/python/modules/_threading/_threading.java | 4 +- 4 files changed, 87 insertions(+), 47 deletions(-) diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -149,7 +149,6 @@ Tests for non-recursive, weak locks (which can be acquired and released from different threads). """ - @unittest.skipIf(support.is_jython, "Jython only supports recursive locks") def test_reacquire(self): # Lock needs to be released before re-acquiring. lock = self.locktype() @@ -169,7 +168,6 @@ _wait() self.assertEqual(len(phase), 2) - @unittest.skipIf(support.is_jython, "Java does not allow locks to be released from different threads") def test_different_thread(self): # Lock can be released from a different thread. lock = self.locktype() @@ -291,10 +289,9 @@ results2.append((r, t2 - t1)) Bunch(f, N).wait_for_finished() self.assertEqual(results1, [False] * N) - epsilon = 1e-5 # wait time is hard to test precisely, so keep low resolution for r, dt in results2: self.assertFalse(r) - self.assertTrue(dt >= (0.2 - epsilon), dt) + self.assertTrue(dt >= 0.2, dt) # The event is set results1 = [] results2 = [] @@ -321,13 +318,13 @@ lock = threading.Lock() cond = self.condtype(lock) cond.acquire() - self.assertTrue(lock.acquire(False)) # All locks in Jython are recursive! + self.assertFalse(lock.acquire(False)) cond.release() self.assertTrue(lock.acquire(False)) - self.assertTrue(cond.acquire(False)) # All locks in Jython are recursive! + self.assertFalse(cond.acquire(False)) lock.release() with cond: - self.assertTrue(lock.acquire(False)) # All locks in Jython are recursive! + self.assertFalse(lock.acquire(False)) def test_unacquired_wait(self): cond = self.condtype() @@ -355,17 +352,9 @@ b.wait_for_started() _wait() self.assertEqual(results1, []) - # FIXME: notify(n) is not currently implemented in Jython, trying - # repeated notifies instead. (and honestly w/o understanding what - # notify(n) really even means for CPython...). - # Notify 3 threads at first cond.acquire() - ###cond.notify(3) - cond.notify() - cond.notify() - cond.notify() - + cond.notify(3) _wait() phase_num = 1 cond.release() @@ -375,12 +364,7 @@ self.assertEqual(results2, []) # Notify 5 threads: they might be in their first or second wait cond.acquire() - ###cond.notify(5) - cond.notify() - cond.notify() - cond.notify() - cond.notify() - cond.notify() + cond.notify(5) _wait() phase_num = 2 cond.release() @@ -419,9 +403,8 @@ results.append(t2 - t1) Bunch(f, N).wait_for_finished() self.assertEqual(len(results), 5) - epsilon = 1e-5 # wait time is hard to test precisely, so keep low resolution for dt in results: - self.assertTrue(dt >= (0.2 - epsilon), dt) + self.assertTrue(dt >= 0.2, dt) class BaseSemaphoreTests(BaseTestCase): diff --git a/src/org/python/modules/_threading/Condition.java b/src/org/python/modules/_threading/Condition.java --- a/src/org/python/modules/_threading/Condition.java +++ b/src/org/python/modules/_threading/Condition.java @@ -17,16 +17,16 @@ public class Condition extends PyObject implements ContextManager, Traverseproc { public static final PyType TYPE = PyType.fromClass(Condition.class); - private final Lock _lock; + private final ConditionSupportingLock _lock; private final java.util.concurrent.locks.Condition _condition; public Condition() { - this(new Lock()); + this(new RLock()); } - public Condition(Lock lock) { + public Condition(ConditionSupportingLock lock) { _lock = lock; - _condition = lock._lock.newCondition(); + _condition = lock.getLock().newCondition(); } @ExposedNew @@ -34,7 +34,7 @@ PyType subtype, PyObject[] args, String[] keywords) { final int nargs = args.length; if (nargs == 1) { - return new Condition((Lock)args[0]); + return new Condition((ConditionSupportingLock)args[0]); } return new Condition(); } @@ -102,13 +102,15 @@ } public void notify$() { - Condition_notify(); + Condition_notify(1); } - @ExposedMethod - final void Condition_notify() { + @ExposedMethod(defaults = "1") + final void Condition_notify(int count) { try { - _condition.signal(); + for( int i = 0; i < count; i++) { + _condition.signal(); + } } catch (IllegalMonitorStateException ex) { throw Py.RuntimeError("cannot notify on un-acquired lock"); } @@ -138,14 +140,14 @@ @ExposedMethod final boolean Condition__is_owned() { - return _lock._lock.isHeldByCurrentThread(); + return _lock._is_owned(); } /* Traverseproc implementation */ @Override public int traverse(Visitproc visit, Object arg) { - return _lock != null ? visit.visit(_lock, arg) : 0; + return _lock != null ? visit.visit((PyObject)_lock, arg) : 0; } @Override diff --git a/src/org/python/modules/_threading/Lock.java b/src/org/python/modules/_threading/Lock.java --- a/src/org/python/modules/_threading/Lock.java +++ b/src/org/python/modules/_threading/Lock.java @@ -1,8 +1,8 @@ package org.python.modules._threading; -import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; +import java.util.concurrent.TimeUnit; import org.python.core.ContextManager; -import org.python.core.Py; import org.python.core.PyException; import org.python.core.PyNewWrapper; import org.python.core.PyObject; @@ -15,13 +15,20 @@ @Untraversable @ExposedType(name = "_threading.Lock") -public class Lock extends PyObject implements ContextManager { +public class Lock extends PyObject implements ContextManager, ConditionSupportingLock { public static final PyType TYPE = PyType.fromClass(Lock.class); - final ReentrantLock _lock; + // see http://bugs.jython.org/issue2328 - need to support another thread + // releasing this lock, per CPython semantics, so support semantics with + // custom non-reentrant lock, not a ReentrantLock + private final Mutex _lock; public Lock() { - _lock = new ReentrantLock(); + this._lock = new Mutex(); + } + + public java.util.concurrent.locks.Lock getLock() { + return _lock; } @ExposedNew @@ -30,7 +37,6 @@ final int nargs = args.length; return new Lock(); } - @ExposedMethod(defaults = "true") final boolean Lock_acquire(boolean blocking) { @@ -63,9 +69,6 @@ @ExposedMethod final void Lock_release() { - if (!_lock.isHeldByCurrentThread() || _lock.getHoldCount() <= 0) { - throw Py.RuntimeError("cannot release un-acquired lock"); - } _lock.unlock(); } @@ -95,10 +98,62 @@ @ExposedMethod final boolean Lock__is_owned() { - return _lock.isHeldByCurrentThread(); + return _lock.isLocked(); } public boolean _is_owned() { return Lock__is_owned(); } + } + + +final class Mutex implements java.util.concurrent.locks.Lock { + + // Our internal helper class + private static class Sync extends AbstractQueuedSynchronizer { + // Reports whether in locked state + protected boolean isHeldExclusively() { + return getState() == 1; + } + + // Acquires the lock if state is zero + public boolean tryAcquire(int acquires) { + assert acquires == 1; // Otherwise unused + if (compareAndSetState(0, 1)) { + setExclusiveOwnerThread(Thread.currentThread()); + return true; + } + return false; + } + + // Releases the lock by setting state to zero + protected boolean tryRelease(int releases) { + assert releases == 1; // Otherwise unused + if (getState() == 0) throw new IllegalMonitorStateException(); + setExclusiveOwnerThread(null); + setState(0); + return true; + } + + // Provides a Condition + ConditionObject newCondition() { return new ConditionObject(); } + } + + // The sync object does all the hard work. We just forward to it. + private final Sync sync = new Sync(); + + public void lock() { sync.acquire(1); } + public boolean tryLock() { return sync.tryAcquire(1); } + public void unlock() { sync.release(1); } + public java.util.concurrent.locks.Condition newCondition() { return sync.newCondition(); } + public boolean isLocked() { return sync.isHeldExclusively(); } + public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } + public void lockInterruptibly() throws InterruptedException { + sync.acquireInterruptibly(1); + } + public boolean tryLock(long timeout, TimeUnit unit) + throws InterruptedException { + return sync.tryAcquireNanos(1, unit.toNanos(timeout)); + } +} diff --git a/src/org/python/modules/_threading/_threading.java b/src/org/python/modules/_threading/_threading.java --- a/src/org/python/modules/_threading/_threading.java +++ b/src/org/python/modules/_threading/_threading.java @@ -10,9 +10,9 @@ public static void classDictInit(PyObject dict) { dict.__setitem__("__name__", Py.newString("_threading")); dict.__setitem__("Lock", Lock.TYPE); - dict.__setitem__("RLock", Lock.TYPE); + dict.__setitem__("RLock", RLock.TYPE); dict.__setitem__("_Lock", Lock.TYPE); - dict.__setitem__("_RLock", Lock.TYPE); + dict.__setitem__("_RLock", RLock.TYPE); dict.__setitem__("Condition", Condition.TYPE); // Hide from Python -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Apr 19 18:08:07 2015 From: jython-checkins at python.org (jim.baker) Date: Sun, 19 Apr 2015 16:08:07 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Missing_files_from_previous?= =?utf-8?q?_commit?= Message-ID: <20150419160807.21337.44398@psf.io> https://hg.python.org/jython/rev/0e419393cf4e changeset: 7677:0e419393cf4e user: Jim Baker date: Sun Apr 19 10:08:01 2015 -0600 summary: Missing files from previous commit files: src/org/python/modules/_threading/ConditionSupportingLock.java | 14 + src/org/python/modules/_threading/RLock.java | 108 ++++++++++ 2 files changed, 122 insertions(+), 0 deletions(-) diff --git a/src/org/python/modules/_threading/ConditionSupportingLock.java b/src/org/python/modules/_threading/ConditionSupportingLock.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/_threading/ConditionSupportingLock.java @@ -0,0 +1,14 @@ +package org.python.modules._threading; + +/** + * The protocol needed for a Lock object to work with a Condition + * object. + */ +interface ConditionSupportingLock +{ + java.util.concurrent.locks.Lock getLock(); + boolean acquire(); + boolean acquire(boolean blocking); + void release(); + boolean _is_owned(); +} diff --git a/src/org/python/modules/_threading/RLock.java b/src/org/python/modules/_threading/RLock.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/_threading/RLock.java @@ -0,0 +1,108 @@ +package org.python.modules._threading; + +import java.util.concurrent.locks.ReentrantLock; +import org.python.core.ContextManager; +import org.python.core.Py; +import org.python.core.PyException; +import org.python.core.PyNewWrapper; +import org.python.core.PyObject; +import org.python.core.PyType; +import org.python.core.ThreadState; +import org.python.core.Untraversable; +import org.python.expose.ExposedMethod; +import org.python.expose.ExposedNew; +import org.python.expose.ExposedType; + + at Untraversable + at ExposedType(name = "_threading.RLock") +public class RLock extends PyObject implements ContextManager, ConditionSupportingLock { + + public static final PyType TYPE = PyType.fromClass(RLock.class); + private final ReentrantLock _lock; + + public RLock() { + this._lock = new ReentrantLock(); + } + + public java.util.concurrent.locks.Lock getLock() { + return _lock; + } + + @ExposedNew + final static PyObject RLock___new__ (PyNewWrapper new_, boolean init, + PyType subtype, PyObject[] args, String[] keywords) { + final int nargs = args.length; + return new Lock(); + } + + + @ExposedMethod(defaults = "true") + final boolean RLock_acquire(boolean blocking) { + if (blocking) { + _lock.lock(); + return true; + } else { + return _lock.tryLock(); + } + } + + public boolean acquire() { + return RLock_acquire(true); + } + + public boolean acquire(boolean blocking) { + return RLock_acquire(blocking); + } + + @ExposedMethod + final PyObject RLock___enter__() { + _lock.lock(); + return this; + } + + public PyObject __enter__(ThreadState ts) { + _lock.lock(); + return this; + } + + @ExposedMethod + final void RLock_release() { + if (!_lock.isHeldByCurrentThread() || _lock.getHoldCount() <= 0) { + throw Py.RuntimeError("cannot release un-acquired lock"); + } + _lock.unlock(); + } + + public void release() { + RLock_release(); + } + + @ExposedMethod + final boolean RLock___exit__(PyObject type, PyObject value, PyObject traceback) { + _lock.unlock(); + return false; + } + + public boolean __exit__(ThreadState ts, PyException exception) { + _lock.unlock(); + return false; + } + + @ExposedMethod + final boolean RLock_locked() { + return _lock.isLocked(); + } + + public boolean locked() { + return RLock_locked(); + } + + @ExposedMethod + final boolean RLock__is_owned() { + return _lock.isHeldByCurrentThread(); + } + + public boolean _is_owned() { + return RLock__is_owned(); + } +} -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Apr 19 20:33:59 2015 From: jython-checkins at python.org (jim.baker) Date: Sun, 19 Apr 2015 18:33:59 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_various_threading_issue?= =?utf-8?q?s_introduced_by_previous_fix?= Message-ID: <20150419183359.27902.38299@psf.io> https://hg.python.org/jython/rev/dd4327161042 changeset: 7678:dd4327161042 user: Jim Baker date: Sun Apr 19 12:33:38 2015 -0600 summary: Fix various threading issues introduced by previous fix repr() of threading.{Condition,Lock,RLock} is now a cleaned-up version of what is seen in CPython. Example for an acquired RLock: <_threading.RLock owner='MainThread' count=1>. But we differ from CPython in providing something similar for Lock: <_threading.Lock owner='MainThread' locked=True> Fixed typo such that creating a new RLock in Python would actually return a Lock, which has quite different semantics in that it's not actually reentrant. Awaiting conditions may return early in general, although spurious notifies are rare in the usual happy path. However, to avoid flakiness in the test, do not expect the time to be exact. This requires patching Lib/lock_tests.py specifically for this scenario. files: CoreExposed.includes | 1 + Lib/test/lock_tests.py | 8 +- Lib/test/test_threading_jy.py | 35 ++++- src/org/python/modules/_threading/Condition.java | 15 ++ src/org/python/modules/_threading/ConditionSupportingLock.java | 1 + src/org/python/modules/_threading/Lock.java | 51 ++++++++- src/org/python/modules/_threading/RLock.java | 43 ++++++- 7 files changed, 124 insertions(+), 30 deletions(-) diff --git a/CoreExposed.includes b/CoreExposed.includes --- a/CoreExposed.includes +++ b/CoreExposed.includes @@ -105,6 +105,7 @@ org/python/modules/jffi/StructLayout$ScalarField.class org/python/modules/_threading/Condition.class org/python/modules/_threading/Lock.class +org/python/modules/_threading/RLock.class org/python/modules/_weakref/CallableProxyType.class org/python/modules/_weakref/ProxyType.class org/python/modules/_weakref/ReferenceType.class diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -291,7 +291,13 @@ self.assertEqual(results1, [False] * N) for r, dt in results2: self.assertFalse(r) - self.assertTrue(dt >= 0.2, dt) + # Fudge factor for running on the JVM - actual waits on + # some OS platforms might be like this example, + # 0.199999809265, slightly less than 0.2 seconds. To avoid + # unnecessary flakiness in testing, make epsilon + # relatively large: + epsilon = 0.01 + self.assertTrue(dt >= 0.2 - epsilon, dt) # The event is set results1 = [] results2 = [] diff --git a/Lib/test/test_threading_jy.py b/Lib/test/test_threading_jy.py --- a/Lib/test/test_threading_jy.py +++ b/Lib/test/test_threading_jy.py @@ -97,22 +97,37 @@ self.assertEqual(joined_threads, num_threads) -class MemoryLeakTestCase(unittest.TestCase): - def test_socket_server(self): - # run socketserver with a small amount of memory; verify it exits cleanly +class ReprTestCase(unittest.TestCase): - - rc = subprocess.call([sys.executable, - "-J-Xmx32m", - test_support.findfile("socketserver_test.py")]) - # stdout=PIPE) - self.assertEquals(rc, 0) + def test_condition(self): + l = Lock() + c = Condition(l) + self.assertEqual(repr(c), "<_threading.Condition(<_threading.Lock owner=None locked=False>), 0") + l.acquire() + self.assertEqual(repr(c), "<_threading.Condition(<_threading.Lock owner='MainThread' locked=True>), 0") + + def test_lock(self): + l = Lock() + self.assertEqual(repr(l), "<_threading.Lock owner=None locked=False>") + r.acquire() + self.assertEqual(repr(r), "<_threading.RLock owner='MainThread' locked=True>") + r.release() + self.assertEqual(repr(r), "<_threading.RLock owner=None locked=False>") + + def test_rlock(self): + r = RLock() + self.assertEqual(repr(r), "<_threading.RLock owner=None count=0>") + r.acquire() + self.assertEqual(repr(r), "<_threading.RLock owner='MainThread' count=1>") + r.acquire() + self.assertEqual(repr(r), "<_threading.RLock owner='MainThread' count=2>") + r.release(); r.release() + self.assertEqual(repr(r), "<_threading.RLock owner=None count=0>") def test_main(): test_support.run_unittest( JavaIntegrationTestCase, - #MemoryLeakTestCase, ThreadingTestCase, TwistedTestCase) diff --git a/src/org/python/modules/_threading/Condition.java b/src/org/python/modules/_threading/Condition.java --- a/src/org/python/modules/_threading/Condition.java +++ b/src/org/python/modules/_threading/Condition.java @@ -5,6 +5,8 @@ import org.python.core.PyException; import org.python.core.PyNewWrapper; import org.python.core.PyObject; +import org.python.core.PyString; +import org.python.core.PyTuple; import org.python.core.PyType; import org.python.core.ThreadState; import org.python.expose.ExposedType; @@ -143,6 +145,19 @@ return _lock._is_owned(); } + @Override + public String toString() { + int count = 0; + try { + count = _lock.getWaitQueueLength(_condition); + } catch (IllegalMonitorStateException ex) { + // ignore if lock is not held + } + return (Py.newString("<_threading.Condition(%s, %d)>").__mod__( + new PyTuple( + Py.newString(_lock.toString()), + Py.newInteger(count)))).toString(); + } /* Traverseproc implementation */ @Override diff --git a/src/org/python/modules/_threading/ConditionSupportingLock.java b/src/org/python/modules/_threading/ConditionSupportingLock.java --- a/src/org/python/modules/_threading/ConditionSupportingLock.java +++ b/src/org/python/modules/_threading/ConditionSupportingLock.java @@ -11,4 +11,5 @@ boolean acquire(boolean blocking); void release(); boolean _is_owned(); + int getWaitQueueLength(java.util.concurrent.locks.Condition condition); } diff --git a/src/org/python/modules/_threading/Lock.java b/src/org/python/modules/_threading/Lock.java --- a/src/org/python/modules/_threading/Lock.java +++ b/src/org/python/modules/_threading/Lock.java @@ -3,9 +3,11 @@ import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.util.concurrent.TimeUnit; import org.python.core.ContextManager; +import org.python.core.Py; import org.python.core.PyException; import org.python.core.PyNewWrapper; import org.python.core.PyObject; +import org.python.core.PyTuple; import org.python.core.PyType; import org.python.core.ThreadState; import org.python.core.Untraversable; @@ -21,10 +23,9 @@ // see http://bugs.jython.org/issue2328 - need to support another thread // releasing this lock, per CPython semantics, so support semantics with // custom non-reentrant lock, not a ReentrantLock - private final Mutex _lock; + private final Mutex _lock = new Mutex(); public Lock() { - this._lock = new Mutex(); } public java.util.concurrent.locks.Lock getLock() { @@ -105,6 +106,19 @@ return Lock__is_owned(); } + public int getWaitQueueLength(java.util.concurrent.locks.Condition condition) { + return _lock.getWaitQueueLength(condition); + } + + @ExposedMethod + public String toString() { + String owner = _lock.getOwnerName(); + return Py.newString("<_threading.Lock owner=%r locked=%s>"). + __mod__(new PyTuple( + owner != null ? Py.newStringOrUnicode(owner) : Py.None, + Py.newBoolean(_lock.isLocked()))).toString(); + } + } @@ -128,16 +142,22 @@ } // Releases the lock by setting state to zero - protected boolean tryRelease(int releases) { - assert releases == 1; // Otherwise unused - if (getState() == 0) throw new IllegalMonitorStateException(); - setExclusiveOwnerThread(null); - setState(0); - return true; - } + protected boolean tryRelease(int releases) { + assert releases == 1; // Otherwise unused + if (getState() == 0) { + throw new IllegalMonitorStateException(); + } + setExclusiveOwnerThread(null); + setState(0); + return true; + } // Provides a Condition ConditionObject newCondition() { return new ConditionObject(); } + + Thread getOwner() { + return getExclusiveOwnerThread(); + } } // The sync object does all the hard work. We just forward to it. @@ -156,4 +176,17 @@ throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } + public int getWaitQueueLength(java.util.concurrent.locks.Condition condition) { + if (condition instanceof AbstractQueuedSynchronizer.ConditionObject) { + return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject) condition); + } else { + // punt, no estimate available, but this should never occur using + // standard locks and conditions from this module + return 0; + } + } + String getOwnerName() { + Thread owner = sync.getOwner(); + return owner != null ? owner.getName() : null; + } } diff --git a/src/org/python/modules/_threading/RLock.java b/src/org/python/modules/_threading/RLock.java --- a/src/org/python/modules/_threading/RLock.java +++ b/src/org/python/modules/_threading/RLock.java @@ -1,11 +1,13 @@ package org.python.modules._threading; -import java.util.concurrent.locks.ReentrantLock; + import org.python.core.ContextManager; import org.python.core.Py; import org.python.core.PyException; import org.python.core.PyNewWrapper; import org.python.core.PyObject; +import org.python.core.PyString; +import org.python.core.PyTuple; import org.python.core.PyType; import org.python.core.ThreadState; import org.python.core.Untraversable; @@ -18,24 +20,22 @@ public class RLock extends PyObject implements ContextManager, ConditionSupportingLock { public static final PyType TYPE = PyType.fromClass(RLock.class); - private final ReentrantLock _lock; + private final RLockImplementation _lock = new RLockImplementation(); public RLock() { - this._lock = new ReentrantLock(); } - public java.util.concurrent.locks.Lock getLock() { - return _lock; - } + public java.util.concurrent.locks.Lock getLock() { + return _lock; + } @ExposedNew - final static PyObject RLock___new__ (PyNewWrapper new_, boolean init, - PyType subtype, PyObject[] args, String[] keywords) { + final static PyObject RLock___new__(PyNewWrapper new_, boolean init, + PyType subtype, PyObject[] args, String[] keywords) { final int nargs = args.length; - return new Lock(); + return new RLock(); } - @ExposedMethod(defaults = "true") final boolean RLock_acquire(boolean blocking) { if (blocking) { @@ -105,4 +105,27 @@ public boolean _is_owned() { return RLock__is_owned(); } + + public int getWaitQueueLength(java.util.concurrent.locks.Condition condition) { + return _lock.getWaitQueueLength(condition); + } + + @ExposedMethod + public String toString() { + String owner = _lock.getOwnerName(); + return Py.newString("<_threading.RLock owner=%r count=%d>"). + __mod__(new PyTuple( + owner != null ? Py.newStringOrUnicode(owner) : Py.None, + Py.newInteger(_lock.getHoldCount()))).toString(); + } } + + +final class RLockImplementation extends java.util.concurrent.locks.ReentrantLock { + String getOwnerName() { + Thread owner = getOwner(); + return owner != null ? owner.getName() : null; + } +} + + -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Apr 19 22:11:37 2015 From: jython-checkins at python.org (jim.baker) Date: Sun, 19 Apr 2015 20:11:37 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Support_both_subclassing_fr?= =?utf-8?q?om_Java_in_a_Python_class_and_a_Python_implementatin?= Message-ID: <20150419201136.30339.15339@psf.io> https://hg.python.org/jython/rev/c8d3b553d93d changeset: 7679:c8d3b553d93d user: Jim Baker date: Sun Apr 19 14:11:17 2015 -0600 summary: Support both subclassing from Java in a Python class and a Python implementatin of __tojava__ Required regenerating with src/templates/gderived.py all classes using object.derived in their template. Thanks to Daniel Martin for an initial version of this change. Fixes http://bugs.jython.org/issue1795 files: ACKNOWLEDGMENTS | 1 + Lib/test/test_java_subclasses.py | 77 +++++++++- src/org/python/antlr/ast/AssertDerived.java | 7 +- src/org/python/antlr/ast/AssignDerived.java | 7 +- src/org/python/antlr/ast/AttributeDerived.java | 7 +- src/org/python/antlr/ast/AugAssignDerived.java | 7 +- src/org/python/antlr/ast/BinOpDerived.java | 7 +- src/org/python/antlr/ast/BoolOpDerived.java | 7 +- src/org/python/antlr/ast/BreakDerived.java | 7 +- src/org/python/antlr/ast/CallDerived.java | 7 +- src/org/python/antlr/ast/ClassDefDerived.java | 7 +- src/org/python/antlr/ast/CompareDerived.java | 7 +- src/org/python/antlr/ast/ContinueDerived.java | 7 +- src/org/python/antlr/ast/DeleteDerived.java | 7 +- src/org/python/antlr/ast/DictDerived.java | 7 +- src/org/python/antlr/ast/EllipsisDerived.java | 7 +- src/org/python/antlr/ast/ExceptHandlerDerived.java | 7 +- src/org/python/antlr/ast/ExecDerived.java | 7 +- src/org/python/antlr/ast/ExprDerived.java | 7 +- src/org/python/antlr/ast/ExpressionDerived.java | 7 +- src/org/python/antlr/ast/ExtSliceDerived.java | 7 +- src/org/python/antlr/ast/ForDerived.java | 7 +- src/org/python/antlr/ast/FunctionDefDerived.java | 7 +- src/org/python/antlr/ast/GeneratorExpDerived.java | 7 +- src/org/python/antlr/ast/GlobalDerived.java | 7 +- src/org/python/antlr/ast/IfDerived.java | 7 +- src/org/python/antlr/ast/IfExpDerived.java | 7 +- src/org/python/antlr/ast/ImportDerived.java | 7 +- src/org/python/antlr/ast/ImportFromDerived.java | 7 +- src/org/python/antlr/ast/IndexDerived.java | 7 +- src/org/python/antlr/ast/InteractiveDerived.java | 7 +- src/org/python/antlr/ast/LambdaDerived.java | 7 +- src/org/python/antlr/ast/ListCompDerived.java | 7 +- src/org/python/antlr/ast/ListDerived.java | 7 +- src/org/python/antlr/ast/ModuleDerived.java | 7 +- src/org/python/antlr/ast/NameDerived.java | 7 +- src/org/python/antlr/ast/NumDerived.java | 7 +- src/org/python/antlr/ast/PassDerived.java | 7 +- src/org/python/antlr/ast/PrintDerived.java | 7 +- src/org/python/antlr/ast/RaiseDerived.java | 7 +- src/org/python/antlr/ast/ReprDerived.java | 7 +- src/org/python/antlr/ast/ReturnDerived.java | 7 +- src/org/python/antlr/ast/SliceDerived.java | 7 +- src/org/python/antlr/ast/StrDerived.java | 7 +- src/org/python/antlr/ast/SubscriptDerived.java | 7 +- src/org/python/antlr/ast/SuiteDerived.java | 7 +- src/org/python/antlr/ast/TryExceptDerived.java | 7 +- src/org/python/antlr/ast/TryFinallyDerived.java | 7 +- src/org/python/antlr/ast/TupleDerived.java | 7 +- src/org/python/antlr/ast/UnaryOpDerived.java | 7 +- src/org/python/antlr/ast/WhileDerived.java | 7 +- src/org/python/antlr/ast/WithDerived.java | 7 +- src/org/python/antlr/ast/YieldDerived.java | 7 +- src/org/python/antlr/ast/aliasDerived.java | 7 +- src/org/python/antlr/ast/argumentsDerived.java | 7 +- src/org/python/antlr/ast/comprehensionDerived.java | 7 +- src/org/python/antlr/ast/keywordDerived.java | 7 +- src/org/python/antlr/op/AddDerived.java | 7 +- src/org/python/antlr/op/AndDerived.java | 7 +- src/org/python/antlr/op/AugLoadDerived.java | 7 +- src/org/python/antlr/op/AugStoreDerived.java | 7 +- src/org/python/antlr/op/BitAndDerived.java | 7 +- src/org/python/antlr/op/BitOrDerived.java | 7 +- src/org/python/antlr/op/BitXorDerived.java | 7 +- src/org/python/antlr/op/DelDerived.java | 7 +- src/org/python/antlr/op/DivDerived.java | 7 +- src/org/python/antlr/op/EqDerived.java | 7 +- src/org/python/antlr/op/FloorDivDerived.java | 7 +- src/org/python/antlr/op/GtDerived.java | 7 +- src/org/python/antlr/op/GtEDerived.java | 7 +- src/org/python/antlr/op/InDerived.java | 7 +- src/org/python/antlr/op/InvertDerived.java | 7 +- src/org/python/antlr/op/IsDerived.java | 7 +- src/org/python/antlr/op/IsNotDerived.java | 7 +- src/org/python/antlr/op/LShiftDerived.java | 7 +- src/org/python/antlr/op/LoadDerived.java | 7 +- src/org/python/antlr/op/LtDerived.java | 7 +- src/org/python/antlr/op/LtEDerived.java | 7 +- src/org/python/antlr/op/ModDerived.java | 7 +- src/org/python/antlr/op/MultDerived.java | 7 +- src/org/python/antlr/op/NotDerived.java | 7 +- src/org/python/antlr/op/NotEqDerived.java | 7 +- src/org/python/antlr/op/NotInDerived.java | 7 +- src/org/python/antlr/op/OrDerived.java | 7 +- src/org/python/antlr/op/ParamDerived.java | 7 +- src/org/python/antlr/op/PowDerived.java | 7 +- src/org/python/antlr/op/RShiftDerived.java | 7 +- src/org/python/antlr/op/StoreDerived.java | 7 +- src/org/python/antlr/op/SubDerived.java | 7 +- src/org/python/antlr/op/UAddDerived.java | 7 +- src/org/python/antlr/op/USubDerived.java | 7 +- src/org/python/core/ClasspathPyImporterDerived.java | 7 +- src/org/python/core/PyArrayDerived.java | 7 +- src/org/python/core/PyBaseExceptionDerived.java | 7 +- src/org/python/core/PyByteArrayDerived.java | 7 +- src/org/python/core/PyClassMethodDerived.java | 7 +- src/org/python/core/PyComplexDerived.java | 7 +- src/org/python/core/PyDictionaryDerived.java | 7 +- src/org/python/core/PyEnumerateDerived.java | 7 +- src/org/python/core/PyFileDerived.java | 7 +- src/org/python/core/PyFloatDerived.java | 7 +- src/org/python/core/PyFrozenSetDerived.java | 7 +- src/org/python/core/PyIntegerDerived.java | 7 +- src/org/python/core/PyListDerived.java | 7 +- src/org/python/core/PyLongDerived.java | 7 +- src/org/python/core/PyModuleDerived.java | 7 +- src/org/python/core/PyObjectDerived.java | 7 +- src/org/python/core/PyPropertyDerived.java | 7 +- src/org/python/core/PySetDerived.java | 7 +- src/org/python/core/PyStringDerived.java | 7 +- src/org/python/core/PySuperDerived.java | 7 +- src/org/python/core/PyTupleDerived.java | 7 +- src/org/python/core/PyTypeDerived.java | 7 +- src/org/python/core/PyUnicodeDerived.java | 7 +- src/org/python/modules/PyStructDerived.java | 7 +- src/org/python/modules/_collections/PyDefaultDictDerived.java | 7 +- src/org/python/modules/_collections/PyDequeDerived.java | 7 +- src/org/python/modules/_csv/PyDialectDerived.java | 7 +- src/org/python/modules/_functools/PyPartialDerived.java | 7 +- src/org/python/modules/_io/PyFileIODerived.java | 7 +- src/org/python/modules/_io/PyIOBaseDerived.java | 7 +- src/org/python/modules/_io/PyRawIOBaseDerived.java | 7 +- src/org/python/modules/_weakref/ReferenceTypeDerived.java | 7 +- src/org/python/modules/bz2/PyBZ2CompressorDerived.java | 7 +- src/org/python/modules/bz2/PyBZ2DecompressorDerived.java | 7 +- src/org/python/modules/bz2/PyBZ2FileDerived.java | 7 +- src/org/python/modules/itertools/PyTeeIteratorDerived.java | 7 +- src/org/python/modules/itertools/chainDerived.java | 7 +- src/org/python/modules/itertools/combinationsDerived.java | 7 +- src/org/python/modules/itertools/combinationsWithReplacementDerived.java | 7 +- src/org/python/modules/itertools/compressDerived.java | 7 +- src/org/python/modules/itertools/countDerived.java | 7 +- src/org/python/modules/itertools/cycleDerived.java | 7 +- src/org/python/modules/itertools/dropwhileDerived.java | 7 +- src/org/python/modules/itertools/groupbyDerived.java | 7 +- src/org/python/modules/itertools/ifilterDerived.java | 7 +- src/org/python/modules/itertools/ifilterfalseDerived.java | 7 +- src/org/python/modules/itertools/isliceDerived.java | 7 +- src/org/python/modules/itertools/izipDerived.java | 7 +- src/org/python/modules/itertools/izipLongestDerived.java | 7 +- src/org/python/modules/itertools/permutationsDerived.java | 7 +- src/org/python/modules/itertools/productDerived.java | 7 +- src/org/python/modules/itertools/repeatDerived.java | 7 +- src/org/python/modules/itertools/starmapDerived.java | 7 +- src/org/python/modules/itertools/takewhileDerived.java | 7 +- src/org/python/modules/random/PyRandomDerived.java | 7 +- src/org/python/modules/thread/PyLocalDerived.java | 7 +- src/org/python/modules/zipimport/zipimporterDerived.java | 7 +- src/templates/object.derived | 7 +- tests/java/javatests/ExtendedInterface.java | 7 + tests/java/javatests/InheritanceD.java | 29 +++ tests/java/javatests/UseExtendedInterface.java | 9 + 152 files changed, 855 insertions(+), 297 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -153,6 +153,7 @@ Eliya Sadan Stefan Richthofer Jason Madden + Daniel Martin Local Variables: mode: indented-text diff --git a/Lib/test/test_java_subclasses.py b/Lib/test/test_java_subclasses.py --- a/Lib/test/test_java_subclasses.py +++ b/Lib/test/test_java_subclasses.py @@ -1,12 +1,13 @@ '''Tests subclassing Java classes in Python''' import os import sys +import threading import unittest from test import test_support from java.lang import (Boolean, Class, ClassLoader, Comparable,Integer, Object, Runnable, String, - Thread, ThreadGroup, UnsupportedOperationException) + Thread, ThreadGroup, InterruptedException, UnsupportedOperationException) from java.util import AbstractList, ArrayList, Date, Hashtable, HashSet, Vector from java.util.concurrent import Callable, Executors @@ -15,7 +16,9 @@ from javax.swing.table import AbstractTableModel from org.python.tests import BeanInterface, Callbacker, Coercions, OwnMethodCaller -from javatests import InheritanceA, InheritanceB, InheritanceC, InheritanceD +from javatests import ( + InheritanceA, InheritanceB, InheritanceC, InheritanceD, + ExtendedInterface, UseExtendedInterface) class InterfaceTest(unittest.TestCase): @@ -555,6 +558,73 @@ self.assertE(e.buildParent(), "D", InheritanceD, E) +class ChooseCorrectToJavaTest(unittest.TestCase): + + # Verifies fix for http://bugs.jython.org/issue1795 + # + # Note that we use threading.Thread because we have imported + # java.lang.Thread as Thread + + def test_extended_thread(self): + + class ExtendedThread(threading.Thread, ExtendedInterface): + def returnSomething(self): + return "yo yo yo" + + result = [None] + def f(r): + r[0] = 47 + + t = ExtendedThread(target=f, args=(result,)) + self.assertEqual( + UseExtendedInterface().countWords(t), + 3) + + # Also verify that t still works as a regular thread + t.start() + t.join() + self.assertFalse(t.isAlive()) + self.assertEqual(result[0], 47) + + def test_interruption(self): + # based on this code http://www.jython.org/jythonbook/en/1.0/Concurrency.html#interruption, + # which demonstrates __tojava__ works properly + + class ExtendedThread(threading.Thread, ExtendedInterface): + def returnSomething(self): + return "yo yo yo" + + def wait_until_interrupted(cv): + with cv: + while not Thread.currentThread().isInterrupted(): + try: + # this condition variable is never notified, so will only + # succeed if interrupted + cv.wait() + except InterruptedException, e: + break + + unfair_condition = threading.Condition() + threads = [ + ExtendedThread( + name="thread #%d" % i, + target=wait_until_interrupted, + args=(unfair_condition,)) + for i in xrange(5)] + + for thread in threads: + thread.start() + for thread in threads: + Thread.interrupt(thread) + for thread in threads: + thread.join(5) + + # this assertion only succeeds if threads terminated because + # they were interrupted + for thread in threads: + self.assertFalse(thread.isAlive()) + + def test_main(): test_support.run_unittest( InterfaceTest, @@ -566,7 +636,8 @@ MetaClassTest, AbstractMethodTest, SuperIsSuperTest, - HierarchyTest) + HierarchyTest, + ChooseCorrectToJavaTest) if __name__ == '__main__': diff --git a/src/org/python/antlr/ast/AssertDerived.java b/src/org/python/antlr/ast/AssertDerived.java --- a/src/org/python/antlr/ast/AssertDerived.java +++ b/src/org/python/antlr/ast/AssertDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/AssignDerived.java b/src/org/python/antlr/ast/AssignDerived.java --- a/src/org/python/antlr/ast/AssignDerived.java +++ b/src/org/python/antlr/ast/AssignDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/AttributeDerived.java b/src/org/python/antlr/ast/AttributeDerived.java --- a/src/org/python/antlr/ast/AttributeDerived.java +++ b/src/org/python/antlr/ast/AttributeDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/AugAssignDerived.java b/src/org/python/antlr/ast/AugAssignDerived.java --- a/src/org/python/antlr/ast/AugAssignDerived.java +++ b/src/org/python/antlr/ast/AugAssignDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/BinOpDerived.java b/src/org/python/antlr/ast/BinOpDerived.java --- a/src/org/python/antlr/ast/BinOpDerived.java +++ b/src/org/python/antlr/ast/BinOpDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/BoolOpDerived.java b/src/org/python/antlr/ast/BoolOpDerived.java --- a/src/org/python/antlr/ast/BoolOpDerived.java +++ b/src/org/python/antlr/ast/BoolOpDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/BreakDerived.java b/src/org/python/antlr/ast/BreakDerived.java --- a/src/org/python/antlr/ast/BreakDerived.java +++ b/src/org/python/antlr/ast/BreakDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/CallDerived.java b/src/org/python/antlr/ast/CallDerived.java --- a/src/org/python/antlr/ast/CallDerived.java +++ b/src/org/python/antlr/ast/CallDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ClassDefDerived.java b/src/org/python/antlr/ast/ClassDefDerived.java --- a/src/org/python/antlr/ast/ClassDefDerived.java +++ b/src/org/python/antlr/ast/ClassDefDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/CompareDerived.java b/src/org/python/antlr/ast/CompareDerived.java --- a/src/org/python/antlr/ast/CompareDerived.java +++ b/src/org/python/antlr/ast/CompareDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ContinueDerived.java b/src/org/python/antlr/ast/ContinueDerived.java --- a/src/org/python/antlr/ast/ContinueDerived.java +++ b/src/org/python/antlr/ast/ContinueDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/DeleteDerived.java b/src/org/python/antlr/ast/DeleteDerived.java --- a/src/org/python/antlr/ast/DeleteDerived.java +++ b/src/org/python/antlr/ast/DeleteDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/DictDerived.java b/src/org/python/antlr/ast/DictDerived.java --- a/src/org/python/antlr/ast/DictDerived.java +++ b/src/org/python/antlr/ast/DictDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/EllipsisDerived.java b/src/org/python/antlr/ast/EllipsisDerived.java --- a/src/org/python/antlr/ast/EllipsisDerived.java +++ b/src/org/python/antlr/ast/EllipsisDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ExceptHandlerDerived.java b/src/org/python/antlr/ast/ExceptHandlerDerived.java --- a/src/org/python/antlr/ast/ExceptHandlerDerived.java +++ b/src/org/python/antlr/ast/ExceptHandlerDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ExecDerived.java b/src/org/python/antlr/ast/ExecDerived.java --- a/src/org/python/antlr/ast/ExecDerived.java +++ b/src/org/python/antlr/ast/ExecDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ExprDerived.java b/src/org/python/antlr/ast/ExprDerived.java --- a/src/org/python/antlr/ast/ExprDerived.java +++ b/src/org/python/antlr/ast/ExprDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ExpressionDerived.java b/src/org/python/antlr/ast/ExpressionDerived.java --- a/src/org/python/antlr/ast/ExpressionDerived.java +++ b/src/org/python/antlr/ast/ExpressionDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ExtSliceDerived.java b/src/org/python/antlr/ast/ExtSliceDerived.java --- a/src/org/python/antlr/ast/ExtSliceDerived.java +++ b/src/org/python/antlr/ast/ExtSliceDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ForDerived.java b/src/org/python/antlr/ast/ForDerived.java --- a/src/org/python/antlr/ast/ForDerived.java +++ b/src/org/python/antlr/ast/ForDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/FunctionDefDerived.java b/src/org/python/antlr/ast/FunctionDefDerived.java --- a/src/org/python/antlr/ast/FunctionDefDerived.java +++ b/src/org/python/antlr/ast/FunctionDefDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/GeneratorExpDerived.java b/src/org/python/antlr/ast/GeneratorExpDerived.java --- a/src/org/python/antlr/ast/GeneratorExpDerived.java +++ b/src/org/python/antlr/ast/GeneratorExpDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/GlobalDerived.java b/src/org/python/antlr/ast/GlobalDerived.java --- a/src/org/python/antlr/ast/GlobalDerived.java +++ b/src/org/python/antlr/ast/GlobalDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/IfDerived.java b/src/org/python/antlr/ast/IfDerived.java --- a/src/org/python/antlr/ast/IfDerived.java +++ b/src/org/python/antlr/ast/IfDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/IfExpDerived.java b/src/org/python/antlr/ast/IfExpDerived.java --- a/src/org/python/antlr/ast/IfExpDerived.java +++ b/src/org/python/antlr/ast/IfExpDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ImportDerived.java b/src/org/python/antlr/ast/ImportDerived.java --- a/src/org/python/antlr/ast/ImportDerived.java +++ b/src/org/python/antlr/ast/ImportDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ImportFromDerived.java b/src/org/python/antlr/ast/ImportFromDerived.java --- a/src/org/python/antlr/ast/ImportFromDerived.java +++ b/src/org/python/antlr/ast/ImportFromDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/IndexDerived.java b/src/org/python/antlr/ast/IndexDerived.java --- a/src/org/python/antlr/ast/IndexDerived.java +++ b/src/org/python/antlr/ast/IndexDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/InteractiveDerived.java b/src/org/python/antlr/ast/InteractiveDerived.java --- a/src/org/python/antlr/ast/InteractiveDerived.java +++ b/src/org/python/antlr/ast/InteractiveDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/LambdaDerived.java b/src/org/python/antlr/ast/LambdaDerived.java --- a/src/org/python/antlr/ast/LambdaDerived.java +++ b/src/org/python/antlr/ast/LambdaDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ListCompDerived.java b/src/org/python/antlr/ast/ListCompDerived.java --- a/src/org/python/antlr/ast/ListCompDerived.java +++ b/src/org/python/antlr/ast/ListCompDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ListDerived.java b/src/org/python/antlr/ast/ListDerived.java --- a/src/org/python/antlr/ast/ListDerived.java +++ b/src/org/python/antlr/ast/ListDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ModuleDerived.java b/src/org/python/antlr/ast/ModuleDerived.java --- a/src/org/python/antlr/ast/ModuleDerived.java +++ b/src/org/python/antlr/ast/ModuleDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/NameDerived.java b/src/org/python/antlr/ast/NameDerived.java --- a/src/org/python/antlr/ast/NameDerived.java +++ b/src/org/python/antlr/ast/NameDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/NumDerived.java b/src/org/python/antlr/ast/NumDerived.java --- a/src/org/python/antlr/ast/NumDerived.java +++ b/src/org/python/antlr/ast/NumDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/PassDerived.java b/src/org/python/antlr/ast/PassDerived.java --- a/src/org/python/antlr/ast/PassDerived.java +++ b/src/org/python/antlr/ast/PassDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/PrintDerived.java b/src/org/python/antlr/ast/PrintDerived.java --- a/src/org/python/antlr/ast/PrintDerived.java +++ b/src/org/python/antlr/ast/PrintDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/RaiseDerived.java b/src/org/python/antlr/ast/RaiseDerived.java --- a/src/org/python/antlr/ast/RaiseDerived.java +++ b/src/org/python/antlr/ast/RaiseDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ReprDerived.java b/src/org/python/antlr/ast/ReprDerived.java --- a/src/org/python/antlr/ast/ReprDerived.java +++ b/src/org/python/antlr/ast/ReprDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/ReturnDerived.java b/src/org/python/antlr/ast/ReturnDerived.java --- a/src/org/python/antlr/ast/ReturnDerived.java +++ b/src/org/python/antlr/ast/ReturnDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/SliceDerived.java b/src/org/python/antlr/ast/SliceDerived.java --- a/src/org/python/antlr/ast/SliceDerived.java +++ b/src/org/python/antlr/ast/SliceDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/StrDerived.java b/src/org/python/antlr/ast/StrDerived.java --- a/src/org/python/antlr/ast/StrDerived.java +++ b/src/org/python/antlr/ast/StrDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/SubscriptDerived.java b/src/org/python/antlr/ast/SubscriptDerived.java --- a/src/org/python/antlr/ast/SubscriptDerived.java +++ b/src/org/python/antlr/ast/SubscriptDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/SuiteDerived.java b/src/org/python/antlr/ast/SuiteDerived.java --- a/src/org/python/antlr/ast/SuiteDerived.java +++ b/src/org/python/antlr/ast/SuiteDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/TryExceptDerived.java b/src/org/python/antlr/ast/TryExceptDerived.java --- a/src/org/python/antlr/ast/TryExceptDerived.java +++ b/src/org/python/antlr/ast/TryExceptDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/TryFinallyDerived.java b/src/org/python/antlr/ast/TryFinallyDerived.java --- a/src/org/python/antlr/ast/TryFinallyDerived.java +++ b/src/org/python/antlr/ast/TryFinallyDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/TupleDerived.java b/src/org/python/antlr/ast/TupleDerived.java --- a/src/org/python/antlr/ast/TupleDerived.java +++ b/src/org/python/antlr/ast/TupleDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/UnaryOpDerived.java b/src/org/python/antlr/ast/UnaryOpDerived.java --- a/src/org/python/antlr/ast/UnaryOpDerived.java +++ b/src/org/python/antlr/ast/UnaryOpDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/WhileDerived.java b/src/org/python/antlr/ast/WhileDerived.java --- a/src/org/python/antlr/ast/WhileDerived.java +++ b/src/org/python/antlr/ast/WhileDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/WithDerived.java b/src/org/python/antlr/ast/WithDerived.java --- a/src/org/python/antlr/ast/WithDerived.java +++ b/src/org/python/antlr/ast/WithDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/YieldDerived.java b/src/org/python/antlr/ast/YieldDerived.java --- a/src/org/python/antlr/ast/YieldDerived.java +++ b/src/org/python/antlr/ast/YieldDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/aliasDerived.java b/src/org/python/antlr/ast/aliasDerived.java --- a/src/org/python/antlr/ast/aliasDerived.java +++ b/src/org/python/antlr/ast/aliasDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/argumentsDerived.java b/src/org/python/antlr/ast/argumentsDerived.java --- a/src/org/python/antlr/ast/argumentsDerived.java +++ b/src/org/python/antlr/ast/argumentsDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/comprehensionDerived.java b/src/org/python/antlr/ast/comprehensionDerived.java --- a/src/org/python/antlr/ast/comprehensionDerived.java +++ b/src/org/python/antlr/ast/comprehensionDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/ast/keywordDerived.java b/src/org/python/antlr/ast/keywordDerived.java --- a/src/org/python/antlr/ast/keywordDerived.java +++ b/src/org/python/antlr/ast/keywordDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/AddDerived.java b/src/org/python/antlr/op/AddDerived.java --- a/src/org/python/antlr/op/AddDerived.java +++ b/src/org/python/antlr/op/AddDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/AndDerived.java b/src/org/python/antlr/op/AndDerived.java --- a/src/org/python/antlr/op/AndDerived.java +++ b/src/org/python/antlr/op/AndDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/AugLoadDerived.java b/src/org/python/antlr/op/AugLoadDerived.java --- a/src/org/python/antlr/op/AugLoadDerived.java +++ b/src/org/python/antlr/op/AugLoadDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/AugStoreDerived.java b/src/org/python/antlr/op/AugStoreDerived.java --- a/src/org/python/antlr/op/AugStoreDerived.java +++ b/src/org/python/antlr/op/AugStoreDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/BitAndDerived.java b/src/org/python/antlr/op/BitAndDerived.java --- a/src/org/python/antlr/op/BitAndDerived.java +++ b/src/org/python/antlr/op/BitAndDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/BitOrDerived.java b/src/org/python/antlr/op/BitOrDerived.java --- a/src/org/python/antlr/op/BitOrDerived.java +++ b/src/org/python/antlr/op/BitOrDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/BitXorDerived.java b/src/org/python/antlr/op/BitXorDerived.java --- a/src/org/python/antlr/op/BitXorDerived.java +++ b/src/org/python/antlr/op/BitXorDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/DelDerived.java b/src/org/python/antlr/op/DelDerived.java --- a/src/org/python/antlr/op/DelDerived.java +++ b/src/org/python/antlr/op/DelDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/DivDerived.java b/src/org/python/antlr/op/DivDerived.java --- a/src/org/python/antlr/op/DivDerived.java +++ b/src/org/python/antlr/op/DivDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/EqDerived.java b/src/org/python/antlr/op/EqDerived.java --- a/src/org/python/antlr/op/EqDerived.java +++ b/src/org/python/antlr/op/EqDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/FloorDivDerived.java b/src/org/python/antlr/op/FloorDivDerived.java --- a/src/org/python/antlr/op/FloorDivDerived.java +++ b/src/org/python/antlr/op/FloorDivDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/GtDerived.java b/src/org/python/antlr/op/GtDerived.java --- a/src/org/python/antlr/op/GtDerived.java +++ b/src/org/python/antlr/op/GtDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/GtEDerived.java b/src/org/python/antlr/op/GtEDerived.java --- a/src/org/python/antlr/op/GtEDerived.java +++ b/src/org/python/antlr/op/GtEDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/InDerived.java b/src/org/python/antlr/op/InDerived.java --- a/src/org/python/antlr/op/InDerived.java +++ b/src/org/python/antlr/op/InDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/InvertDerived.java b/src/org/python/antlr/op/InvertDerived.java --- a/src/org/python/antlr/op/InvertDerived.java +++ b/src/org/python/antlr/op/InvertDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/IsDerived.java b/src/org/python/antlr/op/IsDerived.java --- a/src/org/python/antlr/op/IsDerived.java +++ b/src/org/python/antlr/op/IsDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/IsNotDerived.java b/src/org/python/antlr/op/IsNotDerived.java --- a/src/org/python/antlr/op/IsNotDerived.java +++ b/src/org/python/antlr/op/IsNotDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/LShiftDerived.java b/src/org/python/antlr/op/LShiftDerived.java --- a/src/org/python/antlr/op/LShiftDerived.java +++ b/src/org/python/antlr/op/LShiftDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/LoadDerived.java b/src/org/python/antlr/op/LoadDerived.java --- a/src/org/python/antlr/op/LoadDerived.java +++ b/src/org/python/antlr/op/LoadDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/LtDerived.java b/src/org/python/antlr/op/LtDerived.java --- a/src/org/python/antlr/op/LtDerived.java +++ b/src/org/python/antlr/op/LtDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/LtEDerived.java b/src/org/python/antlr/op/LtEDerived.java --- a/src/org/python/antlr/op/LtEDerived.java +++ b/src/org/python/antlr/op/LtEDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/ModDerived.java b/src/org/python/antlr/op/ModDerived.java --- a/src/org/python/antlr/op/ModDerived.java +++ b/src/org/python/antlr/op/ModDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/MultDerived.java b/src/org/python/antlr/op/MultDerived.java --- a/src/org/python/antlr/op/MultDerived.java +++ b/src/org/python/antlr/op/MultDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/NotDerived.java b/src/org/python/antlr/op/NotDerived.java --- a/src/org/python/antlr/op/NotDerived.java +++ b/src/org/python/antlr/op/NotDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/NotEqDerived.java b/src/org/python/antlr/op/NotEqDerived.java --- a/src/org/python/antlr/op/NotEqDerived.java +++ b/src/org/python/antlr/op/NotEqDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/NotInDerived.java b/src/org/python/antlr/op/NotInDerived.java --- a/src/org/python/antlr/op/NotInDerived.java +++ b/src/org/python/antlr/op/NotInDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/OrDerived.java b/src/org/python/antlr/op/OrDerived.java --- a/src/org/python/antlr/op/OrDerived.java +++ b/src/org/python/antlr/op/OrDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/ParamDerived.java b/src/org/python/antlr/op/ParamDerived.java --- a/src/org/python/antlr/op/ParamDerived.java +++ b/src/org/python/antlr/op/ParamDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/PowDerived.java b/src/org/python/antlr/op/PowDerived.java --- a/src/org/python/antlr/op/PowDerived.java +++ b/src/org/python/antlr/op/PowDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/RShiftDerived.java b/src/org/python/antlr/op/RShiftDerived.java --- a/src/org/python/antlr/op/RShiftDerived.java +++ b/src/org/python/antlr/op/RShiftDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/StoreDerived.java b/src/org/python/antlr/op/StoreDerived.java --- a/src/org/python/antlr/op/StoreDerived.java +++ b/src/org/python/antlr/op/StoreDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/SubDerived.java b/src/org/python/antlr/op/SubDerived.java --- a/src/org/python/antlr/op/SubDerived.java +++ b/src/org/python/antlr/op/SubDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/UAddDerived.java b/src/org/python/antlr/op/UAddDerived.java --- a/src/org/python/antlr/op/UAddDerived.java +++ b/src/org/python/antlr/op/UAddDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/antlr/op/USubDerived.java b/src/org/python/antlr/op/USubDerived.java --- a/src/org/python/antlr/op/USubDerived.java +++ b/src/org/python/antlr/op/USubDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/ClasspathPyImporterDerived.java b/src/org/python/core/ClasspathPyImporterDerived.java --- a/src/org/python/core/ClasspathPyImporterDerived.java +++ b/src/org/python/core/ClasspathPyImporterDerived.java @@ -1110,8 +1110,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyArrayDerived.java b/src/org/python/core/PyArrayDerived.java --- a/src/org/python/core/PyArrayDerived.java +++ b/src/org/python/core/PyArrayDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyBaseExceptionDerived.java b/src/org/python/core/PyBaseExceptionDerived.java --- a/src/org/python/core/PyBaseExceptionDerived.java +++ b/src/org/python/core/PyBaseExceptionDerived.java @@ -1110,8 +1110,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyByteArrayDerived.java b/src/org/python/core/PyByteArrayDerived.java --- a/src/org/python/core/PyByteArrayDerived.java +++ b/src/org/python/core/PyByteArrayDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyClassMethodDerived.java b/src/org/python/core/PyClassMethodDerived.java --- a/src/org/python/core/PyClassMethodDerived.java +++ b/src/org/python/core/PyClassMethodDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyComplexDerived.java b/src/org/python/core/PyComplexDerived.java --- a/src/org/python/core/PyComplexDerived.java +++ b/src/org/python/core/PyComplexDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyDictionaryDerived.java b/src/org/python/core/PyDictionaryDerived.java --- a/src/org/python/core/PyDictionaryDerived.java +++ b/src/org/python/core/PyDictionaryDerived.java @@ -1147,8 +1147,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyEnumerateDerived.java b/src/org/python/core/PyEnumerateDerived.java --- a/src/org/python/core/PyEnumerateDerived.java +++ b/src/org/python/core/PyEnumerateDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyFileDerived.java b/src/org/python/core/PyFileDerived.java --- a/src/org/python/core/PyFileDerived.java +++ b/src/org/python/core/PyFileDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyFloatDerived.java b/src/org/python/core/PyFloatDerived.java --- a/src/org/python/core/PyFloatDerived.java +++ b/src/org/python/core/PyFloatDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyFrozenSetDerived.java b/src/org/python/core/PyFrozenSetDerived.java --- a/src/org/python/core/PyFrozenSetDerived.java +++ b/src/org/python/core/PyFrozenSetDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyIntegerDerived.java b/src/org/python/core/PyIntegerDerived.java --- a/src/org/python/core/PyIntegerDerived.java +++ b/src/org/python/core/PyIntegerDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyListDerived.java b/src/org/python/core/PyListDerived.java --- a/src/org/python/core/PyListDerived.java +++ b/src/org/python/core/PyListDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyLongDerived.java b/src/org/python/core/PyLongDerived.java --- a/src/org/python/core/PyLongDerived.java +++ b/src/org/python/core/PyLongDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyModuleDerived.java b/src/org/python/core/PyModuleDerived.java --- a/src/org/python/core/PyModuleDerived.java +++ b/src/org/python/core/PyModuleDerived.java @@ -1110,8 +1110,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyObjectDerived.java b/src/org/python/core/PyObjectDerived.java --- a/src/org/python/core/PyObjectDerived.java +++ b/src/org/python/core/PyObjectDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyPropertyDerived.java b/src/org/python/core/PyPropertyDerived.java --- a/src/org/python/core/PyPropertyDerived.java +++ b/src/org/python/core/PyPropertyDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PySetDerived.java b/src/org/python/core/PySetDerived.java --- a/src/org/python/core/PySetDerived.java +++ b/src/org/python/core/PySetDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyStringDerived.java b/src/org/python/core/PyStringDerived.java --- a/src/org/python/core/PyStringDerived.java +++ b/src/org/python/core/PyStringDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PySuperDerived.java b/src/org/python/core/PySuperDerived.java --- a/src/org/python/core/PySuperDerived.java +++ b/src/org/python/core/PySuperDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyTupleDerived.java b/src/org/python/core/PyTupleDerived.java --- a/src/org/python/core/PyTupleDerived.java +++ b/src/org/python/core/PyTupleDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyTypeDerived.java b/src/org/python/core/PyTypeDerived.java --- a/src/org/python/core/PyTypeDerived.java +++ b/src/org/python/core/PyTypeDerived.java @@ -1110,8 +1110,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/core/PyUnicodeDerived.java b/src/org/python/core/PyUnicodeDerived.java --- a/src/org/python/core/PyUnicodeDerived.java +++ b/src/org/python/core/PyUnicodeDerived.java @@ -1137,8 +1137,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/PyStructDerived.java b/src/org/python/modules/PyStructDerived.java --- a/src/org/python/modules/PyStructDerived.java +++ b/src/org/python/modules/PyStructDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/_collections/PyDefaultDictDerived.java b/src/org/python/modules/_collections/PyDefaultDictDerived.java --- a/src/org/python/modules/_collections/PyDefaultDictDerived.java +++ b/src/org/python/modules/_collections/PyDefaultDictDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/_collections/PyDequeDerived.java b/src/org/python/modules/_collections/PyDequeDerived.java --- a/src/org/python/modules/_collections/PyDequeDerived.java +++ b/src/org/python/modules/_collections/PyDequeDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/_csv/PyDialectDerived.java b/src/org/python/modules/_csv/PyDialectDerived.java --- a/src/org/python/modules/_csv/PyDialectDerived.java +++ b/src/org/python/modules/_csv/PyDialectDerived.java @@ -1111,8 +1111,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/_functools/PyPartialDerived.java b/src/org/python/modules/_functools/PyPartialDerived.java --- a/src/org/python/modules/_functools/PyPartialDerived.java +++ b/src/org/python/modules/_functools/PyPartialDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/_io/PyFileIODerived.java b/src/org/python/modules/_io/PyFileIODerived.java --- a/src/org/python/modules/_io/PyFileIODerived.java +++ b/src/org/python/modules/_io/PyFileIODerived.java @@ -1111,8 +1111,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/_io/PyIOBaseDerived.java b/src/org/python/modules/_io/PyIOBaseDerived.java --- a/src/org/python/modules/_io/PyIOBaseDerived.java +++ b/src/org/python/modules/_io/PyIOBaseDerived.java @@ -1111,8 +1111,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/_io/PyRawIOBaseDerived.java b/src/org/python/modules/_io/PyRawIOBaseDerived.java --- a/src/org/python/modules/_io/PyRawIOBaseDerived.java +++ b/src/org/python/modules/_io/PyRawIOBaseDerived.java @@ -1111,8 +1111,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/_weakref/ReferenceTypeDerived.java b/src/org/python/modules/_weakref/ReferenceTypeDerived.java --- a/src/org/python/modules/_weakref/ReferenceTypeDerived.java +++ b/src/org/python/modules/_weakref/ReferenceTypeDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/bz2/PyBZ2CompressorDerived.java b/src/org/python/modules/bz2/PyBZ2CompressorDerived.java --- a/src/org/python/modules/bz2/PyBZ2CompressorDerived.java +++ b/src/org/python/modules/bz2/PyBZ2CompressorDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/bz2/PyBZ2DecompressorDerived.java b/src/org/python/modules/bz2/PyBZ2DecompressorDerived.java --- a/src/org/python/modules/bz2/PyBZ2DecompressorDerived.java +++ b/src/org/python/modules/bz2/PyBZ2DecompressorDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/bz2/PyBZ2FileDerived.java b/src/org/python/modules/bz2/PyBZ2FileDerived.java --- a/src/org/python/modules/bz2/PyBZ2FileDerived.java +++ b/src/org/python/modules/bz2/PyBZ2FileDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/PyTeeIteratorDerived.java b/src/org/python/modules/itertools/PyTeeIteratorDerived.java --- a/src/org/python/modules/itertools/PyTeeIteratorDerived.java +++ b/src/org/python/modules/itertools/PyTeeIteratorDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/chainDerived.java b/src/org/python/modules/itertools/chainDerived.java --- a/src/org/python/modules/itertools/chainDerived.java +++ b/src/org/python/modules/itertools/chainDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/combinationsDerived.java b/src/org/python/modules/itertools/combinationsDerived.java --- a/src/org/python/modules/itertools/combinationsDerived.java +++ b/src/org/python/modules/itertools/combinationsDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/combinationsWithReplacementDerived.java b/src/org/python/modules/itertools/combinationsWithReplacementDerived.java --- a/src/org/python/modules/itertools/combinationsWithReplacementDerived.java +++ b/src/org/python/modules/itertools/combinationsWithReplacementDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/compressDerived.java b/src/org/python/modules/itertools/compressDerived.java --- a/src/org/python/modules/itertools/compressDerived.java +++ b/src/org/python/modules/itertools/compressDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/countDerived.java b/src/org/python/modules/itertools/countDerived.java --- a/src/org/python/modules/itertools/countDerived.java +++ b/src/org/python/modules/itertools/countDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/cycleDerived.java b/src/org/python/modules/itertools/cycleDerived.java --- a/src/org/python/modules/itertools/cycleDerived.java +++ b/src/org/python/modules/itertools/cycleDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/dropwhileDerived.java b/src/org/python/modules/itertools/dropwhileDerived.java --- a/src/org/python/modules/itertools/dropwhileDerived.java +++ b/src/org/python/modules/itertools/dropwhileDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/groupbyDerived.java b/src/org/python/modules/itertools/groupbyDerived.java --- a/src/org/python/modules/itertools/groupbyDerived.java +++ b/src/org/python/modules/itertools/groupbyDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/ifilterDerived.java b/src/org/python/modules/itertools/ifilterDerived.java --- a/src/org/python/modules/itertools/ifilterDerived.java +++ b/src/org/python/modules/itertools/ifilterDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/ifilterfalseDerived.java b/src/org/python/modules/itertools/ifilterfalseDerived.java --- a/src/org/python/modules/itertools/ifilterfalseDerived.java +++ b/src/org/python/modules/itertools/ifilterfalseDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/isliceDerived.java b/src/org/python/modules/itertools/isliceDerived.java --- a/src/org/python/modules/itertools/isliceDerived.java +++ b/src/org/python/modules/itertools/isliceDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/izipDerived.java b/src/org/python/modules/itertools/izipDerived.java --- a/src/org/python/modules/itertools/izipDerived.java +++ b/src/org/python/modules/itertools/izipDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/izipLongestDerived.java b/src/org/python/modules/itertools/izipLongestDerived.java --- a/src/org/python/modules/itertools/izipLongestDerived.java +++ b/src/org/python/modules/itertools/izipLongestDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/permutationsDerived.java b/src/org/python/modules/itertools/permutationsDerived.java --- a/src/org/python/modules/itertools/permutationsDerived.java +++ b/src/org/python/modules/itertools/permutationsDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/productDerived.java b/src/org/python/modules/itertools/productDerived.java --- a/src/org/python/modules/itertools/productDerived.java +++ b/src/org/python/modules/itertools/productDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/repeatDerived.java b/src/org/python/modules/itertools/repeatDerived.java --- a/src/org/python/modules/itertools/repeatDerived.java +++ b/src/org/python/modules/itertools/repeatDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/starmapDerived.java b/src/org/python/modules/itertools/starmapDerived.java --- a/src/org/python/modules/itertools/starmapDerived.java +++ b/src/org/python/modules/itertools/starmapDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/itertools/takewhileDerived.java b/src/org/python/modules/itertools/takewhileDerived.java --- a/src/org/python/modules/itertools/takewhileDerived.java +++ b/src/org/python/modules/itertools/takewhileDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/random/PyRandomDerived.java b/src/org/python/modules/random/PyRandomDerived.java --- a/src/org/python/modules/random/PyRandomDerived.java +++ b/src/org/python/modules/random/PyRandomDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/thread/PyLocalDerived.java b/src/org/python/modules/thread/PyLocalDerived.java --- a/src/org/python/modules/thread/PyLocalDerived.java +++ b/src/org/python/modules/thread/PyLocalDerived.java @@ -1111,8 +1111,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/org/python/modules/zipimport/zipimporterDerived.java b/src/org/python/modules/zipimport/zipimporterDerived.java --- a/src/org/python/modules/zipimport/zipimporterDerived.java +++ b/src/org/python/modules/zipimport/zipimporterDerived.java @@ -1138,8 +1138,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/src/templates/object.derived b/src/templates/object.derived --- a/src/templates/object.derived +++ b/src/templates/object.derived @@ -411,8 +411,11 @@ // Otherwise, we call the derived __tojava__, if it exists: PyType self_type=getType(); PyObject impl=self_type.lookup("__tojava__"); - if (impl!=null) - return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class); + if (impl!=null) { + PyObject delegate = impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate != this) + return delegate.__tojava__(Object.class); + } return super.__tojava__(c); } diff --git a/tests/java/javatests/ExtendedInterface.java b/tests/java/javatests/ExtendedInterface.java new file mode 100644 --- /dev/null +++ b/tests/java/javatests/ExtendedInterface.java @@ -0,0 +1,7 @@ +// Used to test for http://bugs.jython.org/issue1795 + +package javatests; + +public interface ExtendedInterface { + String returnSomething(); +} diff --git a/tests/java/javatests/InheritanceD.java b/tests/java/javatests/InheritanceD.java new file mode 100644 --- /dev/null +++ b/tests/java/javatests/InheritanceD.java @@ -0,0 +1,29 @@ +package javatests; + +public class InheritanceD extends InheritanceC { + + public Inheritance replicateMe() { + return new InheritanceD(); + } + + public Inheritance replicateParent() { + return new InheritanceC(); + } + + public static Inheritance build() { + return new InheritanceD(); + } + + public static Inheritance buildParent() { + return new InheritanceC(); + } + + public String whoAmI() { + return "D"; + } + + public static String staticWhoAmI() { + return "D"; + } + +} diff --git a/tests/java/javatests/UseExtendedInterface.java b/tests/java/javatests/UseExtendedInterface.java new file mode 100644 --- /dev/null +++ b/tests/java/javatests/UseExtendedInterface.java @@ -0,0 +1,9 @@ +// Used to test for http://bugs.jython.org/issue1795 + +package javatests; + +public class UseExtendedInterface { + public int countWords(ExtendedInterface obj) { + return obj.returnSomething().split("\\s+").length; + } +} -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Apr 19 22:46:26 2015 From: jython-checkins at python.org (jim.baker) Date: Sun, 19 Apr 2015 20:46:26 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_inconsistent_conversion?= =?utf-8?q?_of_PyObject_to_String_in_StdoutWrapper?= Message-ID: <20150419204626.21347.26452@psf.io> https://hg.python.org/jython/rev/fbcbd5f9462b changeset: 7680:fbcbd5f9462b user: Jim Baker date: Sun Apr 19 14:46:22 2015 -0600 summary: Fix inconsistent conversion of PyObject to String in StdoutWrapper Thanks Richard Fearn for the patch to StdoutWrapper! Fixes http://bugs.jython.org/issue2105 files: ACKNOWLEDGMENTS | 1 + Lib/test/test_pythoninterpreter_jy.py | 27 ++++++++++++- src/org/python/core/StdoutWrapper.java | 2 +- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -154,6 +154,7 @@ Stefan Richthofer Jason Madden Daniel Martin + Richard Fearn Local Variables: mode: indented-text diff --git a/Lib/test/test_pythoninterpreter_jy.py b/Lib/test/test_pythoninterpreter_jy.py --- a/Lib/test/test_pythoninterpreter_jy.py +++ b/Lib/test/test_pythoninterpreter_jy.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- import java.io +import os import sys import traceback import types @@ -10,6 +11,7 @@ from _codecs import encode from sun.awt.image import BufImgVolatileSurfaceManager + def exec_code_in_pi(source, inp=None, out=None, err=None, locals=None): """Runs code in a separate context: (thread, PySystemState, PythonInterpreter)""" @@ -101,13 +103,14 @@ self.assertEquals(42, len(output)) - at unittest.skip("FIXME: Disabled for now (failing in dictionary compare)") class UnicodeSourceTest(unittest.TestCase): # When the core PythonInterpreter is embedded in a Java program # it may be supplied as Unicode source as a string or via streams. - def do_test(self, source, ref_out=u'', ref_var={}, inp=None): + def do_test(self, source, ref_out=u'', ref_var=None, inp=None): + if ref_var is None: + ref_var = {} out = java.io.StringWriter() err = java.io.StringWriter() var = {} @@ -118,6 +121,7 @@ inp = java.io.StringReader(inp) exec_code_in_pi(source, inp, out, err, var) + del var['__builtins__'] self.assertEquals(ref_var, var) self.assertEquals(ref_out, out.toString()) @@ -307,11 +311,30 @@ # There is no readinto() with pi.setIn(Reader) +class StdoutWrapperTest(unittest.TestCase): + + def test_choose_str(self): + + def f(): + class Example: + def __str__(self): + return "str" + def __repr__(self): + return "repr" + print Example() + + out = java.io.StringWriter() + err = java.io.StringWriter() + exec_code_in_pi(f, None, out, err) + self.assertEqual(out.toString(), "str" + os.linesep) + + def test_main(): test.test_support.run_unittest( InterpreterTest, UnicodeSourceTest, InterpreterSetInTest, + StdoutWrapperTest ) if __name__ == "__main__": diff --git a/src/org/python/core/StdoutWrapper.java b/src/org/python/core/StdoutWrapper.java --- a/src/org/python/core/StdoutWrapper.java +++ b/src/org/python/core/StdoutWrapper.java @@ -120,7 +120,7 @@ if (o instanceof PyString) { s = ((PyString) o).getString(); } else { - s = o.toString(); + s = o.__str__().toString(); } file.write(s); return s; -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Apr 20 00:50:16 2015 From: jython-checkins at python.org (jeff.allen) Date: Sun, 19 Apr 2015 22:50:16 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_minor_regression_in_tes?= =?utf-8?q?t=5Fjava=5Fintegration=2E?= Message-ID: <20150419225015.6593.21817@psf.io> https://hg.python.org/jython/rev/2b52f81c8e90 changeset: 7684:2b52f81c8e90 user: Jeff Allen date: Sat Apr 18 23:16:43 2015 +0100 summary: Fix minor regression in test_java_integration. Stop expecting a sys-package-mgr message, suppressed under issue 1572. files: Lib/test/test_java_integration.py | 11 ++++------- 1 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_java_integration.py b/Lib/test/test_java_integration.py --- a/Lib/test/test_java_integration.py +++ b/Lib/test/test_java_integration.py @@ -748,7 +748,7 @@ classpath = os.pathsep.join(jars) compile_java_source( ["-classpath", classpath, "-d", tempdir], - "BarkTheDog", source) + "BarkTheDog", source) # Then in a completely different JVM running our # BarkTheDog code, verify we get an appropriate bark @@ -763,11 +763,8 @@ self.assertRegexpMatches( subprocess.check_output(cmd, env=env, universal_newlines=True, stderr=subprocess.STDOUT), - os.path.join( - r"^\*sys-package-mgr\*: processing new jar, '.+?", - r"proxies.jar'\n" - "Class defined on CLASSPATH \n" - "Rover barks 42 times\n$".format(tempdir))) + r"^Class defined on CLASSPATH \n" + "Rover barks 42 times$") finally: pass # print "Will not remove", tempdir @@ -775,7 +772,7 @@ class CopyTest(unittest.TestCase): - + def test_copy(self): fruits = ArrayList(["apple", "banana"]) fruits_copy = copy.copy(fruits) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Apr 20 00:50:15 2015 From: jython-checkins at python.org (jeff.allen) Date: Sun, 19 Apr 2015 22:50:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Tests_in_org/python/tests/i?= =?utf-8?q?mp_run_only_with__proper_path=2E_Fixes_=232327=2E?= Message-ID: <20150419225015.21343.88734@psf.io> https://hg.python.org/jython/rev/a6f113302fae changeset: 7681:a6f113302fae parent: 7661:415c4a58078e user: Jeff Allen date: Sat Apr 18 11:46:19 2015 +0100 summary: Tests in org/python/tests/imp run only with proper path. Fixes #2327. The JUnit test for package import depends on a particular class path setting. It has its own ant target for this reason, but was also found by the general search for tests, where it ran and failed. files: build.xml | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -929,7 +929,10 @@ - + + + @@ -942,6 +945,7 @@ + -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Apr 20 00:50:15 2015 From: jython-checkins at python.org (jeff.allen) Date: Sun, 19 Apr 2015 22:50:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_sys-package-mgr_console_mes?= =?utf-8?q?sages_silenced_by_default=2E_Fixes_=231572=2E?= Message-ID: <20150419225015.30325.44239@psf.io> https://hg.python.org/jython/rev/7f905bb4c179 changeset: 7682:7f905bb4c179 user: Jeff Allen date: Sat Apr 18 13:43:18 2015 +0100 summary: sys-package-mgr console messages silenced by default. Fixes #1572. The messages concerned are demoted from "message" to "comment" in Jython's private logging framework. Thanks to Emmanuel Jannetti. files: NEWS | 4 ++++ src/org/python/core/packagecache/CachedJarsPackageManager.java | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ For more details, please see https://hg.python.org/jython +Jython 2.7rc3 + Bugs fixed + - [ 1572 ] sys-package-mgr console messages silenced by default. Thanks to Emmanuel Jannetti. + Jython 2.7rc2 Bugs fixed - [ 2301 ] time.strftime now always returns a bytestring (fixes pip on Japanese locales) diff --git a/src/org/python/core/packagecache/CachedJarsPackageManager.java b/src/org/python/core/packagecache/CachedJarsPackageManager.java --- a/src/org/python/core/packagecache/CachedJarsPackageManager.java +++ b/src/org/python/core/packagecache/CachedJarsPackageManager.java @@ -272,7 +272,7 @@ if ((entry == null || !(new File(entry.cachefile).exists())) && cache) { - message("processing new jar, '" + jarcanon + "'"); + comment("processing new jar, '" + jarcanon + "'"); String jarname; if (localfile) { @@ -303,7 +303,7 @@ if (caching) { this.indexModified = true; if (entry.mtime != 0) { - message("processing modified jar, '" + jarcanon + "'"); + comment("processing modified jar, '" + jarcanon + "'"); } entry.mtime = mtime; } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Apr 20 00:50:16 2015 From: jython-checkins at python.org (jeff.allen) Date: Sun, 19 Apr 2015 22:50:16 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_test=5Fzipimport=5Fs?= =?utf-8?q?upport_to_correct_2_failing_tests=2E?= Message-ID: <20150419225015.31113.72446@psf.io> https://hg.python.org/jython/rev/8518cf34b3f9 changeset: 7683:8518cf34b3f9 user: Jeff Allen date: Sat Apr 18 18:50:20 2015 +0100 summary: Update test_zipimport_support to correct 2 failing tests. Merges code from lib-python library, preserving Jython-specifics, and correcting internal inconsistencies. Only the test was broken. files: Lib/test/test_zipimport_support.py | 29 +++++++++++------ 1 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_zipimport_support.py b/Lib/test/test_zipimport_support.py --- a/Lib/test/test_zipimport_support.py +++ b/Lib/test/test_zipimport_support.py @@ -31,7 +31,8 @@ # test_cmd_line_script (covers the zipimport support in runpy) # Retrieve some helpers from other test cases -from test import test_doctest, sample_doctest +from test import (test_doctest, sample_doctest, sample_doctest_no_doctests, + sample_doctest_no_docstrings) from test.test_importhooks import ImportHooksBaseTestCase if is_jython and os._name=="nt": @@ -105,8 +106,6 @@ import zip_pkg self.assertEqual(inspect.getsource(zip_pkg.foo), test_src) - @unittest.skipIf(is_jython, "FIXME: not working on Jython") - # Failure possibly due to sys.path not passing to sub-process in test_doctest. def test_doctest_issue4197(self): # To avoid having to keep two copies of the doctest module's # unit tests in sync, this test works by taking the source of @@ -121,16 +120,26 @@ "test_zipped_doctest") test_src = test_src.replace("test.sample_doctest", "sample_zipped_doctest") - sample_src = inspect.getsource(sample_doctest) - sample_src = sample_src.replace("test.test_doctest", - "test_zipped_doctest") + # The sample doctest files rewritten to include in the zipped version. + sample_sources = {} + for mod in [sample_doctest, sample_doctest_no_doctests, + sample_doctest_no_docstrings]: + src = inspect.getsource(mod) + src = src.replace("test.test_doctest", "test_zipped_doctest") + # Rewrite the module name so that, for example, + # "test.sample_doctest" becomes "sample_zipped_doctest". + mod_name = mod.__name__.split(".")[-1] + mod_name = mod_name.replace("sample_", "sample_zipped_") + sample_sources[mod_name] = src + with temp_dir() as d: script_name = make_script(d, 'test_zipped_doctest', test_src) zip_name, run_name = make_zip_script(d, 'test_zip', script_name) z = zipfile.ZipFile(zip_name, 'a') - z.writestr("sample_zipped_doctest.py", sample_src) + for mod_name, src in sample_sources.items(): + z.writestr(mod_name + ".py", src) z.close() if verbose: zip_file = zipfile.ZipFile(zip_name, 'r') @@ -190,9 +199,10 @@ test_zipped_doctest.test_unittest_reportflags, ] # Needed for test_DocTestParser and test_debug - deprecations = [ + deprecations = [] + if __debug__: # Ignore all warnings about the use of class Tester in this module. - ("class Tester is deprecated", DeprecationWarning)] + deprecations.append(("class Tester is deprecated", DeprecationWarning)) if sys.py3kwarning: deprecations += [ ("backquote not supported", SyntaxWarning), @@ -201,7 +211,6 @@ for obj in known_good_tests: _run_object_doctest(obj, test_zipped_doctest) - @unittest.skipIf(is_jython, "FIXME: not working on Jython") def test_doctest_main_issue4197(self): test_src = textwrap.dedent("""\ class Test: -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Apr 20 00:50:16 2015 From: jython-checkins at python.org (jeff.allen) Date: Sun, 19 Apr 2015 22:50:16 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_jython_-m_test=2Eregrtest_-?= =?utf-8?q?e_now_finds_the_tests_it_should=2E_Fixes_=232332=2E?= Message-ID: <20150419225016.27924.30056@psf.io> https://hg.python.org/jython/rev/0689142744de changeset: 7685:0689142744de user: Jeff Allen date: Sun Apr 19 21:20:17 2015 +0100 summary: jython -m test.regrtest -e now finds the tests it should. Fixes #2332. Aligns findtestdir() with later lib-python version of regrtest so it finds the tests without reliance on sys.argv[0]. Also adds a method that legitimizes use #-comments in the tables of expected skips and failures. (We already do, but they were appearing as test names.) The logic supporting the --expected flag is clarified. files: Lib/test/regrtest.py | 56 +++++++++++++++++++++++-------- NEWS | 1 + 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -376,16 +376,31 @@ import trace tracer = trace.Trace(ignoredirs=[sys.prefix, sys.exec_prefix], trace=False, count=True) + test_times = [] test_support.verbose = verbose # Tell tests to be moderately quiet test_support.use_resources = use_resources test_support.junit_xml_dir = junit_xml save_modules = sys.modules.keys() + skips = _ExpectedSkips() failures = _ExpectedFailures() + + if expected: + # Suppress expected failure from the list of tests. + for t in failures.getexpected(): + if t in tests: + tests.remove(t) + # Suppress expected skips from the list of tests. + for t in skips.getexpected(): + if t in tests: + tests.remove(t) + + # Prevent reporting unexpected success in things we failed to try + failures.keep_only(tests) + skips.keep_only(tests) + for test in tests: - if expected and (test in skips or test in failures): - continue if not quiet: print test sys.stdout.flush() @@ -517,7 +532,7 @@ def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS): """Return a list of all applicable test modules.""" - if not testdir: testdir = findtestdir() + testdir = findtestdir() names = os.listdir(testdir) tests = [] for name in names: @@ -792,13 +807,8 @@ # Collect cyclic trash. gc.collect() -def findtestdir(): - if __name__ == '__main__': - file = sys.argv[0] - else: - file = __file__ - testdir = os.path.dirname(file) or os.curdir - return testdir +def findtestdir(path=None): + return path or os.path.dirname(__file__) or os.curdir def removepy(name): if name.endswith(os.extsep + "py"): @@ -1260,8 +1270,8 @@ test_locale # Should fix these tests so they are not hardcoded for CPython pyc files - # test_compileall - # test_pydoc + test_compileall + test_pydoc # Requires Python bytecode compilation support test_longexp @@ -1343,7 +1353,7 @@ self.valid = False if _platform in _expectations: s = _expectations[_platform] - self.expected = set(s.split()) + self.expected = set(self.split_commented(s)) # expected to be skipped on every platform, even Linux self.expected.add('test_linuxaudiodev') @@ -1374,7 +1384,6 @@ elif len(u'\0'.encode('unicode-internal')) == 4: self.expected.add("test_macostools") - if sys.platform != "win32": # test_sqlite is only reliable on Windows where the library # is distributed with Python @@ -1423,12 +1432,29 @@ def __contains__(self, key): return key in self.expected + def remove(self, item): + self.expected.remove(item) + + def keep_only(self, items): + "Remove items not in the supplied iterable" + self.expected &= set(items) + + @staticmethod + def split_commented(modlist): + """Split list of words (values from _expectations or _failures) + handling #-comments. + """ + for line in modlist.splitlines(): + trunc_line = line.split('#', 1)[0] + for word in trunc_line.split(): + yield word + class _ExpectedFailures(_ExpectedSkips): def __init__(self): self.valid = False if _platform in _failures: s = _failures[_platform] - self.expected = set(s.split()) + self.expected = set(self.split_commented(s)) self.valid = True def savememo(memo,good,bad,skipped): diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ Jython 2.7rc3 Bugs fixed - [ 1572 ] sys-package-mgr console messages silenced by default. Thanks to Emmanuel Jannetti. + - [ 2332 ] jython -m test.regrtest -e now finds the tests it should. Jython 2.7rc2 Bugs fixed -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Apr 20 00:50:16 2015 From: jython-checkins at python.org (jeff.allen) Date: Sun, 19 Apr 2015 22:50:16 +0000 Subject: [Jython-checkins] =?utf-8?q?jython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_misc_fixes_to_trunk?= Message-ID: <20150419225016.27926.35184@psf.io> https://hg.python.org/jython/rev/5e12eb29a6bb changeset: 7686:5e12eb29a6bb parent: 7680:fbcbd5f9462b parent: 7685:0689142744de user: Jeff Allen date: Sun Apr 19 23:49:41 2015 +0100 summary: Merge misc fixes to trunk files: Lib/test/regrtest.py | 56 +++++++-- Lib/test/test_java_integration.py | 11 +- Lib/test/test_zipimport_support.py | 29 +++- NEWS | 2 + build.xml | 6 +- src/org/python/core/packagecache/CachedJarsPackageManager.java | 4 +- 6 files changed, 73 insertions(+), 35 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -376,16 +376,31 @@ import trace tracer = trace.Trace(ignoredirs=[sys.prefix, sys.exec_prefix], trace=False, count=True) + test_times = [] test_support.verbose = verbose # Tell tests to be moderately quiet test_support.use_resources = use_resources test_support.junit_xml_dir = junit_xml save_modules = sys.modules.keys() + skips = _ExpectedSkips() failures = _ExpectedFailures() + + if expected: + # Suppress expected failure from the list of tests. + for t in failures.getexpected(): + if t in tests: + tests.remove(t) + # Suppress expected skips from the list of tests. + for t in skips.getexpected(): + if t in tests: + tests.remove(t) + + # Prevent reporting unexpected success in things we failed to try + failures.keep_only(tests) + skips.keep_only(tests) + for test in tests: - if expected and (test in skips or test in failures): - continue if not quiet: print test sys.stdout.flush() @@ -517,7 +532,7 @@ def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS): """Return a list of all applicable test modules.""" - if not testdir: testdir = findtestdir() + testdir = findtestdir() names = os.listdir(testdir) tests = [] for name in names: @@ -792,13 +807,8 @@ # Collect cyclic trash. gc.collect() -def findtestdir(): - if __name__ == '__main__': - file = sys.argv[0] - else: - file = __file__ - testdir = os.path.dirname(file) or os.curdir - return testdir +def findtestdir(path=None): + return path or os.path.dirname(__file__) or os.curdir def removepy(name): if name.endswith(os.extsep + "py"): @@ -1260,8 +1270,8 @@ test_locale # Should fix these tests so they are not hardcoded for CPython pyc files - # test_compileall - # test_pydoc + test_compileall + test_pydoc # Requires Python bytecode compilation support test_longexp @@ -1343,7 +1353,7 @@ self.valid = False if _platform in _expectations: s = _expectations[_platform] - self.expected = set(s.split()) + self.expected = set(self.split_commented(s)) # expected to be skipped on every platform, even Linux self.expected.add('test_linuxaudiodev') @@ -1374,7 +1384,6 @@ elif len(u'\0'.encode('unicode-internal')) == 4: self.expected.add("test_macostools") - if sys.platform != "win32": # test_sqlite is only reliable on Windows where the library # is distributed with Python @@ -1423,12 +1432,29 @@ def __contains__(self, key): return key in self.expected + def remove(self, item): + self.expected.remove(item) + + def keep_only(self, items): + "Remove items not in the supplied iterable" + self.expected &= set(items) + + @staticmethod + def split_commented(modlist): + """Split list of words (values from _expectations or _failures) + handling #-comments. + """ + for line in modlist.splitlines(): + trunc_line = line.split('#', 1)[0] + for word in trunc_line.split(): + yield word + class _ExpectedFailures(_ExpectedSkips): def __init__(self): self.valid = False if _platform in _failures: s = _failures[_platform] - self.expected = set(s.split()) + self.expected = set(self.split_commented(s)) self.valid = True def savememo(memo,good,bad,skipped): diff --git a/Lib/test/test_java_integration.py b/Lib/test/test_java_integration.py --- a/Lib/test/test_java_integration.py +++ b/Lib/test/test_java_integration.py @@ -748,7 +748,7 @@ classpath = os.pathsep.join(jars) compile_java_source( ["-classpath", classpath, "-d", tempdir], - "BarkTheDog", source) + "BarkTheDog", source) # Then in a completely different JVM running our # BarkTheDog code, verify we get an appropriate bark @@ -763,11 +763,8 @@ self.assertRegexpMatches( subprocess.check_output(cmd, env=env, universal_newlines=True, stderr=subprocess.STDOUT), - os.path.join( - r"^\*sys-package-mgr\*: processing new jar, '.+?", - r"proxies.jar'\n" - "Class defined on CLASSPATH \n" - "Rover barks 42 times\n$".format(tempdir))) + r"^Class defined on CLASSPATH \n" + "Rover barks 42 times$") finally: pass # print "Will not remove", tempdir @@ -775,7 +772,7 @@ class CopyTest(unittest.TestCase): - + def test_copy(self): fruits = ArrayList(["apple", "banana"]) fruits_copy = copy.copy(fruits) diff --git a/Lib/test/test_zipimport_support.py b/Lib/test/test_zipimport_support.py --- a/Lib/test/test_zipimport_support.py +++ b/Lib/test/test_zipimport_support.py @@ -31,7 +31,8 @@ # test_cmd_line_script (covers the zipimport support in runpy) # Retrieve some helpers from other test cases -from test import test_doctest, sample_doctest +from test import (test_doctest, sample_doctest, sample_doctest_no_doctests, + sample_doctest_no_docstrings) from test.test_importhooks import ImportHooksBaseTestCase if is_jython and os._name=="nt": @@ -105,8 +106,6 @@ import zip_pkg self.assertEqual(inspect.getsource(zip_pkg.foo), test_src) - @unittest.skipIf(is_jython, "FIXME: not working on Jython") - # Failure possibly due to sys.path not passing to sub-process in test_doctest. def test_doctest_issue4197(self): # To avoid having to keep two copies of the doctest module's # unit tests in sync, this test works by taking the source of @@ -121,16 +120,26 @@ "test_zipped_doctest") test_src = test_src.replace("test.sample_doctest", "sample_zipped_doctest") - sample_src = inspect.getsource(sample_doctest) - sample_src = sample_src.replace("test.test_doctest", - "test_zipped_doctest") + # The sample doctest files rewritten to include in the zipped version. + sample_sources = {} + for mod in [sample_doctest, sample_doctest_no_doctests, + sample_doctest_no_docstrings]: + src = inspect.getsource(mod) + src = src.replace("test.test_doctest", "test_zipped_doctest") + # Rewrite the module name so that, for example, + # "test.sample_doctest" becomes "sample_zipped_doctest". + mod_name = mod.__name__.split(".")[-1] + mod_name = mod_name.replace("sample_", "sample_zipped_") + sample_sources[mod_name] = src + with temp_dir() as d: script_name = make_script(d, 'test_zipped_doctest', test_src) zip_name, run_name = make_zip_script(d, 'test_zip', script_name) z = zipfile.ZipFile(zip_name, 'a') - z.writestr("sample_zipped_doctest.py", sample_src) + for mod_name, src in sample_sources.items(): + z.writestr(mod_name + ".py", src) z.close() if verbose: zip_file = zipfile.ZipFile(zip_name, 'r') @@ -190,9 +199,10 @@ test_zipped_doctest.test_unittest_reportflags, ] # Needed for test_DocTestParser and test_debug - deprecations = [ + deprecations = [] + if __debug__: # Ignore all warnings about the use of class Tester in this module. - ("class Tester is deprecated", DeprecationWarning)] + deprecations.append(("class Tester is deprecated", DeprecationWarning)) if sys.py3kwarning: deprecations += [ ("backquote not supported", SyntaxWarning), @@ -201,7 +211,6 @@ for obj in known_good_tests: _run_object_doctest(obj, test_zipped_doctest) - @unittest.skipIf(is_jython, "FIXME: not working on Jython") def test_doctest_main_issue4197(self): test_src = textwrap.dedent("""\ class Test: diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -5,6 +5,8 @@ Jython 2.7rc3 Bugs fixed - [ 2326 ] Java's weakly consistent iteration of ConcurrentMap is compatible with mutation + - [ 1572 ] sys-package-mgr console messages silenced by default. Thanks to Emmanuel Jannetti. + - [ 2332 ] jython -m test.regrtest -e now finds the tests it should. Jython 2.7rc2 Bugs fixed diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -929,7 +929,10 @@ - + + + @@ -942,6 +945,7 @@ + diff --git a/src/org/python/core/packagecache/CachedJarsPackageManager.java b/src/org/python/core/packagecache/CachedJarsPackageManager.java --- a/src/org/python/core/packagecache/CachedJarsPackageManager.java +++ b/src/org/python/core/packagecache/CachedJarsPackageManager.java @@ -272,7 +272,7 @@ if ((entry == null || !(new File(entry.cachefile).exists())) && cache) { - message("processing new jar, '" + jarcanon + "'"); + comment("processing new jar, '" + jarcanon + "'"); String jarname; if (localfile) { @@ -303,7 +303,7 @@ if (caching) { this.indexModified = true; if (entry.mtime != 0) { - message("processing modified jar, '" + jarcanon + "'"); + comment("processing modified jar, '" + jarcanon + "'"); } entry.mtime = mtime; } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Apr 20 21:22:57 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 20 Apr 2015 19:22:57 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Many_compatibility_fixes_fo?= =?utf-8?q?r_launcher_=28bin/jython=2C_bin/jython=2Eexe=29?= Message-ID: <20150420192257.21331.93855@psf.io> https://hg.python.org/jython/rev/585cc365d4bd changeset: 7687:585cc365d4bd user: Jim Baker date: Mon Apr 20 13:22:51 2015 -0600 summary: Many compatibility fixes for launcher (bin/jython, bin/jython.exe) Now supports CLASSPATH, and correctly parses JAVA_OPTS and JYTHON_OPTS for inclusion into the command line for org.python.util.jython, which is the actual main program for command line Jython. Updated installer so it generates a shebang line for the launcher that is specific to the CPython 2.7 installation that's available. This change allows for -E to be passed as an option, which does not work if shebang uses #!/usr/bin/env to select, as it previously did. More robust testing, including unit tests that was ported from the now removed test_bat_jy, but now applied to all platforms. RC2 introduced a bug where jython -classpath CLASSPATH could work; this has been removed in favor of jython -J-classpath CLASSPATH (old behavior); this interferes with the processing of the -c option. Fixes http://bugs.jython.org/issue2311 and http://bugs.jython.org/issue2319 files: Lib/test/test_bat_jy.py | 411 ---------- Lib/test/test_jython_launcher.py | 260 ++++++ installer/src/java/org/python/util/install/StartScriptGenerator.java | 55 +- src/shell/jython.exe | Bin src/shell/jython.py | 322 +++++-- 5 files changed, 510 insertions(+), 538 deletions(-) diff --git a/Lib/test/test_bat_jy.py b/Lib/test/test_bat_jy.py deleted file mode 100644 --- a/Lib/test/test_bat_jy.py +++ /dev/null @@ -1,411 +0,0 @@ -'''Tests jython.bat using the --print option''' - -import os -import sys -import unittest -import tempfile - -from test import test_support - -from java.lang import IllegalThreadStateException -from java.lang import Runtime -from java.lang import System -from java.lang import Thread -from java.io import File -from java.io import BufferedReader; -from java.io import InputStreamReader; - -class Monitor(Thread): - def __init__(self, process): - self.process = process - self.output = '' - - def run(self): - reader = BufferedReader(InputStreamReader(self.getStream())) - try: - line = reader.readLine() - while line: - self.output += line - line = reader.readLine() - finally: - reader.close() - - def getOutput(self): - return self.output - -class StdoutMonitor(Monitor): - def __init_(self, process): - Monitor.__init__(self, process) - - def getStream(self): - return self.process.getInputStream() - -class StderrMonitor(Monitor): - def __init_(self, process): - Monitor.__init__(self, process) - - def getStream(self): - return self.process.getErrorStream() - -class StarterProcess: - def writeStarter(self, args, javaHome, jythonHome, jythonOpts, internals=False): - (starter, starterPath) = tempfile.mkstemp(suffix='.bat', prefix='starter', text=True) - starter.close() - outfilePath = starterPath[:-4] + '.out' - starter = open(starterPath, 'w') # open starter as simple file - try: - if javaHome: - starter.write('set JAVA_HOME=%s\n' % javaHome) - if jythonHome: - starter.write('set JYTHON_HOME=%s\n' % jythonHome) - if jythonOpts: - starter.write('set JYTHON_OPTS=%s\n' % jythonOpts) - if internals: - starter.write('set _JYTHON_OPTS=leaking_internals\n') - starter.write('set _JYTHON_HOME=c:/leaking/internals\n') - starter.write(self.buildCommand(args, outfilePath)) - return (starterPath, outfilePath) - finally: - starter.close() - - def buildCommand(self, args, outfilePath): - line = '' - for arg in args: - line += arg - line += ' ' - line += '> ' - line += outfilePath - line += ' 2>&1' - return line - - def getOutput(self, outfilePath): - lines = '' - outfile = open(outfilePath, 'r') - try: - for line in outfile.readlines(): - lines += line - finally: - outfile.close() - return lines - - def isAlive(self, process): - try: - process.exitValue() - return False - except IllegalThreadStateException: - return True - - def run(self, args, javaHome, jythonHome, jythonOpts, internals=False): - ''' creates a start script, executes it and captures the output ''' - (starterPath, outfilePath) = self.writeStarter(args, javaHome, jythonHome, jythonOpts, internals) - try: - process = Runtime.getRuntime().exec(starterPath) - stdoutMonitor = StdoutMonitor(process) - stderrMonitor = StderrMonitor(process) - stdoutMonitor.start() - stderrMonitor.start() - while self.isAlive(process): - Thread.sleep(300) - return self.getOutput(outfilePath) - finally: - os.remove(starterPath) - os.remove(outfilePath) - -class BaseTest(unittest.TestCase): - def quote(self, s): - return '"' + s + '"' - - def unquote(self, s): - if len(s) > 0: - if s[:1] == '"': - s = s[1:] - if len(s) > 0: - if s[-1:] == '"': - s = s[:-1] - return s - - def getHomeDir(self): - ex = sys.executable - tail = ex[-15:] - if tail == '\\bin\\jython.bat': - home = ex[:-15] - else: - home = ex[:-11] # \jython.bat - return home - - def assertOutput(self, flags=None, javaHome=None, jythonHome=None, jythonOpts=None, internals=False): - args = [self.quote(sys.executable), '--print'] - memory = None - stack = None - prop = None - jythonArgs = None - boot = False - jdb = False - if flags: - for flag in flags: - if flag[:2] == '-J': - if flag[2:6] == '-Xmx': - memory = flag[6:] - elif flag[2:6] == '-Xss': - stack = flag[6:] - elif flag[2:4] == '-D': - prop = flag[2:] - elif flag[:2] == '--': - if flag[2:6] == 'boot': - boot = True - elif flag[2:5] == 'jdb': - jdb = True - else: - if jythonArgs: - jythonArgs += ' ' - jythonArgs += flag - else: - jythonArgs = flag - jythonArgs = jythonArgs.replace('%%', '%') # workaround two .bat files - args.append(flag) - process = StarterProcess() - out = process.run(args, javaHome, jythonHome, jythonOpts, internals) - self.assertNotEquals('', out) - homeIdx = out.find('-Dpython.home=') - java = 'java' - if javaHome: - java = self.quote(self.unquote(javaHome) + '\\bin\\java') - elif jdb: - java = 'jdb' - if not memory: - memory = '512m' - if not stack: - stack = '1152k' - beginning = java + ' ' - if prop: - beginning += ' ' + prop - beginning += ' -Xmx' + memory + ' -Xss' + stack + ' ' - self.assertEquals(beginning, out[:homeIdx]) - executableIdx = out.find('-Dpython.executable=') - homeDir = self.getHomeDir() - if jythonHome: - homeDir = self.unquote(jythonHome) - home = '-Dpython.home=' + self.quote(homeDir) + ' ' - self.assertEquals(home, out[homeIdx:executableIdx]) - if boot: - classpathFlag = '-Xbootclasspath/a:' - else: - classpathFlag = '-classpath' - classpathIdx = out.find(classpathFlag) - executable = '-Dpython.executable=' + self.quote(sys.executable) + ' ' - if not boot: - executable += ' ' - self.assertEquals(executable, out[executableIdx:classpathIdx]) - # ignore full contents of classpath at the moment - classIdx = out.find('org.python.util.jython') - self.assertTrue(classIdx > classpathIdx) - restIdx = classIdx + len('org.python.util.jython') - rest = out[restIdx:].strip() - if jythonOpts: - self.assertEquals(self.quote(jythonOpts), rest) - else: - if jythonArgs: - self.assertEquals(jythonArgs, rest) - else: - self.assertEquals('', rest) - -class VanillaTest(BaseTest): - def test_plain(self): - self.assertOutput() - -class JavaHomeTest(BaseTest): - def test_unquoted(self): - # for the build bot, try to specify a real java home - javaHome = System.getProperty('java.home', 'C:\\Program Files\\Java\\someJava') - self.assertOutput(javaHome=javaHome) - - def test_quoted(self): - self.assertOutput(javaHome=self.quote('C:\\Program Files\\Java\\someJava')) - - # this currently fails, meaning we accept only quoted (x86) homes ... - def __test_x86_unquoted(self): - self.assertOutput(javaHome='C:\\Program Files (x86)\\Java\\someJava') - - def test_x86_quoted(self): - self.assertOutput(javaHome=self.quote('C:\\Program Files (x86)\\Java\\someJava')) - -class JythonHomeTest(BaseTest): - def createJythonJar(self, parentDir): - jar = File(parentDir, 'jython.jar') - if not jar.exists(): - self.assertTrue(jar.createNewFile()) - return jar - - def cleanup(self, tmpdir, jar=None): - if jar and jar.exists(): - self.assertTrue(jar.delete()) - os.rmdir(tmpdir) - - def test_unquoted(self): - jythonHomeDir = tempfile.mkdtemp() - jar = self.createJythonJar(jythonHomeDir) - self.assertOutput(jythonHome=jythonHomeDir) - self.cleanup(jythonHomeDir, jar) - - def test_quoted(self): - jythonHomeDir = tempfile.mkdtemp() - jar = self.createJythonJar(jythonHomeDir) - self.assertOutput(jythonHome=self.quote(jythonHomeDir)) - self.cleanup(jythonHomeDir, jar) - -class JythonOptsTest(BaseTest): - def test_single(self): - self.assertOutput(jythonOpts='myOpt') - - def test_multiple(self): - self.assertOutput(jythonOpts='some arbitrary options') - -class InternalsTest(BaseTest): - def test_no_leaks(self): - self.assertOutput(internals=True) - -class JavaOptsTest(BaseTest): - def test_memory(self): - self.assertOutput(['-J-Xmx321m']) - - def test_stack(self): - self.assertOutput(['-J-Xss321k']) - - def test_property(self): - self.assertOutput(['-J-DmyProperty=myValue']) - - def test_property_singlequote(self): - self.assertOutput(["-J-DmyProperty='myValue'"]) - - # a space inside value does not work in jython.bat - def __test_property_singlequote_space(self): - self.assertOutput(["-J-DmyProperty='my Value'"]) - - def test_property_doublequote(self): - self.assertOutput(['-J-DmyProperty="myValue"']) - - # a space inside value does not work in jython.bat - def __test_property_doublequote_space(self): - self.assertOutput(['-J-DmyProperty="my Value"']) - - def test_property_underscore(self): - self.assertOutput(['-J-Dmy_Property=my_Value']) - -class ArgsTest(BaseTest): - def test_file(self): - self.assertOutput(['test.py']) - - def test_dash(self): - self.assertOutput(['-i']) - - def test_combined(self): - self.assertOutput(['-W', 'action', 'line']) - - def test_singlequoted(self): - self.assertOutput(['-c', "'import sys;'"]) - - def test_doublequoted(self): - self.assertOutput(['-c', '"print \'something\'"']) - - def test_nestedquotes(self): - self.assertOutput(['-c', '"print \'something \"really\" cool\'"']) - - def test_nestedquotes2(self): - self.assertOutput(['-c', "'print \"something \'really\' cool\"'"]) - - def test_underscored(self): - self.assertOutput(['-jar', 'my_stuff.jar']) - - def test_property(self): - self.assertOutput(['-DmyProperty=myValue']) - - def test_property_underscored(self): - self.assertOutput(['-DmyProperty=my_Value']) - - def test_property_singlequoted(self): - self.assertOutput(["-DmyProperty='my_Value'"]) - - def test_property_doublequoted(self): - self.assertOutput(['-DmyProperty="my_Value"']) - -class DoubleDashTest(BaseTest): - def test_boot(self): - self.assertOutput(['--boot']) - - def test_jdb(self): - self.assertOutput(['--jdb']) - -class GlobPatternTest(BaseTest): - def test_star_nonexisting(self): - self.assertOutput(['-c', 'import sys; print sys.argv[1:]', '*.nonexisting', '*.nonexisting']) - - def test_star_nonexisting_doublequoted(self): - self.assertOutput(['-c', 'import sys; print sys.argv[1:]', '"*.nonexisting"', '"*.nonexisting"']) - - def test_star_nonexistingfile_singlequoted(self): - self.assertOutput(['-c', 'import sys; print sys.argv[1:]', "'*.nonexisting'", "'*.nonexisting'"]) - - def test_star_existing(self): - self.assertOutput(['-c', 'import sys; print sys.argv[1:]', '*.bat', '*.bat']) - - def test_star_existing_doublequoted(self): - self.assertOutput(['-c', 'import sys; print sys.argv[1:]', '"*.bat"', '"*.bat"']) - - def test_star_existing_singlequoted(self): - self.assertOutput(['-c', 'import sys; print sys.argv[1:]', "'*.bat'", "'*.bat'"]) - -class ArgsSpacesTest(BaseTest): - def test_doublequoted(self): - self.assertOutput(['-c', 'import sys; print sys.argv[1:]', '"part1 part2"', '2nd']) - - def test_singlequoted(self): - self.assertOutput(['-c', 'import sys; print sys.argv[1:]', "'part1 part2'", '2nd']) - - # this test currently fails - def __test_unbalanced_doublequote(self): - self.assertOutput(['-c', 'import sys; print sys.argv[1:]', 'Scarlet O"Hara', '2nd']) - - def test_unbalanced_singlequote(self): - self.assertOutput(['-c', 'import sys; print sys.argv[1:]', "Scarlet O'Hara", '2nd']) - -class ArgsSpecialCharsTest(BaseTest): - # exclamation marks are still very special ... - def __test_exclamationmark(self): - self.assertOutput(['-c', 'import sys; print sys.argv[1:]', 'foo!', 'ba!r', '!baz', '!']) - - # because we go through a starter.bat file, we have to simulate % with %% - def test_percentsign(self): - self.assertOutput(['-c', 'import sys; print sys.argv[1:]', 'foo%%1', '%%1bar', '%%1', '%%']) - - def test_colon(self): - self.assertOutput(['-c', 'import sys; print sys.argv[1:]', 'foo:', ':bar']) - - # a semicolon at the beginning of an arg currently fails (e.g. ;bar) - def test_semicolon(self): - self.assertOutput(['-c', 'import sys; print sys.argv[1:]', 'foo;']) - -class DummyTest(unittest.TestCase): - def test_nothing(self): - pass - -def test_main(): - if os._name == 'nt': - test_support.run_unittest(VanillaTest, - JavaHomeTest, - JythonHomeTest, - JythonOptsTest, - InternalsTest, - JavaOptsTest, - ArgsTest, - DoubleDashTest, - GlobPatternTest, - ArgsSpacesTest, - ArgsSpecialCharsTest) - else: - # provide at least one test for the other platforms - happier build bots - test_support.run_unittest(DummyTest) - - -if __name__ == '__main__': - test_main() - diff --git a/Lib/test/test_jython_launcher.py b/Lib/test/test_jython_launcher.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_jython_launcher.py @@ -0,0 +1,260 @@ +# Cross-platform testing of the Jython launcher (bin/jython or bin/jython.exe) using --print +# Replaces test_bat_jy, with some test cases directly used with minor adaptation from that test + +import os +import pprint +import shlex +import subprocess +import sys +import unittest +from collections import OrderedDict +from test import test_support + +launcher = None +uname = None +is_windows = False +some_jar = os.path.join(os.sep, "a", "b", "c", "some.jar") + + +def get_launcher(executable): + # accounts for continued presence of jython bash script + # when not installed with the installer or if CPython 2.7 + # is not available + if os._name == "nt": + return executable + exec_path = os.path.dirname(sys.executable) + jython_py = os.path.join(exec_path, "jython.py") + if os.path.exists(jython_py): + return jython_py + else: + # presumably jython.py has been renamed to jython, generally + # by the installer + return executable + + +def get_uname(): + _uname = None + try: + _uname = subprocess.check_output(["uname"]).strip().lower() + if _uname.startswith("cygwin"): + _uname = "cygwin" + except OSError: + if os._name == "nt": + _uname = "windows" + return _uname + + +def classpath_delimiter(): + return ";" if (os._name == "nt" or uname == "cygwin") else ":" + + +class TestLauncher(unittest.TestCase): + + def get_cmdline(self, cmd, env): + + output = subprocess.check_output(cmd, env=env).rstrip() + if is_windows: + return subprocess._cmdline2list(output) + else: + return shlex.split(output) + + def get_newenv(self, env=os.environ): + newenv = env.copy() + for var in ("CLASSPATH", + "JAVA_MEM", "JAVA_HOME", "JAVA_OPTS", "JAVA_STACK", + "JYTHON_HOME", "JYTHON_OPTS"): + try: + del newenv[var] + except KeyError: + pass + return newenv + + def get_properties(self, args): + props = OrderedDict() + for arg in args: + if arg.startswith("-D"): + k, v = arg[2:].split("=") + props[k] = v + return props + + def test_classpath_env(self): + env = self.get_newenv() + env["CLASSPATH"] = some_jar + args = self.get_cmdline([launcher, "--print"], env=env) + it = iter(args) + while it: + arg = next(it) + if arg == "-classpath": + self.assertEqual(next(it).split(classpath_delimiter())[-1], some_jar) + break + + def test_classpath(self): + env = self.get_newenv() + args = self.get_cmdline([launcher, "--print", "-J-cp", some_jar], env=env) + it = iter(args) + while it: + arg = next(it) + if arg == "-classpath": + self.assertEqual(next(it).split(classpath_delimiter())[-1], some_jar) + break + + def test_java_home(self): + env = self.get_newenv() + my_java = os.path.join(os.sep, "foo", "bar", "my very own (x86) java") + env["JAVA_HOME"] = my_java + args = self.get_cmdline([launcher, "--print"], env) + self.assertEqual(args[0], os.path.join(my_java, "bin", "java")) + self.assertEqual(args[1], "-Xmx512m") + self.assertEqual(args[2], "-Xss1024k") + self.assertEqual(args[-1], "org.python.util.jython") + + def test_java_opts(self): + env = self.get_newenv() + env["JAVA_OPTS"] = '-Dfoo=bar -Dbaz="some property" -Xmx2g -classpath %s' % some_jar + args = self.get_cmdline([launcher, "--print"], env) + props = self.get_properties(args) + self.assertEqual(args[0], "java") + self.assertEqual(args[1], "-Xmx2g") + self.assertEqual(args[2], "-Xss1024k") + self.assertEqual(args[3], "-classpath", args) + self.assertEqual(args[4].split(classpath_delimiter())[-1], some_jar) + self.assertEqual(args[-1], "org.python.util.jython") + self.assertEqual(props["foo"], "bar") + self.assertEqual(props["baz"], "some property") + + def test_default_options(self): + env = self.get_newenv() + args = self.get_cmdline([launcher, "--print"], env) + props = self.get_properties(args) + self.assertEqual(args[0], "java") + self.assertEqual(args[1], "-Xmx512m") + self.assertEqual(args[2], "-Xss1024k") + self.assertEqual(args[-1], "org.python.util.jython") + self.assertIn("python.home", props) + self.assertIn("python.executable", props) + self.assertIn("python.launcher.uname", props) + self.assertIn("python.launcher.tty", props) + + def test_mem_env(self): + env = self.get_newenv() + env["JAVA_MEM"] = "-Xmx4g" + env["JAVA_STACK"] = "-Xss2m" + args = self.get_cmdline([launcher, "--print"], env) + self.assertEqual(args[0], "java") + self.assertEqual(args[1], "-Xmx4g") + self.assertEqual(args[2], "-Xss2m") + self.assertEqual(args[-1], "org.python.util.jython") + + def test_mem_options(self): + env = self.get_newenv() + args = self.get_cmdline([launcher, "-J-Xss2m", "-J-Xmx4g", "--print"], env) + self.assertEqual(args[0], "java") + self.assertEqual(args[1], "-Xmx4g", args) + self.assertEqual(args[2], "-Xss2m", args) + self.assertEqual(args[-1], "org.python.util.jython") + + def test_jython_opts_env(self): + env = self.get_newenv() + env["JYTHON_OPTS"] = '-c "print 47"' + args = self.get_cmdline([launcher, "--print"], env) + self.assertEqual(args[0], "java") + self.assertEqual(args[1], "-Xmx512m") + self.assertEqual(args[2], "-Xss1024k") + self.assertEqual(args[-3], "org.python.util.jython") + self.assertEqual(args[-2], "-c") + self.assertEqual(args[-1], "print 47") + + def test_options(self): + env = self.get_newenv() + args = self.get_cmdline( + [launcher, + "-Dquoted=a \"quoted\" option", + "-Dunder_score=with_underscores", + "-Dstarred=*/*/more/*/*", + "--print"], env) + props = self.get_properties(args) + self.assertEqual(props["quoted"], 'a "quoted" option') + self.assertEqual(props["under_score"], "with_underscores") + self.assertEqual(props["starred"], "*/*/more/*/*") + + def assertHelp(self, output): + self.assertIn( + "usage: jython [option] ... [-c cmd | -m mod | file | -] [arg] ...", + output) + + def test_help(self): + self.assertHelp(subprocess.check_output([launcher, "--help"], stderr=subprocess.STDOUT)) + self.assertHelp(subprocess.check_output([launcher, "--print", "--help"], stderr=subprocess.STDOUT)) + self.assertHelp(subprocess.check_output([launcher, "--help", "--jdb"], stderr=subprocess.STDOUT)) + with self.assertRaises(subprocess.CalledProcessError) as cm: + subprocess.check_output([launcher, "--bad-arg"], stderr=subprocess.STDOUT) + self.assertHelp(cm.exception.output) + + def test_remaining_args(self): + env = self.get_newenv() + args = self.get_cmdline([launcher, "--print", "--", "--help"], env) + self.assertEqual(args[-2], "org.python.util.jython") + self.assertEqual(args[-1], "--help") + + args = self.get_cmdline([launcher, "--print", "yolk", "--help"], env) + self.assertEqual(args[-3], "org.python.util.jython") + self.assertEqual(args[-2], "yolk") + self.assertEqual(args[-1], "--help") + + def assertCommand(self, command): + args = self.get_cmdline([launcher, "--print"] + command, self.get_newenv()) + self.assertEqual(args[(len(args) - len(command)):], command) + + def test_file(self): + self.assertCommand(['test.py']) + + def test_dash(self): + self.assertCommand(['-i']) + + def test_combined(self): + self.assertCommand(['-W', 'action', 'line']) + + def test_singlequoted(self): + self.assertCommand(['-c', "'import sys;'"]) + + def test_doublequoted(self): + self.assertCommand(['-c', '"print \'something\'"']) + + def test_nestedquotes(self): + self.assertCommand(['-c', '"print \'something \"really\" cool\'"']) + + def test_nestedquotes2(self): + self.assertCommand(['-c', "'print \"something \'really\' cool\"'"]) + + def test_starred_args(self): + self.assertCommand(["my python command.py", "*/*/my ARGS/*.txt"]) + + def test_exclamationmark(self): + self.assertCommand(['-c', 'import sys; print sys.argv[1:]', 'foo!', 'ba!r', '!baz', '!', '!!']) + + def test_percentsign(self): + self.assertCommand(['-c', 'import sys; print sys.argv[1:]', 'foo%1', 'foo%%1', '%%1bar', '%%1', '%1', '%', '%%']) + + def test_colon(self): + self.assertCommand(['-c', 'import sys; print sys.argv[1:]', 'foo:', ':bar']) + + def test_semicolon(self): + self.assertCommand(['-c', ';import sys; print sys.argv[1:]', 'foo;']) + + +def test_main(): + global is_windows + global launcher + global uname + + if sys.executable is None: + return + launcher = get_launcher(sys.executable) + uname = get_uname() + is_windows = uname in ("cygwin", "windows") + test_support.run_unittest( + TestLauncher) + + +if __name__ == "__main__": + test_main() diff --git a/installer/src/java/org/python/util/install/StartScriptGenerator.java b/installer/src/java/org/python/util/install/StartScriptGenerator.java --- a/installer/src/java/org/python/util/install/StartScriptGenerator.java +++ b/installer/src/java/org/python/util/install/StartScriptGenerator.java @@ -1,10 +1,13 @@ package org.python.util.install; +import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardCopyOption; import java.nio.file.attribute.PosixFilePermissions; @@ -16,24 +19,51 @@ _targetDirectory = targetDirectory; } - protected boolean hasCPython27() { - int errorCode = 0; + protected String getShebang() { + String shebang = null; try { String command[] = new String[]{ "/usr/bin/env", "python2.7", "-E", "-c", "import sys; " + "assert sys.version_info.major == 2 and sys.version_info.minor == 7, " + - "'Need Python 2.7, got %r' % (sys.version_info,)"}; + "'Need Python 2.7, got %r' % (sys.version_info,);" + + "print sys.executable"}; long timeout = 3000; ChildProcess childProcess = new ChildProcess(command, timeout); childProcess.setDebug(false); childProcess.setSilent(true); - errorCode = childProcess.run(); + int errorCode = childProcess.run(); + if (errorCode == 0) { + // The whole point of this exercise is that we do not + // want the launcher to interpret or otherwise intercept + // any PYTHON environment variables that are being passed through. + // However, a shebang like /usr/bin/env python2.7 -E + // with an extra argument (-E) in general does not work, + // such as on Linux, so we have to replace with a hard-coded + // path + shebang = "#!" + childProcess.getStdout().get(0) + " -E"; + } } catch (Throwable t) { - errorCode = 1; } - return errorCode == 0; + return shebang; + } + + private final void generateLauncher(String shebang, File infile, File outfile) + throws IOException { + try ( + BufferedReader br = new BufferedReader(new FileReader(infile)); + BufferedWriter bw = new BufferedWriter(new FileWriter(outfile))) { + int i = 0; + for (String line; (line = br.readLine()) != null; i += 1) { + if (i == 0) { + bw.write(shebang); + } else { + bw.write(line); + } + bw.newLine(); + } + } } protected final void generateStartScripts() throws IOException { @@ -43,12 +73,13 @@ Files.delete(bindir.resolve("jython.py")); } else { - if (hasCPython27()) { - Files.move(bindir.resolve("jython.py"), bindir.resolve("jython"), - StandardCopyOption.REPLACE_EXISTING); - } else { - Files.delete(bindir.resolve("jython.py")); + String shebang = getShebang(); + if (shebang != null) { + generateLauncher(shebang, + bindir.resolve("jython.py").toFile(), + bindir.resolve("jython").toFile()); } + Files.delete(bindir.resolve("jython.py")); Files.delete(bindir.resolve("jython.exe")); Files.delete(bindir.resolve("python27.dll")); Files.setPosixFilePermissions(bindir.resolve("jython"), diff --git a/src/shell/jython.exe b/src/shell/jython.exe index 61c68b6657c774bb7d40bcbb3d263411490695eb..2a03827dd99c8d2d908074a2e3de15abf56e30d2 GIT binary patch [stripped] diff --git a/src/shell/jython.py b/src/shell/jython.py --- a/src/shell/jython.py +++ b/src/shell/jython.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2.7 +#!/usr/bin/env python2.7 -E # -*- coding: utf-8 -*- # Launch script for Jython. It may be wrapped as an executable with @@ -7,12 +7,12 @@ # bin/jython if CPython 2.7 is available with the above shebang # invocation. -import argparse import glob import inspect import os import os.path import pipes +import shlex import subprocess import sys from collections import OrderedDict @@ -21,64 +21,69 @@ is_windows = os.name == "nt" or (os.name == "java" and os._name == "nt") -def make_parser(provided_args): - parser = argparse.ArgumentParser(description="Jython", add_help=False) - parser.add_argument("-D", dest="properties", action="append") - parser.add_argument("-J", dest="java", action="append") - parser.add_argument("--boot", action="store_true") - parser.add_argument("--jdb", action="store_true") - parser.add_argument("--help", "-h", action="store_true") - parser.add_argument("--print", dest="print_requested", action="store_true") - parser.add_argument("--profile", action="store_true") - args, remainder = parser.parse_known_args(provided_args) +def parse_launcher_args(args): + class Namespace(object): + pass + parsed = Namespace() + parsed.java = [] + parsed.properties = OrderedDict() + parsed.boot = False + parsed.jdb = False + parsed.help = False + parsed.print_requested = False + parsed.profile = False + parsed.jdb = None - items = args.java or [] - args.java = [] - for item in items: - if item.startswith("-Xmx"): - args.mem = item - elif item.startswith("-Xss"): - args.stack = item - else: - args.java.append(item) - - # need to account for the fact that -c and -cp/-classpath are ambiguous options as far - # as argparse is concerned, so parse separately - args.classpath = [] - r = iter(remainder) - r2 = [] + it = iter(args) + next(it) # ignore sys.argv[0] + i = 1 while True: try: - arg = next(r) + arg = next(it) except StopIteration: break - if arg == "-cp" or arg == "-classpath": + if arg.startswith("-D"): + k, v = arg[2:].split("=") + parsed.properties[k] = v + i += 1 + elif arg in ("-J-classpath", "-J-cp"): try: - args.classpath = next(r) - if args.classpath.startswith("-"): - parser.error("Invalid classpath for -classpath: %s" % repr(args.classpath)[1:]) + next_arg = next(it) except StopIteration: - parser.error("-classpath requires an argument") + bad_option("Argument expected for -J-classpath option") + if next_arg.startswith("-"): + bad_option("Bad option for -J-classpath") + parsed.classpath = next_arg + i += 2 + elif arg.startswith("-J-Xmx"): + parsed.mem = arg[2:] + i += 1 + elif arg.startswith("-J-Xss"): + parsed.stack = arg[2:] + i += 1 + elif arg.startswith("-J"): + parsed.java.append(arg[2:]) + i += 1 + elif arg == "--print": + parsed.print_requested = True + i += 1 + elif arg in ("-h", "--help"): + parsed.help = True + elif arg in ("--boot", "--jdb", "--profile"): + setattr(parsed, arg[2:], True) + i += 1 + elif arg == "--": + i += 1 + break else: - r2.append(arg) - remainder = r2 + break - if args.properties is None: - args.properties = [] - props = OrderedDict() - for kv in args.properties: - k, v = kv.split("=") - props[k] = v - args.properties = props - args.encoding = args.properties.get("file.encoding", None) - - return parser, args + return parsed, args[i:] class JythonCommand(object): - def __init__(self, parser, args, jython_args): - self.parser = parser + def __init__(self, args, jython_args): self.args = args self.jython_args = jython_args @@ -109,13 +114,16 @@ return self._java_command def setup_java_command(self): + if self.args.help: + self._java_home = None + self._java_command = "java" + return + if "JAVA_HOME" not in os.environ: self._java_home = None self._java_command = "jdb" if self.args.jdb else "java" else: self._java_home = os.environ["JAVA_HOME"] - #if self.uname == "cygwin": - # self._java_home = subprocess.check_output(["cygpath", "--windows", self._java_home]).strip() if self.uname == "cygwin": self._java_command = "jdb" if self.args.jdb else "java" else: @@ -159,51 +167,52 @@ return ";" if (is_windows or self.uname == "cygwin") else ":" @property - def classpath(self): - if hasattr(self, "_classpath"): - return self._classpath + def jython_jars(self): + if hasattr(self, "_jython_jars"): + return self._jython_jars if os.path.exists(os.path.join(self.jython_home, "jython-dev.jar")): jars = [os.path.join(self.jython_home, "jython-dev.jar")] - jars.append(os.path.join(self.jython_home, "javalib", "*")) + if self.args.boot: + # Wildcard expansion does not work for bootclasspath + for jar in glob.glob(os.path.join(self.jython_home, "javalib", "*.jar")): + jars.append(jar) + else: + jars.append(os.path.join(self.jython_home, "javalib", "*")) elif not os.path.exists(os.path.join(self.jython_home, "jython.jar")): - self.parser.error( -"""{executable}: -{jython_home} contains neither jython-dev.jar nor jython.jar. + bad_option("""{jython_home} contains neither jython-dev.jar nor jython.jar. Try running this script from the 'bin' directory of an installed Jython or -setting {envvar_specifier}JYTHON_HOME.""".\ - format( - executable=self.executable, +setting {envvar_specifier}JYTHON_HOME.""".format( jython_home=self.jython_home, envvar_specifier="%" if self.uname == "windows" else "$")) else: jars = [os.path.join(self.jython_home, "jython.jar")] - self._classpath = self.classpath_delimiter.join(jars) - if self.args.classpath and not self.args.boot: - self._classpath += self.classpath_delimiter + self.args.classpath - return self._classpath + self._jython_jars = jars + return self._jython_jars + + @property + def java_classpath(self): + if hasattr(self.args, "classpath"): + return self.args.classpath + else: + return os.environ.get("CLASSPATH", ".") @property def java_mem(self): - if hasattr(self.args.java, "mem"): - return self.args.java.mem + if hasattr(self.args, "mem"): + return self.args.mem else: return os.environ.get("JAVA_MEM", "-Xmx512m") @property def java_stack(self): - if hasattr(self.args.java, "stack"): - return self.args.java.mem + if hasattr(self.args, "stack"): + return self.args.stack else: return os.environ.get("JAVA_STACK", "-Xss1024k") @property def java_opts(self): - if "JAVA_OPTS" in os.environ: - options = os.environ["JAVA_OPTS"].split() - else: - options = [] - options.extend([self.java_mem, self.java_stack]) - return options + return [self.java_mem, self.java_stack] @property def java_profile_agent(self): @@ -219,6 +228,9 @@ else: return arg + def make_classpath(self, jars): + return self.classpath_delimiter.join(jars) + def convert_path(self, arg): if self.uname == "cygwin": if not arg.startswith("/cygdrive/"): @@ -235,20 +247,25 @@ args = [self.java_command] args.extend(self.java_opts) args.extend(self.args.java) + + classpath = self.java_classpath + jython_jars = self.jython_jars if self.args.boot: - args.append("-Xbootclasspath/a:%s" % self.convert_path(self.classpath)) - if self.args.classpath: - args.extend(["-classpath", self.convert_path(self.args.classpath)]) + args.append("-Xbootclasspath/a:%s" % self.convert_path(self.make_classpath(jython_jars))) else: - args.extend(["-classpath", self.convert_path(self.classpath)]) + classpath = self.make_classpath(jython_jars) + self.classpath_delimiter + classpath + args.extend(["-classpath", self.convert_path(classpath)]) + if "python.home" not in self.args.properties: args.append("-Dpython.home=%s" % self.convert_path(self.jython_home)) if "python.executable" not in self.args.properties: args.append("-Dpython.executable=%s" % self.convert_path(self.executable)) if "python.launcher.uname" not in self.args.properties: args.append("-Dpython.launcher.uname=%s" % self.uname) - # determine if is-a-tty for the benefit of running on cygwin - mintty doesn't behave like - # a standard windows tty and so JNR posix doesn't detect it properly + # Determines whether running on a tty for the benefit of + # running on Cygwin. This step is needed because the Mintty + # terminal emulator doesn't behave like a standard Microsoft + # Windows tty, and so JNR Posix doesn't detect it properly. if "python.launcher.tty" not in self.args.properties: args.append("-Dpython.launcher.tty=%s" % str(os.isatty(sys.stdin.fileno())).lower()) if self.uname == "cygwin" and "python.console" not in self.args.properties: @@ -265,66 +282,141 @@ return args +def bad_option(msg): + print >> sys.stderr, """ +{msg} +usage: jython [option] ... [-c cmd | -m mod | file | -] [arg] ... +Try `jython -h' for more information. +""".format(msg=msg) + sys.exit(2) + + def print_help(): print >> sys.stderr, """ -Jython launcher options: +Jython launcher-specific options: +-Dname=value : pass name=value property to Java VM (e.g. -Dpython.path=/a/b/c) -Jarg : pass argument through to Java VM (e.g. -J-Xmx512m) ---jdb : run under JDB ---print : print the Java command instead of executing it +--boot : speeds up launch performance by putting Jython jars on the boot classpath +--help : this help message +--jdb : run under JDB java debugger +--print : print the Java command with args for launching Jython instead of executing it --profile: run with the Java Interactive Profiler (http://jiprof.sf.net) ---boot : put jython on the boot classpath (disables the bytecode verifier) -- : pass remaining arguments through to Jython Jython launcher environment variables: +JAVA_MEM : Java memory (sets via -Xmx) +JAVA_OPTS : options to pass directly to Java +JAVA_STACK : Java stack size (sets via -Xss) JAVA_HOME : Java installation directory JYTHON_HOME: Jython installation directory JYTHON_OPTS: default command line arguments """ +def support_java_opts(args): + it = iter(args) + while it: + arg = next(it) + if arg.startswith("-D"): + yield arg + elif arg in ("-classpath", "-cp"): + yield "-J" + arg + try: + yield next(it) + except StopIteration: + bad_option("Argument expected for -classpath option in JAVA_OPTS") + else: + yield "-J" + arg -def split_launcher_args(args): - it = iter(args) - i = 1 - next(it) - while True: - try: - arg = next(it) - except StopIteration: - break - if arg.startswith("-D") or arg.startswith("-J") or \ - arg in ("--boot", "--jdb", "--help", "--print", "--profile"): - i += 1 - elif arg in ("-cp", "-classpath"): - i += 1 - try: - next(it) - i += 1 - except StopIteration: - break # will be picked up in argparse, where an error will be raised - elif arg == "--": - i += 1 - break + +# copied from subprocess module in Jython; see +# http://bugs.python.org/issue1724822 where it is discussed to include +# in Python 3.x for shlex: +def cmdline2list(cmdline): + """Build an argv list from a Microsoft shell style cmdline str + + The reverse of list2cmdline that follows the same MS C runtime + rules. + """ + whitespace = ' \t' + # count of preceding '\' + bs_count = 0 + in_quotes = False + arg = [] + argv = [] + + for ch in cmdline: + if ch in whitespace and not in_quotes: + if arg: + # finalize arg and reset + argv.append(''.join(arg)) + arg = [] + bs_count = 0 + elif ch == '\\': + arg.append(ch) + bs_count += 1 + elif ch == '"': + if not bs_count % 2: + # Even number of '\' followed by a '"'. Place one + # '\' for every pair and treat '"' as a delimiter + if bs_count: + del arg[-(bs_count / 2):] + in_quotes = not in_quotes + else: + # Odd number of '\' followed by a '"'. Place one '\' + # for every pair and treat '"' as an escape sequence + # by the remaining '\' + del arg[-(bs_count / 2 + 1):] + arg.append(ch) + bs_count = 0 else: - break - return args[:i], args[i:] + # regular char + arg.append(ch) + bs_count = 0 + # A single trailing '"' delimiter yields an empty arg + if arg or in_quotes: + argv.append(''.join(arg)) -def main(): + return argv + + +def decode_args(sys_args): + args = [sys_args[0]] + + def get_env_opts(envvar): + opts = os.environ.get(envvar, "") + if is_windows: + return cmdline2list(opts) + else: + return shlex.split(opts) + + java_opts = get_env_opts("JAVA_OPTS") + jython_opts = get_env_opts("JYTHON_OPTS") + + args.extend(support_java_opts(java_opts)) + args.extend(sys_args[1:]) + if sys.stdout.encoding: if sys.stdout.encoding.lower() == "cp65001": sys.exit("""Jython does not support code page 65001 (CP_UTF8). Please try another code page by setting it with the chcp command.""") - sys.argv = [arg.decode(sys.stdout.encoding) for arg in sys.argv] - launcher_args, jython_args = split_launcher_args(sys.argv) - parser, args = make_parser(launcher_args) - jython_command = JythonCommand(parser, args, jython_args) + args = [arg.decode(sys.stdout.encoding) for arg in args] + jython_opts = [arg.decode(sys.stdout.encoding) for arg in jython_opts] + + return args, jython_opts + + +def main(sys_args): + sys_args, jython_opts = decode_args(sys_args) + args, jython_args = parse_launcher_args(sys_args) + jython_command = JythonCommand(args, jython_opts + jython_args) command = jython_command.command - if args.profile: + if args.profile and not args.help: try: os.unlink("profile.txt") except OSError: pass - if args.print_requested: + if args.print_requested and not args.help: if jython_command.uname == "windows": print subprocess.list2cmdline(jython_command.command) else: @@ -349,4 +441,4 @@ if __name__ == "__main__": - main() + main(sys.argv) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Apr 20 22:47:02 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 20 Apr 2015 20:47:02 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_test_for_issue_=232105_?= =?utf-8?q?so_that_the_test_runs_correctly_on_Windows?= Message-ID: <20150420204702.21335.19474@psf.io> https://hg.python.org/jython/rev/3fa3e8cd9323 changeset: 7688:3fa3e8cd9323 user: Jim Baker date: Mon Apr 20 14:46:58 2015 -0600 summary: Fix test for issue #2105 so that the test runs correctly on Windows files: Lib/test/test_pythoninterpreter_jy.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_pythoninterpreter_jy.py b/Lib/test/test_pythoninterpreter_jy.py --- a/Lib/test/test_pythoninterpreter_jy.py +++ b/Lib/test/test_pythoninterpreter_jy.py @@ -326,7 +326,7 @@ out = java.io.StringWriter() err = java.io.StringWriter() exec_code_in_pi(f, None, out, err) - self.assertEqual(out.toString(), "str" + os.linesep) + self.assertEqual(out.toString(), "str\n") def test_main(): -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Apr 21 01:29:07 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 20 Apr 2015 23:29:07 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Project_doc_updates?= Message-ID: <20150420232854.120222.63197@psf.io> https://hg.python.org/jython/rev/11e6776f80c2 changeset: 7689:11e6776f80c2 user: Jim Baker date: Mon Apr 20 17:28:49 2015 -0600 summary: Project doc updates files: ACKNOWLEDGMENTS | 6 +++--- NEWS | 21 +++++++++++++++++++-- README.txt | 32 ++++++++++++++++++++++---------- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -3,7 +3,7 @@ Jython: Python for the Java Platform -Copyright (c) 2000-2014 Jython Developers. +Copyright (c) 2000-2015 Jython Developers. All rights reserved. Copyright (c) 2000 BeOpen.com. @@ -62,8 +62,8 @@ Yin Wang and Steve Yegge contributed the static analyzer from Google (also called indexer). -The Jython startup script (bin/jython) was adapted from the similar -script written for JRuby. +The Jython bash startup script (fallback for bin/jython) was adapted +from the similar script written for JRuby. A huge thanks goes to all the members of the jpython/jython mailing lists. Other folks who have contributed to JPython and diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -4,9 +4,26 @@ Jython 2.7rc3 Bugs fixed + - [ 2311, 2319 ] Many compatibility fixes for launcher (bin/jython, bin/jython.exe) + - [ 2332 ] jython -m test.regrtest -e now finds the tests it should + - [ 1572 ] sys-package-mgr console messages silenced by default. Thanks to Emmanuel Jannetti. + - [ 2327 ] Tests in org/python/tests/imp run only with proper path + - [ 2105 ] Fix inconsistent conversion of PyObject to String in StdoutWrapper + - [ 1795 ] Support both subclassing from Java in a Python class and a Python implementation of __tojava__ + - [ 1861 ] Fix threading.Lock to support non-reentrant semantics + - [ 2323 ] Fixes pickling issues in object.__reduce__ and cPickle.{load, loads} + - [ 1540 ] Fix stack overflow due to how proxies for Java classes resolve super method in Java + - [ 2325 ] Enable piping input into Jython without getting extraneous prompt output + - [ 2324 ] Fix index computation for StringBuilder after seek back in cStringIO + - [ 2171 ] Fixed direct calls to __pow__() on int, long and float with a modulo of None - [ 2326 ] Java's weakly consistent iteration of ConcurrentMap is compatible with mutation - - [ 1572 ] sys-package-mgr console messages silenced by default. Thanks to Emmanuel Jannetti. - - [ 2332 ] jython -m test.regrtest -e now finds the tests it should. + - [ 2322 ] Refreshed several networking modules from CPython 2.7.9 due to CVE-2013-1752 + - [ 1670 ] Added automatic type coercion of decimal.Decimal to java.lang.{Double, Float} + - Pull in hand coded AST work into code gen in asdl_antlr + - [ 2307 ] Fixed normalization of paths on Windows + - Module tempfile now returns temporary directory in proper case (See also CPython issue 14255) + - Faster extended slice deletion in bytearray. + - [ 2304 ] Fixed __module__ missing from functions in the time and operator modules Jython 2.7rc2 Bugs fixed diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -1,15 +1,27 @@ -Welcome to Jython 2.7rc2 -======================== +Jython: Python for the Java Platform -This is the second release candidate of the 2.7 version of Jython. Thanks to -Amobee (http://www.amobee.com/) for sponsoring this release. Thanks to all who -contribute to Jython. +Welcome to Jython 2.7rc3! -Jython 2.7rc2 includes many bug fixes and code stabilization in prep for -release candidates. +This is the third release candidate of the 2.7 version of +Jython. Along with language and runtime compatibility with CPython +2.7, Jython 2.7rc3 provides substantial support of the Python +ecosystem. This includes built-in support of pip/setuptools (start +with bin/pip) and a native launcher for Windows (bin/jython.exe) means +that you can install scripts. -Please see the NEWS file for detailed release notes. +Jim Baker presented a talk at PyCon 2015 about Jython 2.7, including +demos of new features: https://www.youtube.com/watch?v=hLm3garVQFo -The release was compiled on OSX with JDK 7 and requires JDK 7 to run. +The release was compiled on OSX using JDK 7 and requires a minimum of +Java 7 to run. -Please try this out and report any bugs at http://bugs.jython.org. +Please try this release out and report any bugs at http://bugs.jython.org + +Pleae see ACKNOWLEDGMENTS for details about Jython's copyright, +license, contributors, and mailing lists; and NEWS for detailed +release notes, including bugs fixed, backwards breaking changes, and +new features. Thanks go to Amobee (http://www.amobee.com/) for +sponsoring this release. We also deeply thank all who contribute to +Jython, including - but not limited to - bug reports, patches, pull +requests, documentation changes, support emails, and fantastic +conversation on Freenode on #jython. -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Apr 21 01:36:04 2015 From: jython-checkins at python.org (jim.baker) Date: Mon, 20 Apr 2015 23:36:04 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Minor_doc_fixes?= Message-ID: <20150420233604.31113.4716@psf.io> https://hg.python.org/jython/rev/9b3e744fe773 changeset: 7690:9b3e744fe773 user: Jim Baker date: Mon Apr 20 17:35:59 2015 -0600 summary: Minor doc fixes files: README.txt | 11 ++++++----- 1 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -5,9 +5,10 @@ This is the third release candidate of the 2.7 version of Jython. Along with language and runtime compatibility with CPython 2.7, Jython 2.7rc3 provides substantial support of the Python -ecosystem. This includes built-in support of pip/setuptools (start -with bin/pip) and a native launcher for Windows (bin/jython.exe) means -that you can install scripts. +ecosystem. This includes built-in support of pip/setuptools (you can +use with bin/pip) and a native launcher for Windows (bin/jython.exe), +with the implication that you can finally install Jython scripts on +Windows. Jim Baker presented a talk at PyCon 2015 about Jython 2.7, including demos of new features: https://www.youtube.com/watch?v=hLm3garVQFo @@ -17,11 +18,11 @@ Please try this release out and report any bugs at http://bugs.jython.org -Pleae see ACKNOWLEDGMENTS for details about Jython's copyright, +Please see ACKNOWLEDGMENTS for details about Jython's copyright, license, contributors, and mailing lists; and NEWS for detailed release notes, including bugs fixed, backwards breaking changes, and new features. Thanks go to Amobee (http://www.amobee.com/) for sponsoring this release. We also deeply thank all who contribute to Jython, including - but not limited to - bug reports, patches, pull requests, documentation changes, support emails, and fantastic -conversation on Freenode on #jython. +conversation on Freenode at #jython. -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Apr 21 07:28:49 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Tue, 21 Apr 2015 05:28:49 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_version_for_rc3=2E?= Message-ID: <20150421052847.22472.77448@psf.io> https://hg.python.org/jython/rev/40ea8d57ec6a changeset: 7691:40ea8d57ec6a user: Frank Wierzbicki date: Tue Apr 21 05:28:44 2015 +0000 summary: Update version for rc3. files: build.xml | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -84,15 +84,15 @@ - - + + - + -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Apr 21 07:29:05 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Tue, 21 Apr 2015 05:29:05 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Added_tag_v2=2E7rc3_for_cha?= =?utf-8?q?ngeset_40ea8d57ec6a?= Message-ID: <20150421052905.21339.86588@psf.io> https://hg.python.org/jython/rev/8137061fe3cf changeset: 7692:8137061fe3cf user: Frank Wierzbicki date: Tue Apr 21 05:29:03 2015 +0000 summary: Added tag v2.7rc3 for changeset 40ea8d57ec6a files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -90,3 +90,4 @@ 2747ce30b81db7fd620c3aeb50ca3bfa362ac3c8 v2.7rc2 2747ce30b81db7fd620c3aeb50ca3bfa362ac3c8 v2.7rc2 0213400c518ff41ef5700d523b08d249d5a00585 v2.7rc2 +40ea8d57ec6aeb4ece0b874b0978edc5b84fa34f v2.7rc3 -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Apr 23 15:49:46 2015 From: jython-checkins at python.org (jim.baker) Date: Thu, 23 Apr 2015 13:49:46 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Sibling_relationship_with_C?= =?utf-8?q?Python_includes_use_and_derivation?= Message-ID: <20150423134944.98648.44140@psf.io> https://hg.python.org/jython/rev/cb13feb73a05 changeset: 7693:cb13feb73a05 user: Jim Baker date: Thu Apr 23 07:49:39 2015 -0600 summary: Sibling relationship with CPython includes use and derivation files: ACKNOWLEDGMENTS | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -44,6 +44,12 @@ then, Jython 2.x releases have corresponded to equivalent CPython 2.x releases. +Jython includes, modifying as necessary, the CPython standard library, +other code objects, in certain cases ported from C to either Python +and/or Java, and other components such as documentation. These +components are licensed, like Jython itself, under the Python Software +Foundation License version 2 from the Python Software Foundation. + Contacts: * Jython developers jython-dev at lists.sourceforge.net -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Apr 29 04:24:48 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Wed, 29 Apr 2015 02:24:48 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_version_info_for_rel?= =?utf-8?q?ease=2E?= Message-ID: <20150429022448.11940.1078@psf.io> https://hg.python.org/jython/rev/3a7bb3fb3338 changeset: 7694:3a7bb3fb3338 tag: v2.7.0 user: Frank Wierzbicki date: Wed Apr 29 02:24:21 2015 +0000 summary: Update version info for release. files: README.txt | 15 +++++++-------- build.xml | 8 ++++---- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -1,14 +1,13 @@ Jython: Python for the Java Platform -Welcome to Jython 2.7rc3! +Welcome to Jython 2.7.0! -This is the third release candidate of the 2.7 version of -Jython. Along with language and runtime compatibility with CPython -2.7, Jython 2.7rc3 provides substantial support of the Python -ecosystem. This includes built-in support of pip/setuptools (you can -use with bin/pip) and a native launcher for Windows (bin/jython.exe), -with the implication that you can finally install Jython scripts on -Windows. +This is the final release of the 2.7.0 version of Jython. Along with language +and runtime compatibility with CPython 2.7.0, Jython 2.7 provides substantial +support of the Python ecosystem. This includes built-in support of +pip/setuptools (you can use with bin/pip) and a native launcher for Windows +(bin/jython.exe), with the implication that you can finally install Jython +scripts on Windows. Jim Baker presented a talk at PyCon 2015 about Jython 2.7, including demos of new features: https://www.youtube.com/watch?v=hLm3garVQFo diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -84,15 +84,15 @@ - - + + - + - + -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Apr 29 04:24:48 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Wed, 29 Apr 2015 02:24:48 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Added_tag_v2=2E7=2E0_for_ch?= =?utf-8?q?angeset_3a7bb3fb3338?= Message-ID: <20150429022448.3475.45359@psf.io> https://hg.python.org/jython/rev/9987c746f838 changeset: 7695:9987c746f838 user: Frank Wierzbicki date: Wed Apr 29 02:24:55 2015 +0000 summary: Added tag v2.7.0 for changeset 3a7bb3fb3338 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -91,3 +91,4 @@ 2747ce30b81db7fd620c3aeb50ca3bfa362ac3c8 v2.7rc2 0213400c518ff41ef5700d523b08d249d5a00585 v2.7rc2 40ea8d57ec6aeb4ece0b874b0978edc5b84fa34f v2.7rc3 +3a7bb3fb3338964c70d3c734294bfc0f6bc37a3a v2.7.0 -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Apr 29 04:33:53 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Wed, 29 Apr 2015 02:33:53 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_note_that_JYTHON=5FHOME?= =?utf-8?q?_should_be_unset_to_install=2E?= Message-ID: <20150429023353.85191.39205@psf.io> https://hg.python.org/jython/rev/77e0e7c87bd1 changeset: 7696:77e0e7c87bd1 user: Frank Wierzbicki date: Wed Apr 29 02:33:54 2015 +0000 summary: Add note that JYTHON_HOME should be unset to install. files: README.txt | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -9,6 +9,9 @@ (bin/jython.exe), with the implication that you can finally install Jython scripts on Windows. +* Note that if you have JYTHON_HOME set, you should unset it to avoid problems +with the installer and pip/setuptools. + Jim Baker presented a talk at PyCon 2015 about Jython 2.7, including demos of new features: https://www.youtube.com/watch?v=hLm3garVQFo -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Apr 29 04:34:06 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Wed, 29 Apr 2015 02:34:06 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Added_tag_v2=2E7=2E0_for_ch?= =?utf-8?q?angeset_77e0e7c87bd1?= Message-ID: <20150429023406.62677.65746@psf.io> https://hg.python.org/jython/rev/412a8f9445f7 changeset: 7697:412a8f9445f7 user: Frank Wierzbicki date: Wed Apr 29 02:34:13 2015 +0000 summary: Added tag v2.7.0 for changeset 77e0e7c87bd1 files: .hgtags | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -92,3 +92,5 @@ 0213400c518ff41ef5700d523b08d249d5a00585 v2.7rc2 40ea8d57ec6aeb4ece0b874b0978edc5b84fa34f v2.7rc3 3a7bb3fb3338964c70d3c734294bfc0f6bc37a3a v2.7.0 +3a7bb3fb3338964c70d3c734294bfc0f6bc37a3a v2.7.0 +77e0e7c87bd15bad165cebdf8ac88dbae623f339 v2.7.0 -- Repository URL: https://hg.python.org/jython