summaryrefslogtreecommitdiff
path: root/pypers/europython05/Quixote-2.0/ptl/ptl_import.py
blob: d6ac2a0544032a95f296b8e52f452fef208c07eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
"""
$URL: svn+ssh://svn.mems-exchange.org/repos/trunk/quixote/ptl/ptl_import.py $
$Id: ptl_import.py 26357 2005-03-16 14:56:23Z dbinger $

Import hooks; when installed, these hooks allow importing .ptl files
as if they were Python modules.

Note: there's some unpleasant incompatibility between ZODB's import
trickery and the import hooks here.  Bottom line: if you're using ZODB,
import it *before* installing the PTL import hooks.
"""

import sys
import os.path
import imp, ihooks, new
import struct
import marshal
import __builtin__

from ptl_compile import compile_template, PTL_EXT

assert sys.hexversion >= 0x20000b1, "need Python 2.0b1 or later"

def _exec_module_code(code, name, filename):
    if sys.modules.has_key(name):
        mod = sys.modules[name] # necessary for reload()
    else:
        mod = new.module(name)
        sys.modules[name] = mod
    mod.__name__ = name
    mod.__file__ = filename
    exec code in mod.__dict__
    return mod

def _timestamp(filename):
    try:
        s = os.stat(filename)
    except OSError:
        return None
    return s.st_mtime

def _load_pyc(name, filename, pyc_filename):
    try:
        fp = open(pyc_filename, "rb")
    except IOError:
        return None
    if fp.read(4) == imp.get_magic():
        mtime = struct.unpack('<I', fp.read(4))[0]
        ptl_mtime = _timestamp(filename)
        if ptl_mtime is not None and mtime >= ptl_mtime:
            code = marshal.load(fp)
            return _exec_module_code(code, name, filename)
    return None

def _load_ptl(name, filename, file=None):
    if not file:
        try:
            file = open(filename, "rb")
        except IOError:
            return None
    path, ext = os.path.splitext(filename)
    pyc_filename = path + ".pyc"
    module = _load_pyc(name, filename, pyc_filename)
    if module is not None:
        return module
    try:
        output = open(pyc_filename, "wb")
    except IOError:
        output = None
    try:
        code = compile_template(file, filename, output)
    except:
        if output:
            output.close()
            os.unlink(pyc_filename)
        raise
    else:
        if output:
            output.close()
    return _exec_module_code(code, name, filename)


# Constant used to signal a PTL files
PTL_FILE = object()

class PTLHooks(ihooks.Hooks):

    def get_suffixes(self):
        # add our suffixes
        return [(PTL_EXT, 'r', PTL_FILE)] + imp.get_suffixes()

class PTLLoader(ihooks.ModuleLoader):

    def load_module(self, name, stuff):
        file, filename, info = stuff
        (suff, mode, type) = info

        # If it's a PTL file, load it specially.
        if type is PTL_FILE:
            return _load_ptl(name, filename, file)

        else:
            # Otherwise, use the default handler for loading
            return ihooks.ModuleLoader.load_module(self, name, stuff)

try:
    import cimport
except ImportError:
    cimport = None

class cModuleImporter(ihooks.ModuleImporter):
    def __init__(self, loader=None):
        self.loader = loader or ihooks.ModuleLoader()
        cimport.set_loader(self.find_import_module)

    def find_import_module(self, fullname, subname, path):
        stuff = self.loader.find_module(subname, path)
        if not stuff:
            return None
        return self.loader.load_module(fullname, stuff)

    def install(self):
        self.save_import_module = __builtin__.__import__
        self.save_reload = __builtin__.reload
        if not hasattr(__builtin__, 'unload'):
            __builtin__.unload = None
        self.save_unload = __builtin__.unload
        __builtin__.__import__ = cimport.import_module
        __builtin__.reload = cimport.reload_module
        __builtin__.unload = self.unload

_installed = False

def install():
    global _installed
    if not _installed:
        hooks = PTLHooks()
        loader = PTLLoader(hooks)
        if cimport is not None:
            importer = cModuleImporter(loader)
        else:
            importer = ihooks.ModuleImporter(loader)
        ihooks.install(importer)
        _installed = True


if __name__ == '__main__':
    install()