示例#1
0
    def from_config(
        cls,
        configuration: ConnectionConfig,
        identity: Identity,
        crypto_store: CryptoStore,
        data_dir: str,
        **kwargs: Any,
    ) -> "Connection":
        """
        Load a connection from a configuration.

        :param configuration: the connection configuration.
        :param identity: the identity object.
        :param crypto_store: object to access the connection crypto objects.
        :param data_dir: the directory of the AEA project data.
        :return: an instance of the concrete connection class.
        """
        configuration = cast(ConnectionConfig, configuration)
        directory = cast(Path, configuration.directory)
        load_aea_package(configuration)
        connection_module_path = directory / "connection.py"
        if not (connection_module_path.exists() and connection_module_path.is_file()):
            raise AEAComponentLoadException(
                "Connection module '{}' not found.".format(connection_module_path)
            )
        connection_module = load_module(
            "connection_module", directory / "connection.py"
        )
        classes = inspect.getmembers(connection_module, inspect.isclass)
        connection_class_name = cast(str, configuration.class_name)
        connection_classes = list(
            filter(lambda x: re.match(connection_class_name, x[0]), classes)
        )
        name_to_class = dict(connection_classes)
        logger = get_logger(__name__, identity.name)
        logger.debug("Processing connection {}".format(connection_class_name))
        connection_class = name_to_class.get(connection_class_name, None)
        if connection_class is None:
            raise AEAComponentLoadException(
                "Connection class '{}' not found.".format(connection_class_name)
            )
        try:
            connection = connection_class(
                configuration=configuration,
                data_dir=data_dir,
                identity=identity,
                crypto_store=crypto_store,
                **kwargs,
            )
        except Exception as e:  # pragma: nocover # pylint: disable=broad-except
            e_str = parse_exception(e)
            raise AEAInstantiationException(
                f"An error occured during instantiation of connection {configuration.public_id}/{configuration.class_name}:\n{e_str}"
            )
        return connection
示例#2
0
 def handle_wrapper(self, message: Message) -> None:
     """Wrap the call of the handler. This method must be called only by the framework."""
     try:
         self.handle(message)
     except _StopRuntime:
         raise
     except Exception as e:  # pylint: disable=broad-except
         e_str = parse_exception(e)
         raise AEAHandleException(
             f"An error occured during handle of handler {self.context.skill_id}/{type(self).__name__}:\n{e_str}"
         )
示例#3
0
 def act_wrapper(self) -> None:
     """Wrap the call of the action. This method must be called only by the framework."""
     try:
         self.act()
     except _StopRuntime:
         raise
     except Exception as e:  # pylint: disable=broad-except
         e_str = parse_exception(e)
         raise AEAActException(
             f"An error occured during act of behaviour {self.context.skill_id}/{type(self).__name__}:\n{e_str}"
         )
示例#4
0
def _handle_error_while_loading_component_generic_error(
        configuration: ComponentConfiguration, e: Exception):
    """
    Handle Exception for AEA packages.

    :raises Exception: the same exception, but prepending an informative message.
    """
    e_str = parse_exception(e)
    raise AEAPackageLoadingError(
        "Package loading error: An error occurred while loading {} {}: {}".
        format(str(configuration.component_type), configuration.public_id,
               e_str))
示例#5
0
def test_parse_exception_i():
    """Test parse exception."""
    def exception_raise():
        """A function that raises an exception."""
        raise ValueError("expected")

    try:
        exception_raise()
    except Exception as e:
        out = parse_exception(e)

    expected = [
        "Traceback (most recent call last):\n\n",
        'test_exceptions.py", line ',
        "in exception_raise\n",
        'raise ValueError("expected")\n\nValueError: expected\n',
    ]
    assert all([string in out for string in expected])
示例#6
0
    def setup(self) -> None:
        """
        Set up the items in the registry.

        :return: None
        """
        for item in self.fetch_all():
            if item.context.is_active:
                self.logger.debug(
                    "Calling setup() of component {} of skill {}".format(
                        item.name, item.skill_id))
                try:
                    item.setup()
                except Exception as e:  # pragma: nocover # pylint: disable=broad-except
                    e_str = parse_exception(e)
                    e_str = f"An error occurred while setting up item {item.skill_id}/{type(item).__name__}:\n{e_str}"
                    raise AEASetupError(e_str)
            else:
                self.logger.debug(
                    "Ignoring setup() of component {} of skill {}, because the skill is not active."
                    .format(item.name, item.skill_id))
示例#7
0
    def teardown(self) -> None:
        """
        Teardown the registry.

        :return: None
        """
        for name_to_items in self._items.fetch_all():
            for _, item in name_to_items.items():
                self.logger.debug(
                    "Calling teardown() of component {} of skill {}".format(
                        item.name, item.skill_id))
                try:
                    item.teardown()
                except Exception as e:  # pragma: nocover # pylint: disable=broad-except
                    e_str = parse_exception(e)
                    e_str = f"An error occurred while tearing down item {item.skill_id}/{type(item).__name__}:\n{str(e_str)}"
                    e = AEATeardownError(e_str)
                    self.logger.error(str(e))
        _dynamically_added = copy.deepcopy(self._dynamically_added)
        for skill_id, items_names in _dynamically_added.items():
            for item_name in items_names:
                self.unregister((skill_id, item_name))
示例#8
0
    def parse_module(  # pylint: disable=arguments-differ
        cls,
        path: str,
        model_configs: Dict[str, SkillComponentConfiguration],
        skill_context: SkillContext,
    ) -> Dict[str, "Model"]:
        """
        Parse the tasks module.

        :param path: path to the Python skill module.
        :param model_configs: a list of model configurations.
        :param skill_context: the skill context
        :return: a list of Model.
        """
        instances = {}  # type: Dict[str, "Model"]
        if model_configs == {}:
            return instances
        models = []

        model_names = set(config.class_name for _, config in model_configs.items())

        # get all Python modules except the standard ones
        ignore_regex = "|".join(["handlers.py", "behaviours.py", "tasks.py", "__.*"])
        all_python_modules = Path(path).glob("*.py")
        module_paths = set(
            map(
                str,
                filter(
                    lambda x: not re.match(ignore_regex, x.name), all_python_modules
                ),
            )
        )

        for module_path in module_paths:
            skill_context.logger.debug("Trying to load module {}".format(module_path))
            module_name = module_path.replace(".py", "")
            model_module = load_module(module_name, Path(module_path))
            classes = inspect.getmembers(model_module, inspect.isclass)
            filtered_classes = list(
                filter(
                    lambda x: any(re.match(model, x[0]) for model in model_names)
                    and issubclass(x[1], Model)
                    and not str.startswith(x[1].__module__, "aea.")
                    and not str.startswith(
                        x[1].__module__,
                        f"packages.{skill_context.skill_id.author}.skills.{skill_context.skill_id.name}",
                    ),
                    classes,
                )
            )
            models.extend(filtered_classes)

        _check_duplicate_classes(models)
        name_to_class = dict(models)
        _print_warning_message_for_non_declared_skill_components(
            skill_context,
            set(name_to_class.keys()),
            {model_config.class_name for model_config in model_configs.values()},
            "models",
            path,
        )
        for model_id, model_config in model_configs.items():
            model_class_name = model_config.class_name
            skill_context.logger.debug(
                "Processing model id={}, class={}".format(model_id, model_class_name)
            )
            if not model_id.isidentifier():
                raise AEAComponentLoadException(  # pragma: nocover
                    f"'{model_id}' is not a valid identifier."
                )
            model = name_to_class.get(model_class_name, None)
            if model is None:
                skill_context.logger.warning(
                    "Model '{}' cannot be found.".format(model_class_name)
                )
            else:
                try:
                    model_instance = model(
                        name=model_id,
                        skill_context=skill_context,
                        configuration=model_config,
                        **dict(model_config.args),
                    )
                except Exception as e:  # pylint: disable=broad-except # pragma: nocover
                    e_str = parse_exception(e)
                    raise AEAInstantiationException(
                        f"An error occured during instantiation of model {skill_context.skill_id}/{model_config.class_name}:\n{e_str}"
                    )
                instances[model_id] = model_instance
                setattr(skill_context, model_id, model_instance)
        return instances
示例#9
0
    def parse_module(  # pylint: disable=arguments-differ
        cls,
        path: str,
        handler_configs: Dict[str, SkillComponentConfiguration],
        skill_context: SkillContext,
    ) -> Dict[str, "Handler"]:
        """
        Parse the handler module.

        :param path: path to the Python module containing the Handler class.
        :param handler_configs: the list of handler configurations.
        :param skill_context: the skill context
        :return: an handler, or None if the parsing fails.
        """
        handlers = {}  # type: Dict[str, "Handler"]
        if handler_configs == {}:
            return handlers
        handler_names = set(config.class_name for _, config in handler_configs.items())
        handler_module = load_module("handlers", Path(path))
        classes = inspect.getmembers(handler_module, inspect.isclass)
        handler_classes = list(
            filter(
                lambda x: any(re.match(handler, x[0]) for handler in handler_names)
                and not str.startswith(x[1].__module__, "aea.")
                and not str.startswith(
                    x[1].__module__,
                    f"packages.{skill_context.skill_id.author}.skills.{skill_context.skill_id.name}",
                ),
                classes,
            )
        )

        name_to_class = dict(handler_classes)
        _print_warning_message_for_non_declared_skill_components(
            skill_context,
            set(name_to_class.keys()),
            {handler_config.class_name for handler_config in handler_configs.values()},
            "handlers",
            path,
        )
        for handler_id, handler_config in handler_configs.items():
            handler_class_name = cast(str, handler_config.class_name)
            skill_context.logger.debug(
                "Processing handler {}".format(handler_class_name)
            )
            if not handler_id.isidentifier():
                raise AEAComponentLoadException(  # pragma: nocover
                    f"'{handler_id}' is not a valid identifier."
                )
            handler_class = name_to_class.get(handler_class_name, None)
            if handler_class is None:
                skill_context.logger.warning(
                    "Handler '{}' cannot be found.".format(handler_class_name)
                )
            else:
                try:
                    handler = handler_class(
                        name=handler_id,
                        configuration=handler_config,
                        skill_context=skill_context,
                        **dict(handler_config.args),
                    )
                except Exception as e:  # pylint: disable=broad-except # pragma: nocover
                    e_str = parse_exception(e)
                    raise AEAInstantiationException(
                        f"An error occured during instantiation of handler {skill_context.skill_id}/{handler_config.class_name}:\n{e_str}"
                    )
                handlers[handler_id] = handler

        return handlers
示例#10
0
def _handle_error_while_loading_component_module_not_found(
    configuration: ComponentConfiguration, e: ModuleNotFoundError
) -> None:
    """
    Handle ModuleNotFoundError for AEA packages.

    It will rewrite the error message only if the import path starts with 'packages'.
    To do that, it will extract the wrong import path from the error message.

    Depending on the import path, the possible error messages can be:

    - "No AEA package found with author name '{}', type '{}', name '{}'"
    - "'{}' is not a valid type name, choose one of ['protocols', 'connections', 'skills', 'contracts']"
    - "The package '{}/{}' of type '{}' exists, but cannot find module '{}'"

    :raises ModuleNotFoundError: if it is not
    :raises AEAPackageLoadingError: the same exception, but prepending an informative message.
    """
    error_message = str(e)
    match = re.match(r"No module named '([\w.]+)'", error_message)
    if match is None:
        # if for some reason we cannot extract the import path, just re-raise the error
        raise e from e

    import_path = match.group(1)
    parts = import_path.split(".")
    nb_parts = len(parts)
    if parts[0] != PACKAGES or nb_parts < 2:
        # if the first part of the import path is not 'packages',
        # the error is due for other reasons - just re-raise the error
        raise e from e

    def get_new_error_message_no_package_found() -> str:
        """Create a new error message in case the package is not found."""
        enforce(nb_parts <= 4, "More than 4 parts!")
        author = parts[1]
        new_message = "No AEA package found with author name '{}'".format(author)

        if nb_parts >= 3:
            pkg_type = parts[2]
            try:
                ComponentType(pkg_type[:-1])
            except ValueError:
                return "'{}' is not a valid type name, choose one of {}".format(
                    pkg_type, list(map(lambda x: x.to_plural(), ComponentType))
                )
            new_message += ", type '{}'".format(pkg_type)
        if nb_parts == 4:
            pkg_name = parts[3]
            new_message += ", name '{}'".format(pkg_name)
        return new_message

    def get_new_error_message_with_package_found() -> str:
        """Create a new error message in case the package is found."""
        enforce(nb_parts >= 5, "Less than 5 parts!")
        author, pkg_name, pkg_type = parts[:3]
        the_rest = ".".join(parts[4:])
        return "The package '{}/{}' of type '{}' exists, but cannot find module '{}'".format(
            author, pkg_name, pkg_type, the_rest
        )

    if nb_parts < 5:
        new_message = get_new_error_message_no_package_found()
    else:
        new_message = get_new_error_message_with_package_found()

    new_exc = AEAPackageNotFound(new_message)
    new_exc.__traceback__ = e.__traceback__
    e_str = parse_exception(new_exc)
    raise AEAPackageLoadingError(
        "Package loading error: An error occurred while loading {} {}:\n{}".format(
            str(configuration.component_type), configuration.public_id, e_str,
        )
    )