Skip to main content

Make any type binary-combinable with a single line of code.

Project description

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, but bincombo is 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 type Check, 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 the combinable() 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, Check objects 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!")  # True

The combinable() decorator creates a number of types needed to represent discrete checks and combinations thereof. These are stored in a Config object, which is aavailable as class attribute BIN_CONFIG of Check. It can be worth storing these types as module attributes alongside your Check class 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_type

All types in this module have __slots__ defined for smaller memory footprints and improved lookup times, as have the types created by combinable(). 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 make Check binary-combinable without using the combinable() 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 of combinable(), combine_members() and Config have more information.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bincombo-0.2.0.tar.gz (8.0 kB view details)

Uploaded Source

Built Distribution

bincombo-0.2.0-py3-none-any.whl (10.0 kB view details)

Uploaded Python 3

File details

Details for the file bincombo-0.2.0.tar.gz.

File metadata

  • Download URL: bincombo-0.2.0.tar.gz
  • Upload date:
  • Size: 8.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.6.1 CPython/3.9.2 Linux/5.10.0-26-amd64

File hashes

Hashes for bincombo-0.2.0.tar.gz
Algorithm Hash digest
SHA256 74793858bb6a09f627a3ed5c62b8259d46db4d0a281b88074403e56531f27308
MD5 c3d840635a00282414dd350316786f0b
BLAKE2b-256 fa15a8c835cac73d67489813b8a777e2d526e623dcd0e536e630797f44266689

See more details on using hashes here.

File details

Details for the file bincombo-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: bincombo-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 10.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.6.1 CPython/3.9.2 Linux/5.10.0-26-amd64

File hashes

Hashes for bincombo-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cba619f07e4e54a70de4906a0c8b0ca900e1f04402c9652b82cfbba1cdb1407d
MD5 32521382e14a9b6a873847a8475ccd65
BLAKE2b-256 d0d22fe6cb9b29358a4d9f5979b318c4341b3a26bbc53a0605d06f1869aa3f7a

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page