C API Q II : __main__.__dict__.keys() not same as dir()

Johan Hahn johahn at delta.telenordia.se
Sun Apr 14 05:10:57 EDT 2002


Hi

I'm writing a console for a game using the c api.

I figured that since the InteractiveConsole hangs after calling interact()
you have to have atleast 2 threads to use that, right? I thought the
documentation was a little vague on that.

Anyway, for now I use the InteractiveInterpreter and do the input buffering
in C and it works great. So great I decided to implement completion of
Python commands, just like when you hit tab in Unix.

For example if you type...
>>> import code
>>> code.I
...and press <tab> you should be presented the list:
['InteractiveInterpreter', 'InteractiveConsole']

That went fairly easy too (thanks to Python), but one problem remains.

When you import a module using python shell, it appears in
__main__.__dict__. In my program however, that is not the case. The module
is added to sys.modules and can be used without any problem but I need to
see it for my completion code to work.
Here is an example of how it looks in the console:

>>> import __main__, sys, os
>>> __main__.__dict__.keys()
['__builtins__', '__name__', '__doc__']
>>> dir()
['__builtins__', '__doc__', '__main__', '__name__', 'os', 'sys']


Finally, here is my question.
Where does the user imported modules (and all other objects too for that
matter) hide??




Here is part of my code (error checking and reference counting left out)

/* Python code, module b4 */
import code
class jhCon(code.InteractiveInterpreter):
    def complete(self, codeline):
        # First we have to parse the input around the dots
        import string
        parsedCode = string.split(codeline, '.')

        # BUG: dir(__main__) misses user-added objects
        import __main__
        availableCommands = dir(__main__)
        dict = __main__.__dict__

        # traverse the hierarchy
        word = parsedCode[0]
        count = 0
        while word in availableCommands:
            count += 1
            dict = dict[word]
            word = parsedCode[count]
            availableCommands = dir(dict)

        # Check if the incomplete word matches the beginning of
        # any of the availableCommands. If no match do nothing.
        possibleCommands = []
        for command in availableCommands:
            if command[:len(word)] == word:
                possibleCommands.append(command)

        # If we have only one possible command we 'complete' the
        # command by returning only the part of it that remains
        # to be typed in.
        # If there are more than one possible command we print them
        if len(possibleCommands) == 1:
            return possibleCommands[0][len(word):]
        print '\n',possibleCommands

iii = jhCon()
def complete(codeline):
    iii.complete(codeline)




/* C++ code */

Note: I let the constructor and destructor take care of initializing python
and the m_complete variable.

void init()
{
PyObject* moduleName = PyString_FromString("b4");
PyObject* module = PyImport_Import(moduleName);
PyObject* dict = PyModule_GetDict(module);
m_complete = PyDict_GetItemString(dict, "complete");
}


std::string complete(std::string s)
{
PyObject* rslt = PyObject_CallFunction(m_complete, "(s)", s.c_str());
if (!rslt) {           /* Python exception raised */
    PyErr_Print();
    return "";
}
else {
    if (rslt == Py_None)
        return "";
    std::string retVal(PyString_AsString(rslt));
    Py_XDECREF(rslt);
    return retVal;
}
}



mvh,
Johan







More information about the Python-list mailing list