1
0
mirror of https://github.com/JoelBender/bacpypes synced 2025-10-13 00:42:44 +08:00
bacpypes/py27/bacpypes/capability.py
2016-11-07 22:45:32 -05:00

152 lines
4.4 KiB
Python

#!/usr/bin/python
"""
Capability
"""
from .debugging import bacpypes_debugging, ModuleLogger
# some debugging
_debug = 0
_log = ModuleLogger(globals())
#
# Capability
#
@bacpypes_debugging
class Capability(object):
_zindex = 99
def __init__(self):
if _debug: Capability._debug("__init__")
#
# Collector
#
@bacpypes_debugging
class Collector(object):
def __init__(self):
if _debug: Collector._debug("__init__ (%r %r)", self.__class__, self.__class__.__bases__)
# gather the capbilities
self.capabilities = self._search_capability(self.__class__)
# give them a chance to init
for cls in self.capabilities:
if hasattr(cls, '__init__') and cls is not Collector:
if _debug: Collector._debug(" - calling %r.__init__", cls)
cls.__init__(self)
def _search_capability(self, base):
"""Given a class, return a list of all of the derived classes that
are themselves derived from Capability."""
if _debug: Collector._debug("_search_capability %r", base)
rslt = []
for cls in base.__bases__:
if issubclass(cls, Collector):
map( rslt.append, self._search_capability(cls))
elif issubclass(cls, Capability):
rslt.append(cls)
if _debug: Collector._debug(" - rslt: %r", rslt)
return rslt
def capability_functions(self, fn):
"""This generator yields functions that match the
requested capability sorted by z-index."""
if _debug: Collector._debug("capability_functions %r", fn)
# build a list of functions to call
fns = []
for cls in self.capabilities:
xfn = getattr(cls, fn, None)
if _debug: Collector._debug(" - cls, xfn: %r, %r", cls, xfn)
if xfn:
fns.append( (getattr(cls, '_zindex', None), xfn) )
# sort them by z-index
fns.sort(key=lambda v: v[0])
if _debug: Collector._debug(" - fns: %r", fns)
# now yield them in order
for xindx, xfn in fns:
if _debug: Collector._debug(" - yield xfn: %r", xfn)
yield xfn
def add_capability(self, cls):
"""Add a capability to this object."""
if _debug: Collector._debug("add_capability %r", cls)
# the new type has everything the current one has plus this new one
bases = (self.__class__, cls)
if _debug: Collector._debug(" - bases: %r", bases)
# save this additional class
self.capabilities.append(cls)
# morph into a new type
newtype = type(self.__class__.__name__ + '+' + cls.__name__, bases, {})
self.__class__ = newtype
# allow the new type to init
if hasattr(cls, '__init__'):
if _debug: Collector._debug(" - calling %r.__init__", cls)
cls.__init__(self)
#
# compose_capability
#
@bacpypes_debugging
def compose_capability(base, *classes):
"""Create a new class starting with the base and adding capabilities."""
if _debug: compose_capability._debug("compose_capability %r %r", base, classes)
# make sure the base is a Collector
if not issubclass(base, Collector):
raise TypeError("base must be a subclass of Collector")
# make sure you only add capabilities
for cls in classes:
if not issubclass(cls, Capability):
raise TypeError("%s is not a Capability subclass" % (cls,))
# start with everything the base has and add the new ones
bases = (base,) + classes
# build a new name
name = base.__name__
for cls in classes:
name += '+' + cls.__name__
# return a new type
return type(name, bases, {})
#
# add_capability
#
@bacpypes_debugging
def add_capability(base, *classes):
"""Add capabilites to an existing base, all objects get the additional
functionality, but don't get inited. Use with great care!"""
if _debug: add_capability._debug("add_capability %r %r", base, classes)
# start out with a collector
if not issubclass(base, Collector):
raise TypeError("base must be a subclass of Collector")
# make sure you only add capabilities
for cls in classes:
if not issubclass(cls, Capability):
raise TypeError("%s is not a Capability subclass" % (cls,))
base.__bases__ += classes
for cls in classes:
base.__name__ += '+' + cls.__name__