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
10
class MixedModule(Module):
12
NOT_RPYTHON_ATTRIBUTES = ['loaders']
15
expose__file__attribute = True
17
def __init__(self, space, w_name):
19
Module.__init__(self, space, w_name)
21
self.__class__.buildloaders()
23
def get_applevel_name(cls):
25
if cls.applevel_name is not None:
26
return cls.applevel_name
28
pkgroot = cls.__module__
29
return pkgroot.split('.')[-1]
30
get_applevel_name = classmethod(get_applevel_name)
34
w_value = self.getdictvalue_w(space, name)
36
raise OperationError(space.w_AttributeError, space.wrap(name))
39
def call(self, name, *args_w):
40
w_builtin = self.get(name)
41
return self.space.call_function(w_builtin, *args_w)
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)
49
loader = self.loaders[name]
53
#print "trying to load", name
54
w_value = loader(space)
55
#print "loaded", w_value
57
func = space.interpclass_w(w_value)
58
if type(func) is Function:
60
bltin = func._builtinversion_
61
except AttributeError:
62
bltin = BuiltinFunction(func)
63
bltin.w_module = self.w_name
64
func._builtinversion_ = bltin
66
w_value = space.wrap(bltin)
67
space.setitem(self.w_dict, w_name, w_value)
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)
81
# hint for the annotator: Modules can hold state, so they are
85
def buildloaders(cls):
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__
103
buildloaders = classmethod(buildloaders)
105
def extra_interpdef(self, name, spec):
107
pkgroot = cls.__module__
108
loader = getinterpevalloader(pkgroot, spec)
110
w_obj = loader(space)
111
space.setattr(space.wrap(self), space.wrap(name), w_obj)
113
def get__file__(cls, space):
115
return the __file__ attribute of a MixedModule
116
which is the root-directory for the various
117
applevel and interplevel snippets that make
122
except AttributeError:
123
pkgroot = cls.__module__
124
mod = __import__(pkgroot, None, None, ['__doc__'])
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')
131
return space.wrap(fname)
133
get__file__ = classmethod(get__file__)
135
def get__doc__(cls, space):
136
return space.wrap(cls.__doc__)
137
get__doc__ = classmethod(get__doc__)
140
def getinterpevalloader(pkgroot, spec):
142
def ifileloader(space):
143
d = {'space' : space}
144
# EVIL HACK (but it works, and this is not RPython :-)
147
value = eval(spec, d)
148
except NameError, ex:
149
name = ex.args[0].split("'")[1] # super-Evil
151
raise # propagate the NameError
153
d[name] = __import__(pkgroot+'.'+name, None, None, [name])
155
etype, evalue, etb = sys.exc_info()
157
d[name] = __import__(name, None, None, [name])
159
# didn't help, re-raise the original exception for
161
raise etype, evalue, etb
163
#print spec, "->", value
164
if hasattr(value, 'func_code'): # semi-evil
165
return space.wrap(gateway.interp2app(value))
168
is_type = issubclass(value, W_Root) # pseudo-evil
172
return space.gettypefor(value)
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))
182
def getappfileloader(pkgroot, appname, spec):
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
189
app = applevelcache[impbase]
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
197
if fn.endswith('.pyc') or fn.endswith('.pyo'):
199
app = gateway.applevel(source, filename=fn, modname=appname)
200
applevelcache[impbase] = app
202
def afileloader(space):
203
return app.wget(space, attrname)
206
# ____________________________________________________________
207
# Helper to test mixed modules on top of CPython
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.
215
Try: testmodule('_demo')
218
from pypy.objspace.cpy.objspace import CPyObjSpace
219
space = CPyObjSpace()
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)
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)