Exemple #1
0
class TestAgentComponentRegistry:
    def setup_class(self):
        """Set up the test."""
        self.registry = AgentComponentRegistry()

    def test_register_when_component_is_already_registered(self):
        """Test AgentComponentRegistry.register when the component is already registered."""
        component_id = ComponentId(
            ComponentType.PROTOCOL, PublicId("author", "name", "0.1.0")
        )
        component_mock = MagicMock(component_id=component_id)
        self.registry._registered_keys.add(component_id)
        with pytest.raises(
            ValueError, match=r"Component already registered with item id"
        ):
            self.registry.register(component_id, component_mock)
        self.registry._registered_keys = set()

    def test_register_when_component_id_mismatch(self):
        """Test AgentComponentRegistry.register when the component ids mismatch."""
        component_id_1 = ComponentId(
            ComponentType.PROTOCOL, PublicId("author", "name", "0.1.0")
        )
        component_id_2 = ComponentId(
            ComponentType.PROTOCOL, PublicId("author", "name", "0.2.0")
        )
        component_mock = MagicMock(component_id=component_id_1)
        with pytest.raises(
            ValueError, match="Component id '.*' is different to the id '.*' specified."
        ):
            self.registry.register(component_id_2, component_mock)
        self.registry._registered_keys = set()

    def test_unregister_when_no_item_registered(self):
        """Test AgentComponentRegistry.register when the item was not registered."""
        component_id = ComponentId(
            ComponentType.PROTOCOL, PublicId("author", "name", "0.1.0")
        )
        component_mock = MagicMock(component_id=component_id)
        self.registry.register(component_id, component_mock)
        self.registry._registered_keys.remove(component_id)
        with pytest.raises(ValueError, match="No item registered with item id '.*'"):
            self.registry.unregister(component_id)
        self.registry._registered_keys.add(component_id)
        self.registry.unregister(component_id)

    def test_fetch_all(self):
        """Test fetch all."""
        all_components = self.registry.fetch_all()
        assert len(all_components) == 0
        component_id = ComponentId(
            ComponentType.PROTOCOL, PublicId("author", "name", "0.1.0")
        )
        component_mock = MagicMock(component_id=component_id)
        self.registry.register(component_id, component_mock)
        all_components = self.registry.fetch_all()
        assert len(all_components) == 1

        # restore state
        self.registry.unregister(component_id)
Exemple #2
0
class Resources:
    """This class implements the object that holds the resources of an AEA."""
    def __init__(self) -> None:
        """
        Instantiate the resources.

        :return None
        """
        self._component_registry = AgentComponentRegistry()
        self._handler_registry = HandlerRegistry()
        self._behaviour_registry = ComponentRegistry[Behaviour]()
        self._model_registry = ComponentRegistry[Model]()

        self._registries = [
            self._component_registry,
            self._handler_registry,
            self._behaviour_registry,
            self._model_registry,
        ]  # type: List[Registry]

    @property
    def component_registry(self) -> AgentComponentRegistry:
        """Get the agent component registry."""
        return self._component_registry

    @property
    def behaviour_registry(self) -> ComponentRegistry[Behaviour]:
        """Get the behaviour registry."""
        return self._behaviour_registry

    @property
    def handler_registry(self) -> HandlerRegistry:
        """Get the handler registry."""
        return self._handler_registry

    @property
    def model_registry(self) -> ComponentRegistry[Model]:
        """Get the model registry."""
        return self._model_registry

    def add_component(self, component: Component):
        """Add a component to resources."""
        if component.component_type == ComponentType.PROTOCOL:
            self.add_protocol(cast(Protocol, component))
        elif component.component_type == ComponentType.SKILL:
            self.add_skill(cast(Skill, component))
        elif component.component_type == ComponentType.CONTRACT:
            self.add_contract(cast(Contract, component))
        elif component.component_type == ComponentType.CONNECTION:
            self.add_connection(cast(Connection, component))
        else:
            raise ValueError("Component type {} not supported.".format(
                component.component_type.value))

    def add_protocol(self, protocol: Protocol) -> None:
        """
        Add a protocol to the set of resources.

        :param protocol: a protocol
        :return: None
        """
        self._component_registry.register(protocol.component_id, protocol)

    def get_protocol(self, protocol_id: ProtocolId) -> Optional[Protocol]:
        """
        Get protocol for given protocol id.

        :param protocol_id: the protocol id
        :return: a matching protocol, if present, else None
        """
        protocol = self._component_registry.fetch(
            ComponentId(ComponentType.PROTOCOL, protocol_id))
        return cast(Protocol, protocol)

    def get_all_protocols(self) -> List[Protocol]:
        """
        Get the list of all the protocols.

        :return: the list of protocols.
        """
        protocols = self._component_registry.fetch_by_type(
            ComponentType.PROTOCOL)
        return cast(List[Protocol], protocols)

    def remove_protocol(self, protocol_id: ProtocolId) -> None:
        """
        Remove a protocol from the set of resources.

        :param protocol_id: the protocol id for the protocol to be removed.
        :return: None
        """
        self._component_registry.unregister(
            ComponentId(ComponentType.PROTOCOL, protocol_id))

    def add_contract(self, contract: Contract) -> None:
        """
        Add a contract to the set of resources.

        :param contract: a contract
        :return: None
        """
        self._component_registry.register(contract.component_id, contract)

    def get_contract(self, contract_id: ContractId) -> Optional[Contract]:
        """
        Get contract for given contract id.

        :param contract_id: the contract id
        :return: a matching contract, if present, else None
        """
        contract = self._component_registry.fetch(
            ComponentId(ComponentType.CONTRACT, contract_id))
        return cast(Contract, contract)

    def get_all_contracts(self) -> List[Contract]:
        """
        Get the list of all the contracts.

        :return: the list of contracts.
        """
        contracts = self._component_registry.fetch_by_type(
            ComponentType.CONTRACT)
        return cast(List[Contract], contracts)

    def remove_contract(self, contract_id: ContractId) -> None:
        """
        Remove a contract from the set of resources.

        :param contract_id: the contract id for the contract to be removed.
        :return: None
        """
        self._component_registry.unregister(
            ComponentId(ComponentType.CONTRACT, contract_id))

    def add_connection(self, connection: Connection) -> None:
        """
        Add a connection to the set of resources.

        :param connection: a connection
        :return: None
        """
        self._component_registry.register(connection.component_id, connection)

    def get_connection(self,
                       connection_id: ConnectionId) -> Optional[Connection]:
        """
        Get connection for given connection id.

        :param connection_id: the connection id
        :return: a matching connection, if present, else None
        """
        connection = self._component_registry.fetch(
            ComponentId(ComponentType.CONNECTION, connection_id))
        return cast(Connection, connection)

    def get_all_connections(self) -> List[Connection]:
        """
        Get the list of all the connections.

        :return: the list of connections.
        """
        connections = self._component_registry.fetch_by_type(
            ComponentType.CONNECTION)
        return cast(List[Connection], connections)

    def remove_connection(self, connection_id: ConnectionId) -> None:
        """
        Remove a connection from the set of resources.

        :param connection_id: the connection id for the connection to be removed.
        :return: None
        """
        self._component_registry.unregister(
            ComponentId(ComponentType.CONNECTION, connection_id))

    def add_skill(self, skill: Skill) -> None:
        """
        Add a skill to the set of resources.

        :param skill: a skill
        :return: None
        """
        self._component_registry.register(skill.component_id, skill)
        if skill.handlers is not None:
            for handler in skill.handlers.values():
                self._handler_registry.register(
                    (skill.public_id, handler.name), handler)
        if skill.behaviours is not None:
            for behaviour in skill.behaviours.values():
                self._behaviour_registry.register(
                    (skill.public_id, behaviour.name), behaviour)
        if skill.models is not None:
            for model in skill.models.values():
                self._model_registry.register((skill.public_id, model.name),
                                              model)
        self.inject_contracts(skill)

    def inject_contracts(self, skill: Skill) -> None:
        """
        Inject contracts into a skill context.

        :param skill: a skill
        :return: None
        """
        if skill.config.contracts is not None:
            # check all contracts are present
            contracts = {}  # type: Dict[str, Contract]
            for contract_id in skill.config.contracts:
                contract = self._component_registry.fetch(
                    ComponentId(ComponentType.CONTRACT, contract_id))
                if contract is None:
                    raise ValueError(
                        "Missing contract for contract id {}".format(
                            contract_id))
                contracts[contract_id.name] = cast(Contract, contract)
            skill.inject_contracts(contracts)

    def get_skill(self, skill_id: SkillId) -> Optional[Skill]:
        """
        Get the skill for a given skill id.

        :param skill_id: the skill id
        :return: a matching skill, if present, else None
        """
        skill = self._component_registry.fetch(
            ComponentId(ComponentType.SKILL, skill_id))
        return cast(Skill, skill)

    def get_all_skills(self) -> List[Skill]:
        """
        Get the list of all the skills.

        :return: the list of skills.
        """
        skills = self._component_registry.fetch_by_type(ComponentType.SKILL)
        return cast(List[Skill], skills)

    def remove_skill(self, skill_id: SkillId) -> None:
        """
        Remove a skill from the set of resources.

        :param skill_id: the skill id for the skill to be removed.
        :return: None
        """
        self._component_registry.unregister(
            ComponentId(ComponentType.SKILL, skill_id))
        with suppress(ValueError):
            self._handler_registry.unregister_by_skill(skill_id)
        with suppress(ValueError):
            self._behaviour_registry.unregister_by_skill(skill_id)
        with suppress(ValueError):
            self._model_registry.unregister_by_skill(skill_id)

    def get_handler(self, protocol_id: ProtocolId,
                    skill_id: SkillId) -> Optional[Handler]:
        """
        Get a specific handler.

        :param protocol_id: the protocol id the handler is handling
        :param skill_id: the skill id of the handler's skill
        :return: the handler
        """
        handler = self._handler_registry.fetch_by_protocol_and_skill(
            protocol_id, skill_id)
        return handler

    def get_handlers(self, protocol_id: ProtocolId) -> List[Handler]:
        """
        Get all handlers for a given protocol.

        :param protocol_id: the protocol id the handler is handling
        :return: the list of handlers matching the protocol
        """
        handlers = self._handler_registry.fetch_by_protocol(protocol_id)
        return handlers

    def get_all_handlers(self) -> List[Handler]:
        """
        Get all handlers from all skills.

        :return: the list of handlers
        """
        handlers = self._handler_registry.fetch_all()
        return handlers

    def get_behaviour(self, skill_id: SkillId,
                      behaviour_name: str) -> Optional[Behaviour]:
        """
        Get a specific behaviours for a given skill.

        :param skill_id: the skill id
        :param behaviour_name: the behaviour name
        :return: the behaviour, if it is present, else None
        """
        behaviour = self._behaviour_registry.fetch((skill_id, behaviour_name))
        return behaviour

    def get_behaviours(self, skill_id: SkillId) -> List[Behaviour]:
        """
        Get all behaviours for a given skill.

        :param skill_id: the skill id
        :return: the list of behaviours of the skill
        """
        behaviours = self._behaviour_registry.fetch_by_skill(
            skill_id)  # type: List[Behaviour]
        return behaviours

    def get_all_behaviours(self) -> List[Behaviour]:
        """
        Get all behaviours from all skills.

        :return: the list of all behaviours
        """
        behaviours = self._behaviour_registry.fetch_all()
        return behaviours

    def setup(self) -> None:
        """
        Set up the resources.

        Calls setup on all resources.

        :return: None
        """
        for r in self._registries:
            r.setup()

    def teardown(self) -> None:
        """
        Teardown the resources.

        Calls teardown on all resources.

        :return: None
        """
        for r in self._registries:
            r.teardown()