Ian Bicking: the old part of his blog

Re: More on Python Metaprogramming

It's not so hard as you'd think

# Crack fingers

# File orm.py:
belongs_to_gatherer = []
def belongs_to(what):
    belongs_to_gatherer.append(what)
    
has_many_gatherer = []
def has_many(what):
    has_many_gatherer.append(what)

class MetaRecord(type):
    def __new__(cls, name, bases, dictionary):
        global belongs_to_gatherer, has_many_gatherer
        Record = super(MetaRecord, cls).__new__(cls, name, bases, dictionary)
        
        # Now we grab what we've gathered and run the respective methods on them:
        for i in belongs_to_gatherer:
            Record.belongs_to(i)
        belongs_to_gatherer = []
        
        for i in has_many_gatherer:
             Record.has_many(i)
        has_many_gatherer = []
        
        return Record

class ActiveRecord(object):
    __metaclass__ = MetaRecord
    
    @classmethod
    def belongs_to(cls, what):
        # Set it to belong to: what
        print cls, "belongs to", what

    @classmethod
    def has_many(cls, what):
        # Set it to have many: what
        print cls, "has many", what
        
__all__ = [ActiveRecord, belongs_to, has_many]

# In another file:
from orm import *

class Person(ActiveRecord):
    belongs_to('project_manager')
    has_many('milestones')
Comment on More on Python Metaprogramming
by brantley

Comments:

Note that all these examples (this is the third along these lines) require cooperation on the part of the class. I hadn't really considered that, but it is different from Zope's implements() which can be applied to any class without any cooperation on the part of that class.

# Ian Bicking

I liked that! Pretty cool. What about?

def belongs_to_classmethod(cls, what):
print cls.__name__, " Belongs to ", what
class MetaActiveRecord(type):
def __new__(cls, name, bases, dictionary):

Record = super(MetaActiveRecord, cls).__new__(cls, name, bases, dictionary)

if dictionary.has_key('belongs_to'):
Record.belongs_to_classmethod = classmethod(belongs_to_classmethod) Record.belongs_to_classmethod(dictionary['belongs_to'])

System Message: WARNING/2 (<string>, line 13)

Definition list ends without a blank line; unexpected unindent.

return Record

class ActiveRecord(object):
__metaclass__ = MetaActiveRecord
class Person(ActiveRecord):

belongs_to = 'project_manager' def __init__(self):

System Message: ERROR/3 (<string>, line 22)

Unexpected indentation.
print "Person __init__"

a = Person()

prints: Person Belongs to project_manager Person __init__

# Gordon Scott