aglyph.assembler — The Aglyph component assembler

Release:2.1.1

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)[source]

Bases: object

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

Parameters:context (aglyph.context.Context) – a mapping of unique IDs to component and template definitions
assemble(component_spec)[source]

Create an object identified by component_spec and inject its dependencies.

Parameters:

component_spec – used to determine the dotted name or component unique 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 already a string, it is assumed to represent a component unique ID and is used as-is. Otherwise, aglyph.format_dotted_name() is used 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()[source]

Assemble and cache all singleton component objects.

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(XMLContext("my-context.xml"))
assembler.init_singletons()
# -OR-
binder = MyBinder()
binder.init_singletons()
Returns:the initialized singleton component IDs
Return type:list

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()[source]

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()[source]

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

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(XMLContext("my-context.xml"))
assembler.init_borgs()
# -OR-
binder = MyBinder()
binder.init_borgs()
Returns:the initialized borg component IDs
Return type:list

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()[source]

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()[source]

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.