Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/runtime/converter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ internal static Type GetTypeByAlias(IntPtr op) {
// This always returns a new reference. Note that the System.Decimal
// type has no Python equivalent and converts to a managed instance.
//====================================================================
internal static IntPtr ToPython<T>(T value)
{
return ToPython(value, typeof(T));
}

internal static IntPtr ToPython(Object value, Type type) {
IntPtr result = IntPtr.Zero;
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/importhook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ internal static void Initialize() {
IntPtr mod = Runtime.PyDict_GetItemString(dict, "__builtin__");
py_import = Runtime.PyObject_GetAttrString(mod, "__import__");
#endif
hook = new MethodWrapper(typeof(ImportHook), "__import__");
Runtime.PyObject_SetAttrString(mod, "__import__", hook.ptr);
hook = new MethodWrapper(typeof(ImportHook), "__import__", "TernaryFunc");
Runtime.PyObject_SetAttrString(mod, "__import__", hook.ptr);
Runtime.Decref(hook.ptr);

root = new CLRModule();
Expand Down
13 changes: 8 additions & 5 deletions src/runtime/interop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ public static void FreeModuleDef(IntPtr ptr) {
// } PyModuleDef

public static int name = 0;
}
}
#endif // PYTHON3

/// <summary>
Expand Down Expand Up @@ -445,16 +445,19 @@ static Interop() {
pmap["bf_getwritebuffer"] = p["IntObjArgFunc"];
pmap["bf_getsegcount"] = p["ObjObjFunc"];
pmap["bf_getcharbuffer"] = p["IntObjArgFunc"];

pmap["__import__"] = p["TernaryFunc"];
}

internal static Type GetPrototype(string name) {
return pmap[name] as Type;
}

internal static IntPtr GetThunk(MethodInfo method) {
Type dt = Interop.GetPrototype(method.Name);
internal static IntPtr GetThunk(MethodInfo method, string funcType = null) {
Type dt;
if (funcType != null)
dt = typeof(Interop).GetNestedType(funcType) as Type;
else
dt = GetPrototype(method.Name);

if (dt != null) {
IntPtr tmp = Marshal.AllocHGlobal(IntPtr.Size);
Delegate d = Delegate.CreateDelegate(dt, method);
Expand Down
42 changes: 38 additions & 4 deletions src/runtime/metatype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,44 @@ public static void tp_dealloc(IntPtr tp) {
return;
}

static IntPtr DoInstanceCheck(IntPtr tp, IntPtr args, bool checkType)
{
ClassBase cb = GetManagedObject(tp) as ClassBase;

if (cb == null)
return Runtime.PyFalse;

using (PyList argsObj = new PyList(args))
{
if (argsObj.Length() != 1)
return Exceptions.RaiseTypeError("Invalid parameter count");

PyObject arg = argsObj[0];
PyObject otherType;
if (checkType)
otherType = arg;
else
otherType = arg.GetPythonType();

if (Runtime.PyObject_TYPE(otherType.Handle) != PyCLRMetaType)
return Runtime.PyFalse;

ClassBase otherCb = GetManagedObject(otherType.Handle) as ClassBase;
if (otherCb == null)
return Runtime.PyFalse;

return Converter.ToPython(cb.type.IsAssignableFrom(otherCb.type));
}
}



public static IntPtr __instancecheck__(IntPtr tp, IntPtr args)
{
return DoInstanceCheck(tp, args, false);
}

public static IntPtr __subclasscheck__(IntPtr tp, IntPtr args)
{
return DoInstanceCheck(tp, args, true);
}
}


}
27 changes: 4 additions & 23 deletions src/runtime/methodwrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,41 +25,22 @@ internal class MethodWrapper {
public IntPtr mdef;
public IntPtr ptr;

public MethodWrapper(Type type, string name) {
public MethodWrapper(Type type, string name, string funcType = null) {

// Turn the managed method into a function pointer

IntPtr fp = Interop.GetThunk(type.GetMethod(name));

// XXX - here we create a Python string object, then take the
// char * of the internal string to pass to our methoddef
// structure. Its a hack, and the name is leaked!
#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
IntPtr ps = Runtime.PyBytes_FromString(name);
IntPtr sp = Runtime.PyBytes_AS_STRING(ps);
#else
IntPtr ps = Runtime.PyString_FromString(name);
IntPtr sp = Runtime.PyString_AS_STRING(ps);
#endif
IntPtr fp = Interop.GetThunk(type.GetMethod(name), funcType);

// Allocate and initialize a PyMethodDef structure to represent
// the managed method, then create a PyCFunction.

mdef = Runtime.PyMem_Malloc(4 * IntPtr.Size);
Marshal.WriteIntPtr(mdef, sp);
Marshal.WriteIntPtr(mdef, (1 * IntPtr.Size), fp);
Marshal.WriteIntPtr(mdef, (2 * IntPtr.Size), (IntPtr)0x0003); // METH_VARARGS | METH_KEYWORDS
Marshal.WriteIntPtr(mdef, (3 * IntPtr.Size), IntPtr.Zero);
TypeManager.WriteMethodDef(mdef, name, fp, 0x0003);
ptr = Runtime.PyCFunction_NewEx(mdef, IntPtr.Zero, IntPtr.Zero);
}

public IntPtr Call(IntPtr args, IntPtr kw) {
return Runtime.PyCFunction_Call(ptr, args, kw);
}


}


}

}
44 changes: 43 additions & 1 deletion src/runtime/typemanager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,28 @@ internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr
}
}

internal static IntPtr WriteMethodDef(IntPtr mdef, IntPtr name, IntPtr func, int flags, IntPtr doc)
{
Marshal.WriteIntPtr(mdef, name);
Marshal.WriteIntPtr(mdef, (1 * IntPtr.Size), func);
Marshal.WriteInt32(mdef, (2 * IntPtr.Size), flags);
Marshal.WriteIntPtr(mdef, (3 * IntPtr.Size), doc);
return mdef + 4 * IntPtr.Size;
}

internal static IntPtr WriteMethodDef(IntPtr mdef, string name, IntPtr func, int flags = 0x0001, string doc = null)
{
IntPtr namePtr = Marshal.StringToHGlobalAnsi(name);
IntPtr docPtr = doc != null ? Marshal.StringToHGlobalAnsi(doc) : IntPtr.Zero;

return WriteMethodDef(mdef, namePtr, func, flags, docPtr);
}

internal static IntPtr WriteMethodDefSentinel(IntPtr mdef)
{
return WriteMethodDef(mdef, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero);
}

internal static IntPtr CreateMetaType(Type impl) {

// The managed metatype is functionally little different than the
Expand Down Expand Up @@ -300,7 +322,27 @@ internal static IntPtr CreateMetaType(Type impl) {
flags |= TypeFlags.Managed;
flags |= TypeFlags.HeapType;
flags |= TypeFlags.HaveGC;
Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);

// We need space for 3 PyMethodDef structs, each of them
// 4 int-ptrs in size.
IntPtr mdef = Runtime.PyMem_Malloc(3 * (4 * IntPtr.Size));
IntPtr mdefStart = mdef;
mdef = WriteMethodDef(
mdef,
"__instancecheck__",
Interop.GetThunk(typeof(MetaType).GetMethod("__instancecheck__"), "BinaryFunc")
);

mdef = WriteMethodDef(
mdef,
"__subclasscheck__",
Interop.GetThunk(typeof(MetaType).GetMethod("__subclasscheck__"), "BinaryFunc")
);

mdef = WriteMethodDefSentinel(mdef);

Marshal.WriteIntPtr(type, TypeOffset.tp_methods, mdefStart);

Runtime.PyType_Ready(type);

Expand Down
12 changes: 10 additions & 2 deletions src/tests/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,12 +348,20 @@ def testExceptionIsInstanceOfSystemObject(self):
# without causing a crash in the CPython interpreter). This test is
# here mainly to remind me to update the caveat in the documentation
# one day when when exceptions can be new-style classes.

# This behaviour is now over-shadowed by the implementation of
# __instancecheck__ (i.e., overloading isinstance), so for all Python
# version >= 2.6 we expect isinstance(<managed exception>, Object) to
# be true, even though it does not really subclass Object.
from System import OverflowException
from System import Object

o = OverflowException('error')
self.assertFalse(isinstance(o, Object))


if sys.version_info >= (2, 6):
self.assertTrue(isinstance(o, Object))
else:
self.assertFalse(isinstance(o, Object))


def test_suite():
Expand Down