47 lines
1.6 KiB
Python
47 lines
1.6 KiB
Python
def compute_C3_mro(w_obj):
|
|
order_w = []
|
|
parents_w = w_obj.getparents()
|
|
orderlists = [w_base.get_mro()
|
|
for w_base in parents_w]
|
|
orderlists.append([w_obj] + parents_w)
|
|
while orderlists:
|
|
for candidatelist in orderlists:
|
|
w_candidate = candidatelist[0]
|
|
if mro_blockinglist(w_candidate, orderlists) is None:
|
|
break # good w_candidate
|
|
else:
|
|
return mro_error(orderlists) # no candidate found
|
|
assert w_candidate not in order_w
|
|
order_w.append(w_candidate)
|
|
for i in range(len(orderlists)-1, -1, -1):
|
|
if orderlists[i][0] is w_candidate:
|
|
del orderlists[i][0]
|
|
if len(orderlists[i]) == 0:
|
|
del orderlists[i]
|
|
return order_w
|
|
|
|
|
|
def mro_blockinglist(w_candidate, orderlists):
|
|
for lst in orderlists:
|
|
if w_candidate in lst[1:]:
|
|
return lst
|
|
return None # good candidate
|
|
|
|
def mro_error(orderlists):
|
|
# w_obj.getname() is a pure debugging-helper. it can return whatever string
|
|
cycle = []
|
|
w_candidate = orderlists[-1][0]
|
|
if w_candidate in orderlists[-1][1:]:
|
|
# explicit error message for this specific case
|
|
raise TypeError("duplicate parent %s" % w_candidate.getname())
|
|
while w_candidate not in cycle:
|
|
cycle.append(w_candidate)
|
|
nextblockinglist = mro_blockinglist(w_candidate, orderlists)
|
|
w_candidate = nextblockinglist[0]
|
|
del cycle[:cycle.index(w_candidate)]
|
|
cycle.append(w_candidate)
|
|
cycle.reverse()
|
|
names = [w_obj.getname() for w_obj in cycle]
|
|
raise TypeError("cycle among base parents: " + ' < '.join(names))
|
|
|