Import Python module with PyImport_ImportModuleEx

2019-07-10 05:10发布

问题:

I'm learning Python and I try to use Python Markdown in a gedit plugin. Here's how my files are organized:

~/.gnome2/gedit/plugins/mytest.gedit-plugin
~/.gnome2/gedit/plugins/mytest/
~/.gnome2/gedit/plugins/mytest/__init__.py
~/.gnome2/gedit/plugins/mytest/markdown/
~/.gnome2/gedit/plugins/mytest/markdown/__init__.py
~/.gnome2/gedit/plugins/mytest/markdown/preprocessors.py
~/.gnome2/gedit/plugins/mytest/markdown/OTHER_FILES
~/.gnome2/gedit/plugins/mytest/markdown/extensions/
~/.gnome2/gedit/plugins/mytest/markdown/extensions/__init__.py
~/.gnome2/gedit/plugins/mytest/markdown/extensions/headerid.py
~/.gnome2/gedit/plugins/mytest/markdown/extensions/OTHER_FILES

Explication:

My file mytest.gedit-plugin only contains minimal code to declare the plugin:

[Gedit Plugin]
Loader=python
Module=mytest
IAge=2
Name=My test

My plugin has its own subfolder (mytest). The file mytest/__init__.py contains:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import gedit
import markdown

class MyTestPlugin(gedit.Plugin):
    def __init__(self):
        gedit.Plugin.__init__(self)

    def activate(self, window):
        texte = "# Header 1 {#id}"
        print markdown.markdown(texte, extensions=['headerid'])

Finally, the folder mytest/markdown contains default Python Markdown code.

When I activate my plugin in gedit (Edit > Preferences > Plugins), output in the terminal is:

Traceback (most recent call last):
  File "/home/moi/.gnome2/gedit/plugins/mytest/__init__.py", line 5, in <module>
    import markdown
  File "/home/moi/.gnome2/gedit/plugins/mytest/markdown/__init__.py", line 161, in <module>
    import preprocessors
  File "/home/moi/.gnome2/gedit/plugins/mytest/markdown/preprocessors.py", line 11, in <module>
    import markdown
ImportError: No module named markdown

** (gedit:8790): WARNING **: Error loading plugin 'My test'

However, I successfully use Python Markdown outside gedit. For example, the following file works great when I run it in a terminal in the same location as the Python Markdown main folder:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import markdown

texte = "# Header 1 {#id}"
print markdown.markdown(texte, extensions=['headerid'])

I found that if I change import markdown in Python Markdown files for import __init__ as markdown, I can use Python Markdown without its extensions (mytest/markdown/extensions/), but anyway, it still doesn't work with my example:

/home/moi/.gnome2/gedit/plugins/mytest/markdown/__init__.py:114: MarkdownWarning: Failed loading extension 'headerid' from 'markdown.extensions.headerid' or 'mdx_headerid'
  warnings.warn(text, MarkdownWarning)
<h1>Header 1 {#id}</h1>

So, my question is how could I modify import for extensions, or how could I install Python Markdown in a local emplacement (so in $HOME, without root access) to be able to use Python Markdown in a gedit plugin?

Thanks a lot.

Note: I think gedit uses PyImport_ImportModuleEx() to load plugins, so that's why I put it in the title of my question.


Edit 1: 2 details: no root installation and possible to modify Python Markdown files.

Edit 2: Extensions are loaded with the following code in mytest/markdown/__init__.py (about line 525):

# Setup the module names
ext_module = 'markdown.extensions'
module_name_new_style = '.'.join([ext_module, ext_name])
module_name_old_style = '_'.join(['mdx', ext_name])

# Try loading the extention first from one place, then another
try: # New style (markdown.extensons.<extension>)
    module = __import__(module_name_new_style, {}, {}, [ext_module])
except ImportError:
    try: # Old style (mdx.<extension>)
        module = __import__(module_name_old_style)
    except ImportError:
       message(WARN, "Failed loading extension '%s' from '%s' or '%s'"
           % (ext_name, module_name_new_style, module_name_old_style))
       # Return None so we don't try to initiate none-existant extension
       return None

Maybe there's a way to import with relative path. I'm really beginner with Python.

回答1:

If you want to use markdown without modifying it then you're going to have to put it somewhere where the Python library expects it, such as in site-packages/. Otherwise, you will have to modify it to use relative imports instead of absolute imports.