def _comparator_eq(filter_value, tested_value): """ Tests if the filter value is equal to the tested value """ if isinstance(tested_value, ITERABLES): # Convert the list items to strings for value in tested_value: # Try with the string conversion if not is_string(value): value = repr(value) if filter_value == value: # Match ! return True # Standard comparison elif not is_string(tested_value): # String vs string representation return filter_value == repr(tested_value) else: # String vs string return filter_value == tested_value return False
def _comparator_approximate_star(filter_value, tested_value): """ Tests if the filter value, which contains a joker, is nearly equal to the tested value. If the tested value is a string or an array of string, it compares their lower case forms """ lower_filter_value = filter_value.lower() if is_string(tested_value): # Lower case comparison return _comparator_star(lower_filter_value, tested_value.lower()) elif hasattr(tested_value, "__iter__"): # Extract a list of strings new_tested = [ value.lower() for value in tested_value if is_string(value) ] if _comparator_star(lower_filter_value, new_tested): # Value found in the strings return True # Compare the raw values return _comparator_star(filter_value, tested_value) or _comparator_star( lower_filter_value, tested_value )
def __init__(self, field=None, name=None, value=None): """ Sets up the property :param field: The property field in the class (can't be None nor empty) :param name: The property name (if None, this will be the field name) :param value: The property value :raise TypeError: Invalid argument type :raise ValueError: If the name or the name is None or empty """ # Field validity test if not is_string(field): raise TypeError("Field name must be a string") field = field.strip() if not field or ' ' in field: raise ValueError("Empty or invalid property field name '{0}'" .format(field)) # Name validity test if name is not None: if not is_string(name): raise TypeError("Property name must be a string") name = name.strip() if not name: # No name given: use the field name name = field self.__field = field self.__name = name self.__value = value
def _comparator_approximate_star(filter_value, tested_value): """ Tests if the filter value, which contains a joker, is nearly equal to the tested value. If the tested value is a string or an array of string, it compares their lower case forms """ lower_filter_value = filter_value.lower() if is_string(tested_value): # Lower case comparison return _comparator_star(lower_filter_value, tested_value.lower()) elif hasattr(tested_value, '__iter__'): # Extract a list of strings new_tested = [value.lower() for value in tested_value if is_string(value)] if _comparator_star(lower_filter_value, new_tested): # Value found in the strings return True # Compare the raw values return _comparator_star(filter_value, tested_value) \ or _comparator_star(lower_filter_value, tested_value)
def instantiate(self, factory_name, name, properties=None): """ Instantiates a component from the given factory, with the given name :param factory_name: Name of the component factory :param name: Name of the instance to be started :return: The component instance :raise TypeError: The given factory is unknown :raise ValueError: The given name or factory name is invalid, or an instance with the given name already exists :raise Exception: Something wrong occurred in the factory """ # Test parameters if not factory_name or not is_string(factory_name): raise ValueError("Invalid factory name") if not name or not is_string(name): raise ValueError("Invalid component name") if not self.running: # Stop working if the framework is stopping raise ValueError("Framework is stopping") with self.__instances_lock: if name in self.__instances or name in self.__waiting_handlers: raise ValueError( "'{0}' is an already running instance name".format(name)) with self.__factories_lock: # Can raise a TypeError exception factory, factory_context = \ self.__get_factory_with_context(factory_name) # Create component instance try: instance = factory() except: _logger.exception( "Error creating the instance '%s' " "from factory '%s'", name, factory_name) raise TypeError("Factory '{0}' failed to create '{1}'".format( factory_name, name)) # Normalize the given properties properties = \ self._prepare_instance_properties(properties, factory_context.properties) # Set up the component instance context component_context = ComponentContext(factory_context, name, properties) # Try to instantiate the component immediately if not self.__try_instantiate(component_context, instance): # A handler is missing, put the component in the queue self.__waiting_handlers[name] = (component_context, instance) return instance
def instantiate(self, factory_name, name, properties=None): """ Instantiates a component from the given factory, with the given name :param factory_name: Name of the component factory :param name: Name of the instance to be started :return: The component instance :raise TypeError: The given factory is unknown :raise ValueError: The given name or factory name is invalid, or an instance with the given name already exists :raise Exception: Something wrong occurred in the factory """ # Test parameters if not factory_name or not is_string(factory_name): raise ValueError("Invalid factory name") if not name or not is_string(name): raise ValueError("Invalid component name") if not self.running: # Stop working if the framework is stopping raise ValueError("Framework is stopping") with self.__instances_lock: if name in self.__instances or name in self.__waiting_handlers: raise ValueError("'{0}' is an already running instance name" .format(name)) with self.__factories_lock: # Can raise a TypeError exception factory, factory_context = \ self.__get_factory_with_context(factory_name) # Create component instance try: instance = factory() except: _logger.exception("Error creating the instance '%s' " "from factory '%s'", name, factory_name) raise TypeError("Factory '{0}' failed to create '{1}'" .format(factory_name, name)) # Normalize the given properties properties = \ self._prepare_instance_properties(properties, factory_context.properties) # Set up the component instance context component_context = ComponentContext(factory_context, name, properties) # Try to instantiate the component immediately if not self.__try_instantiate(component_context, instance): # A handler is missing, put the component in the queue self.__waiting_handlers[name] = (component_context, instance) return instance
def __init__(self, specification, aggregate=False, optional=False, spec_filter=None): """ Sets up the requirement :param specification: The requirement specification, which must be unique and can't be None :param aggregate: If true, this requirement represents a list :param optional: If true, this requirement is optional :param spec_filter: A filter to select dependencies :raise TypeError: A parameter has an invalid type :raise ValueError: An error occurred while parsing the filter """ if not is_string(specification): raise TypeError("A Requirement specification must be a string") if not specification: raise ValueError("No specification given") self.specification = specification self.aggregate = aggregate self.optional = optional # Original filter keeper self.__original_filter = None # Full filter (with the specification test) self.__full_filter = None # Set up the requirement filter (after setting up self.specification) self.filter = None self.set_filter(spec_filter)
def get_ldap_filter(ldap_filter): # type: (Any) -> Optional[Union[LDAPFilter, LDAPCriteria]] """ Retrieves the LDAP filter object corresponding to the given filter. Parses it the argument if it is an LDAPFilter instance :param ldap_filter: An LDAP filter (LDAPFilter or string) :return: The corresponding filter, can be None :raise ValueError: Invalid filter string found :raise TypeError: Unknown filter type """ if ldap_filter is None: return None if isinstance(ldap_filter, (LDAPFilter, LDAPCriteria)): # No conversion needed return ldap_filter elif is_string(ldap_filter): # Parse the filter return _parse_ldap(ldap_filter) # Unknown type raise TypeError( "Unhandled filter type {0}".format(type(ldap_filter).__name__) )
def get_widget(self, parent): """ Returns the widget to be shown in the framework information panel :param parent: The parent UI container :return: A Qt widget """ # Make the table self._table = QtGui.QTableWidget(0, 3, parent) self._table.setHorizontalHeaderLabels(('ID', 'Name', 'Status')) self._table.verticalHeader().hide() # Fill it for bid, name in self._probe.get_bundles().items(): # JSON-RPC converts integer keys into strings if is_string(bid): bid = int(bid) # Get the state state = self._probe.get_bundle_state(bid) # Append the line self.__append_line(bid, name, state) # Sort the lines self._table.sortItems(0) return self._table
def _deserialize_properties(props): """ Converts properties values into their type """ new_props = {} for key, value in props.items(): key = to_str(key) if is_bytes(value): # Convert value to string if necessary value = to_str(value) try: try: new_props[key] = json.loads(value) except (TypeError, ValueError): if is_string(value) and value.startswith("pelix-type:"): # Pseudo-serialized value_type, value = value.split(":", 3)[2:] if '.' in value_type and value_type not in value: # Not a builtin type... _logger.warning("Won't work: %s (%s)", value, value_type) new_props[key] = eval(value) else: # String new_props[key] = value except Exception as ex: _logger.error("Can't deserialize %s: %s", value, ex) return new_props
def __init__(self, specifications, controller=None): """ Sets up a provided service. A service controller can be defined to enable or disable the service. :param specifications: A list of provided interface(s) name(s) (can't be empty) :param controller: Name of the service controller class field (optional) :raise ValueError: If the specifications are invalid """ if controller is not None: if not is_string(controller): raise ValueError("Controller name must be a string") controller = controller.strip() if not controller: # Empty controller name _logger.warning("Empty controller name given") controller = None elif ' ' in controller: raise ValueError("Controller name contains spaces") self.__specifications = _get_specifications(specifications) self.__controller = controller
def _register_factory(self, factory_name, factory, override): # type: (str, type, bool) -> None """ Registers a component factory :param factory_name: The name of the factory :param factory: The factory class object :param override: If true, previous factory is overridden, else an exception is risen if a previous factory with that name already exists :raise ValueError: The factory name already exists or is invalid :raise TypeError: Invalid factory type """ if not factory_name or not is_string(factory_name): raise ValueError("A factory name must be a non-empty string") if not inspect.isclass(factory): raise TypeError("Invalid factory class '{0}'".format( type(factory).__name__)) with self.__factories_lock: if factory_name in self.__factories: if override: _logger.info("Overriding factory '%s'", factory_name) else: raise ValueError( "'{0}' factory already exist".format(factory_name)) self.__factories[factory_name] = factory # Trigger an event self._fire_ipopo_event(constants.IPopoEvent.REGISTERED, factory_name)
def __init__(self, uid, framework, configurations, name, specifications, properties): # type: (str, str, Any[str, List[str]], Optional[str], List[str], dict) -> None """ :param uid: Unique identified of the end point :param framework: UID of the framework exporting the end point (can be None) :param configurations: Kinds of end point (xmlrpc, ...) :param name: Name of the end point :param specifications: Specifications of the exported service :param properties: Properties of the service """ self.__uid = uid self.__fw_uid = framework or None self.__name = name self.__properties = properties.copy() if properties else {} # Normalize list of configurations if is_string(configurations): tuple_conf = (configurations,) # type: Tuple[str, ...] else: tuple_conf = tuple(configurations) self.__configurations = tuple_conf # Extract the language prefix in specifications self.__specifications = extract_specifications( specifications, self.__properties) # Public variable: the source server, # set up by a Pelix discovery service self.server = None # type: str
def _register_factory(self, factory_name, factory, override): """ Registers a component factory :param factory_name: The name of the factory :param factory: The factory class object :param override: If true, previous factory is overridden, else an exception is risen if a previous factory with that name already exists :raise ValueError: The factory name already exists or is invalid :raise TypeError: Invalid factory type """ if not factory_name or not is_string(factory_name): raise ValueError("A factory name must be a non-empty string") if not inspect.isclass(factory): raise TypeError("Invalid factory class '{0}'" .format(type(factory).__name__)) with self.__factories_lock: if factory_name in self.__factories: if override: _logger.info("Overriding factory '%s'", factory_name) else: raise ValueError("'{0}' factory already exist" .format(factory_name)) self.__factories[factory_name] = factory # Trigger an event self._fire_ipopo_event(constants.IPopoEvent.REGISTERED, factory_name)
def set_filter(self, props_filter): """ Changes the current filter for the given one :param props_filter: The new requirement filter on service properties :raise TypeError: Unknown filter type """ if props_filter is not None and \ not (is_string(props_filter) or isinstance(props_filter, (ldapfilter.LDAPFilter, ldapfilter.LDAPCriteria))): # Unknown type raise TypeError("Invalid filter type {0}" .format(type(props_filter).__name__)) if props_filter is not None: # Filter given, keep its string form self.__original_filter = str(props_filter) else: # No filter self.__original_filter = None # Parse the filter self.filter = ldapfilter.get_ldap_filter(props_filter) # Prepare the full filter spec_filter = "({0}={1})".format(OBJECTCLASS, self.specification) self.__full_filter = ldapfilter.combine_filters( (spec_filter, self.filter))
def _serialize_properties(self, props): """ Converts properties values into strings """ new_props = {} for key, value in props.items(): if is_string(value): new_props[key] = value else: try: new_props[key] = json.dumps(value) except ValueError: new_props[key] = "pelix-type:{0}:{1}" \ .format(type(value).__name__, repr(value)) # FIXME: for use with ECF try: new_props[pelix.constants.OBJECTCLASS] = props[pelix.constants.OBJECTCLASS][0] new_props[pelix.remote.PROP_IMPORTED_CONFIGS] = props[pelix.remote.PROP_IMPORTED_CONFIGS][0] except KeyError: pass return new_props
def set_filter(self, props_filter): """ Changes the current filter for the given one :param props_filter: The new requirement filter on service properties :raise TypeError: Unknown filter type """ if props_filter is not None and \ not (is_string(props_filter) or isinstance(props_filter, (ldapfilter.LDAPFilter, ldapfilter.LDAPCriteria))): # Unknown type raise TypeError("Invalid filter type {0}" .format(type(props_filter).__name__)) if props_filter is not None: # Filter given, keep its string form self.__original_filter = str(props_filter) else: # No filter self.__original_filter = None # Parse the filter self.filter = ldapfilter.get_ldap_filter(props_filter) # Prepare the full filter spec_filter = "({0}={1})".format(OBJECTCLASS, self.specification) self.__full_filter = ldapfilter.combine_filters((spec_filter, self.filter))
def unescape_LDAP(ldap_string): """ Unespaces an LDAP string :param ldap_string: The string to unescape :return: The unprotected string """ if ldap_string is None: return None assert is_string(ldap_string) if ESCAPE_CHARACTER not in ldap_string: # No need to loop return ldap_string escaped = False result = "" for character in ldap_string: if not escaped and character == ESCAPE_CHARACTER: # Escape character found escaped = True else: # Copy the character escaped = False result += character return result
def _get_specifications(specifications): """ Computes the list of strings corresponding to the given specifications :param specifications: A string, a class or a list of specifications :return: A list of strings :raise ValueError: Invalid specification found """ if not specifications: raise ValueError("No specifications given") if inspect.isclass(specifications): # Get the name of the class return [specifications.__name__] elif is_string(specifications): # Specification name specifications = specifications.strip() if not specifications: raise ValueError("Empty specification given") return [specifications] elif isinstance(specifications, (list, tuple)): # List given: normalize its content results = [] for specification in specifications: results.extend(_get_specifications(specification)) return results else: raise ValueError("Unhandled specifications type : {0}".format( type(specifications).__name__))
def __make_local_peer(self, context): """ Prepares a Peer bean with local configuration :param context: Bundle context """ # Get local peer UID, node UID and application ID peer_uid = context.get_property(herald.FWPROP_PEER_UID) \ or context.get_property(pelix.constants.FRAMEWORK_UID) node_uid = context.get_property(herald.FWPROP_NODE_UID) app_id = context.get_property(herald.FWPROP_APPLICATION_ID) \ or herald.DEFAULT_APPLICATION_ID # Find configured groups groups = context.get_property(herald.FWPROP_PEER_GROUPS) if not groups: groups = [] elif is_string(groups): groups = (group.strip() for group in groups.split(',') if group.strip) groups = set(groups) # Add pre-configured group: node UID if node_uid: groups.add(node_uid) # Make the Peer bean peer = beans.Peer(peer_uid, node_uid, app_id, groups, self) # Setup node and name information peer.name = context.get_property(herald.FWPROP_PEER_NAME) peer.node_name = context.get_property(herald.FWPROP_NODE_NAME) return peer
def _comparator_gt(filter_value, tested_value): """ Tests if the filter value is strictly lesser than the tested value tested_value > filter_value """ if is_string(filter_value): value_type = type(tested_value) try: # Try a conversion filter_value = value_type(filter_value) except (TypeError, ValueError): if value_type is int: # Integer/float comparison trick try: filter_value = float(filter_value) except (TypeError, ValueError): # None-float value return False else: # Incompatible type return False try: return tested_value > filter_value except TypeError: # Incompatible type return False
def _deserialize_properties(props): """ Converts properties values into their type """ new_props = {} for key, value in props.items(): key = to_str(key) if is_bytes(value): # Convert value to string if necessary value = to_str(value) try: try: new_props[key] = json.loads(value) except (TypeError, ValueError): if is_string(value) and value.startswith("pelix-type:"): # Pseudo-serialized value_type, value = value.split(":", 3)[2:] if "." in value_type and value_type not in value: # Not a builtin type... _logger.warning( "Won't work: %s (%s)", value, value_type ) new_props[key] = eval(value) else: # String new_props[key] = value except Exception as ex: _logger.error("Can't deserialize %s: %s", value, ex) return new_props
def get_widget(self, parent): """ Returns the widget to be shown in the framework information panel :param parent: The parent UI container :return: A Qt widget """ # Make the table self._table = QtWidgets.QTableWidget(0, 3, parent) self._table.setHorizontalHeaderLabels(('ID', 'Name', 'Status')) self._table.verticalHeader().hide() # Fill it for bid, name in self._probe.get_bundles().items(): # JSON-RPC converts integer keys into strings if is_string(bid): bid = int(bid) # Get the state state = self._probe.get_bundle_state(bid) # Append the line self.__append_line(bid, name, state) # Sort the lines self._table.sortItems(0) return self._table
def __init__( self, uid, framework, configurations, name, specifications, properties ): # type: (str, str, Any[str, List[str]], Optional[str], List[str], dict) -> None """ :param uid: Unique identified of the end point :param framework: UID of the framework exporting the end point (can be None) :param configurations: Kinds of end point (xmlrpc, ...) :param name: Name of the end point :param specifications: Specifications of the exported service :param properties: Properties of the service """ self.__uid = uid self.__fw_uid = framework or None self.__name = name self.__properties = properties.copy() if properties else {} # Normalize list of configurations if is_string(configurations): tuple_conf = (configurations,) # type: Tuple[str, ...] else: tuple_conf = tuple(configurations) self.__configurations = tuple_conf # Extract the language prefix in specifications self.__specifications = extract_specifications( specifications, self.__properties ) # Public variable: the source server, # set up by a Pelix discovery service self.server = None # type: str
def escape_LDAP(ldap_string): """ Escape a string to let it go in an LDAP filter :param ldap_string: The string to escape :return: The protected string """ if ldap_string is None: return None assert is_string(ldap_string) if len(ldap_string) == 0: # No content return ldap_string # Protect escape character previously in the string ldap_string = ldap_string.replace(ESCAPE_CHARACTER, ESCAPE_CHARACTER + ESCAPE_CHARACTER) # Leading space if ldap_string.startswith(" "): ldap_string = "\\ {0}".format(ldap_string[1:]) # Trailing space if ldap_string.endswith(" "): ldap_string = "{0}\\ ".format(ldap_string[:-1]) # Escape other characters for escaped in ESCAPED_CHARACTERS: ldap_string = ldap_string.replace(escaped, ESCAPE_CHARACTER + escaped) return ldap_string
def find_service_references(self, clazz=None, ldap_filter=None, only_one=False): """ Finds all services references matching the given filter. :param clazz: Class implemented by the service :param ldap_filter: Service filter :param only_one: Return the first matching service reference only :return: A list of found references, or None :raise BundleException: An error occurred looking for service references """ with self.__svc_lock: if clazz is None and ldap_filter is None: # Return a sorted copy of the keys list # Do not return None, as the whole content was required return sorted(self.__svc_registry.keys()) if hasattr(clazz, '__name__'): # Escape the type name clazz = ldapfilter.escape_LDAP(clazz.__name__) elif is_string(clazz): # Escape the class name clazz = ldapfilter.escape_LDAP(clazz) if clazz is None: # Directly use the given filter refs_set = sorted(self.__svc_registry.keys()) else: try: # Only for references with the given specification refs_set = iter(self.__svc_specs[clazz]) except KeyError: # No matching specification return None # Parse the filter try: new_filter = ldapfilter.get_ldap_filter(ldap_filter) except ValueError as ex: raise BundleException(ex) if new_filter is not None: # Prepare a generator, as we might not need a complete # walk-through refs_set = (ref for ref in refs_set if new_filter.matches(ref.get_properties())) if only_one: # Return the first element in the list/generator try: return next(refs_set) except StopIteration: # No match return None # Get all the matching references return list(refs_set) or None
def __init__(self, uid, framework, configurations, name, specifications, properties): """ Sets up the members :param uid: Unique identified of the end point :param framework: UID of the framework exporting the end point (can be None) :param configurations: Kinds of end point (xmlrpc, ...) :param name: Name of the end point :param specifications: Specifications of the exported service :param properties: Properties of the service """ self.__uid = uid self.__fw_uid = framework or None self.__name = name self.__properties = properties.copy() if properties else {} # Normalize list of configurations if is_string(configurations): self.__configurations = (configurations, ) else: self.__configurations = tuple(configurations) # Extract the language prefix in specifications self.__specifications = extract_specifications(specifications, self.__properties) # Public variable: the source server, # set up by a Pelix discovery service self.server = None
def _serialize_properties(self, props): """ Converts properties values into strings """ new_props = {} for key, value in props.items(): if is_string(value): new_props[key] = value else: try: new_props[key] = json.dumps(value) except ValueError: new_props[key] = "pelix-type:{0}:{1}" \ .format(type(value).__name__, repr(value)) # FIXME: to simplify the usage with ECF, send single strings instead of # arrays for key in (pelix.constants.OBJECTCLASS, pelix.remote.PROP_IMPORTED_CONFIGS): try: new_props[key] = props[key][0] except KeyError: pass return new_props
def __init__(self, field, specification, aggregate=False, optional=False, spec_filter=None): """ Sets up the requirement :param field: The injected field :param specification: The injected service specification :param aggregate: If true, injects a list :param optional: If true, this injection is optional :param spec_filter: An LDAP query to filter injected services upon their properties :raise TypeError: A parameter has an invalid type :raise ValueError: An error occurred while parsing the filter or an argument is incorrect """ if not field: raise ValueError("Empty field name.") if not is_string(field): raise TypeError("The field name must be a string, not {0}" .format(type(field).__name__)) if ' ' in field: raise ValueError("Field name can't contain spaces.") self.__field = field # Be sure that there is only one required specification specifications = _get_specifications(specification) self.__multi_specs = len(specifications) > 1 # Construct the requirement object self.__requirement = Requirement(specifications[0], aggregate, optional, spec_filter)
def _serialize_properties(props): """ Converts properties values into strings """ new_props = {} for key, value in props.items(): if is_string(value): new_props[key] = value else: try: new_props[key] = json.dumps(value) except ValueError: new_props[key] = "pelix-type:{0}:{1}" \ .format(type(value).__name__, repr(value)) # FIXME: to simplify the usage with ECF, send single strings instead of # arrays for key in (pelix.constants.OBJECTCLASS, pelix.remote.PROP_IMPORTED_CONFIGS): try: new_props[key] = props[key][0] except KeyError: pass return new_props
def _get_specifications(specifications): """ Computes the list of strings corresponding to the given specifications :param specifications: A string, a class or a list of specifications :return: A list of strings :raise ValueError: Invalid specification found """ if not specifications: raise ValueError("No specifications given") if inspect.isclass(specifications): # Get the name of the class return [specifications.__name__] elif is_string(specifications): # Specification name specifications = specifications.strip() if not specifications: raise ValueError("Empty specification given") return [specifications] elif isinstance(specifications, (list, tuple)): # List given: normalize its content results = [] for specification in specifications: results.extend(_get_specifications(specification)) return results else: raise ValueError("Unhandled specifications type : {0}" .format(type(specifications).__name__))
def __init__(self, uid, framework, configurations, name, specifications, properties): """ Sets up the members :param uid: Unique identified of the end point :param framework: UID of the framework exporting the end point (can be None) :param configurations: Kinds of end point (xmlrpc, ...) :param name: Name of the end point :param specifications: Specifications of the exported service :param properties: Properties of the service """ self.__uid = uid self.__fw_uid = framework or None self.__name = name self.__properties = properties.copy() if properties else {} # Normalize list of configurations if is_string(configurations): self.__configurations = (configurations,) else: self.__configurations = tuple(configurations) # Extract the language prefix in specifications self.__specifications = extract_specifications(specifications, self.__properties) # Public variable: the source server, # set up by a Pelix discovery service self.server = None
def unregister_factory(self, factory_name): # type: (str) -> bool """ Unregisters the given component factory :param factory_name: Name of the factory to unregister :return: True the factory has been removed, False if the factory is unknown """ if not factory_name or not is_string(factory_name): # Invalid name return False with self.__factories_lock: try: # Remove the factory from the registry factory_class = self.__factories.pop(factory_name) except KeyError: # Unknown factory return False # Trigger an event self._fire_ipopo_event( constants.IPopoEvent.UNREGISTERED, factory_name ) # Invalidate and delete all components of this factory with self.__instances_lock: # Compute the list of __instances to remove to_remove = self.__get_stored_instances(factory_name) # Remove instances from the registry: avoids dependencies \ # update to link against a component from this factory again. for instance in to_remove: try: # Kill the instance self.kill(instance.name) except ValueError: # Unknown instance: already killed by the invalidation # callback of a component killed in this loop # => ignore pass # Remove waiting component names = [ name for name, (context, _) in self.__waiting_handlers.items() if context.factory_context.name == factory_name ] for name in names: del self.__waiting_handlers[name] # Clear the bundle context of the factory _set_factory_context(factory_class, None) return True
def unregister_factory(self, factory_name): # type: (str) -> bool """ Unregisters the given component factory :param factory_name: Name of the factory to unregister :return: True the factory has been removed, False if the factory is unknown """ if not factory_name or not is_string(factory_name): # Invalid name return False with self.__factories_lock: try: # Remove the factory from the registry factory_class = self.__factories.pop(factory_name) except KeyError: # Unknown factory return False # Trigger an event self._fire_ipopo_event(constants.IPopoEvent.UNREGISTERED, factory_name) # Invalidate and delete all components of this factory with self.__instances_lock: # Compute the list of __instances to remove to_remove = self.__get_stored_instances(factory_name) # Remove instances from the registry: avoids dependencies \ # update to link against a component from this factory again. for instance in to_remove: try: # Kill the instance self.kill(instance.name) except ValueError: # Unknown instance: already killed by the invalidation # callback of a component killed in this loop # => ignore pass # Remove waiting component names = [ name for name, (context, _) in self.__waiting_handlers.items() if context.factory_context.name == factory_name ] for name in names: del self.__waiting_handlers[name] # Clear the bundle context of the factory _set_factory_context(factory_class, None) return True
def testIsString(self): """ Tests the is_string() method """ valid = ["", "aaa", str(42)] invalid = [42, None, [], {}, tuple()] if sys.version_info[0] >= 3: invalid.extend((b"", b"aaa")) else: valid.extend((unicode(""), unicode("aaa"), unicode(42))) invalid.extend((42, None, [], {})) for value in valid: self.assertTrue(utilities.is_string(value), "'{0}' is a string".format(value)) for value in invalid: self.assertFalse(utilities.is_string(value), "'{0}' is not a string".format(value))
def testIsString(self): """ Tests the is_string() method """ valid = ["", "aaa", str(42)] invalid = [42, None, [], {}, tuple()] if sys.version_info[0] >= 3: # Python 3: test bytes invalid.extend((b"", b"aaa")) else: # Python 2: test unicode valid.extend((unicode(""), unicode("aaa"), unicode(42))) for value in valid: self.assertTrue(utilities.is_string(value), "'{0}' is a string".format(value)) for value in invalid: self.assertFalse(utilities.is_string(value), "'{0}' is not a string".format(value))
def matches(self, other): """ Tests if this version matches the given one """ if other is None: # None matches everything return True if self.version is None: # No version matches any version return True if is_string(other): # The given string can be either a version or a range other = other.strip() if other[0] == '[': # Range comparison inclusive = (other[-1] == ']') versions = other[1:-1].split(',') # Convert boundaries minimum = Version(versions[0]) maximum = Version(versions[1]) else: minimum = Version(other) # Allow binding up to the next major version (excluded) maximum = Version(other) + (1,) inclusive = False if isinstance(other, Version): # Compared to another version if other.version is None: # Other matches any version return True else: # Allow binding up to the next major version (excluded) minimum = other maximum = other + (1,) inclusive = False if minimum is not None and self < minimum: # We're under the minimal version return False elif maximum is not None and self > maximum: # We're above the maximal version return False elif not inclusive and self == maximum: # We're at the upper boundary return False else: # Range tests passed return True
def matches(self, other): """ Tests if this version matches the given one """ if other is None: # None matches everything return True if self.version is None: # No version matches any version return True if is_string(other): # The given string can be either a version or a range other = other.strip() if other[0] == '[': # Range comparison inclusive = (other[-1] == ']') versions = other[1:-1].split(',') # Convert boundaries minimum = Version(versions[0]) maximum = Version(versions[1]) else: minimum = Version(other) # Allow binding up to the next major version (excluded) maximum = Version(other) + (1, ) inclusive = False if isinstance(other, Version): # Compared to another version if other.version is None: # Other matches any version return True else: # Allow binding up to the next major version (excluded) minimum = other maximum = other + (1, ) inclusive = False if minimum is not None and self < minimum: # We're under the minimal version return False elif maximum is not None and self > maximum: # We're above the maximal version return False elif not inclusive and self == maximum: # We're at the upper boundary return False else: # Range tests passed return True
def visit_Assign(self, node): """ Found an assignment """ field = getattr(node.targets[0], 'id', None) if field: try: value = ast.literal_eval(node.value) if is_string(value): self.values[field] = value except (ValueError, SyntaxError): # Ignore errors pass
def __init__(self, field, specification, key, allow_none=False, aggregate=False, optional=False, spec_filter=None): """ Sets up the requirement :param field: The injected field :param specification: The injected service specification :param key: Name of the service property to use as a dictionary key :param allow_none: If True, inject services with a None property value :param aggregate: If true, injects a list :param optional: If true, this injection is optional :param spec_filter: An LDAP query to filter injected services upon their properties :raise TypeError: A parameter has an invalid type :raise ValueError: An error occurred while parsing the filter or an argument is incorrect """ # Check if field is valid if not field: raise ValueError("Empty field name.") if not is_string(field): raise TypeError("The field name must be a string, not {0}".format( type(field).__name__)) if ' ' in field: raise ValueError("Field name can't contain spaces.") self.__field = field # Be sure that there is only one required specification specifications = _get_specifications(specification) self.__multi_specs = len(specifications) > 1 # Check if key is valid if not key: raise ValueError("No property key given") # Store the flags self.__key = key self.__allow_none = allow_none # Construct the requirement object self.__requirement = Requirement(specifications[0], aggregate, optional, spec_filter)
def __init__( self, uid, fw_uid, configurations, name, svc_ref, service, properties ): # type: (str, str, Any[str, List[str]], str, pelix.framework.ServiceReference, object, dict) -> None """ :param uid: Unique identified of the end point :param fw_uid: The framework UID :param configurations: Kinds of end point (xmlrpc, ...) :param name: Name of the end point :param svc_ref: ServiceReference of the exported service :param service: Instance of the exported service :param properties: Extra properties :raise ValueError: Invalid UID or the end point exports nothing (all specifications have been filtered) """ if not uid: raise ValueError("Invalid UID") # Given information self.__uid = uid self.__fw_uid = fw_uid self.__instance = service self.__reference = svc_ref self.__configurations = configurations self.__name = name # Normalize extra properties if isinstance(properties, dict): self.__properties = properties else: self.__properties = {} # Normalize the list of configurations if is_string(configurations): self.__configurations = (configurations,) else: self.__configurations = tuple(configurations) # Exported specifications self.__exported_specs = [] # type: List[str] exported_specs = compute_exported_specifications(svc_ref) if exported_specs: # Transform the specifications for export (add the language prefix) self.__exported_specs = format_specifications(exported_specs) else: raise ValueError( "Endpoint {0}, {1}, exports nothing".format( self.__uid, self.__name ) )
def __register_servlet_service(self, service, service_reference): """ Registers a servlet according to its service properties :param service: A servlet service :param service_reference: The associated ServiceReference """ # Servlet bound paths = service_reference.get_property(http.HTTP_SERVLET_PATH) if utilities.is_string(paths): # Register the servlet to a single path self.register_servlet(paths, service) elif isinstance(paths, (list, tuple)): # Register the servlet to multiple paths for path in paths: self.register_servlet(path, service)
def __init__(self, field, specification, key, allow_none=False, aggregate=False, optional=False, spec_filter=None): """ Sets up the requirement :param field: The injected field :param specification: The injected service specification :param key: Name of the service property to use as a dictionary key :param allow_none: If True, inject services with a None property value :param aggregate: If true, injects a list :param optional: If true, this injection is optional :param spec_filter: An LDAP query to filter injected services upon their properties :raise TypeError: A parameter has an invalid type :raise ValueError: An error occurred while parsing the filter or an argument is incorrect """ # Check if field is valid if not field: raise ValueError("Empty field name.") if not is_string(field): raise TypeError("The field name must be a string, not {0}" .format(type(field).__name__)) if ' ' in field: raise ValueError("Field name can't contain spaces.") self.__field = field # Be sure that there is only one required specification specifications = _get_specifications(specification) self.__multi_specs = len(specifications) > 1 # Check if key is valid if not key: raise ValueError("No property key given") # Store the flags self.__key = key self.__allow_none = allow_none # Construct the requirement object self.__requirement = Requirement(specifications[0], aggregate, optional, spec_filter)
def __init__(self, field, specification, aggregate=False, optional=False, spec_filter=None, immediate_rebind=False): """ Sets up the requirement :param field: The injected field :param specification: The injected service specification :param aggregate: If true, injects a list :param optional: If true, this injection is optional :param spec_filter: An LDAP query to filter injected services upon their properties :param 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 :raise TypeError: A parameter has an invalid type :raise ValueError: An error occurred while parsing the filter or an argument is incorrect """ if not field: raise ValueError("Empty field name.") if not is_string(field): raise TypeError("The field name must be a string, not {0}".format( type(field).__name__)) if ' ' in field: raise ValueError("Field name can't contain spaces.") self.__field = field # Be sure that there is only one required specification specifications = _get_specifications(specification) self.__multi_specs = len(specifications) > 1 # Construct the requirement object self.__requirement = Requirement(specifications[0], aggregate, optional, spec_filter, immediate_rebind)
def __init__( self, specification, aggregate=False, optional=False, spec_filter=None, immediate_rebind=False, ): # type: (str, bool, bool, Any, bool) -> None """ Sets up the requirement :param specification: The requirement specification, which must be unique and can't be None :param aggregate: If true, this requirement represents a list :param optional: If true, this requirement is optional :param spec_filter: A filter to select dependencies :param 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 :raise TypeError: A parameter has an invalid type :raise ValueError: An error occurred while parsing the filter """ if not is_string(specification): raise TypeError("A Requirement specification must be a string") if not specification: raise ValueError("No specification given") self.specification = specification self.aggregate = aggregate self.optional = optional self.immediate_rebind = immediate_rebind # Original filter keeper self.__original_filter = None # type: str # Full filter (with the specification ycappuccino_core) self.__full_filter = None # type: ldapfilter.LDAPFilter # Set up the requirement filter (after setting up self.specification) self.filter = None # type: ldapfilter.LDAPFilter self.set_filter(spec_filter)
def __init__( self, specification, aggregate=False, optional=False, spec_filter=None, immediate_rebind=False, ): # type: (str, bool, bool, Any, bool) -> None """ Sets up the requirement :param specification: The requirement specification, which must be unique and can't be None :param aggregate: If true, this requirement represents a list :param optional: If true, this requirement is optional :param spec_filter: A filter to select dependencies :param 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 :raise TypeError: A parameter has an invalid type :raise ValueError: An error occurred while parsing the filter """ if not is_string(specification): raise TypeError("A Requirement specification must be a string") if not specification: raise ValueError("No specification given") self.specification = specification self.aggregate = aggregate self.optional = optional self.immediate_rebind = immediate_rebind # Original filter keeper self.__original_filter = None # type: str # Full filter (with the specification test) self.__full_filter = None # type: ldapfilter.LDAPFilter # Set up the requirement filter (after setting up self.specification) self.filter = None # type: ldapfilter.LDAPFilter self.set_filter(spec_filter)
def __init__(self, name, properties=None): """ Sets up the decorator :param name: Instance name :param properties: Instance properties """ if not is_string(name): raise TypeError("Instance name must be a string") if properties is not None and not isinstance(properties, dict): raise TypeError("Instance properties must be a dictionary or None") name = name.strip() if not name: raise ValueError("Invalid instance name '{0}'".format(name)) self.__name = name self.__properties = properties
def combine_filters(filters, operator=AND): """ Combines two LDAP filters, which can be strings or LDAPFilter objects :param filters: Filters to combine :param operator: The operator for combination :return: The combined filter, can be None if all filters are None :raise ValueError: Invalid filter string found :raise TypeError: Unknown filter type """ if not filters: return None if not hasattr(filters, '__iter__') or is_string(filters): raise TypeError("Filters argument must be iterable") # Remove None filters and convert others ldap_filters = [] for sub_filter in filters: if sub_filter is None: # Ignore None filters continue ldap_filter = get_ldap_filter(sub_filter) if ldap_filter is not None: # Valid filter ldap_filters.append(ldap_filter) if len(ldap_filters) == 0: # Do nothing return None elif len(ldap_filters) == 1: # Only one filter, return it return ldap_filters[0] new_filter = LDAPFilter(operator) for sub_filter in ldap_filters: # Direct combination new_filter.append(sub_filter) return new_filter.normalize()
def __eq__(self, other): """ Tests the equality with another artifact """ if isinstance(other, Artifact): # Compare the other artifact if self.__file == other.__file: # Same file, same artifact return True # All other attributes must be equal return self.__language == other.__language \ and self.__name == other.__name \ and self.__version == other.__version elif is_string(other): # Compare by name return self.__name == other else: # Unknown type return NotImplemented
def _star_comparison(filter_value, tested_value): """ Tests a filter containing a joker """ if not is_string(tested_value): # Unhandled value type... return False parts = filter_value.split("*") i = 0 last_part = len(parts) - 1 idx = 0 for part in parts: # Find the part in the tested value idx = tested_value.find(part, idx) if idx == -1: # Part not found return False len_part = len(part) if i == 0 and len_part != 0 and idx != 0: # First part is not a star, but the tested value is not at # position 0 => Doesn't match return False if ( i == last_part and len_part != 0 and idx != len(tested_value) - len_part ): # Last tested part is not at the end of the sequence return False # Be sure to test the next part idx += len_part i += 1 # Whole test passed return True