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. aFoo
class will have the factory nameFooFactory
.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 theProvides
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
- field – The property field in the class (can’t be
-
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
- field – The property field in the class (can’t be
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 toTrue
.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
andspecification
parameters are mandatory. By default, a requirement is neither aggregated nor optional (both are set toFalse
) 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 theimmediate_rebind
(forced toTrue
) noraggregate
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 likeRequires
, 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 parameteroptional
is set toTrue
by default. Also, theaggregate
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 likeRequires
, 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
andspecification
parameters are mandatory. By default, a requirement is neither aggregated nor optional (both are set toFalse
) 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 contextARG_COMPONENT_CONTEXT
: Gives access to the component contextARG_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 theBundleContext
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 theBundleContext
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