iPOPO Decorators

Component definition

Those decorators describe the component. They must decorate the factory class itself.

Factory definition

The factory definition decorator must be unique per class and must always be the last one executed, i.e. the top one in the source code.

class pelix.ipopo.decorators.ComponentFactory(name=None, excluded=None)

Manipulates the component class according to a FactoryContext object filled by other decorators.

This must be the last executed decorator, i.e. the one on top of others in the source code.

If no factory name is given, it will be generated as ClassNameFactory, e.g. a Foo class will have the factory name FooFactory.

Note that the name of the component factory is the only way to identify it in iPOPO. Therefore, it must be unique in a framework instance.

Warning

The __init__() method of a component factory class must not require any parameter.

Example:
@ComponentFactory()
class Foo(object):
    def __init__(self):
        pass

@ComponentFactory('my-factory')
class Bar(object):
   pass

@ComponentFactory()
class FooBar(object):
    def __init__(self, managed=True):
        # The argument has a default value: it can be instantiated by
        # iPOPO
        pass
Parameters:
  • name – Name of the component factory, used to identify it when instantiating a component. This name must be unique in a Pelix framework instance.
  • excluded – List of IDs of handlers which configuration must not be inherited from the parent class
class pelix.ipopo.decorators.SingletonFactory(name=None, excluded=None)

This decorator is a specialization of the ComponentFactory: it accepts the same arguments and follows the same rule, but it allows only one instance of component from this factory at a time.

If the factory is instantiated while another already exist, a ValueError will be raised.

@SingletonFactory()
class Foo(object):
    def __init__(self):
        pass

@SingletonFactory('my-factory')
class Bar(object):
   pass
Parameters:
  • name – Name of the component factory, used to identify it when instantiating a component. This name must be unique in a Pelix framework instance.
  • excluded – List of IDs of handlers which configuration must not be inherited from the parent class

Component properties

class pelix.ipopo.decorators.Property(field, name=None, value=None)

The @Property decorator defines a component instance property. A property can be used to configure the component at instantiation time and to expose the state of a component. Note that component properties are exposed in the properties of the services it publishes with the Provides decorator.

If no initial value is given in the decorator, the value stored in the injected field in the __init__() method will be used.

Warning

In Python 2, it is required that the component class inherits object for properties to work.

Handler ID:pelix.ipopo.constants.HANDLER_PROPERTY
Example:
@ComponentFactory()
@Property('_answer', 'some.answer', 42)
class Foo(object):
    def call(self):
        print(self._answer)  # Prints 42

        # The properties of the services provided by this component
        # instance would be updated during this assignation
        self._answer = 100
Parameters:
  • field – The property field in the class (can’t be None nor empty)
  • name – The property name (if None, this will be the field name)
  • value – The property value (None by default)
Raises:
  • TypeError – Invalid argument type
  • ValueError – If the name or the name is None or empty
class pelix.ipopo.decorators.HiddenProperty(field, name=None, value=None)

The @HiddenProperty decorator defines a component property which won’t be visible in the properties of the services it provides. This kind of property is also not accessible using iPOPO reflection methods.

This decorator has the same handler, accepts the same parameters and follows the same rules as the Property decorator.

Handler ID:pelix.ipopo.constants.HANDLER_PROPERTY
Example:
@ComponentFactory()
@HiddenProperty('_password', 'some.password', "secret")
class Foo(object):
    def call(self):
        print(self._password)  # I think we're missing the point

        # Service properties won't be affected by this change
        self._password = "UpdatedSecret"
Parameters:
  • field – The property field in the class (can’t be None nor empty)
  • name – The property name (if None, this will be the field name)
  • value – The property value (None by default)
Raises:
  • TypeError – Invalid argument type
  • ValueError – If the name or the name is None or empty

Special properties

Note that some properties have a special meaning for iPOPO and Pelix.

Name Type Description
instance.name str The name of the iPOPO component instance (read only)
service.id int The registration number of a service (read only)
service.ranking int The rank (priority) of the services provided by this component
@ComponentFactory()
@Property('_name', 'instance.name')    # Special property
@Property('_value', 'my.value')        # Some property
@Property('_answer', 'the.answer', 42) # Some property, with a default value
class Foo(object):
   def __init__(self):
       self._name = None    # This will overwritten by iPOPO
       self._value = 12     # 12 will be used if this property is not configured
       self._answer = None  # 42 will be used by default

Provided Services

class pelix.ipopo.decorators.Provides(specifications, controller=None, factory=False, prototype=False)

The @Provides decorator defines a service to be exposed by component instances. This service will be registered (visible) in the Pelix service registry while the component is valid and its service controller is set to True.

All the properties of the component defined with the Property decorator will be visible in the service properties.

The controller is an injected field (a Python property) that must contain a boolean. By default, the controller is set to True, i.e. the service will be provided by the component when it is validated.

Handler ID:pelix.ipopo.constants.HANDLER_PROVIDES
Example:
@ComponentFactory()
# "answer.prefix" will be a property of the service
@Property("_answer", "answer.prefix", "Hello")
@Provides("hello.world")
class Foo(object):
    # The component instance will publish a "hello.world" service as
    # long as it is valid
    def greet(self, name):
        print(self._answer, name, "!")

@ComponentFactory()
# This service will provide multiple specifications
@Provides(["hello.world", "hello.world.extended"], "_svc_flag")
@Provides("reset")
class Bar(object):
    def greet(self, name):
        # Implementation of hello.world
        print("Hello,", name, "!")

    def adieu(self, name):
        print("So long,", name, "!")

        # Sets the controller to False: the service won't be published
        # anymore until the controller is set back to True
        self._svc_flag = False

    def reset(self):
        # Implementation of the "reset" service: publish the service
        # again
        self._svc_flag = True
Parameters:
  • specifications – A list of provided specification(s), or the single provided specification (can’t be empty)
  • controller – The name of the service controller class field (optional)
  • factory – If True, this service is a service factory (False by default)
  • prototype – If True, this service is prototype service factory (False by default)
Raises:

ValueError – If the specifications are invalid

Requirements

class pelix.ipopo.decorators.Requires(field, specification, aggregate=False, optional=False, spec_filter=None, immediate_rebind=False)

The @Requires decorator defines the requirement of a service.

Handler ID:pelix.ipopo.constants.HANDLER_REQUIRES
Example:
@ComponentFactory()
@Requires('_hello', 'hello.world')
class Foo(object):
    pass

@ComponentFactory()
@Requires('_hello', 'hello.world', aggregate=True, optional=False,
          spec_filter='(language=fr)')
class Bar(object):
    pass
Parameters:
  • field – The field where to inject the requirement
  • specification – The specification of the service to inject
  • aggregate – If True, injects a list of services, else the first matching service
  • optional – If True, this injection is optional: the component can be valid without it
  • spec_filter – An LDAP query to filter injected services according to their properties
  • immediate_rebind – If True, the component won’t be invalidated then re-validated if a matching service is available when the injected dependency is unbound

The field and specification parameters are mandatory. By default, a requirement is neither aggregated nor optional (both are set to False) and no specification filter is used.

Note

Since iPOPO 0.5.4, only one specification can be given.

class pelix.ipopo.decorators.Temporal(field, specification, optional=False, spec_filter=None, timeout=10)

The @Temporal decorator defines a single immediate rebind requirement with a grace time when the injected service disappears.

This decorator acts like Requires except it doesn’t support the immediate_rebind (forced to True) nor aggregate arguments.

When the injected service disappears, the component won’t be invalidated before the given timeout. If a matching is found, it is injected in-place and the component instance continues its operations. If the service is used while no service is available, the call is put in hold and blocks until a new service is injected or until the timeout is reached. In the latter case, a TemporalException is raised.

Handler ID:pelix.ipopo.constants.HANDLER_TEMPORAL
Example:
@ComponentFactory()
@Temporal('_hello', 'hello.world', timeout=5)
class Bar(object):
    def call(self):
        # If the service is injected: this call is immediate
        # If the service has gone away, this call will hold for
        # 5 seconds (timeout parameter)
        # - if a service is injected during the grace period, the call
        #   will be done
        try:
            self._hello.greet("World")
        except pelix.ipopo.handlers.temporal.TemporalException:
            # - else, a TemporalException is raised
            print("Service disappeared")
Parameters:
  • field – The injected field
  • specification – The injected service specification
  • optional – If True, this injection is optional
  • spec_filter – An LDAP query to filter injected services upon their properties
  • timeout – Temporal timeout, in seconds (must be greater than 0)
Raises:
  • TypeError – A parameter has an invalid type
  • ValueError – An error occurred while parsing the filter or an argument is incorrect
class pelix.ipopo.decorators.RequiresBest(field, specification, optional=False, spec_filter=None, immediate_rebind=True)

The @RequiresBest decorator acts like Requires, but it always injects the service with the best rank (service.ranking property).

Unlike most of the other requirement decorators, @RequiresBest doesn’t support the injection of a list of services (aggregate) as only the best service is injected.

Handler ID:pelix.ipopo.constants.HANDLER_REQUIRES_BEST
Example:
@ComponentFactory()
@RequiresBest('_hello', 'hello.world', immediate_rebind=True)
class Foo(object):
    def call(self):
        # First call, with the current best service
        self._hello.greet("World")  # prints "Hello, World!"

        # Something happens, the rank of "hello.world" services changes
        # For example, locale changed and French now has a higher rank
        time.sleep(1)

        # Second call without waiting for re-validation as we have set
        # immediate_rebind=True for this example
        self._hello.greet("World")  # prints "Bonjour, World !"

# We can also use a specification filter or make the service optional
@ComponentFactory()
@RequiresBest('_hello', 'hello.world', optional=True,
              spec_filter='(language=fr)')
class Bar(object):
    def call(self):
        if self._hello is not None:
            # First call, with the current best service
            self._hello.greet("World")  # prints "Hello, World!"
Parameters:
  • field – The injected field
  • specification – The injected service specification
  • optional – If True, this injection is optional
  • spec_filter – An LDAP query to filter injected services upon their properties
  • immediate_rebind – If True, the component won’t be invalidated then re-validated if a matching service is available when the injected dependency is unbound
Raises:
  • TypeError – A parameter has an invalid type
  • ValueError – An error occurred while parsing the filter or an argument is incorrect
class pelix.ipopo.decorators.RequiresBroadcast(field, specification, optional=True, spec_filter=None, muffle_exceptions=True, trace_exceptions=True)

The @RequiresBroadcast decorator defines a requirement that will be injected as a single object, hiding the underlying missing dependency or group of services matching the requirement.

Unlike Requires, the parameter optional is set to True by default. Also, the aggregate argument is not available, the behaviour of this handler is to broadcast to all matching services.

Handler ID:pelix.ipopo.constants.HANDLER_REQUIRES_BRODCAST
Example:
@ComponentFactory()
@RequiresBroadcast("_notifier", "some.notifier")
class Bar(object):
    def trace(self, message):
        # We can use the service as a single object, without taking
        # care of the number of services matching our requirement:
        self._notifier.notify("Hello, world")
Parameters:
  • field – The injected field
  • specification – The injected service specification
  • optional – If True, this injection is optional
  • spec_filter – An LDAP query to filter injected services upon their properties
  • muffle_exceptions – If True, exceptions raised by underlying services are not propagated (True by default)
  • trace_exceptions – If True, trace the exceptions that are muffled (True by default)
Raises:
  • TypeError – A parameter has an invalid type
  • ValueError – An error occurred while parsing the filter or an argument is incorrect
class pelix.ipopo.decorators.RequiresMap(field, specification, key, allow_none=False, aggregate=False, optional=False, spec_filter=None)

The @RequiresMap decorator defines a requirement that must be injected in a dictionary, based on a service property.

Handler ID:pelix.ipopo.constants.HANDLER_REQUIRES_MAP
Example:
@ComponentFactory()
@RequiresMap("_hello", "hello.world", "language")
class Bar(object):
    def call(self):
        self._hello["en"].hello("World")
        self._hello["fr"].hello("le Monde")
Parameters:
  • field – The injected field
  • specification – The injected service specification
  • key – The name of the service property to use as a dictionary key
  • allow_none – If True, also injects services with the property value set to None or missing
  • aggregate – If True, injects a list of services with the same property value, else injects only one service (first found) per property value
  • optional – If True, this injection is optional
  • spec_filter – An LDAP query to filter injected services upon their properties
Raises:
  • TypeError – A parameter has an invalid type
  • ValueError – An error occurred while parsing the filter or an argument is incorrect
class pelix.ipopo.decorators.RequiresVarFilter(field, specification, aggregate=False, optional=False, spec_filter=None, immediate_rebind=False)

The @RequiresVarFilter decorator acts like Requires, but its LDAP filter dynamically adapts to the properties of this component.

The decorator accepts a component property key using the {key} format in the LDAP filter string. This placeholder will be replaced by the property value, and will the filter will be updated each time the property value changes.

Handler ID:pelix.ipopo.constants.HANDLER_REQUIRES_VARIABLE_FILTER
Example:
@ComponentFactory()
@Property("_lang", "lang", "fr")
@RequiresVarFilter("_hello", "hello.world", optional=True,
                   spec_filter="(language={lang})")
class Bar(object):
    def call(self):
        # The dependency is optional
        if self._hello is not None:
            # Default "lang" instance property is set to "fr"
            self._hello.greet("le Monde")  # Bonjour le Monde

        # Change the property to have another service
        self._lang = "en"

        # We can call the new service immediately as the dependency is
        # optional (no risk of invalidation), but we have to check if
        # such a service exists
        if self._hello is not None:
            self._hello.greet("World")  # Hello World
Parameters:
  • field – The field where to inject the requirement
  • specification – The specification of the service to inject
  • aggregate – If True, injects a list of services, else the first matching service
  • optional – If True, this injection is optional: the component can be valid without it
  • spec_filter – An LDAP query to filter injected services according to their properties
  • immediate_rebind – If True, the component won’t be invalidated then re-validated if a matching service is available when the injected dependency is unbound

The field and specification parameters are mandatory. By default, a requirement is neither aggregated nor optional (both are set to False) and no specification filter is used.

Note

Since iPOPO 0.5.4, only one specification can be given.

Instance definition

class pelix.ipopo.decorators.Instantiate(name, properties=None)

This decorator tells iPOPO to instantiate a component instance from this factory as soon as its bundle is in ACTIVE state.

The properties argument allows to override the default value given in the @Property and @HiddenProperty decorators.

The properties are associated to the component instance but not added to it. This means that new (meta-) properties can be added to add information to the component (like the Remote Services export properties), but those won’t be accessible directly by the component. Those extra properties will be visible in component’s services properties and in the instance properties returned by the iPOPO get_instance_details() method, but no new field will be injected in the component instance.

@ComponentFactory()
@Property('_name', 'name', 'foo')
@Instantiate('component-1')
@Instantiate('component-2', {'name': 'bar'})
class Foo(object):
    def call(self):
        # component-1 will print "foo" (default value)
        # component-2 will print "bar"
        print("My name property is:", self._name)

@ComponentFactory()
@Provides("thermometer")
@Property('_value', 'value', 1)
@Instantiate('component-3', {'unit': 'K'})
class Bar(object):
    def call(self):
        # We don't have access to the "unit" property value, but it
        # will be visible in the service properties
        print("My value is:", self._value)
Parameters:
  • name – The name of the component instance (mandatory)
  • properties – The initial properties of the instance as a dictionary

Life-cycle events

Those decorators store behavioural information on component methods. They must decorate methods in the component class.

Component state

When all its requirements are fulfilled, the component goes into the VALID state. During the transition, it is in VALIDATING state and the following decorators indicate which method must be called at that time. If the decorated method raises an exception, the component goes into the ERRONEOUS state.

class pelix.ipopo.decorators.ValidateComponent(*args)

The @ValidateComponent decorator declares a callback method for component validation.

Currently, the arguments given to the callback are read-only, to avoid messing with the validation life-cycle. In the future, it might be possible to modify the properties and to use the component context in order to customize the component early.

Example:

Here are some sample uses of the decorator. Note that the number and order of arguments only has to match the list given to the decorator:

from pelix.constants import ARG_COMPONENT_CONTEXT, \
    ARG_BUNDLE_CONTEXT, ARG_PROPERTIES

@ValidateComponent(ARG_COMPONENT_CONTEXT)
def validate_component(self, component_ctx):
    # ...

@ValidateComponent(ARG_BUNDLE_CONTEXT, ARG_COMPONENT_CONTEXT)
def validate_component(self, bundle_ctx, component_ctx):
    # ...

@ValidateComponent(
    ARG_BUNDLE_CONTEXT, ARG_COMPONENT_CONTEXT, ARG_PROPERTIES
 )
def validate_component(self, bundle_ctx, component_ctx, props):
    # ...
Parameters:args

The decorator accepts an ordered list of arguments. They define the signature of the decorated method.

The arguments can be the following ones, declared in the pelix.ipopo.constants module:

  • ARG_BUNDLE_CONTEXT: Gives access to the bundle context
  • ARG_COMPONENT_CONTEXT: Gives access to the component context
  • ARG_PROPERTIES: Gives access to the initial properties of the component (dict)
Raises:TypeError – A parameter has an invalid type or the decorated object is not a method
pelix.ipopo.decorators.Validate(method)

This decorator is an alias to ValidateComponent to decorate a callback method than only accepts the BundleContext argument. It is not possible to have both @Validate and @ValidateComponent decorators used in the same class.

The validation callback decorator is called when a component becomes valid, i.e. if all of its required dependencies has been injected.

If the validation callback raises an exception, the component goes into ERRONEOUS state.

If the component provides a service, the validation method is called before the provided service is registered to the framework.

Example:
@ComponentFactory()
class Foo:
    @Validate
    def validation_method(self, bundle_context):
        '''
        bundle_context: The component's bundle context
        '''
        # ...
Parameters:method – The validation callback method
Raises:TypeError – The decorated element is not a valid function

When one of its requirements is missing, or when it is killed, the component goes into the INVALID state. During the transition, it is in INVALIDATING state and the following decorators indicate which method must be called at that time.

Exceptions raised by the decorated method are ignored.

pelix.ipopo.decorators.InvalidateComponent(*args)

The @InvalidateComponent decorator declares a callback method for component invalidation.

Its arguments and their order describes the ones of the callback it decorates. They are the same as those of ValidateComponent.

Exceptions raised by an invalidation callback are ignored.

If the component provides a service, the invalidation method is called after the provided service has been unregistered to the framework.

pelix.ipopo.decorators.Invalidate(method)

This decorator is an alias to InvalidateComponent to decorate a callback method than only accepts the BundleContext argument. It is not possible to have both @Invalidate and @InvalidateComponent decorators used in the same class.

The invalidation callback decorator is called when a component becomes invalid, i.e. if one of its required dependencies disappeared.

Exceptions raised by an invalidation callback are ignored.

If the component provides a service, the invalidation method is called after the provided service has been unregistered to the framework.

Example:
@ComponentFactory()
class Foo:
    @Invalidate
    def invalidation_method(self, bundle_context):
        '''
        bundle_context: The component's bundle context
        '''
        # ...
Parameters:method – The decorated method
Raises:TypeError – The decorated element is not a function

Injections

pelix.ipopo.decorators.Bind(method)

The @Bind callback decorator is called when a component is bound to a dependency.

The decorated method must accept the injected service object and its ServiceReference as arguments.

If the service is a required one, the bind callback is called before the component is validated.

The service reference can be stored if it is released on unbind.

Exceptions raised by a bind callback are ignored.

Example:
@ComponentFactory()
@Requires("_hello", "hello.svc")
class Foo:
    @Bind
    def bind_method(self, service, service_reference):
        '''
        service: The injected service instance.
        service_reference: The injected service ServiceReference
        '''
        # ...
Parameters:method – The decorated method
Raises:TypeError – The decorated element is not a valid function
class pelix.ipopo.decorators.BindField(field, if_valid=False)

The @BindField callback decorator is called when a component is bound to a dependency, injected in the given field.

The decorated method must accept the field where the service has been injected, the service object and its ServiceReference as arguments.

If the service is a required one, the bind callback is called before the component is validated. The bind field callback is called after the global bind method.

The service reference can be stored if it is released on unbind.

Exceptions raised by a bind callback are ignored.

Example:
@ComponentFactory()
@Requires("_hello", "hello.svc")
class Foo:
   @BindField("_hello")
   def bind_method(self, field, service, service_reference):
       '''
       field: Field wherein the dependency is injected ("_hello")
       service: The injected service instance
       service_reference: The injected service ServiceReference
       '''
       # ...
Parameters:
  • field – The field associated to the binding
  • if_valid – If True, call the decorated method only when the component is valid
pelix.ipopo.decorators.Update(method)

The @Update callback decorator is called when the properties of an injected service have been modified.

The decorated method must accept the injected service object and its ServiceReference and the previous properties as arguments.

Exceptions raised by an update callback are ignored.

Example:
@ComponentFactory()
@Requires("_hello", "hello.svc")
class Foo:
    @Update
    def update_method(self, service, service_reference, old_properties):
        '''
        service: The injected service instance.
        service_reference: The injected service ServiceReference
        old_properties: The previous service properties
        '''
        # ...
Parameters:method – The decorated method
Raises:TypeError – The decorated element is not a valid function
class pelix.ipopo.decorators.UpdateField(field, if_valid=False)

The @UpdateField callback decorator is called when the properties of a service injected in the given field have been updated.

The decorated method must accept the field where the service has been injected, the service object, its ServiceReference and its previous properties as arguments.

Exceptions raised by an update callback are ignored.

Example:
@ComponentFactory()
@Requires("_hello", "hello.svc")
class Foo:
   @UpdateField("_hello")
   def update_method(self, service, service_reference, old_properties):
       '''
       field: Field wherein the dependency was injected ("_hello")
       service: The injected service instance
       service_reference: The injected service ServiceReference
       old_properties: The previous service properties
       '''
       # ...
Parameters:
  • field – The field associated to the binding
  • if_valid – If True, call the decorated method only when the component is valid
pelix.ipopo.decorators.Unbind(method)

The @Unbind callback decorator is called when a component dependency is unbound.

The decorated method must accept the injected service object and its ServiceReference as arguments.

If the service is a required one, the unbind callback is called after the component has been invalidated.

Exceptions raised by an unbind callback are ignored.

Example:
@ComponentFactory()
@Requires("_hello", "hello.svc")
class Foo:
    @Unbind
    def unbind_method(self, service, service_reference):
        '''
        service: The previously injected service instance.
        service_reference: Its ServiceReference
        '''
        # ...
Parameters:method – The decorated method
Raises:TypeError – The decorated element is not a valid function
class pelix.ipopo.decorators.UnbindField(field, if_valid=False)

The @UnbindField callback decorator is called when an injected dependency is unbound.

The decorated method must accept the field where the service has been injected, the service object, its ServiceReference and its previous properties as arguments.

If the service is a required one, the unbind callback is called after the component has been invalidated. The unbind field callback is called before the global unbind method.

Exceptions raised by an unbind callback are ignored.

Example:
@ComponentFactory()
@Requires("_hello", "hello.svc")
class Foo:
   @UnbindField("_hello")
   def unbind_method(self, field, service, service_reference):
       '''
       field: Field wherein the dependency was injected ("_hello")
       service: The injected service instance
       service_reference: The injected service ServiceReference
       '''
       # ...
Parameters:
  • field – The field associated to the binding
  • if_valid – If True, call the decorated method only when the component is valid

Service state

pelix.ipopo.decorators.PostRegistration(method)

The service post-registration callback decorator is called after a service of the component has been registered to the framework.

The decorated method must accept the ServiceReference of the registered service as argument.

Note that when this method is called, the consumers have already been bound and might already use the service.

Example:
@ComponentFactory()
@Provides("hello.svc")
class Foo:
    @PostRegistration
    def callback_method(self, service_reference):
        '''
        service_reference: The ServiceReference of the provided service
        '''
        # Custom notification, ...
Parameters:method – The decorated method
Raises:TypeError – The decorated element is not a valid function
pelix.ipopo.decorators.PostUnregistration(method)

The service post-unregistration callback decorator is called after a service of the component has been unregistered from the framework.

The decorated method must accept the ServiceReference of the registered service as argument.

This method being called after the unregistration, the consumers of the service should have already released it and should not be using it while this callback is notified. This is True by design for consumers managed by the Requires decorator in iPOPO, but some others (badly written or very specific design) might keep a reference on the service even after its unregistration.

Example:
@ComponentFactory()
@Provides("hello.svc")
class Foo:
    @PostUnregistration
    def callback_method(self, service_reference):
        '''
        service_reference: The ServiceReference of the provided service
        '''
        # Clean up, ...
Parameters:method – The decorated method
Raises:TypeError – The decorated element is not a valid function