Skip to content

Commit

Permalink
chore: improve ruff coverage (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-makerx authored Apr 20, 2023
1 parent 85b1aa6 commit 87d9584
Show file tree
Hide file tree
Showing 27 changed files with 816 additions and 671 deletions.
1 change: 0 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
autodoc2_packages = [
{
"path": "../../src/algokit_utils",
# "auto_mode": False,
},
]
autodoc2_skip_module_regexes = [r"algokit_utils\..*"]
Expand Down
38 changes: 19 additions & 19 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 59 additions & 27 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ py-algorand-sdk = "^2"
[tool.poetry.group.dev.dependencies]
pytest = "^7.2.0"
black = {extras = ["d"], version = "*"}
ruff = "^0.0.252"
ruff = "^0.0.261"
pip-audit = "*"
pytest-mock = "*"
mypy = "*"
Expand All @@ -32,36 +32,68 @@ poethepoet = "^0.19.0"
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

# TODO: Copy the stuff
[tool.ruff]
line-length = 120
select = ["E", "F", "ANN", "UP", "N", "C", "B", "A", "YTT", "W", "FBT", "Q", "RUF", "I", "PT"]
ignore = ["ANN101", "ANN401", "C901", "A003"]
select = [
# all possible codes as of this ruff version are listed here,
# ones we don't want/need are commented out to make it clear
# which have been omitted on purpose vs which ones get added
# in new ruff releases and should be considered for enabling
"F", # pyflakes
"E", "W", # pycodestyle
"C90", # mccabe
"I", # isort
"N", # PEP8 naming
"UP", # pyupgrade
"YTT", # flake8-2020
"ANN", # flake8-annotations
# "S", # flake8-bandit
# "BLE", # flake8-blind-except
"FBT", # flake8-boolean-trap
"B", # flake8-bugbear
"A", # flake8-builtins
# "COM", # flake8-commas
"C4", # flake8-comprehensions
"DTZ", # flake8-datetimez
"T10", # flake8-debugger
# "DJ", # flake8-django
# "EM", # flake8-errmsg
# "EXE", # flake8-executable
"ISC", # flake8-implicit-str-concat
"ICN", # flake8-import-conventions
# "G", # flake8-logging-format
# "INP", # flake8-no-pep420
"PIE", # flake8-pie
"T20", # flake8-print
"PYI", # flake8-pyi
"PT", # flake8-pytest-style
"Q", # flake8-quotes
"RSE", # flake8-raise
"RET", # flake8-return
"SLF", # flake8-self
"SIM", # flake8-simplify
"TID", # flake8-tidy-imports
"TCH", # flake8-type-checking
"ARG", # flake8-unused-arguments
"PTH", # flake8-use-pathlib
"ERA", # eradicate
# "PD", # pandas-vet
"PGH", # pygrep-hooks
"PL", # pylint
# "TRY", # tryceratops
# "NPY", # NumPy-specific rules
"RUF", # Ruff-specific rules
]
ignore = [
"ANN101", # no type for self
"ANN102", # no type for cls
"SIM108", # allow if-else in place of ternary
"RET505", # allow else after return
]
# Exclude a variety of commonly ignored directories.
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".hg",
".mypy_cache",
".nox",
".pants.d",
".ruff_cache",
".svn",
".tox",
".venv",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"venv",
extend-exclude = [
"docs"
]
per-file-ignores = {}
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
# Assume Python 3.10.
target-version = "py310"

Expand Down
32 changes: 18 additions & 14 deletions src/algokit_utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,9 @@
get_sandbox_default_account,
)
from algokit_utils.application_client import (
ABIArgsDict,
ABICallArgs,
ABICallArgsDict,
ABICreateCallArgs,
ABICreateCallArgsDict,
ABIMethod,
ApplicationClient,
CommonCallParameters,
CommonCallParametersDict,
CreateCallParameters,
CreateCallParametersDict,
OnCompleteCallParameters,
OnCompleteCallParametersDict,
Program,
execute_atc_with_logic_error,
get_app_id_from_tx_id,
get_next_version,
get_sender_from_signer,
num_extra_program_pages,
Expand All @@ -47,6 +34,10 @@
DELETABLE_TEMPLATE_NAME,
NOTE_PREFIX,
UPDATABLE_TEMPLATE_NAME,
ABICallArgs,
ABICallArgsDict,
ABICreateCallArgs,
ABICreateCallArgsDict,
AppDeployMetaData,
AppLookup,
AppMetaData,
Expand All @@ -58,11 +49,24 @@
OperationPerformed,
TemplateValueDict,
TemplateValueMapping,
get_app_id_from_tx_id,
get_creator_apps,
replace_template_variables,
)
from algokit_utils.logic_error import LogicError
from algokit_utils.models import ABITransactionResponse, Account, TransactionResponse
from algokit_utils.models import (
ABIArgsDict,
ABIMethod,
ABITransactionResponse,
Account,
CommonCallParameters,
CommonCallParametersDict,
CreateCallParameters,
CreateCallParametersDict,
OnCompleteCallParameters,
OnCompleteCallParametersDict,
TransactionResponse,
)
from algokit_utils.network_clients import (
AlgoClientConfig,
get_algod_client,
Expand Down
11 changes: 7 additions & 4 deletions src/algokit_utils/_transfer.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import dataclasses
import logging
from typing import TYPE_CHECKING

import algosdk.transaction
from algosdk.account import address_from_private_key
from algosdk.atomic_transaction_composer import AccountTransactionSigner
from algosdk.transaction import PaymentTxn, SuggestedParams
from algosdk.v2client.algod import AlgodClient

from algokit_utils.models import Account

if TYPE_CHECKING:
from algosdk.v2client.algod import AlgodClient

__all__ = ["TransferParameters", "transfer"]
logger = logging.getLogger(__name__)

Expand All @@ -30,7 +33,7 @@ class TransferParameters:
fee_micro_algos: int | None = None
"""(optional) The flat fee you want to pay, useful for covering extra fees in a transaction group or app call"""
max_fee_micro_algos: int | None = None
"""(optional)The maximum fee that you are happy to pay (default: unbounded) -
"""(optional)The maximum fee that you are happy to pay (default: unbounded) -
if this is set it's possible the transaction could get rejected during network congestion"""


Expand All @@ -44,14 +47,14 @@ def _check_fee(transaction: PaymentTxn, max_fee: int | None) -> None:
f"Algorand suggested fees would cause this transaction to cost {transaction.fee} µALGOs. "
f"Cap for this transaction is {max_fee} µALGOs."
)
elif transaction.fee > algosdk.constants.MIN_TXN_FEE:
if transaction.fee > algosdk.constants.MIN_TXN_FEE:
logger.warning(
f"Algorand network congestion fees are in effect. "
f"This transaction will incur a fee of {transaction.fee} µALGOs."
)


def transfer(client: AlgodClient, parameters: TransferParameters) -> PaymentTxn:
def transfer(client: "AlgodClient", parameters: TransferParameters) -> PaymentTxn:
"""Transfer µALGOs between accounts"""

suggested_params = parameters.suggested_params or client.suggested_params()
Expand Down
37 changes: 23 additions & 14 deletions src/algokit_utils/account.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import logging
import os
import warnings
from collections.abc import Callable
from typing import Any
from typing import TYPE_CHECKING, Any

from algosdk.account import address_from_private_key
from algosdk.kmd import KMDClient
from algosdk.mnemonic import from_private_key, to_private_key
from algosdk.util import algos_to_microalgos
from algosdk.v2client.algod import AlgodClient

from algokit_utils._transfer import TransferParameters, transfer
from algokit_utils.models import Account
from algokit_utils.network_clients import get_kmd_client_from_algod_client, is_localnet

if TYPE_CHECKING:
from collections.abc import Callable

from algosdk.kmd import KMDClient
from algosdk.v2client.algod import AlgodClient

__all__ = [
"create_kmd_wallet_account",
"get_account",
Expand All @@ -26,16 +29,17 @@
]

logger = logging.getLogger(__name__)
_DEFAULT_ACCOUNT_MINIMUM_BALANCE = 1_000_000_000


def get_account_from_mnemonic(mnemonic: str) -> Account:
"""Convert a mnemonic (25 word passphrase) into an Account"""
private_key = to_private_key(mnemonic) # type: ignore[no-untyped-call]
address = address_from_private_key(private_key) # type: ignore[no-untyped-call]
return Account(private_key, address)
return Account(private_key=private_key, address=address)


def create_kmd_wallet_account(kmd_client: KMDClient, name: str) -> Account:
def create_kmd_wallet_account(kmd_client: "KMDClient", name: str) -> Account:
"""Creates a wallet with specified name"""
wallet_id = kmd_client.create_wallet(name, "")["id"] # type: ignore[no-untyped-call]
wallet_handle = kmd_client.init_wallet_handle(wallet_id, "") # type: ignore[no-untyped-call]
Expand All @@ -49,7 +53,7 @@ def create_kmd_wallet_account(kmd_client: KMDClient, name: str) -> Account:


def get_or_create_kmd_wallet_account(
client: AlgodClient, name: str, fund_with_algos: float = 1000, kmd_client: KMDClient | None = None
client: "AlgodClient", name: str, fund_with_algos: float = 1000, kmd_client: "KMDClient | None" = None
) -> Account:
"""Returns a wallet with specified name, or creates one if not found"""
kmd_client = kmd_client or get_kmd_client_from_algod_client(client)
Expand Down Expand Up @@ -85,17 +89,19 @@ def get_or_create_kmd_wallet_account(


def _is_default_account(account: dict[str, Any]) -> bool:
return bool(account["status"] != "Offline" and account["amount"] > 1_000_000_000)
return bool(account["status"] != "Offline" and account["amount"] > _DEFAULT_ACCOUNT_MINIMUM_BALANCE)


def get_sandbox_default_account(client: AlgodClient) -> Account:
def get_sandbox_default_account(client: "AlgodClient") -> Account:
warnings.warn(
"get_sandbox_default_account is deprecated, please use get_localnet_default_account instead", DeprecationWarning
"get_sandbox_default_account is deprecated, please use get_localnet_default_account instead",
DeprecationWarning,
stacklevel=2,
)
return get_localnet_default_account(client)


def get_localnet_default_account(client: AlgodClient) -> Account:
def get_localnet_default_account(client: "AlgodClient") -> Account:
"""Returns the default Account in a LocalNet instance"""
if not is_localnet(client):
raise Exception("Can't get a default account from non LocalNet network")
Expand All @@ -107,15 +113,18 @@ def get_localnet_default_account(client: AlgodClient) -> Account:
return account


def get_dispenser_account(client: AlgodClient) -> Account:
def get_dispenser_account(client: "AlgodClient") -> Account:
"""Returns an Account based on DISPENSER_MNENOMIC environment variable or the default account on LocalNet"""
if is_localnet(client):
return get_localnet_default_account(client)
return get_account(client, "DISPENSER")


def get_kmd_wallet_account(
client: AlgodClient, kmd_client: KMDClient, name: str, predicate: Callable[[dict[str, Any]], bool] | None = None
client: "AlgodClient",
kmd_client: "KMDClient",
name: str,
predicate: "Callable[[dict[str, Any]], bool] | None" = None,
) -> Account | None:
"""Returns wallet matching specified name and predicate or None if not found"""
wallets: list[dict] = kmd_client.list_wallets() # type: ignore[no-untyped-call]
Expand Down Expand Up @@ -145,7 +154,7 @@ def get_kmd_wallet_account(


def get_account(
client: AlgodClient, name: str, fund_with_algos: float = 1000, kmd_client: KMDClient | None = None
client: "AlgodClient", name: str, fund_with_algos: float = 1000, kmd_client: "KMDClient | None" = None
) -> Account:
"""Returns an Algorand account with private key loaded by convention based on the given name identifier.
Expand Down
Loading

1 comment on commit 87d9584

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage

Coverage Report
FileStmtsMissCoverMissing
src/algokit_utils
   _transfer.py48394%13, 50–51
   account.py891583%15–18, 63–67, 96–101, 107, 120, 147, 150, 194
   application_client.py4998184%48–49, 105, 121, 163, 178, 183, 247, 304, 309–310, 312, 314, 381, 390, 399, 449, 457, 466, 510, 518, 527, 571, 579, 588, 615, 641, 649, 658, 700, 708, 717, 777, 792, 810–813, 847, 859–860, 864, 886, 926, 934, 971, 1031–1037, 1041–1046, 1048, 1084, 1091, 1211, 1227–1229, 1231, 1248, 1253–1263, 1269, 1275, 1282–1285, 1309–1314, 1334–1337
   application_specification.py972574%85, 88–97, 110, 118, 126, 155, 171, 193–202, 206
   deploy.py3732394%30–33, 163, 167–168, 185, 241, 318, 322, 328–336, 353–356, 374, 536–537, 557
   logic_error.py36294%6, 30
   models.py69199%70
   network_clients.py53591%58–59, 84, 87–88
TOTAL127315588% 

Tests Skipped Failures Errors Time
137 0 💤 0 ❌ 0 🔥 1m 15s ⏱️

Please sign in to comment.