mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-09 20:57:22 +02:00
try to use python.net as the bridge.
This commit is contained in:
265
Pythonnet.Runtime/metatype.cs
Normal file
265
Pythonnet.Runtime/metatype.cs
Normal file
@@ -0,0 +1,265 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// The managed metatype. This object implements the type of all reflected
|
||||
// types. It also provides support for single-inheritance from reflected
|
||||
// managed types.
|
||||
//========================================================================
|
||||
|
||||
internal class MetaType : ManagedType {
|
||||
|
||||
static IntPtr PyCLRMetaType;
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Metatype initialization. This bootstraps the CLR metatype to life.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr Initialize() {
|
||||
PyCLRMetaType = TypeManager.CreateMetaType(typeof(MetaType));
|
||||
return PyCLRMetaType;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Metatype __new__ implementation. This is called to create a new
|
||||
// class / type when a reflected class is subclassed.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {
|
||||
int len = Runtime.PyTuple_Size(args);
|
||||
if (len < 3) {
|
||||
return Exceptions.RaiseTypeError("invalid argument list");
|
||||
}
|
||||
|
||||
//IntPtr name = Runtime.PyTuple_GetItem(args, 0);
|
||||
IntPtr bases = Runtime.PyTuple_GetItem(args, 1);
|
||||
IntPtr dict = Runtime.PyTuple_GetItem(args, 2);
|
||||
|
||||
// We do not support multiple inheritance, so the bases argument
|
||||
// should be a 1-item tuple containing the type we are subtyping.
|
||||
// That type must itself have a managed implementation. We check
|
||||
// that by making sure its metatype is the CLR metatype.
|
||||
|
||||
if (Runtime.PyTuple_Size(bases) != 1) {
|
||||
return Exceptions.RaiseTypeError(
|
||||
"cannot use multiple inheritance with managed classes"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
IntPtr base_type = Runtime.PyTuple_GetItem(bases, 0);
|
||||
IntPtr mt = Runtime.PyObject_TYPE(base_type);
|
||||
|
||||
if (!((mt == PyCLRMetaType) || (mt == Runtime.PyTypeType))) {
|
||||
return Exceptions.RaiseTypeError("invalid metatype");
|
||||
}
|
||||
|
||||
// Ensure that the reflected type is appropriate for subclassing,
|
||||
// disallowing subclassing of delegates, enums and array types.
|
||||
|
||||
ClassBase cb = GetManagedObject(base_type) as ClassBase;
|
||||
if (cb != null) {
|
||||
if (! cb.CanSubclass() ) {
|
||||
return Exceptions.RaiseTypeError(
|
||||
"delegates, enums and array types cannot be subclassed"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
IntPtr slots = Runtime.PyDict_GetItemString(dict, "__slots__");
|
||||
if (slots != IntPtr.Zero) {
|
||||
return Exceptions.RaiseTypeError(
|
||||
"subclasses of managed classes do not support __slots__"
|
||||
);
|
||||
}
|
||||
|
||||
// hack for now... fix for 1.0
|
||||
//return TypeManager.CreateSubType(args);
|
||||
|
||||
|
||||
// right way
|
||||
|
||||
IntPtr func = Marshal.ReadIntPtr(Runtime.PyTypeType,
|
||||
TypeOffset.tp_new);
|
||||
IntPtr type = NativeCall.Call_3(func, tp, args, kw);
|
||||
if (type == IntPtr.Zero) {
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
int flags = TypeFlags.Default;
|
||||
flags |= TypeFlags.Managed;
|
||||
flags |= TypeFlags.HeapType;
|
||||
flags |= TypeFlags.BaseType;
|
||||
flags |= TypeFlags.Subclass;
|
||||
flags |= TypeFlags.HaveGC;
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
|
||||
|
||||
TypeManager.CopySlot(base_type, type, TypeOffset.tp_dealloc);
|
||||
|
||||
// Hmm - the standard subtype_traverse, clear look at ob_size to
|
||||
// do things, so to allow gc to work correctly we need to move
|
||||
// our hidden handle out of ob_size. Then, in theory we can
|
||||
// comment this out and still not crash.
|
||||
TypeManager.CopySlot(base_type, type, TypeOffset.tp_traverse);
|
||||
TypeManager.CopySlot(base_type, type, TypeOffset.tp_clear);
|
||||
|
||||
|
||||
// for now, move up hidden handle...
|
||||
IntPtr gc = Marshal.ReadIntPtr(base_type, TypeOffset.magic());
|
||||
Marshal.WriteIntPtr(type, TypeOffset.magic(), gc);
|
||||
|
||||
//DebugUtil.DumpType(base_type);
|
||||
//DebugUtil.DumpType(type);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
public static IntPtr tp_alloc(IntPtr mt, int n) {
|
||||
IntPtr type = Runtime.PyType_GenericAlloc(mt, n);
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
public static void tp_free(IntPtr tp) {
|
||||
Runtime.PyObject_GC_Del(tp);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Metatype __call__ implementation. This is needed to ensure correct
|
||||
// initialization (__init__ support), because the tp_call we inherit
|
||||
// from PyType_Type won't call __init__ for metatypes it doesnt know.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw) {
|
||||
IntPtr func = Marshal.ReadIntPtr(tp, TypeOffset.tp_new);
|
||||
if (func == IntPtr.Zero) {
|
||||
return Exceptions.RaiseTypeError("invalid object");
|
||||
}
|
||||
|
||||
IntPtr obj = NativeCall.Call_3(func, tp, args, kw);
|
||||
if (obj == IntPtr.Zero) {
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
IntPtr py__init__ = Runtime.PyString_FromString("__init__");
|
||||
IntPtr type = Runtime.PyObject_TYPE(obj);
|
||||
IntPtr init = Runtime._PyType_Lookup(type, py__init__);
|
||||
Runtime.Decref(py__init__);
|
||||
Runtime.PyErr_Clear();
|
||||
|
||||
if (init != IntPtr.Zero) {
|
||||
IntPtr bound = Runtime.GetBoundArgTuple(obj, args);
|
||||
if (bound == IntPtr.Zero) {
|
||||
Runtime.Decref(obj);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
IntPtr result = Runtime.PyObject_Call(init, bound, kw);
|
||||
Runtime.Decref(bound);
|
||||
|
||||
if (result == IntPtr.Zero) {
|
||||
Runtime.Decref(obj);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
Runtime.Decref(result);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Type __setattr__ implementation for reflected types. Note that this
|
||||
// is slightly different than the standard setattr implementation for
|
||||
// the normal Python metatype (PyTypeType). We need to look first in
|
||||
// the type object of a reflected type for a descriptor in order to
|
||||
// support the right setattr behavior for static fields and properties.
|
||||
//====================================================================
|
||||
|
||||
public static int tp_setattro(IntPtr tp, IntPtr name, IntPtr value) {
|
||||
IntPtr descr = Runtime._PyType_Lookup(tp, name);
|
||||
|
||||
if (descr != IntPtr.Zero) {
|
||||
IntPtr dt = Runtime.PyObject_TYPE(descr);
|
||||
IntPtr fp = Marshal.ReadIntPtr(dt, TypeOffset.tp_descr_set);
|
||||
if (fp != IntPtr.Zero) {
|
||||
return NativeCall.Impl.Int_Call_3(fp, descr, name, value);
|
||||
}
|
||||
Exceptions.SetError(Exceptions.AttributeError,
|
||||
"attribute is read-only");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (Runtime.PyObject_GenericSetAttr(tp, name, value) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// The metatype has to implement [] semantics for generic types, so
|
||||
// here we just delegate to the generic type def implementation. Its
|
||||
// own mp_subscript
|
||||
//====================================================================
|
||||
public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) {
|
||||
ClassBase cb = GetManagedObject(tp) as ClassBase;
|
||||
if (cb != null) {
|
||||
return cb.type_subscript(idx);
|
||||
}
|
||||
return Exceptions.RaiseTypeError("unsubscriptable object");
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Dealloc implementation. This is called when a Python type generated
|
||||
// by this metatype is no longer referenced from the Python runtime.
|
||||
//====================================================================
|
||||
|
||||
public static void tp_dealloc(IntPtr tp) {
|
||||
// Fix this when we dont cheat on the handle for subclasses!
|
||||
|
||||
int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags);
|
||||
if ((flags & TypeFlags.Subclass) == 0) {
|
||||
IntPtr gc = Marshal.ReadIntPtr(tp, TypeOffset.magic());
|
||||
((GCHandle)gc).Free();
|
||||
}
|
||||
|
||||
IntPtr op = Marshal.ReadIntPtr(tp, TypeOffset.ob_type);
|
||||
Runtime.Decref(op);
|
||||
|
||||
// Delegate the rest of finalization the Python metatype. Note
|
||||
// that the PyType_Type implementation of tp_dealloc will call
|
||||
// tp_free on the type of the type being deallocated - in this
|
||||
// case our CLR metatype. That is why we implement tp_free.
|
||||
|
||||
op = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_dealloc);
|
||||
NativeCall.Void_Call_1(op, tp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user