summaryrefslogtreecommitdiff
path: root/mtraits
diff options
context:
space:
mode:
authormichele.simionato <devnull@localhost>2008-08-19 04:49:43 +0000
committermichele.simionato <devnull@localhost>2008-08-19 04:49:43 +0000
commit443dfe1d684ef38741bcb71118bfbe1196bf380e (patch)
tree1b10ea4ac786bc6e3e4db8893ad330627d1bae52 /mtraits
parentbfc23a91358f8f9d38ad2c44353cf65d078981db (diff)
downloadmicheles-443dfe1d684ef38741bcb71118bfbe1196bf380e.tar.gz
Finally fixed the lookup issue for staticmethod and classmethods
Diffstat (limited to 'mtraits')
-rw-r--r--mtraits/doc.py270
-rw-r--r--mtraits/mtrait.py67
-rw-r--r--mtraits/noconflict.py50
3 files changed, 190 insertions, 197 deletions
diff --git a/mtraits/doc.py b/mtraits/doc.py
index b15d96d..8bd3cd4 100644
--- a/mtraits/doc.py
+++ b/mtraits/doc.py
@@ -7,6 +7,13 @@ r"""An implementation of traits in Python
:Download: XXX
:Licence: BSD
:Status: XXX
+:Abstract:
+
+ *The mtrait module provides an implementation of
+ traits as units of composable behavior for Python. It is
+ argued that traits are better than multiple inheritance.
+ Implementing frameworks based on traits is left as an exercise
+ for the reader.*
Motivation
------------------------------------------------
@@ -78,8 +85,8 @@ the features that Guido used to implement the object system (special
method hooks, descriptors, metaclasses) are there, available to the
end user to build her own object system.
-Such features are usually little used in the Python community for
-various good reasons: the object system is good enough as it is and there
+Such features are usually little used in the Python community, for
+many good reasons: the object system is good enough as it is and there
is no reason to change it; moreover there is a strong opposition to
change the language, because Python programmers believe in uniformity
and in using common idioms; finally, it is difficult for application
@@ -123,8 +130,7 @@ properties:
4. the ordering of traits is not important, i.e. enhancing a class
first with trait T1 and then with trait T2 or viceversa is the same;
5. if traits T1 and T2 have names in common, enhancing a class both
- with T1 and T2 raises an error unless unless you specify *explicitely*
- how the overriding of the common names has to be made;
+ with T1 and T2 raises an error;
6. if a trait has methods in common with the base class, then the
trait methods have the precedence;
7. a class can be seen both as a composition of traits and as an homogeneous
@@ -226,7 +232,7 @@ A few caveats
As you see, in a lot of cases replacing mixins with traits is fairly
straightforward: however, in some cases you can run into problems.
For instance, rule 6 implies an attribute lookup different from
-the usual lookup. Consider the following example:
+the standard lookup. Consider the following example:
.. code-block:: python
@@ -377,7 +383,7 @@ Traits play well with pydoc, ipython and the other tools used
to introspect Python objects: try to type
``help(lbl)`` and you will see for yourself how it works.
-Beyond the looking glass
+The Trait Object System
----------------------------------------------------------------------
The goal of the ``mtrait`` module it to modify the standard
@@ -388,13 +394,8 @@ and must forbid your from defining your own ``__getattribute__`` and
``__getstate__`` methods; these
two fundamental properties must be preserved under inheritance (i.e. the
son of a TOS class must be a TOS class) and therefore the implementation
-requires necessarily metaclasses.
-
-In theory you could build your trait objects yourself as explained in
-the previous paragraph, and you could implement the dispatch to traits
-by hand; however, in practice it is much easier if you just rely on the
-magic of the ``include`` class decorator, which is doing a lot of work
-on your behalf. In particular, internally the class decorator works
+necessarily requires metaclasses.
+Internally the ``include`` class decorator works
its magic by changing the metaclass of the original class. Usually the
metaclass is changed to ``TOSMeta``, the basic class of the Trait
Object System. However in general not all TOS classes are
@@ -410,7 +411,7 @@ prevent accidental mistakes, not to give any guarantee.
On the other hand,
the ``include`` class decorator ensures that the metaclass of the
decorated class is a subclass of the metaclass of the undecorated
-class and that it adds the proper ``__traits__``,
+class; moreover, it adds the proper ``__traits__``,
``__getattribute__``, ``__getstate__`` and ``__mixins__`` attributes,
doing the same job as ``TOSMeta`` even if it is not necessarily a
subclass of ``TOSMeta``.
@@ -420,8 +421,8 @@ suitable ``__getattribute__`` method to its instances.
We need to override the
``__getattribute__`` method
since we want to change the attribute lookup rules: in regular
-Python, the usual rules are 1. look at the class 2. look at
-the base class and 3. look at ``__getattr__``; rules 6 instead
+Python, the usual rules are look at the class, look at
+the base class and look at ``__getattr__``; rules 6 instead
says that traits must have the precedence over the base class,
so overriding ``__getattr__`` would not be enough. Fortunately,
the Python object model is powerful enough to allows users
@@ -447,7 +448,10 @@ the ``__metaclass__`` hook and specify the mixins directly with ``__mixins__``:
$$TOSWidget2
-However, ``include`` does more than that, since it
+The magic of ``include``
+------------------------------------------------------
+
+``include`` does more than just dispatching to the ``__metaclass__`` hook: it
takes care automatically of possible metaclass conflicts. In the case of
Tkinter there is no such problem, since ``BaseWidget`` is just a traditional
old-style class and the metaclass for ``TOSWidget2`` is just ``TOSMeta``:
@@ -463,31 +467,41 @@ instance Zope classes; in that case having a class decorator smart
enough to figure out the right metaclass to use is a convenient
facility. Here is an example:
-$$MyMetacls
-
-.. code-block:: python
+$$AddGreetings
-$$Base2
+$$PackWidget
-The ``include`` decorator automatically generates the right metaclass
-which avoids the dreaded `metaclass conflict`_, a subclass of ``MyMetacls``:
+The ``include`` decorator automatically generates the right metaclass as
+a subclass of ``AddGreetings``:
.. code-block:: python
- >>> print type(Base2).__mro__
- (<class 'mtrait._TOSMetaMyMetacls'>, <class '__main__.MyMetacls'>, <type 'type'>, <type 'object'>)
+ >>> print type(PackWidget).__mro__
+ (<class 'mtrait._TOSMetaAddGreetings'>, <class '__main__.AddGreetings'>, <type 'type'>, <type 'object'>)
- >>> Base2.__traits__
- <Traits Pack bound to <class '__main__.Base2'>>
-
- >>> Base2.greetings
+This trick avoids the dreaded `metaclass conflict`_. ``_TOSMetaAddGreetings``
+provides the same features of ``TOSMeta`` and in particular you may
+check that it sets the ``__traits__`` attribute correctly:
+
+ >>> PackWidget.__traits__
+ <Traits Pack bound to <class '__main__.PackWidget'>>
+
+On the other hand, ``_TOSMetaAddGreetings`` is a subclass of ``AddGreetings``
+which calls ``AddGreetings.__new__``, so the features provided by
+``AddGreetings`` are not lost either; in this example you may check
+that the greetings attribute is correctly set:
+
+ >>> PackWidget.greetings
'hello!'
-The name is automatically generated from the name of the base
+The name of the generated metaclass
+is automatically generated from the name of the base
metaclass; moreover, a register of the generated metaclasses
is kept, so that metaclasses are reused if possible.
If you want to understand the details, you are welcome
-to give a look at the implementation, which is pretty small.
+to give a look at the implementation, which is pretty short
+and simple, compared to the general recipe to remove
+the `metaclass conflict`_ in a true multiple inheritance situation.
.. _sqlalchemy: http://www.sqlalchemy.org/
.. _metaclass conflict: http://code.activestate.com/recipes/204197/
@@ -501,8 +515,9 @@ class and another class you will get a ``TypeError``:
.. code-block:: python
- >>> class M: pass
- ...
+ >>> class M:
+ ... "An empty mixin"
+ ...
>>> class Widget2(TOSWidget, M): #doctest: +ELLIPSIS
... pass
...
@@ -513,11 +528,11 @@ class and another class you will get a ``TypeError``:
This behavior is intentional: with this restriction you can simulate
an ideal world in which Python did not support multiple
inheritance. Suppose you want to claim that supporting multiple
-inheritance was a mistake and that Python would have been better
-without it (which is the position I tend to have nowadays, but see the
-notes below): how can you prove that claim? Simply by writing code
-that does not use multiple inheritance and it is clearer and more
-mantainable that code using multiple inheritance.
+inheritance was a mistake and that Python would have been better off
+without it (which is the position I tend to have nowadays): how can
+you prove that claim? Simply by writing code that does not use
+multiple inheritance and it is clearer and more mantainable that code
+using multiple inheritance.
I am releasing this trait implementation hoping you will help me to
prove (or possibly disprove) the point. You may see traits as a
@@ -526,11 +541,11 @@ order and without name clashes which does not pollute the namespace of
the original class; it does not have cooperative methods either. Still
I think these are acceptable restrictions since they give back in
return many advantages in terms of simplicity: for instance, ``super``
-becomes trivial, since each class has a single superclass.
+becomes trivial, since each class has a single superclass, whereas
+we all know that the `current
+super in Python`_ is very far from trivial.
-We all know that the `current
-super in Python`_ is very far from trivial, instead. More importantly,
-we all know that. many people use multiple inheritance incorrectly,
+More importantly, many people use multiple inheritance incorrectly,
confusing the ``is-a`` relation with the ``has-a`` relation; with
traits, there is no confusion. Since there is a single base class, you
can associate the ``is-a`` relation with the base class whereas the
@@ -556,41 +571,26 @@ of ``C`` gets the new version of the method, which is pretty useful
for debugging purposes. This feature is lost in the simplistic
approach but not lost in the trait approach: the trait implementation
is fully dynamic and if you change the mixin the instances will be
-changed too. This however, is a minor point.
-
-The real reason why just
-including methods in the class namespace is a bad idea is that it
-easily leads you into the problem of *namespace pollution*. I have
-discussed the issue elsewhere_: if you keep injecting methods into a
-class (both directly or via inheritance) you may end up having
-hundreds of methods flattened at the same level. A picture is worth a
-thousand words, so have a look at the `PloneSite hierarchy`_ if you
-want to understand the horror I would like to avoid with traits
-(the picture shows the number of
-nonspecial attributes defined per class in square brackets): in
-the Plone Site hierarchy there
-are 38 classes, 88 overridden names, 42 special names, 648
-non-special attributes and methods. It is a maintenance nighmare.
-The
-``mtrait`` implementation avoids name space pollution since each trait
-has its own namespace and you are guaranteed against name
+changed too. This however, is a minor issue (I never
+used that feature much).
+
+The real reason why just including methods in the class namespace is a
+bad idea is that it easily leads you into the problem of *namespace
+pollution*. I have discussed the issue elsewhere_: if you keep
+injecting methods into a class (both directly or via inheritance) you
+may end up having hundreds of methods flattened at the same level. A
+picture is worth a thousand words, so have a look at the `PloneSite
+hierarchy`_ if you want to understand the horror I would like to avoid
+with traits (the picture shows the number of nonspecial attributes
+defined per class in square brackets): in the Plone Site hierarchy
+there are 38 classes, 88 overridden names, 42 special names, 648
+non-special attributes and methods. It is a nighmare.
+
+The ``mtrait`` implementation avoids name space pollution since each
+trait has its own namespace and you are guaranteed against name
conflicts. Moreover, introspecting traits is much easier than
-introspecting inheritance hierarchies: even the autocompletion
-feature works best.
-
-*Note 1*: even if I think that a language would be better off without
-full multiple inheritance with cooperative methods, that does not mean
-that I am against interfaces. I think a class should be able to
-implement multiple interfaces at the same time, but this has nothing
-to do with multiple inheritance. However in Python (starting from
-Python 2.6) multiple inheritance is abused to simulate interface
-requirements so that if you want to implement many interfaces at the
-same time you are suggested to inherit from many abstract base classes
-at the same time. In an ideal language without multiple inheritance
-you could just add an ``__interfaces__`` attribute to classes. In an
-ideal language interfaces would be abstract objects (a little more
-than a list of names) whereas in Python they are concrete classes and
-that explains why you inherit from them.
+introspecting inheritance hierarchies: even the autocompletion feature
+works best.
.. _current super in Python: http://www.artima.com/weblogs/viewpost.jsp?thread=236275
.. _elsewhere: http://stacktrace.it/articoli/2008/06/i-pericoli-della-programmazione-con-i-mixin1/
@@ -601,38 +601,46 @@ Discussion of some design decisions and future work
--------------------------------------------------------
The decision of having TOS classes which are not instances of TOSMeta
-has been a hard one. That was my original idea in version 0.1 of this
-module; however in version 0.2 I changed my mind and I made all TOS
-classes instances of TOSMeta. That implies that if your original class
-has a nontrivial metaclass, then the TOS class must inherit both from
-the original metaclass *and* ``TOSMeta``, i.e. multiple inheritance
-and cooperation of methods are required at the metaclass level. I did
-not like it, since I am arguing here that you can do everything without
-multiple inheritance and cooperative methods; moreover using multiple
-inheritance at the metaclass level means that one has to solve the
-`metaclass conflict`_ in a general way. I did so, by using my own
-cookbook recipe, and all my tests passed.
-
-Neverthess, at the end, in version 0.3 I decided to go
-back to the original design. The metaclass conflict recipe is too
-complex, and I see it as a code smell (*if the implementation is hard
-to explain, it's a bad idea*), just another indication that multiple
-inheritance is a bad idea. On the other hand, in the original
-design it is possible to add the features of ``TOSMeta`` to the
-original metaclass by subclassing it with *single* inheritance
-and thus avoiding the conflict. The price to pay is that the
-TOS class is no more an instance of ``TOSMeta``, but this is
-not an issue: the important thing is that TOS classes perform
-the dispatch on their traits as ``TOSMeta`` would dictate.
-
-The Smalltalk implementation of traits provides method renaming
-out of the box. The Python implementation has no facilities in
-this sense. In the future I may decide to give some support for
-renaming, or I may not. At the present you can just rename
-your methods by hand.
-Also, in the future I may decide to add some kind of adaptation mechanism
-or I may not: after all the primary goal of this implementation is semplicity
-and I don't want to clutter it with too many features.
+required some thinking. That was my original idea in version 0.1 of
+``mtrait``; however in version 0.2 I wanted to see what would happen
+if I made all TOS classes instances of TOSMeta. That implied that if
+your original class had a nontrivial metaclass, then the TOS class had
+to inherit both from the original metaclass *and* ``TOSMeta``,
+i.e. multiple inheritance and cooperation of methods was required at
+the metaclass level. I did not like it, since I was arguing that
+you can do everything without multiple inheritance and cooperative
+methods; moreover using multiple inheritance at the metaclass level
+meant that one had to solve the metaclass conflict in a general
+way. I did so, by using my own cookbook recipe, and all my tests
+passed.
+
+Neverthess, at the end, in version 0.3 I decided to go back to the
+original design. The metaclass conflict recipe is too complex, and I
+see it as a code smell - *if the implementation is hard to explain,
+it's a bad idea* - just another indication that multiple inheritance
+is bad. In the original design it is possible to add
+the features of ``TOSMeta`` to the original metaclass by subclassing
+it with *single* inheritance and thus avoiding the conflict.
+
+The price to pay is that the TOS class is no more an instance of
+``TOSMeta``, but this is a non-issue: the important thing is that TOS
+classes perform the dispatch on their traits as ``TOSMeta`` would
+dictate. Moreover, starting from Python 2.6, thanks to `Abstract Base
+Classes`_, you may satisfy the ``isinstance(obj, cls)`` check even if
+``obj`` is not an instance of ``cls``, by registering a suitable base
+class (similarly for ``issubclass``). In our situation, that means
+that it is enough to register ``TOSMeta`` as base class of the
+original metaclass.
+
+Where to go from here? For the moment, I have no clear idea about the
+future. The Smalltalk implementation of traits provides method
+renaming out of the box. The Python implementation has no facilities
+in this sense. In the future I may decide to give some support for
+renaming, or I may not. At the present you can just rename your
+methods by hand. Also, in the future I may decide to add some kind of
+adaptation mechanism or I may not: after all the primary goal of this
+implementation is semplicity and I don't want to clutter it with too
+many features.
I am very open to feedback and criticism: I am releasing this module
with the hope that it will be used in real life situations to gather
@@ -652,6 +660,7 @@ try them out.
implementation; it stands for *Meta* or for *My* or even for
*Michele*, at your will ;)
+.. _Abstract Base Classes: http://www.python.org/dev/peps/pep-3119/
.. _traits: http://www.iam.unibe.ch/~scg/Research/Traits/
.. _Traits - Composable Units of Behavior: http://www.iam.unibe.ch/%7Escg/Archive/Papers/Scha03aTraits.pdf
.. _PLT Scheme: http://www.cs.utah.edu/plt/publications/aplas06-fff.pdf
@@ -680,9 +689,9 @@ class TOSWidget2(BaseWidget):
forget = Pack.forget.im_func
propagate = Pack.propagate.im_func
-label = TOSWidget(master=None, widgetName='label', cnf=dict(text="hello"))
-
-pickle.dumps(label)
+def test_label():
+ label = TOSWidget(master=None, widgetName='label', cnf=dict(text="hello"))
+ pickle.dumps(label)
class HTTP(object):
def GET(self):
@@ -708,15 +717,15 @@ class Mixin(object):
def method(self):
return self._helper() + 1
-class MyMetacls(type):
- "A do-nothing metaclass for exemplification purposes"
+class AddGreetings(type):
+ "A metaclass a 'greetings' attribute for exemplification purposes"
def __new__(mcl, name, bases, dic):
dic['greetings'] = 'hello!'
- return super(MyMetacls, mcl).__new__(mcl, name, bases, dic)
+ return super(AddGreetings, mcl).__new__(mcl, name, bases, dic)
-class Base2:
- __metaclass__ = MyMetacls
- include(Pack)
+class PackWidget(BaseWidget):
+ __metaclass__ = AddGreetings
+ include(Pack) # put this line AFTER the __metaclass__ hook!
def test_getattr():
try:
@@ -731,7 +740,7 @@ def test_getattr():
def test_multi_include():
class B(object):
- __metaclass__ = MyMetacls
+ __metaclass__ = AddGreetings
include(FTP)
class C(B):
include(HTTP)
@@ -742,7 +751,7 @@ def test_multi_include():
x = D(1)
x.a
x.cm()
- #x.sm()
+ x.sm()
print type(B), type(C)
def test_Trait_pickle():
@@ -832,4 +841,27 @@ PloneSite=app.rcare.__class__
plot_classes(PloneSite.mro(), verbose=2)
+In theory you could build your trait objects yourself as explained in
+the previous paragraph, and you could implement the dispatch to traits
+by hand; however, in practice it is much easier if you just rely on the
+magic of the class decorator, which is doing a lot of work
+on your behalf. In particular,
+
+
+*Note 1*: Python has somewhat of a schizofrenic attitude towards inheritance.
+Recent evolutions of the language
+
+even if I think that a language would be better off without
+full multiple inheritance with cooperative methods, that does not mean
+that I am against interfaces. I think a class should be able to
+implement multiple interfaces at the same time, but this has nothing
+to do with multiple inheritance. However in Python (starting from
+Python 2.6) multiple inheritance is abused to simulate interface
+requirements so that if you want to implement many interfaces at the
+same time you are suggested to inherit from many abstract base classes
+at the same time. In an ideal language without multiple inheritance
+you could just add an ``__interfaces__`` attribute to classes. In an
+ideal language interfaces would be abstract objects (a little more
+than a list of names) whereas in Python they are concrete classes and
+that explains why you inherit from them.
'''
diff --git a/mtraits/mtrait.py b/mtraits/mtrait.py
index bd00556..bd7d3b1 100644
--- a/mtraits/mtrait.py
+++ b/mtraits/mtrait.py
@@ -6,10 +6,13 @@ class OverridingError(NameError):
class OverridingWarning(Warning):
pass
+def special(name):
+ "True if name has the form __XXX__"
+ return name.startswith('__') and name.endswith('__')
+
def getnames(obj):
"Get the nonspecial attributes in obj"
- return set(name for name in dir(obj)
- if not (name.startswith('__') and name.endswith('__')))
+ return set(name for name in dir(obj) if not special(name))
def find_common_names(mixins):
"Perform n*(n-1)/2 namespace overlapping checks on a set of n mixins"
@@ -34,13 +37,23 @@ def check_overridden(mixins, exclude, raise_='error'):
raise OverridingError(msg)
elif raise_ == 'warning':
warnings.warn(msg, OverridingWarning, stacklevel=2)
-
-def getboundvalue(value, obj, objcls):
- "Convert a value into a bound descriptor or do nothing"
+
+def get_from_vars(ob, name, obj, objcls):
+ "Get a bound attribute from vars(obj)"
+ value = vars(ob)[name]
try: # return the bound descriptor
return value.__get__(obj, objcls)
except AttributeError: # not a descriptor
return value
+
+def get_from_cls(cls, name, obj, objcls):
+ "Get a bound attribute from cls and its ancestors"
+ for subc in inspect.getmro(cls):
+ try:
+ return get_from_vars(subc, name, obj, objcls)
+ except KeyError:
+ continue
+ raise AttributeError(name)
# added to the instances of TOSMeta
def __obj_getattribute__(obj, name, get=object.__getattribute__):
@@ -51,7 +64,7 @@ def __obj_getattribute__(obj, name, get=object.__getattribute__):
3. look at the traits;
4. look at the base classes and to __getattr__
"""
- if name.startswith('__') and name.endswith('__'): # special name, do nothing
+ if special(name): # regular lookup
return get(obj, name)
try:
return vars(obj)[name]
@@ -59,11 +72,12 @@ def __obj_getattribute__(obj, name, get=object.__getattribute__):
pass
objcls = type(obj)
try:
- return getboundvalue(vars(objcls)[name], obj, objcls)
+ return get_from_vars(objcls, name, obj, objcls)
except KeyError:
pass
for boundtrait in obj.__traits__:
try:
+ #if name == 'sm': import pdb; pdb.set_trace()
return getattr(boundtrait, name)
except AttributeError:
pass
@@ -77,11 +91,11 @@ def __cls_getattribute__(cls, name, get=type.__getattribute__):
2. look at the traits;
3. look at the base classes and the metaclass __getattr__
"""
- if (name.startswith('__') and name.endswith('__')) or name == 'mro':
- # special names, do nothing
+ if special(name) or name == 'mro':
+ # regular lookup
return get(cls, name)
try:
- return getboundvalue(vars(cls)[name], None, cls)
+ return get_from_vars(cls, name, None, cls)
except KeyError:
pass
for boundtrait in cls.__traits__:
@@ -91,6 +105,8 @@ def __cls_getattribute__(cls, name, get=type.__getattribute__):
pass
return get(cls, name)
+# saving functions into an object will break pickle, so you must
+# dispatch to the original classes
class Trait(object):
"""
Class for mixin dispatchers. Mixin dispatchers are instantiated through the
@@ -102,10 +118,7 @@ class Trait(object):
"""
def __init__(self, inner, name, obj=None, objcls=None):
- if isinstance(inner, self.__class__): # already a trait
- self.__inner = inner._Trait__inner
- else:
- self.__inner = inner
+ self.__inner = inner
self.__name__ = name
self.__obj = obj
self.__objcls = objcls
@@ -116,18 +129,13 @@ class Trait(object):
def __getattr__(self, name):
"obj.dispatcher.method(args) returns mixin.method(obj, args)"
- value = getattr(self.__inner, name)
- try: # if (unbound) method, go back to the function
- value = value.im_func
- except AttributeError:
- pass
obj, objcls = self.__obj, self.__objcls
- if obj or objcls:
- try: # return the bound descriptor
- return value.__get__(obj, objcls)
- except AttributeError: # not a descriptor
- pass
- return value
+ if inspect.isclass(self.__inner):
+ return get_from_cls(self.__inner, name, obj, objcls)
+ try:
+ return get_from_vars(self.__inner, name, obj, objcls)
+ except KeyError:
+ raise AttributeError
def __iter__(self):
return iter(getnames(self.__inner))
@@ -202,7 +210,8 @@ def oldstyle(bases):
def isTOSclass(cls):
"True if cls satisfies the TOS interface"
- return hasattr(cls, '__traits__')
+ # not check for __mixins__ and __getstate__ for the moment
+ return hasattr(cls, '__traits__')
class TOSMeta(type):
"""
@@ -233,7 +242,7 @@ class TOSMeta(type):
dic['__getstate__'] = dic.get('__getstate__', vars)
basemixins = ()
else:
- basemixins = tuple(t._Trait__inner for t in traits)
+ basemixins = getattr(bases[0], '__mixins__', ())
mixins = dic.get('__mixins__', ())
if mixins:
commonset = set(basemixins) & set(mixins)
@@ -242,7 +251,7 @@ class TOSMeta(type):
mixins = basemixins + mixins
check_overridden(mixins, exclude=set(dic))
dic['__traits__'] = TraitContainer.from_(mixins)
- # since TOS hierarchies are single-inheritance, I don't need super
+ # TOS hierarchies are single-inheritance, I don't need super
return mcl.__base__.__new__(mcl, name, bases, dic)
__getattribute__ = __cls_getattribute__
@@ -263,6 +272,8 @@ def new(mcl, name, bases, dic, mixins):
typ = type('_TOSMeta' + typ.__name__, (mcl,), dict(
__new__=TOSMeta.__new__, __getattribute__= __cls_getattribute__))
known_metas.add(typ)
+ # in Python 2.6 add something like
+ # ABCMeta.register(TOSMeta, typ) # issubclass(typ, TOSMeta)
dic['__mixins__'] = mixins
return typ(name, bases, dic)
diff --git a/mtraits/noconflict.py b/mtraits/noconflict.py
deleted file mode 100644
index bbdb678..0000000
--- a/mtraits/noconflict.py
+++ /dev/null
@@ -1,50 +0,0 @@
-"""
-An helper module for meta-type conflict resolution
-"""
-
-import inspect, types
-
-memoized_metaclasses_map = {}
-
-def skip_redundant(iterable, skipset=None):
- "Redundant items are repeated items or items in the original skipset."
- if skipset is None: skipset = set()
- for item in iterable:
- if item not in skipset:
- skipset.add(item)
- yield item
-
-def remove_redundant(metaclasses):
- skipset = set([types.ClassType])
- for meta in metaclasses: # determines the metaclasses to be skipped
- skipset.update(inspect.getmro(meta)[1:])
- return tuple(skip_redundant(metaclasses, skipset))
-
-# make tuple of needed metaclasses in specified priority order
-def get_noconflict_metaclass(bases, left_metas, right_metas):
- metas = left_metas + tuple(map(type, bases)) + right_metas
- needed_metas = remove_redundant(metas)
-
- # return existing confict-solving meta, if any
- if needed_metas in memoized_metaclasses_map:
- return memoized_metaclasses_map[needed_metas]
- # nope: compute, memoize and return needed conflict-solving meta
- elif not needed_metas: # wee, a trivial case, happy us
- meta = type
- elif len(needed_metas) == 1: # another trivial case
- meta = needed_metas[0]
- # check for recursion, can happen i.e. for Zope ExtensionClasses
- elif needed_metas == bases:
- raise TypeError("Incompatible root metatypes", needed_metas)
- else: # gotta work ...
- metaname = '_' + ''.join(m.__name__ for m in needed_metas)
- meta = classmaker()(metaname, needed_metas, {})
- memoized_metaclasses_map[needed_metas] = meta
- return meta
-
-# recursive builder used in conjunction with get_noconflict_metaclass
-def classmaker(left_metas=(), right_metas=()):
- def make_class(name, bases, adict):
- metaclass = get_noconflict_metaclass(bases, left_metas, right_metas)
- return metaclass(name, bases, adict)
- return make_class