~ubuntu-branches/ubuntu/karmic/pypy/karmic

« back to all changes in this revision

Viewing changes to pypy/interpreter/mixedmodule.py

  • Committer: Bazaar Package Importer
  • Author(s): Alexandre Fayolle
  • Date: 2007-04-13 09:33:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070413093309-yoojh4jcoocu2krz
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
from pypy.interpreter.module import Module
 
2
from pypy.interpreter.function import Function, BuiltinFunction
 
3
from pypy.interpreter import gateway 
 
4
from pypy.interpreter.error import OperationError 
 
5
from pypy.interpreter.baseobjspace import W_Root
 
6
import os, sys
 
7
 
 
8
import inspect
 
9
 
 
10
class MixedModule(Module):
 
11
 
 
12
    NOT_RPYTHON_ATTRIBUTES = ['loaders']
 
13
 
 
14
    applevel_name = None
 
15
    expose__file__attribute = True
 
16
    
 
17
    def __init__(self, space, w_name): 
 
18
        """ NOT_RPYTHON """ 
 
19
        Module.__init__(self, space, w_name) 
 
20
        self.lazy = True 
 
21
        self.__class__.buildloaders()
 
22
 
 
23
    def get_applevel_name(cls):
 
24
        """ NOT_RPYTHON """
 
25
        if cls.applevel_name is not None:
 
26
            return cls.applevel_name
 
27
        else:
 
28
            pkgroot = cls.__module__
 
29
            return pkgroot.split('.')[-1]
 
30
    get_applevel_name = classmethod(get_applevel_name)
 
31
 
 
32
    def get(self, name):
 
33
        space = self.space
 
34
        w_value = self.getdictvalue_w(space, name) 
 
35
        if w_value is None: 
 
36
            raise OperationError(space.w_AttributeError, space.wrap(name))
 
37
        return w_value 
 
38
 
 
39
    def call(self, name, *args_w): 
 
40
        w_builtin = self.get(name) 
 
41
        return self.space.call_function(w_builtin, *args_w)
 
42
 
 
43
    def getdictvalue(self, space, w_name):
 
44
        w_value = space.finditem(self.w_dict, w_name)
 
45
        if self.lazy and w_value is None:
 
46
            name = space.str_w(w_name)
 
47
            w_name = space.new_interned_w_str(w_name)
 
48
            try: 
 
49
                loader = self.loaders[name]
 
50
            except KeyError: 
 
51
                return None 
 
52
            else: 
 
53
                #print "trying to load", name
 
54
                w_value = loader(space) 
 
55
                #print "loaded", w_value 
 
56
                # obscure
 
57
                func = space.interpclass_w(w_value)
 
58
                if type(func) is Function:
 
59
                    try:
 
60
                        bltin = func._builtinversion_
 
61
                    except AttributeError:
 
62
                        bltin = BuiltinFunction(func)
 
63
                        bltin.w_module = self.w_name
 
64
                        func._builtinversion_ = bltin
 
65
                        bltin.name = name
 
66
                    w_value = space.wrap(bltin)
 
67
                space.setitem(self.w_dict, w_name, w_value) 
 
68
        return w_value
 
69
 
 
70
    def getdict(self): 
 
71
        if self.lazy: 
 
72
            space = self.space
 
73
            for name in self.loaders: 
 
74
                w_value = self.get(name)  
 
75
                space.setitem(self.w_dict, space.new_interned_str(name), w_value) 
 
76
            self.lazy = False 
 
77
        return self.w_dict 
 
78
 
 
79
    def _freeze_(self):
 
80
        self.getdict()
 
81
        # hint for the annotator: Modules can hold state, so they are
 
82
        # not constant
 
83
        return False
 
84
 
 
85
    def buildloaders(cls): 
 
86
        """ NOT_RPYTHON """ 
 
87
        if not hasattr(cls, 'loaders'): 
 
88
            # build a constant dictionary out of
 
89
            # applevel/interplevel definitions 
 
90
            cls.loaders = loaders = {}
 
91
            pkgroot = cls.__module__
 
92
            appname = cls.get_applevel_name()
 
93
            for name, spec in cls.interpleveldefs.items(): 
 
94
                loaders[name] = getinterpevalloader(pkgroot, spec) 
 
95
            for name, spec in cls.appleveldefs.items(): 
 
96
                loaders[name] = getappfileloader(pkgroot, appname, spec)
 
97
            assert '__file__' not in loaders 
 
98
            if cls.expose__file__attribute:
 
99
                loaders['__file__'] = cls.get__file__
 
100
            if '__doc__' not in loaders:
 
101
                loaders['__doc__'] = cls.get__doc__
 
102
 
 
103
    buildloaders = classmethod(buildloaders)
 
104
 
 
105
    def extra_interpdef(self, name, spec):
 
106
        cls = self.__class__
 
107
        pkgroot = cls.__module__
 
108
        loader = getinterpevalloader(pkgroot, spec)
 
109
        space = self.space
 
110
        w_obj = loader(space)
 
111
        space.setattr(space.wrap(self), space.wrap(name), w_obj)
 
112
 
 
113
    def get__file__(cls, space): 
 
114
        """ NOT_RPYTHON. 
 
115
        return the __file__ attribute of a MixedModule 
 
116
        which is the root-directory for the various 
 
117
        applevel and interplevel snippets that make
 
118
        up the module. 
 
119
        """ 
 
120
        try: 
 
121
            fname = cls._fname 
 
122
        except AttributeError: 
 
123
            pkgroot = cls.__module__
 
124
            mod = __import__(pkgroot, None, None, ['__doc__'])
 
125
            fname = mod.__file__ 
 
126
            assert os.path.basename(fname).startswith('__init__.py')
 
127
            # make it clear that it's not really the interp-level module
 
128
            # at this path that we are seeing, but an app-level version of it
 
129
            fname = os.path.join(os.path.dirname(fname), '*.py')
 
130
            cls._fname = fname 
 
131
        return space.wrap(fname) 
 
132
 
 
133
    get__file__ = classmethod(get__file__) 
 
134
 
 
135
    def get__doc__(cls, space):
 
136
        return space.wrap(cls.__doc__)
 
137
    get__doc__ = classmethod(get__doc__)
 
138
 
 
139
 
 
140
def getinterpevalloader(pkgroot, spec):
 
141
    """ NOT_RPYTHON """     
 
142
    def ifileloader(space): 
 
143
        d = {'space' : space}
 
144
        # EVIL HACK (but it works, and this is not RPython :-) 
 
145
        while 1: 
 
146
            try: 
 
147
                value = eval(spec, d) 
 
148
            except NameError, ex: 
 
149
                name = ex.args[0].split("'")[1] # super-Evil 
 
150
                if name in d:
 
151
                    raise   # propagate the NameError
 
152
                try: 
 
153
                    d[name] = __import__(pkgroot+'.'+name, None, None, [name])
 
154
                except ImportError:
 
155
                    etype, evalue, etb = sys.exc_info()
 
156
                    try:
 
157
                        d[name] = __import__(name, None, None, [name])
 
158
                    except ImportError:
 
159
                        # didn't help, re-raise the original exception for
 
160
                        # clarity
 
161
                        raise etype, evalue, etb
 
162
            else: 
 
163
                #print spec, "->", value
 
164
                if hasattr(value, 'func_code'):  # semi-evil 
 
165
                    return space.wrap(gateway.interp2app(value))
 
166
 
 
167
                try:
 
168
                    is_type = issubclass(value, W_Root)  # pseudo-evil
 
169
                except TypeError:
 
170
                    is_type = False
 
171
                if is_type:
 
172
                    return space.gettypefor(value)
 
173
 
 
174
                W_Object = getattr(space, 'W_Object', ()) # for cpyobjspace
 
175
                assert isinstance(value, (W_Root, W_Object)), (
 
176
                    "interpleveldef %s.%s must return a wrapped object "
 
177
                    "(got %r instead)" % (pkgroot, spec, value))
 
178
                return value 
 
179
    return ifileloader 
 
180
        
 
181
applevelcache = {}
 
182
def getappfileloader(pkgroot, appname, spec):
 
183
    """ NOT_RPYTHON """ 
 
184
    # hum, it's a bit more involved, because we usually 
 
185
    # want the import at applevel
 
186
    modname, attrname = spec.split('.')
 
187
    impbase = pkgroot + '.' + modname
 
188
    try:
 
189
        app = applevelcache[impbase]
 
190
    except KeyError:
 
191
        import imp
 
192
        pkg = __import__(pkgroot, None, None, ['__doc__'])
 
193
        file, fn, (suffix, mode, typ) = imp.find_module(modname, pkg.__path__)
 
194
        assert typ == imp.PY_SOURCE
 
195
        source = file.read()
 
196
        file.close()
 
197
        if fn.endswith('.pyc') or fn.endswith('.pyo'):
 
198
            fn = fn[:-1]
 
199
        app = gateway.applevel(source, filename=fn, modname=appname)
 
200
        applevelcache[impbase] = app
 
201
 
 
202
    def afileloader(space): 
 
203
        return app.wget(space, attrname)
 
204
    return afileloader 
 
205
 
 
206
# ____________________________________________________________
 
207
# Helper to test mixed modules on top of CPython
 
208
 
 
209
def testmodule(name, basepath='pypy.module'):
 
210
    """Helper to test mixed modules on top of CPython,
 
211
    running with the CPy Object Space.  The module should behave
 
212
    more or less as if it had been compiled, either with the
 
213
    pypy/bin/compilemodule.py tool, or within pypy-c.
 
214
 
 
215
    Try:   testmodule('_demo')
 
216
    """
 
217
    import sys, new
 
218
    from pypy.objspace.cpy.objspace import CPyObjSpace
 
219
    space = CPyObjSpace()
 
220
    
 
221
    fullname = "%s.%s" % (basepath, name) 
 
222
    Module = __import__(fullname, 
 
223
                        None, None, ["Module"]).Module
 
224
    appname = Module.get_applevel_name()
 
225
    mod = Module(space, space.wrap(appname))
 
226
    res = new.module(appname)
 
227
    sys.modules[appname] = res
 
228
    moddict = space.unwrap(mod.getdict())
 
229
    res.__dict__.update(moddict)
 
230
    return res
 
231
 
 
232
def compilemodule(name, interactive=False):
 
233
    "Compile a PyPy module for CPython."
 
234
    from pypy.rpython.rctypes.tool.compilemodule import compilemodule
 
235
    return compilemodule(name, interactive=interactive)