Example #1
0
    def load(
        cls,
        working_dir: str,
        public_id: PublicId,
        is_local: bool = False,
        registry_path: str = "packages",
        skip_consistency_check: bool = False,
    ) -> "Project":
        """
        Load project with given public_id to working_dir.

        :param working_dir: the working directory
        :param public_id: the public id
        :param is_local: whether to fetch from local or remote
        :param registry_path: the path to the registry locally
        :param skip_consistency_check: consistency checks flag
        """
        ctx = Context(cwd=working_dir, registry_path=registry_path)
        ctx.set_config("skip_consistency_check", skip_consistency_check)
        path = os.path.join(working_dir, public_id.author, public_id.name)
        target_dir = os.path.join(public_id.author, public_id.name)
        if is_local:
            fetch_agent_locally(ctx, public_id, target_dir=target_dir)
        else:
            fetch_agent(ctx, public_id, target_dir=target_dir)
        return cls(public_id, path)
Example #2
0
def fetch_local_or_mixed(ctx: Context, item_type: str,
                         item_id: PublicId) -> None:
    """
    Fetch item, either local or mixed, depending on the parameters/context configuration.

    It will first try to fetch from local registry; in case of failure,
    if the 'is_mixed' flag is set, it will try to fetch from remote registry.

    Context expects 'is_local' and 'is_mixed' to be set.

    :param ctx: the CLI context.
    :param item_type: the type of the package.
    :param item_id: the public id of the item.
    :return: None
    """
    def _raise(item_type_: str, item_id_: PublicId, exception):
        """Temporary function to raise exception (used below twice)."""
        raise click.ClickException(
            f"Failed to add {item_type_} dependency {item_id_}: {str(exception)}"
        )

    try:
        add_item(ctx, item_type, item_id)
    except click.ClickException as e:
        if not ctx.config.get("is_mixed", False):
            _raise(item_type, item_id, e)
        ctx.set_config("is_local", False)
        try:
            add_item(ctx, item_type, item_id)
        except click.ClickException as e:
            _raise(item_type, item_id, e)
        ctx.set_config("is_local", True)
Example #3
0
def do_fetch(
    ctx: Context,
    public_id: PublicId,
    local: bool,
    remote: bool,
    alias: Optional[str] = None,
    target_dir: Optional[str] = None,
) -> None:
    """
    Run the Fetch command.

    :param ctx: the CLI context.
    :param public_id: the public id.
    :param local: whether to fetch from local
    :param remote whether to fetch from remote
    :param alias: the agent alias.
    :param target_dir: the target directory, in case fetching locally.
    :return: None
    """
    enforce(
        not (local and remote), "'local' and 'remote' options are mutually exclusive."
    )
    is_mixed = not local and not remote
    ctx.set_config("is_local", local and not remote)
    ctx.set_config("is_mixed", is_mixed)
    if remote:
        fetch_agent(ctx, public_id, alias=alias, target_dir=target_dir)
    elif local:
        fetch_agent_locally(ctx, public_id, alias=alias, target_dir=target_dir)
    else:
        fetch_mixed(ctx, public_id, alias=alias, target_dir=target_dir)
Example #4
0
def _fetch_agent_deps(ctx: Context, is_mixed: bool = True) -> None:
    """
    Fetch agent dependencies.

    :param ctx: context object.
    :param is_mixed: flag to enable mixed mode (try first local, then remote).

    :return: None
    :raises: ClickException re-raises if occurs in add_item call.
    """
    ctx.set_config("is_local", True)
    ctx.set_config("is_mixed", is_mixed)
    for item_type in ("protocol", "contract", "connection", "skill"):
        item_type_plural = "{}s".format(item_type)
        required_items = getattr(ctx.agent_config, item_type_plural)
        for item_id in required_items:
            fetch_local_or_mixed(ctx, item_type, item_id)
Example #5
0
def add_item(agent_id: str, item_type: str, item_id: str):
    """Add a protocol, skill or connection to the register to a local agent."""
    ctx = Context(cwd=os.path.join(app_context.agents_dir, agent_id))
    ctx.set_config("is_local", app_context.local)
    try:
        try_to_load_agent_config(ctx)
        cli_add_item(ctx, item_type, PublicId.from_str(item_id))
    except ClickException as e:
        return (
            {
                "detail": "Failed to add {} {} to agent {}. {}".format(
                    item_type, item_id, agent_id, str(e)
                )
            },
            400,
        )  # 400 Bad request
    else:
        return agent_id, 201  # 200 (OK)
Example #6
0
def setup_search_ctx(ctx: Context, local: bool) -> None:
    """
    Set up search command.

    :param click_context: click context object.
    :param local: bool flag for local search.

    :return: None.
    """
    if local:
        ctx.set_config("is_local", True)
        # if we are in an agent directory, try to load the configuration file.
        # otherwise, use the default path (i.e. 'packages/' in the current directory.)
        try:
            try_to_load_agent_config(ctx, is_exit_on_except=False)
            registry_directory = ctx.agent_config.registry_path
        except Exception:  # pylint: disable=broad-except
            registry_directory = os.path.join(ctx.cwd, DEFAULT_REGISTRY_PATH)

        ctx.set_config("registry_directory", registry_directory)
        logger.debug("Using registry {}".format(registry_directory))
Example #7
0
def _fetch_agent_deps(ctx: Context) -> None:
    """
    Fetch agent dependencies.

    :param ctx: context object.

    :return: None
    :raises: ClickException re-raises if occures in add_item call.
    """
    ctx.set_config("is_local", True)

    for item_type in ("protocol", "contract", "connection", "skill"):
        item_type_plural = "{}s".format(item_type)
        required_items = getattr(ctx.agent_config, item_type_plural)
        for item_id in required_items:
            try:
                add_item(ctx, item_type, item_id)
            except click.ClickException as e:
                raise click.ClickException(
                    "Failed to add {} dependency {}: {}".format(
                        item_type, item_id, str(e)))
Example #8
0
    def load(
        cls,
        working_dir: str,
        public_id: PublicId,
        is_local: bool = False,
        is_remote: bool = False,
        is_restore: bool = False,
        registry_path: str = DEFAULT_REGISTRY_NAME,
        skip_consistency_check: bool = False,
    ) -> "Project":
        """
        Load project with given public_id to working_dir.

        If local = False and remote = False, then the packages
        are fetched in mixed mode (i.e. first try from local
        registry, and then from remote registry in case of failure).

        :param working_dir: the working directory
        :param public_id: the public id
        :param is_local: whether to fetch from local
        :param is_remote whether to fetch from remote
        :param registry_path: the path to the registry locally
        :param skip_consistency_check: consistency checks flag
        """
        ctx = Context(cwd=working_dir, registry_path=registry_path)
        ctx.set_config("skip_consistency_check", skip_consistency_check)

        path = os.path.join(working_dir, public_id.author, public_id.name)
        target_dir = os.path.join(public_id.author, public_id.name)

        if not is_restore and not os.path.exists(target_dir):
            do_fetch(ctx,
                     public_id,
                     is_local,
                     is_remote,
                     target_dir=target_dir)
        return cls(public_id, path)
Example #9
0
def test_create_and_run_agent():
    """Test for running and agent, reading TTY and errors."""
    # Set up a temporary current working directory in which to make agents
    with TempCWD() as temp_cwd:
        app = create_app()

        # copy the 'packages' directory in the parent of the agent folder.
        shutil.copytree(Path(CUR_PATH, "..", "packages"),
                        Path(temp_cwd.temp_dir, "packages"))

        agent_id = "test_agent"

        # Make an agent
        # We do it programmatically as we need to create an agent with default author
        # that was prevented from GUI.
        ctx = Context(cwd=temp_cwd.temp_dir)
        ctx.set_config("is_local", True)
        create_aea(ctx, agent_id, local=True, author=DEFAULT_AUTHOR)

        # Add the local connection
        with patch("aea.cli_gui.app_context.local", True):
            response_add = app.post(
                "api/agent/" + agent_id + "/connection",
                content_type="application/json",
                data=json.dumps(str(LOCAL_PUBLIC_ID)),
            )
            assert response_add.status_code == 201

        # Get the running status before we have run it
        response_status = app.get(
            "api/agent/" + agent_id + "/run",
            data=None,
            content_type="application/json",
        )
        assert response_status.status_code == 200
        data = json.loads(response_status.get_data(as_text=True))
        assert "NOT_STARTED" in data["status"]

        # run the agent with a non existent connection
        response_run = app.post(
            "api/agent/" + agent_id + "/run",
            content_type="application/json",
            data=json.dumps("author/non-existent-connection:0.1.0"),
        )
        assert response_run.status_code == 400

        # run the agent with default connection - should be something in the error output?
        response_run = app.post(
            "api/agent/" + agent_id + "/run",
            content_type="application/json",
            data=json.dumps(""),
        )
        assert response_run.status_code == 201
        time.sleep(2)

        # Stop the agent running
        response_stop = app.delete(
            "api/agent/" + agent_id + "/run",
            data=None,
            content_type="application/json",
        )
        assert response_stop.status_code == 200
        time.sleep(2)

        # run the agent with stub connection
        response_run = app.post(
            "api/agent/" + agent_id + "/run",
            content_type="application/json",
            data=json.dumps(str(STUB_CONNECTION_PUBLIC_ID)),
        )
        assert response_run.status_code == 201

        time.sleep(2)

        # Try running it again (this should fail)
        response_run = app.post(
            "api/agent/" + agent_id + "/run",
            content_type="application/json",
            data=json.dumps(str(STUB_CONNECTION_PUBLIC_ID)),
        )
        assert response_run.status_code == 400

        # Get the running status
        response_status = app.get(
            "api/agent/" + agent_id + "/run",
            data=None,
            content_type="application/json",
        )
        assert response_status.status_code == 200
        data = json.loads(response_status.get_data(as_text=True))

        assert data["error"] == ""
        assert "RUNNING" in data["status"]
        app.delete(
            "api/agent/" + agent_id + "/run",
            data=None,
            content_type="application/json",
        )
        time.sleep(1)

        # Get the running status
        response_status = app.get(
            "api/agent/" + agent_id + "/run",
            data=None,
            content_type="application/json",
        )
        assert response_status.status_code == 200
        data = json.loads(response_status.get_data(as_text=True))
        assert "process terminate" in data["error"]
        assert "NOT_STARTED" in data["status"]

        # run the agent again (takes a different path through code)
        response_run = app.post(
            "api/agent/" + agent_id + "/run",
            content_type="application/json",
            data=json.dumps(str(STUB_CONNECTION_PUBLIC_ID)),
        )
        assert response_run.status_code == 201

        time.sleep(2)

        # Get the running status
        response_status = app.get(
            "api/agent/" + agent_id + "/run",
            data=None,
            content_type="application/json",
        )
        assert response_status.status_code == 200
        data = json.loads(response_status.get_data(as_text=True))

        assert data["error"] == ""
        assert "RUNNING" in data["status"]

        # Stop the agent running
        response_stop = app.delete(
            "api/agent/" + agent_id + "/run",
            data=None,
            content_type="application/json",
        )
        assert response_stop.status_code == 200
        time.sleep(2)

        # Get the running status
        response_status = app.get(
            "api/agent/" + agent_id + "/run",
            data=None,
            content_type="application/json",
        )
        assert response_status.status_code == 200
        data = json.loads(response_status.get_data(as_text=True))
        assert "process terminate" in data["error"]
        assert "NOT_STARTED" in data["status"]

        # Stop a none existent agent running
        response_stop = app.delete(
            "api/agent/" + agent_id + "_NOT" + "/run",
            data=None,
            content_type="application/json",
        )
        assert response_stop.status_code == 400
        time.sleep(2)

        genuine_func = aea.cli_gui.call_aea_async

        def _dummycall_aea_async(param_list, dir_arg):
            assert param_list[0] == sys.executable
            assert param_list[1] == "-m"
            assert param_list[2] == "aea.cli"
            if param_list[3] == "run":
                return None
            else:
                return genuine_func(param_list, dir_arg)

        # Run when process files (but other call - such as status should not fail)
        with patch("aea.cli_gui.call_aea_async", _dummycall_aea_async):
            response_run = app.post(
                "api/agent/" + agent_id + "/run",
                content_type="application/json",
                data=json.dumps(str(STUB_CONNECTION_PUBLIC_ID)),
            )
        assert response_run.status_code == 400
Example #10
0
def create_aea(
    ctx: Context,
    agent_name: str,
    local: bool,
    author: Optional[str] = None,
    empty: bool = False,
) -> None:
    """
    Create AEA project.

    :param ctx: Context object.
    :param local: boolean flag for local folder usage.
    :param agent_name: agent name.
    :param author: optional author name (valid with local=True only).
    :param empty: optional boolean flag for skip adding default dependencies.

    :return: None
    :raises: ClickException if an error occured.
    """
    try:
        _check_is_parent_folders_are_aea_projects_recursively()
    except Exception:
        raise click.ClickException(
            "The current folder is already an AEA project. Please move to the parent folder."
        )

    if author is not None:
        if local:
            do_init(author, False, False)
        else:
            raise click.ClickException(
                "Author is not set up. Please use 'aea init' to initialize.")

    config = get_or_create_cli_config()
    set_author = config.get(AUTHOR_KEY, None)
    if set_author is None:
        raise click.ClickException(
            "The AEA configurations are not initialized. Uses `aea init` before continuing or provide optional argument `--author`."
        )

    if Path(agent_name).exists():
        raise click.ClickException("Directory already exist. Aborting...")

    click.echo("Initializing AEA project '{}'".format(agent_name))
    click.echo("Creating project directory './{}'".format(agent_name))
    path = Path(agent_name)
    ctx.clean_paths.append(str(path))

    # we have already checked that the directory does not exist.
    path.mkdir(exist_ok=False)

    try:
        # set up packages directories.
        _setup_package_folder(Path(agent_name, "protocols"))
        _setup_package_folder(Path(agent_name, "contracts"))
        _setup_package_folder(Path(agent_name, "connections"))
        _setup_package_folder(Path(agent_name, "skills"))

        # set up a vendor directory
        Path(agent_name, "vendor").mkdir(exist_ok=False)
        Path(agent_name, "vendor", "__init__.py").touch(exist_ok=False)

        # create a config file inside it
        click.echo("Creating config file {}".format(DEFAULT_AEA_CONFIG_FILE))
        agent_config = _crete_agent_config(ctx, agent_name, set_author)

        # next commands must be done from the agent's directory -> overwrite ctx.cwd
        ctx.agent_config = agent_config
        ctx.cwd = agent_config.agent_name

        if not empty:
            click.echo("Adding default packages ...")
            if local:
                ctx.set_config("is_local", True)
            add_item(ctx, "connection", DEFAULT_CONNECTION)
            add_item(ctx, "skill", DEFAULT_SKILL)

    except Exception as e:
        raise click.ClickException(str(e))
Example #11
0
def protocol(ctx: Context, protocol_specification_path: str,
             language: str) -> None:
    """Generate a protocol based on a specification and add it to the configuration file and agent."""
    ctx.set_config("language", language)
    _generate_protocol(ctx, protocol_specification_path)