Code Time!

Here is code:

from google.appengine.ext import db
from google.appengine.ext.db import polymodel
_connection_model_superclass = polymodel.PolyModel
class ConnectionModelMetaclass(type(_connection_model_superclass)):
    def __new__(cls, name, bases, dct):
        myname = name.replace('ConnectionModel','').lower()
        if myname:
            #this is not the baseclass
            to_collection_name = 'myto_%s_connections' % myname #or any other naming scheme you like
            from_collection_name = 'myfrom_%s_connections' % myname #or any other naming scheme you like
            myto = 'myto_%s'%myname
            myfrom = 'myfrom_%s'%myname
            dct[myto] = db.ReferenceProperty(collection_name = to_collection_name)
            dct[myfrom] = db.ReferenceProperty(collection_name = from_collection_name)
            if 'put' in dct:
                myput = dct['put']
            else:
                myput = None

            def put(self):
                setattr(self, myto, self.myto)
                setattr(self, myfrom, self.myfrom)
                self._validate_connected_types()
                if myput is not None:
                    myput(self)
                else:
                    MyClass = eval(name)
                    super(MyClass, self).put()
            dct['put'] = put

        return super(ConnectionModelMetaclass, cls).__new__(cls, name, bases, dct)

class ConnectionModel(_connection_model_superclass):
    __metaclass__ = ConnectionModelMetaclass
    ALLOWED_CONNECTIONS = {}#empty dict means anything goes. dict if of kind tuple->tuple
    timestamp = db.DateTimeProperty(auto_now = True)
    myto = db.ReferenceProperty(collection_name = 'myto_connections')
    myfrom = db.ReferenceProperty(collection_name = 'myfrom_connections')
    connection_index = db.StringProperty()#for strict sorting and paging of connections
    def _validate_connected_types(self):
        if None in (self.myfrom, self.myto):
            raise AttributeError
        if not self._check_connection():
            raise AttributeError(\
                'Connection %s --> %s is not allowed for class %s',
                self.myfrom.__class__.__name__,
                self.myto.__class__.__name__,
                self.__class__)

    def _check_connection(self):
        if len(self.ALLOWED_CONNECTIONS) == 0:
            return True
        for froms, tos in self.ALLOWED_CONNECTIONS.iteritems():
            if isinstance(self.myfrom, froms):
                if isinstance(self.myto, tos):
                    return True
        return False

    def put(self):
        if not self.connection_index:
            self.connection_index = '%s|%s|%s' % \
                    (self.timestamp, self.myfrom.key().name(),\
                        self.myto.key().name())
        super(ConnectionModel, self).put()

class LikeConnectionModel(ConnectionModel):
    ALLOWED_CONNECTIONS = {UserModel : ImageModel}

class FollowConnectionModel(ConnectionModel):
    ALLOWED_CONNECTIONS = {UserModel : (UserModel, ImageModel) }#users can follow users and (what the heck) follow images

And a break..

And more code!

#!/usr/bin/python2
"""
Linux ioctl numbers made easy

size can be an integer or format string compatible with struct module

for example include/linux/watchdog.h:

#define WATCHDOG_IOCTL_BASE     'W'

struct watchdog_info {
        __u32 options;          /* Options the card/driver supports */
        __u32 firmware_version; /* Firmware version of the card */
        __u8  identity[32];     /* Identity of the board */
};

#define WDIOC_GETSUPPORT  _IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info)

becomes:

WDIOC_GETSUPPORT = _IOR(ord('W'), 0, "=II32s")

"""
import struct
# constant for linux portability
_IOC_NRBITS = 8
_IOC_TYPEBITS = 8

# architecture specific
_IOC_SIZEBITS = 14
_IOC_DIRBITS = 2

_IOC_NRMASK = (1 << _IOC_NRBITS) - 1
_IOC_TYPEMASK = (1 << _IOC_TYPEBITS) - 1
_IOC_SIZEMASK = (1 << _IOC_SIZEBITS) - 1
_IOC_DIRMASK = (1 << _IOC_DIRBITS) - 1

_IOC_NRSHIFT = 0
_IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
_IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
_IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS

_IOC_NONE = 0
_IOC_WRITE = 1
_IOC_READ = 2

def _IOC(dir, type, nr, size):
    if isinstance(size, str) or isinstance(size, unicode):
        size = struct.calcsize(size)
    return dir  << _IOC_DIRSHIFT  | \
           type << _IOC_TYPESHIFT | \
           nr   << _IOC_NRSHIFT   | \
           size << _IOC_SIZESHIFT

def _IO(type, nr): return _IOC(_IOC_NONE, type, nr, 0)
def _IOR(type, nr, size): return _IOC(_IOC_READ, type, nr, size)
def _IOW(type, nr, size): return _IOC(_IOC_WRITE, type, nr, size)
def _IOWR(type, nr, size): return _IOC(_IOC_READ | _IOC_WRITE, type, nr, size)
## end of http://code.activestate.com/recipes/578225/ }}}