/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Python.Runtime; namespace QuantConnect.Python { /// /// Provides extension methods for managing python wrapper classes /// public static class PythonWrapper { /// /// Validates that the specified completely implements the provided interface type /// /// The interface type /// The model implementing the interface type public static PyObject ValidateImplementationOf(this PyObject model) { var notInterface = !typeof(TInterface).IsInterface; var missingMembers = new List(); var members = typeof(TInterface).GetMembers(BindingFlags.Public | BindingFlags.Instance); using (Py.GIL()) { foreach (var member in members) { var method = member as MethodInfo; if ((method == null || !method.IsSpecialName) && !model.HasAttr(member.Name) && !model.HasAttr(member.Name.ToSnakeCase())) { if (notInterface) { if (method != null && !method.IsAbstract && (method.IsFinal || !method.IsVirtual || method.DeclaringType != typeof(TInterface))) { continue; } else if (member is ConstructorInfo) { continue; } else if (member.Name is "ToString") { continue; } } missingMembers.Add(member.Name); } } if (missingMembers.Any()) { throw new NotImplementedException( Messages.PythonWrapper.InterfaceNotFullyImplemented(typeof(TInterface).Name, model.GetPythonType().Name, missingMembers)); } } return model; } /// /// Invokes the specified method on the provided instance with the specified arguments /// /// The instance /// The name of the method to invoke /// The arguments to call the method with /// The return value of the called method converted into the type public static T InvokeMethod(this PyObject model, string methodName, params object[] args) { using var _ = Py.GIL(); return InvokeMethodImpl(model, methodName, args).GetAndDispose(); } /// /// Invokes the specified method on the provided instance with the specified arguments /// /// The instance /// The name of the method to invoke /// The arguments to call the method with public static void InvokeMethod(this PyObject model, string methodName, params object[] args) { InvokeMethodImpl(model, methodName, args); } /// /// Invokes the given method with the specified arguments /// /// The method to invoke /// The arguments to call the method with /// The return value of the called method converted into the type public static T Invoke(this PyObject method, params object[] args) { using var _ = Py.GIL(); return InvokeMethodImpl(method, args).GetAndDispose(); } /// /// Invokes the given method with the specified arguments /// /// The method to invoke /// The arguments to call the method with public static PyObject Invoke(this PyObject method, params object[] args) { return InvokeMethodImpl(method, args); } private static PyObject InvokeMethodImpl(PyObject model, string methodName, params object[] args) { using var _ = Py.GIL(); PyObject method = model.GetMethod(methodName); return InvokeMethodImpl(method, args); } private static PyObject InvokeMethodImpl(PyObject method, params object[] args) { using var _ = Py.GIL(); return method.Invoke(args.Select(arg => arg.ToPython()).ToArray()); } } }