Skip to content

Commit

Permalink
perf: make CLI load faster (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey authored Oct 28, 2024
1 parent 050addf commit c800f58
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 27 deletions.
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v5.0.0
hooks:
- id: check-yaml

Expand All @@ -10,25 +10,25 @@ repos:
- id: isort

- repo: https://github.com/psf/black
rev: 24.4.2
rev: 24.10.0

hooks:
- id: black
name: black

- repo: https://github.com/pycqa/flake8
rev: 7.0.0
rev: 7.1.1
hooks:
- id: flake8

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
rev: v1.13.0
hooks:
- id: mypy
additional_dependencies: [types-requests, types-setuptools, pydantic]

- repo: https://github.com/executablebooks/mdformat
rev: 0.7.17
rev: 0.7.18
hooks:
- id: mdformat
additional_dependencies: [mdformat-gfm, mdformat-frontmatter, mdformat-pyproject]
Expand Down
22 changes: 18 additions & 4 deletions ape_safe/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from typing import Optional
from importlib import import_module
from typing import Any, Optional

from ape import plugins
from ape.api import PluginConfig

from .accounts import SafeAccount, SafeContainer
from .multisend import MultiSend


class SafeConfig(PluginConfig):
default_safe: Optional[str] = None
Expand All @@ -19,10 +17,26 @@ def config_class():

@plugins.register(plugins.AccountPlugin)
def account_types():
from .accounts import SafeAccount, SafeContainer

return SafeContainer, SafeAccount


def __getattr__(name: str) -> Any:
if name == "MultiSend":
from .multisend import MultiSend

return MultiSend

elif name in ("SafeAccount", "SafeContainer"):
return getattr(import_module("ape_safe.accounts"), name)

else:
raise AttributeError(name)


__all__ = [
"MultiSend",
"SafeAccount",
"SafeContainer",
]
9 changes: 6 additions & 3 deletions ape_safe/_cli/click_ext.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from collections.abc import Sequence
from typing import NoReturn, Optional, Union, cast
from typing import TYPE_CHECKING, NoReturn, Optional, Union, cast

import click
from ape.api import AccountAPI
Expand All @@ -8,15 +8,18 @@
from ape.utils import ManagerAccessMixin
from click import BadOptionUsage, MissingParameter

from ape_safe.accounts import SafeContainer
if TYPE_CHECKING:
from ape_safe.accounts import SafeContainer


class SafeCliContext(ApeCliContextObject):
@property
def safes(self) -> SafeContainer:
def safes(self) -> "SafeContainer":
# NOTE: Would only happen in local development of this plugin.
assert "safe" in self.account_manager.containers, "Are all API methods implemented?"

from ape_safe.accounts import SafeContainer

safe_container = self.account_manager.containers["safe"]
return cast(SafeContainer, safe_container)

Expand Down
28 changes: 20 additions & 8 deletions ape_safe/_cli/pending.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
from collections.abc import Sequence
from typing import Optional, Union, cast
from typing import TYPE_CHECKING, Optional, Union, cast

import click
import rich
from ape.api import AccountAPI
from ape.cli import ConnectedProviderCommand
from ape.exceptions import SignatureError
from ape.types import AddressType, MessageSignature
from eth_typing import ChecksumAddress, Hash32
from eth_utils import humanize_hash
from hexbytes import HexBytes

from ape_safe import SafeAccount
from ape_safe._cli.click_ext import (
SafeCliContext,
execute_option,
Expand All @@ -21,9 +19,12 @@
submitter_option,
txn_ids_argument,
)
from ape_safe.accounts import get_signatures
from ape_safe.client import UnexecutedTxData
from ape_safe.utils import get_safe_tx_hash

if TYPE_CHECKING:
from ape.api import AccountAPI

from ape_safe.accounts import SafeAccount
from ape_safe.client import UnexecutedTxData


@click.group()
Expand Down Expand Up @@ -119,6 +120,11 @@ def propose(cli_ctx, ecosystem, safe, data, gas_price, value, receiver, nonce, s
"""
Create a new transaction
"""
from ape.api import AccountAPI

from ape_safe.accounts import get_signatures
from ape_safe.utils import get_safe_tx_hash

nonce = safe.new_nonce if nonce is None else nonce
txn = ecosystem.create_transaction(
value=value,
Expand Down Expand Up @@ -178,6 +184,10 @@ def propose(cli_ctx, ecosystem, safe, data, gas_price, value, receiver, nonce, s
@txn_ids_argument
@execute_option
def approve(cli_ctx: SafeCliContext, safe, txn_ids, execute):
from ape.api import AccountAPI

from ape_safe.utils import get_safe_tx_hash

submitter: Optional[AccountAPI] = execute if isinstance(execute, AccountAPI) else None
pending_transactions = list(
safe.client.get_transactions(confirmed=False, starting_nonce=safe.next_nonce)
Expand Down Expand Up @@ -258,7 +268,7 @@ def execute(cli_ctx, safe, txn_ids, submitter, nonce):
cli_ctx.abort_txns_not_found(txn_ids)


def _execute(safe: SafeAccount, txn: UnexecutedTxData, submitter: AccountAPI, **tx_kwargs):
def _execute(safe: "SafeAccount", txn: "UnexecutedTxData", submitter: "AccountAPI", **tx_kwargs):
safe_tx = safe.create_safe_tx(**txn.model_dump(mode="json", by_alias=True))
signatures: dict[AddressType, MessageSignature] = {
c.owner: MessageSignature.from_rsv(c.signature) for c in txn.confirmations
Expand All @@ -276,6 +286,8 @@ def reject(cli_ctx: SafeCliContext, safe, txn_ids, execute):
"""
Reject one or more pending transactions
"""
from ape.api import AccountAPI

submit = False if execute in (False, None) else True
submitter = execute if isinstance(execute, AccountAPI) else None
if submitter is None and submit:
Expand Down Expand Up @@ -369,7 +381,7 @@ def _show_confs(confs, extra_line: bool = True, prefix: Optional[str] = None):

# Helper method for handling transactions in a loop.
def _filter_tx_from_ids(
txn_ids: Sequence[Union[int, str]], txn: UnexecutedTxData
txn_ids: Sequence[Union[int, str]], txn: "UnexecutedTxData"
) -> Sequence[Union[int, str]]:
if txn.nonce in txn_ids:
# Filter out all transactions with the same nonce
Expand Down
7 changes: 5 additions & 2 deletions ape_safe/_cli/safe_mgmt.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@
skip_confirmation_option,
)
from ape.exceptions import ChainError, ProviderNotConnectedError
from ape.types import AddressType
from eth_typing import ChecksumAddress

from ape_safe._cli.click_ext import SafeCliContext, safe_argument, safe_cli_ctx
from ape_safe.client import ExecutedTxData


@click.command(name="list")
Expand Down Expand Up @@ -90,6 +88,7 @@ def add(cli_ctx: SafeCliContext, ecosystem, network, address, alias):
"""
Add a Safe to locally tracked Safes
"""
from ape.types import AddressType

address = cli_ctx.conversion_manager.convert(address, AddressType)
safe_contract = cli_ctx.chain_manager.contracts.instance_at(address)
Expand Down Expand Up @@ -138,6 +137,10 @@ def all_txns(cli_ctx: SafeCliContext, account, confirmed):
"""
View and filter all transactions for a given Safe using Safe API
"""
from ape.types import AddressType

from ape_safe.client import ExecutedTxData

if account in cli_ctx.account_manager.aliases:
account = cli_ctx.account_manager.load(account)

Expand Down
4 changes: 2 additions & 2 deletions ape_safe/client/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ class SignatureType(str, Enum):
class SafeTxConfirmation(BaseModel):
owner: AddressType
submission_date: datetime = Field(alias="submissionDate")
transaction_hash: Optional[HexBytes] = Field(None, alias="transactionHash")
transaction_hash: Optional[HexBytes] = Field(default=None, alias="transactionHash")
signature: HexBytes
signature_type: Optional[SignatureType] = Field(None, alias="signatureType")
signature_type: Optional[SignatureType] = Field(default=None, alias="signatureType")


class OperationType(int, Enum):
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ include = '\.pyi?$'
[tool.pytest.ini_options]
# NOTE: can't use xdist
addopts = """
-p no:pytest_ethereum
-n 0
--cov-branch
--cov-report term
Expand Down
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
"ape-solidity>=0.8", # Needed for compiling the Safe contracts
],
"lint": [
"black>=24.8.0,<25", # Auto-formatter and linter
"mypy>=1.11.1,<2", # Static type analyzer
"black>=24.10.0,<25", # Auto-formatter and linter
"mypy>=1.13.0,<2", # Static type analyzer
"types-requests", # Needed for mypy type shed
"types-setuptools", # Needed for mypy type shed
"flake8>=7.1.1,<8", # Style linter
"isort>=5.13.2,<6", # Import sorting linter
"mdformat>=0.7.17,<0.8", # Docs formatter and linter
"mdformat>=0.7.18,<0.8", # Docs formatter and linter
"mdformat-pyproject>=0.0.1", # Allows configuring in pyproject.toml
],
"release": [ # `release` GitHub Action job uses this
Expand Down

0 comments on commit c800f58

Please sign in to comment.