[Jython-checkins] jython (merge default -> default): Merge recent import-related fixes to trunk
jeff.allen
jython-checkins at python.org
Sun May 17 10:11:29 CEST 2015
https://hg.python.org/jython/rev/bb6cababa5bd
changeset: 7712:bb6cababa5bd
parent: 7706:bfa13b3a5553
parent: 7711:dccf5d04d58e
user: Jeff Allen <ja.py at farowl.co.uk>
date: Sun May 17 09:10:22 2015 +0100
summary:
Merge recent import-related fixes to trunk
files:
Lib/test/test_classpathimporter.py | 160 ++++++++-
Lib/test/test_support.py | 97 ++---
NEWS | 2 +
src/org/python/core/ClasspathPyImporter.java | 114 +++++++-
src/org/python/core/util/importer.java | 19 +-
src/org/python/modules/zipimport/zipimporter.java | 10 +-
6 files changed, 309 insertions(+), 93 deletions(-)
diff --git a/Lib/test/test_classpathimporter.py b/Lib/test/test_classpathimporter.py
--- a/Lib/test/test_classpathimporter.py
+++ b/Lib/test/test_classpathimporter.py
@@ -8,15 +8,15 @@
from test import test_support
from java.lang import Thread
+import pkgutil
+
class ClasspathImporterTestCase(unittest.TestCase):
def setUp(self):
self.orig_context = Thread.currentThread().contextClassLoader
- self.orig_path = sys.path
def tearDown(self):
Thread.currentThread().contextClassLoader = self.orig_context
- sys.path = self.orig_path
# I don't like the checked in jar file bug1239.jar. The *one* thing I
# liked about the tests in bugtests/ is that you could create a java file,
@@ -26,74 +26,174 @@
# with sys.path.append where not getting scanned if they start with a top
# level package we already have, like the "org" in org.python.*
def test_bug1239(self):
- sys.path.append("Lib/test/bug1239.jar")
- import org.test403javapackage.test403
+ with test_support.DirsOnSysPath("Lib/test/bug1239.jar"):
+ import org.test403javapackage.test403
# different from test_bug1239 in that only a Java package is imported, not
# a Java class. I'd also like to get rid of this checked in test jar.
def test_bug1126(self):
- sys.path.append("Lib/test/bug1126/bug1126.jar")
- import org.subpackage
+ with test_support.DirsOnSysPath("Lib/test/bug1126/bug1126.jar"):
+ import org.subpackage
class PyclasspathImporterTestCase(unittest.TestCase):
+ RESOURCE_DATA = "Always look\non the bright side\r\nof life."
+
def setUp(self):
self.orig_context = Thread.currentThread().contextClassLoader
- self.orig_path = sys.path
self.temp_dir = tempfile.mkdtemp()
self.modules = sys.modules.keys()
def tearDown(self):
Thread.currentThread().contextClassLoader = self.orig_context
- sys.path = self.orig_path
- shutil.rmtree(self.temp_dir)
for module in sys.modules.keys():
if module not in self.modules:
del sys.modules[module]
+ try:
+ shutil.rmtree(self.temp_dir)
+ except OSError:
+ # On Windows at least we cannot delete the open JAR
+ pass
- def setClassLoaderAndCheck(self, orig_jar, prefix, compile_path=''):
- # Create a new jar and compile prefer_compiled into it
+ def prepareJar(self, orig_jar):
+ # Create a new copy of the checked-in test jar
orig_jar = test_support.findfile(orig_jar)
jar = os.path.join(self.temp_dir, os.path.basename(orig_jar))
shutil.copy(orig_jar, jar)
+ return jar
- code = os.path.join(self.temp_dir, 'prefer_compiled.py')
- fp = open(code, 'w')
- fp.write('compiled = True')
- fp.close()
+ def compileToJar(self, jar, compile_path=''):
+ # Add a compiled version of prefer_compiled.py to the jar
+ source = 'prefer_compiled.py'
+ code = os.path.join(self.temp_dir, source)
+ with open(code, 'w') as fp:
+ fp.write('compiled = True')
+ # Compile that file
py_compile.compile(code)
- zip = zipfile.ZipFile(jar, 'a')
- zip.write(os.path.join(self.temp_dir, 'prefer_compiled$py.class'),
- os.path.join(compile_path, 'jar_pkg',
- 'prefer_compiled$py.class'))
- zip.close()
+ # Now add the compiled file to the jar
+ compiled = source.replace('.py', '$py.class')
+ with zipfile.ZipFile(jar, 'a') as zip:
+ zip.write(os.path.join(self.temp_dir, compiled),
+ os.path.join(compile_path, 'jar_pkg', compiled))
+ return compiled
- Thread.currentThread().contextClassLoader = test_support.make_jar_classloader(jar)
+ def addResourceToJar(self, jar, package='jar_pkg'):
+ name = 'testdata.dat'
+ with zipfile.ZipFile(jar, 'a') as zip:
+ zip.writestr(package + '/' + name, self.RESOURCE_DATA)
+ return name
+
+ def checkImports(self, prefix, compiled):
import flat_in_jar
self.assertEquals(flat_in_jar.value, 7)
import jar_pkg
self.assertEquals(prefix + '/jar_pkg/__init__.py', jar_pkg.__file__)
from jar_pkg import prefer_compiled
- self.assertEquals(prefix + '/jar_pkg/prefer_compiled$py.class', prefer_compiled.__file__)
+ self.assertEquals(prefix + '/jar_pkg/' + compiled, prefer_compiled.__file__)
self.assert_(prefer_compiled.compiled)
self.assertRaises(NameError, __import__, 'flat_bad')
self.assertRaises(NameError, __import__, 'jar_pkg.bad')
- @unittest.skip("FIXME: worked in Jython 2.5")
def test_default_pyclasspath(self):
- self.setClassLoaderAndCheck('classimport.jar', '__pyclasspath__')
+ jar = self.prepareJar('classimport.jar')
+ compiled = self.compileToJar(jar)
+ Thread.currentThread().contextClassLoader = test_support.make_jar_classloader(jar)
+ self.checkImports('__pyclasspath__', compiled)
- @unittest.skip("FIXME: worked in Jython 2.5")
def test_path_in_pyclasspath(self):
- sys.path = ['__pyclasspath__/Lib']
- self.setClassLoaderAndCheck('classimport_Lib.jar',
- '__pyclasspath__/Lib', 'Lib')
+ jar = self.prepareJar('classimport_Lib.jar')
+ compiled = self.compileToJar(jar, 'Lib')
+ Thread.currentThread().contextClassLoader = test_support.make_jar_classloader(jar)
+ with test_support.DirsOnSysPath():
+ sys.path = ['__pyclasspath__/Lib']
+ self.checkImports('__pyclasspath__/Lib', compiled)
+
+ def test_loader_is_package(self):
+ jar = self.prepareJar('classimport.jar')
+ Thread.currentThread().contextClassLoader = test_support.make_jar_classloader(jar)
+ mod_name = 'flat_in_jar'
+ loader = pkgutil.get_loader(mod_name)
+ self.assertFalse(loader.is_package(mod_name))
+ self.assertTrue(loader.is_package('jar_pkg'))
+ self.assertFalse(loader.is_package('jar_pkg.prefer_compiled'))
+
+ def test_loader_get_code(self):
+ # Execute Python code out of the JAR
+ jar = self.prepareJar('classimport.jar')
+ Thread.currentThread().contextClassLoader = test_support.make_jar_classloader(jar)
+ loader = pkgutil.get_loader('jar_pkg')
+ space = { 'value':None, 'compiled':None}
+
+ # flat_in_jar contains the assignment value = 7
+ code = loader.get_code('flat_in_jar')
+ exec code in space
+ self.assertEquals(space['value'], 7)
+
+ # jar_pkg.prefer_compiled contains the assignment compiled = False
+ code = loader.get_code('jar_pkg.prefer_compiled')
+ exec code in space
+ self.assertEquals(space['compiled'], False)
+
+ # Compile a new one containing the assignment compiled = True
+ self.compileToJar(jar)
+ code = loader.get_code('jar_pkg.prefer_compiled')
+ exec code in space
+ self.assertEquals(space['compiled'], True)
+
+ def test_pkgutil_get_data(self):
+ # Test loader.get_data used via pkgutil
+ jar = self.prepareJar('classimport.jar')
+ name = self.addResourceToJar(jar)
+ Thread.currentThread().contextClassLoader = test_support.make_jar_classloader(jar)
+ data = pkgutil.get_data('jar_pkg', name)
+ self.assertIsInstance(data, bytes)
+ self.assertEqual(data, self.RESOURCE_DATA)
+
+ def test_loader_get_data(self):
+ # Test loader.get_data used via pkgutil.get_loader
+ jar = self.prepareJar('classimport.jar')
+ name = self.addResourceToJar(jar)
+ Thread.currentThread().contextClassLoader = test_support.make_jar_classloader(jar)
+ loader = pkgutil.get_loader('jar_pkg')
+ # path is a resource path (not file system path using os.path.sep)
+ path = 'jar_pkg/' + name
+ data = loader.get_data(path)
+ self.assertIsInstance(data, bytes)
+ self.assertEqual(data, self.RESOURCE_DATA)
+
+ def test_importer_get_data(self):
+ # Test loader.get_data used via pkgutil.get_importer
+ jar = self.prepareJar('classimport.jar')
+ name = self.addResourceToJar(jar)
+ Thread.currentThread().contextClassLoader = test_support.make_jar_classloader(jar)
+ importer = pkgutil.get_importer('__pyclasspath__/')
+ # path is a resource path (may be file system path using os.path.sep)
+ path = os.path.join('jar_pkg', name)
+ data = importer.get_data(path)
+ self.assertIsInstance(data, bytes)
+ self.assertEqual(data, self.RESOURCE_DATA)
+ # Check works a second time (stream use internal to implementation)
+ data = importer.get_data(path)
+ self.assertEqual(data, self.RESOURCE_DATA)
+
+ def test_importer_get_source(self):
+ # Test loader.get_source used via pkgutil.get_importer
+ jar = self.prepareJar('classimport.jar')
+ Thread.currentThread().contextClassLoader = test_support.make_jar_classloader(jar)
+ importer = pkgutil.get_importer('__pyclasspath__/')
+ # In package
+ mod = 'jar_pkg.prefer_compiled'
+ source = importer.get_source(mod)
+ self.assertIsInstance(source, bytes)
+ self.assertEqual(source, 'compiled = False\n')
def test_main():
- test_support.run_unittest(ClasspathImporterTestCase,
- PyclasspathImporterTestCase)
+ test_support.run_unittest(
+ ClasspathImporterTestCase,
+ PyclasspathImporterTestCase
+ )
if __name__ == '__main__':
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py
--- a/Lib/test/test_support.py
+++ b/Lib/test/test_support.py
@@ -31,7 +31,6 @@
except ImportError:
thread = None
-
__all__ = ["Error", "TestFailed", "ResourceDenied", "import_module",
"verbose", "use_resources", "max_memuse", "record_original_stdout",
"get_original_stdout", "unload", "unlink", "rmtree", "forget",
@@ -58,7 +57,7 @@
"""Test skipped because it requested a disallowed resource.
This is raised when a test calls requires() for a resource that
- has not be enabled. It is used to distinguish between expected
+ has not been enabled. It is used to distinguish between expected
and unexpected skips.
"""
@@ -220,7 +219,6 @@
# Increase the timeout and try again
time.sleep(timeout)
timeout *= 2
- print "Still cannot delete", pathname
warnings.warn('tests may fail, delete still pending for ' + pathname,
RuntimeWarning, stacklevel=4)
@@ -291,7 +289,7 @@
possibility of False being returned occurs when regrtest.py is executing."""
# see if the caller's module is __main__ - if so, treat as if
# the resource was set
- if sys._getframe().f_back.f_globals.get("__name__") == "__main__":
+ if sys._getframe(1).f_globals.get("__name__") == "__main__":
return
if not is_resource_enabled(resource):
if msg is None:
@@ -469,30 +467,30 @@
# 2 latin characters.
TESTFN_UNICODE = unicode("@test-\xe0\xf2", "latin-1")
TESTFN_ENCODING = sys.getfilesystemencoding()
- # TESTFN_UNICODE_UNENCODEABLE is a filename that should *not* be
+ # TESTFN_UNENCODABLE is a filename that should *not* be
# able to be encoded by *either* the default or filesystem encoding.
# This test really only makes sense on Windows NT platforms
# which have special Unicode support in posixmodule.
if (not hasattr(sys, "getwindowsversion") or
sys.getwindowsversion()[3] < 2): # 0=win32s or 1=9x/ME
- TESTFN_UNICODE_UNENCODEABLE = None
+ TESTFN_UNENCODABLE = None
else:
# Japanese characters (I think - from bug 846133)
- TESTFN_UNICODE_UNENCODEABLE = eval('u"@test-\u5171\u6709\u3055\u308c\u308b"')
+ TESTFN_UNENCODABLE = eval('u"@test-\u5171\u6709\u3055\u308c\u308b"')
try:
# XXX - Note - should be using TESTFN_ENCODING here - but for
# Windows, "mbcs" currently always operates as if in
# errors=ignore' mode - hence we get '?' characters rather than
# the exception. 'Latin1' operates as we expect - ie, fails.
# See [ 850997 ] mbcs encoding ignores errors
- TESTFN_UNICODE_UNENCODEABLE.encode("Latin1")
+ TESTFN_UNENCODABLE.encode("Latin1")
except UnicodeEncodeError:
pass
else:
print \
'WARNING: The filename %r CAN be encoded by the filesystem. ' \
'Unicode filename tests may not be effective' \
- % TESTFN_UNICODE_UNENCODEABLE
+ % TESTFN_UNENCODABLE
# Make sure we can write to TESTFN, try in /tmp if we can't
fp = None
@@ -556,7 +554,6 @@
rmtree(name)
-
def findfile(file, here=__file__, subdir=None):
"""Try to find a file on sys.path and the working directory. If it is not
found the argument passed to the function is returned (this does not
@@ -572,30 +569,6 @@
if os.path.exists(fn): return fn
return file
-def verify(condition, reason='test failed'):
- """Verify that condition is true. If not, raise TestFailed.
-
- The optional argument reason can be given to provide
- a better error text.
- """
-
- if not condition:
- raise TestFailed(reason)
-
-def vereq(a, b):
- """Raise TestFailed if a == b is false.
-
- This is better than verify(a == b) because, in case of failure, the
- error message incorporates repr(a) and repr(b) so you can see the
- inputs.
-
- Note that "not (a == b)" isn't necessarily the same as "a != b"; the
- former is tested.
- """
-
- if not (a == b):
- raise TestFailed("%r == %r" % (a, b))
-
def sortdict(dict):
"Like repr(dict), but in sorted order."
items = dict.items()
@@ -617,12 +590,8 @@
unlink(TESTFN)
def check_syntax_error(testcase, statement):
- try:
- compile(statement, '<test string>', 'exec')
- except SyntaxError:
- pass
- else:
- testcase.fail('Missing SyntaxError: "%s"' % statement)
+ testcase.assertRaises(SyntaxError, compile, statement,
+ '<test string>', 'exec')
def open_urlresource(url, check=None):
import urlparse, urllib2
@@ -784,7 +753,7 @@
Use like this:
with CleanImport("foo"):
- __import__("foo") # new reference
+ importlib.import_module("foo") # new reference
"""
def __init__(self, *module_names):
@@ -854,6 +823,31 @@
os.environ = self._environ
+class DirsOnSysPath(object):
+ """Context manager to temporarily add directories to sys.path.
+
+ This makes a copy of sys.path, appends any directories given
+ as positional arguments, then reverts sys.path to the copied
+ settings when the context ends.
+
+ Note that *all* sys.path modifications in the body of the
+ context manager, including replacement of the object,
+ will be reverted at the end of the block.
+ """
+
+ def __init__(self, *paths):
+ self.original_value = sys.path[:]
+ self.original_object = sys.path
+ sys.path.extend(paths)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *ignore_exc):
+ sys.path = self.original_object
+ sys.path[:] = self.original_value
+
+
class TransientResource(object):
"""Raise ResourceDenied if an exception is raised while the context manager
@@ -946,17 +940,10 @@
socket.setdefaulttimeout(old_timeout)
-
@contextlib.contextmanager
def captured_output(stream_name):
- """Run the 'with' statement body using a StringIO object in place of a
- specific attribute on the sys module.
- Example use (with 'stream_name=stdout')::
-
- with captured_stdout() as s:
- print "hello"
- assert s.getvalue() == "hello"
- """
+ """Return a context manager used by captured_stdout and captured_stdin
+ that temporarily replaces the sys stream *stream_name* with a StringIO."""
import StringIO
orig_stdout = getattr(sys, stream_name)
setattr(sys, stream_name, StringIO.StringIO())
@@ -966,6 +953,12 @@
setattr(sys, stream_name, orig_stdout)
def captured_stdout():
+ """Capture the output of sys.stdout:
+
+ with captured_stdout() as s:
+ print "hello"
+ self.assertEqual(s.getvalue(), "hello")
+ """
return captured_output("stdout")
def captured_stderr():
@@ -1108,7 +1101,7 @@
# to make sure they work. We still want to avoid using
# too much memory, though, but we do that noisily.
maxsize = 5147
- self.failIf(maxsize * memuse + overhead > 20 * _1M)
+ self.assertFalse(maxsize * memuse + overhead > 20 * _1M)
else:
maxsize = int((max_memuse - overhead) / memuse)
if maxsize < minsize:
@@ -1168,7 +1161,6 @@
test(result)
return result
-
def _id(obj):
return obj
@@ -1219,7 +1211,6 @@
-
def _run_suite(suite):
"""Run tests from a unittest.TestSuite-derived class."""
if not junit_xml_dir:
diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,8 @@
- [ 2310 ] test_import runs on Windows (and passes with 4 skips).
- [ 2347 ] failures in test_import_pep328 when run with -m
- [ 2158, 2259 ] Fixed behaviour of relative from ... import *
+ - [ 1879 ] -m command now executes scripts from inside a jar file
+ - [ 2058 ] ClasspathPyImporter implements PEP 302 get_data (and others)
Jython 2.7rc3
Bugs fixed
diff --git a/src/org/python/core/ClasspathPyImporter.java b/src/org/python/core/ClasspathPyImporter.java
--- a/src/org/python/core/ClasspathPyImporter.java
+++ b/src/org/python/core/ClasspathPyImporter.java
@@ -1,10 +1,13 @@
/* Copyright (c) Jython Developers */
package org.python.core;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
+import org.python.core.util.FileUtil;
+import org.python.core.util.StringUtil;
import org.python.core.util.importer;
import org.python.expose.ExposedMethod;
import org.python.expose.ExposedNew;
@@ -41,6 +44,83 @@
}
/**
+ * Return the contents of the jarred file at the specified path
+ * as bytes.
+ *
+ * @param path a String path name within the archive
+ * @return a String of data in binary mode (no CRLF)
+ */
+ @Override
+ public String get_data(String path) {
+ return ClasspathPyImporter_get_data(path);
+ }
+
+ @ExposedMethod
+ final String ClasspathPyImporter_get_data(String path) {
+ // Strip any leading occurrence of the hook string
+ int len = PYCLASSPATH_PREFIX.length();
+ if (len < path.length() && path.startsWith(PYCLASSPATH_PREFIX)) {
+ path = path.substring(len);
+ }
+
+ // Bundle wraps the stream together with a close operation
+ try (Bundle bundle = makeBundle(path, makeEntry(path))) {
+ byte[] data = FileUtil.readBytes(bundle.inputStream);
+ return StringUtil.fromBytes(data);
+ } catch (IOException ioe) {
+ throw Py.IOError(ioe);
+ }
+ }
+
+ /**
+ * Return the source code for the module as a string (using
+ * newline characters for line endings)
+ *
+ * @param fullname the fully qualified name of the module
+ * @return a String of the module's source code or null
+ */
+ public String get_source(String fullname) {
+ return ClasspathPyImporter_get_source(fullname);
+ }
+
+ @ExposedMethod
+ final String ClasspathPyImporter_get_source(String fullname) {
+
+ ModuleInfo moduleInfo = getModuleInfo(fullname);
+
+ if (moduleInfo == ModuleInfo.ERROR) {
+ return null;
+
+ } else if (moduleInfo == ModuleInfo.NOT_FOUND) {
+ throw Py.ImportError(String.format("can't find module '%s'", fullname));
+
+ } else {
+ // Turn the module name into a source file name
+ String path = makeFilename(fullname);
+ if (moduleInfo == ModuleInfo.PACKAGE) {
+ path += File.separator + "__init__.py";
+ } else {
+ path += ".py";
+ }
+
+ // Bundle wraps the stream together with a close operation
+ try (Bundle bundle = makeBundle(path, makeEntry(path))) {
+ InputStream is = bundle.inputStream;
+ if (is != null) {
+ byte[] data = FileUtil.readBytes(is);
+ return StringUtil.fromBytes(data);
+ } else {
+ // we have the module, but no source
+ return null;
+ }
+ } catch (IOException ioe) {
+ throw Py.IOError(ioe);
+ }
+ }
+
+ }
+
+ /**
* Find the module for the fully qualified name.
*
* @param fullname the fully qualified name of the module
@@ -54,6 +134,32 @@
}
/**
+ * Determine whether a module is a package.
+ *
+ * @param fullname the fully qualified name of the module
+ * @return whether the module is a package
+ */
+ @ExposedMethod
+ final boolean ClasspathPyImporter_is_package(String fullname) {
+ return importer_is_package(fullname);
+ }
+
+ /**
+ * Return the code object associated with the module.
+ *
+ * @param fullname the fully qualified name of the module
+ * @return the module's PyCode object or None
+ */
+ @ExposedMethod
+ final PyObject ClasspathPyImporter_get_code(String fullname) {
+ ModuleCodeData moduleCodeData = getModuleCode(fullname);
+ if (moduleCodeData != null) {
+ return moduleCodeData.code;
+ }
+ return Py.None;
+ }
+
+ /**
* Load a module for the fully qualified name.
*
* @param fullname the fully qualified name of the module
@@ -87,14 +193,18 @@
@Override
protected String makeEntry(String filename) {
+ // In some contexts, the resource string arrives as from os.path.join(*parts)
+ if (!getSeparator().equals(File.separator)) {
+ filename = filename.replace(File.separator, getSeparator());
+ }
if (entries.containsKey(filename)) {
return filename;
}
InputStream is;
if (Py.getSystemState().getClassLoader() != null) {
- is = tryClassLoader(filename, Py.getSystemState().getClassLoader(), "sys");
+ is = tryClassLoader(filename, Py.getSystemState().getClassLoader(), "sys");
} else {
- is = tryClassLoader(filename, imp.getParentClassLoader(), "parent");
+ is = tryClassLoader(filename, imp.getParentClassLoader(), "parent");
}
if (is != null) {
entries.put(filename, is);
diff --git a/src/org/python/core/util/importer.java b/src/org/python/core/util/importer.java
--- a/src/org/python/core/util/importer.java
+++ b/src/org/python/core/util/importer.java
@@ -4,6 +4,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.EnumSet;
+
import org.python.core.BytecodeLoader;
import org.python.core.Py;
import org.python.core.PyCode;
@@ -40,6 +41,11 @@
}
/**
+ * Return the bytes for the data located at <code>path</code>.
+ */
+ public abstract String get_data(String path);
+
+ /**
* Returns the separator between directories and files used by this type of importer.
*/
protected abstract String getSeparator();
@@ -112,10 +118,20 @@
}
/**
+ * @param fullname
+ * the fully qualified name of the module
+ * @return whether the module is a package
+ */
+ protected final boolean importer_is_package(String fullname) {
+ ModuleInfo info = getModuleInfo(fullname);
+ return info == ModuleInfo.PACKAGE;
+ }
+
+ /**
* Bundle is an InputStream, bundled together with a method that can close the input stream and
* whatever resources are associated with it when the resource is imported.
*/
- protected abstract static class Bundle {
+ protected abstract static class Bundle implements AutoCloseable {
public InputStream inputStream;
public Bundle(InputStream inputStream) {
@@ -125,6 +141,7 @@
/**
* Close the underlying resource if necessary. Raises an IOError if a problem occurs.
*/
+ @Override
public abstract void close();
}
diff --git a/src/org/python/modules/zipimport/zipimporter.java b/src/org/python/modules/zipimport/zipimporter.java
--- a/src/org/python/modules/zipimport/zipimporter.java
+++ b/src/org/python/modules/zipimport/zipimporter.java
@@ -165,11 +165,12 @@
/**
* Return the uncompressed data for the file at the specified path
- * as a String.
+ * as bytes.
*
* @param path a String path name within the archive
* @return a String of data in binary mode (no CRLF)
*/
+ @Override
public String get_data(String path) {
return zipimporter_get_data(path);
}
@@ -280,12 +281,7 @@
}
PyObject tocEntry = files.__finditem__(path);
- if (tocEntry != null) {
- return get_data(path);
- }
-
- // we have the module, but no source
- return null;
+ return (tocEntry == null) ? null : get_data(path);
}
/**
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list