Opened 16 years ago
Last modified 4 years ago
#4904 new enhancement
Render documentation for modules packaged in EGG | ZIP files | PEP-302 compatible sources
Reported by: | Olemis Lang | Owned by: | Alec Thomas |
---|---|---|---|
Priority: | high | Component: | PyDocPlugin |
Severity: | major | Keywords: | PEP 302, egg, plugins, pydoc |
Cc: | Trac Release: | 0.11 |
Description
I implemented this enhancement when I was setting up the Trac environment I use to manage the development of many plugins (especially TracGViz plugin which is meant to embed iGoogle gadgets in wiki pages using WikiFormatting). I'm used to see in action in the same site the plugins I build (yes, I eat my own dog food ;). That time I realized that even when TracGViz plugin was installed and living in sys.path
, its documentation wasnt shown, and its path was not included in the index page.
I discovered that this was due to two main reasons:
- For the index page, PyDocPlugin filters
sys.path
explicitly so that only the plugins found in the file system be considered. - For the module documentation, the fact is that the implementation relies on
imp
module to load the modules the documentation will be extracted from. This feature is kind of deprecated after PEP 302 -- New Import Hooks has been aproved.
Therefore I wrote a patch to solve the second issue. You can see it in action to generate the API reference documentation for TracGViz plugin.
-
.py
old new 169 169 170 170 def load_object(self, fullobject): 171 171 """ Load an arbitrary object from a full dotted path. """ 172 self.log.debug("Preparing docs for %s", fullobject) 172 173 fullspec = fullobject.split('.') 173 174 i = 0 174 175 module = mfile = mdescr = None 175 176 mpath = self.syspath 177 self.log.debug("Using PATH = %s", mpath) 176 178 # Find module 179 import sys 177 180 if fullspec[0] in sys.builtin_module_names: 178 181 module = __import__(fullspec[0], None, None) 179 182 i += 1 180 183 else: 181 while i < len(fullspec): 184 185 # I removed this since it is not compatible with PEP 302 186 # import hooks and it doesn't load the modules packaged 187 # in zip | egg files. 188 189 # while i < len(fullspec): 190 # try: 191 # f, p, mdescr = imp.find_module(fullspec[i], mpath) 192 # if mfile: 193 # mfile.close() 194 # mfile, mpath = f, [p] 195 # i += 1 196 # except ImportError: 197 # break 198 mname = fullspec[0] 199 import sys # Ensure loaders cache is updated 200 201 def importer(path): 182 202 try: 183 f, p, mdescr = imp.find_module(fullspec[i], mpath) 184 if mfile: 185 mfile.close() 186 mfile, mpath = f, [p] 187 i += 1 188 except ImportError: 203 return sys.path_importer_cache[path] 204 except KeyError: # Not in cache. Try path hooks instead 205 for imp_type in sys.path_hooks: 206 try: 207 return imp_type(path) 208 except: 209 pass 210 else: # No further choices. 211 return imp.NullImporter(path) 212 for path in mpath: 213 i = 0 214 _imp = importer(path) 215 if isinstance(_imp, imp.NullImporter): 216 continue 217 if _imp is None: # Legacy code. No importer object :( 218 mpath = [path] 219 while i < len(fullspec): 220 try: 221 f, p, mdescr = imp.find_module(fullspec[i], mpath) 222 if mfile: 223 mfile.close() 224 mfile, mpath = f, [p] 225 i += 1 226 except ImportError: 227 break 228 else: 229 mname = '' 230 while i < len(fullspec): 231 try: 232 mname+= fullspec[i] 233 self.log.debug("Trying importer '%s' for object '%s'", 234 _imp, mname) 235 if _imp.find_module(mname) is None: 236 break 237 self.log.debug("Ok") 238 path = os.path.join(path, fullspec[i]) 239 i += 1 240 self.log.debug("Setting new path %s", path) 241 _imp = importer(path) 242 self.log.debug("New importer %s", _imp) 243 mname+= '.' 244 except Exception, exc: 245 self.log.debug("Error %s message '%s'", \ 246 exc.__class__, 247 str(exc)) 248 self.log.debug("Search for '%s' stopped at %d", 249 fullobject, i) 250 if i > 0: 189 251 break 252 else: 253 self.log.debug("Unable to import '%s'", fullobject) 254 raise ImportError, fullobject 190 255 try: 191 256 mname = ".".join(fullspec[0:i]) 192 if sys.modules.has_key(mname): 193 module = sys.modules[mname] 194 elif mname and mdescr: 195 module = imp.load_module(mname, mfile, mpath[0], mdescr) 257 self.log.debug("Module name %s", mname) 258 __import__(mname, None, None) 259 self.log.debug("Retrieving %s from sys.path", mname) 260 module = sys.modules[mname] 261 self.log.debug("Ok") 196 262 finally: 197 263 if mfile: 198 264 mfile.close() … … 237 303 238 304 def _makedoc(self, target, visibility): 239 305 """Warning: this helper method returns a `str` object.""" 306 self.log.debug('Loading module and object') 240 307 module, object = self.load_object(target) 308 self.log.debug('Module and object loaded') 241 309 try: 242 310 self.makedoc_lock.acquire() 243 311 if visibility == 'private' or \
The first issue still remains open, since that PEP doesnt provide standards for module enumeration.
Best Regards,
Olemis Lang