[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/QuantConnect/pythonnet/master/src/runtime/PythonEngine.cs [Back]  [Original]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;

using Python.Runtime.Native;

namespace Python.Runtime
{
    /// 
    /// This class provides the public interface of the Python runtime.
    /// 
    public class PythonEngine : IDisposable
    {
        private static DelegateManager? delegateManager;
        private static bool initialized;
        private static IntPtr _pythonHome = IntPtr.Zero;
        private static IntPtr _programName = IntPtr.Zero;
        private static IntPtr _pythonPath = IntPtr.Zero;
        private static InteropConfiguration interopConfiguration = InteropConfiguration.MakeDefault();

        public PythonEngine()
        {
            Initialize();
        }

        public PythonEngine(params string[] args)
        {
            Initialize(args);
        }

        public PythonEngine(IEnumerable args)
        {
            Initialize(args);
        }

        public void Dispose()
        {
            Shutdown();
        }

        public static bool IsInitialized
        {
            get { return initialized; }
        }

        private static void EnsureInitialized()
        {
            if (!IsInitialized)
                throw new InvalidOperationException(
                    "Python must be initialized for this operation"
                );
        }

        /// Set to true to enable GIL debugging assistance.
        public static bool DebugGIL { get; set; } = false;

        internal static DelegateManager DelegateManager
        {
            get
            {
                if (delegateManager == null)
                {
                    throw new InvalidOperationException(
                        "DelegateManager has not yet been initialized using Python.Runtime.PythonEngine.Initialize().");
                }
                return delegateManager;
            }
        }

        public static InteropConfiguration InteropConfiguration
        {
            get => interopConfiguration;
            set
            {
                if (IsInitialized)
                    throw new NotSupportedException("Changing interop configuration when engine is running is not supported");

                interopConfiguration = value ?? throw new ArgumentNullException(nameof(InteropConfiguration));
            }
        }

        public static string ProgramName
        {
            get
            {
                IntPtr p = Runtime.TryUsingDll(() => Runtime.Py_GetProgramName());
                return UcsMarshaler.PtrToPy3UnicodePy2String(p) ?? "";
            }
            set
            {
                Marshal.FreeHGlobal(_programName);
                _programName = Runtime.TryUsingDll(
                    () => UcsMarshaler.Py3UnicodePy2StringtoPtr(value)
                );
                Runtime.Py_SetProgramName(_programName);
            }
        }

        public static string PythonHome
        {
            get
            {
                EnsureInitialized();
                IntPtr p = Runtime.TryUsingDll(() => Runtime.Py_GetPythonHome());
                return UcsMarshaler.PtrToPy3UnicodePy2String(p) ?? "";
            }
            set
            {
                // this value is null in the beginning
                Marshal.FreeHGlobal(_pythonHome);
                _pythonHome = UcsMarshaler.Py3UnicodePy2StringtoPtr(value);
                Runtime.TryUsingDll(() => Runtime.Py_SetPythonHome(_pythonHome));
            }
        }

        public static string PythonPath
        {
            get
            {
                IntPtr p = Runtime.TryUsingDll(() => Runtime.Py_GetPath());
                return UcsMarshaler.PtrToPy3UnicodePy2String(p) ?? "";
            }
            set
            {
                Marshal.FreeHGlobal(_pythonPath);
                _pythonPath = Runtime.TryUsingDll(
                    () => UcsMarshaler.Py3UnicodePy2StringtoPtr(value)
                );
                Runtime.Py_SetPath(_pythonPath);
            }
        }

        public static Version MinSupportedVersion => new(3, 7);
        public static Version MaxSupportedVersion => new(3, 14, int.MaxValue, int.MaxValue);
        public static bool IsSupportedVersion(Version version) => version >= MinSupportedVersion && version = 0; --index)
            {
                if (ShutdownHandlers[index] == handler)
                {
                    ShutdownHandlers.RemoveAt(index);
                    break;
                }
            }
        }

        /// 
        /// Run all the shutdown handlers.
        ///
        /// They're run in opposite order they were added.
        /// 
        static void ExecuteShutdownHandlers()
        {
            while(ShutdownHandlers.Count > 0)
            {
                var handler = ShutdownHandlers[ShutdownHandlers.Count - 1];
                ShutdownHandlers.RemoveAt(ShutdownHandlers.Count - 1);
                handler();
            }
        }

        /// 
        /// AcquireLock Method
        /// 
        /// 
        /// Acquire the Python global interpreter lock (GIL). Managed code
        /// *must* call this method before using any objects or calling any
        /// methods on objects in the Python.Runtime namespace. The only
        /// exception is PythonEngine.Initialize, which may be called without
        /// first calling AcquireLock.
        /// Each call to AcquireLock must be matched by a corresponding call
        /// to ReleaseLock, passing the token obtained from AcquireLock.
        /// For more information, see the "Extending and Embedding" section
        /// of the Python documentation on www.python.org.
        /// 
        internal static PyGILState AcquireLock()
        {
            return Runtime.PyGILState_Ensure();
        }


        /// 
        /// ReleaseLock Method
        /// 
        /// 
        /// Release the Python global interpreter lock using a token obtained
        /// from a previous call to AcquireLock.
        /// For more information, see the "Extending and Embedding" section
        /// of the Python documentation on www.python.org.
        /// 
        internal static void ReleaseLock(PyGILState gs)
        {
            Runtime.PyGILState_Release(gs);
        }


        /// 
        /// BeginAllowThreads Method
        /// 
        /// 
        /// Release the Python global interpreter lock to allow other threads
        /// to run. This is equivalent to the Py_BEGIN_ALLOW_THREADS macro
        /// provided by the C Python API.
        /// For more information, see the "Extending and Embedding" section
        /// of the Python documentation on www.python.org.
        /// 
        public static unsafe IntPtr BeginAllowThreads()
        {
            return (IntPtr)Runtime.PyEval_SaveThread();
        }


        /// 
        /// EndAllowThreads Method
        /// 
        /// 
        /// Re-aquire the Python global interpreter lock for the current
        /// thread. This is equivalent to the Py_END_ALLOW_THREADS macro
        /// provided by the C Python API.
        /// For more information, see the "Extending and Embedding" section
        /// of the Python documentation on www.python.org.
        /// 
        public static unsafe void EndAllowThreads(IntPtr ts)
        {
            Runtime.PyEval_RestoreThread((PyThreadState*)ts);
        }

        public static PyObject Compile(string code, string filename = "", RunFlagType mode = RunFlagType.File)
        {
            var flag = (int)mode;
            NewReference ptr = Runtime.Py_CompileString(code, filename, flag);
            PythonException.ThrowIfIsNull(ptr);
            return ptr.MoveToPyObject();
        }


        /// 
        /// Eval Method
        /// 
        /// 
        /// Evaluate a Python expression and returns the result.
        /// It's a subset of Python eval function.
        /// 
        public static PyObject Eval(string code, PyDict? globals = null, PyObject? locals = null)
        {
            PyObject result = RunString(code, globals.BorrowNullable(), locals.BorrowNullable(), RunFlagType.Eval);
            return result;
        }


        /// 
        /// Exec Method
        /// 
        /// 
        /// Run a string containing Python code.
        /// It's a subset of Python exec function.
        /// 
        public static void Exec(string code, PyDict? globals = null, PyObject? locals = null)
        {
            using PyObject result = RunString(code, globals.BorrowNullable(), locals.BorrowNullable(), RunFlagType.File);
            if (result.obj != Runtime.PyNone)
            {
                throw PythonException.ThrowLastAsClrException();
            }
        }
        /// 
        /// Exec Method
        /// 
        /// 
        /// Run a string containing Python code.
        /// It's a subset of Python exec function.
        /// 
        internal static void Exec(string code, BorrowedReference globals, BorrowedReference locals = default)
        {
            using PyObject result = RunString(code, globals: globals, locals: locals, RunFlagType.File);
            if (result.obj != Runtime.PyNone)
            {
                throw PythonException.ThrowLastAsClrException();
            }
        }

        /// 
        /// Gets the Python thread ID.
        /// 
        /// The Python thread ID.
        public static ulong GetPythonThreadID()
        {
            using PyObject threading = Py.Import("threading");
            using PyObject id = threading.InvokeMethod("get_ident");
            return id.As();
        }

        /// 
        /// Interrupts the execution of a thread.
        /// 
        /// The Python thread ID.
        /// The number of thread states modified; this is normally one, but will be zero if the thread id is not found.
        public static int Interrupt(ulong pythonThreadID)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                return Runtime.PyThreadState_SetAsyncExcLLP64((uint)pythonThreadID, Exceptions.KeyboardInterrupt);
            }

            return Runtime.PyThreadState_SetAsyncExcLP64(pythonThreadID, Exceptions.KeyboardInterrupt);
        }

        /// 
        /// RunString Method. Function has been deprecated and will be removed.
        /// Use Exec/Eval/RunSimpleString instead.
        /// 
        [Obsolete("RunString is deprecated and will be removed. Use Exec/Eval/RunSimpleString instead.")]
        public static PyObject RunString(string code, PyDict? globals = null, PyObject? locals = null)
        {
            return RunString(code, globals.BorrowNullable(), locals.BorrowNullable(), RunFlagType.File);
        }

        /// 
        /// Internal RunString Method.
        /// 
        /// 
        /// Run a string containing Python code. Returns the result of
        /// executing the code string as a PyObject instance, or null if
        /// an exception was raised.
        /// 
        internal static PyObject RunString(string code, BorrowedReference globals, BorrowedReference locals, RunFlagType flag)
        {
            if (code is null) throw new ArgumentNullException(nameof(code));

            NewReference tempGlobals = default;
            if (globals.IsNull)
            {
                globals = Runtime.PyEval_GetGlobals();
                if (globals.IsNull)
                {
                    tempGlobals = Runtime.PyDict_New();
                    globals = tempGlobals.BorrowOrThrow();
                    Runtime.PyDict_SetItem(
                        globals, PyIdentifier.__builtins__,
                        Runtime.PyEval_GetBuiltins()
                    );
                }
            }

            if (locals == null)
            {
                locals = globals;
            }

            try
            {
                NewReference result = Runtime.PyRun_String(
                    code, flag, globals, locals
                );
                PythonException.ThrowIfIsNull(result);
                return result.MoveToPyObject();
            }
            finally
            {
                tempGlobals.Dispose();
            }
        }
    }

    public enum RunFlagType : int
    {
        Single = 256,
        File = 257, /* Py_file_input */
        Eval = 258
    }
}

Web Proxy Viewer  |  New URL  |  Original Page