iPOPO Components¶
A component is an object with a life-cycle, requiring services and providing ones, and associated to properties. The code of a component is reduced to its functional purpose: its life-cycle, dependencies, etc. are handled by iPOPO. In iPOPO, a component is an instance of component factory, i.e. a Python class manipulated with the iPOPO decorators.
Note
Due to the use of Python properties, all component factories must be
new-style classes. It is the case of all Python 3 classes, but Python 2.x
classes must explicitly inherit from the object
class.
Life-cycle¶
The component life cycle is handled by an instance manager created by the iPOPO service. This instance manager will inject control methods, run-time dependencies, and will register the component services. All changes will be notified to the component using the callback methods it decorated.
![iPOPO component life-cycle graph](../_images/component_lifecycle.png)
State | Description |
---|---|
INSTANTIATED | The component has been instantiated. Its constructor has been called and the control methods have been injected |
VALIDATED | All required dependencies have been injected. All services provided by the component will be registered right after this method returned |
KILLED | The component has been invalidated and won’t be usable again |
ERRONEOUS | The component raised an error during its validation. It is not destroyed and a validation can be retried manually |
API¶
iPOPO components are handled through the iPOPO core service, which can itself
be accessed through the Pelix API or the utility context manager
use_ipopo()
.
The core service provides the pelix.ipopo.core
specification.
-
pelix.ipopo.constants.
use_ipopo
(bundle_context)¶ Utility context to use the iPOPO service safely in a “with” block. It looks after the the iPOPO service and releases its reference when exiting the context.
Parameters: bundle_context – The calling bundle context Returns: The iPOPO service Raises: BundleException – Service not found The following snippet shows how to use this method:
from pelix.ipopo.constants import use_ipopo # ... considering "context" being a BundleContext object with use_ipopo(context) as ipopo: # use the iPOPO core service with the "ipopo" variable ipopo.instantiate("my.factory", "my.component", {"some.property": [1, 2, 3], "answer": 42}) # ... out of the "with" context, the iPOPO service has been released # and shouldn't be used
Here are the most commonly used methods from the iPOPO core service to handle components and factories:
-
class
pelix.ipopo.core.
_IPopoService
(bundle_context)¶ The iPOPO registry and service.
This service is registered automatically and must not be started manually.
Parameters: bundle_context – The iPOPO bundle context -
add_listener
(listener)¶ Register an iPOPO event listener.
The event listener must have a method with the following prototype:
def handle_ipopo_event(self, event): ''' event: A IPopoEvent object ''' # ...
Parameters: listener – The listener to register Returns: True if the listener has been added to the registry
-
get_factories
()¶ Retrieves the names of the registered factories
Returns: A list of factories. Can be empty.
-
get_factory_details
(name)¶ Retrieves a dictionary with details about the given factory
name
: The factory namebundle
: The Bundle object of the bundle providing the factoryproperties
: Copy of the components properties defined by the factoryrequirements
: List of the requirements defined by the factoryid
: Requirement ID (field where it is injected)specification
: Specification of the required serviceaggregate
: If True, multiple services will be injectedoptional
: If True, the requirement is optional
services
: List of the specifications of the services provided by components of this factoryhandlers
: Dictionary of the non-built-in handlers required by this factory. The dictionary keys are handler IDs, and it contains a tuple with:- A copy of the configuration of the handler (0)
- A flag indicating if the handler is present or not
Parameters: name – The name of a factory Returns: A dictionary describing the factory Raises: ValueError – Invalid factory
-
get_instance_details
(name)¶ Retrieves a snapshot of the given component instance. The result dictionary has the following keys:
name
: The component namefactory
: The name of the component factorybundle_id
: The ID of the bundle providing the component factorystate
: The current component stateservices
: A{Service ID → Service reference}
dictionary, with all services provided by the componentdependencies
: A dictionary associating field names with the following dictionary:handler
: The name of the type of the dependency handlerfilter
(optional): The requirement LDAP filteroptional
: A flag indicating whether the requirement is optional or notaggregate
: A flag indicating whether the requirement is a set of services or notbinding
: A list of the ServiceReference the component is bound to
properties
: A dictionary key → value, with all properties of the component. The value is converted to its string representation, to avoid unexpected behaviours.
Parameters: name – The name of a component instance Returns: A dictionary of details Raises: ValueError – Invalid component name
-
get_instances
()¶ Retrieves the list of the currently registered component instances
Returns: A list of (name, factory name, state) tuples.
-
instantiate
(factory_name, name, properties=None)¶ Instantiates a component from the given factory, with the given name
Parameters: - factory_name – Name of the component factory
- name – Name of the instance to be started
- properties – Initial properties of the component instance
Returns: The component instance
Raises: - TypeError – The given factory is unknown
- ValueError – The given name or factory name is invalid, or an instance with the given name already exists
- Exception – Something wrong occurred in the factory
-
kill
(name)¶ Kills the given component
Parameters: name – Name of the component to kill Raises: ValueError – Invalid component name
-
remove_listener
(listener)¶ Unregister an iPOPO event listener.
Parameters: listener – The listener to register Returns: True if the listener has been removed from the registry
-
retry_erroneous
(name, properties_update=None)¶ Removes the ERRONEOUS state of the given component, and retries a validation
Parameters: - name – Name of the component to retry
- properties_update – A dictionary to update the initial properties of the component
Returns: The new state of the component
Raises: ValueError – Invalid component name
-
A word on Python 3.7 Data classes¶
These indications have to be taken into account when using iPOPO decorators on data classes. They are also valid when using the dataclasses package for Python 3.6.
Important notes¶
- All fields of the Data Class must have a default value.
This will let the
@dataclass
decorator generate an__init__
method without explicit arguments, which is a requirement for iPOPO. - If the
init=False
argument is given to@dataclass
, it is necessary to implement your own__init__
, defining all fields, otherwise generated methods like__repr__
won’t work.
Good to know¶
- Injected fields (
@Property
,@Requires
, …) will lose the default value given in the class definition, in favor to the ones given to the iPOPO decorators. This is due to the redefinition of the fields by those decorators. Other fields are not touched at all. - The
@dataclass
decorator can be used before or after the iPOPO decorators