Skip to content

[WIP] Add ability to create module from C# #1447

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 29, 2021
Merged

[WIP] Add ability to create module from C# #1447

merged 7 commits into from
Jul 29, 2021

Conversation

slide
Copy link
Contributor

@slide slide commented Apr 21, 2021

What does this implement/fix? Explain your changes.

This allows doing something like this, which I haven't found any other way to do:

var mod = PythonEngine.AddModule("mymod");
var myobj = new object();
mod.SetAttr("myprop".ToPython(), myobj.ToPython());
import mymod
print(mymod.myprop)

This is very useful for providing objects to an embedded Python engine.

Does this close any currently open issues?

I could not find any specific issues that would be related.

Any other comments?

This is an initial PR to get feedback if this would be allowed, I have a build of the library locally with this change and use this in my code, but would like to have it upstream if possible. I will fill out the remaining details and add tests if folks think this would be ok.

Checklist

Check all those that are applicable and complete.

  • Make sure to include one or more tests for your change
  • If an enhancement PR, please create docs and at best an example
  • Add yourself to AUTHORS
  • Updated the CHANGELOG

@lostmsu
Copy link
Member

lostmsu commented Apr 22, 2021

We now have https://github.com/pythonnet/pythonnet/blob/master/src/runtime/pymodule.cs
I think it would make sense to give it a static factory method Create instead of placing code into PythonEngine.

Also, you should probably use

internal static NewReference PyModule_New(string name)

@slide
Copy link
Contributor Author

slide commented Apr 22, 2021

Cool, I didn't know about pymodule.cs, I'll definitely migrate there and use the PyModule_New


namespace Python.EmbeddingTest
{
class TestPyModule
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think test class must be public.

@@ -37,5 +40,40 @@ public static PyModule FromString(string name, string code)
PythonException.ThrowIfIsNull(m);
return new PyModule(ref m);
}

public static PyModule Create(string name, string filename = "none")
Copy link
Member

@lostmsu lostmsu Apr 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method violates single responsibility principle.

First, Create should never return an existing module. Instead, the caller should be able to check if module already exists by name by calling a separate function.

Second, I am uncertain about setting up __builtins__ by default. It would be great to know why Python does not do it before discarding that potentially good rationale. Users can always manually do newModule.Dict.Set("__builtins__", GetBuiltIns()). If this is a common scenario in your product, just make a factory method combining the two.

Third, I don't think adding new module to sys.modules right away is a good idea. Especially, overwriting the existing value. This might cause hard to debug surprise issues.

Copy link
Contributor Author

@slide slide Jul 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second, I am uncertain about setting up __builtins__ by default. It would be great to know why Python does not do it before discarding that potentially good rationale. Users can always manually do newModule.Dict.Set("__builtins__", GetBuiltIns()). If this is a common scenario in your product, just make a factory method combining the two.

I didn't see a public method that would allow access to the __builtins__. There is an internal method, on Runtime, but not a public method that could be used outside.

PythonException.ThrowIfIsNull(__builtins__);
int rc = Runtime.PyDict_SetItemString(globals, "__builtins__", __builtins__);
PythonException.ThrowIfIsNotZero(rc);
rc = Runtime.PyDict_SetItemString(globals, "__file__", new BorrowedReference(filename.ToPython().Handle));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default value for filename should be null and when it is null __file__ should simply not be set.

@LimpingNinja
Copy link

This is a good add feature, is anyone working on it? I am migrating from C where I create a handful of accessible modules from C using Py_InitModule3() and passing in the methods (C function pointers) and vars. Is there an alternative method here or is this something that would pend this change being actioned?

@slide
Copy link
Contributor Author

slide commented Jul 25, 2021

I need to get back to it and make the changes that were requested. I just have a local compiled version with my changes that I have been using, so I haven't had a huge push to get me back to fixing this up. I'll try and work on it soon.

@slide
Copy link
Contributor Author

slide commented Jul 27, 2021

@lostmsu I think I addressed the feedback you provided, please let me know if there are more changes you would like me to make. If not, I will make this a normal PR and remove the WIP.

@slide
Copy link
Contributor Author

slide commented Jul 29, 2021

Feedback hopefully addressed. Thanks for being patient. I still don't know the codebase very well.

@lostmsu lostmsu merged commit 9555248 into pythonnet:master Jul 29, 2021
@slide slide deleted the addmodule branch September 29, 2022 15:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants