From: <pj...@us...> - 2008-11-24 02:02:51
|
Revision: 5626 http://jython.svn.sourceforge.net/jython/?rev=5626&view=rev Author: pjenvey Date: 2008-11-24 02:02:47 +0000 (Mon, 24 Nov 2008) Log Message: ----------- add an isBaseType flag to @ExposedType for toggling whether types are subclassable. disallow subclassing of builtin_function_or_method (fixes test_descr.errors). note that this requires an ant clean refs #1758319 Modified Paths: -------------- trunk/jython/Lib/test/test_descr.py trunk/jython/src/org/python/core/Py.java trunk/jython/src/org/python/core/PyBuiltinCallable.java trunk/jython/src/org/python/core/PySystemState.java trunk/jython/src/org/python/core/PyType.java trunk/jython/src/org/python/expose/BaseTypeBuilder.java trunk/jython/src/org/python/expose/ExposedType.java trunk/jython/src/org/python/expose/TypeBuilder.java trunk/jython/src/org/python/expose/generate/ExposedTypeProcessor.java trunk/jython/src/org/python/expose/generate/ExposedTypeVisitor.java trunk/jython/src/org/python/expose/generate/TypeExposer.java trunk/jython/tests/java/org/python/expose/generate/ExposedTypeVisitorTest.java trunk/jython/tests/java/org/python/expose/generate/SimpleExposed.java trunk/jython/tests/java/org/python/expose/generate/TypeExposerTest.java Modified: trunk/jython/Lib/test/test_descr.py =================================================================== --- trunk/jython/Lib/test/test_descr.py 2008-11-24 01:57:05 UTC (rev 5625) +++ trunk/jython/Lib/test/test_descr.py 2008-11-24 02:02:47 UTC (rev 5626) @@ -4404,11 +4404,6 @@ classmethods_in_c, staticmethods_in_c, - # Jython allows subclassing of classes it shouldn't (like - # builtin_function_or_method): - # http://bugs.jython.org/issue1758319 - errors, - # CPython's unicode.__cmp__ is derived from type (and only # takes 1 arg) specials, Modified: trunk/jython/src/org/python/core/Py.java =================================================================== --- trunk/jython/src/org/python/core/Py.java 2008-11-24 01:57:05 UTC (rev 5625) +++ trunk/jython/src/org/python/core/Py.java 2008-11-24 02:02:47 UTC (rev 5626) @@ -82,7 +82,9 @@ /** A Python string containing ' ' **/ public static PyString Space; /** Set if the type object is dynamically allocated */ - public static long TPFLAGS_HEAPTYPE; + public static long TPFLAGS_HEAPTYPE = 1L << 9; + /** Set if the type allows subclassing */ + public static long TPFLAGS_BASETYPE = 1L << 10; /** Builtin types that are used to setup PyObject. */ static final Set<Class> BOOTSTRAP_TYPES = new HashSet<Class>(4); Modified: trunk/jython/src/org/python/core/PyBuiltinCallable.java =================================================================== --- trunk/jython/src/org/python/core/PyBuiltinCallable.java 2008-11-24 01:57:05 UTC (rev 5625) +++ trunk/jython/src/org/python/core/PyBuiltinCallable.java 2008-11-24 02:02:47 UTC (rev 5626) @@ -3,8 +3,7 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedType; -// XXX: not subclassable -@ExposedType(name = "builtin_function_or_method") +@ExposedType(name = "builtin_function_or_method", isBaseType = false) public abstract class PyBuiltinCallable extends PyObject { protected Info info; Modified: trunk/jython/src/org/python/core/PySystemState.java =================================================================== --- trunk/jython/src/org/python/core/PySystemState.java 2008-11-24 01:57:05 UTC (rev 5625) +++ trunk/jython/src/org/python/core/PySystemState.java 2008-11-24 02:02:47 UTC (rev 5626) @@ -589,8 +589,6 @@ Py.Newline = new PyString("\n"); Py.Space = new PyString(" "); - Py.TPFLAGS_HEAPTYPE = (1L<<9); - // Setup standard wrappers for stdout and stderr... Py.stderr = new StderrWrapper(); Py.stdout = new StdoutWrapper(); Modified: trunk/jython/src/org/python/core/PyType.java =================================================================== --- trunk/jython/src/org/python/core/PyType.java 2008-11-24 01:57:05 UTC (rev 5625) +++ trunk/jython/src/org/python/core/PyType.java 2008-11-24 02:02:47 UTC (rev 5626) @@ -58,6 +58,9 @@ boolean has_set; boolean has_delete; + /** Whether this type allows subclassing. */ + private boolean isBaseType = true; + /** Whether finalization is required for this type's instances (implements __del__). */ private boolean needs_finalizer; @@ -134,7 +137,6 @@ bases_list = new PyObject[] {object_type}; } - // XXX can be subclassed ? if (dict.__finditem__("__module__") == null) { PyFrame frame = Py.getFrame(); if (frame != null) { @@ -164,6 +166,11 @@ newtype.numSlots = newtype.base.numSlots; newtype.bases = bases_list; + if (!newtype.base.isBaseType) { + throw Py.TypeError(String.format("type '%.100s' is not an acceptable base type", + newtype.base.name)); + } + PyObject slots = dict.__finditem__("__slots__"); boolean needsDictDescr = false; if (slots == null) { @@ -209,7 +216,7 @@ } } - newtype.tp_flags = Py.TPFLAGS_HEAPTYPE; + newtype.tp_flags = Py.TPFLAGS_HEAPTYPE | Py.TPFLAGS_BASETYPE; // special case __new__, if function => static method PyObject tmp = dict.__finditem__("__new__"); @@ -420,6 +427,11 @@ } + private void setIsBaseType(boolean isBaseType) { + this.isBaseType = isBaseType; + tp_flags = isBaseType ? tp_flags | Py.TPFLAGS_BASETYPE : tp_flags & ~Py.TPFLAGS_BASETYPE; + } + private void mro_internal() { if (getType() == TYPE) { mro = compute_mro(); @@ -891,6 +903,7 @@ PyType objType = fromClass(builder.getTypeClass()); objType.name = builder.getName(); objType.dict = builder.getDict(objType); + objType.setIsBaseType(builder.getIsBaseType()); Class<?> base = builder.getBase(); if (base == Object.class) { base = forClass.getSuperclass(); @@ -907,17 +920,19 @@ return exposedAs; } Class<?> base = null; + boolean isBaseType = true; String name = null; TypeBuilder tb = getBuilder(c); if (tb != null) { name = tb.getName(); + isBaseType = tb.getIsBaseType(); if (!tb.getBase().equals(Object.class)) { base = tb.getBase(); } } PyType type = class_to_type.get(c); if (type == null) { - type = createType(c, base, name); + type = createType(c, base, name, isBaseType); } return type; } @@ -926,7 +941,7 @@ return classToBuilder == null ? null : classToBuilder.get(c); } - private static PyType createType(Class<?> c, Class<?> base, String name) { + private static PyType createType(Class<?> c, Class<?> base, String name, boolean isBaseType) { PyType newtype; if (c == PyType.class) { newtype = new PyType(false); @@ -955,6 +970,7 @@ newtype.name = name; newtype.underlying_class = c; newtype.builtin = true; + newtype.setIsBaseType(isBaseType); fillInMRO(newtype, base); // basic mro, base, bases newtype.fillDict(); return newtype; Modified: trunk/jython/src/org/python/expose/BaseTypeBuilder.java =================================================================== --- trunk/jython/src/org/python/expose/BaseTypeBuilder.java 2008-11-24 01:57:05 UTC (rev 5625) +++ trunk/jython/src/org/python/expose/BaseTypeBuilder.java 2008-11-24 02:02:47 UTC (rev 5626) @@ -22,14 +22,18 @@ private String name; + private boolean isBaseType; + public BaseTypeBuilder(String name, Class typeClass, Class baseClass, + boolean isBaseType, PyBuiltinMethod[] meths, PyDataDescr[] descrs, PyNewWrapper newWrapper) { this.typeClass = typeClass; this.baseClass = baseClass; + this.isBaseType = isBaseType; this.name = name; this.descrs = descrs; this.meths = meths; @@ -64,4 +68,8 @@ public Class getBase() { return baseClass; } -} \ No newline at end of file + + public boolean getIsBaseType() { + return isBaseType; + } +} Modified: trunk/jython/src/org/python/expose/ExposedType.java =================================================================== --- trunk/jython/src/org/python/expose/ExposedType.java 2008-11-24 01:57:05 UTC (rev 5625) +++ trunk/jython/src/org/python/expose/ExposedType.java 2008-11-24 02:02:47 UTC (rev 5626) @@ -26,4 +26,9 @@ * unspecified, the base is set to object, or PyObject.class. */ Class base() default Object.class; + + /** + * @return Whether this type allows subclassing. + */ + boolean isBaseType() default true; } Modified: trunk/jython/src/org/python/expose/TypeBuilder.java =================================================================== --- trunk/jython/src/org/python/expose/TypeBuilder.java 2008-11-24 01:57:05 UTC (rev 5625) +++ trunk/jython/src/org/python/expose/TypeBuilder.java 2008-11-24 02:02:47 UTC (rev 5626) @@ -15,4 +15,6 @@ public Class getTypeClass(); public Class getBase(); + + public boolean getIsBaseType(); } Modified: trunk/jython/src/org/python/expose/generate/ExposedTypeProcessor.java =================================================================== --- trunk/jython/src/org/python/expose/generate/ExposedTypeProcessor.java 2008-11-24 01:57:05 UTC (rev 5625) +++ trunk/jython/src/org/python/expose/generate/ExposedTypeProcessor.java 2008-11-24 02:02:47 UTC (rev 5626) @@ -109,6 +109,8 @@ private Type baseType = OBJECT; + private boolean isBaseType = true; + private boolean generatedStaticBlock; private TypeProcessor(ClassVisitor cv) { @@ -140,6 +142,10 @@ public void handleResult(Type base) { baseType = base; } + + public void handleResult(boolean boolIsBaseType) { + isBaseType = boolIsBaseType; + } }; } return super.visitAnnotation(desc, visible); @@ -158,6 +164,7 @@ } typeExposer = new TypeExposer(onType, baseType, + isBaseType, getName(), methodExposers, descExposers.values(), Modified: trunk/jython/src/org/python/expose/generate/ExposedTypeVisitor.java =================================================================== --- trunk/jython/src/org/python/expose/generate/ExposedTypeVisitor.java 2008-11-24 01:57:05 UTC (rev 5625) +++ trunk/jython/src/org/python/expose/generate/ExposedTypeVisitor.java 2008-11-24 02:02:47 UTC (rev 5626) @@ -13,6 +13,8 @@ private Type base = Type.getType(Object.class); + private boolean isBaseType = true; + public ExposedTypeVisitor(Type onType) { this.onType = onType; } @@ -23,6 +25,8 @@ typeName = (String)value; } else if(name.equals("base")) { base = (Type)value; + } else if(name.equals("isBaseType")) { + isBaseType = (Boolean)value; } else { super.visit(name, value); } @@ -36,10 +40,13 @@ } handleResult(typeName); handleResult(base); + handleResult(isBaseType); } public abstract void handleResult(Type base); + public abstract void handleResult(boolean isBaseType); + /** * @param name - * the name the type should be exposed as from the annotation. Modified: trunk/jython/src/org/python/expose/generate/TypeExposer.java =================================================================== --- trunk/jython/src/org/python/expose/generate/TypeExposer.java 2008-11-24 01:57:05 UTC (rev 5625) +++ trunk/jython/src/org/python/expose/generate/TypeExposer.java 2008-11-24 02:02:47 UTC (rev 5626) @@ -18,6 +18,8 @@ private Type baseType; + private boolean isBaseType; + private Type onType; private String name; @@ -32,12 +34,14 @@ public TypeExposer(Type onType, Type baseType, + boolean isBaseType, String name, Collection<MethodExposer> methods, Collection<DescriptorExposer> descriptors, Exposer ne) { super(BaseTypeBuilder.class, makeGeneratedName(onType)); this.baseType = baseType; + this.isBaseType = isBaseType; this.onType = onType; this.name = name; this.methods = methods; @@ -101,6 +105,7 @@ mv.visitLdcInsn(getName()); mv.visitLdcInsn(onType); mv.visitLdcInsn(baseType); + mv.visitLdcInsn(isBaseType); mv.visitLdcInsn(numNames); mv.visitTypeInsn(ANEWARRAY, BUILTIN_METHOD.getInternalName()); mv.visitVarInsn(ASTORE, 1); @@ -135,7 +140,8 @@ } else { mv.visitInsn(ACONST_NULL); } - superConstructor(STRING, CLASS, CLASS, ABUILTIN_METHOD, ADATA_DESCR, PYNEWWRAPPER); + superConstructor(STRING, CLASS, CLASS, BOOLEAN, ABUILTIN_METHOD, ADATA_DESCR, + PYNEWWRAPPER); endConstructor(); } } Modified: trunk/jython/tests/java/org/python/expose/generate/ExposedTypeVisitorTest.java =================================================================== --- trunk/jython/tests/java/org/python/expose/generate/ExposedTypeVisitorTest.java 2008-11-24 01:57:05 UTC (rev 5625) +++ trunk/jython/tests/java/org/python/expose/generate/ExposedTypeVisitorTest.java 2008-11-24 02:02:47 UTC (rev 5626) @@ -20,6 +20,11 @@ public void handleResult(Type base) { baseResult = base; } + + @Override + public void handleResult(boolean isBaseType) { + isBaseTypeResult = isBaseType; + } }; } @@ -32,9 +37,11 @@ public void testNamedType() { etv.visit("name", "different"); etv.visit("base", Type.getType(PyObject.class)); + etv.visit("isBaseType", false); etv.visitEnd(); assertEquals("different", result); assertEquals(Type.getType(PyObject.class), baseResult); + assertEquals(false, isBaseTypeResult); } ExposedTypeVisitor etv; @@ -42,4 +49,6 @@ private String result; private Type baseResult; + + private boolean isBaseTypeResult; } Modified: trunk/jython/tests/java/org/python/expose/generate/SimpleExposed.java =================================================================== --- trunk/jython/tests/java/org/python/expose/generate/SimpleExposed.java 2008-11-24 01:57:05 UTC (rev 5625) +++ trunk/jython/tests/java/org/python/expose/generate/SimpleExposed.java 2008-11-24 02:02:47 UTC (rev 5626) @@ -15,7 +15,7 @@ import org.python.expose.ExposedType; import org.python.expose.MethodType; -@ExposedType(name = "simpleexposed") +@ExposedType(name = "simpleexposed", isBaseType = false) public class SimpleExposed extends PyObject { public void method() {} @@ -145,4 +145,4 @@ public String toStringVal = TO_STRING_RETURN; public static final String TO_STRING_RETURN = "A simple test class"; -} \ No newline at end of file +} Modified: trunk/jython/tests/java/org/python/expose/generate/TypeExposerTest.java =================================================================== --- trunk/jython/tests/java/org/python/expose/generate/TypeExposerTest.java 2008-11-24 01:57:05 UTC (rev 5625) +++ trunk/jython/tests/java/org/python/expose/generate/TypeExposerTest.java 2008-11-24 02:02:47 UTC (rev 5626) @@ -22,6 +22,7 @@ TypeBuilder t = etp.getTypeExposer().makeBuilder(); assertEquals("simpleexposed", t.getName()); assertEquals(SimpleExposed.class, t.getTypeClass()); + assertEquals(false, t.getIsBaseType()); PyType type = PyType.fromClass(SimpleExposed.class); PyObject dict = t.getDict(type); assertNotNull(dict.__finditem__("simple_method")); @@ -36,6 +37,7 @@ ExposedTypeProcessor etp = new ExposedTypeProcessor(getClass().getClassLoader() .getResourceAsStream("org/python/expose/generate/TypeExposerTest$SimplestNew.class")); TypeBuilder te = etp.getTypeExposer().makeBuilder(); + assertEquals(true, te.getIsBaseType()); PyObject new_ = te.getDict(PyType.fromClass(SimplestNew.class)).__finditem__("__new__"); assertEquals(Py.One, new_.__call__(PyType.fromClass(SimplestNew.class))); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |