Welcome, guest | Sign In | My Account | Store | Cart

Checks a class definition for required attributes <br> To use it, add two lines to your class, __metaclass__=InterfaceChecker and __implements__=[InterfaceName]. The example below generates the following error message: <br> InterfaceOmission: ['__delitem__'] <br> Verifying interfaces for an object becomes trivial. For instance, if you need to validate that variable 'x' implements a minimal sequence interface, verify that: <br> MinimalSequence in x.__implements__

Python, 53 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
########## First define the interface checker and interfaces

from sets import Set
import UserDict

class InterfaceOmission(Exception): pass

class InterfaceChecker(type):
    "Validates the presence of required attributes"
    def __new__(cls, classname, bases, classdict):
        obj = type(classname, bases, classdict)
        if '__implements__' in classdict:
            defined = Set(dir(obj))
            for interface in classdict['__implements__']:
                required = Set(dir(interface))
                if not required.issubset(defined):
                    raise InterfaceOmission, list(required - defined)
        return obj

class MinimalMapping(object):
    "Interface specification"
    def __getitem__(self, key): pass
    def __setitem__(self, key, value): pass
    def __delitem__(self, key): pass
    def __contains__(self, key): pass

class FullMapping(MinimalMapping, UserDict.DictMixin):
    pass

class MinimalSequence(object):
    def __len__(self): pass
    def __getitem__(self, index): pass

class Callable(object):
    def __call__(self, *args): pass


########## The user code starts here

class MyClass(object):
    __metaclass__ = InterfaceChecker
    __implements__ = [MinimalMapping, Callable]
    def __getitem__(self, key): pass
    def __setitem__(self, key, value): pass
    #def __delitem__(self, key): pass    
    def __contains__(self, key): pass
    def __call__(self, *args): pass
    def setdefault(self, key, default):
        'Not required by the interface'


m = MyClass()
assert MinimalMapping in m.__implements__

Fancier implementations are possible. The above is mostly a proof-of-concept.

The sets.Set class from Python 2.3 is used to make the code more clear. An equivalent using dictionaries is easily coded for Python 2.2. Also, UserDict.DictMixin, a Py 2.3 feature, is used in the definition of a full mapping interface; however, that is easily coded in Python 2.2 (see the cookbook recipe for the code).

1 comment

Michele Simionato 19 years, 1 month ago  # | flag

I like it for the nice usage of the set module. The only change I would do is in the variable names in InterfaceChecker.__new__:

cls -> mcl, obj -> cls.

They look nicer to me ;)