diff --git a/src/embed_tests/GlobalTestsSetup.cs b/src/embed_tests/GlobalTestsSetup.cs
index 458ab6a99..9a832cb0c 100644
--- a/src/embed_tests/GlobalTestsSetup.cs
+++ b/src/embed_tests/GlobalTestsSetup.cs
@@ -7,7 +7,7 @@ namespace Python.EmbeddingTest
// As the SetUpFixture, the OneTimeTearDown of this class is executed after
// all tests have run.
[SetUpFixture]
- public class GlobalTestsSetup
+ public partial class GlobalTestsSetup
{
[OneTimeTearDown]
public void FinalCleanup()
diff --git a/src/embed_tests/TestFinalizer.cs b/src/embed_tests/TestFinalizer.cs
index 46e2fcdf1..c040e6930 100644
--- a/src/embed_tests/TestFinalizer.cs
+++ b/src/embed_tests/TestFinalizer.cs
@@ -101,7 +101,17 @@ public void CollectOnShutdown()
PythonEngine.Shutdown();
garbage = Finalizer.Instance.GetCollectedObjects();
- Assert.IsEmpty(garbage);
+
+ if (garbage.Count > 0)
+ {
+ PythonEngine.Initialize();
+ string objects = string.Join("\n", garbage.Select(ob =>
+ {
+ var obj = new PyObject(new BorrowedReference(ob));
+ return $"{obj} [{obj.GetPythonType()}@{obj.Handle}]";
+ }));
+ Assert.Fail("Garbage is not empty:\n" + objects);
+ }
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] // ensure lack of references to obj
@@ -173,7 +183,7 @@ public void SimpleTestMemory()
bool oldState = Finalizer.Instance.Enable;
try
{
- using (PyObject gcModule = PythonEngine.ImportModule("gc"))
+ using (PyModule gcModule = PyModule.Import("gc"))
using (PyObject pyCollect = gcModule.GetAttr("collect"))
{
long span1 = CompareWithFinalizerOn(pyCollect, false);
diff --git a/src/embed_tests/TestNativeTypeOffset.cs b/src/embed_tests/TestNativeTypeOffset.cs
index 7dd5a765e..8efd16e02 100644
--- a/src/embed_tests/TestNativeTypeOffset.cs
+++ b/src/embed_tests/TestNativeTypeOffset.cs
@@ -9,7 +9,7 @@
using Python.Runtime;
-namespace Python.EmbeddingPythonTest
+namespace Python.EmbeddingTest
{
public class TestNativeTypeOffset
{
diff --git a/src/embed_tests/TestPythonException.cs b/src/embed_tests/TestPythonException.cs
index 31addfba1..a74fc3a8b 100644
--- a/src/embed_tests/TestPythonException.cs
+++ b/src/embed_tests/TestPythonException.cs
@@ -46,7 +46,7 @@ public void TestPythonErrorTypeName()
{
try
{
- var module = PythonEngine.ImportModule("really____unknown___module");
+ var module = PyModule.Import("really____unknown___module");
Assert.Fail("Unknown module should not be loaded");
}
catch (PythonException ex)
@@ -95,7 +95,7 @@ public void TestPythonExceptionFormatNoTraceback()
{
try
{
- var module = PythonEngine.ImportModule("really____unknown___module");
+ var module = PyModule.Import("really____unknown___module");
Assert.Fail("Unknown module should not be loaded");
}
catch (PythonException ex)
diff --git a/src/embed_tests/TestRuntime.cs b/src/embed_tests/TestRuntime.cs
index 59c66cc5e..32369190c 100644
--- a/src/embed_tests/TestRuntime.cs
+++ b/src/embed_tests/TestRuntime.cs
@@ -96,7 +96,7 @@ public static void PyCheck_Iter_PyObject_IsIterable_ThreadingLock_Test()
// TypeFlags.HaveIter set in Python 2. This tests a different code path in PyObject_IsIterable and PyIter_Check.
var threading = Runtime.Runtime.PyImport_ImportModule("threading");
Exceptions.ErrorCheck(threading);
- var threadingDict = Runtime.Runtime.PyModule_GetDict(new BorrowedReference(threading));
+ var threadingDict = Runtime.Runtime.PyModule_GetDict(threading);
Exceptions.ErrorCheck(threadingDict);
var lockType = Runtime.Runtime.PyDict_GetItemString(threadingDict, "Lock");
if (lockType.IsNull)
@@ -110,6 +110,8 @@ public static void PyCheck_Iter_PyObject_IsIterable_ThreadingLock_Test()
Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(lockInstance));
Assert.IsFalse(Runtime.Runtime.PyIter_Check(lockInstance));
+ threading.Dispose();
+
Runtime.Runtime.Py_Finalize();
}
}
diff --git a/src/embed_tests/pyimport.cs b/src/embed_tests/pyimport.cs
index 24f31acff..b34a5d25b 100644
--- a/src/embed_tests/pyimport.cs
+++ b/src/embed_tests/pyimport.cs
@@ -52,7 +52,7 @@ public void Dispose()
[Test]
public void TestDottedName()
{
- PyObject module = PythonEngine.ImportModule("PyImportTest.test.one");
+ var module = PyModule.Import("PyImportTest.test.one");
Assert.IsNotNull(module);
}
@@ -62,7 +62,7 @@ public void TestDottedName()
[Test]
public void TestSysArgsImportException()
{
- PyObject module = PythonEngine.ImportModule("PyImportTest.sysargv");
+ var module = PyModule.Import("PyImportTest.sysargv");
Assert.IsNotNull(module);
}
diff --git a/src/embed_tests/pyinitialize.cs b/src/embed_tests/pyinitialize.cs
index c774680dd..66a9a3f7c 100644
--- a/src/embed_tests/pyinitialize.cs
+++ b/src/embed_tests/pyinitialize.cs
@@ -175,7 +175,8 @@ public static void TestRunExitFuncs()
{
called = true;
};
- atexit.InvokeMethod("register", callback.ToPython());
+ atexit.InvokeMethod("register", callback.ToPython()).Dispose();
+ atexit.Dispose();
Runtime.Runtime.Shutdown();
Assert.True(called);
}
diff --git a/src/runtime/BorrowedReference.cs b/src/runtime/BorrowedReference.cs
index 2f5c347c7..d49f52fe9 100644
--- a/src/runtime/BorrowedReference.cs
+++ b/src/runtime/BorrowedReference.cs
@@ -28,6 +28,14 @@ public BorrowedReference(IntPtr pointer)
=> a.pointer == b.pointer;
public static bool operator !=(BorrowedReference a, BorrowedReference b)
=> a.pointer != b.pointer;
+ public static bool operator ==(BorrowedReference reference, NullOnly @null)
+ => reference.IsNull;
+ public static bool operator !=(BorrowedReference reference, NullOnly @null)
+ => !reference.IsNull;
+ public static bool operator ==(NullOnly @null, BorrowedReference reference)
+ => reference.IsNull;
+ public static bool operator !=(NullOnly @null, BorrowedReference reference)
+ => !reference.IsNull;
public override bool Equals(object obj) {
if (obj is IntPtr ptr)
diff --git a/src/runtime/CustomMarshaler.cs b/src/runtime/CustomMarshaler.cs
index 4814e6c0b..3ef5cd662 100644
--- a/src/runtime/CustomMarshaler.cs
+++ b/src/runtime/CustomMarshaler.cs
@@ -189,49 +189,4 @@ public static ICustomMarshaler GetInstance(string cookie)
return Instance;
}
}
-
-
- ///
- /// Custom Marshaler to deal with Managed String to Native
- /// conversion on UTF-8. Use on functions that expect UTF-8 encoded
- /// strings like `PyUnicode_FromStringAndSize`
- ///
- ///
- /// If instead we used `MarshalAs(UnmanagedType.LPWStr)` the output to
- /// `foo` would be `f\x00o\x00o\x00`.
- ///
- internal class Utf8Marshaler : MarshalerBase
- {
- private static readonly MarshalerBase Instance = new Utf8Marshaler();
- private static readonly Encoding PyEncoding = Encoding.UTF8;
-
- public override IntPtr MarshalManagedToNative(object managedObj)
- {
- var s = managedObj as string;
-
- if (s == null)
- {
- return IntPtr.Zero;
- }
-
- byte[] bStr = PyEncoding.GetBytes(s + "\0");
- IntPtr mem = Marshal.AllocHGlobal(bStr.Length);
- try
- {
- Marshal.Copy(bStr, 0, mem, bStr.Length);
- }
- catch (Exception)
- {
- Marshal.FreeHGlobal(mem);
- throw;
- }
-
- return mem;
- }
-
- public static ICustomMarshaler GetInstance(string cookie)
- {
- return Instance;
- }
- }
}
diff --git a/src/runtime/exceptions.cs b/src/runtime/exceptions.cs
index afd0bc14e..da8653853 100644
--- a/src/runtime/exceptions.cs
+++ b/src/runtime/exceptions.cs
@@ -95,8 +95,8 @@ internal static Exception ToException(IntPtr ob)
///
public static class Exceptions
{
- internal static IntPtr warnings_module;
- internal static IntPtr exceptions_module;
+ internal static PyModule warnings_module;
+ internal static PyModule exceptions_module;
///
/// Initialization performed on startup of the Python runtime.
@@ -104,15 +104,12 @@ public static class Exceptions
internal static void Initialize()
{
string exceptionsModuleName = "builtins";
- exceptions_module = Runtime.PyImport_ImportModule(exceptionsModuleName);
-
- Exceptions.ErrorCheck(exceptions_module);
- warnings_module = Runtime.PyImport_ImportModule("warnings");
- Exceptions.ErrorCheck(warnings_module);
+ exceptions_module = PyModule.Import(exceptionsModuleName);
+ warnings_module = PyModule.Import("warnings");
Type type = typeof(Exceptions);
foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | BindingFlags.Static))
{
- IntPtr op = Runtime.PyObject_GetAttrString(exceptions_module, fi.Name);
+ IntPtr op = Runtime.PyObject_GetAttrString(exceptions_module.obj, fi.Name);
if (op != IntPtr.Zero)
{
fi.SetValue(type, op);
@@ -147,8 +144,8 @@ internal static void Shutdown()
Runtime.XDecref(op);
fi.SetValue(null, IntPtr.Zero);
}
- Runtime.Py_CLEAR(ref exceptions_module);
- Runtime.Py_CLEAR(ref warnings_module);
+ exceptions_module.Dispose();
+ warnings_module.Dispose();
}
///
@@ -348,9 +345,7 @@ public static void warn(string message, IntPtr exception, int stacklevel)
Exceptions.RaiseTypeError("Invalid exception");
}
- Runtime.XIncref(warnings_module);
- IntPtr warn = Runtime.PyObject_GetAttrString(warnings_module, "warn");
- Runtime.XDecref(warnings_module);
+ IntPtr warn = Runtime.PyObject_GetAttrString(warnings_module.obj, "warn");
Exceptions.ErrorCheck(warn);
IntPtr args = Runtime.PyTuple_New(3);
diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs
index 066c765fe..13b45df51 100644
--- a/src/runtime/importhook.cs
+++ b/src/runtime/importhook.cs
@@ -155,7 +155,7 @@ public static unsafe NewReference GetCLRModule(BorrowedReference fromList = defa
// find any items from the from list and get them from the root if they're not
// already in the module dictionary
- if (fromList != null && fromList != default)
+ if (fromList != null)
{
if (Runtime.PyTuple_Check(fromList))
{
@@ -224,7 +224,7 @@ public static IntPtr __import__(IntPtr self, IntPtr argsRaw, IntPtr kw)
if (num_args >= 4)
{
fromList = Runtime.PyTuple_GetItem(args, 3);
- if (fromList != default &&
+ if (fromList != null &&
Runtime.PyObject_IsTrue(fromList) == 1)
{
fromlist = true;
@@ -297,7 +297,7 @@ public static IntPtr __import__(IntPtr self, IntPtr argsRaw, IntPtr kw)
BorrowedReference modules = Runtime.PyImport_GetModuleDict();
BorrowedReference module = Runtime.PyDict_GetItem(modules, py_mod_name);
- if (module != default)
+ if (module != null)
{
if (fromlist)
{
diff --git a/src/runtime/pymodule.cs b/src/runtime/pymodule.cs
new file mode 100644
index 000000000..800edb686
--- /dev/null
+++ b/src/runtime/pymodule.cs
@@ -0,0 +1,41 @@
+using System;
+
+namespace Python.Runtime
+{
+ public class PyModule : PyScope
+ {
+ internal PyModule(ref NewReference reference) : base(ref reference, PyScopeManager.Global) { }
+ public PyModule(PyObject o) : base(o.Reference, PyScopeManager.Global) { }
+
+ ///
+ /// Given a module or package name, import the
+ /// module and return the resulting module object as a .
+ ///
+ /// Fully-qualified module or package name
+ public static PyModule Import(string name)
+ {
+ NewReference op = Runtime.PyImport_ImportModule(name);
+ PythonException.ThrowIfIsNull(op);
+ return new PyModule(ref op);
+ }
+
+ ///
+ /// Reloads the module, and returns the updated object
+ ///
+ public PyModule Reload()
+ {
+ NewReference op = Runtime.PyImport_ReloadModule(this.Reference);
+ PythonException.ThrowIfIsNull(op);
+ return new PyModule(ref op);
+ }
+
+ public static PyModule FromString(string name, string code)
+ {
+ using NewReference c = Runtime.Py_CompileString(code, "none", (int)RunFlagType.File);
+ PythonException.ThrowIfIsNull(c);
+ NewReference m = Runtime.PyImport_ExecCodeModule(name, c);
+ PythonException.ThrowIfIsNull(m);
+ return new PyModule(ref m);
+ }
+ }
+}
diff --git a/src/runtime/pyscope.cs b/src/runtime/pyscope.cs
index 9d68b76fa..4d09004bd 100644
--- a/src/runtime/pyscope.cs
+++ b/src/runtime/pyscope.cs
@@ -22,15 +22,9 @@ public class PyGILAttribute : Attribute
}
[PyGIL]
- public class PyScope : DynamicObject, IDisposable
+ public class PyScope : PyObject
{
- public readonly string Name;
-
- ///
- /// the python Module object the scope associated with.
- ///
- readonly PyObject obj;
- internal BorrowedReference Reference => obj.Reference;
+ public string Name { get; }
///
/// the variable dict of the scope. Borrowed.
@@ -49,20 +43,24 @@ public class PyScope : DynamicObject, IDisposable
///
public event Action OnDispose;
- ///
- /// Constructor
- ///
- ///
- /// Create a scope based on a Python Module.
- ///
- internal PyScope(ref NewReference ptr, PyScopeManager manager)
+ /// Create a scope based on a Python Module.
+ internal PyScope(ref NewReference reference, PyScopeManager manager)
+ : this(reference.DangerousMoveToPointer(), manager) { }
+ /// Create a scope based on a Python Module.
+ internal PyScope(BorrowedReference reference, PyScopeManager manager)
+ : this(reference.DangerousGetAddress(), manager)
{
- if (!Runtime.PyType_IsSubtype(Runtime.PyObject_TYPE(ptr), Runtime.PyModuleType))
+ Runtime.XIncref(reference.DangerousGetAddress());
+ }
+
+ /// Create a scope based on a Python Module.
+ private PyScope(IntPtr ptr, PyScopeManager manager) : base(ptr)
+ {
+ if (!Runtime.PyType_IsSubtype(Runtime.PyObject_TYPE(Reference), Runtime.PyModuleType))
{
throw new PyScopeException("object is not a module");
}
Manager = manager ?? PyScopeManager.Global;
- obj = ptr.MoveToPyObject();
//Refcount of the variables not increase
variables = Runtime.PyModule_GetDict(Reference).DangerousGetAddress();
PythonException.ThrowIfIsNull(variables);
@@ -72,7 +70,8 @@ internal PyScope(ref NewReference ptr, PyScopeManager manager)
Runtime.PyEval_GetBuiltins()
);
PythonException.ThrowIfIsNotZero(res);
- this.Name = this.Get("__name__");
+ using var name = this.Get("__name__");
+ this.Name = name.As();
}
///
@@ -118,7 +117,7 @@ public dynamic Import(string name, string asname = null)
}
else
{
- PyObject module = PythonEngine.ImportModule(name);
+ var module = PyModule.Import(name);
Import(module, asname);
return module;
}
@@ -132,7 +131,7 @@ public dynamic Import(string name, string asname = null)
///
public void Import(PyScope scope, string asname)
{
- this.SetPyValue(asname, scope.obj.Handle);
+ this.SetPyValue(asname, scope.Handle);
}
///
@@ -169,7 +168,7 @@ public void ImportAll(string name)
}
else
{
- PyObject module = PythonEngine.ImportModule(name);
+ var module = PyModule.Import(name);
ImportAll(module);
}
}
@@ -503,16 +502,20 @@ public override bool TrySetMember(SetMemberBinder binder, object value)
private void Check()
{
- if (this.obj.IsDisposed)
+ if (this.obj == IntPtr.Zero)
{
throw new PyScopeException($"The scope of name '{Name}' object has been disposed");
}
}
- public void Dispose()
+ protected override void Dispose(bool disposing)
{
+ if (this.obj == IntPtr.Zero)
+ {
+ return;
+ }
+ base.Dispose(disposing);
this.OnDispose?.Invoke(this);
- this.obj.Dispose();
}
}
diff --git a/src/runtime/pystring.cs b/src/runtime/pystring.cs
index b3d0dc86d..07eabba14 100644
--- a/src/runtime/pystring.cs
+++ b/src/runtime/pystring.cs
@@ -67,11 +67,8 @@ public PyString(string s) : base(FromString(s))
///
- /// IsStringType Method
- ///
- ///
/// Returns true if the given object is a Python string.
- ///
+ ///
public static bool IsStringType(PyObject value)
{
return Runtime.PyString_Check(value.obj);
diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs
index 35ea3f6d2..b12309733 100644
--- a/src/runtime/pythonengine.cs
+++ b/src/runtime/pythonengine.cs
@@ -468,62 +468,27 @@ public static void EndAllowThreads(IntPtr ts)
Runtime.PyEval_RestoreThread(ts);
}
+ [Obsolete("Use PyModule.Import")]
+ public static PyObject ImportModule(string name) => PyModule.Import(name);
- ///
- /// ImportModule Method
- ///
- ///
- /// Given a fully-qualified module or package name, import the
- /// module and return the resulting module object as a PyObject
- /// or null if an exception is raised.
- ///
- public static PyObject ImportModule(string name)
- {
- IntPtr op = Runtime.PyImport_ImportModule(name);
- PythonException.ThrowIfIsNull(op);
- return new PyObject(op);
- }
-
-
- ///
- /// ReloadModule Method
- ///
- ///
- /// Given a PyObject representing a previously loaded module, reload
- /// the module.
- ///
+ [Obsolete("Use PyModule.Reload")]
public static PyObject ReloadModule(PyObject module)
- {
- IntPtr op = Runtime.PyImport_ReloadModule(module.Handle);
- PythonException.ThrowIfIsNull(op);
- return new PyObject(op);
- }
+ => module is PyModule pyModule ? pyModule.Reload() : new PyModule(module).Reload();
-
- ///
- /// ModuleFromString Method
- ///
- ///
- /// Given a string module name and a string containing Python code,
- /// execute the code in and return a module of the given name.
- ///
+ [Obsolete("Use PyModule.FromString")]
public static PyObject ModuleFromString(string name, string code)
- {
- IntPtr c = Runtime.Py_CompileString(code, "none", (int)RunFlagType.File);
- PythonException.ThrowIfIsNull(c);
- IntPtr m = Runtime.PyImport_ExecCodeModule(name, c);
- PythonException.ThrowIfIsNull(m);
- return new PyObject(m);
- }
+ => PyModule.FromString(name, code);
+
public static PyObject Compile(string code, string filename = "", RunFlagType mode = RunFlagType.File)
{
var flag = (int)mode;
- IntPtr ptr = Runtime.Py_CompileString(code, filename, flag);
+ NewReference ptr = Runtime.Py_CompileString(code, filename, flag);
PythonException.ThrowIfIsNull(ptr);
- return new PyObject(ptr);
+ return ptr.MoveToPyObject();
}
+
///
/// Eval Method
///
@@ -742,10 +707,12 @@ public static KeywordArguments kw(params object[] kv)
return dict;
}
- public static PyObject Import(string name)
- {
- return PythonEngine.ImportModule(name);
- }
+ ///
+ /// Given a module or package name, import the
+ /// module and return the resulting module object as a .
+ ///
+ /// Fully-qualified module or package name
+ public static PyModule Import(string name) => PyModule.Import(name);
public static void SetArgv()
{
diff --git a/src/runtime/pythonexception.cs b/src/runtime/pythonexception.cs
index 7dd4f0811..648888293 100644
--- a/src/runtime/pythonexception.cs
+++ b/src/runtime/pythonexception.cs
@@ -48,7 +48,7 @@ public PythonException()
if (_pyTB != IntPtr.Zero)
{
- using PyObject tb_module = PythonEngine.ImportModule("traceback");
+ using var tb_module = PyModule.Import("traceback");
Runtime.XIncref(_pyTB);
using var pyTB = new PyObject(_pyTB);
@@ -198,7 +198,7 @@ public string Format()
using (PyObject pyType = new PyObject(type))
using (PyObject pyValue = new PyObject(value))
using (PyObject pyTB = new PyObject(tb))
- using (PyObject tb_mod = PythonEngine.ImportModule("traceback"))
+ using (PyObject tb_mod = PyModule.Import("traceback"))
{
var buffer = new StringBuilder();
var values = tb_mod.InvokeMethod("format_exception", pyType, pyValue, pyTB);
diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs
index ec7f5e446..173bd294d 100644
--- a/src/runtime/runtime.cs
+++ b/src/runtime/runtime.cs
@@ -278,9 +278,8 @@ private static void InitPyMembers()
_PyObject_NextNotImplemented = Get_PyObject_NextNotImplemented();
{
- IntPtr sys = PyImport_ImportModule("sys");
- PyModuleType = PyObject_Type(sys);
- XDecref(sys);
+ using var sys = PyImport_ImportModule("sys");
+ PyModuleType = PyObject_Type(sys.DangerousMoveToPointer());
}
}
@@ -937,14 +936,14 @@ internal static NewReference PyRun_String(string code, RunFlagType st, BorrowedR
/// Return value: New reference.
/// This is a simplified interface to Py_CompileStringFlags() below, leaving flags set to NULL.
///
- internal static IntPtr Py_CompileString(string str, string file, int start)
+ internal static NewReference Py_CompileString(string str, string file, int start)
{
using var strPtr = new StrPtr(str, Encoding.UTF8);
using var fileObj = new PyString(file);
return Delegates.Py_CompileStringObject(strPtr, fileObj.Reference, start, Utf8String, -1);
}
- internal static IntPtr PyImport_ExecCodeModule(string name, IntPtr code)
+ internal static NewReference PyImport_ExecCodeModule(string name, BorrowedReference code)
{
using var namePtr = new StrPtr(name, Encoding.UTF8);
return Delegates.PyImport_ExecCodeModule(namePtr, code);
@@ -1027,11 +1026,18 @@ internal static int PyObject_HasAttrString(BorrowedReference pointer, string nam
internal static IntPtr PyObject_GetAttrString(IntPtr pointer, string name)
{
using var namePtr = new StrPtr(name, Encoding.UTF8);
- return Delegates.PyObject_GetAttrString(pointer, namePtr);
+ return Delegates.PyObject_GetAttrString(new BorrowedReference(pointer), namePtr)
+ .DangerousMoveToPointerOrNull();
}
+ internal static NewReference PyObject_GetAttrString(BorrowedReference pointer, string name)
+ {
+ using var namePtr = new StrPtr(name, Encoding.UTF8);
+ return Delegates.PyObject_GetAttrString(pointer, namePtr);
+ }
- internal static IntPtr PyObject_GetAttrString(IntPtr pointer, StrPtr name) => Delegates.PyObject_GetAttrString(pointer, name);
+ internal static NewReference PyObject_GetAttrString(BorrowedReference pointer, StrPtr name)
+ => Delegates.PyObject_GetAttrString(pointer, name);
internal static int PyObject_SetAttrString(IntPtr pointer, string name, IntPtr value)
@@ -1917,13 +1923,13 @@ internal static string PyModule_GetFilename(IntPtr module)
/// Return value: New reference.
///
- internal static IntPtr PyImport_ImportModule(string name)
+ internal static NewReference PyImport_ImportModule(string name)
{
using var namePtr = new StrPtr(name, Encoding.UTF8);
return Delegates.PyImport_ImportModule(namePtr);
}
- internal static IntPtr PyImport_ReloadModule(IntPtr module) => Delegates.PyImport_ReloadModule(module);
+ internal static NewReference PyImport_ReloadModule(BorrowedReference module) => Delegates.PyImport_ReloadModule(module);
internal static BorrowedReference PyImport_AddModule(string name)
@@ -2294,13 +2300,13 @@ static Delegates()
PyRun_SimpleStringFlags = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyRun_SimpleStringFlags), GetUnmanagedDll(_PythonDll));
PyRun_StringFlags = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyRun_StringFlags), GetUnmanagedDll(_PythonDll));
PyEval_EvalCode = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyEval_EvalCode), GetUnmanagedDll(_PythonDll));
- Py_CompileStringObject = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(Py_CompileStringObject), GetUnmanagedDll(_PythonDll));
- PyImport_ExecCodeModule = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyImport_ExecCodeModule), GetUnmanagedDll(_PythonDll));
+ Py_CompileStringObject = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(Py_CompileStringObject), GetUnmanagedDll(_PythonDll));
+ PyImport_ExecCodeModule = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyImport_ExecCodeModule), GetUnmanagedDll(_PythonDll));
PyCFunction_NewEx = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyCFunction_NewEx), GetUnmanagedDll(_PythonDll));
PyCFunction_Call = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyCFunction_Call), GetUnmanagedDll(_PythonDll));
PyMethod_New = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyMethod_New), GetUnmanagedDll(_PythonDll));
PyObject_HasAttrString = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_HasAttrString), GetUnmanagedDll(_PythonDll));
- PyObject_GetAttrString = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_GetAttrString), GetUnmanagedDll(_PythonDll));
+ PyObject_GetAttrString = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_GetAttrString), GetUnmanagedDll(_PythonDll));
PyObject_SetAttrString = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_SetAttrString), GetUnmanagedDll(_PythonDll));
PyObject_HasAttr = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_HasAttr), GetUnmanagedDll(_PythonDll));
PyObject_GetAttr = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyObject_GetAttr), GetUnmanagedDll(_PythonDll));
@@ -2458,8 +2464,8 @@ static Delegates()
PyModule_GetFilename = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyModule_GetFilename), GetUnmanagedDll(_PythonDll));
PyModule_Create2 = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyModule_Create2), GetUnmanagedDll(_PythonDll));
PyImport_Import = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyImport_Import), GetUnmanagedDll(_PythonDll));
- PyImport_ImportModule = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyImport_ImportModule), GetUnmanagedDll(_PythonDll));
- PyImport_ReloadModule = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyImport_ReloadModule), GetUnmanagedDll(_PythonDll));
+ PyImport_ImportModule = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyImport_ImportModule), GetUnmanagedDll(_PythonDll));
+ PyImport_ReloadModule = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyImport_ReloadModule), GetUnmanagedDll(_PythonDll));
PyImport_AddModule = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyImport_AddModule), GetUnmanagedDll(_PythonDll));
PyImport_GetModuleDict = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyImport_GetModuleDict), GetUnmanagedDll(_PythonDll));
PySys_SetArgvEx = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PySys_SetArgvEx), GetUnmanagedDll(_PythonDll));
@@ -2566,13 +2572,13 @@ static Delegates()
internal static delegate* unmanaged[Cdecl] PyRun_SimpleStringFlags { get; }
internal static delegate* unmanaged[Cdecl] PyRun_StringFlags { get; }
internal static delegate* unmanaged[Cdecl] PyEval_EvalCode { get; }
- internal static delegate* unmanaged[Cdecl] Py_CompileStringObject { get; }
- internal static delegate* unmanaged[Cdecl] PyImport_ExecCodeModule { get; }
+ internal static delegate* unmanaged[Cdecl] Py_CompileStringObject { get; }
+ internal static delegate* unmanaged[Cdecl] PyImport_ExecCodeModule { get; }
internal static delegate* unmanaged[Cdecl] PyCFunction_NewEx { get; }
internal static delegate* unmanaged[Cdecl] PyCFunction_Call { get; }
internal static delegate* unmanaged[Cdecl] PyMethod_New { get; }
internal static delegate* unmanaged[Cdecl] PyObject_HasAttrString { get; }
- internal static delegate* unmanaged[Cdecl] PyObject_GetAttrString { get; }
+ internal static delegate* unmanaged[Cdecl] PyObject_GetAttrString { get; }
internal static delegate* unmanaged[Cdecl] PyObject_SetAttrString { get; }
internal static delegate* unmanaged[Cdecl] PyObject_HasAttr { get; }
internal static delegate* unmanaged[Cdecl] PyObject_GetAttr { get; }
@@ -2723,8 +2729,8 @@ static Delegates()
internal static delegate* unmanaged[Cdecl] PyModule_GetFilename { get; }
internal static delegate* unmanaged[Cdecl] PyModule_Create2 { get; }
internal static delegate* unmanaged[Cdecl] PyImport_Import { get; }
- internal static delegate* unmanaged[Cdecl] PyImport_ImportModule { get; }
- internal static delegate* unmanaged[Cdecl] PyImport_ReloadModule { get; }
+ internal static delegate* unmanaged[Cdecl] PyImport_ImportModule { get; }
+ internal static delegate* unmanaged[Cdecl] PyImport_ReloadModule { get; }
internal static delegate* unmanaged[Cdecl] PyImport_AddModule { get; }
internal static delegate* unmanaged[Cdecl] PyImport_GetModuleDict { get; }
internal static delegate* unmanaged[Cdecl] PySys_SetArgvEx { get; }
diff --git a/src/runtime/runtime_state.cs b/src/runtime/runtime_state.cs
index 295219675..b541a7c44 100644
--- a/src/runtime/runtime_state.cs
+++ b/src/runtime/runtime_state.cs
@@ -139,18 +139,15 @@ private static void RestoreObjects(IntPtr dummyGC)
public static IEnumerable PyGCGetObjects()
{
- var gc = PyImport_ImportModule("gc");
- PythonException.ThrowIfIsNull(gc);
- var get_objects = PyObject_GetAttrString(gc, "get_objects");
- var objs = PyObject_CallObject(get_objects, IntPtr.Zero);
+ using var gc = PyModule.Import("gc");
+ using var get_objects = gc.GetAttr("get_objects");
+ var objs = PyObject_CallObject(get_objects.Handle, IntPtr.Zero);
var length = PyList_Size(new BorrowedReference(objs));
for (long i = 0; i < length; i++)
{
var obj = PyList_GetItem(new BorrowedReference(objs), i);
yield return obj.DangerousGetAddress();
}
- XDecref(objs);
- XDecref(gc);
}
public static IEnumerable GetModuleNames()
diff --git a/src/runtime/tricks/NullOnly.cs b/src/runtime/tricks/NullOnly.cs
new file mode 100644
index 000000000..cc2679a61
--- /dev/null
+++ b/src/runtime/tricks/NullOnly.cs
@@ -0,0 +1,12 @@
+namespace Python.Runtime
+{
+ ///
+ /// An utility class, that can only have one value: null.
+ /// Useful for overloading operators on structs,
+ /// that have meaningful concept of null value (e.g. pointers and references).
+ ///
+ class NullOnly
+ {
+ private NullOnly() { }
+ }
+}
diff --git a/src/testing/threadtest.cs b/src/testing/threadtest.cs
index 9c76929b2..6664c3643 100644
--- a/src/testing/threadtest.cs
+++ b/src/testing/threadtest.cs
@@ -34,7 +34,7 @@ public static string CallEchoString(string arg)
{
if (module == null)
{
- module = PythonEngine.ModuleFromString("tt", testmod);
+ module = PyModule.FromString("tt", testmod);
}
PyObject func = module.GetAttr("echostring");
var parg = new PyString(arg);
@@ -58,7 +58,7 @@ public static string CallEchoString2(string arg)
{
if (module == null)
{
- module = PythonEngine.ModuleFromString("tt", testmod);
+ module = PyModule.FromString("tt", testmod);
}
PyObject func = module.GetAttr("echostring2");