Commit a921480a authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #544 from undingen/misc_stuff

Misc stuff
parents 2f75201c 13d73fc6
......@@ -364,3 +364,31 @@ PyObject *string_join(PyStringObject *self, PyObject *orig)
Py_DECREF(seq);
return res;
}
PyObject* string__format__(PyObject* self, PyObject* args)
{
PyObject *format_spec;
PyObject *result = NULL;
PyObject *tmp = NULL;
/* If 2.x, convert format_spec to the same type as value */
/* This is to allow things like u''.format('') */
if (!PyArg_ParseTuple(args, "O:__format__", &format_spec))
goto done;
if (!(PyString_Check(format_spec) || PyUnicode_Check(format_spec))) {
PyErr_Format(PyExc_TypeError, "__format__ arg must be str "
"or unicode, not %s", Py_TYPE(format_spec)->tp_name);
goto done;
}
tmp = PyObject_Str(format_spec);
if (tmp == NULL)
goto done;
format_spec = tmp;
result = _PyBytes_FormatAdvanced(self,
PyString_AS_STRING(format_spec),
PyString_GET_SIZE(format_spec));
done:
Py_XDECREF(tmp);
return result;
}
......@@ -1879,6 +1879,9 @@ extern "C" PyObject* PyNumber_Long(PyObject* o) noexcept {
if (o->cls == float_cls)
return PyLong_FromDouble(PyFloat_AsDouble(o));
if (o->cls == int_cls)
return PyLong_FromLong(((BoxedInt*)o)->n);
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
}
......
......@@ -184,6 +184,13 @@ static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noe
}
return v;
}
#ifdef HAVE_LONG_LONG
case 'L':
return PyLong_FromLongLong((PY_LONG_LONG)va_arg(*p_va, PY_LONG_LONG));
case 'K':
return PyLong_FromUnsignedLongLong((PY_LONG_LONG)va_arg(*p_va, unsigned PY_LONG_LONG));
#endif
#ifdef Py_USING_UNICODE
case 'u': {
PyObject* v;
......
......@@ -2647,6 +2647,246 @@ static void remove_subclass(PyTypeObject* base, PyTypeObject* type) noexcept {
}
}
static int equiv_structs(PyTypeObject* a, PyTypeObject* b) noexcept {
// Pyston change: added attrs_offset equality check
// return a == b || (a != NULL && b != NULL && a->tp_basicsize == b->tp_basicsize
// && a->tp_itemsize == b->tp_itemsize
// && a->tp_dictoffset == b->tp_dictoffset && a->tp_weaklistoffset == b->tp_weaklistoffset
// && ((a->tp_flags & Py_TPFLAGS_HAVE_GC) == (b->tp_flags & Py_TPFLAGS_HAVE_GC)));
return a == b || (a != NULL && b != NULL && a->tp_basicsize == b->tp_basicsize && a->tp_itemsize == b->tp_itemsize
&& a->tp_dictoffset == b->tp_dictoffset && a->tp_weaklistoffset == b->tp_weaklistoffset
&& a->attrs_offset == b->attrs_offset
&& ((a->tp_flags & Py_TPFLAGS_HAVE_GC) == (b->tp_flags & Py_TPFLAGS_HAVE_GC)));
}
static void update_all_slots(PyTypeObject* type) noexcept {
slotdef* p;
init_slotdefs();
for (p = slotdefs; p->name; p++) {
/* update_slot returns int but can't actually fail */
update_slot(type, p->name);
}
}
static int same_slots_added(PyTypeObject* a, PyTypeObject* b) noexcept {
PyTypeObject* base = a->tp_base;
Py_ssize_t size;
PyObject* slots_a, *slots_b;
assert(base == b->tp_base);
size = base->tp_basicsize;
if (a->tp_dictoffset == size && b->tp_dictoffset == size)
size += sizeof(PyObject*);
// Pyston change: have to check attrs_offset
if (a->attrs_offset == size && b->attrs_offset == size)
size += sizeof(HCAttrs);
if (a->tp_weaklistoffset == size && b->tp_weaklistoffset == size)
size += sizeof(PyObject*);
/* Check slots compliance */
slots_a = ((PyHeapTypeObject*)a)->ht_slots;
slots_b = ((PyHeapTypeObject*)b)->ht_slots;
if (slots_a && slots_b) {
if (PyObject_Compare(slots_a, slots_b) != 0)
return 0;
size += sizeof(PyObject*) * PyTuple_GET_SIZE(slots_a);
}
return size == a->tp_basicsize && size == b->tp_basicsize;
}
static int compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, const char* attr) noexcept {
PyTypeObject* newbase, *oldbase;
if (newto->tp_dealloc != oldto->tp_dealloc || newto->tp_free != oldto->tp_free) {
PyErr_Format(PyExc_TypeError, "%s assignment: "
"'%s' deallocator differs from '%s'",
attr, newto->tp_name, oldto->tp_name);
return 0;
}
newbase = newto;
oldbase = oldto;
while (equiv_structs(newbase, newbase->tp_base))
newbase = newbase->tp_base;
while (equiv_structs(oldbase, oldbase->tp_base))
oldbase = oldbase->tp_base;
if (newbase != oldbase && (newbase->tp_base != oldbase->tp_base || !same_slots_added(newbase, oldbase))) {
PyErr_Format(PyExc_TypeError, "%s assignment: "
"'%s' object layout differs from '%s'",
attr, newto->tp_name, oldto->tp_name);
return 0;
}
return 1;
}
static int mro_subclasses(PyTypeObject* type, PyObject* temp) noexcept {
PyTypeObject* subclass;
PyObject* ref, *subclasses, *old_mro;
Py_ssize_t i, n;
subclasses = type->tp_subclasses;
if (subclasses == NULL)
return 0;
assert(PyList_Check(subclasses));
n = PyList_GET_SIZE(subclasses);
for (i = 0; i < n; i++) {
ref = PyList_GET_ITEM(subclasses, i);
assert(PyWeakref_CheckRef(ref));
subclass = (PyTypeObject*)PyWeakref_GET_OBJECT(ref);
assert(subclass != NULL);
if ((PyObject*)subclass == Py_None)
continue;
assert(PyType_Check(subclass));
old_mro = subclass->tp_mro;
if (mro_internal(subclass) < 0) {
subclass->tp_mro = old_mro;
return -1;
} else {
PyObject* tuple;
tuple = PyTuple_Pack(2, subclass, old_mro);
Py_DECREF(old_mro);
if (!tuple)
return -1;
if (PyList_Append(temp, tuple) < 0)
return -1;
Py_DECREF(tuple);
}
if (mro_subclasses(subclass, temp) < 0)
return -1;
}
return 0;
}
int type_set_bases(PyTypeObject* type, PyObject* value, void* context) noexcept {
Py_ssize_t i;
int r = 0;
PyObject* ob, *temp;
PyTypeObject* new_base, *old_base;
PyObject* old_bases, *old_mro;
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
PyErr_Format(PyExc_TypeError, "can't set %s.__bases__", type->tp_name);
return -1;
}
if (!value) {
PyErr_Format(PyExc_TypeError, "can't delete %s.__bases__", type->tp_name);
return -1;
}
if (!PyTuple_Check(value)) {
PyErr_Format(PyExc_TypeError, "can only assign tuple to %s.__bases__, not %s", type->tp_name,
Py_TYPE(value)->tp_name);
return -1;
}
if (PyTuple_GET_SIZE(value) == 0) {
PyErr_Format(PyExc_TypeError, "can only assign non-empty tuple to %s.__bases__, not ()", type->tp_name);
return -1;
}
for (i = 0; i < PyTuple_GET_SIZE(value); i++) {
ob = PyTuple_GET_ITEM(value, i);
if (!PyClass_Check(ob) && !PyType_Check(ob)) {
PyErr_Format(PyExc_TypeError, "%s.__bases__ must be tuple of old- or new-style classes, not '%s'",
type->tp_name, Py_TYPE(ob)->tp_name);
return -1;
}
if (PyType_Check(ob)) {
if (PyType_IsSubtype((PyTypeObject*)ob, type)) {
PyErr_SetString(PyExc_TypeError, "a __bases__ item causes an inheritance cycle");
return -1;
}
}
}
new_base = best_base(value);
if (!new_base) {
return -1;
}
if (!compatible_for_assignment(type->tp_base, new_base, "__bases__"))
return -1;
Py_INCREF(new_base);
Py_INCREF(value);
old_bases = type->tp_bases;
old_base = type->tp_base;
old_mro = type->tp_mro;
type->tp_bases = value;
type->tp_base = new_base;
if (mro_internal(type) < 0) {
goto bail;
}
temp = PyList_New(0);
if (!temp)
goto bail;
r = mro_subclasses(type, temp);
if (r < 0) {
for (i = 0; i < PyList_Size(temp); i++) {
PyTypeObject* cls;
PyObject* mro;
PyArg_UnpackTuple(PyList_GET_ITEM(temp, i), "", 2, 2, &cls, &mro);
Py_INCREF(mro);
ob = cls->tp_mro;
cls->tp_mro = mro;
Py_DECREF(ob);
}
Py_DECREF(temp);
goto bail;
}
Py_DECREF(temp);
/* any base that was in __bases__ but now isn't, we
need to remove |type| from its tp_subclasses.
conversely, any class now in __bases__ that wasn't
needs to have |type| added to its subclasses. */
/* for now, sod that: just remove from all old_bases,
add to all new_bases */
for (i = PyTuple_GET_SIZE(old_bases) - 1; i >= 0; i--) {
ob = PyTuple_GET_ITEM(old_bases, i);
if (PyType_Check(ob)) {
remove_subclass((PyTypeObject*)ob, type);
}
}
for (i = PyTuple_GET_SIZE(value) - 1; i >= 0; i--) {
ob = PyTuple_GET_ITEM(value, i);
if (PyType_Check(ob)) {
if (add_subclass((PyTypeObject*)ob, type) < 0)
r = -1;
}
}
update_all_slots(type);
Py_DECREF(old_bases);
Py_DECREF(old_base);
Py_DECREF(old_mro);
return r;
bail:
Py_DECREF(type->tp_bases);
Py_DECREF(type->tp_base);
if (type->tp_mro != old_mro) {
Py_DECREF(type->tp_mro);
}
type->tp_bases = old_bases;
type->tp_base = old_base;
type->tp_mro = old_mro;
return -1;
}
// commonClassSetup is for the common code between PyType_Ready (which is just for extension classes)
// and our internal type-creation endpoints (BoxedClass::BoxedClass()).
// TODO: Move more of the duplicated logic into here.
......
......@@ -32,6 +32,7 @@ void commonClassSetup(BoxedClass* cls);
// We could probably unify things more but that's for later.
PyTypeObject* best_base(PyObject* bases) noexcept;
PyObject* mro_external(PyObject* self) noexcept;
int type_set_bases(PyTypeObject* type, PyObject* value, void* context) noexcept;
}
#endif
......@@ -461,8 +461,14 @@ extern "C" int PySequence_SetItem(PyObject* o, Py_ssize_t i, PyObject* v) noexce
}
extern "C" int PySequence_DelItem(PyObject* o, Py_ssize_t i) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return -1;
try {
// Not sure if this is really the same:
delitem(o, boxInt(i));
return 0;
} catch (ExcInfo e) {
setCAPIException(e);
return -1;
}
}
extern "C" int PySequence_SetSlice(PyObject* o, Py_ssize_t i1, Py_ssize_t i2, PyObject* v) noexcept {
......
......@@ -196,11 +196,11 @@ extern "C" PyObject* PyInt_FromString(const char* s, char** pend, int base) noex
s++;
errno = 0;
if (base == 0 && s[0] == '0') {
x = (long)strtoul(s, &end, base);
x = (long)PyOS_strtoul(const_cast<char*>(s), &end, base);
if (x < 0)
return PyLong_FromString(s, pend, base);
} else
x = strtol(s, &end, base);
x = PyOS_strtol(const_cast<char*>(s), &end, base);
if (end == s || !isalnum(Py_CHARMASK(end[-1])))
goto bad;
while (*end && isspace(Py_CHARMASK(*end)))
......
......@@ -4165,7 +4165,7 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
return rtn;
}
RELEASE_ASSERT(arg3->cls == dict_cls, "%s", getTypeName(arg3));
RELEASE_ASSERT(PyDict_Check(arg3), "%s", getTypeName(arg3));
BoxedDict* attr_dict = static_cast<BoxedDict*>(arg3);
RELEASE_ASSERT(arg2->cls == tuple_cls, "");
......
......@@ -44,6 +44,7 @@ extern "C" PyObject* string_index(PyStringObject* self, PyObject* args) noexcept
extern "C" PyObject* string_rindex(PyStringObject* self, PyObject* args) noexcept;
extern "C" PyObject* string_rfind(PyStringObject* self, PyObject* args) noexcept;
extern "C" PyObject* string_splitlines(PyStringObject* self, PyObject* args) noexcept;
extern "C" PyObject* string__format__(PyObject* self, PyObject* args) noexcept;
// from cpython's stringobject.c:
#define LEFTSTRIP 0
......@@ -2652,6 +2653,7 @@ static PyMethodDef string_methods[] = {
{ "expandtabs", (PyCFunction)string_expandtabs, METH_VARARGS, NULL },
{ "splitlines", (PyCFunction)string_splitlines, METH_VARARGS, NULL },
{ "zfill", (PyCFunction)string_zfill, METH_VARARGS, NULL },
{ "__format__", (PyCFunction)string__format__, METH_VARARGS, NULL },
};
void setupStr() {
......
......@@ -1546,6 +1546,22 @@ public:
return rtn;
}
static Box* clear(Box* _self) {
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
HCAttrs* attrs = self->b->getHCAttrsPtr();
RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, "");
while (true) {
const auto& attrMap = attrs->hcls->getStrAttrOffsets();
if (attrMap.size() == 0)
break;
self->b->delattr(attrMap.begin()->first(), NULL);
}
return None;
}
static Box* len(Box* _self) {
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
......@@ -1985,6 +2001,63 @@ static PyObject* object_reduce_ex(PyObject* self, PyObject* args) noexcept {
return _common_reduce(self, proto);
}
/*
from PEP 3101, this code implements:
class object:
def __format__(self, format_spec):
if isinstance(format_spec, str):
return format(str(self), format_spec)
elif isinstance(format_spec, unicode):
return format(unicode(self), format_spec)
*/
static PyObject* object_format(PyObject* self, PyObject* args) noexcept {
PyObject* format_spec;
PyObject* self_as_str = NULL;
PyObject* result = NULL;
Py_ssize_t format_len;
if (!PyArg_ParseTuple(args, "O:__format__", &format_spec))
return NULL;
#ifdef Py_USING_UNICODE
if (PyUnicode_Check(format_spec)) {
format_len = PyUnicode_GET_SIZE(format_spec);
self_as_str = PyObject_Unicode(self);
} else if (PyString_Check(format_spec)) {
#else
if (PyString_Check(format_spec)) {
#endif
format_len = PyString_GET_SIZE(format_spec);
self_as_str = PyObject_Str(self);
} else {
PyErr_SetString(PyExc_TypeError, "argument to __format__ must be unicode or str");
return NULL;
}
if (self_as_str != NULL) {
/* Issue 7994: If we're converting to a string, we
should reject format specifications */
if (format_len > 0) {
if (PyErr_WarnEx(PyExc_PendingDeprecationWarning, "object.__format__ with a non-empty format "
"string is deprecated",
1) < 0) {
goto done;
}
/* Eventually this will become an error:
PyErr_Format(PyExc_TypeError,
"non-empty format string passed to object.__format__");
goto done;
*/
}
result = PyObject_Format(self_as_str, format_spec);
}
done:
Py_XDECREF(self_as_str);
return result;
}
static Box* objectClass(Box* obj, void* context) {
assert(obj->cls != instance_cls); // should override __class__ in classobj
return obj->cls;
......@@ -2029,6 +2102,7 @@ static void objectSetClass(Box* obj, Box* val, void* context) {
static PyMethodDef object_methods[] = {
{ "__reduce_ex__", object_reduce_ex, METH_VARARGS, NULL }, //
{ "__reduce__", object_reduce, METH_VARARGS, NULL }, //
{ "__format__", object_format, METH_VARARGS, PyDoc_STR("default object formatter") },
};
static Box* typeName(Box* b, void*) {
......@@ -2086,8 +2160,11 @@ static Box* typeBases(Box* b, void*) {
return type->tp_bases;
}
static void typeSetBases(Box* b, Box* v, void*) {
Py_FatalError("unimplemented");
static void typeSetBases(Box* b, Box* v, void* c) {
RELEASE_ASSERT(isSubclass(b->cls, type_cls), "");
BoxedClass* type = static_cast<BoxedClass*>(b);
if (type_set_bases(type, v, c) == -1)
throwCAPIException();
}
// cls should be obj->cls.
......@@ -2540,6 +2617,7 @@ void setupRuntime() {
new BoxedFunction(boxRTFunction((void*)AttrWrapper::itervalues, UNKNOWN, 1)));
attrwrapper_cls->giveAttr("iteritems", new BoxedFunction(boxRTFunction((void*)AttrWrapper::iteritems, UNKNOWN, 1)));
attrwrapper_cls->giveAttr("copy", new BoxedFunction(boxRTFunction((void*)AttrWrapper::copy, UNKNOWN, 1)));
attrwrapper_cls->giveAttr("clear", new BoxedFunction(boxRTFunction((void*)AttrWrapper::clear, NONE, 1)));
attrwrapper_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::len, BOXED_INT, 1)));
attrwrapper_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::iter, UNKNOWN, 1)));
attrwrapper_cls->giveAttr("update",
......
......@@ -38,3 +38,12 @@ p()
c1.__dict__ = d = {}
d['i'] = 5
p()
class C(object):
def foo(self):
return 0
c = C()
c.attr = "test"
c.__dict__.clear()
print hasattr(c, "attr")
print hasattr(c, "foo")
......@@ -67,6 +67,7 @@ print type(int(L()))
print int(u'123')
print int("9223372036854775808", 0)
print int("0b101", 2), int("0b101", 0)
print 1 << 63, 1 << 64, -1 << 63, -1 << 64, 2 << 63
print type(1 << 63), type(1 << 64), type(-1 << 63), type(-1 << 64), type(2 << 63)
......
class A(object):
def foo(self):
print "foo"
class B(object):
def bar(self):
print "bar"
class C(object):
def baz(self):
print "baz"
class D(C):
pass
print D.__bases__ == (C,)
print hasattr(D, "bar")
try:
D.__bases__ += (A, B, C)
except Exception as e:
print e # duplicate base class C
D.__bases__ += (A, B)
print D.__bases__ == (C, A, B, C)
print D.__base__ == (C)
D().foo(), D().bar(), D().baz()
D.__bases__ = (C,)
print D.__bases__ == (C,)
print hasattr(D, "foo"), hasattr(D, "bar"), hasattr(D, "baz")
D().baz()
# inheritance circle:
try:
C.__bases__ = (D,)
except TypeError as e:
print e
class Slots(object):
__slots__ = ["a", "b", "c"]
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
try:
Slots.__bases__ = (A,)
except TypeError:
print "cought TypeError exception" # pyston and cpython throw a different exception
# This tests are copied from CPython an can be removed when we support running test/cpython/test_descr.py
class CPythonTests(object):
def assertEqual(self, x, y):
assert x == y
def fail(self, msg):
print "Error", msg
def test_mutable_bases(self):
# Testing mutable bases...
# stuff that should work:
class C(object):
pass
class C2(object):
def __getattribute__(self, attr):
if attr == 'a':
return 2
else:
return super(C2, self).__getattribute__(attr)
def meth(self):
return 1
class D(C):
pass
class E(D):
pass
d = D()
e = E()
D.__bases__ = (C,)
D.__bases__ = (C2,)
self.assertEqual(d.meth(), 1)
self.assertEqual(e.meth(), 1)
self.assertEqual(d.a, 2)
self.assertEqual(e.a, 2)
self.assertEqual(C2.__subclasses__(), [D])
try:
del D.__bases__
except (TypeError, AttributeError):
pass
else:
self.fail("shouldn't be able to delete .__bases__")
try:
D.__bases__ = ()
except TypeError, msg:
if str(msg) == "a new-style class can't have only classic bases":
self.fail("wrong error message for .__bases__ = ()")
else:
self.fail("shouldn't be able to set .__bases__ to ()")
try:
D.__bases__ = (D,)
except TypeError:
pass
else:
# actually, we'll have crashed by here...
self.fail("shouldn't be able to create inheritance cycles")
try:
D.__bases__ = (C, C)
except TypeError:
pass
else:
self.fail("didn't detect repeated base classes")
try:
D.__bases__ = (E,)
except TypeError:
pass
else:
self.fail("shouldn't be able to create inheritance cycles")
# let's throw a classic class into the mix:
class Classic:
def meth2(self):
return 3
D.__bases__ = (C, Classic)
self.assertEqual(d.meth2(), 3)
self.assertEqual(e.meth2(), 3)
try:
d.a
except AttributeError:
pass
else:
self.fail("attribute should have vanished")
try:
D.__bases__ = (Classic,)
except TypeError:
pass
else:
self.fail("new-style class must have a new-style base")
def test_mutable_bases_catch_mro_conflict(self):
# Testing mutable bases catch mro conflict...
class A(object):
pass
class B(object):
pass
class C(A, B):
pass
class D(A, B):
pass
class E(C, D):
pass
try:
C.__bases__ = (B, A)
except TypeError:
pass
else:
self.fail("didn't catch MRO conflict")
tests = CPythonTests()
tests.test_mutable_bases()
tests.test_mutable_bases_catch_mro_conflict()
print
print "Finished"
......@@ -168,3 +168,8 @@ it = iter("hello world")
print list(it)
print "'{0}' '{1}'".format("Hello " * 3, "Hello " * -3)
class C(object):
def __str__(self):
return "my class"
print "{0}".format(C())
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