Commit 26587156 authored by Marius Wachtler's avatar Marius Wachtler

Merge pull request #1061 from corona10/subclass

Add list of not subclassable class
parents 189c7ac1 fc5bd373
......@@ -1850,7 +1850,7 @@ void setupBuiltins() {
"Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is "
"the `nil' object; Ellipsis represents `...' in slices.");
ellipsis_cls = BoxedClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(Box), false, "ellipsis");
ellipsis_cls = BoxedClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(Box), false, "ellipsis", false);
ellipsis_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)ellipsisRepr, STR, 1)));
Ellipsis = new (ellipsis_cls) Box();
assert(Ellipsis->cls);
......
......@@ -1642,10 +1642,12 @@ extern "C" PyObject* PyMethod_Class(PyObject* im) noexcept {
}
void setupClassobj() {
classobj_cls = BoxedClass::create(type_cls, object_cls, &BoxedClassobj::gcHandler, offsetof(BoxedClassobj, attrs),
offsetof(BoxedClassobj, weakreflist), sizeof(BoxedClassobj), false, "classobj");
instance_cls = BoxedClass::create(type_cls, object_cls, &BoxedInstance::gcHandler, offsetof(BoxedInstance, attrs),
offsetof(BoxedInstance, weakreflist), sizeof(BoxedInstance), false, "instance");
classobj_cls
= BoxedClass::create(type_cls, object_cls, &BoxedClassobj::gcHandler, offsetof(BoxedClassobj, attrs),
offsetof(BoxedClassobj, weakreflist), sizeof(BoxedClassobj), false, "classobj", false);
instance_cls
= BoxedClass::create(type_cls, object_cls, &BoxedInstance::gcHandler, offsetof(BoxedInstance, attrs),
offsetof(BoxedInstance, weakreflist), sizeof(BoxedInstance), false, "instance", false);
classobj_cls->giveAttr("__new__",
new BoxedFunction(FunctionMetadata::create((void*)classobjNew, UNKNOWN, 4, false, false)));
......
......@@ -116,7 +116,8 @@ extern "C" int PyCode_GetArgCount(PyCodeObject* op) noexcept {
}
void setupCode() {
code_cls = BoxedClass::create(type_cls, object_cls, &BoxedCode::gcHandler, 0, 0, sizeof(BoxedCode), false, "code");
code_cls = BoxedClass::create(type_cls, object_cls, &BoxedCode::gcHandler, 0, 0, sizeof(BoxedCode), false, "code",
false);
code_cls->giveAttr("__new__", None); // Hacky way of preventing users from instantiating this
......
......@@ -171,8 +171,8 @@ extern "C" PyFrameObject* PyFrame_ForStackLevel(int stack_level) noexcept {
}
void setupFrame() {
frame_cls
= BoxedClass::create(type_cls, object_cls, &BoxedFrame::gchandler, 0, 0, sizeof(BoxedFrame), false, "frame");
frame_cls = BoxedClass::create(type_cls, object_cls, &BoxedFrame::gchandler, 0, 0, sizeof(BoxedFrame), false,
"frame", false);
frame_cls->tp_dealloc = BoxedFrame::simpleDestructor;
frame_cls->has_safe_tp_dealloc = true;
......
......@@ -481,7 +481,7 @@ void generatorDestructor(Box* b) {
void setupGenerator() {
generator_cls
= BoxedClass::create(type_cls, object_cls, &BoxedGenerator::gcHandler, 0, offsetof(BoxedGenerator, weakreflist),
sizeof(BoxedGenerator), false, "generator");
sizeof(BoxedGenerator), false, "generator", false);
generator_cls->tp_dealloc = generatorDestructor;
generator_cls->has_safe_tp_dealloc = true;
generator_cls->giveAttr(
......
......@@ -243,9 +243,9 @@ Box* xrangeReduce(Box* self) {
}
void setupXrange() {
xrange_cls = BoxedClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedXrange), false, "xrange");
xrange_cls = BoxedClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedXrange), false, "xrange", false);
xrange_iterator_cls = BoxedClass::create(type_cls, object_cls, &BoxedXrangeIterator::gcHandler, 0, 0,
sizeof(BoxedXrangeIterator), false, "rangeiterator");
sizeof(BoxedXrangeIterator), false, "rangeiterator", false);
static PySequenceMethods xrange_as_sequence;
xrange_cls->tp_as_sequence = &xrange_as_sequence;
......
......@@ -210,7 +210,7 @@ llvm_compat_bool calliterHasnextUnboxed(Box* b) {
void setupIter() {
seqiter_cls = BoxedClass::create(type_cls, object_cls, &BoxedSeqIter::gcHandler, 0, 0, sizeof(BoxedSeqIter), false,
"iterator");
"iterator", false);
seqiter_cls->giveAttr("next", new BoxedFunction(FunctionMetadata::create((void*)seqiterNext, UNKNOWN, 1)));
seqiter_cls->giveAttr("__hasnext__",
......
......@@ -1295,7 +1295,7 @@ void setupList() {
list_cls->tp_as_mapping = &list_as_mapping;
list_iterator_cls = BoxedClass::create(type_cls, object_cls, &BoxedListIterator::gcHandler, 0, 0,
sizeof(BoxedListIterator), false, "listiterator");
sizeof(BoxedListIterator), false, "listiterator", false);
list_reverse_iterator_cls = BoxedClass::create(type_cls, object_cls, &BoxedListIterator::gcHandler, 0, 0,
sizeof(BoxedListIterator), false, "listreverseiterator");
list_iterator_cls->instances_are_nonzero = list_reverse_iterator_cls->instances_are_nonzero = true;
......
......@@ -399,7 +399,7 @@ void BoxedClass::freeze() {
}
BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int weaklist_offset,
int instance_size, bool is_user_defined, const char* name)
int instance_size, bool is_user_defined, const char* name, bool is_subclassable)
: attrs(HiddenClass::makeSingleton()),
gc_visit(gc_visit),
attrs_offset(attrs_offset),
......@@ -418,7 +418,8 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
tp_flags |= Py_TPFLAGS_DEFAULT_CORE;
tp_flags |= Py_TPFLAGS_CHECKTYPES;
tp_flags |= Py_TPFLAGS_BASETYPE;
if (is_subclassable)
tp_flags |= Py_TPFLAGS_BASETYPE;
tp_flags |= Py_TPFLAGS_HAVE_GC;
if (base && (base->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER))
......@@ -496,10 +497,11 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
}
BoxedClass* BoxedClass::create(BoxedClass* metaclass, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
int weaklist_offset, int instance_size, bool is_user_defined, const char* name) {
int weaklist_offset, int instance_size, bool is_user_defined, const char* name,
bool is_subclassable) {
assert(!is_user_defined);
BoxedClass* made = new (metaclass, 0)
BoxedClass(base, gc_visit, attrs_offset, weaklist_offset, instance_size, is_user_defined, name);
BoxedClass* made = new (metaclass, 0) BoxedClass(base, gc_visit, attrs_offset, weaklist_offset, instance_size,
is_user_defined, name, is_subclassable);
// While it might be ok if these were set, it'd indicate a difference in
// expectations as to who was going to calculate them:
......
......@@ -2805,7 +2805,7 @@ void setupStr() {
str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
str_iterator_cls = BoxedClass::create(type_cls, object_cls, &BoxedStringIterator::gcHandler, 0, 0,
sizeof(BoxedStringIterator), false, "striterator");
sizeof(BoxedStringIterator), false, "striterator", false);
str_iterator_cls->giveAttr(
"__hasnext__", new BoxedFunction(FunctionMetadata::create((void*)BoxedStringIterator::hasnext, BOXED_BOOL, 1)));
str_iterator_cls->giveAttr(
......
......@@ -3705,17 +3705,17 @@ void setupRuntime() {
sizeof(BoxedFile), false, "file");
int_cls = new (0) BoxedClass(object_cls, NULL, 0, 0, sizeof(BoxedInt), false, "int");
int_cls->tp_flags |= Py_TPFLAGS_INT_SUBCLASS;
bool_cls = new (0) BoxedClass(int_cls, NULL, 0, 0, sizeof(BoxedBool), false, "bool");
bool_cls = new (0) BoxedClass(int_cls, NULL, 0, 0, sizeof(BoxedBool), false, "bool", false);
complex_cls = new (0) BoxedClass(object_cls, NULL, 0, 0, sizeof(BoxedComplex), false, "complex");
long_cls = new (0) BoxedClass(object_cls, &BoxedLong::gchandler, 0, 0, sizeof(BoxedLong), false, "long");
long_cls->tp_flags |= Py_TPFLAGS_LONG_SUBCLASS;
float_cls = new (0) BoxedClass(object_cls, NULL, 0, 0, sizeof(BoxedFloat), false, "float");
function_cls = new (0)
BoxedClass(object_cls, &BoxedFunction::gcHandler, offsetof(BoxedFunction, attrs),
offsetof(BoxedFunction, in_weakreflist), sizeof(BoxedFunction), false, "function");
offsetof(BoxedFunction, in_weakreflist), sizeof(BoxedFunction), false, "function", false);
builtin_function_or_method_cls = new (0)
BoxedClass(object_cls, &BoxedFunction::gcHandler, 0, offsetof(BoxedBuiltinFunctionOrMethod, in_weakreflist),
sizeof(BoxedBuiltinFunctionOrMethod), false, "builtin_function_or_method");
sizeof(BoxedBuiltinFunctionOrMethod), false, "builtin_function_or_method", false);
function_cls->tp_dealloc = builtin_function_or_method_cls->tp_dealloc = functionDtor;
function_cls->has_safe_tp_dealloc = builtin_function_or_method_cls->has_safe_tp_dealloc = true;
......@@ -3833,10 +3833,10 @@ void setupRuntime() {
instancemethod_cls = BoxedClass::create(type_cls, object_cls, &BoxedInstanceMethod::gcHandler, 0,
offsetof(BoxedInstanceMethod, in_weakreflist), sizeof(BoxedInstanceMethod),
false, "instancemethod");
false, "instancemethod", false);
slice_cls
= BoxedClass::create(type_cls, object_cls, &BoxedSlice::gcHandler, 0, 0, sizeof(BoxedSlice), false, "slice");
slice_cls = BoxedClass::create(type_cls, object_cls, &BoxedSlice::gcHandler, 0, 0, sizeof(BoxedSlice), false,
"slice", false);
set_cls = BoxedClass::create(type_cls, object_cls, &BoxedSet::gcHandler, 0, offsetof(BoxedSet, weakreflist),
sizeof(BoxedSet), false, "set");
frozenset_cls = BoxedClass::create(type_cls, object_cls, &BoxedSet::gcHandler, 0, offsetof(BoxedSet, weakreflist),
......@@ -4037,7 +4037,6 @@ void setupRuntime() {
slice_cls->giveAttr("step", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedSlice, step)));
slice_cls->freeze();
slice_cls->tp_compare = (cmpfunc)slice_compare;
slice_cls->tp_flags &= ~Py_TPFLAGS_BASETYPE;
static PyMappingMethods attrwrapper_as_mapping;
attrwrapper_cls->tp_as_mapping = &attrwrapper_as_mapping;
......
......@@ -291,10 +291,11 @@ public:
// These should only be used for builtin types:
static BoxedClass* create(BoxedClass* metatype, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
int weaklist_offset, int instance_size, bool is_user_defined, const char* name);
int weaklist_offset, int instance_size, bool is_user_defined, const char* name,
bool is_subclassable = true);
BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int weaklist_offset, int instance_size,
bool is_user_defined, const char* name);
bool is_user_defined, const char* name, bool is_subclassable = true);
DEFAULT_CLASS_VAR(type_cls, sizeof(SlotOffset));
......
# should_error
class foo(slice):
pass
import re
import inspect
def gen():
print ("generator test")
yield 'a'
yield 'b'
def is_subclassable(base_cls):
try:
class C(base_cls):
pass
except TypeError as e:
assert 'is not an acceptable base type' in repr(e)
return False
return True
class b:
def __init__(self):
self.c = 1
def d(self):
print self.c
#slice
assert not is_subclassable(slice)
#xrange
assert not is_subclassable(type(xrange(1)))
#range-iterator
assert not is_subclassable(type(iter(range(5))))
#xrange-iterator
assert not is_subclassable(type(iter(xrange(5))))
#callable-iterator
assert not is_subclassable(type(re.finditer(r'\bs\w+', "some text with swords")))
#striterator
assert not is_subclassable(type(iter("abc")))
#memoryview
assert not is_subclassable(type(memoryview("abc")))
#buffer
assert not is_subclassable(type(buffer('abcde', 2,1)))
#Ellipsis
assert not is_subclassable(type(Ellipsis))
#generator
assert not is_subclassable(type(gen()))
#bool
assert not is_subclassable(type(True))
#classobj
assert not is_subclassable(type(b))
#code
assert not is_subclassable(type(compile('sum([1, 2, 3])', '', 'single')))
#instance
ins = b()
assert not is_subclassable(type(ins))
#instance_method
assert not is_subclassable(type(ins.d))
#frame
assert not is_subclassable(type(inspect.currentframe()))
#function
assert not is_subclassable(type(is_subclassable))
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment