muster

a responsive classes framework


Keywords
attrs, traits, traitlets, descriptors, validation, observe, callbacks
License
MIT
Install
pip install muster==0.0.1

Documentation

Muster

A streamlined framework for responsive classes.

Summary

Muster, is a descriptor callback framework, that is both approachable, and extremely extensible. Other frameworks have been approachable and others extensible, but few, if any have been both. Muster uses specialized metaclass, but manages to remain agnostic about the user's class model. Despite this, Muster still allows you to define customized callbacks to arbitrary object mutations. The former means that creating classes with Muster is about as simple as it gets, and the latter makes the framework extremely adaptable. To accomplish this, Muster uses three core concepts:

  1. Models - the place where Members live
  2. Members - the things directives control
  3. Directives - manage Member operations

Models

A Model is simply a class which inherits from muster.Model

from muster import Model

class A(Model):
    """This is my Model."""
    pass

so you're pretty much free to do whatever you want!

Unless you're concerned with the dark arts of metaclasses.

Members

Members are objects which exist on classes. Without directives, Members like x act prety much like any other attribute:

from muster import Model, Member

class A(Model):
    x = Member()
  • setting values
a.x = 1
  • getting values
print(a.x)
  • and deleting values
del a.x

Directives

Directives are string annotations which are identified by the Member descriptors they refer to, and trigger a response from the Member. This is achieved by performing two seperate operations that leverage regex patterns - the first determines whether a directive refers to a particular Member, while the second figures out whether the Member knows of the directive. Once this is done, a corresponding method is called which understands how to carry out the directive. While there is a base class which can support any kind of directive Member descriptors know of two basic ones: "before ..." and "after..." with the following supported actions:

  • "setting" - occurs when the member is set
  • "deleting" - occurs when the member is deleted
  • "default" - occurs when the member is retrieved but has no value.

"before <action> <member>"

A "before" directive allows you to register a callback that will be triggered before a Member's method is called.

For example:

from muster import Model, Member

class A(Model):

    x = Member()
    
    _x_is_int : "before setting x"
    
    def _x_is_int(self, member, data):
        data["value"] = int(data["value"])

In this example setting corresponds to a supported <action> and x refers to the <member> that should respond to the directive.

"after <action> <member>"

A "after" directive allows you to register a callback that will be triggered after a Member's method is called.

from muster import Model, Member

class A(Model):

    x = Member()
    
    _x_old : "before setting x"
    _x_change : "after setting x"
    
    def _x_old(self, member, data):
        data["old"] = getattr(self, "x", None)

    def _x_change(self, member, data):
        msg = "x : %r => %r"
        info = (data["old"], data["value"])
        print(msg % info)

A().x = 1
# x : None => 1

In this example we see a "before" directive used in conjunction with an "after" directive. Similarly to the "before" directive, in "after", setting corresponds to a supported <action> and x refers to the <member> that should respond to the directive.