1
from pypy.objspace.std.objspace import *
2
from pypy.interpreter.function import Function, StaticMethod
3
from pypy.interpreter.argument import Arguments
4
from pypy.interpreter import gateway
5
from pypy.interpreter.typedef import weakref_descr
6
from pypy.objspace.std.stdtypedef import std_dict_descr, issubtypedef, Member
7
from pypy.objspace.std.objecttype import object_typedef
8
from pypy.objspace.std.dictproxyobject import W_DictProxyObject
9
from pypy.rlib.objectmodel import we_are_translated, hint
10
from pypy.rlib.rarithmetic import intmask, r_uint
12
from copy_reg import _HEAPTYPE
14
# from compiler/misc.py
16
MANGLE_LEN = 256 # magic constant from compile.c
18
def _mangle(name, klass):
19
if not name.startswith('__'):
21
if len(name) + 2 >= MANGLE_LEN:
23
if name.endswith('__'):
27
while klass[i] == '_':
33
tlen = len(klass) + len(name)
35
end = len(klass) + MANGLE_LEN-tlen
37
klass = '' # annotator hint
41
return "_%s%s" % (klass, name)
43
class VersionTag(object):
46
class W_TypeObject(W_Object):
47
from pypy.objspace.std.typetype import type_typedef as typedef
49
lazyloaders = {} # can be overridden by specific instances
51
def __init__(w_self, space, name, bases_w, dict_w,
52
overridetypedef=None):
55
w_self.bases_w = bases_w
56
w_self.dict_w = dict_w
57
w_self.ensure_static__new__()
59
w_self.needsdel = False
60
w_self.w_bestbase = None
61
w_self.weak_subclasses_w = []
63
# make sure there is a __doc__ in dict_w
64
if '__doc__' not in dict_w:
65
dict_w['__doc__'] = space.w_None
67
if overridetypedef is not None:
68
w_self.instancetypedef = overridetypedef
69
w_self.hasdict = overridetypedef.hasdict
70
w_self.weakrefable = overridetypedef.weakrefable
71
w_self.__flags__ = 0 # not a heaptype
72
if overridetypedef.base is not None:
73
w_self.w_bestbase = space.gettypeobject(overridetypedef.base)
75
w_self.__flags__ = _HEAPTYPE
76
# initialize __module__ in the dict
77
if '__module__' not in dict_w:
79
caller = space.getexecutioncontext().framestack.top()
81
w_globals = w_locals = space.newdict()
83
w_globals = caller.w_globals
84
w_str_name = space.wrap('__name__')
85
w_name = space.finditem(w_globals, w_str_name)
86
if w_name is not None:
87
dict_w['__module__'] = w_name
88
# find the most specific typedef
89
instancetypedef = object_typedef
90
for w_base in bases_w:
91
if not isinstance(w_base, W_TypeObject):
93
if issubtypedef(w_base.instancetypedef, instancetypedef):
94
if instancetypedef is not w_base.instancetypedef:
95
instancetypedef = w_base.instancetypedef
96
w_self.w_bestbase = w_base
97
elif not issubtypedef(instancetypedef, w_base.instancetypedef):
98
raise OperationError(space.w_TypeError,
99
space.wrap("instance layout conflicts in "
100
"multiple inheritance"))
101
if not instancetypedef.acceptable_as_base_class:
102
raise OperationError(space.w_TypeError,
103
space.wrap("type '%s' is not an "
104
"acceptable base class" %
105
instancetypedef.name))
106
w_self.instancetypedef = instancetypedef
107
w_self.hasdict = False
108
w_self.weakrefable = False
109
hasoldstylebase = False
110
w_most_derived_base_with_slots = None
112
for w_base in bases_w:
113
if not isinstance(w_base, W_TypeObject):
114
hasoldstylebase = True
118
if w_base.nslots != 0:
119
if w_most_derived_base_with_slots is None:
120
w_most_derived_base_with_slots = w_base
122
if space.is_true(space.issubtype(w_base, w_most_derived_base_with_slots)):
123
w_most_derived_base_with_slots = w_base
124
elif not space.is_true(space.issubtype(w_most_derived_base_with_slots, w_base)):
125
raise OperationError(space.w_TypeError,
126
space.wrap("instance layout conflicts in "
127
"multiple inheritance"))
128
w_self.hasdict = w_self.hasdict or w_base.hasdict
129
w_self.needsdel = w_self.needsdel or w_base.needsdel
130
w_self.weakrefable = w_self.weakrefable or w_base.weakrefable
131
if not w_newstyle: # only classic bases
132
raise OperationError(space.w_TypeError,
133
space.wrap("a new-style class can't have only classic bases"))
135
if w_most_derived_base_with_slots:
136
nslots = w_most_derived_base_with_slots.nslots
137
w_self.w_bestbase = w_most_derived_base_with_slots
141
if w_self.w_bestbase is None:
142
w_self.w_bestbase = w_newstyle
146
if '__slots__' in dict_w:
150
w_slots = dict_w['__slots__']
151
if space.is_true(space.isinstance(w_slots, space.w_str)):
152
if space.int_w(space.len(w_slots)) == 0:
153
raise OperationError(space.w_TypeError,
154
space.wrap('__slots__ must be identifiers'))
155
slot_names_w = [w_slots]
157
slot_names_w = space.unpackiterable(w_slots)
158
for w_slot_name in slot_names_w:
159
slot_name = space.str_w(w_slot_name)
160
# slot_name should be a valid identifier
161
if len(slot_name) == 0:
162
raise OperationError(space.w_TypeError,
163
space.wrap('__slots__ must be identifiers'))
164
first_char = slot_name[0]
165
if not first_char.isalpha() and first_char != '_':
166
raise OperationError(space.w_TypeError,
167
space.wrap('__slots__ must be identifiers'))
169
if not c.isalnum() and c!= '_':
170
raise OperationError(space.w_TypeError,
171
space.wrap('__slots__ must be identifiers'))
172
if slot_name == '__dict__':
173
if wantdict or w_self.hasdict:
174
raise OperationError(space.w_TypeError,
175
space.wrap("__dict__ slot disallowed: we already got one"))
177
elif slot_name == '__weakref__':
178
if wantweakref or w_self.weakrefable:
179
raise OperationError(space.w_TypeError,
180
space.wrap("__weakref__ slot disallowed: we already got one"))
185
slot_name = _mangle(slot_name, name)
186
# Force interning of slot names.
187
slot_name = space.str_w(space.new_interned_str(slot_name))
188
w_self.dict_w[slot_name] = space.wrap(Member(nslots, slot_name, w_self))
191
w_self.nslots = nslots
193
wantdict = wantdict or hasoldstylebase
195
if wantdict and not w_self.hasdict:
196
w_self.dict_w['__dict__'] = space.wrap(std_dict_descr)
197
w_self.hasdict = True
198
if '__del__' in dict_w:
199
w_self.needsdel = True
200
if wantweakref and not w_self.weakrefable:
201
w_self.dict_w['__weakref__'] = space.wrap(weakref_descr)
202
w_self.weakrefable = True
203
w_type = space.type(w_self)
204
if not space.is_w(w_type, space.w_type):
205
if space.config.objspace.std.withtypeversion:
206
w_self.version_tag = None
208
mro_func = space.lookup(w_self, 'mro')
209
mro_func_args = Arguments(space, [w_self])
210
w_mro = space.call_args(mro_func, mro_func_args)
211
w_self.mro_w = space.unpackiterable(w_mro)
213
w_self.mro_w = w_self.compute_mro()
214
if space.config.objspace.std.withtypeversion:
215
if w_self.instancetypedef.hasdict:
216
w_self.version_tag = None
218
w_self.version_tag = VersionTag()
222
assert space.config.objspace.std.withtypeversion
223
if w_self.version_tag is not None:
224
w_self.version_tag = VersionTag()
225
subclasses_w = w_self.get_subclasses()
226
for w_subclass in subclasses_w:
227
assert isinstance(w_subclass, W_TypeObject)
231
for w_base in w_self.bases_w:
232
if not isinstance(w_base, W_TypeObject):
234
w_base.add_subclass(w_self)
236
# compute the most parent class with the same layout as us
237
def get_layout(w_self):
238
w_bestbase = w_self.w_bestbase
239
if w_bestbase is None: # object
241
if w_self.instancetypedef is not w_bestbase.instancetypedef:
243
if w_self.nslots == w_bestbase.nslots:
244
return w_bestbase.get_layout()
247
# compute a tuple that fully describes the instance layout
248
def get_full_instance_layout(w_self):
249
w_layout = w_self.get_layout()
250
return (w_layout, w_self.hasdict, w_self.needsdel, w_self.weakrefable)
252
def compute_mro(w_self):
253
return compute_C3_mro(w_self.space, w_self)
255
def ensure_static__new__(w_self):
256
# special-case __new__, as in CPython:
257
# if it is a Function, turn it into a static method
258
if '__new__' in w_self.dict_w:
259
w_new = w_self.dict_w['__new__']
260
if isinstance(w_new, Function):
261
w_self.dict_w['__new__'] = StaticMethod(w_new)
263
def getdictvalue(w_self, space, w_attr):
264
return w_self.getdictvalue_w(space, space.str_w(w_attr))
266
def getdictvalue_w(w_self, space, attr):
267
w_value = w_self.dict_w.get(attr, None)
268
if w_self.lazyloaders and w_value is None:
269
if attr in w_self.lazyloaders:
270
w_attr = space.new_interned_str(attr)
271
loader = w_self.lazyloaders[attr]
272
del w_self.lazyloaders[attr]
274
if w_value is not None: # None means no such attribute
275
w_self.dict_w[attr] = w_value
279
def lookup(w_self, name):
280
# note that this doesn't call __get__ on the result at all
282
if space.config.objspace.std.withmethodcache:
283
return w_self.lookup_where_with_method_cache(name)[1]
285
return w_self._lookup(name)
287
def lookup_where(w_self, name):
289
if space.config.objspace.std.withmethodcache:
290
return w_self.lookup_where_with_method_cache(name)
292
return w_self._lookup_where(name)
294
def _lookup(w_self, key):
296
for w_class in w_self.mro_w:
297
w_value = w_class.getdictvalue_w(space, key)
298
if w_value is not None:
302
def _lookup_where(w_self, key):
303
# like lookup() but also returns the parent class in which the
304
# attribute was found
306
for w_class in w_self.mro_w:
307
w_value = w_class.getdictvalue_w(space, key)
308
if w_value is not None:
309
return w_class, w_value
312
def lookup_where_with_method_cache(w_self, name):
314
assert space.config.objspace.std.withmethodcache
315
ec = space.getexecutioncontext()
316
version_tag = w_self.version_tag
317
if version_tag is None:
318
tup = w_self._lookup_where(name)
320
SHIFT = r_uint.BITS - space.config.objspace.std.methodcachesizeexp
321
method_hash = r_uint(intmask(id(version_tag) * hash(name))) >> SHIFT
322
cached_version_tag = ec.method_cache_versions[method_hash]
323
if cached_version_tag is version_tag:
324
cached_name = ec.method_cache_names[method_hash]
325
if cached_name is name:
326
tup = ec.method_cache_lookup_where[method_hash]
327
if space.config.objspace.std.withmethodcachecounter:
328
ec.method_cache_hits[name] = \
329
ec.method_cache_hits.get(name, 0) + 1
330
# print "hit", w_self, name
332
tup = w_self._lookup_where(name)
333
ec.method_cache_versions[method_hash] = version_tag
334
ec.method_cache_names[method_hash] = name
335
ec.method_cache_lookup_where[method_hash] = tup
336
if space.config.objspace.std.withmethodcachecounter:
337
ec.method_cache_misses[name] = \
338
ec.method_cache_misses.get(name, 0) + 1
339
# print "miss", w_self, name
342
def check_user_subclass(w_self, w_subtype):
344
if not isinstance(w_subtype, W_TypeObject):
345
raise OperationError(space.w_TypeError,
346
space.wrap("X is not a type object (%s)" % (
347
space.type(w_subtype).getname(space, '?'))))
348
if not space.is_true(space.issubtype(w_subtype, w_self)):
349
raise OperationError(space.w_TypeError,
350
space.wrap("%s.__new__(%s): %s is not a subtype of %s" % (
351
w_self.name, w_subtype.name, w_subtype.name, w_self.name)))
352
if w_self.instancetypedef is not w_subtype.instancetypedef:
353
raise OperationError(space.w_TypeError,
354
space.wrap("%s.__new__(%s) is not safe, use %s.__new__()" % (
355
w_self.name, w_subtype.name, w_subtype.name)))
358
def _freeze_(w_self):
359
"NOT_RPYTHON. Forces the lazy attributes to be computed."
360
if 'lazyloaders' in w_self.__dict__:
361
for attr in w_self.lazyloaders.keys():
362
w_self.getdictvalue_w(w_self.space, attr)
363
del w_self.lazyloaders
366
def getdict(w_self): # returning a dict-proxy!
367
if w_self.lazyloaders:
368
w_self._freeze_() # force un-lazification
371
for key, w_value in w_self.dict_w.items():
372
dictspec.append((space.wrap(key), w_value))
373
newdic = space.newdict()
374
newdic.initialize_content(dictspec)
375
return W_DictProxyObject(newdic)
377
def unwrap(w_self, space):
378
if w_self.instancetypedef.fakedcpytype is not None:
379
return w_self.instancetypedef.fakedcpytype
380
from pypy.objspace.std.model import UnwrapError
381
raise UnwrapError(w_self)
383
def is_heaptype(w_self):
384
w_self = hint(w_self, deepfreeze=True)
385
return w_self.__flags__&_HEAPTYPE
387
def get_module(w_self):
389
if w_self.is_heaptype() and '__module__' in w_self.dict_w:
390
return w_self.dict_w['__module__']
392
# for non-heap types, CPython checks for a module.name in the
393
# type name. That's a hack, so we're allowed to use a different
395
if ('__module__' in w_self.dict_w and
396
space.is_true(space.isinstance(w_self.dict_w['__module__'],
398
return w_self.dict_w['__module__']
399
return space.wrap('__builtin__')
401
def add_subclass(w_self, w_subclass):
403
from pypy.module._weakref.interp__weakref import basic_weakref
404
w_newref = basic_weakref(space, w_subclass)
406
for i in range(len(w_self.weak_subclasses_w)):
407
w_ref = w_self.weak_subclasses_w[i]
408
ob = space.call_function(w_ref)
409
if space.is_w(ob, space.w_None):
410
w_self.weak_subclasses_w[i] = w_newref
413
w_self.weak_subclasses_w.append(w_newref)
415
def remove_subclass(w_self, w_subclass):
418
for i in range(len(w_self.weak_subclasses_w)):
419
w_ref = w_self.weak_subclasses_w[i]
420
ob = space.call_function(w_ref)
421
if space.is_w(ob, w_subclass):
422
del w_self.weak_subclasses_w[i]
425
def get_subclasses(w_self):
428
for w_ref in w_self.weak_subclasses_w:
429
w_ob = space.call_function(w_ref)
430
if not space.is_w(w_ob, space.w_None):
431
subclasses_w.append(w_ob)
435
# for now, weakref support for W_TypeObject is hard to get automatically
437
def getweakref(self):
438
return self._lifeline_
439
def setweakref(self, space, weakreflifeline):
440
self._lifeline_ = weakreflifeline
443
def call__Type(space, w_type, __args__):
444
# special case for type(x)
445
if space.is_w(w_type, space.w_type):
447
w_obj, = __args__.fixedunpack(1)
451
return space.type(w_obj)
452
# invoke the __new__ of the type
453
w_newfunc = space.getattr(w_type, space.wrap('__new__'))
454
w_newobject = space.call_args(w_newfunc, __args__.prepend(w_type))
455
# maybe invoke the __init__ of the type
456
if space.is_true(space.isinstance(w_newobject, w_type)):
457
w_descr = space.lookup(w_newobject, '__init__')
458
w_result = space.get_and_call_args(w_descr, w_newobject, __args__)
459
## if not space.is_w(w_result, space.w_None):
460
## raise OperationError(space.w_TypeError,
461
## space.wrap("__init__() should return None"))
464
def issubtype__Type_Type(space, w_type1, w_type2):
465
return space.newbool(w_type2 in w_type1.mro_w)
467
def repr__Type(space, w_obj):
468
w_mod = w_obj.get_module()
469
if not space.is_true(space.isinstance(w_mod, space.w_str)):
472
mod = space.str_w(w_mod)
473
if not w_obj.is_heaptype() or (mod is not None and mod == '__builtin__'):
477
if mod is not None and mod !='__builtin__':
478
return space.wrap("<%s '%s.%s'>" % (kind, mod, w_obj.name))
480
return space.wrap("<%s '%s'>" % (kind, w_obj.name))
482
def getattr__Type_ANY(space, w_type, w_name):
483
name = space.str_w(w_name)
484
w_descr = space.lookup(w_type, name)
485
if w_descr is not None:
486
if space.is_data_descr(w_descr):
487
return space.get(w_descr,w_type)
488
w_value = w_type.lookup(name)
489
if w_value is not None:
490
# __get__(None, type): turns e.g. functions into unbound methods
491
return space.get(w_value, space.w_None, w_type)
492
if w_descr is not None:
493
return space.get(w_descr,w_type)
494
msg = "type object '%s' has no attribute '%s'" %(w_type.name, name)
495
raise OperationError(space.w_AttributeError, space.wrap(msg))
497
def setattr__Type_ANY_ANY(space, w_type, w_name, w_value):
498
# Note. This is exactly the same thing as descroperation.descr__setattr__,
499
# but it is needed at bootstrap to avoid a call to w_type.getdict() which
500
# would un-lazify the whole type.
501
if space.config.objspace.std.withtypeversion:
503
name = space.str_w(w_name)
504
w_descr = space.lookup(w_type, name)
505
if w_descr is not None:
506
if space.is_data_descr(w_descr):
507
space.set(w_descr, w_type, w_value)
510
if not w_type.is_heaptype():
511
msg = "can't set attributes on type object '%s'" %(w_type.name,)
512
raise OperationError(space.w_TypeError, space.wrap(msg))
513
w_type.dict_w[name] = w_value
515
def delattr__Type_ANY(space, w_type, w_name):
516
if space.config.objspace.std.withtypeversion:
518
if w_type.lazyloaders:
519
w_type._freeze_() # force un-lazification
520
name = space.str_w(w_name)
521
w_descr = space.lookup(w_type, name)
522
if w_descr is not None:
523
if space.is_data_descr(w_descr):
524
space.delete(w_descr, w_type)
526
if not w_type.is_heaptype():
527
msg = "can't delete attributes on type object '%s'" %(w_type.name,)
528
raise OperationError(space.w_TypeError, space.wrap(msg))
530
del w_type.dict_w[name]
533
raise OperationError(space.w_AttributeError, w_name)
536
# ____________________________________________________________
539
abstract_mro = gateway.applevel("""
540
def abstract_mro(klass):
541
# abstract/classic mro
548
if not isinstance(klass.__bases__, tuple):
549
raise TypeError, '__bases__ must be a tuple'
550
stack += klass.__bases__[::-1]
552
""", filename=__file__).interphook("abstract_mro")
554
def get_mro(space, klass):
555
if isinstance(klass, W_TypeObject):
556
return list(klass.mro_w)
558
return space.unpackiterable(abstract_mro(space, klass))
561
def compute_C3_mro(space, cls):
563
orderlists = [get_mro(space, base) for base in cls.bases_w]
564
orderlists.append([cls] + cls.bases_w)
566
for candidatelist in orderlists:
567
candidate = candidatelist[0]
568
if mro_blockinglist(candidate, orderlists) is GOODCANDIDATE:
569
break # good candidate
571
return mro_error(space, orderlists) # no candidate found
572
assert candidate not in order
573
order.append(candidate)
574
for i in range(len(orderlists)-1, -1, -1):
575
if orderlists[i][0] == candidate:
577
if len(orderlists[i]) == 0:
583
def mro_blockinglist(candidate, orderlists):
584
for lst in orderlists:
585
if candidate in lst[1:]:
587
return GOODCANDIDATE # good candidate
589
def mro_error(space, orderlists):
591
candidate = orderlists[-1][0]
592
if candidate in orderlists[-1][1:]:
593
# explicit error message for this specific case
594
raise OperationError(space.w_TypeError,
595
space.wrap("duplicate base class " + candidate.getname(space,"?")))
596
while candidate not in cycle:
597
cycle.append(candidate)
598
nextblockinglist = mro_blockinglist(candidate, orderlists)
599
candidate = nextblockinglist[0]
600
del cycle[:cycle.index(candidate)]
601
cycle.append(candidate)
603
names = [cls.getname(space, "?") for cls in cycle]
604
raise OperationError(space.w_TypeError,
605
space.wrap("cycle among base classes: " + ' < '.join(names)))
607
# ____________________________________________________________