concrete_descendents ignoring abstract flag?
As far as I can tell, param.concrete_descendents is ignoring whether a class is declared abstract:

Here the definition of concrete_descendents is:
def _is_abstract(class_):
try:
return class_.abstract
except AttributeError:
return False
def concrete_descendents(parentclass):
return dict((c.__name__,c) for c in descendents(parentclass)
if not _is_abstract(c))
and the definition of SelectorBase is:
class SelectorBase(Parameter):
__abstract = True
def get_range(self):
raise NotImplementedError("get_range() must be implemented in subclasses.")
SelectorBase appears be declaring itself abstract, but that doesn't get picked up by concrete_descendents, as SelectorBase is not excluded from the list returned. I can't quite see how this was ever meant to work, given that none of this code appears to have changed in the past 9 years. Or am I just confused?
Parameterized classes inherit the abstract property from the ParameterizedMetaclass metaclass (instances don't inherit this property). So _is_abstract above works fine when the class is a Parameterized subclass. SelectorBase.__abstract = True should be removed as Parameters aren't Parameterized subclasses.
class ParameterizedMetaclass(type):
# Should use the official Python 2.6+ abstract base classes; see
# https://github.com/holoviz/param/issues/84
def __is_abstract(mcs):
"""
Return True if the class has an attribute __abstract set to True.
Subclasses will return False unless they themselves have
__abstract set to true. This mechanism allows a class to
declare itself to be abstract (e.g. to avoid it being offered
as an option in a GUI), without the "abstract" property being
inherited by its subclasses (at least one of which is
presumably not abstract).
"""
# Can't just do ".__abstract", because that is mangled to
# _ParameterizedMetaclass__abstract before running, but
# the actual class object will have an attribute
# _ClassName__abstract. So, we have to mangle it ourselves at
# runtime. Mangling follows description in
# https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
try:
return getattr(mcs,'_%s__abstract'%mcs.__name__.lstrip("_"))
except AttributeError:
return False
abstract = property(__is_abstract)