public static T InvokeGetProperty <T>(IPythonDerivedType obj, string propertyName) { FieldInfo fi = obj.GetType().GetField("__pyobj__"); CLRObject self = (CLRObject)fi.GetValue(obj); if (null == self) { throw new NullReferenceException("Instance must be specified when getting a property"); } IntPtr gs = Runtime.PyGILState_Ensure(); try { Runtime.Incref(self.pyHandle); using (PyObject pyself = new PyObject(self.pyHandle)) using (PyObject pyvalue = pyself.GetAttr(propertyName)) return((T)pyvalue.AsManagedObject(typeof(T))); } finally { Runtime.PyGILState_Release(gs); } }
/// <summary> /// This is the implementation of the overridden methods in the derived /// type. It looks for a python method with the same name as the method /// on the managed base class and if it exists and isn't the managed /// method binding (i.e. it has been overridden in the derived python /// class) it calls it, otherwise it calls the base method. /// </summary> public static T InvokeMethod <T>(IPythonDerivedType obj, string methodName, string origMethodName, object[] args) { FieldInfo fi = obj.GetType().GetField("__pyobj__"); var self = (CLRObject)fi.GetValue(obj); if (null != self) { var disposeList = new List <PyObject>(); IntPtr gs = Runtime.PyGILState_Ensure(); try { Runtime.XIncref(self.pyHandle); var pyself = new PyObject(self.pyHandle); disposeList.Add(pyself); Runtime.XIncref(Runtime.PyNone); var pynone = new PyObject(Runtime.PyNone); disposeList.Add(pynone); PyObject method = pyself.GetAttr(methodName, pynone); disposeList.Add(method); if (method.Handle != Runtime.PyNone) { // if the method hasn't been overridden then it will be a managed object ManagedType managedMethod = ManagedType.GetManagedObject(method.Handle); if (null == managedMethod) { var pyargs = new PyObject[args.Length]; for (var i = 0; i < args.Length; ++i) { pyargs[i] = new PyObject(Converter.ToPythonImplicit(args[i])); disposeList.Add(pyargs[i]); } PyObject py_result = method.Invoke(pyargs); disposeList.Add(py_result); return((T)py_result.AsManagedObject(typeof(T))); } } } finally { foreach (PyObject x in disposeList) { x?.Dispose(); } Runtime.PyGILState_Release(gs); } } if (origMethodName == null) { throw new NotImplementedException("Python object does not have a '" + methodName + "' method"); } return((T)obj.GetType().InvokeMember(origMethodName, BindingFlags.InvokeMethod, null, obj, args)); }
/// <summary> /// Python properties may have the following function attributes set to control how they're exposed: /// - _clr_property_type_ - property type (required) /// </summary> /// <param name="propertyName">Property name to add to the type</param> /// <param name="func">Python property object</param> /// <param name="typeBuilder">TypeBuilder for the new type the method/property is to be added to</param> private static void AddPythonProperty(string propertyName, PyObject func, TypeBuilder typeBuilder) { // add the method to call back into python MethodAttributes methodAttribs = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.ReuseSlot | MethodAttributes.HideBySig | MethodAttributes.SpecialName; using (PyObject pyPropertyType = func.GetAttr("_clr_property_type_")) { var propertyType = pyPropertyType.AsManagedObject(typeof(Type)) as Type; if (propertyType == null) { throw new ArgumentException("_clr_property_type must be a CLR type"); } PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType, null); if (func.HasAttr("fget")) { using (PyObject pyfget = func.GetAttr("fget")) { if (pyfget.IsTrue()) { MethodBuilder methodBuilder = typeBuilder.DefineMethod("get_" + propertyName, methodAttribs, propertyType, null); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, propertyName); il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeGetProperty").MakeGenericMethod(propertyType)); il.Emit(OpCodes.Ret); propertyBuilder.SetGetMethod(methodBuilder); } } } if (func.HasAttr("fset")) { using (PyObject pyset = func.GetAttr("fset")) { if (pyset.IsTrue()) { MethodBuilder methodBuilder = typeBuilder.DefineMethod("set_" + propertyName, methodAttribs, null, new[] { propertyType }); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, propertyName); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeSetProperty").MakeGenericMethod(propertyType)); il.Emit(OpCodes.Ret); propertyBuilder.SetSetMethod(methodBuilder); } } } } }
/// <summary> /// Python method may have the following function attributes set to control how they're exposed: /// - _clr_return_type_ - method return type (required) /// - _clr_arg_types_ - list of method argument types (required) /// - _clr_method_name_ - method name, if different from the python method name (optional) /// </summary> /// <param name="methodName">Method name to add to the type</param> /// <param name="func">Python callable object</param> /// <param name="typeBuilder">TypeBuilder for the new type the method/property is to be added to</param> private static void AddPythonMethod(string methodName, PyObject func, TypeBuilder typeBuilder) { if (func.HasAttr("_clr_method_name_")) { using (PyObject pyMethodName = func.GetAttr("_clr_method_name_")) { methodName = pyMethodName.ToString(); } } using (PyObject pyReturnType = func.GetAttr("_clr_return_type_")) using (PyObject pyArgTypes = func.GetAttr("_clr_arg_types_")) { var returnType = pyReturnType.AsManagedObject(typeof(Type)) as Type; if (returnType == null) { returnType = typeof(void); } if (!pyArgTypes.IsIterable()) { throw new ArgumentException("_clr_arg_types_ must be a list or tuple of CLR types"); } var argTypes = new List <Type>(); foreach (PyObject pyArgType in pyArgTypes) { var argType = pyArgType.AsManagedObject(typeof(Type)) as Type; if (argType == null) { throw new ArgumentException("_clr_arg_types_ must be a list or tuple of CLR types"); } argTypes.Add(argType); } // add the method to call back into python MethodAttributes methodAttribs = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.ReuseSlot | MethodAttributes.HideBySig; MethodBuilder methodBuilder = typeBuilder.DefineMethod(methodName, methodAttribs, returnType, argTypes.ToArray()); ILGenerator il = methodBuilder.GetILGenerator(); il.DeclareLocal(typeof(object[])); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, methodName); il.Emit(OpCodes.Ldnull); // don't fall back to the base type's method il.Emit(OpCodes.Ldc_I4, argTypes.Count); il.Emit(OpCodes.Newarr, typeof(object)); il.Emit(OpCodes.Stloc_0); for (var i = 0; i < argTypes.Count; ++i) { il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldc_I4, i); il.Emit(OpCodes.Ldarg, i + 1); if (argTypes[i].IsValueType) { il.Emit(OpCodes.Box, argTypes[i]); } il.Emit(OpCodes.Stelem, typeof(object)); } il.Emit(OpCodes.Ldloc_0); if (returnType == typeof(void)) { il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeMethodVoid")); } else { il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeMethod").MakeGenericMethod(returnType)); } il.Emit(OpCodes.Ret); } }
public override object ToClr(PyObject pyObj) { return(pyObj.AsManagedObject(typeof(double))); }