Skip to content

Instantly share code, notes, and snippets.

@wingyiu
Created December 4, 2014 09:07
Show Gist options
  • Save wingyiu/0ca90541ed9a083da633 to your computer and use it in GitHub Desktop.
Save wingyiu/0ca90541ed9a083da633 to your computer and use it in GitHub Desktop.
"""A dynamic class mixer."""
__author__ = "Andy Dustman <andy@dustman.net>"
__revision__ = "$Revision: 1.5 $"[11:-2]
import types
import new
if hasattr(types, 'ObjectType'):
classobj = type
else:
from new import classobj
class object: pass
def mix(module, importer=None, base=[], mixin=[], superclass=None):
"""
Import all public objects from another module, creating new
subclasses with specified base or mixin classes. In effect,
it is similar to doing:
from module import *
except that if subclasses of superclass are found, then new
classes are defined with base classes of mixin + the original
class + base.
Typical use (bar.py):
class BarBase: ...
class BarMixIn: ...
from ClassMixer import mix
import foo
globals().mix(
foo,
importer="bar",
base=[BarBase],
mixin=[BarMixIn],
superclass=foo.Foo,
)
del foo, mix
If foo has a class Spam(Foo), then this effectively creates:
class Spam(BarMixIn, foo.Spam, BarBase): pass
Classes which are not a subclass of foo.Foo, and other non-class
objects, are imported unchanged.
If for some dumb reason you don't specify either base or mixin,
the classes are imported unchanged. base and mixin are sequences
of classes, possibly empty. If superclass is not specified, all
classes in module are mixed. In practice, you should probably
stick to a single class in either base or mixin (not both). If
importer is not specified, the new classes will work fine, but may
not show up properly using pydoc.
"""
g = {}
all = getattr(module, "__all__", dir(module))
for k in all:
if k[0] == "_":
continue
o = getattr(module, k)
if type(o) is types.ClassType or \
(type(o) is types.TypeType and issubclass(o, object)):
if superclass and not issubclass(o, superclass):
g[k] = o
continue
if not (mixin or base): # dumb
g[k] = o
continue
cl = mixin[:]
cl.append(o)
cl.extend(base)
g2 = {}
if importer:
g2['__module__'] = importer
try:
o2 = classobj(k, tuple(cl), g2)
except TypeError:
# probably due to trying to make a new-style class
# from only classic classes
o2 = new.classobj(k, tuple(cl), g2)
g[k] = o2
else:
g[k] = o
return g
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment