Hooking __import__ when embedding the interpreter

Stefan Bellon sbellon at sbellon.de
Fri Jun 29 05:57:13 EDT 2007


Hi all,

I am embedding the Python interpreter using the C API and extending it
using modules generated by SWIG. In order to guarantee consistency
about importing those modules, I would like to "hook" into the Python's
import statement and __import__ function and do some checks there.

I have experimented a bit already, but still have a few questions and
would be happy if anybody from the group could shed some light on those.

At present, I have the following test code:


#include <stdio.h>
#include <Python.h>

static PyObject *
__import__(PyObject *self, PyObject *args)
{
    char *name;
    PyObject *globals = NULL;
    PyObject *locals = NULL;
    PyObject *fromlist = NULL;

    if (!PyArg_ParseTuple
        (args, "s|OOO:__import__", &name, &globals, &locals, &fromlist))
    {
        return NULL;
    }

    PyObject *m = PyDict_GetItemString(PyImport_GetModuleDict(), name);
    if (m)
    {
        Py_INCREF(m);
        return m;
    }

    if (!strcmp(name, "foobar")) // to be replaced by the consistency check!
    {
        PyErr_SetString
          (PyExc_ImportError, "cannot import module right now");
        return NULL;
    }

    return PyImport_ImportModuleEx(name, globals, locals, fromlist);
}

static PyMethodDef import_hook[] =
{
    { "__import__", __import__ },
    { NULL, NULL }
};

int main()
{
    Py_Initialize();

    Py_InitModule("import_hook", import_hook);

    PyObject_SetAttrString
      (PyImport_ImportModule("__builtin__"),
       "__import__",
       PyObject_GetAttrString
         (PyImport_ImportModule("import_hook"), "__import__"));

    PyRun_InteractiveLoop(stdin, "<stdin>");

    Py_Finalize();
}


The code of __import__ above was inspired by the code of
builtin__import__ in Python/bltinmodule.c with the addition of the
early exit if the module is already loaded and the "consistency"
check which I reduced to some "cannot load module foobar" for ease
of the test case.


Now to my open questions.

1) The above code seems to work ok when using the "import" statement,
   but it does not when using the dynamic __import__ function. If using
   it that way, I get:

>>> sys=__import__("sys")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
SystemError: new style getargs format but argument is not a tuple

   What am I missing in order to get the __import__ function covered
   as well?


2) Another point is, that I need to check _from where_ the module is
   imported. In fact, this is going to become part of the consistency
   check condition. How can I find out from which module the import
   was initiated?


3) My final point is related to 2) ... if I get to the module object,
   then how do I get at the source file name of that? I noticed that
   when a .pyc is available, then this is preferred. I'd like to get at
   the .py file itself. Is this available or do I just have to strip
   off the trailing 'c' (or 'o'?) if present (seems hacky to me).


I am very much looking forward to your suggestions!

Greetings,
Stefan

-- 
Stefan Bellon



More information about the Python-list mailing list