<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><br><div><div>On Apr 14, 2012, at 3:32 PM, Guido van Rossum wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><span class="Apple-style-span" style="border-collapse: separate; font-family: 'Bitstream Vera Sans Mono'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; "><span class="Apple-style-span" style="font-family: monospace; ">Funny, I was just thinking about having a simple standard API that<br>will let you open files (and list directories) relative to a given<br>module or package regardless of how the thing is loaded.</span></span></blockquote></div><div><br></div><div>Twisted has such a thing, mostly written by me, called twisted.python.modules.</div><div><br></div><div>Sorry if I'm repeating myself here, I know I've brought it up on this list before, but it seems germane to this thread. &nbsp;I'd be interested in getting feedback from the import-wizards participating in this thread in case it is doing anything bad (in particular I'd like to make sure it will keep working in future versions of Python), but I think it may provide quite a good template for a standard API.</div><div><br></div><div>The code's here: &lt;<a href="http://twistedmatrix.com/trac/browser/trunk/twisted/python/modules.py">http://twistedmatrix.com/trac/browser/trunk/twisted/python/modules.py</a>&gt;</div><div><br></div><div>The API is fairly simple.</div><div><br></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;"><div><div><div>&gt;&gt;&gt; from twisted.python.modules import getModule</div></div><div>&gt;&gt;&gt; e = getModule("email") # get an abstract "module" object (un-loaded)</div></div><div><div>&gt;&gt;&gt; e</div></div><div><div>PythonModule&lt;'email'&gt;</div></div><div><div>&gt;&gt;&gt; walker = e.walkModules() # walk the module hierarchy</div></div><div><div>&gt;&gt;&gt; walker.next()</div></div><div><div>PythonModule&lt;'email'&gt;</div></div><div><div>&gt;&gt;&gt; walker.next()</div></div><div><div>PythonModule&lt;'email._parseaddr'&gt;</div></div><div><div>&gt;&gt;&gt; walker.next() # et cetera</div></div><div><div>PythonModule&lt;'email.base64mime'&gt;</div></div><div><div>&gt;&gt;&gt; charset = e["charset"] # get the 'charset' child module of the 'e' package</div></div><div><div>&gt;&gt;&gt; charset.filePath</div></div><div><div>FilePath('.../lib/python2.7/email/charset.py')</div></div><div><div><div>&gt;&gt;&gt; charset.filePath.parent().children() # list the directory containing charset.py</div></div><div></div></div></blockquote><div><div><br></div><div>Worth pointing out is that although in this example it's a FilePath, it could also be a ZipPath if you imported stuff from a zipfile. &nbsp;We have an adapter that inspects path_importer_cache and produces appropriately-shaped filesystem-like objects depending on where your module was imported from. &nbsp;Thank you to authors of PEP 302; that was my religion while writing this code.</div><div><br></div><div>You can also, of course, ask to load something once you've identified it with the traversal API:</div><div><br></div></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;"><div><div>&gt;&gt;&gt; charset.load()</div></div><div><div>&lt;module 'email.charset' from '.../lib/python2.7/email/charset.pyc'&gt;</div></div></blockquote><div><br></div><div>You can also ask questions like this, which are very useful when debugging setup problems:</div><div><br></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;"><div><div>&gt;&gt;&gt; ifaces = getModule("twisted.internet.interfaces")</div><div>&gt;&gt;&gt; ifaces.pathEntry</div><div>PathEntry&lt;FilePath('/Domicile/glyph/Projects/Twisted/trunk')&gt;</div><div>&gt;&gt;&gt; list(ifaces.pathEntry.iterModules())</div><div>[PythonModule&lt;'setup'&gt;, PythonModule&lt;'twisted'&gt;]</div></div></blockquote><div><br></div><div>This asks what <i>sys.path entry</i> is responsible twisted.internet.interfaces, and then what other modules could be loaded from there. &nbsp;Just 'setup' and 'twisted' indicates that this is a development install (not surprising for one of my computers), since site-packages would be much more crowded.</div><div><br></div><div>The idiom for saying "there's a file installed near this module, and I'd like to grab it as a string", is pretty straightforward:</div><div><br></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;"><div>from twisted.python.modules import getModule</div><div>mod = getModule(__name__).filePath.sibling("my-file").open().read()</div></blockquote><div><br></div><div>And hopefully it's obvious from this idiom how one might get the pathname, or a stream rather than the bytes.</div><div><br></div><div>-glyph</div></body></html>