Created
December 4, 2014 09:07
-
-
Save wingyiu/0ca90541ed9a083da633 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""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