Skip to content

Commit

Permalink
Merge pull request #982 from fetchai/develop
Browse files Browse the repository at this point in the history
Release v0.2.4
  • Loading branch information
DavidMinarsch authored Mar 25, 2020
2 parents 4404811 + d15aea6 commit 05ed40b
Show file tree
Hide file tree
Showing 234 changed files with 17,553 additions and 4,924 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ jobs:
run: |
pip install pipenv
pip install tox
sudo apt-get clean
sudo apt-get install -y protobuf-compiler
- name: Security Check - Main
run: tox -e bandit-main
- name: Security Check - Tests
Expand Down
9 changes: 9 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Release History

## 0.2.4 (2020-03-25)

- Breaking change to all protocols as we transition to auto-generated protocols
- Fixes to protocol generator to move it to alpha status
- Updates to documentation on protocols and OEF search and communication nodes
- Improvements and fixes to AEA launch command
- Multiple docs updates and restructuring
- Multiple additional minor fixes and changes

## 0.2.3 (2020-03-19)

- Fixes stub connection file I/O
Expand Down
2 changes: 2 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ verify_ssl = true
name = "test-pypi"

[dev-packages]
aries-cloudagent = "==0.4.5"
bandit = "==1.6.2"
black = "==19.10b0"
bs4 = "==0.0.1"
Expand Down Expand Up @@ -37,6 +38,7 @@ pytest = "==5.3.5"
pytest-asyncio = "==0.10.0"
pytest-cov = "==2.8.1"
pytest-randomly = "==3.2.1"
requests = "==2.23.0"
safety = "==1.8.5"
tox = "==3.14.5"

Expand Down
2 changes: 1 addition & 1 deletion aea/__version__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
__title__ = "aea"
__description__ = "Autonomous Economic Agent framework"
__url__ = "https://github.com/fetchai/agents-aea.git"
__version__ = "0.2.3"
__version__ = "0.2.4"
__author__ = "Fetch.AI Limited"
__license__ = "Apache-2.0"
__copyright__ = "2019 Fetch.AI Limited"
56 changes: 48 additions & 8 deletions aea/cli/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import os
import shutil
import subprocess # nosec
import sys

import click
Expand All @@ -35,6 +36,7 @@
from aea.configurations.base import (
DEFAULT_AEA_CONFIG_FILE,
ProtocolSpecification,
ProtocolSpecificationParseError,
PublicId,
)
from aea.configurations.loader import ConfigLoader
Expand All @@ -50,13 +52,21 @@ def generate(ctx: Context):

def _generate_item(ctx: Context, item_type, specification_path):
"""Generate an item based on a specification and add it to the configuration file and agent."""
# # check protocol buffer compiler is installed
# res = shutil.which("protoc")
# if res is None:
# print(
# "Please install protocol buffer first! See the following link: https://developers.google.com/protocol-buffers/"
# )
# sys.exit(1)
# check protocol buffer compiler is installed
res = shutil.which("protoc")
if res is None:
logger.error(
"Please install protocol buffer first! See the following link: https://developers.google.com/protocol-buffers/"
)
sys.exit(1)

# check black code formatter is installed
res = shutil.which("black")
if res is None:
logger.error(
"Please install black code formater first! See the following link: https://black.readthedocs.io/en/stable/installation_and_usage.html"
)
sys.exit(1)

# Get existing items
existing_id_list = getattr(ctx.agent_config, "{}s".format(item_type))
Expand Down Expand Up @@ -129,13 +139,43 @@ def _generate_item(ctx: Context, item_type, specification_path):
)
)
sys.exit(1)
except ProtocolSpecificationParseError as e:
logger.error(
"The following error happened while parsing the protocol specification: "
+ str(e)
)
shutil.rmtree(
os.path.join(item_type_plural, protocol_spec.name), ignore_errors=True
)
sys.exit(1)
except Exception as e:
logger.exception(e)
logger.debug("Exception thrown: " + str(e))
logger.error(
"There was an error while generating the protocol. The protocol is NOT generated."
)
shutil.rmtree(
os.path.join(item_type_plural, protocol_spec.name), ignore_errors=True
)
sys.exit(1)

# Run black code formatting
try:
subp = subprocess.Popen( # nosec
[
sys.executable,
"-m",
"black",
os.path.join(item_type_plural, protocol_spec.name),
"--quiet",
]
)
subp.wait(10.0)
finally:
poll = subp.poll()
if poll is None: # pragma: no cover
subp.terminate()
subp.wait(5)


@generate.command()
@click.argument("protocol_specification_path", type=str, required=True)
Expand Down
6 changes: 2 additions & 4 deletions aea/cli/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,8 @@ def _build_aea(ctx: Context, connection_ids: List[PublicId]) -> AEA:
ctx.agent_config.ledger_apis_dict, ctx.agent_config.default_ledger
)

default_connection_id = PublicId.from_str(ctx.agent_config.default_connection)
connection_ids = (
[default_connection_id] if connection_ids is None else connection_ids
)
all_connection_ids = ctx.agent_config.connections
connection_ids = all_connection_ids if connection_ids is None else connection_ids
connections = []
try:
for connection_id in connection_ids:
Expand Down
2 changes: 1 addition & 1 deletion aea/cli_gui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ def _kill_running_oef_nodes():
)
stdout = b""
try:
process.wait(5.0)
process.wait(10.0)
(stdout, stderr) = process.communicate()
image_ids.update(stdout.decode("utf-8").splitlines())
finally:
Expand Down
10 changes: 6 additions & 4 deletions aea/configurations/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,21 @@
# ------------------------------------------------------------------------------

"""Classes to handle AEA configurations."""

import re
from abc import ABC, abstractmethod
from enum import Enum
from typing import Dict, Generic, List, Optional, Set, Tuple, TypeVar, Union, cast


T = TypeVar("T")
DEFAULT_AEA_CONFIG_FILE = "aea-config.yaml"
DEFAULT_SKILL_CONFIG_FILE = "skill.yaml"
DEFAULT_CONNECTION_CONFIG_FILE = "connection.yaml"
DEFAULT_PROTOCOL_CONFIG_FILE = "protocol.yaml"
DEFAULT_PRIVATE_KEY_PATHS = {"fetchai": "", "ethereum": ""}
T = TypeVar("T")


Dependency = dict
"""
A dependency is a dictionary with the following (optional) keys:
- version: a version specifier(s) (e.g. '==0.1.0').
Expand All @@ -40,7 +42,8 @@
If the 'git' field is set, the 'version' field will be ignored.
They are supposed to be forwarded to the 'pip' command.
"""
Dependency = dict

Dependencies = Dict[str, Dependency]
"""
A dictionary from package name to dependency data structure (see above).
The package name must satisfy the constraints on Python packages names.
Expand All @@ -49,7 +52,6 @@
The main advantage of having a dictionary is that we implicitly filter out dependency duplicates.
We cannot have two items with the same package name since the keys of a YAML object form a set.
"""
Dependencies = Dict[str, Dependency]


class ConfigurationType(Enum):
Expand Down
12 changes: 11 additions & 1 deletion aea/context/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
from aea.mail.base import Address, OutBox
from aea.skills.tasks import TaskManager

DEFAULT_OEF = "default_oef"


class AgentContext:
"""Provide read access to relevant data of the agent for the skills."""
Expand Down Expand Up @@ -68,6 +70,9 @@ def __init__(
self._preferences = preferences
self._goal_pursuit_readiness = goal_pursuit_readiness
self._task_manager = task_manager
self._search_service_address = (
DEFAULT_OEF # TODO: make this configurable via aea-config.yaml
)

@property
def shared_state(self) -> Dict[str, Any]:
Expand All @@ -91,7 +96,7 @@ def addresses(self) -> Dict[str, Address]:

@property
def address(self) -> Address:
"""Get the defualt address."""
"""Get the default address."""
return self.identity.address

@property
Expand Down Expand Up @@ -133,3 +138,8 @@ def ledger_apis(self) -> LedgerApis:
def task_manager(self) -> TaskManager:
"""Get the task manager."""
return self._task_manager

@property
def search_service_address(self) -> Address:
"""Get the address of the search service."""
return self._search_service_address
53 changes: 53 additions & 0 deletions aea/helpers/search/generic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2018-2019 Fetch.AI Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------

"""This module contains a generic data model."""

from typing import Any, Dict, List

from aea.helpers.search.models import Attribute, DataModel

SUPPORTED_TYPES = {"str": str, "int": int, "float": float, "bool": bool}


class GenericDataModel(DataModel):
"""Data model for the generic seller aea."""

def __init__(self, data_model_name: str, data_model_attributes: Dict[str, Any]):
"""Initialise the dataModel."""
self.attributes = [] # type: List[Attribute]
for values in data_model_attributes.values():
assert (
values["type"] in SUPPORTED_TYPES.keys()
), "Type is not supported. Use str, int, float or bool"
assert isinstance(
values["name"], (SUPPORTED_TYPES[values["type"]],)
), "The datamodel values are of wrong type!"
assert isinstance(
values["is_required"], bool
), "Wrong type!! is_required must be bool"
self.attributes.append(
Attribute(
name=values["name"], # type: ignore
type=SUPPORTED_TYPES[values["type"]],
is_required=values["is_required"],
)
)

super().__init__(data_model_name, self.attributes)
58 changes: 58 additions & 0 deletions aea/helpers/search/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
# ------------------------------------------------------------------------------

"""Useful classes for the OEF search."""

import pickle # nosec
from abc import ABC, abstractmethod
from copy import deepcopy
from enum import Enum
Expand Down Expand Up @@ -108,6 +110,35 @@ def __iter__(self):
"""Create an iterator."""
return iter(self.values)

@classmethod
def encode(
cls, performative_content, description_from_message: "Description"
) -> None:
"""
Encode an instance of this class into the protocol buffer object.
The content in the 'performative_content' argument must be matched with the message content in the 'description_from_message' argument.
:param performative_content: the performative protocol buffer object containing a content whose type is this class.
:param description_from_message: the message content to be encoded in the protocol buffer object.
:return: None
"""
description_from_message_bytes = pickle.dumps(description_from_message) # nosec
performative_content.description = description_from_message_bytes

@classmethod
def decode(cls, description_from_pb2) -> "Description":
"""
Decode a protocol buffer object that corresponds with this class into an instance of this class.
A new instance of this class must be created that matches the content in the 'description_from_pb2' argument.
:param description_from_pb2: the protocol buffer content object whose type corresponds with this class.
:return: A new instance of this class that matches the protocol buffer object in the 'description_from_pb2' argument.
"""
service_description = pickle.loads(description_from_pb2.description) # nosec
return service_description


class ConstraintTypes(Enum):
"""Types of constraint."""
Expand Down Expand Up @@ -448,3 +479,30 @@ def __eq__(self, other):
and self.constraints == other.constraints
and self.model == other.model
)

@classmethod
def encode(cls, performative_content, query_from_message: "Query") -> None:
"""
Encode an instance of this class into the protocol buffer object.
The content in the 'performative_content' argument must be matched with the message content in the 'query_from_message' argument.
:param performative_content: the performative protocol buffer object containing a content whose type is this class.
:param query_from_message: the message content to be encoded in the protocol buffer object.
:return: None
"""
query_bytes = pickle.dumps(query_from_message) # nosec
performative_content.query_bytes = query_bytes

@classmethod
def decode(cls, query_from_pb2) -> "Query":
"""
Decode a protocol buffer object that corresponds with this class into an instance of this class.
A new instance of this class must be created that matches the content in the 'query_from_pb2' argument.
:param query_from_pb2: the protocol buffer content object whose type corresponds with this class.
:return: A new instance of this class that matches the protocol buffer object in the 'query_from_pb2' argument.
"""
query = pickle.loads(query_from_pb2.query_bytes) # nosec
return query
8 changes: 7 additions & 1 deletion aea/protocols/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import inspect
import json
import logging
import os
import re
from abc import ABC, abstractmethod
Expand All @@ -43,6 +44,8 @@
)
from aea.mail.base import Address

logger = logging.getLogger(__name__)


class Message:
"""This class implements a message."""
Expand All @@ -59,7 +62,10 @@ def __init__(self, body: Optional[Dict] = None, **kwargs):
self._counterparty = None # type: Optional[Address]
self._body = copy(body) if body else {} # type: Dict[str, Any]
self._body.update(kwargs)
assert self._is_consistent(), "Message initialization inconsistent."
try:
self._is_consistent()
except Exception as e:
logger.error(e)

@property
def counterparty(self) -> Address:
Expand Down
Loading

0 comments on commit 05ed40b

Please sign in to comment.