def from_dir(cls, directory: str) -> "Protocol": """ Load a protocol from a directory. :param directory: the skill directory. :param agent_context: the agent's context :return: the Protocol object. :raises Exception: if the parsing failed. """ # check if there is the config file. If not, then return None. protocol_loader = ConfigLoader("protocol-config_schema.json", ProtocolConfig) protocol_config = protocol_loader.load( open(os.path.join(directory, DEFAULT_PROTOCOL_CONFIG_FILE))) protocol_module = load_module("protocols", Path(directory, "serialization.py")) add_agent_component_module_to_sys_modules("protocol", protocol_config.name, protocol_config.author, protocol_module) classes = inspect.getmembers(protocol_module, inspect.isclass) serializer_classes = list( filter(lambda x: re.match("\\w+Serializer", x[0]), classes)) assert len( serializer_classes) == 1, "Not exactly one serializer detected." serializer_class = serializer_classes[0][1] protocol_id = PublicId(protocol_config.author, protocol_config.name, protocol_config.version) protocol = Protocol(protocol_id, serializer_class(), protocol_config) return protocol
def verify_or_create_private_keys(ctx: Context) -> None: """ Verify or create private keys. :param ctx: Context """ path = Path(DEFAULT_AEA_CONFIG_FILE) agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig) fp = path.open(mode="r", encoding="utf-8") aea_conf = agent_loader.load(fp) for identifier, _value in aea_conf.private_key_paths.read_all(): if identifier not in registry.supported_crypto_ids: ValueError("Unsupported identifier in private key paths.") for identifier, private_key_path in IDENTIFIER_TO_KEY_FILES.items(): config_private_key_path = aea_conf.private_key_paths.read(identifier) if config_private_key_path is None: create_private_key(identifier) aea_conf.private_key_paths.update(identifier, private_key_path) else: try: _try_validate_private_key_path(identifier, private_key_path) except FileNotFoundError: # pragma: no cover raise click.ClickException( "File {} for private key {} not found.".format( repr(private_key_path), identifier, ) ) # update aea config path = Path(DEFAULT_AEA_CONFIG_FILE) fp = path.open(mode="w", encoding="utf-8") agent_loader.dump(aea_conf, fp) ctx.agent_config = aea_conf
def _add_protocol(self, directory: str, protocol_name: str): """ Add a protocol. :param directory: the agent's resources directory. :param protocol_name: the name of the protocol to be added. :return: None """ # get the serializer serialization_spec = importlib.util.spec_from_file_location("serialization", os.path.join(directory, "protocols", protocol_name, "serialization.py")) serialization_module = importlib.util.module_from_spec(serialization_spec) serialization_spec.loader.exec_module(serialization_module) # type: ignore classes = inspect.getmembers(serialization_module, inspect.isclass) serializer_classes = list(filter(lambda x: re.match("\\w+Serializer", x[0]), classes)) serializer_class = serializer_classes[0][1] logger.debug("Found serializer class {serializer_class} for protocol {protocol_name}" .format(serializer_class=serializer_class, protocol_name=protocol_name)) serializer = serializer_class() config_loader = ConfigLoader("protocol-config_schema.json", ProtocolConfig) protocol_config = config_loader.load(open(Path(directory, "protocols", protocol_name, DEFAULT_PROTOCOL_CONFIG_FILE))) # instantiate the protocol manager. protocol = Protocol(protocol_name, serializer, protocol_config) self.register((protocol_name, None), protocol)
def _verify_ledger_apis_access() -> None: """Verify access to ledger apis.""" path = Path(DEFAULT_AEA_CONFIG_FILE) agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig) fp = open(str(path), mode="r", encoding="utf-8") aea_conf = agent_loader.load(fp) for identifier, value in aea_conf.ledger_apis.read_all(): if identifier not in SUPPORTED_LEDGER_APIS: ValueError("Unsupported identifier in ledger apis.") fetchai_ledger_api_config = aea_conf.ledger_apis.read(FETCHAI) if fetchai_ledger_api_config is None: logger.debug("No fetchai ledger api config specified.") else: fetchai_ledger_api_config = cast(LedgerAPIConfig, fetchai_ledger_api_config) _try_to_instantiate_fetchai_ledger_api(fetchai_ledger_api_config.addr, fetchai_ledger_api_config.port) ethereum_ledger_config = aea_conf.ledger_apis.read(ETHEREUM) if ethereum_ledger_config is None: logger.debug("No ethereum ledger api config specified.") else: ethereum_ledger_config = cast(LedgerAPIConfig, ethereum_ledger_config) _try_to_instantiate_ethereum_ledger_api(ethereum_ledger_config.addr, ethereum_ledger_config.port)
def _load_protocol_specification_from_string( specification_content: str, ) -> ProtocolSpecification: """Load a protocol specification from string.""" file = StringIO(initial_value=specification_content) config_loader = ConfigLoader("protocol-specification_schema.json", ProtocolSpecification) protocol_spec = config_loader.load_protocol_specification(file) return protocol_spec
def dump_config(self) -> None: """Save agent config on the disc.""" config_data = self.json self.agent_config.validate_config_data( config_data, env_vars_friendly=self.env_vars_friendly) with open_file(self.agent_config_file_path, "w") as file_pointer: ConfigLoader.from_configuration_type(PackageType.AGENT).dump( self.agent_config, file_pointer)
class Context(object): """A class to keep configuration of the cli tool.""" agent_config: AgentConfig def __init__(self, cwd: str = "."): """Init the context.""" self.config = dict() # type: Dict self.agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig) self.skill_loader = ConfigLoader("skill-config_schema.json", SkillConfig) self.connection_loader = ConfigLoader("connection-config_schema.json", ConnectionConfig) self.protocol_loader = ConfigLoader("protocol-config_schema.json", ProtocolConfig) self.cwd = cwd def set_config(self, key, value) -> None: """ Set a config. :param key: the key for the configuration. :param value: the value associated with the key. :return: None """ self.config[key] = value logger.debug(' config[%s] = %s' % (key, value)) def get_dependencies(self) -> List[str]: """Aggregate the dependencies from every component. :return a list of dependency version specification. e.g. ["gym >= 1.0.0"] """ dependencies = [] # type: List[str] for protocol_id in self.agent_config.protocols: path = str( Path("protocols", protocol_id, DEFAULT_PROTOCOL_CONFIG_FILE)) protocol_config = self.protocol_loader.load(open(path)) deps = cast(List[str], protocol_config.dependencies) dependencies.extend(deps) for connection_id in self.agent_config.connections: path = str( Path("connections", connection_id, DEFAULT_CONNECTION_CONFIG_FILE)) connection_config = self.connection_loader.load(open(path)) deps = cast(List[str], connection_config.dependencies) dependencies.extend(deps) for skill_id in self.agent_config.skills: path = str(Path("skills", skill_id, DEFAULT_SKILL_CONFIG_FILE)) skill_config = self.skill_loader.load(open(path)) deps = cast(List[str], skill_config.dependencies) dependencies.extend(deps) return sorted(set(dependencies))
def test_compare_latest_generator_output_with_test_protocol(self): """Test that the "t_protocol" test protocol matches with what the latest generator generates based on the specification.""" # check protoc is installed res = shutil.which("protoc") if res is None: pytest.skip( "Please install protocol buffer first! See the following link: https://developers.google.com/protocol-buffers/" ) # Specification protocol_name = "t_protocol" path_to_specification = os.path.join(self.cwd, "tests", "data", "sample_specification.yaml") path_to_generated_protocol = self.t path_to_original_protocol = os.path.join(self.cwd, "tests", "data", "generator", protocol_name) path_to_package = "tests.data.generator." # Load the config config_loader = ConfigLoader("protocol-specification_schema.json", ProtocolSpecification) protocol_specification = config_loader.load_protocol_specification( open(path_to_specification)) # Generate the protocol protocol_generator = ProtocolGenerator( protocol_specification, path_to_generated_protocol, path_to_protocol_package=path_to_package, ) protocol_generator.generate() # Apply black try: subp = subprocess.Popen( # nosec [ sys.executable, "-m", "black", os.path.join(path_to_generated_protocol, protocol_name), "--quiet", ]) subp.wait(10.0) finally: poll = subp.poll() if poll is None: # pragma: no cover subp.terminate() subp.wait(5) # compare __init__.py init_file_generated = Path(self.t, protocol_name, "__init__.py") init_file_original = Path( path_to_original_protocol, "__init__.py", ) assert filecmp.cmp(init_file_generated, init_file_original)
def __init__(self, cwd: str = "."): """Init the context.""" self.config = dict() # type: Dict self.agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig) self.skill_loader = ConfigLoader("skill-config_schema.json", SkillConfig) self.connection_loader = ConfigLoader("connection-config_schema.json", ConnectionConfig) self.protocol_loader = ConfigLoader("protocol-config_schema.json", ProtocolConfig) self.cwd = cwd
def load_protocol_specification(specification_path: str) -> ProtocolSpecification: """ Load a protocol specification. :param specification_path: path to the protocol specification yaml file. :return: A ProtocolSpecification object """ config_loader = ConfigLoader( "protocol-specification_schema.json", ProtocolSpecification ) protocol_spec = config_loader.load_protocol_specification(open(specification_path)) return protocol_spec
def from_dir(cls, directory: str, agent_context: AgentContext) -> 'Skill': """ Load a skill from a directory. :param directory: the skill :param agent_context: the agent's context :return: the Skill object. :raises Exception: if the parsing failed. """ # check if there is the config file. If not, then return None. skill_loader = ConfigLoader("skill-config_schema.json", SkillConfig) skill_config = skill_loader.load(open(os.path.join(directory, DEFAULT_SKILL_CONFIG_FILE))) skills_spec = importlib.util.spec_from_file_location(skill_config.name, os.path.join(directory, "__init__.py")) skill_module = importlib.util.module_from_spec(skills_spec) sys.modules[skill_config.name + "_skill"] = skill_module loader_contents = [path.name for path in Path(directory).iterdir()] skills_packages = list(filter(lambda x: not x.startswith("__"), loader_contents)) # type: ignore logger.debug("Processing the following skill package: {}".format(skills_packages)) skill_context = SkillContext(agent_context) handlers_by_id = skill_config.handlers.read_all() if len(handlers_by_id) > 0: handlers_configurations = list(dict(handlers_by_id).values()) handlers = Handler.parse_module(os.path.join(directory, "handlers.py"), handlers_configurations, skill_context) else: handlers = [] behaviours_by_id = skill_config.behaviours.read_all() if len(behaviours_by_id) > 0: behaviours_configurations = list(dict(behaviours_by_id).values()) behaviours = Behaviour.parse_module(os.path.join(directory, "behaviours.py"), behaviours_configurations, skill_context) else: behaviours = [] tasks_by_id = skill_config.tasks.read_all() if len(tasks_by_id) > 0: tasks_configurations = list(dict(tasks_by_id).values()) tasks = Task.parse_module(os.path.join(directory, "tasks.py"), tasks_configurations, skill_context) else: tasks = [] shared_classes_by_id = skill_config.shared_classes.read_all() if len(shared_classes_by_id) > 0: shared_classes_configurations = list(dict(shared_classes_by_id).values()) shared_classes_instances = SharedClass.parse_module(directory, shared_classes_configurations, skill_context) else: shared_classes_instances = [] skill = Skill(skill_config, skill_context, handlers, behaviours, tasks, shared_classes_instances) skill_context._skill = skill return skill
def _verify_or_create_private_keys(aea_project_path: Path) -> None: """Verify or create private keys.""" path_to_configuration = aea_project_path / DEFAULT_AEA_CONFIG_FILE agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig) fp_read = path_to_configuration.open(mode="r", encoding="utf-8") agent_configuration = agent_loader.load(fp_read) for identifier, _value in agent_configuration.private_key_paths.read_all(): if identifier not in SUPPORTED_CRYPTOS: ValueError("Unsupported identifier in private key paths.") fetchai_private_key_path = agent_configuration.private_key_paths.read(FETCHAI) if fetchai_private_key_path is None: _create_fetchai_private_key( private_key_file=str(aea_project_path / FETCHAI_PRIVATE_KEY_FILE) ) agent_configuration.private_key_paths.update(FETCHAI, FETCHAI_PRIVATE_KEY_FILE) else: try: _try_validate_fet_private_key_path( str(aea_project_path / fetchai_private_key_path), exit_on_error=False ) except FileNotFoundError: # pragma: no cover logger.error( "File {} for private key {} not found.".format( repr(fetchai_private_key_path), FETCHAI, ) ) raise ethereum_private_key_path = agent_configuration.private_key_paths.read(ETHEREUM) if ethereum_private_key_path is None: _create_ethereum_private_key( private_key_file=str(aea_project_path / ETHEREUM_PRIVATE_KEY_FILE) ) agent_configuration.private_key_paths.update( ETHEREUM, ETHEREUM_PRIVATE_KEY_FILE ) else: try: _try_validate_ethereum_private_key_path( str(aea_project_path / ethereum_private_key_path), exit_on_error=False ) except FileNotFoundError: # pragma: no cover logger.error( "File {} for private key {} not found.".format( repr(ethereum_private_key_path), ETHEREUM, ) ) raise fp_write = path_to_configuration.open(mode="w", encoding="utf-8") agent_loader.dump(agent_configuration, fp_write)
def from_dir(cls, directory: str, agent_context: AgentContext) -> "Skill": """ Load a skill from a directory. :param directory: the skill directory. :param agent_context: the agent's context :return: the Skill object. :raises Exception: if the parsing failed. """ # check if there is the config file. If not, then return None. skill_loader = ConfigLoader("skill-config_schema.json", SkillConfig) skill_config = skill_loader.load( open(os.path.join(directory, DEFAULT_SKILL_CONFIG_FILE))) skill_module = load_agent_component_package("skill", skill_config.name, skill_config.author, Path(directory)) add_agent_component_module_to_sys_modules("skill", skill_config.name, skill_config.author, skill_module) loader_contents = [path.name for path in Path(directory).iterdir()] skills_packages = list( filter(lambda x: not x.startswith("__"), loader_contents)) # type: ignore logger.debug("Processing the following skill package: {}".format( skills_packages)) skill_context = SkillContext(agent_context) # set the logger of the skill context. logger_name = "aea.{}.skills.{}.{}".format(agent_context.agent_name, skill_config.author, skill_config.name) skill_context._logger = logging.getLogger(logger_name) handlers_by_id = dict(skill_config.handlers.read_all()) handlers = Handler.parse_module(os.path.join(directory, "handlers.py"), handlers_by_id, skill_context) behaviours_by_id = dict(skill_config.behaviours.read_all()) behaviours = Behaviour.parse_module( os.path.join(directory, "behaviours.py"), behaviours_by_id, skill_context, ) models_by_id = dict(skill_config.models.read_all()) model_instances = Model.parse_module(directory, models_by_id, skill_context) skill = Skill(skill_config, skill_context, handlers, behaviours, model_instances) skill_context._skill = skill return skill
def _add_protocol( self, protocol_directory: Path, allowed_protocols: Optional[Set[PublicId]] = None, ): """ Add a protocol. If the protocol is not allowed, it is ignored. :param protocol_directory: the directory of the protocol to be added. :param allowed_protocols: an optional set of allowed protocols. If None, every protocol is allowed. :return: None """ protocol_name = protocol_directory.name config_loader = ConfigLoader("protocol-config_schema.json", ProtocolConfig) protocol_config = config_loader.load( open(protocol_directory / DEFAULT_PROTOCOL_CONFIG_FILE)) protocol_public_id = PublicId(protocol_config.author, protocol_config.name, protocol_config.version) if (allowed_protocols is not None and protocol_public_id not in allowed_protocols): logger.debug( "Ignoring protocol {}, not declared in the configuration file." .format(protocol_public_id)) return # get the serializer serialization_spec = importlib.util.spec_from_file_location( "serialization", protocol_directory / "serialization.py") serialization_module = importlib.util.module_from_spec( serialization_spec) serialization_spec.loader.exec_module( serialization_module) # type: ignore classes = inspect.getmembers(serialization_module, inspect.isclass) serializer_classes = list( filter(lambda x: re.match("\\w+Serializer", x[0]), classes)) serializer_class = serializer_classes[0][1] logger.debug( "Found serializer class {serializer_class} for protocol {protocol_name}" .format(serializer_class=serializer_class, protocol_name=protocol_name)) serializer = serializer_class() # instantiate the protocol protocol = Protocol(protocol_config.public_id, serializer, protocol_config) self.register(protocol_public_id, protocol)
def _verify_or_create_private_keys(ctx: Context) -> None: """ Verify or create private keys. :param ctx: Context """ path = Path(DEFAULT_AEA_CONFIG_FILE) agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig) fp = path.open(mode="r", encoding="utf-8") aea_conf = agent_loader.load(fp) for identifier, _value in aea_conf.private_key_paths.read_all(): if identifier not in SUPPORTED_CRYPTOS: ValueError("Unsupported identifier in private key paths.") fetchai_private_key_path = aea_conf.private_key_paths.read(FETCHAI) if fetchai_private_key_path is None: _create_fetchai_private_key() aea_conf.private_key_paths.update(FETCHAI, FETCHAI_PRIVATE_KEY_FILE) else: try: _try_validate_fet_private_key_path(fetchai_private_key_path) except FileNotFoundError: # pragma: no cover logger.error("File {} for private key {} not found.".format( repr(fetchai_private_key_path), FETCHAI, )) sys.exit(1) ethereum_private_key_path = aea_conf.private_key_paths.read(ETHEREUM) if ethereum_private_key_path is None: _create_ethereum_private_key() aea_conf.private_key_paths.update(ETHEREUM, ETHEREUM_PRIVATE_KEY_FILE) else: try: _try_validate_ethereum_private_key_path(ethereum_private_key_path) except FileNotFoundError: # pragma: no cover logger.error("File {} for private key {} not found.".format( repr(ethereum_private_key_path), ETHEREUM, )) sys.exit(1) # update aea config path = Path(DEFAULT_AEA_CONFIG_FILE) fp = path.open(mode="w", encoding="utf-8") agent_loader.dump(aea_conf, fp) ctx.agent_config = aea_conf
def fingerprint_package(package_dir: Path, package_type: Union[str, PackageType]) -> None: """ Fingerprint components of an item. :param ctx: the context. :param item_type: the item type. :param item_public_id: the item public id. :return: None """ package_type = PackageType(package_type) item_type = str(package_type) default_config_file_name = _get_default_configuration_file_name_from_type( item_type) config_loader = ConfigLoader.from_configuration_type(item_type) config_file_path = Path(package_dir, default_config_file_name) config = config_loader.load(open_file(config_file_path)) if not package_dir.exists(): # we only permit non-vendorized packages to be fingerprinted raise ValueError("Package not found at path {}".format(package_dir)) fingerprints_dict = _compute_fingerprint( package_dir, ignore_patterns=config.fingerprint_ignore_patterns ) # type: Dict[str, str] # Load item specification yaml file and add fingerprints config.fingerprint = fingerprints_dict config_loader.dump(config, open_file(config_file_path, "w"))
def loader(self) -> ConfigLoader: """ Create ConfigLoader for Agent config. :return: ConfigLoader for AgentConfig """ return ConfigLoader.from_configuration_type(PackageType.AGENT)
def _run_interaction_channel(): # load agent configuration file loader = ConfigLoader.from_configuration_type(PackageType.AGENT) agent_configuration = loader.load(Path(DEFAULT_AEA_CONFIG_FILE).open()) agent_name = agent_configuration.name # load stub connection configuration = ConnectionConfig( input_file=DEFAULT_OUTPUT_FILE_NAME, output_file=DEFAULT_INPUT_FILE_NAME, connection_id=StubConnection.connection_id, ) identity_stub = Identity(agent_name + "_interact", "interact") stub_connection = StubConnection(configuration=configuration, identity=identity_stub) multiplexer = Multiplexer([stub_connection]) inbox = InBox(multiplexer) outbox = OutBox(multiplexer, default_address=identity_stub.address) dialogues = DefaultDialogues(identity_stub.name) try: multiplexer.connect() while True: # pragma: no cover _process_envelopes(agent_name, identity_stub, inbox, outbox, dialogues) except KeyboardInterrupt: click.echo("Interaction interrupted!") except BaseException as e: # pylint: disable=broad-except # pragma: no cover click.echo(e) finally: multiplexer.disconnect()
def test_agent_config_updated(self): """Test the agent configuration is updated.""" loader = ConfigLoader.from_configuration_type(PackageType.AGENT) with Path(self._get_cwd(), DEFAULT_AEA_CONFIG_FILE).open() as fp: agent_config = loader.load(fp) assert DefaultMessage.protocol_id in agent_config.protocols assert ERROR_SKILL_PUBLIC_ID in agent_config.skills
def bump_version_in_yaml(configuration_file_path: Path, type_: str, version: str) -> None: """Bump the package version in the package yaml.""" loader = ConfigLoader.from_configuration_type(type_[:-1]) config = loader.load(configuration_file_path.open()) config.version = version loader.dump(config, open(configuration_file_path, "w"))
def _run_interaction_channel(): loader = ConfigLoader.from_configuration_type(PackageType.AGENT) agent_configuration = loader.load(Path(DEFAULT_AEA_CONFIG_FILE).open()) agent_name = agent_configuration.name identity_stub = Identity(agent_name + "_interact", "interact") _load_packages(identity_stub) # load agent configuration file from packages.fetchai.connections.stub.connection import ( # noqa: F811 # pylint: disable=import-outside-toplevel DEFAULT_INPUT_FILE_NAME, DEFAULT_OUTPUT_FILE_NAME, StubConnection, ) from packages.fetchai.protocols.default.dialogues import ( # noqa: F811 # pylint: disable=import-outside-toplevel DefaultDialogue, DefaultDialogues, ) from packages.fetchai.protocols.default.message import ( # noqa: F811 # pylint: disable=import-outside-toplevel DefaultMessage, ) # load stub connection configuration = ConnectionConfig( input_file=DEFAULT_OUTPUT_FILE_NAME, output_file=DEFAULT_INPUT_FILE_NAME, connection_id=StubConnection.connection_id, ) stub_connection = StubConnection( configuration=configuration, identity=identity_stub ) multiplexer = Multiplexer([stub_connection]) inbox = InBox(multiplexer) outbox = OutBox(multiplexer) def role_from_first_message( # pylint: disable=unused-argument message: Message, receiver_address: Address ) -> BaseDialogue.Role: """Infer the role of the agent from an incoming/outgoing first message :param message: an incoming/outgoing first message :param receiver_address: the address of the receiving agent :return: The role of the agent """ return DefaultDialogue.Role.AGENT dialogues = DefaultDialogues(identity_stub.name, role_from_first_message) try: multiplexer.connect() while True: # pragma: no cover _process_envelopes(agent_name, inbox, outbox, dialogues, DefaultMessage) except KeyboardInterrupt: click.echo("Interaction interrupted!") except BaseException as e: # pylint: disable=broad-except # pragma: no cover click.echo(e) finally: multiplexer.disconnect()
def _get_item_details(ctx, item_type) -> List[Dict]: """Return a list of item details, given the item type.""" result = [] item_type_plural = item_type + "s" public_ids = getattr(ctx.agent_config, item_type_plural) # type: Set[PublicId] default_file_name = _get_default_configuration_file_name_from_type( item_type) for public_id in public_ids: # first, try to retrieve the item from the vendor directory. configuration_filepath = Path( ctx.cwd, "vendor", public_id.author, item_type_plural, public_id.name, default_file_name, ) # otherwise, if it does not exist, retrieve the item from the agent custom packages if not configuration_filepath.exists(): configuration_filepath = Path(ctx.cwd, item_type_plural, public_id.name, default_file_name) configuration_loader = ConfigLoader.from_configuration_type( PackageType(item_type)) details = retrieve_details(public_id.name, configuration_loader, str(configuration_filepath)) result.append(details) return result
def _load_agent_config(self) -> AgentConfig: """Load the agent configuration.""" config_loader = ConfigLoader.from_configuration_type( ConfigurationType.AGENT) agent_config = config_loader.load( open(os.path.join(self.directory, DEFAULT_AEA_CONFIG_FILE))) return agent_config
def test_config_loader_dump(): """Test ConfigLoader.dump""" config_loader = ConfigLoader.from_configuration_type(PackageType.PROTOCOL) configuration = MagicMock() with mock.patch.object(aea.configurations.loader, "yaml_dump"), mock.patch( "jsonschema.Draft4Validator.validate" ), mock.patch("builtins.open"): config_loader.dump(configuration, open("foo"))
def _add_item(click_context, item_type, item_public_id) -> None: """ Add an item. :param click_context: the click context. :param item_type: the item type. :param item_public_id: the item public id. :return: None """ ctx = cast(Context, click_context.obj) agent_name = cast(str, ctx.agent_config.agent_name) item_type_plural = item_type + "s" supported_items = getattr(ctx.agent_config, item_type_plural) is_local = ctx.config.get("is_local") click.echo("Adding {} '{}' to the agent '{}'...".format( item_type, item_public_id, agent_name)) # check if we already have an item with the same name logger.debug("{} already supported by the agent: {}".format( item_type_plural.capitalize(), supported_items)) if _is_item_present(item_type, item_public_id, ctx): logger.error("A {} with id '{}/{}' already exists. Aborting...".format( item_type, item_public_id.author, item_public_id.name)) sys.exit(1) # find and add protocol if item_public_id in [DEFAULT_CONNECTION, DEFAULT_PROTOCOL, DEFAULT_SKILL]: package_path = _find_item_in_distribution(ctx, item_type, item_public_id) _copy_package_directory(ctx, package_path, item_type, item_public_id.name, item_public_id.author) elif is_local: package_path = _find_item_locally(ctx, item_type, item_public_id) _copy_package_directory(ctx, package_path, item_type, item_public_id.name, item_public_id.author) else: package_path = fetch_package(item_type, public_id=item_public_id, cwd=ctx.cwd) if item_type in {"connection", "skill"}: configuration_file_name = _get_default_configuration_file_name_from_type( item_type) configuration_path = package_path / configuration_file_name configuration_loader = ConfigLoader.from_configuration_type( ConfigurationType(item_type)) item_configuration = configuration_loader.load( configuration_path.open()) _add_protocols(click_context, item_configuration.protocols) # add the item to the configurations. logger.debug("Registering the {} into {}".format(item_type, DEFAULT_AEA_CONFIG_FILE)) supported_items.add(item_public_id) ctx.agent_loader.dump( ctx.agent_config, open(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), "w"))
def verify_or_create_private_keys( aea_project_path: Path, exit_on_error: bool = True, ) -> AgentConfig: """ Verify or create private keys. :param ctx: Context """ path_to_aea_config = aea_project_path / DEFAULT_AEA_CONFIG_FILE agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig) fp = path_to_aea_config.open(mode="r", encoding="utf-8") aea_conf = agent_loader.load(fp) for identifier, _value in aea_conf.private_key_paths.read_all(): if identifier not in crypto_registry.supported_ids: # pragma: nocover ValueError("Unsupported identifier in private key paths.") for identifier, private_key_path in IDENTIFIER_TO_KEY_FILES.items(): config_private_key_path = aea_conf.private_key_paths.read(identifier) if config_private_key_path is None: if identifier == aea_conf.default_ledger: # pragma: nocover create_private_key( identifier, private_key_file=str(aea_project_path / private_key_path), ) aea_conf.private_key_paths.update(identifier, private_key_path) else: try: try_validate_private_key_path( identifier, str(aea_project_path / private_key_path), exit_on_error=exit_on_error, ) except FileNotFoundError: # pragma: no cover raise ValueError( "File {} for private key {} not found.".format( repr(private_key_path), identifier, )) # update aea config fp = path_to_aea_config.open(mode="w", encoding="utf-8") agent_loader.dump(aea_conf, fp) return aea_conf
def retrieve_details(name: str, loader: ConfigLoader, config_filepath: str): """Return description of a protocol, skill or connection.""" config = loader.load(open(str(config_filepath))) assert config.name == name return { "name": config.name, "description": config.description, "version": config.version }
def test_config_loader_dump_agent_config(): """Test ConfigLoader.dump""" config_loader = ConfigLoader.from_configuration_type(PackageType.AGENT) configuration = MagicMock(ordered_json={"component_configurations": []}) with mock.patch.object(aea.configurations.loader, "yaml_dump_all"), mock.patch.object( ConfigValidator, "_validate"), mock.patch("builtins.open"): config_loader.dump(configuration, open("foo"))
def populate_skills( self, directory: str, agent_context: AgentContext, allowed_skills: Optional[Set[PublicId]] = None, ) -> None: """ Populate skills. :param directory: the agent's resources directory. :param agent_context: the agent's context object :param allowed_skills: an optional set of allowed skills (public ids). If None, every skill is allowed. :return: None """ skill_directory_paths = set() # type: ignore # find all skill directories from vendor/*/skills skill_directory_paths.update( Path(directory, "vendor").glob("./*/skills/*/")) # find all skill directories from skills/ skill_directory_paths.update(Path(directory, "skills").glob("./*/")) skills_packages_paths = list( filter( lambda x: PACKAGE_NAME_REGEX.match(str(x.name)) and x.is_dir(), skill_directory_paths, )) # type: ignore logger.debug("Found the following skill packages: {}".format( pprint.pformat(map(str, skills_packages_paths)))) for skill_directory in skills_packages_paths: logger.debug( "Processing the following skill directory: '{}".format( skill_directory)) try: skill_loader = ConfigLoader.from_configuration_type( ConfigurationType.SKILL) skill_config = skill_loader.load( open(skill_directory / DEFAULT_SKILL_CONFIG_FILE)) if (allowed_skills is not None and skill_config.public_id not in allowed_skills): logger.debug( "Ignoring skill {}, not declared in the configuration file." .format(skill_config.public_id)) continue else: skill = Skill.from_dir(str(skill_directory), agent_context) assert skill is not None self.add_skill(skill) except Exception as e: logger.warning( "A problem occurred while parsing the skill directory {}. Exception: {}" .format(skill_directory, str(e)))
def from_dir(cls, directory: str, agent_context: AgentContext) -> Optional['Skill']: """ Load a skill from a directory. :param directory: the skill :param agent_context: the agent's context :return: the Skill object. None if the parsing failed. """ # check if there is the config file. If not, then return None. skill_loader = ConfigLoader("skill-config_schema.json", SkillConfig) skill_config = skill_loader.load(open(os.path.join(directory, DEFAULT_SKILL_CONFIG_FILE))) if skill_config is None: return None skills_spec = importlib.util.spec_from_file_location(skill_config.name, os.path.join(directory, "__init__.py")) if skills_spec is None: logger.warning("No skill found.") return None skill_module = importlib.util.module_from_spec(skills_spec) sys.modules[skill_config.name + "_skill"] = skill_module skills_packages = list(filter(lambda x: not x.startswith("__"), skills_spec.loader.contents())) # type: ignore logger.debug("Processing the following skill package: {}".format(skills_packages)) skill_context = SkillContext(agent_context) handlers_configurations = list(dict(skill_config.handlers.read_all()).values()) handlers = Handler.parse_module(os.path.join(directory, "handlers.py"), handlers_configurations, skill_context) behaviours_configurations = list(dict(skill_config.behaviours.read_all()).values()) behaviours = Behaviour.parse_module(os.path.join(directory, "behaviours.py"), behaviours_configurations, skill_context) tasks_configurations = list(dict(skill_config.tasks.read_all()).values()) tasks = Task.parse_module(os.path.join(directory, "tasks.py"), tasks_configurations, skill_context) shared_classes_configurations = list(dict(skill_config.shared_classes.read_all()).values()) shared_classes_instances = SharedClass.parse_module(directory, shared_classes_configurations, skill_context) skill = Skill(skill_config, skill_context, handlers, behaviours, tasks, shared_classes_instances) skill_context._skill = skill return skill