diff --git a/CHANGELOG.md b/CHANGELOG.md index 735a7d0261..0b7e879b86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * (testground)[#1644](https://github.com/crypto-org-chain/cronos/pull/1644) load generator retry with backoff on error. * [#1648](https://github.com/crypto-org-chain/cronos/pull/1648) Add abort OE in PrepareProposal. * (testground)[#1651](https://github.com/crypto-org-chain/cronos/pull/1651) Benchmark use cosmos broadcast rpc. +* (testground)[#1650](https://github.com/crypto-org-chain/cronos/pull/1650) Benchmark support batch mode. *Oct 14, 2024* diff --git a/testground/benchmark/.flake8 b/testground/benchmark/.flake8 new file mode 100644 index 0000000000..09022d9662 --- /dev/null +++ b/testground/benchmark/.flake8 @@ -0,0 +1,4 @@ +[flake8] +max-line-length = 88 +extend-ignore = E203 +exclude = __pycache__ diff --git a/testground/benchmark/benchmark/stateless.py b/testground/benchmark/benchmark/stateless.py index 8ac87f20b8..f938633c19 100644 --- a/testground/benchmark/benchmark/stateless.py +++ b/testground/benchmark/benchmark/stateless.py @@ -59,6 +59,7 @@ def validate_json(ctx, param, value): @click.option("--num-txs", default=1000) @click.option("--num-idle", default=20) @click.option("--tx-type", default="simple-transfer") +@click.option("--batch-size", default=1) @click.option("--config-patch", default="{}", callback=validate_json) @click.option("--app-patch", default="{}", callback=validate_json) @click.option("--genesis-patch", default="{}", callback=validate_json) @@ -82,6 +83,7 @@ def _gen( num_txs: int = 1000, num_idle: int = 20, tx_type: str = "simple-transfer", + batch_size: int = 1, validator_generate_load: bool = True, config_patch: dict = None, app_patch: dict = None, @@ -145,7 +147,8 @@ def _gen( "num_txs": num_txs, "num_idle": num_idle, "tx_type": tx_type, - "validator-generate-load": validator_generate_load, + "batch_size": batch_size, + "validator_generate_load": validator_generate_load, } (outdir / "config.json").write_text(json.dumps(cfg)) @@ -216,6 +219,7 @@ def run(outdir: str, datadir: str, cronosd, global_seq): @click.option("--num-accounts", default=10) @click.option("--num-txs", default=1000) @click.option("--tx-type", default="simple-transfer") +@click.option("--batch-size", default=1) @click.option("--node", type=int) def gen_txs(**kwargs): return _gen_txs(**kwargs) @@ -249,13 +253,14 @@ def _gen_txs( num_accounts: int = 10, num_txs: int = 1000, tx_type: str = "simple-transfer", + batch_size: int = 1, node: Optional[int] = None, ): outdir = Path(outdir) def job(global_seq): print("generating", num_accounts * num_txs, "txs for node", global_seq) - txs = transaction.gen(global_seq, num_accounts, num_txs, tx_type) + txs = transaction.gen(global_seq, num_accounts, num_txs, tx_type, batch_size) transaction.save(txs, outdir, global_seq) print("saved", len(txs), "txs for node", global_seq) @@ -269,7 +274,7 @@ def job(global_seq): def do_run( datadir: Path, home: Path, cronosd: str, group: str, global_seq: int, cfg: dict ): - if group == FULLNODE_GROUP or cfg.get("validator-generate-load", True): + if group == FULLNODE_GROUP or cfg.get("validator_generate_load", True): txs = prepare_txs(cfg, datadir, global_seq) else: txs = [] @@ -437,7 +442,11 @@ def prepare_txs(cfg, datadir, global_seq): else: print("generating", cfg["num_accounts"] * cfg["num_txs"], "txs") txs = transaction.gen( - global_seq, cfg["num_accounts"], cfg["num_txs"], cfg["tx_type"] + global_seq, + cfg["num_accounts"], + cfg["num_txs"], + cfg["tx_type"], + cfg["batch_size"], ) return txs diff --git a/testground/benchmark/benchmark/stats.py b/testground/benchmark/benchmark/stats.py index 1a0978179c..c5a74c8fa9 100644 --- a/testground/benchmark/benchmark/stats.py +++ b/testground/benchmark/benchmark/stats.py @@ -1,6 +1,6 @@ from datetime import datetime -from .utils import block, block_height +from .utils import block, block_eth, block_height # the tps calculation use the average of the last 10 blocks TPS_WINDOW = 5 @@ -19,18 +19,33 @@ def calculate_tps(blocks): return txs / time_diff -def dump_block_stats(fp): +def get_block_info_cosmos(height): + blk = block(height) + timestamp = datetime.fromisoformat(blk["result"]["block"]["header"]["time"]) + txs = len(blk["result"]["block"]["data"]["txs"]) + return timestamp, txs + + +def get_block_info_eth(height): + blk = block_eth(height) + timestamp = datetime.fromtimestamp(int(blk["timestamp"], 0)) + txs = len(blk["transactions"]) + return timestamp, txs + + +def dump_block_stats(fp, eth=True): """ - dump simple statistics for blocks for analysis + dump block stats using web3 json-rpc, which splits batch tx """ tps_list = [] current = block_height() blocks = [] # skip block 1 whose timestamp is not accurate for i in range(2, current + 1): - blk = block(i) - timestamp = datetime.fromisoformat(blk["result"]["block"]["header"]["time"]) - txs = len(blk["result"]["block"]["data"]["txs"]) + if eth: + timestamp, txs = get_block_info_eth(i) + else: + timestamp, txs = get_block_info_cosmos(i) blocks.append((txs, timestamp)) tps = calculate_tps(blocks[-TPS_WINDOW:]) tps_list.append(tps) diff --git a/testground/benchmark/benchmark/transaction.py b/testground/benchmark/benchmark/transaction.py index 48d8685e7e..291fb84389 100644 --- a/testground/benchmark/benchmark/transaction.py +++ b/testground/benchmark/benchmark/transaction.py @@ -14,7 +14,7 @@ from . import cosmostx from .erc20 import CONTRACT_ADDRESS -from .utils import DEFAULT_DENOM, LOCAL_RPC, gen_account, split +from .utils import DEFAULT_DENOM, LOCAL_RPC, gen_account, split, split_batch GAS_PRICE = 1000000000 CHAIN_ID = 777 @@ -55,8 +55,10 @@ def erc20_transfer_tx(nonce: int): Job = namedtuple( - "Job", ["chunk", "global_seq", "num_accounts", "num_txs", "tx_type", "create_tx"] + "Job", + ["chunk", "global_seq", "num_accounts", "num_txs", "tx_type", "create_tx", "batch"], ) +EthTx = namedtuple("EthTx", ["tx", "raw", "sender"]) def _do_job(job: Job): @@ -68,19 +70,25 @@ def _do_job(job: Job): for i in range(job.num_txs): tx = job.create_tx(i) raw = acct.sign_transaction(tx).rawTransaction - txs.append(build_cosmos_tx(tx, raw, HexBytes(acct.address))) + txs.append(EthTx(tx, raw, HexBytes(acct.address))) total += 1 if total % 1000 == 0: print("generated", total, "txs for node", job.global_seq) + + # to keep it simple, only build batch inside the account + txs = [ + build_cosmos_tx(*txs[start:end]) + for start, end in split_batch(len(txs), job.batch) + ] acct_txs.append(txs) return acct_txs -def gen(global_seq, num_accounts, num_txs, tx_type: str) -> [str]: +def gen(global_seq, num_accounts, num_txs, tx_type: str, batch: int) -> [str]: chunks = split(num_accounts, os.cpu_count()) create_tx = TX_TYPES[tx_type] jobs = [ - Job(chunk, global_seq, num_accounts, num_txs, tx_type, create_tx) + Job(chunk, global_seq, num_accounts, num_txs, tx_type, create_tx, batch) for chunk in chunks ] @@ -112,20 +120,24 @@ def load(datadir: Path, global_seq: int) -> [str]: return ujson.load(f) -def build_cosmos_tx(tx: dict, raw: bytes, sender: bytes) -> str: +def build_cosmos_tx(*txs: EthTx) -> str: """ - return base64 encoded cosmos tx + return base64 encoded cosmos tx, support batch """ - msg = cosmostx.build_any( - "/ethermint.evm.v1.MsgEthereumTx", - cosmostx.MsgEthereumTx( - from_=sender, - raw=raw, - ), - ) - fee = tx["gas"] * tx["gasPrice"] + msgs = [ + cosmostx.build_any( + "/ethermint.evm.v1.MsgEthereumTx", + cosmostx.MsgEthereumTx( + from_=tx.sender, + raw=tx.raw, + ), + ) + for tx in txs + ] + fee = sum(tx.tx["gas"] * tx.tx["gasPrice"] for tx in txs) + gas = sum(tx.tx["gas"] for tx in txs) body = cosmostx.TxBody( - messages=[msg], + messages=msgs, extension_options=[ cosmostx.build_any("/ethermint.evm.v1.ExtensionOptionsEthereumTx") ], @@ -133,7 +145,7 @@ def build_cosmos_tx(tx: dict, raw: bytes, sender: bytes) -> str: auth_info = cosmostx.AuthInfo( fee=cosmostx.Fee( amount=[cosmostx.Coin(denom=DEFAULT_DENOM, amount=str(fee))], - gas_limit=tx["gas"], + gas_limit=gas, ) ) return base64.b64encode( @@ -151,7 +163,9 @@ async def async_sendtx(session, raw): json={ "jsonrpc": "2.0", "method": "broadcast_tx_async", - "params": {"tx": raw}, + "params": { + "tx": raw, + }, "id": 1, }, ) as rsp: diff --git a/testground/benchmark/benchmark/utils.py b/testground/benchmark/benchmark/utils.py index e3c8e94e32..5d71f74122 100644 --- a/testground/benchmark/benchmark/utils.py +++ b/testground/benchmark/benchmark/utils.py @@ -171,6 +171,18 @@ def block(height): return requests.get(f"{LOCAL_RPC}/block?height={height}").json() +def block_eth(height: int): + return requests.post( + f"{LOCAL_JSON_RPC}", + json={ + "jsonrpc": "2.0", + "method": "eth_getBlockByNumber", + "params": [hex(height), False], + "id": 1, + }, + ).json()["result"] + + def block_txs(height): return block(height)["result"]["block"]["data"]["txs"] @@ -181,3 +193,17 @@ def split(a: int, n: int): """ k, m = divmod(a, n) return [(i * k + min(i, m), (i + 1) * k + min(i + 1, m)) for i in range(n)] + + +def split_batch(a: int, size: int): + """ + Split range(0, a) into batches with size + """ + if size < 1: + size = 1 + + k, m = divmod(a, size) + parts = [(i * size, (i + 1) * size) for i in range(k)] + if m: + parts.append((k * size, a)) + return parts diff --git a/testground/benchmark/overlay.nix b/testground/benchmark/overlay.nix index d1aeb3e7dd..3360074e3b 100644 --- a/testground/benchmark/overlay.nix +++ b/testground/benchmark/overlay.nix @@ -11,6 +11,8 @@ let pyunormalize = [ "setuptools" ]; pytest-github-actions-annotate-failures = [ "setuptools" ]; cprotobuf = [ "setuptools" ]; + flake8-black = [ "setuptools" ]; + flake8-isort = [ "hatchling" ]; }; in lib.mapAttrs diff --git a/testground/benchmark/poetry.lock b/testground/benchmark/poetry.lock index 72b5b389a8..9fc7d678cc 100644 --- a/testground/benchmark/poetry.lock +++ b/testground/benchmark/poetry.lock @@ -304,6 +304,50 @@ files = [ {file = "bitarray-2.9.2.tar.gz", hash = "sha256:a8f286a51a32323715d77755ed959f94bef13972e9a2fe71b609e40e6d27957e"}, ] +[[package]] +name = "black" +version = "24.10.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.9" +files = [ + {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, + {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, + {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, + {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, + {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, + {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, + {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, + {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, + {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, + {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, + {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, + {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, + {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, + {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, + {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, + {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, + {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, + {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, + {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, + {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, + {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, + {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.10)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + [[package]] name = "certifi" version = "2024.7.4" @@ -837,6 +881,58 @@ dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "hy docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] test = ["hypothesis (>=4.43.0)", "mypy (==1.5.1)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] +[[package]] +name = "flake8" +version = "7.1.1" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.8.1" +files = [ + {file = "flake8-7.1.1-py2.py3-none-any.whl", hash = "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213"}, + {file = "flake8-7.1.1.tar.gz", hash = "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.12.0,<2.13.0" +pyflakes = ">=3.2.0,<3.3.0" + +[[package]] +name = "flake8-black" +version = "0.3.6" +description = "flake8 plugin to call black as a code style validator" +optional = false +python-versions = ">=3.7" +files = [ + {file = "flake8-black-0.3.6.tar.gz", hash = "sha256:0dfbca3274777792a5bcb2af887a4cad72c72d0e86c94e08e3a3de151bb41c34"}, + {file = "flake8_black-0.3.6-py3-none-any.whl", hash = "sha256:fe8ea2eca98d8a504f22040d9117347f6b367458366952862ac3586e7d4eeaca"}, +] + +[package.dependencies] +black = ">=22.1.0" +flake8 = ">=3" + +[package.extras] +develop = ["build", "twine"] + +[[package]] +name = "flake8-isort" +version = "6.1.1" +description = "flake8 plugin that integrates isort" +optional = false +python-versions = ">=3.8" +files = [ + {file = "flake8_isort-6.1.1-py3-none-any.whl", hash = "sha256:0fec4dc3a15aefbdbe4012e51d5531a2eb5fa8b981cdfbc882296a59b54ede12"}, + {file = "flake8_isort-6.1.1.tar.gz", hash = "sha256:c1f82f3cf06a80c13e1d09bfae460e9666255d5c780b859f19f8318d420370b3"}, +] + +[package.dependencies] +flake8 = "*" +isort = ">=5.0.0,<6" + +[package.extras] +test = ["pytest"] + [[package]] name = "frozenlist" version = "1.4.1" @@ -986,6 +1082,20 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "isort" +version = "5.13.2" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, +] + +[package.extras] +colors = ["colorama (>=0.4.6)"] + [[package]] name = "jsonmerge" version = "1.9.2" @@ -1129,6 +1239,17 @@ files = [ [package.extras] test = ["pytest"] +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + [[package]] name = "multidict" version = "6.0.5" @@ -1228,6 +1349,17 @@ files = [ {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, ] +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + [[package]] name = "netifaces" version = "0.11.0" @@ -1292,6 +1424,33 @@ files = [ [package.dependencies] regex = ">=2022.3.15" +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] + [[package]] name = "pluggy" version = "1.5.0" @@ -1327,6 +1486,17 @@ files = [ {file = "protobuf-5.27.2.tar.gz", hash = "sha256:f3ecdef226b9af856075f28227ff2c90ce3a594d092c39bee5513573f25e2714"}, ] +[[package]] +name = "pycodestyle" +version = "2.12.1" +description = "Python style guide checker" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3"}, + {file = "pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"}, +] + [[package]] name = "pycryptodome" version = "3.20.0" @@ -1490,6 +1660,17 @@ files = [ [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" +[[package]] +name = "pyflakes" +version = "3.2.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, + {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, +] + [[package]] name = "pytest" version = "8.2.2" @@ -2237,4 +2418,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "bebd65d7cba833c0079907f3174c7441312f4daa9c254a5030bdeb7c81bf6387" +content-hash = "16d29b66f6557b3efa49e9ad0b143851b37a3d5d518f7607e6c55618b7f5e326" diff --git a/testground/benchmark/pyproject.toml b/testground/benchmark/pyproject.toml index c18f9132d6..ed4953d96a 100644 --- a/testground/benchmark/pyproject.toml +++ b/testground/benchmark/pyproject.toml @@ -24,6 +24,10 @@ cprotobuf = "^0.1.11" [tool.poetry.group.dev.dependencies] pytest = "^8.2" pytest-github-actions-annotate-failures = "^0.2.0" +black = "^24.10.0" +flake8 = "^7.1.1" +flake8-black = "^0.3.6" +flake8-isort = "^6.1.1" [build-system] requires = ["poetry-core"]