开发者

Getting python -m module to work for a module implemented in C

开发者 https://www.devze.com 2023-03-09 05:01 出处:网络
I have a pure C module for Python and I\'d like to be able to invoke it using the python -m modulename approach.This works fine with modules implemented in Python and one obvious workaround is to add

I have a pure C module for Python and I'd like to be able to invoke it using the python -m modulename approach. This works fine with modules implemented in Python and one obvious workaround is to add an extra file for that purpose. However I really want to keep things to my one single distributed binary and not add a second file just for this workaround.

I don't care how hacky the solution is.

If you do try to use a C module with -m then you get an error message No code 开发者_开发百科object available for <modulename>.


-m implementation is in runpy._run_module_as_main . Its essence is:

mod_name, loader, code, fname = _get_module_details(mod_name)
<...>
exec code in run_globals

A compiled module has no "code object" accociated with it so the 1st statement fails with ImportError("No code object available for <module>"). You need to extend runpy - specifically, _get_module_details - to make it work for a compiled module. I suggest returning a code object constructed from the aforementioned "import mod; mod.main()": (python 2.6.1)

    code = loader.get_code(mod_name)
    if code is None:
+       if loader.etc[2]==imp.C_EXTENSION:
+           code=compile("import %(mod)s; %(mod)s.main()"%{'mod':mod_name},"<extension loader wrapper>","exec")
+       else:
+           raise ImportError("No code object available for %s" % mod_name)
-       raise ImportError("No code object available for %s" % mod_name)
    filename = _get_filename(loader, mod_name)

(Update: fixed an error in format string)

Now...

C:\Documents and Settings\Пользователь>python -m pythoncom

C:\Documents and Settings\Пользователь>

This still won't work for builtin modules. Again, you'll need to invent some notion of "main code unit" for them.

Update:

I've looked through the internals called from _get_module_details and can say with confidence that they don't even attempt to retrieve a code object from a module of type other than imp.PY_SOURCE, imp.PY_COMPILED or imp.PKG_DIRECTORY . So you have to patch this machinery this way or another for -m to work. Python fails before retrieving anything from your module (it doesn't even check if the dll is a valid module) so you can't do anything by building it in a special way.


Does your requirement of single distributed binary allow for the use of an egg? If so, you could package your module with a __main__.py with your calling code and the usual __init__.py...

If you're really adamant, maybe you could extend pkgutil.ImpLoader.get_code to return something for C modules (e.g., maybe a special __code__ function). To do that, I think you're going to have to actually change it in the Python source. Even then, pkgutil uses exec to execute the code block, so it would have to be Python code anyway.

TL;DR: I think you're euchred. While Python modules have code at the global level that runs at import time, C modules don't; they're mostly just a dict namespace. Thus, running a C module doesn't really make sense from a conceptual standpoint. You need some real Python code to direct the action.


I think that you need to start by making a separate file in Python and getting the -m option to work. Then, turn that Python file into a code object and incorporate it into your binary in such a way that it continues to work.

Look up setuptools in PyPi, download the .egg and take a look at the file. You will see that the first few bytes contain a Python script and these are followed by a .ZIP file bytestream. Something similar may work for you.


There's a brand new thing that may solve your problems easily. I've just learnt about it and it looks preety decent to me: http://code.google.com/p/pts-mini-gpl/wiki/StaticPython

0

精彩评论

暂无评论...
验证码 换一张
取 消