From 2faadc22d4b788143062390eba8c3f9842b26c4b Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 7 Nov 2024 15:40:44 -0800 Subject: [PATCH 01/12] add ProposalVoteData test, AsyncSubtensor.encode_params test --- bittensor/core/async_subtensor.py | 4 +- bittensor/core/subtensor.py | 6 +- tests/unit_tests/test_async_subtensor.py | 95 ++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 tests/unit_tests/test_async_subtensor.py diff --git a/bittensor/core/async_subtensor.py b/bittensor/core/async_subtensor.py index e2c75d1086..156df602bf 100644 --- a/bittensor/core/async_subtensor.py +++ b/bittensor/core/async_subtensor.py @@ -147,13 +147,13 @@ async def __aexit__(self, exc_type, exc_val, exc_tb): async def encode_params( self, - call_definition: list["ParamWithTypes"], + call_definition: dict[str, list["ParamWithTypes"]], params: Union[list[Any], dict[str, Any]], ) -> str: """Returns a hex encoded string of the params using their types.""" param_data = scalecodec.ScaleBytes(b"") - for i, param in enumerate(call_definition["params"]): # type: ignore + for i, param in enumerate(call_definition["params"]): scale_obj = await self.substrate.create_scale_object(param["type"]) if isinstance(params, list): param_data += scale_obj.encode(params[i]) diff --git a/bittensor/core/subtensor.py b/bittensor/core/subtensor.py index 252414362a..771bd8fcf7 100644 --- a/bittensor/core/subtensor.py +++ b/bittensor/core/subtensor.py @@ -389,15 +389,15 @@ def add_args(cls, parser: "argparse.ArgumentParser", prefix: Optional[str] = Non @networking.ensure_connected def _encode_params( self, - call_definition: list["ParamWithTypes"], + call_definition: dict[str, list["ParamWithTypes"]], params: Union[list[Any], dict[str, Any]], ) -> str: """Returns a hex encoded string of the params using their types.""" param_data = scalecodec.ScaleBytes(b"") - for i, param in enumerate(call_definition["params"]): # type: ignore + for i, param in enumerate(call_definition["params"]): scale_obj = self.substrate.create_scale_object(param["type"]) - if type(params) is list: + if isinstance(params, list): param_data += scale_obj.encode(params[i]) else: if param["name"] not in params: diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py new file mode 100644 index 0000000000..6365647cbb --- /dev/null +++ b/tests/unit_tests/test_async_subtensor.py @@ -0,0 +1,95 @@ +import pytest + +from bittensor.core import async_subtensor + + +@pytest.fixture +def subtensor(mocker): + fake_async_substrate = mocker.AsyncMock() + fake_async_substrate.websocket.sock.getsockopt.return_value = 0 + mocker.patch.object( + async_subtensor, "AsyncSubstrateInterface", return_value=fake_async_substrate + ) + return async_subtensor.AsyncSubtensor() + + +def test_decode_ss58_tuples_in_proposal_vote_data(mocker): + """Tests that ProposalVoteData instance instantiation works properly,""" + # Preps + mocked_decode_account_id = mocker.patch.object(async_subtensor, "decode_account_id") + fake_proposal_dict = { + "index": "0", + "threshold": 1, + "ayes": ("0 line", "1 line"), + "nays": ("2 line", "3 line"), + "end": 123, + } + + # Call + async_subtensor.ProposalVoteData(fake_proposal_dict) + + # Asserts + assert mocked_decode_account_id.call_count == len(fake_proposal_dict["ayes"]) + len( + fake_proposal_dict["nays"] + ) + assert mocked_decode_account_id.mock_calls == [ + mocker.call("0"), + mocker.call("1"), + mocker.call("2"), + mocker.call("3"), + ] + + +@pytest.mark.asyncio +async def test_encode_params(subtensor, mocker): + """Tests encode_params happy path.""" + # Preps + subtensor.substrate.create_scale_object = mocker.AsyncMock() + subtensor.substrate.create_scale_object.return_value.encode = mocker.Mock( + return_value=b"" + ) + + call_definition = { + "params": [ + {"name": "coldkey", "type": "Vec"}, + {"name": "uid", "type": "u16"}, + ] + } + params = ["coldkey", "uid"] + + # Call + decoded_params = await subtensor.encode_params( + call_definition=call_definition, params=params + ) + + # Asserts + subtensor.substrate.create_scale_object.call_args( + mocker.call("coldkey"), + mocker.call("Vec"), + mocker.call("uid"), + mocker.call("u16"), + ) + assert decoded_params == "0x" + + +@pytest.mark.asyncio +async def test_encode_params_raises_error(subtensor, mocker): + """Tests encode_params with raised error.""" + # Preps + subtensor.substrate.create_scale_object = mocker.AsyncMock() + subtensor.substrate.create_scale_object.return_value.encode = mocker.Mock( + return_value=b"" + ) + + call_definition = { + "params": [ + {"name": "coldkey", "type": "Vec"}, + ] + } + params = {"undefined param": "some value"} + + # Call and assert + with pytest.raises(ValueError): + await subtensor.encode_params(call_definition=call_definition, params=params) + + subtensor.substrate.create_scale_object.return_value.encode.assert_not_called() From 7943d55baad7b09d642d2fedf3a2135e830a50e7 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 7 Nov 2024 15:45:56 -0800 Subject: [PATCH 02/12] test for `AsyncSubtensor.get_current_block` --- tests/unit_tests/test_async_subtensor.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index 6365647cbb..5ceee38f35 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -1,12 +1,14 @@ import pytest +from substrateinterface import SubstrateInterface from bittensor.core import async_subtensor @pytest.fixture def subtensor(mocker): - fake_async_substrate = mocker.AsyncMock() - fake_async_substrate.websocket.sock.getsockopt.return_value = 0 + fake_async_substrate = mocker.AsyncMock( + spec=async_subtensor.AsyncSubstrateInterface + ) mocker.patch.object( async_subtensor, "AsyncSubstrateInterface", return_value=fake_async_substrate ) @@ -93,3 +95,14 @@ async def test_encode_params_raises_error(subtensor, mocker): await subtensor.encode_params(call_definition=call_definition, params=params) subtensor.substrate.create_scale_object.return_value.encode.assert_not_called() + + +@pytest.mark.asyncio +async def test_get_current_block(subtensor): + """Tests get_current_block method.""" + # Call + result = await subtensor.get_current_block() + + # Asserts + subtensor.substrate.get_block_number.assert_called_once() + assert result == subtensor.substrate.get_block_number.return_value From 02093345fd54a9add9949b4892dc561a71fde428 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 7 Nov 2024 15:55:06 -0800 Subject: [PATCH 03/12] test for `AsyncSubtensor.get_block_hash` --- tests/unit_tests/test_async_subtensor.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index 5ceee38f35..bc3e485104 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -106,3 +106,23 @@ async def test_get_current_block(subtensor): # Asserts subtensor.substrate.get_block_number.assert_called_once() assert result == subtensor.substrate.get_block_number.return_value + + +@pytest.mark.asyncio +async def test_get_block_hash_without_block_id_aka_none(subtensor): + """Tests get_block_hash method without passed block_id.""" + # Call + result = await subtensor.get_block_hash() + + # Asserts + assert result == subtensor.substrate.get_chain_head.return_value + + +@pytest.mark.asyncio +async def test_get_block_hash_with_block_id(subtensor): + """Tests get_block_hash method with passed block_id.""" + # Call + result = await subtensor.get_block_hash(block_id=1) + + # Asserts + assert result == subtensor.substrate.get_block_hash.return_value From 5dff9b1a1020e72bfd99141052d7eef3ce4d1db2 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 7 Nov 2024 16:03:25 -0800 Subject: [PATCH 04/12] test for `AsyncSubtensor.is_hotkey_registered_any` --- tests/unit_tests/test_async_subtensor.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index bc3e485104..d2578092d0 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -126,3 +126,20 @@ async def test_get_block_hash_with_block_id(subtensor): # Asserts assert result == subtensor.substrate.get_block_hash.return_value + + +@pytest.mark.asyncio +async def test_is_hotkey_registered_any(subtensor, mocker): + """Tests is_hotkey_registered_any method.""" + # Preps + mocked_get_netuids_for_hotkey = mocker.AsyncMock(return_value=[1, 2]) + subtensor.get_netuids_for_hotkey = mocked_get_netuids_for_hotkey + + # Call + result = await subtensor.is_hotkey_registered_any( + hotkey_ss58="hotkey", block_hash="FAKE_HASH" + ) + + # Asserts + assert result == (len(mocked_get_netuids_for_hotkey.return_value) > 0) + From 319f30a69f9abaab9ea2fe16a72e35f0c8706fa7 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 7 Nov 2024 16:07:59 -0800 Subject: [PATCH 05/12] test for `AsyncSubtensor.get_subnet_burn_cost` --- tests/unit_tests/test_async_subtensor.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index d2578092d0..b5f2467270 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -143,3 +143,22 @@ async def test_is_hotkey_registered_any(subtensor, mocker): # Asserts assert result == (len(mocked_get_netuids_for_hotkey.return_value) > 0) + +@pytest.mark.asyncio +async def test_get_subnet_burn_cost(subtensor, mocker): + # Preps + mocked_query_runtime_api = mocker.AsyncMock(spec=subtensor.query_runtime_api) + subtensor.query_runtime_api = mocked_query_runtime_api + fake_block_hash = None + + # Call + result = await subtensor.get_subnet_burn_cost(block_hash=fake_block_hash) + + # Assert + assert result == mocked_query_runtime_api.return_value + mocked_query_runtime_api.assert_called_once_with( + runtime_api="SubnetRegistrationRuntimeApi", + method="get_network_registration_cost", + params=[], + block_hash=fake_block_hash, + ) From 7e6111d9b4e23aca8dc96d1dde585487374be31e Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 7 Nov 2024 16:17:34 -0800 Subject: [PATCH 06/12] test for `AsyncSubtensor.get_total_subnets` --- tests/unit_tests/test_async_subtensor.py | 37 +++++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index b5f2467270..dabe567eaf 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -1,5 +1,4 @@ import pytest -from substrateinterface import SubstrateInterface from bittensor.core import async_subtensor @@ -46,7 +45,9 @@ def test_decode_ss58_tuples_in_proposal_vote_data(mocker): async def test_encode_params(subtensor, mocker): """Tests encode_params happy path.""" # Preps - subtensor.substrate.create_scale_object = mocker.AsyncMock() + subtensor.substrate.create_scale_object = mocker.AsyncMock( + spec=async_subtensor.AsyncSubstrateInterface.create_scale_object + ) subtensor.substrate.create_scale_object.return_value.encode = mocker.Mock( return_value=b"" ) @@ -78,7 +79,9 @@ async def test_encode_params(subtensor, mocker): async def test_encode_params_raises_error(subtensor, mocker): """Tests encode_params with raised error.""" # Preps - subtensor.substrate.create_scale_object = mocker.AsyncMock() + subtensor.substrate.create_scale_object = mocker.AsyncMock( + spec=async_subtensor.AsyncSubstrateInterface.create_scale_object + ) subtensor.substrate.create_scale_object.return_value.encode = mocker.Mock( return_value=b"" ) @@ -132,7 +135,9 @@ async def test_get_block_hash_with_block_id(subtensor): async def test_is_hotkey_registered_any(subtensor, mocker): """Tests is_hotkey_registered_any method.""" # Preps - mocked_get_netuids_for_hotkey = mocker.AsyncMock(return_value=[1, 2]) + mocked_get_netuids_for_hotkey = mocker.AsyncMock( + return_value=[1, 2], spec=subtensor.get_netuids_for_hotkey + ) subtensor.get_netuids_for_hotkey = mocked_get_netuids_for_hotkey # Call @@ -146,6 +151,7 @@ async def test_is_hotkey_registered_any(subtensor, mocker): @pytest.mark.asyncio async def test_get_subnet_burn_cost(subtensor, mocker): + """Tests get_subnet_burn_cost method.""" # Preps mocked_query_runtime_api = mocker.AsyncMock(spec=subtensor.query_runtime_api) subtensor.query_runtime_api = mocked_query_runtime_api @@ -162,3 +168,26 @@ async def test_get_subnet_burn_cost(subtensor, mocker): params=[], block_hash=fake_block_hash, ) + + +@pytest.mark.asyncio +async def test_get_total_subnets(subtensor, mocker): + """Tests get_total_subnets method.""" + # Preps + mocked_substrate_query = mocker.AsyncMock( + spec=async_subtensor.AsyncSubstrateInterface.query + ) + subtensor.substrate.query = mocked_substrate_query + fake_block_hash = None + + # Call + result = await subtensor.get_total_subnets(block_hash=fake_block_hash) + + # Assert + assert result == mocked_substrate_query.return_value + mocked_substrate_query.assert_called_once_with( + module="SubtensorModule", + storage_function="TotalNetworks", + params=[], + block_hash=fake_block_hash, + ) From e2e5f7aa85d380e4e833d099d0aa1866668f1746 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 7 Nov 2024 17:18:03 -0800 Subject: [PATCH 07/12] test for `AsyncSubtensor.get_subnets` --- bittensor/core/async_subtensor.py | 2 +- tests/unit_tests/test_async_subtensor.py | 28 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/bittensor/core/async_subtensor.py b/bittensor/core/async_subtensor.py index 156df602bf..de005a9ac2 100644 --- a/bittensor/core/async_subtensor.py +++ b/bittensor/core/async_subtensor.py @@ -277,7 +277,7 @@ async def get_subnets(self, block_hash: Optional[str] = None) -> list[int]: return ( [] if result is None or not hasattr(result, "records") - else [netuid async for netuid, exists in result if exists] + else [netuid for netuid, exists in result.records if exists] ) async def is_hotkey_delegate( diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index dabe567eaf..8a0e4ee1dd 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -1,3 +1,5 @@ +from pickle import FALSE + import pytest from bittensor.core import async_subtensor @@ -191,3 +193,29 @@ async def test_get_total_subnets(subtensor, mocker): params=[], block_hash=fake_block_hash, ) + + +@pytest.mark.parametrize( + "records, result", + [([(0, True), (1, False), (3, False), (3, True)], [0, 1, 3]), ([], [])], + ids=["with records", "empty-records"], +) +@pytest.mark.asyncio +async def test_get_subnets(subtensor, mocker, records, result): + """Tests get_subnets method with any return.""" + # Preps + fake_result = mocker.AsyncMock() + fake_result.records = records + + mocked_substrate_query_map = mocker.AsyncMock( + spec=async_subtensor.AsyncSubstrateInterface.query_map, + ) + + subtensor.substrate.query_map = mocked_substrate_query_map + fake_block_hash = None + + # Call + result = await subtensor.get_subnets(block_hash=fake_block_hash) + + # Asserts + assert result == result From e45960d14def73fdd36a3ee40edf42345570ac2c Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 7 Nov 2024 17:37:16 -0800 Subject: [PATCH 08/12] test for `AsyncSubtensor.is_hotkey_delegate` --- tests/unit_tests/test_async_subtensor.py | 33 ++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index 8a0e4ee1dd..ddf0e069a4 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -218,4 +218,37 @@ async def test_get_subnets(subtensor, mocker, records, result): result = await subtensor.get_subnets(block_hash=fake_block_hash) # Asserts + mocked_substrate_query_map.assert_called_once_with( + module="SubtensorModule", + storage_function="NetworksAdded", + block_hash=fake_block_hash, + reuse_block_hash=True, + ) assert result == result + + +@pytest.mark.parametrize( + "hotkey_ss58_in_result", + [True, False], + ids=["hotkey-exists", "hotkey-doesnt-exist"], +) +@pytest.mark.asyncio +async def test_is_hotkey_delegate(subtensor, mocker, hotkey_ss58_in_result): + """Tests is_hotkey_delegate method.""" + # Preps + fake_hotkey_ss58 = "hotkey_58" + mocked_get_delegates = mocker.AsyncMock( + return_value=[ + mocker.Mock(hotkey_ss58=fake_hotkey_ss58 if hotkey_ss58_in_result else "") + ] + ) + subtensor.get_delegates = mocked_get_delegates + + # Call + result = await subtensor.is_hotkey_delegate( + hotkey_ss58=fake_hotkey_ss58, block_hash=None, reuse_block=True + ) + + # Asserts + assert result == hotkey_ss58_in_result + mocked_get_delegates.assert_called_once_with(block_hash=None, reuse_block=True) From 6710164b3f1a85069848d4e70dd16e267fedec94 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 7 Nov 2024 18:04:58 -0800 Subject: [PATCH 09/12] test for `AsyncSubtensor.get_delegates` --- tests/unit_tests/test_async_subtensor.py | 39 +++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index ddf0e069a4..0172e18ec3 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -234,7 +234,7 @@ async def test_get_subnets(subtensor, mocker, records, result): ) @pytest.mark.asyncio async def test_is_hotkey_delegate(subtensor, mocker, hotkey_ss58_in_result): - """Tests is_hotkey_delegate method.""" + """Tests is_hotkey_delegate method with any return.""" # Preps fake_hotkey_ss58 = "hotkey_58" mocked_get_delegates = mocker.AsyncMock( @@ -252,3 +252,40 @@ async def test_is_hotkey_delegate(subtensor, mocker, hotkey_ss58_in_result): # Asserts assert result == hotkey_ss58_in_result mocked_get_delegates.assert_called_once_with(block_hash=None, reuse_block=True) + + +@pytest.mark.parametrize( + "fake_hex_bytes_result, response", [(None, []), ("0xaabbccdd", b"\xaa\xbb\xcc\xdd")] +) +@pytest.mark.asyncio +async def test_get_delegates(subtensor, mocker, fake_hex_bytes_result, response): + """Tests get_delegates method.""" + # Preps + mocked_query_runtime_api = mocker.AsyncMock( + spec=subtensor.query_runtime_api, return_value=fake_hex_bytes_result + ) + subtensor.query_runtime_api = mocked_query_runtime_api + mocked_delegate_info_list_from_vec_u8 = mocker.Mock() + async_subtensor.DelegateInfo.list_from_vec_u8 = ( + mocked_delegate_info_list_from_vec_u8 + ) + + # Call + result = await subtensor.get_delegates(block_hash=None, reuse_block=True) + + # Asserts + if fake_hex_bytes_result: + assert result == mocked_delegate_info_list_from_vec_u8.return_value + mocked_delegate_info_list_from_vec_u8.assert_called_once_with( + bytes.fromhex(fake_hex_bytes_result[2:]) + ) + else: + assert result == response + + mocked_query_runtime_api.assert_called_once_with( + runtime_api="DelegateInfoRuntimeApi", + method="get_delegates", + params=[], + block_hash=None, + reuse_block=True, + ) From dd2fee57c887b44913f1acc7f1d9c65e2064d197 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 7 Nov 2024 18:27:30 -0800 Subject: [PATCH 10/12] replace spec to autospec because of python 3.11 doesn't accept the first one --- tests/unit_tests/test_async_subtensor.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index 0172e18ec3..61b93e5b13 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -8,7 +8,7 @@ @pytest.fixture def subtensor(mocker): fake_async_substrate = mocker.AsyncMock( - spec=async_subtensor.AsyncSubstrateInterface + autospec=async_subtensor.AsyncSubstrateInterface ) mocker.patch.object( async_subtensor, "AsyncSubstrateInterface", return_value=fake_async_substrate @@ -48,7 +48,7 @@ async def test_encode_params(subtensor, mocker): """Tests encode_params happy path.""" # Preps subtensor.substrate.create_scale_object = mocker.AsyncMock( - spec=async_subtensor.AsyncSubstrateInterface.create_scale_object + autospec=async_subtensor.AsyncSubstrateInterface.create_scale_object ) subtensor.substrate.create_scale_object.return_value.encode = mocker.Mock( return_value=b"" @@ -82,7 +82,7 @@ async def test_encode_params_raises_error(subtensor, mocker): """Tests encode_params with raised error.""" # Preps subtensor.substrate.create_scale_object = mocker.AsyncMock( - spec=async_subtensor.AsyncSubstrateInterface.create_scale_object + autospec=async_subtensor.AsyncSubstrateInterface.create_scale_object ) subtensor.substrate.create_scale_object.return_value.encode = mocker.Mock( return_value=b"" @@ -138,7 +138,7 @@ async def test_is_hotkey_registered_any(subtensor, mocker): """Tests is_hotkey_registered_any method.""" # Preps mocked_get_netuids_for_hotkey = mocker.AsyncMock( - return_value=[1, 2], spec=subtensor.get_netuids_for_hotkey + return_value=[1, 2], autospec=subtensor.get_netuids_for_hotkey ) subtensor.get_netuids_for_hotkey = mocked_get_netuids_for_hotkey @@ -155,7 +155,7 @@ async def test_is_hotkey_registered_any(subtensor, mocker): async def test_get_subnet_burn_cost(subtensor, mocker): """Tests get_subnet_burn_cost method.""" # Preps - mocked_query_runtime_api = mocker.AsyncMock(spec=subtensor.query_runtime_api) + mocked_query_runtime_api = mocker.AsyncMock(autospec=subtensor.query_runtime_api) subtensor.query_runtime_api = mocked_query_runtime_api fake_block_hash = None @@ -177,7 +177,7 @@ async def test_get_total_subnets(subtensor, mocker): """Tests get_total_subnets method.""" # Preps mocked_substrate_query = mocker.AsyncMock( - spec=async_subtensor.AsyncSubstrateInterface.query + autospec=async_subtensor.AsyncSubstrateInterface.query ) subtensor.substrate.query = mocked_substrate_query fake_block_hash = None @@ -208,7 +208,7 @@ async def test_get_subnets(subtensor, mocker, records, result): fake_result.records = records mocked_substrate_query_map = mocker.AsyncMock( - spec=async_subtensor.AsyncSubstrateInterface.query_map, + autospec=async_subtensor.AsyncSubstrateInterface.query_map, ) subtensor.substrate.query_map = mocked_substrate_query_map @@ -262,7 +262,7 @@ async def test_get_delegates(subtensor, mocker, fake_hex_bytes_result, response) """Tests get_delegates method.""" # Preps mocked_query_runtime_api = mocker.AsyncMock( - spec=subtensor.query_runtime_api, return_value=fake_hex_bytes_result + autospec=subtensor.query_runtime_api, return_value=fake_hex_bytes_result ) subtensor.query_runtime_api = mocked_query_runtime_api mocked_delegate_info_list_from_vec_u8 = mocker.Mock() From 8c9797143f45772e9337732b3aee6bd489708393 Mon Sep 17 00:00:00 2001 From: Roman <167799377+roman-opentensor@users.noreply.github.com> Date: Fri, 8 Nov 2024 08:34:58 -0800 Subject: [PATCH 11/12] Update tests/unit_tests/test_async_subtensor.py Co-authored-by: Benjamin Himes <37844818+thewhaleking@users.noreply.github.com> --- tests/unit_tests/test_async_subtensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index 61b93e5b13..5e4959b1a3 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -148,7 +148,7 @@ async def test_is_hotkey_registered_any(subtensor, mocker): ) # Asserts - assert result == (len(mocked_get_netuids_for_hotkey.return_value) > 0) + assert result is (len(mocked_get_netuids_for_hotkey.return_value) > 0) @pytest.mark.asyncio From 6aaca8409d3f67678715cf47faaad7e4cea1de36 Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 8 Nov 2024 09:54:57 -0800 Subject: [PATCH 12/12] fix review comments --- bittensor/core/async_subtensor.py | 4 ++-- bittensor/core/subtensor.py | 2 +- tests/unit_tests/test_async_subtensor.py | 12 +++++++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/bittensor/core/async_subtensor.py b/bittensor/core/async_subtensor.py index de005a9ac2..d1f61533a0 100644 --- a/bittensor/core/async_subtensor.py +++ b/bittensor/core/async_subtensor.py @@ -277,7 +277,7 @@ async def get_subnets(self, block_hash: Optional[str] = None) -> list[int]: return ( [] if result is None or not hasattr(result, "records") - else [netuid for netuid, exists in result.records if exists] + else [netuid async for netuid, exists in result if exists] ) async def is_hotkey_delegate( @@ -440,7 +440,7 @@ async def query_runtime_api( return_type = call_definition["type"] - as_scale_bytes = scalecodec.ScaleBytes(json_result["result"]) # type: ignore + as_scale_bytes = scalecodec.ScaleBytes(json_result["result"]) rpc_runtime_config = RuntimeConfiguration() rpc_runtime_config.update_type_registry(load_type_registry_preset("legacy")) diff --git a/bittensor/core/subtensor.py b/bittensor/core/subtensor.py index 771bd8fcf7..67888cd999 100644 --- a/bittensor/core/subtensor.py +++ b/bittensor/core/subtensor.py @@ -1232,7 +1232,7 @@ def get_subnet_hyperparameters( else: bytes_result = bytes.fromhex(hex_bytes_result) - return SubnetHyperparameters.from_vec_u8(bytes_result) # type: ignore + return SubnetHyperparameters.from_vec_u8(bytes_result) # Community uses this method # Returns network ImmunityPeriod hyper parameter. diff --git a/tests/unit_tests/test_async_subtensor.py b/tests/unit_tests/test_async_subtensor.py index 5e4959b1a3..6b58684f70 100644 --- a/tests/unit_tests/test_async_subtensor.py +++ b/tests/unit_tests/test_async_subtensor.py @@ -196,19 +196,21 @@ async def test_get_total_subnets(subtensor, mocker): @pytest.mark.parametrize( - "records, result", - [([(0, True), (1, False), (3, False), (3, True)], [0, 1, 3]), ([], [])], + "records, response", + [([(0, True), (1, False), (3, False), (3, True)], [0, 3]), ([], [])], ids=["with records", "empty-records"], ) @pytest.mark.asyncio -async def test_get_subnets(subtensor, mocker, records, result): +async def test_get_subnets(subtensor, mocker, records, response): """Tests get_subnets method with any return.""" # Preps - fake_result = mocker.AsyncMock() + fake_result = mocker.AsyncMock(autospec=list) fake_result.records = records + fake_result.__aiter__.return_value = iter(records) mocked_substrate_query_map = mocker.AsyncMock( autospec=async_subtensor.AsyncSubstrateInterface.query_map, + return_value=fake_result, ) subtensor.substrate.query_map = mocked_substrate_query_map @@ -224,7 +226,7 @@ async def test_get_subnets(subtensor, mocker, records, result): block_hash=fake_block_hash, reuse_block_hash=True, ) - assert result == result + assert result == response @pytest.mark.parametrize(