diff --git a/src/embed_tests/TestPyModule.cs b/src/embed_tests/TestPyModule.cs new file mode 100644 index 000000000..e575a73a6 --- /dev/null +++ b/src/embed_tests/TestPyModule.cs @@ -0,0 +1,47 @@ + +using System; + +using NUnit.Framework; + +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestPyModule + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public void TestCreate() + { + using PyScope scope = Py.CreateScope(); + + Assert.IsFalse(PyModule.SysModules.HasKey("testmod")); + + PyModule testmod = new PyModule("testmod"); + + testmod.SetAttr("testattr1", "True".ToPython()); + + PyModule.SysModules.SetItem("testmod", testmod); + + using PyObject code = PythonEngine.Compile( + "import testmod\n" + + "x = testmod.testattr1" + ); + scope.Execute(code); + + Assert.IsTrue(scope.TryGet("x", out dynamic x)); + Assert.AreEqual("True", x.ToString()); + } + } +} diff --git a/src/runtime/pymodule.cs b/src/runtime/pymodule.cs index 800edb686..e6c50bc66 100644 --- a/src/runtime/pymodule.cs +++ b/src/runtime/pymodule.cs @@ -1,4 +1,7 @@ using System; +using System.Text; + +using Python.Runtime.Native; namespace Python.Runtime { @@ -6,6 +9,7 @@ public class PyModule : PyScope { internal PyModule(ref NewReference reference) : base(ref reference, PyScopeManager.Global) { } public PyModule(PyObject o) : base(o.Reference, PyScopeManager.Global) { } + public PyModule(string name, string filename = null) : this(Create(name, filename)) { } /// /// Given a module or package name, import the @@ -37,5 +41,49 @@ public static PyModule FromString(string name, string code) PythonException.ThrowIfIsNull(m); return new PyModule(ref m); } + + private static PyModule Create(string name, string filename=null) + { + if(string.IsNullOrWhiteSpace(name)) + { + throw new ArgumentNullException(nameof(name)); + } + + NewReference op = Runtime.PyModule_New(name); + PythonException.ThrowIfIsNull(op); + + if (filename != null) + { + BorrowedReference globals = Runtime.PyModule_GetDict(op); + PythonException.ThrowIfIsNull(globals); + int rc = Runtime.PyDict_SetItemString(globals, "__file__", filename.ToPython().Reference); + PythonException.ThrowIfIsNotZero(rc); + } + + return new PyModule(ref op); + } + + public void SetBuiltins(PyDict builtins) + { + if(builtins == null || builtins.IsNone()) + { + throw new ArgumentNullException(nameof(builtins)); + } + + BorrowedReference globals = Runtime.PyModule_GetDict(this.Reference); + PythonException.ThrowIfIsNull(globals); + int rc = Runtime.PyDict_SetItemString(globals, "__builtins__", builtins.Reference); + PythonException.ThrowIfIsNotZero(rc); + } + + public static PyDict SysModules + { + get + { + BorrowedReference sysModulesRef = Runtime.PyImport_GetModuleDict(); + PythonException.ThrowIfIsNull(sysModulesRef); + return new PyDict(sysModulesRef); + } + } } } diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 43ee08716..4114fc4d0 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -2280,6 +2280,16 @@ internal static IntPtr GetBuiltins() return PyImport_Import(PyIdentifier.builtins); } + public static PyDict Builtins + { + get + { + BorrowedReference builtins = PyEval_GetBuiltins(); + PythonException.ThrowIfIsNull(builtins); + return new PyDict(builtins); + } + } + internal static class Delegates { static readonly ILibraryLoader libraryLoader = LibraryLoader.Instance;