As part of a generification of some of my core metaframework code I found myself wanting to do a bit of introspection on the contents of the modules I was importing in as tests. Somehow I ended up running across the pyclbr (Python Class Browser) module which can return to me a list of the classes contained in a document. (I can then check each class to see if unittest.TestCase is it’s superclass and treat it accordingly).
Because nothing is as easy as it could (should?) be, the pyclbr module doesn’t work in Jython which is what I write this sort of thing in. Turns out that it is smart (?) enough to check whether the file it is to look at is flat text (good) or some other format (not good). Because Jython runs inside the Java VM it deals with .class files which are certainly not string parsable. Consquently, pyclbr.read_module() would always return an empty dictionary (and no helpful debugging messaging, btw).
Flash forward a bit and I’ve submitted a patch to Jython which will restore functionality to this cool little function.
I’ve got a small, but questionable track record at getting patches applied (CPython: 0/1, Selenium IDE: 1/2, Jython 0?/1) so I’m putting the diff below the cut.
*** c:\jython\jython-2.2.1\Lib\pyclbr.py Sat Oct 13 12:06:30 2007 --- c:\temp\jpythonruby\jython2.2b2\Lib\pyclbr.py Wed Nov 14 10:53:04 2007 *************** *** 196,208 **** path = [file] + path f, file, (suff, mode, type) = \ imp.find_module('__init__', [file]) if type != imp.PY_SOURCE: # not Python source, can't do anything with this module f.close() ! _modules[module] = dict ! return dict _modules[module] = dict classstack = [] # stack of (class, indent) pairs src = f.read() f.close() --- 196,219 ---- path = [file] + path f, file, (suff, mode, type) = \ imp.find_module('__init__', [file]) if type != imp.PY_SOURCE: # not Python source, can't do anything with this module + # -- unless maybe we happen to be jython where the modules are compiled f.close() ! if type == imp.PY_COMPILED and not sys.platform.startswith("java"): ! _modules[module] = dict ! return dict ! else: ! # check that the corresponding .py exists ! import os.path ! s_file = os.path.basename(file).replace(os.path.basename(file)[os.path.basename(file).find("$"):], ".py") ! s_path = file.replace(os.path.basename(file), s_file) ! if os.path.exists(s_path): ! # reset the pointers to the source ! f = open(s_path, "r") ! file = s_path _modules[module] = dict classstack = [] # stack of (class, indent) pairs src = f.read() f.close()
Adam — why don’t you submit a talk proposal for PyCon ’08? It will be in Chicago, March 14-16. Check out
http://us.pycon.org/2008/conference/proposals/
for details.
The organizers are very much looking for talk proposals — the deadline is this Friday.
I’m sure you’d have a ton of Python-related material to choose from. This post proves it 🙂
Grig