Commits

slug...@gmail.com  committed d2b1a82

Add ``exclude`` argument to ``subclasses_only()``.

  • Participants
  • Parent commits 826e84d

Comments (0)

Files changed (3)

 * webhelpers.misc:
 
   - New exception ``OverwriteError``.
+  - Add ``exclude`` argument to ``subclasses_only``.
 
 1.0b4 (2010-01-24)
 ------------------

File tests/test_misc.py

 
 from webhelpers.misc import *
 
+def by_name(class_):
+    return class_.__name__
+
+#### Simple test
+
 class DummyBase(object):  pass
 class Subclass1(DummyBase):  pass
 class Subclass2(DummyBase):  pass
 
 def test_subclasses_only():
     subclasses = subclasses_only(DummyBase, globals())
-    subclasses.sort()
+    subclasses.sort(key=by_name)
     control = [Subclass1, Subclass2]
     eq_(subclasses, control)
+
+#### Tea test
+
+class Tea(object):  pass
+
+# Abstract subclasses
+class Black(Tea):  pass
+class Green(Tea):  pass
+
+# Concrete classes (grandchildren)
+class EnglishBreakfast(Black):  pass
+class Sencha(Green):  pass
+class EarlGrey(Black):  pass
+class JasminePearl(Green):  pass
+
+def test_subclasses_only_with_exclude():
+    subclasses = subclasses_only(Tea, globals(), [Black, Green])
+    subclasses.sort(key=by_name)
+    control = [EarlGrey, EnglishBreakfast, JasminePearl, Sencha]
+    eq_(subclasses, control)

File webhelpers/misc.py

 
 
 
-def subclasses_only(class_, it):
+def subclasses_only(class_, it, exclude=None):
     """Extract the subclasses of a class from a module, dict, or iterable.
 
     Return a list of subclasses found. The class itself will not be included.
     introspect another module or namespace, pass
     ``vars(the_module_or_namespace)``.
 
-    Example: to collect all subclasses in the current module::
-    >>> subclasses_only(MyBaseClass, globals())   # doctest: +SKIP
-    [Subclass1, Subclass2]
+    ``exclude`` is an optional list of additional classes to ignore. 
+    This is mainly used to exclude abstract subclasses.
     """
     if isinstance(it, dict):
         it = it.itervalues()
     class_types = (type, types.ClassType)
+    ignore = [class_]
+    if exclude:
+        ignore.extend(exclude)
     return [x for x in it if isinstance(x, class_types) and 
-        issubclass(x, class_) and x is not class_]
+        issubclass(x, class_) and x not in ignore]
 
 class DeclarativeException(Exception):
     """A simpler way to define an exception with a fixed message.