0001"""Kid Import Hooks.
0002
0003When installed, these hooks allow importing .kid files as if they were
0004Python modules.
0005
0006Notes:
0007
0008There's some unpleasant incompatibility between ZODB's import trickery and the
0009import hooks here. Bottom line: if you're using ZODB, import it *before*
0010installing the import hooks.
0011
0012This module is based heavily on code from the Quixote ptl_import module by MEMS
0013Exchange -- thanks guys.
0014"""
0015
0016__revision__ = "$Rev: 252 $"
0017__date__ = "$Date: 2006-01-15 14:55:12 -0500 (Sun, 15 Jan 2006) $"
0018__author__ = "Ryan Tomayko (rtomayko@gmail.com)"
0019__copyright__ = "Copyright 2004-2005, Ryan Tomayko"
0020
0021# Permission is hereby granted, free of charge, to any person obtaining a copy
0022# of this software and associated documentation files (the "Software"), to deal
0023# in the Software without restriction, including without limitation the rights
0024# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0025# copies of the Software, and to permit persons to whom the Software is
0026# furnished to do so, subject to the following conditions:
0027#
0028# The above copyright notice and this permission notice shall be included in
0029# all copies or substantial portions of the Software.
0030#
0031# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0032# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0033# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0034# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0035# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0036# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0037# SOFTWARE.
0038
0039
0040import os
0041import sys
0042import time
0043import imp, ihooks, new
0044import __builtin__
0045
0046import kid.compiler
0047KID_EXT = kid.compiler.KID_EXT
0048
0049assert sys.hexversion >= 0x20000b1, "need Python 2.0b1 or later"
0050
0051_installed = False
0052def install(suffixes=None):
0053    global _installed
0054    if not _installed:
0055        hooks = KIDHooks(suffixes=suffixes)
0056        loader = KIDLoader(hooks)
0057        if cimport is not None:
0058            importer = cModuleImporter(loader)
0059        else:
0060            importer = ihooks.ModuleImporter(loader)
0061        ihooks.install(importer)
0062        _installed = True
0063
0064def uninstall():
0065    global _installed
0066    _installed = False
0067    ihooks.uninstall()
0068
0069def import_template(name, filename, force=0):
0070    if not force and name and sys.modules.has_key(name):
0071        return sys.modules[name]
0072    template = kid.compiler.KidFile(filename)
0073    code = template.compile(dump_source=os.environ.get('KID_OUTPUT_PY'))
0074    module = _create_module(code, name, filename)
0075    return module
0076
0077def get_template_name(name, filename):
0078    if name:
0079        return name
0080    else:
0081        return 'kid.util.template_' + hex(hash(filename) + 0x80000000)
0082
0083def _create_module(code, name, filename, store=1):
0084    name = get_template_name(name, filename)
0085    mod = new.module(name)
0086    mod.__file__ = filename
0087    mod.__ctime__ = time.time()
0088    exec code in mod.__dict__
0089    if store:
0090        sys.modules[name] = mod
0091    return mod
0092
0093# this is put in a pyc file to signal that it is a kid file
0094KID_FILE = object()
0095
0096class KIDHooks(ihooks.Hooks):
0097
0098    def __init__(self, verbose=ihooks.VERBOSE, suffixes=None):
0099        ihooks.Hooks.__init__(self, verbose)
0100        self.suffixes = suffixes or []
0101
0102    def get_suffixes(self):
0103        return [(KID_EXT, 'r', KID_FILE)]                   + [(suffix, 'r', KID_FILE) for suffix in self.suffixes]                   + imp.get_suffixes()
0106
0107class KIDLoader(ihooks.ModuleLoader):
0108
0109    def load_module(self, name, stuff):
0110        file, filename, info = stuff
0111        (suff, mode, type) = info
0112        if type is KID_FILE:
0113            return import_template(name, filename, force=1)
0114        else:
0115            return ihooks.ModuleLoader.load_module(self, name, stuff)
0116
0117try:
0118    import cimport
0119except ImportError:
0120    cimport = None
0121
0122class cModuleImporter(ihooks.ModuleImporter):
0123    def __init__(self, loader=None):
0124        self.loader = loader or ihooks.ModuleLoader()
0125        cimport.set_loader(self.find_import_module)
0126
0127    def find_import_module(self, fullname, subname, path):
0128        stuff = self.loader.find_module(subname, path)
0129        if not stuff:
0130            return None
0131        return self.loader.load_module(fullname, stuff)
0132
0133    def install(self):
0134        self.save_import_module = __builtin__.__import__
0135        self.save_reload = __builtin__.reload
0136        if not hasattr(__builtin__, 'unload'):
0137            __builtin__.unload = None
0138        self.save_unload = __builtin__.unload
0139        __builtin__.__import__ = cimport.import_module
0140        __builtin__.reload = cimport.reload_module
0141        __builtin__.unload = self.unload