[PEAK] Type and class adaptation

Radek Kanovsky rk at dat.cz
Fri Nov 19 12:21:17 EST 2004


Hi all,

sometimes I need adapt types or classes itself, i.e. not their
instances. I mean some mechanism that gives me descriptor, validator,
input field factory, parser or something useful for int type, MyClass,
etc. Not for number 444, not for MyClass instance. For example:

    int               -> ITypeDescriptor
    myint(int)        -> ITypeDescriptor
    MyClass           -> ITypeDescriptor
    SubClass(MyClass) -> ITypeDescriptor

Additionaly this mechanism should follow class hierarchy. If one define
adapter for int, myint should be adaptable by this adapter too, until
more specific adapter for myint is defined elsewhere. (suppose myint is
inherited from int)

This isn't easily solvable by protocols package. Although one can
declare adapter from MyClass to ITypeDescriptor, this isn't possible for
int, because int hasn't writable __dict__. Additionally if I declare
adapter for MyClass, this adapter is not applicable to SubClass.

Now I have TypeRegistry class whose instances allow register adapters or
implementations and lookup implementations for types and classes:

    >>> TypeDescriptor = TypeRegistry()
    >>> TypeDescriptor.registerImplementation(int, IntTypeDescriptor)
    >>> TypeDescriptor.registerAdapter(varchar, VarcharAsTypeDescriptor)

    >>> TypeDescriptor(int)
    IntTypeDescriptor
    >>> TypeDescriptor(myint)
    IntTypeDescriptor
    # varchar[16] returns varchar16 subclass of varchar
    >>> TypeDescriptor(varchar[16])
    VarcharTypeDescriptor[16]
    >>> TypeDescriptor(varchar[32])
    VarcharTypeDescriptor[32]

This worked perfectly until situation when both types and instances
needed some kind of adaptation. So I have tried generic function. First
solution used 'issubclass' in predicate:

    [typeDescriptor.when("issubclass(arg,int)")]
    def typeDescriptorForInt(arg) ...

    [typeDescriptor.when("issubclass(arg,myint)")]
    def typeDescriptorForMyInt(arg) ...

This method failed on ambiguity when dispatching arg=int. So there
should be some ITest that helps. Looking at dispatch.ClassTest I have
made slight modification of it that resulted to 'IsSubclass' test:

    [typeDescriptor.when("arg in IsSubclass(int)")]
    def typeDescriptorForInt(arg) ...

    [typeDescriptor.when("arg in IsSubclass(myint)")]
    def typeDescriptorForMyInt(arg) ...

This works fine. I think that 'issubclass(t1, t2)' expression can be
safely replaced by IsSubclass test directly by predicate parser.

Has anybody some solution or opinion? Did I miss something?

RadekK





--------------- IsSubclass ----------------------------------------

def dispatch_by_subclass (klass, table):
    while True:
        if klass in table:
            return table[klass]
        try:
            klass, = klass.__bases__
        except ValueError:
            if klass.__bases__:
                return table.reseed(klass)
            else:
                break
    if klass in table:
        return table[object]


class IsSubclass (protocols.Adapter) :

    protocols.advise(instancesProvide=[ITest])

    dispatch_function = staticmethod(dispatch_by_subclass)

    def seeds(self,table):
        return [self.subject, object]

    def __contains__(self,ob):
        if isinstance(ob,ClassTypes):
            return issubclass(ob, self.subject)
        return False

    def implies(self, otherTest):
        return self.subject in ITest(otherTest) or otherTest is NullTest

    def __repr__(self):
        return "IsSubclass(%s)" % self.subject.__name__

    def subscribe(self,listener): pass

    def unsubscribe(self,listener): pass

    def __eq__(self,other):
        return type(self) is type(other) and self.subject is other.subject

    def __ne__(self,other):
        return not self.__eq__(other)



More information about the PEAK mailing list