diff --git a/src/embed_tests/InitializeTest.cs b/src/embed_tests/InitializeTest.cs index a9667343c..6c6f0f1f1 100644 --- a/src/embed_tests/InitializeTest.cs +++ b/src/embed_tests/InitializeTest.cs @@ -10,7 +10,29 @@ namespace Python.EmbeddingTest public class InitializeTest { [Test] - public static void Test() + public static void LoadSpecificArgs() + { + var args = new[] { "test1", "test2" }; + using (new PythonEngine(args)) + using (var argv = new PyList(Runtime.Runtime.PySys_GetObject("argv"))) + { + Assert.That(argv[0].ToString() == args[0]); + Assert.That(argv[1].ToString() == args[1]); + } + } + + [Test] + public static void LoadDefaultArgs() + { + using (new PythonEngine()) + using (var argv = new PyList(Runtime.Runtime.PySys_GetObject("argv"))) + { + Assert.That(argv.Length() != 0); + } + } + + [Test] + public static void StartAndStopTwice() { PythonEngine.Initialize(); PythonEngine.Shutdown(); diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs index c296f1b87..754aaf2cd 100644 --- a/src/runtime/pythonengine.cs +++ b/src/runtime/pythonengine.cs @@ -2,17 +2,39 @@ using System.IO; using System.Threading; using System.Reflection; +using System.Collections.Generic; +using System.Linq; namespace Python.Runtime { /// /// This class provides the public interface of the Python runtime. /// - public class PythonEngine + public class PythonEngine : IDisposable { private static DelegateManager delegateManager; private static bool initialized; + public PythonEngine() + { + Initialize(); + } + + public PythonEngine(params string[] args) + { + Initialize(args); + } + + public PythonEngine(IEnumerable args) + { + Initialize(args); + } + + public void Dispose() + { + Shutdown(); + } + #region Properties public static bool IsInitialized @@ -102,6 +124,11 @@ public static int RunSimpleString(string code) #endregion + public static void Initialize() + { + Initialize(Enumerable.Empty()); + } + /// /// Initialize Method /// @@ -112,7 +139,7 @@ public static int RunSimpleString(string code) /// first call. It is *not* necessary to hold the Python global /// interpreter lock (GIL) to call this method. /// - public static void Initialize() + public static void Initialize(IEnumerable args) { if (!initialized) { @@ -126,6 +153,8 @@ public static void Initialize() initialized = true; Exceptions.Clear(); + Py.SetArgv(args); + // register the atexit callback (this doesn't use Py_AtExit as the C atexit // callbacks are called after python is fully finalized but the python ones // are called while the python engine is still running). @@ -187,7 +216,8 @@ public static void Initialize() // when it is imported by the CLR extension module. //==================================================================== #if PYTHON3 - public static IntPtr InitExt() { + public static IntPtr InitExt() + { #elif PYTHON2 public static void InitExt() { @@ -351,10 +381,7 @@ public static void EndAllowThreads(IntPtr ts) public static PyObject ImportModule(string name) { IntPtr op = Runtime.PyImport_ImportModule(name); - if (op == IntPtr.Zero) - { - return null; - } + Py.Throw(); return new PyObject(op); } @@ -370,10 +397,7 @@ public static PyObject ImportModule(string name) public static PyObject ReloadModule(PyObject module) { IntPtr op = Runtime.PyImport_ReloadModule(module.Handle); - if (op == IntPtr.Zero) - { - throw new PythonException(); - } + Py.Throw(); return new PyObject(op); } @@ -389,15 +413,9 @@ public static PyObject ReloadModule(PyObject module) public static PyObject ModuleFromString(string name, string code) { IntPtr c = Runtime.Py_CompileString(code, "none", (IntPtr)257); - if (c == IntPtr.Zero) - { - throw new PythonException(); - } + Py.Throw(); IntPtr m = Runtime.PyImport_ExecCodeModule(name, c); - if (m == IntPtr.Zero) - { - throw new PythonException(); - } + Py.Throw(); return new PyObject(m); } @@ -445,10 +463,7 @@ public static PyObject RunString( code, flag, globals.Value, locals.Value ); - if (Runtime.PyErr_Occurred() != 0) - { - throw new PythonException(); - } + Py.Throw(); return new PyObject(result); } @@ -500,7 +515,7 @@ public class KeywordArguments : PyDict public static KeywordArguments kw(params object[] kv) { var dict = new KeywordArguments(); - if (kv.Length%2 != 0) + if (kv.Length % 2 != 0) throw new ArgumentException("Must have an equal number of keys and values"); for (int i = 0; i < kv.Length; i += 2) { @@ -521,5 +536,50 @@ public static PyObject Import(string name) { return PythonEngine.ImportModule(name); } + + public static void SetArgv() + { + IEnumerable args; + try + { + args = Environment.GetCommandLineArgs(); + } + catch (NotSupportedException) + { + args = Enumerable.Empty(); + } + + SetArgv( + new[] { "" }.Concat( + Environment.GetCommandLineArgs().Skip(1) + ) + ); + } + + public static void SetArgv(params string[] argv) + { + SetArgv(argv as IEnumerable); + } + + public static void SetArgv(IEnumerable argv) + { + using (GIL()) + { + var arr = argv.ToArray(); + Runtime.PySys_SetArgvEx(arr.Length, arr, 0); + Py.Throw(); + } + } + + internal static void Throw() + { + using (GIL()) + { + if (Runtime.PyErr_Occurred() != 0) + { + throw new PythonException(); + } + } + } } } diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 5f0ecfbd2..9b5c4ffb5 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -2027,11 +2027,26 @@ internal unsafe static extern IntPtr internal unsafe static extern IntPtr PyImport_GetModuleDict(); - +#if PYTHON3 [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, CharSet = CharSet.Ansi)] internal unsafe static extern void - PySys_SetArgv(int argc, IntPtr argv); + PySys_SetArgvEx( + int argc, + [MarshalAsAttribute(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] + string[] argv, + int updatepath + ); +#elif PYTHON2 + [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, + ExactSpelling = true, CharSet = CharSet.Ansi)] + internal unsafe static extern void + PySys_SetArgvEx( + int argc, + string[] argv, + int updatepath + ); +#endif [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, CharSet = CharSet.Ansi)]