Commit 99058d3d authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add simple support for methods with the METH_CLASS flag

I think this is ok, but it's implemented pretty differently from CPython
for now so I'm not sure.
parent 7785fe53
...@@ -24,29 +24,39 @@ Box* BoxedMethodDescriptor::__call__(BoxedMethodDescriptor* self, Box* obj, Boxe ...@@ -24,29 +24,39 @@ Box* BoxedMethodDescriptor::__call__(BoxedMethodDescriptor* self, Box* obj, Boxe
assert(varargs->cls == tuple_cls); assert(varargs->cls == tuple_cls);
assert(kwargs->cls == dict_cls); assert(kwargs->cls == dict_cls);
if (!isSubclass(obj->cls, self->type)) int ml_flags = self->method->ml_flags;
raiseExcHelper(TypeError, "descriptor '%s' requires a '%s' object but received a '%s'", self->method->ml_name,
getFullNameOfClass(self->type).c_str(), getFullTypeName(obj).c_str()); int call_flags;
if (ml_flags & METH_CLASS) {
if (!isSubclass(obj->cls, type_cls))
raiseExcHelper(TypeError, "descriptor '%s' requires a type but received a '%s'", self->method->ml_name,
getFullTypeName(obj).c_str());
call_flags = ml_flags & (~METH_CLASS);
} else {
if (!isSubclass(obj->cls, self->type))
raiseExcHelper(TypeError, "descriptor '%s' requires a '%s' object but received a '%s'",
self->method->ml_name, getFullNameOfClass(self->type).c_str(), getFullTypeName(obj).c_str());
call_flags = ml_flags;
}
threading::GLPromoteRegion _gil_lock; threading::GLPromoteRegion _gil_lock;
int ml_flags = self->method->ml_flags;
Box* rtn; Box* rtn;
if (ml_flags == METH_NOARGS) { if (call_flags == METH_NOARGS) {
assert(varargs->elts.size() == 0); assert(varargs->elts.size() == 0);
assert(kwargs->d.size() == 0); assert(kwargs->d.size() == 0);
rtn = (Box*)self->method->ml_meth(obj, NULL); rtn = (Box*)self->method->ml_meth(obj, NULL);
} else if (ml_flags == METH_VARARGS) { } else if (call_flags == METH_VARARGS) {
assert(kwargs->d.size() == 0); assert(kwargs->d.size() == 0);
rtn = (Box*)self->method->ml_meth(obj, varargs); rtn = (Box*)self->method->ml_meth(obj, varargs);
} else if (ml_flags == (METH_VARARGS | METH_KEYWORDS)) { } else if (call_flags == (METH_VARARGS | METH_KEYWORDS)) {
rtn = (Box*)((PyCFunctionWithKeywords)self->method->ml_meth)(obj, varargs, kwargs); rtn = (Box*)((PyCFunctionWithKeywords)self->method->ml_meth)(obj, varargs, kwargs);
} else if (ml_flags == METH_O) { } else if (call_flags == METH_O) {
assert(kwargs->d.size() == 0); assert(kwargs->d.size() == 0);
assert(varargs->elts.size() == 1); assert(varargs->elts.size() == 1);
rtn = (Box*)self->method->ml_meth(obj, varargs->elts[0]); rtn = (Box*)self->method->ml_meth(obj, varargs->elts[0]);
} else { } else {
RELEASE_ASSERT(0, "0x%x", ml_flags); RELEASE_ASSERT(0, "0x%x", call_flags);
} }
checkAndThrowCAPIException(); checkAndThrowCAPIException();
......
...@@ -389,7 +389,8 @@ extern "C" PyObject* Py_InitModule4(const char* name, PyMethodDef* methods, cons ...@@ -389,7 +389,8 @@ extern "C" PyObject* Py_InitModule4(const char* name, PyMethodDef* methods, cons
if (VERBOSITY()) if (VERBOSITY())
printf("Loading method %s\n", methods->ml_name); printf("Loading method %s\n", methods->ml_name);
assert((methods->ml_flags & (~(METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O))) == 0); RELEASE_ASSERT((methods->ml_flags & (~(METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O))) == 0, "%d",
methods->ml_flags);
module->giveAttr(methods->ml_name, module->giveAttr(methods->ml_name,
new BoxedCApiFunction(methods->ml_flags, passthrough, methods->ml_name, methods->ml_meth)); new BoxedCApiFunction(methods->ml_flags, passthrough, methods->ml_name, methods->ml_meth));
......
...@@ -144,10 +144,20 @@ public: ...@@ -144,10 +144,20 @@ public:
static Box* __get__(BoxedMethodDescriptor* self, Box* inst, Box* owner) { static Box* __get__(BoxedMethodDescriptor* self, Box* inst, Box* owner) {
RELEASE_ASSERT(self->cls == method_cls, ""); RELEASE_ASSERT(self->cls == method_cls, "");
// CPython handles this differently: they create the equivalent of different BoxedMethodDescriptor
// objects but with different class objects, which define different __get__ and __call__ methods.
if (self->method->ml_flags & METH_CLASS)
return boxInstanceMethod(owner, self);
if (self->method->ml_flags & METH_STATIC)
Py_FatalError("unimplemented");
if (self->method->ml_flags & METH_COEXIST)
Py_FatalError("unimplemented");
if (inst == None) if (inst == None)
return self; return self;
// CPython apparently returns a "builtin_function_or_method" object else
return boxInstanceMethod(inst, self); return boxInstanceMethod(inst, self);
} }
static Box* __call__(BoxedMethodDescriptor* self, Box* obj, BoxedTuple* varargs, Box** _args); static Box* __call__(BoxedMethodDescriptor* self, Box* obj, BoxedTuple* varargs, Box** _args);
......
...@@ -6,3 +6,6 @@ print repr(datetime.time()) ...@@ -6,3 +6,6 @@ print repr(datetime.time())
print datetime.datetime.__base__ print datetime.datetime.__base__
print repr(datetime.datetime(1, 2, 3)) print repr(datetime.datetime(1, 2, 3))
print str(datetime.timedelta(0)) print str(datetime.timedelta(0))
# now() works on both the class and on its instances:
datetime.datetime.now().now()
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