Skip to content

Commit 7cab332

Browse files
committed
Merge pull request #347 from filmor/add-pysetargv
Closes #347
2 parents f7f2fc0 + 3785c40 commit 7cab332

File tree

3 files changed

+125
-28
lines changed

3 files changed

+125
-28
lines changed

src/embed_tests/InitializeTest.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using NUnit.Framework;
1+
using NUnit.Framework;
22
using Python.Runtime;
33
using System;
44
using System.Collections.Generic;
@@ -10,7 +10,29 @@ namespace Python.EmbeddingTest
1010
public class InitializeTest
1111
{
1212
[Test]
13-
public static void Test()
13+
public static void LoadSpecificArgs()
14+
{
15+
var args = new[] { "test1", "test2" };
16+
using (new PythonEngine(args))
17+
using (var argv = new PyList(Runtime.Runtime.PySys_GetObject("argv")))
18+
{
19+
Assert.That(argv[0].ToString() == args[0]);
20+
Assert.That(argv[1].ToString() == args[1]);
21+
}
22+
}
23+
24+
[Test]
25+
public static void LoadDefaultArgs()
26+
{
27+
using (new PythonEngine())
28+
using (var argv = new PyList(Runtime.Runtime.PySys_GetObject("argv")))
29+
{
30+
Assert.That(argv.Length() != 0);
31+
}
32+
}
33+
34+
[Test]
35+
public static void StartAndStopTwice()
1436
{
1537
PythonEngine.Initialize();
1638
PythonEngine.Shutdown();

src/runtime/pythonengine.cs

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,39 @@
22
using System.IO;
33
using System.Threading;
44
using System.Reflection;
5+
using System.Collections.Generic;
6+
using System.Linq;
57

68
namespace Python.Runtime
79
{
810
/// <summary>
911
/// This class provides the public interface of the Python runtime.
1012
/// </summary>
11-
public class PythonEngine
13+
public class PythonEngine : IDisposable
1214
{
1315
private static DelegateManager delegateManager;
1416
private static bool initialized;
1517

18+
public PythonEngine()
19+
{
20+
Initialize();
21+
}
22+
23+
public PythonEngine(params string[] args)
24+
{
25+
Initialize(args);
26+
}
27+
28+
public PythonEngine(IEnumerable<string> args)
29+
{
30+
Initialize(args);
31+
}
32+
33+
public void Dispose()
34+
{
35+
Shutdown();
36+
}
37+
1638
#region Properties
1739

1840
public static bool IsInitialized
@@ -102,6 +124,11 @@ public static int RunSimpleString(string code)
102124

103125
#endregion
104126

127+
public static void Initialize()
128+
{
129+
Initialize(Enumerable.Empty<string>());
130+
}
131+
105132
/// <summary>
106133
/// Initialize Method
107134
/// </summary>
@@ -112,7 +139,7 @@ public static int RunSimpleString(string code)
112139
/// first call. It is *not* necessary to hold the Python global
113140
/// interpreter lock (GIL) to call this method.
114141
/// </remarks>
115-
public static void Initialize()
142+
public static void Initialize(IEnumerable<string> args)
116143
{
117144
if (!initialized)
118145
{
@@ -126,6 +153,8 @@ public static void Initialize()
126153
initialized = true;
127154
Exceptions.Clear();
128155

156+
Py.SetArgv(args);
157+
129158
// register the atexit callback (this doesn't use Py_AtExit as the C atexit
130159
// callbacks are called after python is fully finalized but the python ones
131160
// are called while the python engine is still running).
@@ -187,7 +216,8 @@ public static void Initialize()
187216
// when it is imported by the CLR extension module.
188217
//====================================================================
189218
#if PYTHON3
190-
public static IntPtr InitExt() {
219+
public static IntPtr InitExt()
220+
{
191221
#elif PYTHON2
192222
public static void InitExt()
193223
{
@@ -351,10 +381,7 @@ public static void EndAllowThreads(IntPtr ts)
351381
public static PyObject ImportModule(string name)
352382
{
353383
IntPtr op = Runtime.PyImport_ImportModule(name);
354-
if (op == IntPtr.Zero)
355-
{
356-
return null;
357-
}
384+
Py.Throw();
358385
return new PyObject(op);
359386
}
360387

@@ -370,10 +397,7 @@ public static PyObject ImportModule(string name)
370397
public static PyObject ReloadModule(PyObject module)
371398
{
372399
IntPtr op = Runtime.PyImport_ReloadModule(module.Handle);
373-
if (op == IntPtr.Zero)
374-
{
375-
throw new PythonException();
376-
}
400+
Py.Throw();
377401
return new PyObject(op);
378402
}
379403

@@ -389,15 +413,9 @@ public static PyObject ReloadModule(PyObject module)
389413
public static PyObject ModuleFromString(string name, string code)
390414
{
391415
IntPtr c = Runtime.Py_CompileString(code, "none", (IntPtr)257);
392-
if (c == IntPtr.Zero)
393-
{
394-
throw new PythonException();
395-
}
416+
Py.Throw();
396417
IntPtr m = Runtime.PyImport_ExecCodeModule(name, c);
397-
if (m == IntPtr.Zero)
398-
{
399-
throw new PythonException();
400-
}
418+
Py.Throw();
401419
return new PyObject(m);
402420
}
403421

@@ -445,10 +463,7 @@ public static PyObject RunString(
445463
code, flag, globals.Value, locals.Value
446464
);
447465

448-
if (Runtime.PyErr_Occurred() != 0)
449-
{
450-
throw new PythonException();
451-
}
466+
Py.Throw();
452467

453468
return new PyObject(result);
454469
}
@@ -500,7 +515,7 @@ public class KeywordArguments : PyDict
500515
public static KeywordArguments kw(params object[] kv)
501516
{
502517
var dict = new KeywordArguments();
503-
if (kv.Length%2 != 0)
518+
if (kv.Length % 2 != 0)
504519
throw new ArgumentException("Must have an equal number of keys and values");
505520
for (int i = 0; i < kv.Length; i += 2)
506521
{
@@ -521,5 +536,50 @@ public static PyObject Import(string name)
521536
{
522537
return PythonEngine.ImportModule(name);
523538
}
539+
540+
public static void SetArgv()
541+
{
542+
IEnumerable<string> args;
543+
try
544+
{
545+
args = Environment.GetCommandLineArgs();
546+
}
547+
catch (NotSupportedException)
548+
{
549+
args = Enumerable.Empty<string>();
550+
}
551+
552+
SetArgv(
553+
new[] { "" }.Concat(
554+
Environment.GetCommandLineArgs().Skip(1)
555+
)
556+
);
557+
}
558+
559+
public static void SetArgv(params string[] argv)
560+
{
561+
SetArgv(argv as IEnumerable<string>);
562+
}
563+
564+
public static void SetArgv(IEnumerable<string> argv)
565+
{
566+
using (GIL())
567+
{
568+
var arr = argv.ToArray();
569+
Runtime.PySys_SetArgvEx(arr.Length, arr, 0);
570+
Py.Throw();
571+
}
572+
}
573+
574+
internal static void Throw()
575+
{
576+
using (GIL())
577+
{
578+
if (Runtime.PyErr_Occurred() != 0)
579+
{
580+
throw new PythonException();
581+
}
582+
}
583+
}
524584
}
525585
}

src/runtime/runtime.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2027,11 +2027,26 @@ internal unsafe static extern IntPtr
20272027
internal unsafe static extern IntPtr
20282028
PyImport_GetModuleDict();
20292029

2030-
2030+
#if PYTHON3
20312031
[DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
20322032
ExactSpelling = true, CharSet = CharSet.Ansi)]
20332033
internal unsafe static extern void
2034-
PySys_SetArgv(int argc, IntPtr argv);
2034+
PySys_SetArgvEx(
2035+
int argc,
2036+
[MarshalAsAttribute(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)]
2037+
string[] argv,
2038+
int updatepath
2039+
);
2040+
#elif PYTHON2
2041+
[DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
2042+
ExactSpelling = true, CharSet = CharSet.Ansi)]
2043+
internal unsafe static extern void
2044+
PySys_SetArgvEx(
2045+
int argc,
2046+
string[] argv,
2047+
int updatepath
2048+
);
2049+
#endif
20352050

20362051
[DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
20372052
ExactSpelling = true, CharSet = CharSet.Ansi)]

0 commit comments

Comments
 (0)