************************ 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 =================== .. autofunction:: featuremonkey.compose .. autofunction:: featuremonkey.compose_later Feature Layout =================== Product Selection =================== .. autofunction:: featuremonkey.select .. autofunction:: featuremonkey.select_equation