aglyph.assembler — The Aglyph component assembler — Aglyph 3.0.0 documentation

# `aglyph.assembler` — The Aglyph component assembler

Release: | 3.0.0

The Aglyph assembler creates application objects from component definitions, injecting dependencies into those objects through initialization arguments and keywords, attributes, setter methods, and/or properties.

Application components and their dependencies are defined in an `aglyph.context.Context`, which is used to initialize an assembler.

An assembler provides thread-safe caching of singleton component instances, borg component shared-states (i.e. instance `__dict__` references), and weakref component instance weak references.

class `aglyph.assembler.` `Assembler`(context)

  Bases: `object`

  Create application objects using type 2 (setter) and type 3 (constructor) dependency injection.

  Parameters: | context (aglyph.context.Context) – a context object mapping unique IDs to component and template definitions

  `assemble`(component_spec)

    Create an object identified by component_spec and inject its dependencies.

    Parameters: | component_spec – a unique component ID, or an object whose dotted name is a unique component ID
    Returns: | a complete object with all of its resolved dependencies
    Raises: | KeyError – if component_spec does not identify a component in this assembler’s context aglyph.AglyphError – if component_spec causes a circular dependency

    If component_spec is a string, it is assumed to be a unique component ID and is used as-is. Otherwise, `aglyph.format_dotted_name()` is called to convert component_spec into a dotted name string, which is assumed to be the component’s unique ID.

    How a component object is assembled (created, initialized, wired, and returned) is determined by the component’s `aglyph.component.Component.strategy`:

    “prototype”

      A new object is always created, initialized, wired, and returned.

      This is the default assembly strategy for Aglyph components.

    “singleton”

      If the component has been assembled already during the current application lifetime and there has been no intervening call to `clear_singletons()`, then a cached reference to the object is returned.

      Otherwise, a new object is created, initialized, wired, cached, and returned.

      Singleton component objects are cached by their `aglyph.component.Component.unique_id`.

      Note

      Assembly of singleton components is a thread-safe operation.

    “borg”

      If the component has been assembled already during the current application lifetime and there has been no intervening call to `clear_borgs()`, then a new instance is created and a cached reference to the shared-state is directly assigned to the instance `__dict__`.

      Otherwise, a new instance is created, initialized, and wired; its instance `__dict__` is cached; and the instance is returned.

      Borg component instance shared-states are cached by their `aglyph.component.Component.unique_id`.

      Note

      Assembly of borg components is a thread-safe operation.

      Warning

      The borg assembly strategy is only supported for components whose objects have an instance `__dict__`.

      This means that components using builtin classes, or components using classes that define or inherit a `__slots__` member, cannot be declated as borg components.

    New in version 2.1.0: support for the “weakref” assembly strategy

    “weakref”

      In the simplest terms, this is a “prototype” that can exhibit “singleton” behavior: as long as there is at least one “live” reference to the assembled object in the application runtime, then requests to assemble this component will return the same (cached) object.

      When the only reference to the assembled object that remains is the cached (weak) reference, the Python garbage collector is free to destroy the object, at which point it is automatically removed from the Aglyph cache. Subsequent requests to assemble the same component will cause a new object to be created, initialized, wired, cached (as a weak reference), and returned.

      Note

      Please refer to the `weakref` module for a detailed explanation of weak reference behavior.

    New in version 2.0.0: Either `aglyph.component.Component.factory_name` or `aglyph.component.Component.member_name` may be defined to exercise more control over how a component object is created and initialized. Refer to the linked documentation for details.

    Note

    This method is called recursively to assemble any dependency of component_spec that is defined as a `aglyph.component.Reference`.

  `init_singletons`()

    Assemble and cache all singleton component objects.

    Returns: | the initialized singleton component IDs
    Return type: | `list`

    This method may be called at any time to “prime” the internal singleton cache. For example, to eagerly initialize all singleton components for your application:

        assembler = Assembler(my_context)
        assembler.init_singletons()

    Note

    Only singleton components that do not already have cached objects will be initialized by this method.

    Initialization of singleton component objects is a thread-safe operation.

  `clear_singletons`()

    Evict all cached singleton component objects.

    Returns: | the evicted singleton component IDs
    Return type: | `list`

    Aglyph makes the following guarantees:

    1. All cached singleton objects’ “before_clear” lifecycle methods are called (if specified) when they are evicted from cache.
    2. The singleton cache will be empty when this method terminates.

    Note

    Any exception raised by a “before_clear” lifecycle method is caught, logged, and issued as a `RuntimeWarning`.

    Eviction of cached singleton component objects is a thread-safe operation.

  `init_borgs`()

    Assemble and cache the shared-states for all borg component objects.

    Returns: | the initialized borg component IDs
    Return type: | `list`

    This method may be called at any time to “prime” the internal borg cache. For example, to eagerly initialize all borg component shared-states for your application:

        assembler = Assembler(my_context)
        assembler.init_borgs()

    Note

    Only borg components that do not already have cached shared-states will be initialized by this method.

    Initialization of borg component shared-states is a thread-safe operation.

  `clear_borgs`()

    Evict all cached borg component shared-states.

    Returns: | the evicted borg component IDs
    Return type: | `list`

    Aglyph makes the following guarantees:

    1. All cached borg shared-states’ “before_clear” lifecycle methods are called (if specified) when they are evicted from cache.
    2. The borg cache will be empty when this method terminates.

    Note

    Any exception raised by a “before_clear” lifecycle method is caught, logged, and issued as a `RuntimeWarning`.

    Eviction of cached borg component shared-states is a thread-safe operation.

  `clear_weakrefs`()

    Evict all cached weakref component objects.

    Returns: | the evicted weakref component IDs
    Return type: | `list`

    Aglyph makes the following guarantees:

    1. IF a cached weakref object is still available AND the component definition specifies a “before_clear” lifecycle method, Aglyph will call that method when the object is evicted.
    2. The weakref cache will be empty when this method terminates.

    Note

    Any exception raised by a “before_clear” lifecycle method is caught, logged, and issued as a `RuntimeWarning`.

    Eviction of cached weakref component objects is a thread-safe operation.

    Warning

    While eviction of weakref components is a thread-safe operation with respect to explicit modification of the weakref cache (i.e. any other thread attempting to `assemble()` a weakref component or to `clear_weakrefs()` will be blocked until this method returns), the nature of weak references means that entries may still “disappear” from the cache even while the cache lock is held.

    With respect to cache-clearing, this means that referent component objects may no longer be available even after the cache lock has been acquired and the weakref component IDs (keys) are retrieved from the cache. Practically speaking, this means that callers must be aware of two things:

    1. Aglyph cannot guarantee that “before_clear” lifecycle methods are called on weakref component objects, because there is no guarantee that a cached weak references is “live.” (This is the nature of weak references.)
    2. Aglyph will only return the component IDs of weakref component objects that were “live” at the moment they were cleared.

    Please refer to the `weakref` module for a detailed explanation of weak reference behavior.

  `__contains__`(component_spec)

    Tell whether or not the component identified by component_spec is defined in this assembler’s context.

    Parameters: | component_spec – used to determine the dotted name or component unique ID
    Returns: | `True` if component_spec identifies a component that is defined in this assembler’s context, else `False`

    Note

    Any component_spec for which this method returns `True` can be assembled by this assembler.

    Accordingly, this method will return `False` if component_spec actually identifies a `aglyph.component.Template` defined in this assembler’s context.