
"Brett Cannon" brett@python.org wrote:
On 2/11/07, Josiah Carlson jcarlson@uci.edu wrote:
Josiah Carlson jcarlson@uci.edu wrote:
Anyways...I hear where you are coming from with your statements of 'if __name__ could be anything, and we could train people to use ismain(), then all of this relative import stuff could *just work*'. It would require inserting a bunch of (fake?) packages in valid Python name parent paths (just in case people want to do cousin, etc., imports from __main__).
You have convinced me.
And in that vein, I have implemented a bit of code that mangles the __name__ of the __main__ module, sets up pseudo-packages for parent paths with valid Python names, imports __init__.py modules in ancestor packages, adds an ismain() function to builtins, etc.
It allows for crazy things like...
from ..uncle import cousin from ..parent import sibling #the above equivalent to: from . import sibling from .sibling import nephew
...all executed within the __main__ module (which gets a new __name__). Even better, it works with vanilla Python 2.5, and doesn't even require an import hook.
The only unfortunate thing is that because you cannot predict how far up the tree relative imports go, you cannot know how far up the paths one should go in creating the ancestral packages. My current (simple) implementation goes as far up as the root, or the parent of the deepest path with an __init__.py[cw] .
Just to make sure that I understand this correctly, __name__ is set to __main__ for the module that is being executed. Then other modules in the package are also called __main__, but with the proper dots and such to resolve to the proper depth in the package?
No. Say, for example, that you had a tree like the following.
.../ pk1/ pk2/ __init__.py pk3/ __init__.py run.py
Also say that run.py was run from the command line, and the relative import code that I have written gets executed. The following assumes that at least a "dummy" module is inserted into sys.modules['__main__']
1) A fake package called 'pk1' with __path__ == ['../pk1'] is inserted into sys.modules. 2) 'pk1.pk2' is imported as per package rules (__init__.py is executed), and gets a __path__ == ['../pk1/pk2/'] . 3) 'pk1.pk2.pk3' is imported as per package rules (__init__.py is executed), and gets a __path__ == ['../pk1/pk2/pk3'] . 4) We fetch sys.packages['__main__'], give it a new __name__ of 'pk1.pk2.pk3.__main__', but don't give it a path. Also insert the module into sys.modules['pk1.pk2.pk3.__main__']. 5) Add ismain() to builtins. 6) The remainder of run.py is executed.
If you are curious, I can send you a copy off-list.
I have way too much on my plate right now to dive into it right now, but I assume the patch is either against runpy or my import code?
No. It's actually a standalone module. When imported (presumably from __main__ as the first thing it does), it performs the mangling, importing, etc. I'm sure I could modify runpy to do all of this, but only if alter_sys was True.
I could probably do the same with your import code, where can I find it?
One reason *not* to do the __main__..uncle.cousin namings is that it is not clear how one should go about removing those __main__ trailing dots without examining __main__'s __file__ all the time, especially with non-filesystem imports with nonsensical __file__.
- Josiah