Package: bincombo
Make any type binary-combinable with a single line of code.The most obvious use case arguably is the creation of binary expressions over custom
types, butbincombois not limited to combination of boolean values.
By providing appropriate map/reduce operations, any type of data of the discrete
members of a combination can be aggregated to form a combined result.The implementation solely relies on inheritance, no meta programming is involved.
You are free to use your own metaclasses, should you wish to do so.Suppose you have a custom typeCheck, which accepts or rejects values depending
on the result of the invocation of some callable.
You can make instances of it combinable using the binary operators&(and) and|(or) and also support the unary~(invert) by using thecombinable()decorator:import bincombo

@bincombo.combinable(methods=("check",))
class Check:
    __slots__ = ("checker",)

    def __init__(self, checker):
        self.checker = checker

    def check(self, value):
        return self.checker(value)Now,Checkobjects can be binary-combined:c1 = Check(lambda v: isinstance(v, int) and v >= 42)
c2 = Check(lambda v: isinstance(v, str))
c3 = Check(lambda v: "hello" in v)
c = c1 | c2 & ~c3
c.check(41)  # False
c.check(42)  # True
c.check("hello, world!")  # False
c.check("hey, world!")  # TrueThecombinable()decorator creates a number of types needed to represent discrete
checks and combinations thereof.
These are stored in aConfigobject, which is aavailable as class attributeBIN_CONFIGofCheck.
It can be worth storing these types as module attributes alongside yourCheckclass to have them at hand for explicit use or type checking:BaseCheck = Check.BIN_CONFIG.base_type
CheckCombo = Check.BIN_CONFIG.combo_type
AllChecks = Check.BIN_CONFIG.and_type
AnyCheck = Check.BIN_CONFIG.or_typeAll types in this module have__slots__defined for smaller memory footprints
and improved lookup times, as have the types created bycombinable().
It is recommended to also equip your own type with__slots__if possible to
benefit from entirely__dict__-less objects.To gain a better understanding of how all the types relate or to further customize
them, here is how you would makeCheckbinary-combinable without using thecombinable()helper:# This is a base class from which both the discrete Check type and the type
# representing a combination of Check objects will inherit.
# It can be used, for instance, to test whether some object is Check-like
# using isinstance(obj, BaseCheck).
class BaseCheck:
    __slots__ = ()

# Check should support all three operations.
feature_mixins = (
    bincombo.AndSupportMixin, bincombo.OrSupportMixin, bincombo.InvertSupportMixin
)

# This is the type that would normally be returned by combinable() decorator.
# Here it replaces the original Check, but you could also give it a different name.
class Check(*feature_mixins, Check, BaseCheck):
    __slots__ = ()

# Objects of this type represent (possibly negated) AND/OR combinations of
# Check objects.
class CheckCombo(*feature_mixins, bincombo.Combo, BaseCheck):
    __slots__ = ()

    # Create a proxy check() method that queries an individual combo member.
    # bincombo will call this method for all members, combining the returned
    # boolean values using and/or, depending on the combination type, and possibly
    # invert the final result.
    @bincombo.combine_members
    def check(self, member, value):
        return member.check(value)

# This is an AND combination.
class AllChecks(bincombo.AndComboMixin, CheckCombo):
    __slots__ = ()

# This is an OR combination.
class AnyCheck(bincombo.OrComboMixin, CheckCombo):
    __slots__ = ()

# Finally, bincombo has to be taught all the types just created.
# By attaching the Config object to BaseCheck as a class attribute, both Check
# and CheckCombo instances will have it available due to inheritance.
BaseCheck.BIN_CONFIG = bincombo.Config(
    BaseCheck, Check, CheckCombo, AllChecks, AnyCheck
)Further customization of the combining abilities is possible, the documentations ofcombinable(),combine_members()andConfighave more information.