Ian Bicking: the old part of his blog

Re: More on Python Metaprogramming

I don't know whether it's really desirable, but it doesn't seem to be hard to achieve the 'direct syntactic port of ActiveRecord:' using an auxilliary queue and a registration callback e.g.,:

_RegisterPropertyQueue = []

class ActiveRecord(object):
    class __metaclass__(type):
        def __init__(cls, name, bases, dct):
            setattr(cls, "_has_many", set())
            setattr(cls, "_belongs_to", set())
            setattr(cls, "_has_and_belongs_to_many", set())
            for obj in _RegisterPropertyQueue:
                obj.__register__(cls)
            del _RegisterPropertyQueue[:]

            
class RegisterProperty(object):
    def __new__(cls, *args, **kw):
        o = object.__new__(cls)
        _RegisterPropertyQueue.append(o)
        return o
    def __register__(self, cls):
        raise NotImplementedError
        
class Relation(RegisterProperty):
    def __init__(self, other):
        self.other = other
    
class has_many(Relation):
    def __register__(self, cls):
        other = self.other
        cls._has_many.add(other)
        other._belongs_to.add(cls)
        
class belongs_to(Relation):
    def __register__(self, cls):
        other = self.other
        cls._belongs_to.add(other)
        other._has_many.add(cls)
    
class has_and_belongs_to_many(Relation):
    def __register__(self, cls):
        other = self.other
        other._has_and_belongs_to_many.add(cls)
        cls._has_and_belongs_to_many.add(other)    


        
class ProjectManager(ActiveRecord): pass

class Milestones(ActiveRecord): pass

class Categories(ActiveRecord): pass

class Person(ActiveRecord):
    belongs_to(ProjectManager)
    has_many(Milestones)
    has_and_belongs_to_many(Categories)
            

assert ProjectManager in Person._belongs_to
assert Milestones in Person._has_many
assert Person in Categories._has_and_belongs_to_many
Comment on More on Python Metaprogramming
by Michael Spencer