[Python-Dev] creating __all__ in extension modules

Skip Montanaro skip@mojam.com (Skip Montanaro)
Sat, 3 Feb 2001 17:01:01 -0600 (CST)


    Tim> I'm afraid I find it hard to believe people will *keep* C-module
    Tim> __all__ lists in synch with the code as the years go by.  If we're
    Tim> going to do this, how about adding code to Py_InitModule4 that
    Tim> sucks the non-underscore names out of its PyMethodDef argument and
    Tim> automagically builds an __all__ attr?  Then nothing ever needs to
    Tim> be fiddled by hand for C modules.

The way it works now is that the module author inserts a call to
_PyModuleCreateAllList at or near the end of the module's init func

    /* initialize module's __all__ list */
    _PyModule_CreateAllList(d);

that initializes and populates __all__ based on the keys in the module's
dict.  Unlike having to manually maintain __all__, I think this solution is
fairly un-onerous (one-time change).  Again, my assumption is that all
non-underscore prefixed symbols in a module's dict will be exported.  If
this isn't true, the author can simply delete any elements from __all__
after the call to _PyModule_CreateAllList.

This functionality can't be subsumed by Py_InitModule4 because the author is
allowed to insert values into the module dict after that call (see
posixmodule.c for a significant example of this).

_PyModule_CreateAllList is currently defined in modsupport.c (not checked in
yet) as

    /* helper function to create __all__ from an extension module's dict */
    int
    _PyModule_CreateAllList(PyObject *d) {
	    PyObject *v, *k, *s;

	    unsigned int i;
	    int res;

	    v = PyList_New(0);
	    if (v == NULL)
		    return -1;

	    res = 0;
	    if (!PyDict_SetItemString(d, "__all__", v)) {
		    k = PyDict_Keys(d);
		    if (k == NULL)
			    res = -1;
		    else {
			    for (i = 0; res == 0 && i < PyObject_Length(k); i++) {
				    s = PySequence_GetItem(k, i);
				    if (s == NULL)
					    res = -1;
				    else {
					    if (PyString_AsString(s)[0] != '_')
						    if (PyList_Append(v, s))
							    res = -1;
					    Py_DECREF(s);
				    }
			    }
		    }
	    }

	    Py_DECREF(v);
	    return res;
    }

I don't know (nor much care - you guys decide) if it's named with or without
a leading underscore.  I view it as a more-or-less internal function, but
one that many C extension modules will call (guess that might make it not
internal).  I haven't written a doc blurb for the API manual yet.

Skip