Robot Framework Integrated Development Environment (RIDE)
noconflict.py
Go to the documentation of this file.
1 # Copyright 2008-2015 Nokia Networks
2 # Copyright 2016- Robot Framework Foundation
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 # Metaclass fix from http://code.activestate.com/recipes/204197-solving-the-metaclass-conflict/
17 
18 import inspect
19 import types
20 
21 
22 
23 
24 
25 
27 def skip_redundant(iterable, skipset=None):
28  "Redundant items are repeated items or items in the original skipset."
29  if skipset is None: skipset = set()
30  for item in iterable:
31  if item not in skipset:
32  skipset.add(item)
33  yield item
34 
35 
36 def remove_redundant(metaclasses):
37  skipset = {type(types)}
38  for meta in metaclasses: # determines the metaclasses to be skipped
39  skipset.update(inspect.getmro(meta)[1:])
40  return tuple(skip_redundant(metaclasses, skipset))
41 
42 
45 
46 
47 memoized_metaclasses_map = {}
48 
49 
50 def get_noconflict_metaclass(bases, left_metas, right_metas):
51  # make tuple of needed metaclasses in specified priority order
52  metas = left_metas + tuple(map(type, bases)) + right_metas
53  needed_metas = remove_redundant(metas)
54 
55  # return existing confict-solving meta, if any
56  if needed_metas in memoized_metaclasses_map:
57  return memoized_metaclasses_map[needed_metas]
58  # nope: compute, memoize and return needed conflict-solving meta
59  elif not needed_metas: # wee, a trivial case, happy us
60  meta = type
61  elif len(needed_metas) == 1: # another trivial case
62  meta = needed_metas[0]
63  # check for recursion, can happen i.e. for Zope ExtensionClasses
64  elif needed_metas == bases:
65  raise TypeError("Incompatible root metatypes", needed_metas)
66  else: # gotta work ...
67  metaname = '_' + ''.join([m.__name__ for m in needed_metas])
68  meta = classmaker()(metaname, needed_metas, {})
69  memoized_metaclasses_map[needed_metas] = meta
70  return meta
71 
72 
73 def classmaker(left_metas=(), right_metas=()):
74  def make_class(name, bases, adict):
75  metaclass = get_noconflict_metaclass(bases, left_metas, right_metas)
76  return metaclass(name, bases, adict)
77  return make_class
78 
def skip_redundant(iterable, skipset=None)
preliminary: two utility functions #####################
Definition: noconflict.py:27
def classmaker(left_metas=(), right_metas=())
Definition: noconflict.py:73
def remove_redundant(metaclasses)
Definition: noconflict.py:36
def get_noconflict_metaclass(bases, left_metas, right_metas)
Definition: noconflict.py:50