0001"""Kid Import Hooks.
0002
0003When installed, these hooks allow importing .kid files as if they were
0004Python modules.
0005
0006"""
0007
0008__revision__ = "$Rev: 317 $"
0009__date__ = "$Date: 2006-04-21 08:51:24 +0000 (Fri, 21 Apr 2006) $"
0010__author__ = "Ryan Tomayko (rtomayko@gmail.com)"
0011__copyright__ = "Copyright 2004-2005, Ryan Tomayko"
0012__license__ = "MIT <http://www.opensource.org/licenses/mit-license.php>"
0013
0014import os, sys, time, new
0015import __builtin__
0016
0017import kid.compiler
0018KID_EXT = kid.compiler.KID_EXT
0019
0020assert sys.hexversion >= 0x20000b1, "need Python 2.0b1 or later"
0021
0022_installed = False
0023
0024def install(suffixes=None):
0025    global _installed
0026    if not _installed:
0027        _install_hook(suffixes=suffixes)
0028        _installed = True
0029
0030def uninstall():
0031    global _installed
0032    if _installed:
0033        _uninstall_hook()
0034        _installed = False
0035
0036def import_template(name, filename, force=0):
0037    if not force and name and sys.modules.has_key(name):
0038        return sys.modules[name]
0039    template = kid.compiler.KidFile(filename)
0040    code = template.compile(dump_source=os.environ.get('KID_OUTPUT_PY'))
0041    module = _create_module(code, name, filename)
0042    return module
0043
0044def get_template_name(name, filename):
0045    if name:
0046        return name
0047    else:
0048        return 'kid.util.template_%x' % (hash(filename) + sys.maxint + 1)
0049
0050def _create_module(code, name, filename, store=1, ns={}):
0051    name = get_template_name(name, filename)
0052    mod = new.module(name)
0053    mod.__file__ = filename
0054    mod.__ctime__ = time.time()
0055    mod.__dict__.update(ns)
0056    exec code in mod.__dict__
0057    if store:
0058        sys.modules[name] = mod
0059    return mod
0060
0061# this is put in a pyc file to signal that it is a kid file
0062KID_FILE = object()
0063
0064try: # if possible, use new (PEP 302) import hooks
0065    from sys import path_hooks, path_importer_cache
0066except ImportError:
0067    path_hooks = None
0068
0069if path_hooks is not None:
0070
0071    class KIDLoader(object):
0072
0073        def __init__(self, path=None):
0074            if path and os.path.isdir(path):
0075                self.path = path
0076            else:
0077                raise ImportError
0078
0079        def find_module(self, fullname):
0080            path = os.path.join(self.path, fullname.split('.')[-1])
0081            for ext in [KID_EXT] + self.suffixes:
0082                if os.path.exists(path + ext):
0083                    self.filename = path + ext
0084                    return self
0085            return None
0086
0087        def load_module(self, fullname):
0088            return import_template(fullname, self.filename, force=1)
0089
0090    def _install_hook(suffixes=None):
0091        KIDLoader.suffixes = suffixes or []
0092        path_hooks.append(KIDLoader)
0093        sys.path_importer_cache.clear()
0094
0095    def _uninstall_hook():
0096        i = 0
0097        while i < len(path_hooks):
0098            if path_hooks[i] is KIDLoader:
0099                del path_hooks[i]
0100            else:
0101                i += 1
0102        sys.path_importer_cache.clear()
0103
0104else: # Python < 2.3, fall back to using the old ihooks module
0105
0106    import ihooks, imp
0107
0108    class KIDHooks(ihooks.Hooks):
0109
0110        def __init__(self, verbose=ihooks.VERBOSE, suffixes=None):
0111            ihooks.Hooks.__init__(self, verbose)
0112            self.suffixes = suffixes or []
0113
0114        def get_suffixes(self):
0115            return [(suffix, 'r', KID_FILE)
0116                for suffix in [KID_EXT] + self.suffixes] + imp.get_suffixes()
0117
0118    class KIDLoader(ihooks.ModuleLoader):
0119
0120        def load_module(self, name, stuff):
0121            file, filename, info = stuff
0122            (suff, mode, type) = info
0123            if type is KID_FILE:
0124                return import_template(name, filename, force=1)
0125            else:
0126                return ihooks.ModuleLoader.load_module(self, name, stuff)
0127
0128    def _install_hook(suffixes=None):
0129        hooks = KIDHooks(suffixes=suffixes)
0130        loader = KIDLoader(hooks)
0131        importer = ihooks.ModuleImporter(loader)
0132        ihooks.install(importer)
0133
0134    def _uninstall_hook():
0135        ihooks.uninstall()