<br><br><div><span class="gmail_quote">On 9/27/06, <b class="gmail_sendername">Phillip J. Eby</b> &lt;<a href="mailto:pje@telecommunity.com">pje@telecommunity.com</a>&gt; wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
At 04:11 PM 9/27/2006 -0700, Brett Cannon wrote:<br><br><br>&gt;On 9/27/06, Phillip J. Eby<br>&gt;&lt;&lt;mailto:<a href="mailto:pje@telecommunity.com">pje@telecommunity.com</a>&gt;<a href="mailto:pje@telecommunity.com">pje@telecommunity.com
</a>&gt; wrote:<br>&gt;&gt;At 02:11 PM 9/27/2006 -0700, Brett Cannon wrote:<br>&gt;&gt; &gt;But it has been suggested here that the import machinery be rewritten in<br>&gt;&gt; &gt;Python.&nbsp;&nbsp;Now I have never touched the import code since it has always had
<br>&gt;&gt; &gt;the reputation of being less than friendly to work with.&nbsp;&nbsp;I am asking for<br>&gt;&gt; &gt;opinions from people who have worked with the import machinery before if<br>&gt;&gt; &gt;it is so bad that it is worth trying to re-implement the import semantics
<br>&gt;&gt; &gt;in pure Python or if in the name of time to just work with the C<br>&gt;&gt; &gt;code.&nbsp;&nbsp;Basically I will end up breaking up built-in, .py, .pyc, and<br>&gt;&gt; &gt;extension modules into individual importers and then have a chaining class
<br>&gt;&gt; &gt;to act as a combined .pyc/.py combination importer (this will also make<br>&gt;&gt; &gt;writing out to .pyc files an optional step of the .py import).<br>&gt;&gt;<br>&gt;&gt;The problem you would run into here would be supporting zip imports.
<br>&gt;<br>&gt;I have not looked at zipimport so I don't know the exact issue in terms of<br>&gt;how it hooks into the import machinery.&nbsp;&nbsp;But a C level API will most<br>&gt;likely be needed.<br><br>I was actually assuming you planned to reimplement that in Python as well,
<br>and hence the need for the storage/format separation.</blockquote><div><br>I was not explictly planning on it. <br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
&gt;&gt;&nbsp;&nbsp; It<br>&gt;&gt;would probably be more useful to have a mapping of file types to &quot;format<br>&gt;&gt;handlers&quot;, because then a filesystem importer or zip importer would then be<br>&gt;&gt;able to work with any .py/.pyc/.pyo/whatever formats, along with any new
<br>&gt;&gt;ones that are invented, without reinventing the wheel.<br>&gt;<br>&gt;So you are saying the zipimporter would then pull out of the zip file the<br>&gt;individual file to import and pass that to the format-specific importer?
<br><br>No, I'm saying that the zipimporter would simply call the format importers<br>in sequence, as in your original concept.&nbsp;&nbsp;However, these importers would<br>call *back* to the zipimporter to ask if the file they are looking for is
<br>there.</blockquote><div><br>Ah, OK.&nbsp; So for importing 'email', the zipimporter would call the .pyc importer and it would ask the zipimporter, &quot;can you get me email.pyc?&quot; and if it said no it would move on to asking the .py importer for 
email.py, etc.<br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">&gt;&gt;Thus, whether it's file import, zip import, web import, or whatever, the
<br>&gt;&gt;same handlers would be reusable, and when people invent new extensions like<br>&gt;&gt;.ptl, .kid, etc., they can just register format handlers instead.<br>&gt;<br>&gt;So a sepration of data store from data interpretation for importation.&nbsp;&nbsp;My
<br>&gt;only worry is a possible explosion of checks for the various data<br>&gt;types.&nbsp;&nbsp;If you are using the file data store and had .py, .pyc, .so,<br>&gt;module.so , .ptl, and .kid registered that might suck in terms of
<br>&gt;performance hit.<br><br>Look at it this way: the parent importer can always pull a directory<br>listing once and cache it for the duration of its calls to the child<br>importers.&nbsp;&nbsp;In practice, however, I suspect that the stat calls will be
<br>faster.&nbsp;&nbsp;In the case of a zipimport parent, the zip directory is already<br>cached.<br><br>Also, keep in mind that most imports will likely occur *before* any special<br>additional types get registered, so the hits will be minimal.&nbsp;&nbsp;And the more
<br>of sys.path is taken up by zip files, the less of a hit it will be for each<br>query.</blockquote><div><br>That's fine.&nbsp; Just thinking about how the current situation sucks for NFS but how caching just isn't done.&nbsp; But obvoiusly this could change. 
<br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">&gt;&nbsp;&nbsp; And I am assuming for a web import that it would decide based on the<br>
&gt; extension of the resulting web address?<br><br>No - you'd effectively end up doing a web hit for each possible<br>extension.&nbsp;&nbsp;Which would suck, but that's what caching is<br>for.&nbsp;&nbsp;Realistically, you wouldn't want to do web-based imports without some
<br>disk-based caching anyway.<br><br>&gt;&nbsp;&nbsp; And checking for the various types might not work well for other data<br>&gt; store types.&nbsp;&nbsp;Guess you would need a way to register with the data store<br>&gt; exactly what types of data interpretation you might want to check.
<br><br>No, you just need a method on the parent importer like get_data().<br><br><br>&gt;Other option is to just have the data store do its magic and somehow know<br>&gt;what kind of data interpretation is needed for the string returned (
e.g.,<br>&gt;a database data store might implicitly only store .py code and thus know<br>&gt;that it will only return a string of source).&nbsp;&nbsp;Then that string and the<br>&gt;supposed file extension is passed ot the next step of creating a module
<br>&gt;from that data string.<br><br>Again, all that's way more complex than you need; you can do the same thing<br>by just raising IOError from get_data() when asked for something that's not<br>a .py.<br><br><br>&gt;&gt;Format handlers could of course be based on the PEP 302 protocol, and
<br>&gt;&gt;simply accept a &quot;parent importer&quot; with a get_data() method.&nbsp;&nbsp;So, let's say<br>&gt;&gt;you have a PyImporter:<br>&gt;&gt;<br>&gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class PyImporter:<br>&gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def __init__(self, parent_importer):
<br>&gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.parent = parent_importer<br>&gt;&gt;<br>&gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def find_module(self, fullname):<br>&gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;path = fullname.split('.')[-1]+'.py'<br>&gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try:<br>&gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;source = 
self.parent.get_data(path)<br>&gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;except IOError:<br>&gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return None<br>&gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:<br>&gt;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return PySourceLoader(source)<br>&gt;&gt;<br>&gt;&gt;See what I mean?&nbsp;&nbsp;The importers and loaders thus don't have to do direct
<br>&gt;&gt;filesystem operations.<br>&gt;<br>&gt;I think so.&nbsp;&nbsp;Basically you want more of a way to stack imports so that the<br>&gt;basic importers are just passed the string of what it is supposed to load<br>&gt;from.&nbsp;&nbsp;Other importers higher in the chain can handle getting that string.
<br><br>No, they're full importers; they're not passed &quot;a string&quot;.&nbsp;&nbsp;The only<br>difference between this and your original idea of an importer chain is that<br>I'm saying the chained format-specific importers need to know who their
<br>&quot;parent&quot; importer (the data store) is, so they can be data-store<br>independent.&nbsp;&nbsp;Everything else can be done with that, and perhaps a few<br>extra parent importer methods for stat, save, etc.</blockquote><div>
<br>OK. <br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">&gt;&gt;Of course, to fully support .pyc timestamp checking and writeback, you'd
<br>&gt;&gt;need some sort of &quot;stat&quot; or &quot;getmtime&quot; feature on the parent importer, as<br>&gt;&gt;well as perhaps an optional &quot;save_data&quot; method.&nbsp;&nbsp;These would be extensions<br>&gt;&gt;to PEP 302, but welcome ones.
<br>&gt;<br>&gt;Could pass the string representing the location of where the string came<br>&gt;from.&nbsp;&nbsp;That would allow for the required stat calls for .pyc files as<br>&gt;needed without having to implement methods just for this one use case.
<br><br>Huh?&nbsp;&nbsp;In order to know if a .pyc is up to date, you need the st_mtime of<br>the .py file.&nbsp;&nbsp;That can't be done in the parent importer without giving it<br>format knowledge, which goes against the point of the exercise.
</blockquote><div><br>Sorry, thought .pyc files based whether they needed to be recompiled based on the stat info on the .py and .pyc file, not on data stored from within the .pyc .<br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
&nbsp;&nbsp;Thus,<br>something like stat() and save() methods need to be available on the<br>parent, if it can support them.<br><br><br>&gt;&gt;Anyway, based on my previous work with pkg_resource, pkgutil, zipimport,<br>&gt;&gt;import.c
 , etc. I would say this is how I'd want to structure a<br>&gt;&gt;reimplementation of the core system.&nbsp;&nbsp;And if it were for Py3K, I'd probably<br>&gt;&gt;treat sys.path and all the import hooks associated with it as a single
<br>&gt;&gt;meta-importer on sys.meta_path -- listed after a meta-importer for handling<br>&gt;&gt;frozen and built-in modules.&nbsp;&nbsp;(I.e., the meta-importer that uses sys.path<br>&gt;&gt;and its path hooks would be last on sys.meta_path
.)<br>&gt;<br>&gt;Ah, interesting idea!&nbsp;&nbsp;Could even go as far as removing sys.path and just<br>&gt;making it an attribute of the base importer if you really wanted to make<br>&gt;it just meta_path for imports.<br><br>Perhaps, but then that just means you have to have a new variable for
<br>'sys.path_importer' or some such, just to get at it.&nbsp;&nbsp;(i.e., code won't be<br>able to assume it's always the last item in sys.meta_path).&nbsp;&nbsp;So this seems<br>wasteful and changing things just for the sake of change, vs. just keeping
<br>the other PEP 302 sys variables.&nbsp;&nbsp;I just think the *implementation* of them<br>can move to sys.meta_path, as that simplifies the main __import__ function<br>down to just calling meta_path importers in sequence, modulo some package
<br>issues.<br><br>One other rather tricky matter is that the sys.path meta-importer has to<br>deal with package __path__ management...&nbsp;&nbsp;and actually, meta_path importers<br>are supposed to receive a copy of sys.path...&nbsp;&nbsp;ugh.&nbsp;&nbsp;Well, it was a nice
<br>idea, but I guess you can't actually implement sys.path using a meta_path<br>importer.&nbsp;&nbsp;:(&nbsp;&nbsp;For Py3K, we could drop the path argument to find_module()<br>and manage it, but it can't be done and still allow current meta_path hooks
<br>to work right.</blockquote><div><br>Ah, true. <br></div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">&gt;&gt;In other words, sys.meta_path
 is really the only critical import hook from<br>&gt;&gt;the raw interpreter's point of view.&nbsp;&nbsp;sys.path, however, (along with<br>&gt;&gt;sys.path_hooks and sys.path_importer_cache) is critical from the<br>&gt;&gt;perspective of users, applications, etc., as there has to be some way to
<br>&gt;&gt;get things onto Python's path in the first place.<br>&gt;<br>&gt;Yeah, I think I get it.&nbsp;&nbsp;I don't know how much it simplifies things for<br>&gt;users but I think it might make it easier for alternative import writers.
<br><br>That was the idea, yes.&nbsp;&nbsp;:)</blockquote><div><br>&nbsp;</div>=)<div>&nbsp;</div>-Brett <br><br></div><br>