Commit 6775ce65 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #555 from undingen/dictproxy

Add __cmp__ and dictproxy
parents a1aed5de f677127a
......@@ -390,6 +390,7 @@ STDOBJECT_SRCS := \
iterobject.c \
bufferobject.c \
cobject.c \
dictproxy.c \
$(EXTRA_STDOBJECT_SRCS)
STDPYTHON_SRCS := \
......
......@@ -78,6 +78,7 @@ file(GLOB_RECURSE STDOBJECT_SRCS Objects
bytes_methods.c
capsule.c
cobject.c
dictproxy.c
exceptions.c
floatobject.c
iterobject.c
......
......@@ -80,6 +80,8 @@ PyAPI_DATA(PyTypeObject) PyWrapperDescr_Type;
PyAPI_DATA(PyTypeObject) PyDictProxy_Type;
PyAPI_DATA(PyTypeObject) PyGetSetDescr_Type;
PyAPI_DATA(PyTypeObject) PyMemberDescr_Type;
#else
PyAPI_DATA(PyTypeObject) PyDictProxy_Type;
#endif
// (Pyston TODO: add #defines to our names)
PyAPI_DATA(PyTypeObject*) wrapperdescr_cls;
......
......@@ -848,9 +848,7 @@ PyTypeObject PyBuffer_Type = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
// Pyston change:
//(cmpfunc)buffer_compare, /* tp_compare */
NULL, /* tp_compare */
(cmpfunc)buffer_compare, /* tp_compare */
(reprfunc)buffer_repr, /* tp_repr */
0, /* tp_as_number */
&buffer_as_sequence, /* tp_as_sequence */
......
// This file is originally from CPython 2.7, with modifications for Pyston
// The code is normally part of descrobject.c
#include "Python.h"
/* --- Readonly proxy for dictionaries (actually any mapping) --- */
/* This has no reason to be in this file except that adding new files is a
bit of a pain */
typedef struct {
PyObject_HEAD
PyObject *dict;
} proxyobject;
static Py_ssize_t
proxy_len(proxyobject *pp)
{
return PyObject_Size(pp->dict);
}
static PyObject *
proxy_getitem(proxyobject *pp, PyObject *key)
{
return PyObject_GetItem(pp->dict, key);
}
static PyMappingMethods proxy_as_mapping = {
(lenfunc)proxy_len, /* mp_length */
(binaryfunc)proxy_getitem, /* mp_subscript */
0, /* mp_ass_subscript */
};
static int
proxy_contains(proxyobject *pp, PyObject *key)
{
return PyDict_Contains(pp->dict, key);
}
static PySequenceMethods proxy_as_sequence = {
0, /* sq_length */
0, /* sq_concat */
0, /* sq_repeat */
0, /* sq_item */
0, /* sq_slice */
0, /* sq_ass_item */
0, /* sq_ass_slice */
(objobjproc)proxy_contains, /* sq_contains */
0, /* sq_inplace_concat */
0, /* sq_inplace_repeat */
};
static PyObject *
proxy_has_key(proxyobject *pp, PyObject *key)
{
int res = PyDict_Contains(pp->dict, key);
if (res < 0)
return NULL;
return PyBool_FromLong(res);
}
static PyObject *
proxy_get(proxyobject *pp, PyObject *args)
{
PyObject *key, *def = Py_None;
if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def))
return NULL;
return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);
}
static PyObject *
proxy_keys(proxyobject *pp)
{
return PyMapping_Keys(pp->dict);
}
static PyObject *
proxy_values(proxyobject *pp)
{
return PyMapping_Values(pp->dict);
}
static PyObject *
proxy_items(proxyobject *pp)
{
return PyMapping_Items(pp->dict);
}
static PyObject *
proxy_iterkeys(proxyobject *pp)
{
return PyObject_CallMethod(pp->dict, "iterkeys", NULL);
}
static PyObject *
proxy_itervalues(proxyobject *pp)
{
return PyObject_CallMethod(pp->dict, "itervalues", NULL);
}
static PyObject *
proxy_iteritems(proxyobject *pp)
{
return PyObject_CallMethod(pp->dict, "iteritems", NULL);
}
static PyObject *
proxy_copy(proxyobject *pp)
{
return PyObject_CallMethod(pp->dict, "copy", NULL);
}
static PyMethodDef proxy_methods[] = {
{"has_key", (PyCFunction)proxy_has_key, METH_O,
PyDoc_STR("D.has_key(k) -> True if D has a key k, else False")},
{"get", (PyCFunction)proxy_get, METH_VARARGS,
PyDoc_STR("D.get(k[,d]) -> D[k] if D.has_key(k), else d."
" d defaults to None.")},
{"keys", (PyCFunction)proxy_keys, METH_NOARGS,
PyDoc_STR("D.keys() -> list of D's keys")},
{"values", (PyCFunction)proxy_values, METH_NOARGS,
PyDoc_STR("D.values() -> list of D's values")},
{"items", (PyCFunction)proxy_items, METH_NOARGS,
PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")},
{"iterkeys", (PyCFunction)proxy_iterkeys, METH_NOARGS,
PyDoc_STR("D.iterkeys() -> an iterator over the keys of D")},
{"itervalues",(PyCFunction)proxy_itervalues, METH_NOARGS,
PyDoc_STR("D.itervalues() -> an iterator over the values of D")},
{"iteritems", (PyCFunction)proxy_iteritems, METH_NOARGS,
PyDoc_STR("D.iteritems() ->"
" an iterator over the (key, value) items of D")},
{"copy", (PyCFunction)proxy_copy, METH_NOARGS,
PyDoc_STR("D.copy() -> a shallow copy of D")},
{0}
};
static void
proxy_dealloc(proxyobject *pp)
{
_PyObject_GC_UNTRACK(pp);
Py_DECREF(pp->dict);
PyObject_GC_Del(pp);
}
static PyObject *
proxy_getiter(proxyobject *pp)
{
return PyObject_GetIter(pp->dict);
}
static PyObject *
proxy_str(proxyobject *pp)
{
return PyObject_Str(pp->dict);
}
static PyObject *
proxy_repr(proxyobject *pp)
{
PyObject *dictrepr;
PyObject *result;
dictrepr = PyObject_Repr(pp->dict);
if (dictrepr == NULL)
return NULL;
result = PyString_FromFormat("dict_proxy(%s)", PyString_AS_STRING(dictrepr));
Py_DECREF(dictrepr);
return result;
}
static int
proxy_traverse(PyObject *self, visitproc visit, void *arg)
{
proxyobject *pp = (proxyobject *)self;
Py_VISIT(pp->dict);
return 0;
}
static int
proxy_compare(proxyobject *v, PyObject *w)
{
return PyObject_Compare(v->dict, w);
}
static PyObject *
proxy_richcompare(proxyobject *v, PyObject *w, int op)
{
return PyObject_RichCompare(v->dict, w, op);
}
PyTypeObject PyDictProxy_Type = {
// Pyston change:
// PyVarObject_HEAD_INIT(&PyType_Type, 0)
PyVarObject_HEAD_INIT(NULL, 0)
"dictproxy", /* tp_name */
sizeof(proxyobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)proxy_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)proxy_compare, /* tp_compare */
(reprfunc)proxy_repr, /* tp_repr */
0, /* tp_as_number */
&proxy_as_sequence, /* tp_as_sequence */
&proxy_as_mapping, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
(reprfunc)proxy_str, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */
proxy_traverse, /* tp_traverse */
0, /* tp_clear */
(richcmpfunc)proxy_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)proxy_getiter, /* tp_iter */
0, /* tp_iternext */
proxy_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
};
PyObject *
PyDictProxy_New(PyObject *dict)
{
proxyobject *pp;
pp = PyObject_GC_New(proxyobject, &PyDictProxy_Type);
if (pp != NULL) {
Py_INCREF(dict);
pp->dict = dict;
_PyObject_GC_TRACK(pp);
}
return (PyObject *)pp;
}
......@@ -699,8 +699,7 @@ _PyWeakref_ProxyType = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
// Pyston change:
0, //proxy_compare, /* tp_compare */
proxy_compare, /* tp_compare */
(reprfunc)proxy_repr, /* tp_repr */
&proxy_as_number, /* tp_as_number */
&proxy_as_sequence, /* tp_as_sequence */
......@@ -737,7 +736,7 @@ _PyWeakref_CallableProxyType = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, //proxy_compare, /* tp_compare */
proxy_compare, /* tp_compare */
(unaryfunc)proxy_repr, /* tp_repr */
&proxy_as_number, /* tp_as_number */
&proxy_as_sequence, /* tp_as_sequence */
......
......@@ -2934,8 +2934,6 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
gc::registerNonheapRootObject(cls);
// unhandled fields:
RELEASE_ASSERT(cls->tp_compare == NULL, "");
int ALLOWABLE_FLAGS = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES
| Py_TPFLAGS_HAVE_NEWBUFFER;
ALLOWABLE_FLAGS |= Py_TPFLAGS_INT_SUBCLASS | Py_TPFLAGS_LONG_SUBCLASS | Py_TPFLAGS_LIST_SUBCLASS
......
......@@ -177,20 +177,29 @@ std::string getInplaceOpName(int op_type) {
// Maybe better name is "swapped" -- it's what the runtime will try if the normal op
// name fails, it will switch the order of the lhs/rhs and call the reverse op.
// Calling it "reverse" because that's what I'm assuming the 'r' stands for in ex __radd__
std::string getReverseOpName(int op_type) {
int getReverseCmpOp(int op_type, bool& success) {
success = true;
if (op_type == AST_TYPE::Lt)
return getOpName(AST_TYPE::Gt);
return AST_TYPE::Gt;
if (op_type == AST_TYPE::LtE)
return getOpName(AST_TYPE::GtE);
return AST_TYPE::GtE;
if (op_type == AST_TYPE::Gt)
return getOpName(AST_TYPE::Lt);
return AST_TYPE::Lt;
if (op_type == AST_TYPE::GtE)
return getOpName(AST_TYPE::LtE);
return AST_TYPE::LtE;
if (op_type == AST_TYPE::NotEq)
return getOpName(AST_TYPE::NotEq);
return AST_TYPE::NotEq;
if (op_type == AST_TYPE::Eq)
return getOpName(AST_TYPE::Eq);
return AST_TYPE::Eq;
success = false;
return op_type;
}
std::string getReverseOpName(int op_type) {
bool reversed = false;
op_type = getReverseCmpOp(op_type, reversed);
if (reversed)
return getOpName(op_type);
const std::string& normal_name = getOpName(op_type);
return "__r" + normal_name.substr(2);
}
......
......@@ -1402,6 +1402,7 @@ template <class T, class R> void findNodes(const R& roots, std::vector<T*>& outp
llvm::StringRef getOpSymbol(int op_type);
const std::string& getOpName(int op_type);
int getReverseCmpOp(int op_type, bool& success);
std::string getReverseOpName(int op_type);
std::string getInplaceOpName(int op_type);
std::string getInplaceOpSymbol(int op_type);
......
......@@ -467,6 +467,140 @@ Box* instanceDelitem(Box* _inst, Box* key) {
return runtimeCall(delitem_func, ArgPassSpec(1), key, NULL, NULL, NULL, NULL);
}
/* Try a 3-way comparison, returning an int; v is an instance. Return:
-2 for an exception;
-1 if v < w;
0 if v == w;
1 if v > w;
2 if this particular 3-way comparison is not implemented or undefined.
*/
static int half_cmp(PyObject* v, PyObject* w) noexcept {
// static PyObject* cmp_obj;
PyObject* args;
PyObject* cmp_func;
PyObject* result;
long l;
assert(PyInstance_Check(v));
// Pyston change:
#if 0
if (cmp_obj == NULL) {
cmp_obj = PyString_InternFromString("__cmp__");
if (cmp_obj == NULL)
return -2;
}
cmp_func = PyObject_GetAttr(v, cmp_obj);
if (cmp_func == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -2;
PyErr_Clear();
return 2;
}
#else
try {
cmp_func = _instanceGetattribute(v, boxStrConstant("__cmp__"), false);
if (!cmp_func)
return 2;
} catch (ExcInfo e) {
setCAPIException(e);
return -2;
}
#endif
args = PyTuple_Pack(1, w);
if (args == NULL) {
Py_DECREF(cmp_func);
return -2;
}
result = PyEval_CallObject(cmp_func, args);
Py_DECREF(args);
Py_DECREF(cmp_func);
if (result == NULL)
return -2;
if (result == Py_NotImplemented) {
Py_DECREF(result);
return 2;
}
l = PyInt_AsLong(result);
Py_DECREF(result);
if (l == -1 && PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError, "comparison did not return an int");
return -2;
}
return l < 0 ? -1 : l > 0 ? 1 : 0;
}
/* Try a 3-way comparison, returning an int; either v or w is an instance.
We first try a coercion. Return:
-2 for an exception;
-1 if v < w;
0 if v == w;
1 if v > w;
2 if this particular 3-way comparison is not implemented or undefined.
*/
static int instance_compare(PyObject* v, PyObject* w) noexcept {
int c;
c = PyNumber_CoerceEx(&v, &w);
if (c < 0)
return -2;
if (c == 0) {
/* If neither is now an instance, use regular comparison */
if (!PyInstance_Check(v) && !PyInstance_Check(w)) {
c = PyObject_Compare(v, w);
Py_DECREF(v);
Py_DECREF(w);
if (PyErr_Occurred())
return -2;
return c < 0 ? -1 : c > 0 ? 1 : 0;
}
} else {
/* The coercion didn't do anything.
Treat this the same as returning v and w unchanged. */
Py_INCREF(v);
Py_INCREF(w);
}
if (PyInstance_Check(v)) {
c = half_cmp(v, w);
if (c <= 1) {
Py_DECREF(v);
Py_DECREF(w);
return c;
}
}
if (PyInstance_Check(w)) {
c = half_cmp(w, v);
if (c <= 1) {
Py_DECREF(v);
Py_DECREF(w);
if (c >= -1)
c = -c;
return c;
}
}
Py_DECREF(v);
Py_DECREF(w);
return 2;
}
Box* instanceCompare(Box* _inst, Box* other) {
int rtn = instance_compare(_inst, other);
if (rtn == 2)
return NotImplemented;
if (rtn == -2)
throwCAPIException();
return boxInt(rtn);
}
Box* instanceContains(Box* _inst, Box* key) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
......@@ -695,6 +829,7 @@ void setupClassobj() {
instance_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)instanceGetitem, UNKNOWN, 2)));
instance_cls->giveAttr("__setitem__", new BoxedFunction(boxRTFunction((void*)instanceSetitem, UNKNOWN, 3)));
instance_cls->giveAttr("__delitem__", new BoxedFunction(boxRTFunction((void*)instanceDelitem, UNKNOWN, 2)));
instance_cls->giveAttr("__cmp__", new BoxedFunction(boxRTFunction((void*)instanceCompare, UNKNOWN, 2)));
instance_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)instanceContains, UNKNOWN, 2)));
instance_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)instanceHash, UNKNOWN, 1)));
instance_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)instanceIter, UNKNOWN, 1)));
......
......@@ -439,8 +439,17 @@ Box* dictContains(BoxedDict* self, Box* k) {
/* Return 1 if `key` is in dict `op`, 0 if not, and -1 on error. */
extern "C" int PyDict_Contains(PyObject* op, PyObject* key) noexcept {
BoxedDict* mp = (BoxedDict*)op;
try {
if (op->cls == attrwrapper_cls) {
Box* rtn = PyObject_CallMethod(op, "__contains__", "O", key);
if (!rtn)
return -1;
return rtn == True;
}
BoxedDict* mp = (BoxedDict*)op;
assert(isSubclass(mp->cls, dict_cls));
return mp->getOrNull(key) ? 1 : 0;
} catch (ExcInfo e) {
setCAPIException(e);
......
......@@ -3620,6 +3620,28 @@ extern "C" Box* augbinop(Box* lhs, Box* rhs, int op_type) {
return rtn;
}
static bool convert3wayCompareResultToBool(Box* v, int op_type) {
long result = PyInt_AsLong(v);
if (result == -1 && PyErr_Occurred())
throwCAPIException();
switch (op_type) {
case AST_TYPE::Eq:
return result == 0;
case AST_TYPE::NotEq:
return result != 0;
case AST_TYPE::Lt:
return result < 0;
case AST_TYPE::Gt:
return result > 0;
case AST_TYPE::LtE:
return result < 0 || result == 0;
case AST_TYPE::GtE:
return result > 0 || result == 0;
default:
RELEASE_ASSERT(0, "op type %d not implemented", op_type);
};
}
Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrite_args) {
if (op_type == AST_TYPE::Is || op_type == AST_TYPE::IsNot) {
bool neg = (op_type == AST_TYPE::IsNot);
......@@ -3704,6 +3726,18 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
if (rrtn != NULL && rrtn != NotImplemented)
return rrtn;
std::string cmp_name = "__cmp__";
lrtn = callattrInternal1(lhs, &cmp_name, CLASS_ONLY, NULL, ArgPassSpec(1), rhs);
if (lrtn && lrtn != NotImplemented) {
return boxBool(convert3wayCompareResultToBool(lrtn, op_type));
}
rrtn = callattrInternal1(rhs, &cmp_name, CLASS_ONLY, NULL, ArgPassSpec(1), lhs);
if (rrtn && rrtn != NotImplemented) {
bool success = false;
int reversed_op = getReverseCmpOp(op_type, success);
assert(success);
return boxBool(convert3wayCompareResultToBool(rrtn, reversed_op));
}
if (op_type == AST_TYPE::Eq)
return boxBool(lhs == rhs);
......@@ -4357,8 +4391,8 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
base_heap_cls->nslots() * sizeof(BoxedHeapClass::SlotOffset));
}
if (!made->getattr("__dict__") && (made->instancesHaveHCAttrs() || made->instancesHaveDictAttrs()))
made->giveAttr("__dict__", dict_descr);
if (made->instancesHaveHCAttrs() || made->instancesHaveDictAttrs())
made->setattr("__dict__", dict_descr, NULL);
for (const auto& p : attr_dict->d) {
auto k = coerceUnicodeToStr(p.first);
......
......@@ -495,6 +495,12 @@ extern "C" void typeGCHandler(GCVisitor* v, Box* b) {
}
static Box* typeDict(Box* obj, void* context) {
if (obj->cls->instancesHaveHCAttrs())
return PyDictProxy_New(obj->getAttrWrapper());
abort();
}
static Box* typeSubDict(Box* obj, void* context) {
if (obj->cls->instancesHaveHCAttrs())
return obj->getAttrWrapper();
if (obj->cls->instancesHaveDictAttrs())
......@@ -502,7 +508,7 @@ static Box* typeDict(Box* obj, void* context) {
abort();
}
static void typeSetDict(Box* obj, Box* val, void* context) {
static void typeSubSetDict(Box* obj, Box* val, void* context) {
if (obj->cls->instancesHaveDictAttrs()) {
RELEASE_ASSERT(val->cls == dict_cls, "");
obj->setDict(static_cast<BoxedDict*>(val));
......@@ -1635,6 +1641,20 @@ public:
return new AttrWrapperIter(self);
}
static Box* eq(Box* _self, Box* _other) {
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
// In order to not have to reimplement dict cmp: just create a real dict for now and us it.
BoxedDict* dict = (BoxedDict*)AttrWrapper::copy(_self);
assert(dict->cls == dict_cls);
const std::string eq_str = "__eq__";
return callattrInternal(dict, &eq_str, LookupScope::CLASS_ONLY, NULL, ArgPassSpec(1), _other, NULL, NULL, NULL,
NULL);
}
static Box* ne(Box* _self, Box* _other) { return eq(_self, _other) == True ? False : True; }
friend class AttrWrapperIter;
};
......@@ -2437,9 +2457,9 @@ void setupRuntime() {
str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
dict_descr = new (pyston_getset_cls) BoxedGetsetDescriptor(typeDict, typeSetDict, NULL);
dict_descr = new (pyston_getset_cls) BoxedGetsetDescriptor(typeSubDict, typeSubSetDict, NULL);
gc::registerPermanentRoot(dict_descr);
type_cls->giveAttr("__dict__", dict_descr);
type_cls->giveAttr("__dict__", new (pyston_getset_cls) BoxedGetsetDescriptor(typeDict, NULL, NULL));
instancemethod_cls = BoxedHeapClass::create(type_cls, object_cls, &instancemethodGCHandler, 0,
......@@ -2619,6 +2639,8 @@ void setupRuntime() {
attrwrapper_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::str, UNKNOWN, 1)));
attrwrapper_cls->giveAttr("__contains__",
new BoxedFunction(boxRTFunction((void*)AttrWrapper::contains, UNKNOWN, 2)));
attrwrapper_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::eq, UNKNOWN, 2)));
attrwrapper_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::ne, UNKNOWN, 2)));
attrwrapper_cls->giveAttr("keys", new BoxedFunction(boxRTFunction((void*)AttrWrapper::keys, LIST, 1)));
attrwrapper_cls->giveAttr("values", new BoxedFunction(boxRTFunction((void*)AttrWrapper::values, LIST, 1)));
attrwrapper_cls->giveAttr("items", new BoxedFunction(boxRTFunction((void*)AttrWrapper::items, LIST, 1)));
......@@ -2652,6 +2674,7 @@ void setupRuntime() {
PyCallIter_AddHasNext();
PyType_Ready(&PyCallIter_Type);
PyType_Ready(&PyCObject_Type);
PyType_Ready(&PyDictProxy_Type);
initerrno();
init_sha();
......
......@@ -391,6 +391,17 @@ CREATE_UN(s_hex, PyString_FromString("hex"));
#undef CREATE_BIN
static int
slots_tester_compare(PyObject* x, PyObject* y)
{
printf("inside slots_tester_compare\n");
if (x < y)
return -1;
else if (x == y)
return 0;
return 1;
}
static PyNumberMethods slots_tester_as_number = {
(binaryfunc)s_add, /* nb_add */
(binaryfunc)s_subtract, /* nb_subtract */
......@@ -442,7 +453,7 @@ static PyTypeObject slots_tester_num = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
slots_tester_compare, /* tp_compare */
0, /* tp_repr */
&slots_tester_as_number, /* tp_as_number */
0, /* tp_as_sequence */
......
# expected: fail
# we don't support tp_compare yet
s = 'Hello world'
t = buffer(s, 6, 5)
s2 = "Goodbye world"
t2 = buffer(s2, 8, 5)
print t == t2
s = 'Hello world'
t = buffer(s, 6, 5)
print t
s2 = "Goodbye world"
t2 = buffer(s2, 8, 5)
print t2
print t == t2
......@@ -38,6 +38,8 @@ for i in xrange(3):
print float(t)
print hex(t)
print oct(t)
print slots_test.SlotsTesterNum(0) == slots_test.SlotsTesterNum(0)
print slots_test.SlotsTesterNum(0) == slots_test.SlotsTesterNum(1)
for i in slots_test.SlotsTesterSeq(6):
print i
......
......@@ -59,6 +59,9 @@ class C(object):
def __ge__(self, rhs):
print "ge"
return False
def __cmp__(self, rhs):
print "cmp"
assert False
for i in xrange(2):
print C("") > 2
......@@ -113,3 +116,34 @@ d = {}
for i in xrange(20):
d[NonboolEq(i % 10)] = i
print len(d), sorted(d.values())
class C(object):
def __init__(self, n):
self.n = n
def __eq__(self, rhs):
print "eq"
if isinstance(rhs, C):
return self.n == rhs.n
return self.n == int(rhs)
def __cmp__(self, rhs):
print "cmp"
v = 0
if isinstance(rhs, C):
v = rhs.n
else:
v = int(rhs)
if self.n < v:
return -2L
elif self.n > v:
return 2L
return 0L
for lhs in (C(0), C(1), 0, 1):
for rhs in (C(0), C(1), 0, 1):
print lhs < rhs, lhs == rhs, lhs != rhs, lhs > rhs, lhs <= rhs, lhs >= rhs
del C.__eq__
for lhs in (C(0), C(1), 0, 1):
for rhs in (C(0), C(1), 0, 1):
print lhs < rhs, lhs == rhs, lhs != rhs, lhs > rhs, lhs <= rhs, lhs >= rhs
......@@ -31,9 +31,8 @@ print 'C.dd is %s' % str(C.dd)
print 'C.ndd is %s' % str(C.ndd)
C.dd = 6
C.ndd = 7
#TODO it would be nice to print these out (once __dict__ is implemented)
#print C.__dict__['dd']
#print C.__dict__['ndd']
print C.__dict__['dd']
print C.__dict__['ndd']
print C.dd
print C.ndd
......@@ -62,8 +61,8 @@ print 'D.dd is %s' % str(D.dd)
print 'D.ndd is %s' % str(D.ndd)
D.dd = 6
D.ndd = 7
#print D.__dict__['dd']
#print D.__dict__['ndd']
print D.__dict__['dd']
print D.__dict__['ndd']
class DataDescriptor(object):
def __get__(self, obj, type): return 1
......@@ -82,7 +81,7 @@ print d1.a
print 'D1.a is %s' % str(D1.a)
D1.a = 6
#print D1.__dict__['a']
print D1.__dict__['a']
class C2(object):
a = 4
......@@ -93,7 +92,7 @@ print d2.a
print 'D2.a is %s' % str(D2.a)
D2.a = 6
#print D2.__dict__['a']
print D2.__dict__['a']
class C3(object):
a = NonDataDescriptor()
......@@ -104,15 +103,15 @@ print d3.a
print 'D3.a is %s' % str(D3.a)
D3.a = 6
#print D3.__dict__['a']
print D3.__dict__['a']
class C4(object):
a = 6
class D4(C4):
a = NonDataDescriptor()
d4 = D4()
#print d4.a
print d4.a
print 'D4.a is %s' % str(D4.a)
D4.a = 6
#print D4.__dict__['a']
print D4.__dict__['a']
......@@ -49,3 +49,14 @@ d1.clear()
print hasattr(c, "attr")
print hasattr(c, "foo")
print c.__dict__ is d1
dictproxy = C.__dict__
print type(dictproxy)
print "foo" in dictproxy
print "foo" in dictproxy.keys()
print type(dictproxy["foo"])
print dictproxy == dict(C.__dict__)
try:
dictproxy["test"] = "val"
except Exception as e:
print e
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