Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 75a8b87

Browse files
committed
introduced PyModule (inherits PyScope)
changed PyScope to inherit from PyObject
1 parent 0151b77 commit 75a8b87

13 files changed

+121
-118
lines changed

src/embed_tests/TestFinalizer.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,17 @@ public void CollectOnShutdown()
101101

102102
PythonEngine.Shutdown();
103103
garbage = Finalizer.Instance.GetCollectedObjects();
104-
Assert.IsEmpty(garbage);
104+
105+
if (garbage.Count > 0)
106+
{
107+
PythonEngine.Initialize();
108+
string objects = string.Join("\n", garbage.Select(ob =>
109+
{
110+
var obj = new PyObject(new BorrowedReference(ob));
111+
return $"{obj} [{obj.GetPythonType()}@{obj.Handle}]";
112+
}));
113+
Assert.Fail("Garbage is not empty:\n" + objects);
114+
}
105115
}
106116

107117
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] // ensure lack of references to obj
@@ -173,7 +183,7 @@ public void SimpleTestMemory()
173183
bool oldState = Finalizer.Instance.Enable;
174184
try
175185
{
176-
using (PyObject gcModule = PythonEngine.ImportModule("gc"))
186+
using (PyModule gcModule = PyModule.Import("gc"))
177187
using (PyObject pyCollect = gcModule.GetAttr("collect"))
178188
{
179189
long span1 = CompareWithFinalizerOn(pyCollect, false);

src/embed_tests/TestPythonException.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public void TestPythonErrorTypeName()
4646
{
4747
try
4848
{
49-
var module = PythonEngine.ImportModule("really____unknown___module");
49+
var module = PyModule.Import("really____unknown___module");
5050
Assert.Fail("Unknown module should not be loaded");
5151
}
5252
catch (PythonException ex)
@@ -95,7 +95,7 @@ public void TestPythonExceptionFormatNoTraceback()
9595
{
9696
try
9797
{
98-
var module = PythonEngine.ImportModule("really____unknown___module");
98+
var module = PyModule.Import("really____unknown___module");
9999
Assert.Fail("Unknown module should not be loaded");
100100
}
101101
catch (PythonException ex)

src/embed_tests/TestRuntime.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public static void PyCheck_Iter_PyObject_IsIterable_ThreadingLock_Test()
9696
// TypeFlags.HaveIter set in Python 2. This tests a different code path in PyObject_IsIterable and PyIter_Check.
9797
var threading = Runtime.Runtime.PyImport_ImportModule("threading");
9898
Exceptions.ErrorCheck(threading);
99-
var threadingDict = Runtime.Runtime.PyModule_GetDict(new BorrowedReference(threading));
99+
var threadingDict = Runtime.Runtime.PyModule_GetDict(threading);
100100
Exceptions.ErrorCheck(threadingDict);
101101
var lockType = Runtime.Runtime.PyDict_GetItemString(threadingDict, "Lock");
102102
if (lockType.IsNull)
@@ -110,6 +110,8 @@ public static void PyCheck_Iter_PyObject_IsIterable_ThreadingLock_Test()
110110
Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(lockInstance));
111111
Assert.IsFalse(Runtime.Runtime.PyIter_Check(lockInstance));
112112

113+
threading.Dispose();
114+
113115
Runtime.Runtime.Py_Finalize();
114116
}
115117
}

src/embed_tests/pyimport.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public void Dispose()
5252
[Test]
5353
public void TestDottedName()
5454
{
55-
PyObject module = PythonEngine.ImportModule("PyImportTest.test.one");
55+
var module = PyModule.Import("PyImportTest.test.one");
5656
Assert.IsNotNull(module);
5757
}
5858

@@ -62,7 +62,7 @@ public void TestDottedName()
6262
[Test]
6363
public void TestSysArgsImportException()
6464
{
65-
PyObject module = PythonEngine.ImportModule("PyImportTest.sysargv");
65+
var module = PyModule.Import("PyImportTest.sysargv");
6666
Assert.IsNotNull(module);
6767
}
6868

src/embed_tests/pyinitialize.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,8 @@ public static void TestRunExitFuncs()
175175
{
176176
called = true;
177177
};
178-
atexit.InvokeMethod("register", callback.ToPython());
178+
atexit.InvokeMethod("register", callback.ToPython()).Dispose();
179+
atexit.Dispose();
179180
Runtime.Runtime.Shutdown();
180181
Assert.True(called);
181182
}

src/runtime/exceptions.cs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -95,24 +95,21 @@ internal static Exception ToException(IntPtr ob)
9595
/// </remarks>
9696
public static class Exceptions
9797
{
98-
internal static IntPtr warnings_module;
99-
internal static IntPtr exceptions_module;
98+
internal static PyModule warnings_module;
99+
internal static PyModule exceptions_module;
100100

101101
/// <summary>
102102
/// Initialization performed on startup of the Python runtime.
103103
/// </summary>
104104
internal static void Initialize()
105105
{
106106
string exceptionsModuleName = "builtins";
107-
exceptions_module = Runtime.PyImport_ImportModule(exceptionsModuleName);
108-
109-
Exceptions.ErrorCheck(exceptions_module);
110-
warnings_module = Runtime.PyImport_ImportModule("warnings");
111-
Exceptions.ErrorCheck(warnings_module);
107+
exceptions_module = PyModule.Import(exceptionsModuleName);
108+
warnings_module = PyModule.Import("warnings");
112109
Type type = typeof(Exceptions);
113110
foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | BindingFlags.Static))
114111
{
115-
IntPtr op = Runtime.PyObject_GetAttrString(exceptions_module, fi.Name);
112+
IntPtr op = Runtime.PyObject_GetAttrString(exceptions_module.obj, fi.Name);
116113
if (op != IntPtr.Zero)
117114
{
118115
fi.SetValue(type, op);
@@ -147,8 +144,8 @@ internal static void Shutdown()
147144
Runtime.XDecref(op);
148145
fi.SetValue(null, IntPtr.Zero);
149146
}
150-
Runtime.Py_CLEAR(ref exceptions_module);
151-
Runtime.Py_CLEAR(ref warnings_module);
147+
exceptions_module.Dispose();
148+
warnings_module.Dispose();
152149
}
153150

154151
/// <summary>
@@ -348,9 +345,7 @@ public static void warn(string message, IntPtr exception, int stacklevel)
348345
Exceptions.RaiseTypeError("Invalid exception");
349346
}
350347

351-
Runtime.XIncref(warnings_module);
352-
IntPtr warn = Runtime.PyObject_GetAttrString(warnings_module, "warn");
353-
Runtime.XDecref(warnings_module);
348+
IntPtr warn = Runtime.PyObject_GetAttrString(warnings_module.obj, "warn");
354349
Exceptions.ErrorCheck(warn);
355350

356351
IntPtr args = Runtime.PyTuple_New(3);

src/runtime/pymodule.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
3+
namespace Python.Runtime
4+
{
5+
public class PyModule : PyScope
6+
{
7+
internal PyModule(ref NewReference reference) : base(ref reference, PyScopeManager.Global) { }
8+
9+
/// <summary>
10+
/// Given a module or package name, import the
11+
/// module and return the resulting module object as a <see cref="PyModule"/>.
12+
/// </summary>
13+
/// <param name="name">Fully-qualified module or package name</param>
14+
public static PyModule Import(string name)
15+
{
16+
NewReference op = Runtime.PyImport_ImportModule(name);
17+
PythonException.ThrowIfIsNull(op);
18+
return new PyModule(ref op);
19+
}
20+
21+
/// <summary>
22+
/// Reloads the module, and returns the updated object
23+
/// </summary>
24+
public PyModule Reload()
25+
{
26+
NewReference op = Runtime.PyImport_ReloadModule(this.Reference);
27+
PythonException.ThrowIfIsNull(op);
28+
return new PyModule(ref op);
29+
}
30+
31+
public static PyModule FromString(string name, string code)
32+
{
33+
using NewReference c = Runtime.Py_CompileString(code, "none", (int)RunFlagType.File);
34+
PythonException.ThrowIfIsNull(c);
35+
NewReference m = Runtime.PyImport_ExecCodeModule(name, c);
36+
PythonException.ThrowIfIsNull(m);
37+
return new PyModule(ref m);
38+
}
39+
}
40+
}

src/runtime/pyscope.cs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,9 @@ public class PyGILAttribute : Attribute
2222
}
2323

2424
[PyGIL]
25-
public class PyScope : DynamicObject, IDisposable
25+
public class PyScope : PyObject
2626
{
27-
public readonly string Name;
28-
29-
/// <summary>
30-
/// the python Module object the scope associated with.
31-
/// </summary>
32-
readonly PyObject obj;
33-
internal BorrowedReference Reference => obj.Reference;
27+
public string Name { get; }
3428

3529
/// <summary>
3630
/// the variable dict of the scope. Borrowed.
@@ -55,14 +49,13 @@ public class PyScope : DynamicObject, IDisposable
5549
/// <remarks>
5650
/// Create a scope based on a Python Module.
5751
/// </remarks>
58-
internal PyScope(ref NewReference ptr, PyScopeManager manager)
52+
internal PyScope(ref NewReference ptr, PyScopeManager manager) : base(ptr.DangerousMoveToPointer())
5953
{
60-
if (!Runtime.PyType_IsSubtype(Runtime.PyObject_TYPE(ptr), Runtime.PyModuleType))
54+
if (!Runtime.PyType_IsSubtype(Runtime.PyObject_TYPE(Reference), Runtime.PyModuleType))
6155
{
6256
throw new PyScopeException("object is not a module");
6357
}
6458
Manager = manager ?? PyScopeManager.Global;
65-
obj = ptr.MoveToPyObject();
6659
//Refcount of the variables not increase
6760
variables = Runtime.PyModule_GetDict(Reference).DangerousGetAddress();
6861
PythonException.ThrowIfIsNull(variables);
@@ -72,7 +65,8 @@ internal PyScope(ref NewReference ptr, PyScopeManager manager)
7265
Runtime.PyEval_GetBuiltins()
7366
);
7467
PythonException.ThrowIfIsNotZero(res);
75-
this.Name = this.Get<string>("__name__");
68+
using var name = this.Get("__name__");
69+
this.Name = name.As<string>();
7670
}
7771

7872
/// <summary>
@@ -118,7 +112,7 @@ public dynamic Import(string name, string asname = null)
118112
}
119113
else
120114
{
121-
PyObject module = PythonEngine.ImportModule(name);
115+
var module = PyModule.Import(name);
122116
Import(module, asname);
123117
return module;
124118
}
@@ -132,7 +126,7 @@ public dynamic Import(string name, string asname = null)
132126
/// </remarks>
133127
public void Import(PyScope scope, string asname)
134128
{
135-
this.SetPyValue(asname, scope.obj.Handle);
129+
this.SetPyValue(asname, scope.Handle);
136130
}
137131

138132
/// <summary>
@@ -169,7 +163,7 @@ public void ImportAll(string name)
169163
}
170164
else
171165
{
172-
PyObject module = PythonEngine.ImportModule(name);
166+
var module = PyModule.Import(name);
173167
ImportAll(module);
174168
}
175169
}
@@ -503,16 +497,20 @@ public override bool TrySetMember(SetMemberBinder binder, object value)
503497

504498
private void Check()
505499
{
506-
if (this.obj.IsDisposed)
500+
if (this.obj == IntPtr.Zero)
507501
{
508502
throw new PyScopeException($"The scope of name '{Name}' object has been disposed");
509503
}
510504
}
511505

512-
public void Dispose()
506+
protected override void Dispose(bool disposing)
513507
{
508+
if (this.obj == IntPtr.Zero)
509+
{
510+
return;
511+
}
512+
base.Dispose(disposing);
514513
this.OnDispose?.Invoke(this);
515-
this.obj.Dispose();
516514
}
517515
}
518516

src/runtime/pythonengine.cs

Lines changed: 4 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -469,61 +469,15 @@ public static void EndAllowThreads(IntPtr ts)
469469
}
470470

471471

472-
/// <summary>
473-
/// ImportModule Method
474-
/// </summary>
475-
/// <remarks>
476-
/// Given a fully-qualified module or package name, import the
477-
/// module and return the resulting module object as a PyObject
478-
/// or null if an exception is raised.
479-
/// </remarks>
480-
public static PyObject ImportModule(string name)
481-
{
482-
IntPtr op = Runtime.PyImport_ImportModule(name);
483-
PythonException.ThrowIfIsNull(op);
484-
return new PyObject(op);
485-
}
486-
487-
488-
/// <summary>
489-
/// ReloadModule Method
490-
/// </summary>
491-
/// <remarks>
492-
/// Given a PyObject representing a previously loaded module, reload
493-
/// the module.
494-
/// </remarks>
495-
public static PyObject ReloadModule(PyObject module)
496-
{
497-
IntPtr op = Runtime.PyImport_ReloadModule(module.Handle);
498-
PythonException.ThrowIfIsNull(op);
499-
return new PyObject(op);
500-
}
501-
502-
503-
/// <summary>
504-
/// ModuleFromString Method
505-
/// </summary>
506-
/// <remarks>
507-
/// Given a string module name and a string containing Python code,
508-
/// execute the code in and return a module of the given name.
509-
/// </remarks>
510-
public static PyObject ModuleFromString(string name, string code)
511-
{
512-
IntPtr c = Runtime.Py_CompileString(code, "none", (int)RunFlagType.File);
513-
PythonException.ThrowIfIsNull(c);
514-
IntPtr m = Runtime.PyImport_ExecCodeModule(name, c);
515-
PythonException.ThrowIfIsNull(m);
516-
return new PyObject(m);
517-
}
518-
519472
public static PyObject Compile(string code, string filename = "", RunFlagType mode = RunFlagType.File)
520473
{
521474
var flag = (int)mode;
522-
IntPtr ptr = Runtime.Py_CompileString(code, filename, flag);
475+
NewReference ptr = Runtime.Py_CompileString(code, filename, flag);
523476
PythonException.ThrowIfIsNull(ptr);
524-
return new PyObject(ptr);
477+
return ptr.MoveToPyObject();
525478
}
526479

480+
527481
/// <summary>
528482
/// Eval Method
529483
/// </summary>
@@ -744,7 +698,7 @@ public static KeywordArguments kw(params object[] kv)
744698

745699
public static PyObject Import(string name)
746700
{
747-
return PythonEngine.ImportModule(name);
701+
return PyModule.Import(name);
748702
}
749703

750704
public static void SetArgv()

src/runtime/pythonexception.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public PythonException()
4848

4949
if (_pyTB != IntPtr.Zero)
5050
{
51-
using PyObject tb_module = PythonEngine.ImportModule("traceback");
51+
using var tb_module = PyModule.Import("traceback");
5252

5353
Runtime.XIncref(_pyTB);
5454
using var pyTB = new PyObject(_pyTB);
@@ -198,7 +198,7 @@ public string Format()
198198
using (PyObject pyType = new PyObject(type))
199199
using (PyObject pyValue = new PyObject(value))
200200
using (PyObject pyTB = new PyObject(tb))
201-
using (PyObject tb_mod = PythonEngine.ImportModule("traceback"))
201+
using (PyObject tb_mod = PyModule.Import("traceback"))
202202
{
203203
var buffer = new StringBuilder();
204204
var values = tb_mod.InvokeMethod("format_exception", pyType, pyValue, pyTB);

0 commit comments

Comments
 (0)