featuremonkey Reference

Feature Structure Trees

featuremonkey recognizes python packages, modules, classes, functions and methods as being part of the FST.

FST Declaration

FSTs are declared as modules or classes depending on the preference of the user. modules and classes can be mixed arbitrarily.

Note

when using classes, please make sure to use new style classes. Old style classes are completely unsupported by featuremonkey - because they are old and are removed from the python language with 3.0. To create a new style class, simply inherit from object or another new style class explicitely.

FSTs specify introductions and refinements of structures contained in the global interpreter state. This is done by defining specially crafted names inside the FST module/class.

FST Introduction

Introductions are useful to add new attributes to existing packages/modules/classes/instances.

An introduction is specified by creating a name starting with introduce_ followed by the name to introduce directly inside the FST module/class. The attribute value will be used like so to derive the value to introduce:

  • If the FST attribute value is not callable, it is used as the value to introduce without further processing.
  • If it is a callable, it is called to obtain the value to introduce. The callable will be called without arguments and must return this value.

Example:

class TestFST1(object):
    #introduce name ``a`` with value ``7``
    introduce_a = 7

    #introduce name ``b`` with value ``6``
    def introduce_b(self):
        return 6

    #introduce method ``foo`` that returns ``42`` when called
    def introduce_foo(self):
        def foo(self):
            return 42

        return foo

Warning

Names can only be introduced if they do not already exist in the current interpreter state. Otherwise compose will raise a CompositionError. If that happens, the product may be in an inconsistent state. Consider restarting the whole product!

FST Refinement

Refinements are used to refine existing attributes of packages/modules/classes/instances.

An introduction is specified much like an introduction. It is done by creating a name starting with refine_ followed by the name to refine directly inside the FST module/class. The attribute value will be used like so to derive the value to introduce:

  • If the FST attribute value is not callable, it is used as the refined value without further processing. This is a replacement
  • If it is a callable e.g. a method, it is called to obtain the refined value. The callable will be called with the single argument original and must return this value. original is a reference to the current implementation of the name that is to be refined. It is analogous to super in OOP.

Example:

class TestFST1(object):
    #refine name ``a`` with value ``7``
    refine_a = 7

    #refine name ``b`` with value ``6``
    def introduce_b(self, original):
        return 6

    #refine method ``foo`` to make it return double the value of before.
    def refine_foo(self, original):
        def foo(self):
            return orginal(self) * 2

        return foo

Note

when calling original in a method refinement(for both classes and instances), you need to explicitely pass self as first parameter to original.

Warning

Names can only be refined if they exist in the current interpreter state. Otherwise compose will raise a CompositionError. If that happens, the product may be in an inconsistent state. Consider restarting the whole product!

FST nesting

FSTs can be nested to refine nested structures of the interpreter state. To create a child FST node, create a name starting with child_ followed by the nested name. The value must be either a FST class or instance or a FST module. As an example, consider a refinement to the os module. We want to introduce os.foo and also refine os.path.join. We could do this by composing a FST on os to introduce foo and then composing another FST on os.path that refines join. Alternatively, we can use FST nesting and specify it as follows:

class os(object):
    introduce_foo = 123
    class child_path(object):
        def refine_join(self, original):
            def join(*elems):
                return original(elems)
            return join

Got it?

FST Composition

featuremonkey.compose(self, *things)

compose applies multiple fsts onto a base implementation. Pass the base implementation as last parameter. fsts are merged from RIGHT TO LEFT (like function application) e.g.:

class MyFST(object):
#place introductions and refinements here introduce_foo = ‘bar’

compose(MyFST(), MyClass)

featuremonkey.compose_later(self, *things)

register list of things for composition using compose()

compose_later takes a list of fsts. The last element specifies the base module as string things are composed directly after the base module is imported by application code

Feature Layout

Product Selection

featuremonkey.select(self, *features)

selects the features given as string e.g passing ‘hello’ and ‘world’ will result in imports of ‘hello’ and ‘world’. Then, if possible ‘hello.feature’ and ‘world.feature’ are imported and select is called in each feature module.

featuremonkey.select_equation(self, filename)

Project Versions

Table Of Contents

Previous topic

Installation

This Page