From ef44dc3175d0487bad87f51bea7c94fb7f099cba Mon Sep 17 00:00:00 2001 From: Bogdan Opanchuk Date: Sat, 30 Dec 2023 16:41:59 -0800 Subject: [PATCH] Lint tests --- pyproject.toml | 3 +- tests/conftest.py | 4 +- tests/ruff.toml | 29 ++++++++++++++ tests/test_abi_types.py | 2 +- tests/test_client.py | 57 +++++++++++++++------------- tests/test_compiler.py | 4 +- tests/test_contract.py | 16 ++++---- tests/test_contract_abi.py | 25 ++++++------ tests/test_contract_functionality.py | 5 +-- tests/test_entities.py | 35 +++++++++-------- tests/test_fallback_provider.py | 29 ++++++-------- tests/test_provider.py | 35 ++++++++--------- tests/test_rpc_provider.py | 3 +- tests/test_test_provider.py | 37 ++---------------- 14 files changed, 145 insertions(+), 139 deletions(-) create mode 100644 tests/ruff.toml diff --git a/pyproject.toml b/pyproject.toml index 4faad47..bcd2248 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -160,4 +160,5 @@ target-version = "py38" [tool.isort] profile = "black" -src_paths = ["pons", "test"] +src_paths = ["pons", "tests"] +known_first_party = ["pons"] diff --git a/tests/conftest.py b/tests/conftest.py index db6df1e..3658850 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,7 +5,7 @@ @pytest.fixture def test_provider(): - yield TesterProvider(root_balance=Amount.ether(100)) + return TesterProvider(root_balance=Amount.ether(100)) @pytest.fixture @@ -17,7 +17,7 @@ async def session(test_provider): @pytest.fixture def root_signer(test_provider): - yield test_provider.root + return test_provider.root @pytest.fixture diff --git a/tests/ruff.toml b/tests/ruff.toml new file mode 100644 index 0000000..22fe72f --- /dev/null +++ b/tests/ruff.toml @@ -0,0 +1,29 @@ +# Extend the `pyproject.toml` file in the parent directory. +extend = "../pyproject.toml" + +flake8-pytest-style.fixture-parentheses = false + +ignore = [ + # assert usage is what we do in tests + "S101", + # have to access private members sometimes + "SLF001", + # skipping type annotations for now + "ANN001", + "ANN002", + "ANN003", + "ANN201", + "ANN202", + # no docstrings in tests + "D100", + "D101", + "D102", + "D103", + "D107", + # We need it quite often during RPC and Solidity encoding/decoding + "FBT003", + # Yeah, that's great if your context manager calls are a few characters long + "SIM117", + # Too many false positives in the testing context. + "PLR2004", +] diff --git a/tests/test_abi_types.py b/tests/test_abi_types.py index accf465..c844d2c 100644 --- a/tests/test_abi_types.py +++ b/tests/test_abi_types.py @@ -266,7 +266,7 @@ def test_normalization_roundtrip(): assert struct._denormalize(expected_normalized) == value -def check_topic_encode_decode(tp, val, encoded_val, can_be_decoded=True): +def check_topic_encode_decode(tp, val, encoded_val, *, can_be_decoded=True): assert tp.encode_to_topic(val) == encoded_val if can_be_decoded: assert tp.decode_from_topic(encoded_val) == val diff --git a/tests/test_client.py b/tests/test_client.py index 14d8a86..613fb07 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -27,14 +27,14 @@ from pons._abi_types import encode_args, keccak from pons._client import BadResponseFormat, ProviderError, TransactionFailed from pons._contract_abi import PANIC_ERROR -from pons._entities import rpc_decode_block, rpc_encode_data +from pons._entities import rpc_encode_data from pons._provider import RPCError @pytest.fixture def compiled_contracts(): path = Path(__file__).resolve().parent / "TestClient.sol" - yield compile_contract_file(path) + return compile_contract_file(path) @contextmanager @@ -60,7 +60,7 @@ async def test_net_version(test_provider, session): # This is not going to get called def wrong_net_version(): - raise NotImplementedError() # pragma: no cover + raise NotImplementedError # pragma: no cover # The result should have been cached the first time with monkeypatched(test_provider, "net_version", wrong_net_version): @@ -81,7 +81,7 @@ async def test_eth_chain_id(test_provider, session): # This is not going to get called def wrong_chain_id(): - raise NotImplementedError() # pragma: no cover + raise NotImplementedError # pragma: no cover # The result should have been cached the first time with monkeypatched(test_provider, "eth_chain_id", wrong_chain_id): @@ -132,12 +132,13 @@ async def test_wait_for_transaction_receipt( tx_hash = await session.broadcast_transfer(root_signer, another_signer.address, to_transfer) # The receipt won't be available until we mine, so the waiting should time out + timeout = 5 start_time = trio.current_time() with pytest.raises(trio.TooSlowError): - with trio.fail_after(5): + with trio.fail_after(timeout): receipt = await session.wait_for_transaction_receipt(tx_hash) end_time = trio.current_time() - assert end_time - start_time == 5 + assert end_time - start_time == timeout # Now let's enable mining while we wait for the receipt receipt = None @@ -147,7 +148,7 @@ async def get_receipt(): receipt = await session.wait_for_transaction_receipt(tx_hash) async def delayed_enable_mining(): - await trio.sleep(5) + await trio.sleep(timeout) test_provider.enable_auto_mine_transactions() async with trio.open_nursery() as nursery: @@ -197,14 +198,16 @@ async def test_eth_call_decoding_error(session, compiled_contracts, root_signer) async def test_estimate_deploy(session, compiled_contracts): compiled_contract = compiled_contracts["BasicContract"] gas = await session.estimate_deploy(compiled_contract.constructor(1)) - assert isinstance(gas, int) and gas > 0 + assert isinstance(gas, int) + assert gas > 0 async def test_estimate_transfer(session, root_signer, another_signer): gas = await session.estimate_transfer( root_signer.address, another_signer.address, Amount.ether(10) ) - assert isinstance(gas, int) and gas > 0 + assert isinstance(gas, int) + assert gas > 0 with pytest.raises( ProviderError, @@ -219,7 +222,8 @@ async def test_estimate_transact(session, compiled_contracts, root_signer): compiled_contract = compiled_contracts["BasicContract"] deployed_contract = await session.deploy(root_signer, compiled_contract.constructor(1)) gas = await session.estimate_transact(deployed_contract.method.setState(456)) - assert isinstance(gas, int) and gas > 0 + assert isinstance(gas, int) + assert gas > 0 async def test_eth_gas_price(session): @@ -328,7 +332,7 @@ def mock_get_transaction_receipt(tx_hash_hex): await session.deploy(root_signer, basic_contract.constructor(0)) -async def test_transact(test_provider, session, compiled_contracts, root_signer): +async def test_transact(session, compiled_contracts, root_signer): basic_contract = compiled_contracts["BasicContract"] # Normal transact @@ -369,13 +373,14 @@ async def test_transact_and_return_events( deployed_contract = await session.deploy(root_signer, basic_contract.constructor(123)) - Event1 = deployed_contract.event.Event1 - Event2 = deployed_contract.event.Event2 + event1 = deployed_contract.event.Event1 + event2 = deployed_contract.event.Event2 - results_for = lambda x: { - Event1: [{"value": x}, {"value": x + 1}], - Event2: [{"value": x + 2}, {"value": x + 3}], - } + def results_for(x): + return { + event1: [{"value": x}, {"value": x + 1}], + event2: [{"value": x + 2}, {"value": x + 3}], + } # Normal operation: one relevant transaction in the block @@ -383,7 +388,7 @@ async def test_transact_and_return_events( result = await session.transact( root_signer, deployed_contract.method.emitMultipleEvents(x), - return_events=[Event1, Event2], + return_events=[event1, event2], ) assert result == results_for(x) @@ -396,7 +401,7 @@ async def test_transact_and_return_events( async def transact(signer, x): result = await session.transact( - signer, deployed_contract.method.emitMultipleEvents(x), return_events=[Event1, Event2] + signer, deployed_contract.method.emitMultipleEvents(x), return_events=[event1, event2] ) results[x] = result @@ -415,7 +420,7 @@ async def delayed_enable_mining(): assert results[x2] == results_for(x2) -async def test_get_block(test_provider, session, root_signer, another_signer): +async def test_get_block(session, root_signer, another_signer): to_transfer = Amount.ether(10) await session.transfer(root_signer, another_signer.address, to_transfer) @@ -438,7 +443,7 @@ async def test_get_block(test_provider, session, root_signer, another_signer): assert block_info is None -async def test_eth_get_transaction_by_hash(test_provider, session, root_signer, another_signer): +async def test_eth_get_transaction_by_hash(session, root_signer, another_signer): to_transfer = Amount.ether(1) tx_hash = await session.broadcast_transfer(root_signer, another_signer.address, to_transfer) @@ -451,7 +456,7 @@ async def test_eth_get_transaction_by_hash(test_provider, session, root_signer, async def test_eth_get_filter_changes_bad_response(test_provider, session, monkeypatch): - monkeypatch.setattr(test_provider, "eth_get_filter_changes", lambda filter_id: {"foo": 1}) + monkeypatch.setattr(test_provider, "eth_get_filter_changes", lambda _filter_id: {"foo": 1}) block_filter = await session.eth_new_block_filter() @@ -461,7 +466,7 @@ async def test_eth_get_filter_changes_bad_response(test_provider, session, monke await session.eth_get_filter_changes(block_filter) -async def test_block_filter(test_provider, session, root_signer, another_signer): +async def test_block_filter(session, root_signer, another_signer): to_transfer = Amount.ether(1) await session.transfer(root_signer, another_signer.address, to_transfer) @@ -871,7 +876,7 @@ async def test_unknown_error_reasons(test_provider, session, compiled_contracts, # Provider returns an unknown panic code - def eth_estimate_gas(*args, **kwargs): + def eth_estimate_gas(*_args, **_kwargs): # Invalid selector data = PANIC_ERROR.selector + encode_args((abi.uint(256), 888)) raise RPCError(RPCErrorCode.EXECUTION_ERROR, "execution reverted", rpc_encode_data(data)) @@ -882,7 +887,7 @@ def eth_estimate_gas(*args, **kwargs): # Provider returns an unknown error (a selector not present in the ABI) - def eth_estimate_gas(*args, **kwargs): + def eth_estimate_gas(*_args, **_kwargs): # Invalid selector data = b"1234" + encode_args((abi.uint(256), 1)) raise RPCError(RPCErrorCode.EXECUTION_ERROR, "execution reverted", rpc_encode_data(data)) @@ -895,7 +900,7 @@ def eth_estimate_gas(*args, **kwargs): # Provider returns an error with an unknown RPC code - def eth_estimate_gas(*args, **kwargs): + def eth_estimate_gas(*_args, **_kwargs): # Invalid selector data = PANIC_ERROR.selector + encode_args((abi.uint(256), 0)) raise RPCError(12345, "execution reverted", rpc_encode_data(data)) diff --git a/tests/test_compiler.py b/tests/test_compiler.py index a63d8aa..d1cd317 100644 --- a/tests/test_compiler.py +++ b/tests/test_compiler.py @@ -6,7 +6,7 @@ def test_multiple_contracts(): path = Path(__file__).resolve().parent / "TestCompiler.sol" contracts = compile_contract_file(path, evm_version=EVMVersion.SHANGHAI, optimize=True) - assert list(sorted(contracts)) == ["Contract1", "Contract2"] + assert sorted(contracts) == ["Contract1", "Contract2"] def test_import_remappings(): @@ -15,4 +15,4 @@ def test_import_remappings(): contracts = compile_contract_file( path, import_remappings={"@to_be_remapped": root_path / "test_compiler_subdir"} ) - assert list(sorted(contracts)) == ["Contract1", "Contract2"] + assert sorted(contracts) == ["Contract1", "Contract2"] diff --git a/tests/test_contract.py b/tests/test_contract.py index fe01a2e..3b9ac01 100644 --- a/tests/test_contract.py +++ b/tests/test_contract.py @@ -1,5 +1,5 @@ -from collections import namedtuple from pathlib import Path +from typing import NamedTuple, Tuple import pytest @@ -21,12 +21,11 @@ @pytest.fixture def compiled_contracts(): path = Path(__file__).resolve().parent / "TestContract.sol" - yield compile_contract_file(path) + return compile_contract_file(path) def test_abi_declaration(compiled_contracts): """Checks that the compiler output is parsed correctly.""" - compiled_contract = compiled_contracts["JsonAbiTest"] cabi = compiled_contract.abi @@ -70,7 +69,6 @@ def test_abi_declaration(compiled_contracts): def test_api_binding(compiled_contracts): """Checks that the methods are bound correctly on deploy.""" - compiled_contract = compiled_contracts["JsonAbiTest"] address = Address(b"\xab" * 20) @@ -112,9 +110,13 @@ def test_api_binding(compiled_contracts): ) # We only need a couple of fields - fake_log_entry = namedtuple("fake_log_entry", ["topics", "data", "address"]) + class FakeLogEntry(NamedTuple): + data: bytes + address: Address + topics: Tuple[LogTopic, ...] + decoded = event_filter.decode_log_entry( - fake_log_entry( + FakeLogEntry( address=address, topics=[LogTopic(abi.uint(256).encode(1)), LogTopic(keccak(b"1234"))], data=encode_args((abi.bytes(4), b"4567"), (abi.bytes(), b"bytestring")), @@ -124,5 +126,5 @@ def test_api_binding(compiled_contracts): with pytest.raises(ValueError, match="Log entry originates from a different contract"): decoded = event_filter.decode_log_entry( - fake_log_entry(address=Address(b"\xba" * 20), topics=[], data=b"") + FakeLogEntry(address=Address(b"\xba" * 20), topics=[], data=b"") ) diff --git a/tests/test_contract_abi.py b/tests/test_contract_abi.py index 369a590..ba5c3a4 100644 --- a/tests/test_contract_abi.py +++ b/tests/test_contract_abi.py @@ -1,10 +1,9 @@ import re -from collections import namedtuple +from typing import NamedTuple, Tuple import pytest from pons import ( - ABIDecodingError, Constructor, ContractABI, Either, @@ -549,28 +548,28 @@ def test_contract_abi_errors(): with pytest.raises( ValueError, match="JSON ABI contains more than one constructor declarations" ): - abi = ContractABI.from_json([constructor_abi, constructor_abi]) + ContractABI.from_json([constructor_abi, constructor_abi]) fallback_abi = dict(type="fallback", stateMutability="payable") with pytest.raises(ValueError, match="JSON ABI contains more than one fallback declarations"): - abi = ContractABI.from_json([fallback_abi, fallback_abi]) + ContractABI.from_json([fallback_abi, fallback_abi]) receive_abi = dict(type="receive", stateMutability="payable") with pytest.raises( ValueError, match="JSON ABI contains more than one receive method declarations" ): - abi = ContractABI.from_json([receive_abi, receive_abi]) + ContractABI.from_json([receive_abi, receive_abi]) event_abi = dict(type="event", name="Foo", inputs=[], anonymous=False) with pytest.raises(ValueError, match="JSON ABI contains more than one declarations of `Foo`"): - abi = ContractABI.from_json([event_abi, event_abi]) + ContractABI.from_json([event_abi, event_abi]) error_abi = dict(type="error", name="Foo", inputs=[]) with pytest.raises(ValueError, match="JSON ABI contains more than one declarations of `Foo`"): - abi = ContractABI.from_json([error_abi, error_abi]) + ContractABI.from_json([error_abi, error_abi]) with pytest.raises(ValueError, match="Unknown ABI entry type: foobar"): - abi = ContractABI.from_json([dict(type="foobar")]) + ContractABI.from_json([dict(type="foobar")]) def test_event_from_json(): @@ -627,12 +626,14 @@ def test_event_encode(): def test_event_decode(): # We only need a couple of fields - fake_log_entry = namedtuple("fake_log_entry", ["topics", "data"]) + class FakeLogEntry(NamedTuple): + topics: Tuple[LogTopic, ...] + data: bytes event = Event("Foo", dict(a=abi.bool, b=abi.uint(8), c=abi.bytes(4), d=abi.bytes()), {"a", "b"}) decoded = event.decode_log_entry( - fake_log_entry( + FakeLogEntry( [ LogTopic(keccak(event.name.encode() + event.fields.canonical_form.encode())), LogTopic(abi.bool.encode(True)), @@ -646,7 +647,7 @@ def test_event_decode(): # Wrong selector with pytest.raises(ValueError, match="This log entry belongs to a different event"): decoded = event.decode_log_entry( - fake_log_entry( + FakeLogEntry( [ LogTopic(keccak(b"NotFoo" + event.fields.canonical_form.encode())), LogTopic(abi.bool.encode(True)), @@ -666,7 +667,7 @@ def test_event_decode(): ) decoded = event.decode_log_entry( - fake_log_entry( + FakeLogEntry( [LogTopic(abi.bool.encode(True)), LogTopic(abi.uint(8).encode(2))], encode_args((abi.bytes(4), b"1234"), (abi.bytes(), b"bytestring")), ) diff --git a/tests/test_contract_functionality.py b/tests/test_contract_functionality.py index 80e17ab..a43e99c 100644 --- a/tests/test_contract_functionality.py +++ b/tests/test_contract_functionality.py @@ -17,7 +17,7 @@ @pytest.fixture def compiled_contracts(): path = Path(__file__).resolve().parent / "TestContractFunctionality.sol" - yield compile_contract_file(path) + return compile_contract_file(path) async def test_empty_constructor(session, root_signer, compiled_contracts): @@ -25,7 +25,6 @@ async def test_empty_constructor(session, root_signer, compiled_contracts): Checks that an empty constructor is created automatically if none is provided, and it can be used to deploy the contract. """ - compiled_contract = compiled_contracts["NoConstructor"] deployed_contract = await session.deploy(root_signer, compiled_contract.constructor()) @@ -61,7 +60,7 @@ async def test_basics(session, root_signer, another_signer, compiled_contracts): assert result == (inner, outer) -async def test_overloaded_method(session, root_signer, another_signer, compiled_contracts): +async def test_overloaded_method(session, root_signer, compiled_contracts): compiled_contract = compiled_contracts["Test"] # Deploy the contract diff --git a/tests/test_entities.py b/tests/test_entities.py index 12c5214..55696ae 100644 --- a/tests/test_entities.py +++ b/tests/test_entities.py @@ -21,11 +21,12 @@ def test_amount(): # Conversions - assert Amount.wei(100).as_wei() == 100 - assert Amount.wei(100).as_gwei() == 100 / 10**9 - assert Amount.wei(100).as_ether() == 100 / 10**18 - assert Amount.gwei(100).as_wei() == 100 * 10**9 - assert Amount.ether(100).as_wei() == 100 * 10**18 + val = 100 + assert Amount.wei(val).as_wei() == val + assert Amount.wei(val).as_gwei() == val / 10**9 + assert Amount.wei(val).as_ether() == val / 10**18 + assert Amount.gwei(val).as_wei() == val * 10**9 + assert Amount.ether(val).as_wei() == val * 10**18 with pytest.raises(TypeError, match="Amount must be an integer, got float"): Amount.wei(100.0) @@ -56,7 +57,7 @@ def test_amount(): # The type is hashable amount_set = {Amount.wei(100), Amount.wei(100), Amount.wei(50)} - assert len(amount_set) == 2 + assert amount_set == {Amount.wei(100), Amount.wei(50)} class MyAmount(Amount): pass @@ -82,6 +83,8 @@ def test_address(): random_addr = b"dv\xbbCQ,\xfe\xd0\xbfF\x8aq\x07OK\xf9\xa1i\x88(" random_addr_checksum = "0x6476Bb43512CFed0bF468a71074F4bF9A1698828" + random_addr2 = os.urandom(20) + assert bytes(Address(random_addr)) == random_addr assert bytes(Address.from_hex(random_addr_checksum)) == random_addr assert bytes(Address.from_hex(random_addr_checksum.lower())) == random_addr @@ -101,8 +104,8 @@ class MyAddress(Address): assert repr(MyAddress(random_addr)) == f"MyAddress.from_hex({random_addr_checksum})" # The type is hashable - addr_set = {Address(random_addr), Address(os.urandom(20)), Address(random_addr)} - assert len(addr_set) == 2 + addr_set = {Address(random_addr), Address(random_addr2), Address(random_addr)} + assert addr_set == {Address(random_addr), Address(random_addr2)} with pytest.raises(TypeError, match="Address must be a bytestring, got str"): Address(random_addr_checksum) @@ -115,11 +118,11 @@ class MyAddress(Address): with pytest.raises(TypeError, match="Incompatible types: MyAddress and Address"): # For whatever reason the the values are switched places in `__eq__()` - Address(random_addr) == MyAddress(random_addr) + assert Address(random_addr) == MyAddress(random_addr) # This error comes from eth_utils, we don't care about the phrasing, # but want to detect if the type changes. - with pytest.raises(ValueError): + with pytest.raises(ValueError): # noqa: PT011 Address.from_hex(random_addr_checksum[:-1]) with pytest.raises(RPCDecodingError, match="Address must be 20 bytes long, got 19"): @@ -178,8 +181,9 @@ def test_decode_tx_receipt(): def test_encode_decode_quantity(): - assert rpc_encode_quantity(100) == "0x64" - assert rpc_decode_quantity("0x64") == 100 + val = 100 + assert rpc_encode_quantity(val) == hex(val) + assert rpc_decode_quantity(hex(val)) == val with pytest.raises(RPCDecodingError, match="Encoded quantity must be a string"): rpc_decode_quantity(100) @@ -206,20 +210,21 @@ def test_encode_decode_data(): def test_encode_decode_block(): + val = 123 assert rpc_encode_block(Block.LATEST) == "latest" assert rpc_encode_block(Block.EARLIEST) == "earliest" assert rpc_encode_block(Block.PENDING) == "pending" assert rpc_encode_block(Block.SAFE) == "safe" assert rpc_encode_block(Block.FINALIZED) == "finalized" - assert rpc_encode_block(123) == "0x7b" + assert rpc_encode_block(val) == hex(val) assert rpc_decode_block("latest") == "latest" assert rpc_decode_block("earliest") == "earliest" assert rpc_decode_block("pending") == "pending" - assert rpc_decode_block("0x7b") == 123 + assert rpc_decode_block(hex(val)) == val def test_decode_bool(): - assert rpc_decode_bool(True) == True + assert rpc_decode_bool(True) is True with pytest.raises(RPCDecodingError, match="Encoded boolean must be `true` or `false`"): rpc_decode_bool(1) diff --git a/tests/test_fallback_provider.py b/tests/test_fallback_provider.py index 8ea3b2c..d125693 100644 --- a/tests/test_fallback_provider.py +++ b/tests/test_fallback_provider.py @@ -1,17 +1,11 @@ import os from contextlib import asynccontextmanager from enum import Enum -from typing import AsyncIterator, List, Optional +from typing import AsyncIterator import pytest -from pons import ( - CycleFallback, - FallbackProvider, - FallbackStrategy, - PriorityFallback, - Unreachable, -) +from pons import CycleFallback, FallbackProvider, PriorityFallback, Unreachable from pons._fallback_provider import PriorityFallbackStrategy from pons._provider import JSON, InvalidResponse, Provider, ProviderSession, RPCError @@ -44,16 +38,15 @@ class MockSession(ProviderSession): def __init__(self, provider: Provider): self.provider = provider - async def rpc(self, method: str, *args: JSON) -> JSON: + async def rpc(self, method: str, *_args: JSON) -> JSON: self.provider.requests.append(method) - if self.provider.state == ProviderState.NORMAL: - return "success" - elif self.provider.state == ProviderState.UNREACHABLE: + if self.provider.state == ProviderState.UNREACHABLE: raise Unreachable("") - elif self.provider.state == ProviderState.BAD_RESPONSE: + if self.provider.state == ProviderState.BAD_RESPONSE: raise InvalidResponse("") - elif self.provider.state == ProviderState.RPC_ERROR: + if self.provider.state == ProviderState.RPC_ERROR: raise RPCError(-1, "") + return "success" async def test_default_fallback(): @@ -138,21 +131,21 @@ async def test_raising_errors(): providers[1].set_state(ProviderState.UNREACHABLE) providers[2].set_state(ProviderState.UNREACHABLE) with pytest.raises(Unreachable): - result = await session.rpc(random_request()) + await session.rpc(random_request()) # InvalidResponse is raised if present providers[0].set_state(ProviderState.UNREACHABLE) providers[1].set_state(ProviderState.BAD_RESPONSE) providers[2].set_state(ProviderState.UNREACHABLE) with pytest.raises(InvalidResponse): - result = await session.rpc(random_request()) + await session.rpc(random_request()) # RPCError is raised if present providers[0].set_state(ProviderState.UNREACHABLE) providers[1].set_state(ProviderState.BAD_RESPONSE) providers[2].set_state(ProviderState.RPC_ERROR) with pytest.raises(RPCError): - result = await session.rpc(random_request()) + await session.rpc(random_request()) async def test_nested_providers(): @@ -199,7 +192,7 @@ async def test_nested_providers(): request = random_request() providers[3].set_state(ProviderState.NORMAL) providers[2].set_state(ProviderState.UNREACHABLE) - result = await session.rpc_at_pin(path, request) + await session.rpc_at_pin(path, request) assert providers[3].requests[-1] == request diff --git a/tests/test_provider.py b/tests/test_provider.py index f1c5a5b..723363a 100644 --- a/tests/test_provider.py +++ b/tests/test_provider.py @@ -12,7 +12,6 @@ InvalidResponse, Provider, ProviderSession, - ResponseDict, RPCError, RPCErrorCode, ) @@ -42,17 +41,19 @@ async def test_dict_request(session, root_signer, another_signer): def test_rpc_error(): - error = RPCError.from_json({"code": 2, "message": "error", "data": "additional data"}) - assert error.code == 2 + error_code = 2 + + error = RPCError.from_json({"code": error_code, "message": "error", "data": "additional data"}) + assert error.code == error_code assert error.data == "additional data" - assert error.to_json() == {"code": 2, "message": "error", "data": "additional data"} + assert error.to_json() == {"code": error_code, "message": "error", "data": "additional data"} - error = RPCError.from_json({"code": 2, "message": "error"}) + error = RPCError.from_json({"code": error_code, "message": "error"}) assert error.data is None - assert error.to_json() == {"code": 2, "message": "error"} + assert error.to_json() == {"code": error_code, "message": "error"} - error = RPCError.from_json({"code": "2", "message": "error"}) - assert error.code == 2 + error = RPCError.from_json({"code": str(error_code), "message": "error"}) + assert error.code == error_code error = RPCError.invalid_request() assert error.code == RPCErrorCode.INVALID_REQUEST.value @@ -97,14 +98,14 @@ async def test_dict_request_introspection(session, root_signer, another_signer): async def test_unexpected_response_type( test_provider, session, monkeypatch, root_signer, another_signer ): - monkeypatch.setattr(test_provider, "eth_get_transaction_receipt", lambda tx_hash: "something") + monkeypatch.setattr(test_provider, "eth_get_transaction_receipt", lambda _tx_hash: "something") tx_hash = await session.broadcast_transfer( root_signer, another_signer.address, Amount.ether(10) ) with pytest.raises(BadResponseFormat, match="Expected a dictionary as a response, got str"): - receipt = await session.eth_get_transaction_receipt(tx_hash) + await session.eth_get_transaction_receipt(tx_hash) async def test_missing_field(test_provider, session, monkeypatch, root_signer, another_signer): @@ -126,7 +127,7 @@ def faulty_eth_get_transaction_receipt(tx_hash): with pytest.raises( BadResponseFormat, match="Expected field `status` is missing from the result" ): - receipt = await session.eth_get_transaction_receipt(tx_hash) + await session.eth_get_transaction_receipt(tx_hash) async def test_none_instead_of_dict( @@ -136,7 +137,7 @@ async def test_none_instead_of_dict( # (the interpretation of such an event is up to the client). # `eth_getTransactionReceipt` can return a None normally (if there's no receipt yet), # but we force it here, just in case. - monkeypatch.setattr(test_provider, "eth_get_transaction_receipt", lambda tx_hash: None) + monkeypatch.setattr(test_provider, "eth_get_transaction_receipt", lambda _tx_hash: None) tx_hash = await session.broadcast_transfer( root_signer, another_signer.address, Amount.ether(10) ) @@ -146,7 +147,7 @@ async def test_none_instead_of_dict( async def test_non_ok_http_status(test_provider, session, monkeypatch): def faulty_net_version(): # A generic exception will generate a 500 status code - raise Exception("Something unexpected happened") + raise Exception("Something unexpected happened") # noqa: TRY002 monkeypatch.setattr(test_provider, "net_version", faulty_net_version) @@ -154,7 +155,7 @@ def faulty_net_version(): await session.net_version() -async def test_neither_result_nor_error_field(test_provider, session, monkeypatch): +async def test_neither_result_nor_error_field(session, monkeypatch): # Tests the handling of a badly formed provider response # without either "error" or "result" fields. # Unfortunately we can't achieve that by just patching the provider, have to patch the server @@ -172,11 +173,11 @@ async def faulty_process_request(*args, **kwargs): await session.net_version() -async def test_result_is_not_a_dict(test_provider, session, monkeypatch): +async def test_result_is_not_a_dict(session, monkeypatch): # Tests the handling of a badly formed provider response that is not a dictionary. # Unfortunately we can't achieve that by just patching the provider, have to patch the server - async def faulty_process_request(*args, **kwargs): + async def faulty_process_request(*_args, **_kwargs): return (HTTPStatus.OK, 1) monkeypatch.setattr(_test_rpc_provider, "process_request", faulty_process_request) @@ -203,7 +204,7 @@ async def session(self): yield MockSession() class MockSession(ProviderSession): - async def rpc(self, method, *args): + async def rpc(self, method, *_args): return method provider = MockProvider() diff --git a/tests/test_rpc_provider.py b/tests/test_rpc_provider.py index 61bfa5e..13c15b6 100644 --- a/tests/test_rpc_provider.py +++ b/tests/test_rpc_provider.py @@ -2,9 +2,8 @@ # and don't use high-level API. import pytest -import trio -from pons import Amount, Client, RPCError, RPCErrorCode, ServerHandle, TesterProvider +from pons import RPCError, RPCErrorCode, ServerHandle @pytest.fixture diff --git a/tests/test_test_provider.py b/tests/test_test_provider.py index ccf6e37..d1c39b4 100644 --- a/tests/test_test_provider.py +++ b/tests/test_test_provider.py @@ -32,7 +32,7 @@ # (since TesterProvider is what we're testing). @pytest.fixture def provider(): - yield TesterProvider(root_balance=Amount.ether(100)) + return TesterProvider(root_balance=Amount.ether(100)) @pytest.fixture @@ -44,7 +44,7 @@ async def session(provider): @pytest.fixture def root_signer(provider): - yield provider.root + return provider.root @pytest.fixture @@ -139,14 +139,14 @@ async def test_eth_get_transaction_count(provider, session, root_signer, another assert provider.eth_get_transaction_count(address, rpc_encode_block(Block.LATEST)) == "0x1" -async def test_eth_send_raw_transaction(provider, session, root_signer, another_signer): +async def test_eth_send_raw_transaction(provider, root_signer, another_signer): amount = Amount.ether(1) dest = another_signer.address latest = rpc_encode_block(Block.LATEST) tx = make_transfer_tx(provider, dest, amount, 0) signed_tx = root_signer.sign_transaction(tx) - tx_hash = TxHash.rpc_decode(provider.eth_send_raw_transaction(rpc_encode_data(signed_tx))) + provider.eth_send_raw_transaction(rpc_encode_data(signed_tx)) # Test that the transaction came through assert provider.eth_get_balance(dest.rpc_encode(), latest) == amount.rpc_encode() @@ -221,35 +221,6 @@ async def test_eth_get_transaction_by_hash(provider, root_signer, another_signer assert provider.eth_get_transaction_by_hash("0x" + "1" * 64) is None -async def test_eth_get_transaction_by_hash(provider, root_signer, another_signer): - amount = Amount.ether(1) - dest = another_signer.address - - tx = make_transfer_tx(provider, dest, amount, 0) - signed_tx = root_signer.sign_transaction(tx) - tx_hash = TxHash.rpc_decode(provider.eth_send_raw_transaction(rpc_encode_data(signed_tx))) - - recorded_tx = provider.eth_get_transaction_by_hash(tx_hash.rpc_encode()) - - preserved_fields = [ - "type", - "chainId", - "nonce", - "value", - "to", - "gas", - "maxFeePerGas", - "maxPriorityFeePerGas", - ] - for field in preserved_fields: - assert recorded_tx[field] == tx[field] - - assert recorded_tx["blockNumber"] == "0x1" - - # Test non-existent transaction - assert provider.eth_get_transaction_by_hash("0x" + "1" * 64) is None - - async def test_eth_get_block_by_hash(provider, root_signer, another_signer): amount = Amount.ether(1) dest = another_signer.address