On Mar 10, 9:33 pm, a...@pythoncraft.com (Aahz) wrote: > In article > <60848752-2c3f-4512-bf61-0bc11c919...@i20g2000prf.googlegroups.com>, > Carl Banks <pavlovevide...@gmail.com> wrote: > > > > >The problem comes when a different part of the upstream package also > >subclasses or creates a Box. When an upstream function creates a box, > >it creates an upstream.packaging.Box instead of a > >mine.custom_packaging.Box, but I'd want it to do the latter. > > The only clean way I'm aware of is to pass in an instance and use > instance.__class__ to create new instances. Did you come up with > another idea?
Ok, so after lots of false starts and muttering, and much mindbending to get my head around the import dynamics, I came up with this simple (not straightforward) recipe, which does not require an import hook, but has one major drawback (that I can live with). I defined this function: def adapt(base_full_mod_name): mp = base_full_mod_name.split('.') if len(mp) < 2: raise ValueError('can only adapt packaged modules') adapt_full_mod_name = '.'.join(["custom"] + mp[1:]) keepref_full_mod_name = '.'.join(["_upstream"] + mp[1:]) adapt_mod_name = mp[-1] parent_full_mod_name = '.'.join(mp[:-1]) try: mod = __import__(adapt_full_mod_name,globals(),locals(), ('*',)) except ImportError: pass else: sys.modules[keepref_full_mod_name] = sys.modules [base_full_mod_name] sys.modules[base_full_mod_name] = mod setattr(sys.modules[parent_full_mod_name],adapt_mod_name,mod) Most of the modules in package "upstream" have a little bit of boilerplate at the very end that looks something like this: from . import adaptation adaptation.adapt(__name__) Believe it or not, this causes whoever imports the module to actually receive a different module. It exploits the fact that the semantics of __import__ are, for the lack of a better word, retarded. If you write "from upstream import staging", staging would end up bound to the module custom.stating (if custom.staging exists). This allows you to subclass upsteam.staging.Box naturally, and anyone who tries to use upstream.staging.Box will actually be using custom.staging.Box. (Actually not quite true, a user in the same module would still be using Box, but that's easily work-around-able.) The major drawback is that "from upstream.staging import Box" will fail. It will import upstream.staging.Box, not custom.stating.Box" if it's the first time upstream.stating is imported. I can live with it since I expect the modules to be carefully imported in order before anyone uses their contents. A minor drawback is it only works for modules in a package, no biggie. It probably crashes and burns in circular import situations, and there's almost certainly some other pitfalls. It's probably too magical for most people, but as I said I can tolerate a lot of magic. I think it's ok because all adaptible modules have boilerplate at the end cluing a user that some other behavior might be tacked onto this module. That was the key sticking point for me, I could have used an import hook, but I REALLY didn't want a user to see "import upstream.staging" and not have any clue why they were importing custom.staging. Carl Banks -- http://mail.python.org/mailman/listinfo/python-list