diff --git a/.github/workflows/common_checks.yml b/.github/workflows/common_checks.yml new file mode 100644 index 000000000..13e5a9e80 --- /dev/null +++ b/.github/workflows/common_checks.yml @@ -0,0 +1,50 @@ +name: main_workflow +on: + push: + branches: + - develop + - main + pull_request: +jobs: + linter_checks: + continue-on-error: False + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + python-version: ["3.10.9"] + timeout-minutes: 30 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@master + with: + python-version: ${{ matrix.python-version }} + - uses: actions/setup-go@v3 + with: + go-version: "1.17.7" + - name: Install dependencies + run: | + sudo apt-get update --fix-missing + sudo apt-get autoremove + sudo apt-get autoclean + pip install tomte[tox]==0.2.15 + pip install --user --upgrade setuptools + sudo npm install -g markdown-spellcheck + - name: Security checks + run: | + tox -p -e bandit -e safety + - name: Code style check + run: | + tox -p -e black-check -e isort-check + - name: Flake7 + run: | + tox -e flake8 + - name: Pylint + run: tox -e pylint + - name: Static type check + run: tox -e mypy + # - name: Check spelling + # run: tox -e spell-check + # - name: License compatibility check + # run: tox -e liccheck + # tox -p -e vulture -e darglint diff --git a/.gitignore b/.gitignore index cb5365069..46beac971 100644 --- a/.gitignore +++ b/.gitignore @@ -21,13 +21,12 @@ frontend/build .DS_STORE # python -backend/__pycache__/ -backend/scripts/__pycache__/ +.tox/ .operate/ -data/ __pycache__/ -backend/tmp/ +data/ backend/temp/ +backend/tmp/ tmp/ temp/ diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 000000000..54b10e4d4 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,60 @@ +[MASTER] +ignore-patterns=contract.py +ignore=operate/data/contracts/ + +[MESSAGES CONTROL] +disable=C0103,R0801,C0301,C0201,C0204,C0209,W1203,C0302,R1735,R1729,W0511,E0611,R0903 + +# See here for more options: https://www.codeac.io/documentation/pylint-configuration.html +R1735: use-dict-literal +R1729: use-a-generator +C0103: invalid-name +C0201: consider-iterating-dictionary +W1203: logging-fstring-interpolation +C0204: bad-mcs-classmethod-argument +C0209: consider-using-f-string +C0301: http://pylint-messages.wikidot.com/messages:c0301 > Line too long +C0302: http://pylint-messages.wikidot.com/messages:c0302 > Too many lines in module +R0801: similar lines +E0611: no-name-in-module +R0903: Too few public methods + +[IMPORTS] +ignored-modules=os,io + +[DESIGN] +# min-public-methods=1 +max-public-methods=58 +# max-returns=10 +# max-bool-expr=7 +max-args=6 +# max-locals=31 +# max-statements=80 +max-parents=10 +max-branches=36 +max-attributes=8 + +[REFACTORING] +# max-nested-blocks=6 + +[SPELLING] +# uncomment to enable +# spelling-dict=en_US + +# List of comma separated words that should not be checked. +spelling-ignore-words=nocover,pragma,params,noqa,kwargs,str,async,json,boolean,config,pytest,args,url,tx,jsonschema,traceback,api,nosec + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=10 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + diff --git a/operate/cli.py b/operate/cli.py index 501b8c5bf..626bf2112 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -20,7 +20,7 @@ """Operate app CLI module.""" import os -import shutil +import typing as t from pathlib import Path from aea_ledger_ethereum.ethereum import EthereumCrypto @@ -37,6 +37,7 @@ from operate.keys import Keys from operate.services.manage import Services + DEFAULT_HARDHAT_KEY = ( "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" ).encode() @@ -45,7 +46,7 @@ class App(Resource): """App resource.""" - def __init__(self, home: Path) -> None: + def __init__(self, home: t.Optional[Path] = None) -> None: """Initialize object.""" super().__init__() self._path = (home or (Path.home() / OPERATE)).resolve() @@ -76,7 +77,7 @@ def make(self) -> None: ) @property - def json(self) -> None: + def json(self) -> dict: """Json representation of the app.""" return { "name": "Operate HTTP server", @@ -98,7 +99,7 @@ def _daemon( host: Annotated[str, params.String(help="HTTP server host string")] = "localhost", port: Annotated[int, params.Integer(help="HTTP server port")] = 8000, home: Annotated[ - Path, params.Directory(long_flag="--home", help="Home directory") + t.Optional[Path], params.Directory(long_flag="--home", help="Home directory") ] = None, ) -> None: """Launch operate daemon.""" @@ -125,28 +126,6 @@ def _daemon( ) -@_operate.command(name="prune") -def _prune( - home: Annotated[ - Path, params.Directory(long_flag="--home", help="Home directory") - ] = None, -) -> None: - """Delete unused/cached data.""" - app = App(home=home) - for service in app.services.json: - if service["active"]: - continue - try: - shutil.rmtree(app.services.path / service["hash"]) - print("Removed service " + service["hash"]) - except PermissionError: - print( - "Error removing " - + service["hash"] - + " please try with admin previledges" - ) - - def main() -> None: """CLI entry point.""" run(cli=_operate) diff --git a/operate/data/__init__.py b/operate/data/__init__.py index 14575eed2..82fbdd231 100644 --- a/operate/data/__init__.py +++ b/operate/data/__init__.py @@ -21,4 +21,5 @@ from pathlib import Path + DATA_DIR = Path(__file__).parent diff --git a/operate/data/contracts/uniswap_v2_erc20/contract.py b/operate/data/contracts/uniswap_v2_erc20/contract.py index 06d9c03c3..e1fd2f3a9 100644 --- a/operate/data/contracts/uniswap_v2_erc20/contract.py +++ b/operate/data/contracts/uniswap_v2_erc20/contract.py @@ -26,6 +26,7 @@ from aea.contracts.base import Contract from aea_ledger_ethereum import EthereumApi + PUBLIC_ID = PublicId.from_str("valory/uniswap_v2_erc20:0.1.0") _logger = logging.getLogger( @@ -197,7 +198,6 @@ def get_transaction_transfer_logs( # type: ignore # pylint: disable=too-many-a transfer_logs: List = [] if transfer_logs_data: - transfer_logs = cast( List, transfer_logs_data["logs"], diff --git a/operate/http/__init__.py b/operate/http/__init__.py index 85de2dc77..0151f8ba4 100644 --- a/operate/http/__init__.py +++ b/operate/http/__init__.py @@ -29,6 +29,9 @@ from operate.http.exceptions import NotAllowed, ResourceException + +# pylint: disable=no-self-use + GenericResource = t.TypeVar("GenericResource") PostPayload = t.TypeVar("PostPayload") PostResponse = t.TypeVar("PostResponse") @@ -52,7 +55,7 @@ class Resource( ): """Web<->Local resource object.""" - _handlers: t.Dict[str, t.Callable[[t.Dict], t.Dict]] + _handlers: t.Dict[str, t.Callable] def __init__(self) -> None: """Initialize object.""" @@ -119,7 +122,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> t.Any: return try: - handler = self._handlers.get(request.method) + handler = self._handlers[request.method] try: data = await request.json() except json.decoder.JSONDecodeError: @@ -134,8 +137,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> t.Any: content={"error": e.args[0]}, status_code=e.code, ) - except Exception as e: - raise + except Exception as e: # pylint: disable=broad-except response = JSONResponse( content={"error": str(e)}, status_code=500, diff --git a/operate/keys.py b/operate/keys.py index 0d2711caa..e1855918e 100644 --- a/operate/keys.py +++ b/operate/keys.py @@ -20,7 +20,6 @@ """Keys manager.""" import json import os -import typing as t from pathlib import Path from aea_ledger_ethereum.ethereum import EthereumCrypto diff --git a/operate/ledger/__init__.py b/operate/ledger/__init__.py index e3bef0ad8..55f4262bd 100644 --- a/operate/ledger/__init__.py +++ b/operate/ledger/__init__.py @@ -26,6 +26,7 @@ from operate.ledger.solana import Solana from operate.types import ChainType, LedgerType + ETHEREUM_RPC = "https://ethereum.publicnode.com" GNOSIS_RPC = "https://rpc.gnosischain.com" GOERLI_RPC = "https://ethereum-goerli.publicnode.com" @@ -60,16 +61,20 @@ def get_default_rpc(chain: ChainType) -> str: + """Get default RPC chain type.""" return DEFAULT_RPCS.get(chain, ETHEREUM_RPC) def get_ledger_helper_by_chain(rpc: str, chain: ChainType) -> LedgerHelper: + """Get ledger helper by chain type.""" return CHAIN_HELPERS.get(chain, Ethereum)(rpc=rpc) def get_ledger_helper_by_ledger(rpc: str, ledger: LedgerHelper) -> LedgerHelper: - return LEDGER_HELPERS.get(ledger, Ethereum)(rpc=rpc) + """Get ledger helper by ledger type.""" + return LEDGER_HELPERS.get(ledger, Ethereum)(rpc=rpc) # type: ignore -def get_currency_denom(chain: ChainType): +def get_currency_denom(chain: ChainType) -> str: + """Get currency denom by chain type.""" return CURRENCY_DENOMS.get(chain, "Wei") diff --git a/operate/ledger/base.py b/operate/ledger/base.py index 8a9054b25..0231b2795 100644 --- a/operate/ledger/base.py +++ b/operate/ledger/base.py @@ -23,7 +23,7 @@ from abc import ABC, abstractmethod -class LedgerHelper(ABC): +class LedgerHelper(ABC): # pylint: disable=too-few-public-methods """Base ledger helper.""" api: t.Any diff --git a/operate/ledger/ethereum.py b/operate/ledger/ethereum.py index be88f061c..8fe44600b 100644 --- a/operate/ledger/ethereum.py +++ b/operate/ledger/ethereum.py @@ -33,6 +33,7 @@ class Ethereum(LedgerHelper): api: EthereumApi def __init__(self, rpc: str) -> None: + """Initialize object.""" super().__init__(rpc) self.api = EthereumApi(address=self.rpc) diff --git a/operate/ledger/profiles.py b/operate/ledger/profiles.py index 3f95407c8..8180f4582 100644 --- a/operate/ledger/profiles.py +++ b/operate/ledger/profiles.py @@ -21,6 +21,7 @@ from operate.types import ChainType, ContractAddresses + CONTRACTS = { ChainType.GNOSIS: ContractAddresses( { diff --git a/operate/ledger/solana.py b/operate/ledger/solana.py index 80c09060f..861ebad2a 100644 --- a/operate/ledger/solana.py +++ b/operate/ledger/solana.py @@ -28,9 +28,6 @@ class Solana(LedgerHelper): """Solana ledger helper.""" - def __init__(self, rpc: str) -> None: - super().__init__(rpc) - def create_key(self) -> t.Dict: """Create key.""" return { diff --git a/operate/services/manage.py b/operate/services/manage.py index 01cd21f4f..22c0a70da 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -47,11 +47,12 @@ from operate.types import ( ChainData, ConfigurationTemplate, - ServicesType, ServiceTemplate, ServiceType, + ServicesType, ) + OPERATE = ".operate" CONFIG = "config.json" SERVICES = "services" @@ -83,10 +84,6 @@ def build_dirs(build_dir: Path) -> None: continue -class GetServices(ServicesType): - """Get payload.""" - - class PostServices(ServiceTemplate): """Create payload.""" @@ -112,7 +109,7 @@ class DeleteServicesResponse(TypedDict): class Services( Resource[ - GetServices, + ServicesType, PostServices, ServiceType, PutServices, @@ -142,7 +139,7 @@ async def access( await resource(scope=scope, receive=receive, send=send) @property - def json(self) -> GetServices: + def json(self) -> ServicesType: """Returns the list of available services.""" data = [] for path in self.path.iterdir(): @@ -279,7 +276,7 @@ def _create( return service - def create(self, data: PostServices) -> PostServices: + def create(self, data: PostServices) -> ServiceType: """Create a service.""" service = self._create( phash=data["hash"], @@ -326,7 +323,7 @@ def update(self, data: PutServices) -> ServiceType: # Swap owners on the old safe owner, *_ = old.chain_data["instances"] - owner_key = self.keys.get(owner).get("private_key") + owner_key = str(self.keys.get(owner).get("private_key")) ocm.swap( service_id=old.chain_data["token"], multisig=old.chain_data["multisig"], diff --git a/operate/services/protocol.py b/operate/services/protocol.py index 3e4ac4b60..5e812229d 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -48,7 +48,8 @@ from operate.data.contracts.service_staking_token.contract import ( ServiceStakingTokenContract, ) -from operate.ledger.profiles import CONTRACTS +from operate.types import ContractAddresses + ZERO_ETH = 0 @@ -80,7 +81,7 @@ class MultiSendOperation(Enum): DELEGATE_CALL = 1 -def hash_payload_to_hex( +def hash_payload_to_hex( # pylint: disable=too-many-arguments,too-many-locals safe_tx_hash: str, ether_value: int, safe_tx_gas: int, @@ -245,7 +246,9 @@ def stake( # since it has the same interface as ERC721 we might want to create # a ERC721 contract package - def _build_approval_tx(*args, **kargs) -> t.Dict: + def _build_approval_tx( # pylint: disable=unused-argument + *args: t.Any, **kargs: t.Any + ) -> t.Dict: return registry_contracts.erc20.get_approve_tx( ledger_api=self.ledger_api, contract_address=service_registry, @@ -254,7 +257,7 @@ def _build_approval_tx(*args, **kargs) -> t.Dict: amount=service_id, ) - setattr(tx_settler, "build", _build_approval_tx) + setattr(tx_settler, "build", _build_approval_tx) # noqa: B010 tx_settler.transact( method=lambda: {}, contract="", @@ -262,7 +265,9 @@ def _build_approval_tx(*args, **kargs) -> t.Dict: dry_run=False, ) - def _build_staking_tx(*args, **kargs) -> t.Dict: + def _build_staking_tx( # pylint: disable=unused-argument + *args: t.Any, **kargs: t.Any + ) -> t.Dict: return self.ledger_api.build_transaction( contract_instance=self.staking_ctr.get_instance( ledger_api=self.ledger_api, @@ -276,7 +281,7 @@ def _build_staking_tx(*args, **kargs) -> t.Dict: raise_on_try=True, ) - setattr(tx_settler, "build", _build_staking_tx) + setattr(tx_settler, "build", _build_staking_tx) # noqa: B010 tx_settler.transact( method=lambda: {}, contract="", @@ -328,7 +333,9 @@ def unstake(self, service_id: int, staking_contract: str) -> None: sleep=self.sleep, ) - def _build_unstaking_tx(*args, **kargs) -> t.Dict: + def _build_unstaking_tx( # pylint: disable=unused-argument + *args: t.Any, **kargs: t.Any + ) -> t.Dict: return self.ledger_api.build_transaction( contract_instance=self.staking_ctr.get_instance( ledger_api=self.ledger_api, @@ -342,7 +349,7 @@ def _build_unstaking_tx(*args, **kargs) -> t.Dict: raise_on_try=True, ) - setattr(tx_settler, "build", _build_unstaking_tx) + setattr(tx_settler, "build", _build_unstaking_tx) # noqa: B010 tx_settler.transact( method=lambda: {}, contract="", @@ -354,7 +361,7 @@ def _build_unstaking_tx(*args, **kargs) -> t.Dict: class OnChainManager: """On chain service management.""" - def __init__(self, rpc: str, key: Path, contracts: t.Dict) -> None: + def __init__(self, rpc: str, key: Path, contracts: ContractAddresses) -> None: """On chain manager.""" self.rpc = rpc self.key = key @@ -427,7 +434,7 @@ def info(self, token_id: int) -> t.Dict: instances=instances, ) - def mint( + def mint( # pylint: disable=too-many-arguments,too-many-locals self, package_path: Path, agent_id: int, @@ -437,8 +444,8 @@ def mint( nft: Optional[Union[Path, IPFSHash]], update_token: t.Optional[int] = None, token: t.Optional[str] = None, - ): - "Mint service." + ) -> t.Dict: + """Mint service.""" # TODO: Support for update self._patch() manager = MintManager( @@ -538,7 +545,7 @@ def deploy( reuse_multisig=reuse_multisig, ) - def swap( + def swap( # pylint: disable=too-many-arguments,too-many-locals self, service_id: int, multisig: str, @@ -554,7 +561,7 @@ def swap( ) with tempfile.TemporaryDirectory() as temp_dir: key_file = Path(temp_dir, "key.txt") - key_file.write_text(owner_key) + key_file.write_text(owner_key, encoding="utf-8") owner_crypto = EthereumCrypto(private_key_path=str(key_file)) owner_cryptos: list[EthereumCrypto] = [owner_crypto] owners = [ diff --git a/operate/services/service.py b/operate/services/service.py index 6ba7c92d6..c884f045a 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -152,7 +152,7 @@ class Deployment( t.Dict, DeploymentType, t.Dict, - t.Dict, + DeploymentType, StopDeployment, DeploymentType, ] @@ -244,9 +244,9 @@ def create(self, data: t.Dict) -> DeploymentType: ): (build / volume).mkdir(exist_ok=True) _volumes.append(f"./{volume}:{mount}:Z") - for service in deployment["services"]: - if "abci" in service: - deployment["services"][service]["volumes"].extend(_volumes) + for node in deployment["services"]: + if "abci" in node: + deployment["services"][node]["volumes"].extend(_volumes) with compose.open("w", encoding="utf-8") as stream: yaml_dump(data=deployment, stream=stream) @@ -330,7 +330,7 @@ def ledger_config(self) -> LedgerConfig: override["type"] == "connection" and "valory/ledger" in override["public_id"] ): - (ledger, config), *_ = override["config"]["ledger_apis"].items() + (_, config), *_ = override["config"]["ledger_apis"].items() return LedgerConfig( rpc=config["address"], chain=ChainType.from_id(cid=config["chain_id"]), @@ -340,7 +340,7 @@ def ledger_config(self) -> LedgerConfig: def deployment_config(self) -> DeploymentConfig: """Returns deployment config.""" - return DeploymentConfig(self.config.json.get("deployment", {})) + return DeploymentConfig(self.config.json.get("deployment", {})) # type: ignore class Service( @@ -356,24 +356,15 @@ class Service( ): """Service class.""" - name: t.Optional[str] - hash: str - keys: KeysType - ledger: LedgerConfig - chain_data: ChainData - - service_path: Path - path: Path - _helper: t.Optional[ServiceHelper] - def __init__( + def __init__( # pylint: disable=too-many-arguments self, service_path: Path, phash: str, keys: KeysType, - ledger: t.Optional[LedgerConfig] = None, - chain_data: t.Optional[ChainData] = None, + ledger: LedgerConfig, + chain_data: ChainData, name: t.Optional[str] = None, ) -> None: """Initialize object.""" @@ -417,14 +408,14 @@ def json(self) -> ServiceType: readme = self.service_path / "README.md" return ServiceType( { - "name": self.name, + "name": str(self.name), "hash": self.hash, "keys": self.keys, "ledger": self.ledger, "chain_data": self.chain_data, "service_path": str(self.service_path), "readme": ( - readme.read_text(encoding="utf-8") if readme.exists() else None + readme.read_text(encoding="utf-8") if readme.exists() else "" ), } ) @@ -450,13 +441,13 @@ def load(cls, path: Path) -> "Service": ) @classmethod - def new( + def new( # pylint: disable=too-many-arguments cls, path: Path, phash: str, keys: KeysType, ledger: LedgerConfig, - chain_data: t.Optional[ChainData] = None, + chain_data: ChainData, name: t.Optional[str] = None, ) -> "Service": """Create a new service.""" @@ -481,11 +472,6 @@ def new( service.store() return service - def __update(self, data: ServiceType) -> ServiceType: - """Update service.""" - # TODO: Finish implementation - return self.json - def delete(self, data: DeleteServicePayload) -> DeleteServiceResponse: """Delete service.""" shutil.rmtree(self.path) diff --git a/operate/types.py b/operate/types.py index 8f3cd2099..7bf7967d8 100644 --- a/operate/types.py +++ b/operate/types.py @@ -24,6 +24,7 @@ from typing_extensions import NotRequired, TypedDict + _ACTIONS = { "status": 0, "build": 1, @@ -97,9 +98,9 @@ class ContractAddresses(TypedDict): class LedgerConfig(TypedDict): """Ledger config.""" - rpc: str - type: LedgerType - chain: ChainType + rpc: NotRequired[str] + type: NotRequired[LedgerType] + chain: NotRequired[ChainType] LedgerConfigs = t.List[LedgerConfig] @@ -127,9 +128,7 @@ class VariableType(TypedDict): class ServiceState(enum.IntEnum): - """ - Service state - """ + """Service state""" NON_EXISTENT = 0 PRE_REGISTRATION = 1 @@ -142,10 +141,10 @@ class ServiceState(enum.IntEnum): class ChainData(TypedDict): """Chain data for service.""" - instances: t.List[str] # Agent instances registered as safe owners - token: int - multisig: str - staked: bool + instances: NotRequired[t.List[str]] # Agent instances registered as safe owners + token: NotRequired[int] + multisig: NotRequired[str] + staked: NotRequired[bool] class ChainDeployment(TypedDict): @@ -173,6 +172,7 @@ class ServiceType(TypedDict): readme: NotRequired[str] ledger: NotRequired[LedgerConfig] chain_data: NotRequired[ChainData] + service_path: NotRequired[str] ServicesType = t.List[ServiceType] @@ -194,7 +194,7 @@ class ConfigurationTemplate(TypedDict): threshold: int use_staking: bool cost_of_bond: int - olas_required_to_bond: int + olas_cost_of_bond: int olas_required_to_stake: int fund_requirements: FundRequirementsTemplate @@ -245,6 +245,5 @@ class DeployedNodes(TypedDict): class DeploymentType(TypedDict): """Deployment type.""" - version: int status: Status nodes: DeployedNodes diff --git a/scripts/fund.py b/scripts/fund.py index 293488c84..3670b8d3e 100644 --- a/scripts/fund.py +++ b/scripts/fund.py @@ -8,6 +8,7 @@ from aea_ledger_ethereum.ethereum import EthereumApi, EthereumCrypto from dotenv import load_dotenv + OLAS_CONTRACT_ADDRESS_GNOSIS = "0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f" load_dotenv() @@ -42,6 +43,7 @@ "IUniswapV2ERC20.json", ), "r", + encoding="utf-8", ) as abi_file: abi = json.load(abi_file)["abi"] diff --git a/scripts/test_e2e.py b/scripts/test_e2e.py index 9378c5022..1741a23dd 100644 --- a/scripts/test_e2e.py +++ b/scripts/test_e2e.py @@ -25,10 +25,12 @@ from aea.helpers.yaml_utils import yaml_load from aea_ledger_ethereum.ethereum import EthereumApi, EthereumCrypto + BASE_URL = "http://localhost:8000/api" -def test_endpoint_e2e(): +def test_endpoint_e2e() -> None: + """Test endpoint end to end""" with Path("templates/trader.yaml").open("r", encoding="utf-8") as stream: trader_template = yaml_load(stream=stream) phash = trader_template["hash"] @@ -72,9 +74,9 @@ def test_endpoint_e2e(): ledger_api.get_transaction_receipt(tx_digest=digest) old = trader_template["hash"] - trader_template["hash"] = ( - "bafybeicxdpkuk5z5zfbkso7v5pywf4v7chxvluyht7dtgalg6dnhl7ejoe" - ) + trader_template[ + "hash" + ] = "bafybeicxdpkuk5z5zfbkso7v5pywf4v7chxvluyht7dtgalg6dnhl7ejoe" print( requests.put( url=f"{BASE_URL}/services", diff --git a/scripts/test_staking_e2e.py b/scripts/test_staking_e2e.py index d0ca0527a..803ab4ee8 100644 --- a/scripts/test_staking_e2e.py +++ b/scripts/test_staking_e2e.py @@ -25,10 +25,12 @@ from aea.helpers.yaml_utils import yaml_load from aea_ledger_ethereum.ethereum import EthereumApi, EthereumCrypto + BASE_URL = "http://localhost:8000/api" -def test_endpoint_e2e(): +def test_endpoint_e2e() -> None: + """Test endpoint end to end""" with Path("templates/trader.yaml").open("r", encoding="utf-8") as stream: trader_template = yaml_load(stream=stream) phash = trader_template["hash"] @@ -73,9 +75,9 @@ def test_endpoint_e2e(): ledger_api.get_transaction_receipt(tx_digest=digest) old = trader_template["hash"] - trader_template["hash"] = ( - "bafybeicxdpkuk5z5zfbkso7v5pywf4v7chxvluyht7dtgalg6dnhl7ejoe" - ) + trader_template[ + "hash" + ] = "bafybeicxdpkuk5z5zfbkso7v5pywf4v7chxvluyht7dtgalg6dnhl7ejoe" print( requests.put( url=f"{BASE_URL}/services", diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..d420712d8 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +"""Tests.""" diff --git a/tox.ini b/tox.ini new file mode 100644 index 000000000..6e3735f1f --- /dev/null +++ b/tox.ini @@ -0,0 +1,197 @@ +[tox] +envlist = isort +skip_missing_interpreters = true +isolated_build = True + + +[testenv:bandit] +skipsdist = True +skip_install = True +deps = + tomte[bandit]==0.2.15 +commands = + bandit -r operate -x */tests/* + bandit -s B101 -r tests scripts + +[testenv:black] +skipsdist = True +skip_install = True +deps = + tomte[black]==0.2.15 +commands = + black operate scripts tests + +[testenv:black-check] +skipsdist = True +skip_install = True +deps = + tomte[black]==0.2.15 +commands = + black --check operate scripts tests + +[testenv:isort] +skipsdist = True +skip_install = True +deps = + tomte[isort]==0.2.15 +commands = + isort operate/ scripts/ tests/ + +[testenv:isort-check] +skipsdist = True +skip_install = True +deps = + tomte[isort]==0.2.15 +commands = + isort --check-only --gitignore operate/ scripts/ tests/ + +[testenv:flake8] +skipsdist = True +skip_install = True +deps = + tomte[flake8]==0.2.15 +commands = + flake8 operate scripts tests + +[testenv:mypy] +skipsdist = True +skip_install = True +deps = + tomte[mypy]==0.2.15 +commands = + mypy operate/ tests/ scripts/ --disallow-untyped-defs --config-file tox.ini + +[testenv:pylint] +whitelist_externals = /bin/sh +skipsdist = True +deps = + tomte[pylint]==0.2.15 +commands = + pylint operate scripts -j 0 --rcfile=.pylintrc + +[testenv:safety] +skipsdist = True +skip_install = True +deps = + tomte[safety]==0.2.15 +commands = + safety check -i 37524 -i 38038 -i 37776 -i 38039 -i 39621 -i 40291 -i 39706 -i 41002 -i 51358 -i 51499 + +[testenv:vulture] +skipsdist = True +skip_install = True +deps = + tomte[vulture]==0.2.15 +commands = + vulture operate/services scripts/whitelist.py + +[testenv:darglint] +skipsdist = True +skip_install = True +deps = + tomte[darglint]==0.2.15 +commands = + darglint operate scripts packages/valory/* tests + + +[testenv:check-copyright] +skipsdist = True +skip_install = True +deps = +commands = + {toxinidir}/scripts/check_copyright.py --check + +[testenv:fix-copyright] +skipsdist = True +skip_install = True +deps = +commands = + {toxinidir}/scripts/check_copyright.py + +[testenv:liccheck] +skipsdist = True +usedevelop = True +deps = tomte[liccheck,cli]==0.2.15 +commands = + tomte freeze-dependencies --output-path {envtmpdir}/requirements.txt + liccheck -s tox.ini -r {envtmpdir}/requirements.txt -l PARANOID + +[flake8] +paths=autonomy,packages,scripts,tests +exclude=.md, + *_pb2.py, + autonomy/__init__.py, + custom_types.py, + *_pb2_grpc.py, + packages/valory/connections/http_client, + packages/valory/connections/ledger, + packages/valory/connections/p2p_libp2p_client, + packages/valory/protocols/acn, + packages/valory/protocols/contract_api, + packages/valory/protocols/http, + packages/valory/protocols/ledger_api +max-line-length = 88 +select = B,C,D,E,F,I,W, +ignore = E203,E501,W503,D202,B014,D400,D401,DAR,B028,B017 +application-import-names = autonomy,packages,tests,scripts + +[isort] +# for black compatibility +multi_line_output=3 +include_trailing_comma=True +force_grid_wrap=0 +use_parentheses=True +ensure_newline_before_comments = True +line_length=88 +# custom configurations +order_by_type=False +case_sensitive=True +lines_after_imports=2 +skip = +skip_glob = +known_first_party=operate +known_local_folder=tests +sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER + +[mypy] +strict_optional = True + +[mypy-typing_extentions.*] +ignore_missing_imports = True + +[mypy-requests.*] +ignore_missing_imports = True + +[mypy-aea.*] +ignore_missing_imports = True + +[mypy-aea_ledger_ethereum.*] +ignore_missing_imports = True + + +[mypy-dotenv.*] +ignore_missing_imports = True + + +[mypy-autonomy.*] +ignore_missing_imports = True + + +[mypy-hexbytes.*] +ignore_missing_imports = True + + +[mypy-starlette.*] +ignore_missing_imports = True + + +[mypy-aea_cli_ipfs.*] +ignore_missing_imports = True + + +[mypy-clea.*] +ignore_missing_imports = True + + +[mypy-uvicorn.*] +ignore_missing_imports = True \ No newline at end of file