[Jython-checkins] jython: Retain target file name, to be used in code objects if source not available
jim.baker
jython-checkins at python.org
Wed Dec 24 22:17:16 CET 2014
https://hg.python.org/jython/rev/ae190b66bf4c
changeset: 7470:ae190b66bf4c
user: Jim Baker <jim.baker at rackspace.com>
date: Wed Dec 24 14:17:00 2014 -0700
summary:
Retain target file name, to be used in code objects if source not available
If the compiled (*.py$class) file is available without the companion
source file, code objects when loaded now set co_filename to the
target filename originally associated with that file, regardless of
what the name of the file is now. Note as with CPython, modules can be
compiled with a different target filename than their source filename.
Bumps bytecode magic (org.python.core.imp.APIVersion) to 35. Adds a
new retained annotation, org.python.compiler.Filename, to annotate
compiled modules, as implemented using PyFunctionTable.
This change can be seen in the following decompilation of a compiled
Python module:
import org.python.compiler.*;
import org.python.core.*;
@APIVersion(35)
@MTime(1419447569000L)
@Filename("foo.py")
public class foo$py extends PyFunctionTable implements PyRunnable
{ ... }
Fixes the last failing test case in test_import, test_module_without_source
files:
src/org/python/compiler/ClassFile.java | 5 +-
src/org/python/compiler/Filename.java | 9 +
src/org/python/core/AnnotationReader.java | 14 ++-
src/org/python/core/imp.java | 63 +++++++++-
4 files changed, 78 insertions(+), 13 deletions(-)
diff --git a/src/org/python/compiler/ClassFile.java b/src/org/python/compiler/ClassFile.java
--- a/src/org/python/compiler/ClassFile.java
+++ b/src/org/python/compiler/ClassFile.java
@@ -189,7 +189,7 @@
av.visitEnd();
}
}
-
+
public void write(OutputStream stream) throws IOException {
cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, this.name, null, this.superclass, interfaces);
AnnotationVisitor av = cw.visitAnnotation("Lorg/python/compiler/APIVersion;", true);
@@ -203,6 +203,9 @@
av.visitEnd();
if (sfilename != null) {
+ av = cw.visitAnnotation("Lorg/python/compiler/Filename;", true);
+ av.visit("value", sfilename);
+ av.visitEnd();
cw.visitSource(sfilename, null);
}
endClassAnnotations();
diff --git a/src/org/python/compiler/Filename.java b/src/org/python/compiler/Filename.java
new file mode 100644
--- /dev/null
+++ b/src/org/python/compiler/Filename.java
@@ -0,0 +1,9 @@
+package org.python.compiler;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+ at Retention(RetentionPolicy.RUNTIME)
+public @interface Filename {
+ String value();
+}
diff --git a/src/org/python/core/AnnotationReader.java b/src/org/python/core/AnnotationReader.java
--- a/src/org/python/core/AnnotationReader.java
+++ b/src/org/python/core/AnnotationReader.java
@@ -24,9 +24,11 @@
private boolean nextVisitIsVersion = false;
private boolean nextVisitIsMTime = false;
+ private boolean nextVisitIsFilename = false;
private int version = -1;
private long mtime = -1;
+ private String filename = null;
/**
* Reads the classfile bytecode in data and to extract the version.
@@ -50,6 +52,7 @@
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
nextVisitIsVersion = desc.equals("Lorg/python/compiler/APIVersion;");
nextVisitIsMTime = desc.equals("Lorg/python/compiler/MTime;");
+ nextVisitIsFilename = desc.equals("Lorg/python/compiler/Filename;");
return new AnnotationVisitor(Opcodes.ASM4) {
public void visit(String name, Object value) {
@@ -58,8 +61,11 @@
nextVisitIsVersion = false;
} else if (nextVisitIsMTime) {
mtime = (Long)value;
- nextVisitIsVersion = false;
- }
+ nextVisitIsMTime = false;
+ } else if (nextVisitIsFilename) {
+ filename = (String)value;
+ nextVisitIsFilename = false;
+ }
}
};
}
@@ -71,4 +77,8 @@
public long getMTime() {
return mtime;
}
+
+ public String getFilename() {
+ return filename;
+ }
}
diff --git a/src/org/python/core/imp.java b/src/org/python/core/imp.java
--- a/src/org/python/core/imp.java
+++ b/src/org/python/core/imp.java
@@ -27,7 +27,7 @@
private static final String UNKNOWN_SOURCEFILE = "<unknown>";
- private static final int APIVersion = 34;
+ private static final int APIVersion = 35;
public static final int NO_MTIME = -1;
@@ -35,6 +35,34 @@
// imports unless `from __future__ import absolute_import`
public static final int DEFAULT_LEVEL = -1;
+ public static class CodeData {
+ private final byte[] bytes;
+ private final long mtime;
+ private final String filename;
+
+ public CodeData(byte[] bytes, long mtime, String filename) {
+ this.bytes = bytes;
+ this.mtime = mtime;
+ this.filename = filename;
+ }
+
+ public byte[] getBytes() {
+ return bytes;
+ }
+
+ public long getMTime() {
+ return mtime;
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+ }
+
+ public static enum CodeImport {
+ source, compiled_only;
+ }
+
/** A non-empty fromlist for __import__'ing sub-modules. */
private static final PyObject nonEmptyFromlist = new PyTuple(Py.newString("__doc__"));
@@ -174,9 +202,14 @@
static PyObject createFromPyClass(String name, InputStream fp, boolean testing,
String sourceName, String compiledName, long mtime) {
- byte[] data = null;
+ return createFromPyClass(name, fp, testing, sourceName, compiledName, mtime, CodeImport.source);
+ }
+
+ static PyObject createFromPyClass(String name, InputStream fp, boolean testing,
+ String sourceName, String compiledName, long mtime, CodeImport source) {
+ CodeData data = null;
try {
- data = readCode(name, fp, testing, mtime);
+ data = readCodeData(name, fp, testing, mtime);
} catch (IOException ioe) {
if (!testing) {
throw Py.ImportError(ioe.getMessage() + "[name=" + name + ", source=" + sourceName
@@ -188,7 +221,8 @@
}
PyCode code;
try {
- code = BytecodeLoader.makeCode(name + "$py", data, sourceName);
+ code = BytecodeLoader.makeCode(name + "$py", data.getBytes(),
+ source == CodeImport.compiled_only ? data.getFilename() : sourceName);
} catch (Throwable t) {
if (testing) {
return null;
@@ -199,7 +233,6 @@
Py.writeComment(IMPORT_LOG, String.format("import %s # precompiled from %s", name,
compiledName));
-
return createFromCode(name, code, compiledName);
}
@@ -208,6 +241,14 @@
}
public static byte[] readCode(String name, InputStream fp, boolean testing, long mtime) throws IOException {
+ return readCodeData(name, fp, testing, mtime).getBytes();
+ }
+
+ public static CodeData readCodeData(String name, InputStream fp, boolean testing) throws IOException {
+ return readCodeData(name, fp, testing, NO_MTIME);
+ }
+
+ public static CodeData readCodeData(String name, InputStream fp, boolean testing, long mtime) throws IOException {
byte[] data = readBytes(fp);
int api;
AnnotationReader ar = new AnnotationReader(data);
@@ -226,7 +267,7 @@
return null;
}
}
- return data;
+ return new CodeData(data, mtime, ar.getFilename());
}
public static byte[] compileSource(String name, File file) {
@@ -582,8 +623,9 @@
Py.writeDebug(IMPORT_LOG, "trying precompiled " + compiledFile.getPath());
long classTime = compiledFile.lastModified();
if (classTime >= pyTime) {
- PyObject ret = createFromPyClass(modName, makeStream(compiledFile), true,
- displaySourceName, displayCompiledName, pyTime);
+ PyObject ret = createFromPyClass(
+ modName, makeStream(compiledFile), true,
+ displaySourceName, displayCompiledName, pyTime);
if (ret != null) {
return ret;
}
@@ -598,8 +640,9 @@
// If no source, try loading precompiled
Py.writeDebug(IMPORT_LOG, "trying precompiled with no source " + compiledFile.getPath());
if (compiledFile.isFile() && caseok(compiledFile, compiledName)) {
- return createFromPyClass(modName, makeStream(compiledFile), true, displaySourceName,
- displayCompiledName);
+ return createFromPyClass(
+ modName, makeStream(compiledFile), true, displaySourceName,
+ displayCompiledName, NO_MTIME, CodeImport.compiled_only);
}
} catch (SecurityException e) {
// ok
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list