@@ -629,3 +629,337 @@ async def test_get_total_stake_for_hotkey(subtensor, mocker):
629629 )
630630 mocked_substrate_query_multiple .assert_called_once ()
631631 assert result == {0 : async_subtensor .Balance (1 )}
632+
633+
634+ @pytest .mark .parametrize (
635+ "records, response" ,
636+ [([(0 , True ), (1 , False ), (3 , False ), (3 , True )], [0 , 3 ]), ([], [])],
637+ ids = ["with records" , "empty-records" ],
638+ )
639+ @pytest .mark .asyncio
640+ async def test_get_netuids_for_hotkey (subtensor , mocker , records , response ):
641+ """Tests get_netuids_for_hotkey method."""
642+ # Preps
643+ fake_result = mocker .AsyncMock (autospec = list )
644+ fake_result .records = records
645+ fake_result .__aiter__ .return_value = iter (records )
646+
647+ mocked_substrate_query_map = mocker .AsyncMock (
648+ autospec = async_subtensor .AsyncSubstrateInterface .query_map ,
649+ return_value = fake_result ,
650+ )
651+
652+ subtensor .substrate .query_map = mocked_substrate_query_map
653+ fake_hotkey_ss58 = "hotkey_58"
654+ fake_block_hash = None
655+
656+ # Call
657+ result = await subtensor .get_netuids_for_hotkey (
658+ hotkey_ss58 = fake_hotkey_ss58 , block_hash = fake_block_hash , reuse_block = True
659+ )
660+
661+ # Assertions
662+ mocked_substrate_query_map .assert_called_once_with (
663+ module = "SubtensorModule" ,
664+ storage_function = "IsNetworkMember" ,
665+ params = [fake_hotkey_ss58 ],
666+ block_hash = fake_block_hash ,
667+ reuse_block_hash = True ,
668+ )
669+ assert result == response
670+
671+
672+ @pytest .mark .asyncio
673+ async def test_subnet_exists (subtensor , mocker ):
674+ """Tests subnet_exists method ."""
675+ # Preps
676+ fake_netuid = 1
677+ fake_block_hash = "block_hash"
678+ fake_reuse_block_hash = True
679+
680+ mocked_substrate_query = mocker .AsyncMock (
681+ autospec = async_subtensor .AsyncSubstrateInterface .query
682+ )
683+ subtensor .substrate .query = mocked_substrate_query
684+
685+ # Call
686+ result = await subtensor .subnet_exists (
687+ netuid = fake_netuid ,
688+ block_hash = fake_block_hash ,
689+ reuse_block = fake_reuse_block_hash ,
690+ )
691+
692+ # Asserts
693+ mocked_substrate_query .assert_called_once_with (
694+ module = "SubtensorModule" ,
695+ storage_function = "NetworksAdded" ,
696+ params = [fake_netuid ],
697+ block_hash = fake_block_hash ,
698+ reuse_block_hash = fake_reuse_block_hash ,
699+ )
700+ assert result == mocked_substrate_query .return_value
701+
702+
703+ @pytest .mark .asyncio
704+ async def test_get_hyperparameter_happy_path (subtensor , mocker ):
705+ """Tests get_hyperparameter method with happy path."""
706+ # Preps
707+ fake_param_name = "param_name"
708+ fake_netuid = 1
709+ fake_block_hash = "block_hash"
710+ fake_reuse_block_hash = True
711+
712+ # kind of fake subnet exists
713+ mocked_subtensor_subnet_exists = mocker .AsyncMock (return_value = True )
714+ subtensor .subnet_exists = mocked_subtensor_subnet_exists
715+
716+ mocked_substrate_query = mocker .AsyncMock (
717+ autospec = async_subtensor .AsyncSubstrateInterface .query
718+ )
719+ subtensor .substrate .query = mocked_substrate_query
720+
721+ # Call
722+ result = await subtensor .get_hyperparameter (
723+ param_name = fake_param_name ,
724+ netuid = fake_netuid ,
725+ block_hash = fake_block_hash ,
726+ reuse_block = fake_reuse_block_hash ,
727+ )
728+
729+ # Assertions
730+ mocked_subtensor_subnet_exists .assert_called_once ()
731+ mocked_substrate_query .assert_called_once_with (
732+ module = "SubtensorModule" ,
733+ storage_function = fake_param_name ,
734+ params = [fake_netuid ],
735+ block_hash = fake_block_hash ,
736+ reuse_block_hash = fake_reuse_block_hash ,
737+ )
738+ assert result == mocked_substrate_query .return_value
739+
740+
741+ @pytest .mark .asyncio
742+ async def test_get_hyperparameter_if_subnet_does_not_exist (subtensor , mocker ):
743+ """Tests get_hyperparameter method if subnet does not exist."""
744+ # Preps
745+ # kind of fake subnet doesn't exist
746+ mocked_subtensor_subnet_exists = mocker .AsyncMock (return_value = False )
747+ subtensor .subnet_exists = mocked_subtensor_subnet_exists
748+
749+ mocked_substrate_query = mocker .AsyncMock (
750+ autospec = async_subtensor .AsyncSubstrateInterface .query
751+ )
752+ subtensor .substrate .query = mocked_substrate_query
753+
754+ # Call
755+ result = await subtensor .get_hyperparameter (mocker .Mock (), mocker .Mock ())
756+
757+ # Assertions
758+ mocked_subtensor_subnet_exists .assert_called_once ()
759+ mocked_substrate_query .assert_not_called ()
760+ assert result is None
761+
762+
763+ @pytest .mark .parametrize (
764+ "all_netuids, filter_for_netuids, response" ,
765+ [([1 , 2 ], [3 , 4 ], []), ([1 , 2 ], [1 , 3 ], [1 ]), ([1 , 2 ], None , [1 , 2 ])],
766+ ids = [
767+ "all arguments -> no comparison" ,
768+ "all arguments -> is comparison" ,
769+ "not filter_for_netuids" ,
770+ ],
771+ )
772+ @pytest .mark .asyncio
773+ async def test_filter_netuids_by_registered_hotkeys (
774+ subtensor , mocker , all_netuids , filter_for_netuids , response
775+ ):
776+ """Tests filter_netuids_by_registered_hotkeys method."""
777+ # Preps
778+ fake_wallet_1 = mocker .Mock (autospec = async_subtensor .Wallet )
779+ fake_wallet_1 .hotkey .ss58_address = "ss58_address_1"
780+ fake_wallet_2 = mocker .Mock (autospec = async_subtensor .Wallet )
781+ fake_wallet_2 .hotkey .ss58_address = "ss58_address_2"
782+
783+ fake_all_netuids = all_netuids
784+ fake_filter_for_netuids = filter_for_netuids
785+ fake_all_hotkeys = [fake_wallet_1 , fake_wallet_2 ]
786+ fake_block_hash = "fake_block_hash"
787+ fake_reuse_block = True
788+
789+ mocked_get_netuids_for_hotkey = mocker .AsyncMock (
790+ # returned subnets list
791+ return_value = [1 , 2 ]
792+ )
793+ subtensor .get_netuids_for_hotkey = mocked_get_netuids_for_hotkey
794+
795+ # Call
796+
797+ result = await subtensor .filter_netuids_by_registered_hotkeys (
798+ all_netuids = fake_all_netuids ,
799+ filter_for_netuids = fake_filter_for_netuids ,
800+ all_hotkeys = fake_all_hotkeys ,
801+ block_hash = fake_block_hash ,
802+ reuse_block = fake_reuse_block ,
803+ )
804+
805+ # Asserts
806+ mocked_get_netuids_for_hotkey .call_count = len (fake_all_netuids )
807+ assert mocked_get_netuids_for_hotkey .mock_calls == [
808+ mocker .call (
809+ w .hotkey .ss58_address ,
810+ block_hash = fake_block_hash ,
811+ reuse_block = fake_reuse_block ,
812+ )
813+ for w in fake_all_hotkeys
814+ ]
815+ assert result == response
816+
817+
818+ @pytest .mark .asyncio
819+ async def test_get_existential_deposit_happy_path (subtensor , mocker ):
820+ """Tests get_existential_deposit method."""
821+ # Preps
822+ fake_block_hash = "block_hash"
823+ fake_reuse_block_hash = True
824+
825+ mocked_substrate_get_constant = mocker .AsyncMock (return_value = 1 )
826+ subtensor .substrate .get_constant = mocked_substrate_get_constant
827+
828+ spy_balance_from_rao = mocker .spy (async_subtensor .Balance , "from_rao" )
829+
830+ # Call
831+ result = await subtensor .get_existential_deposit (
832+ block_hash = fake_block_hash , reuse_block = fake_reuse_block_hash
833+ )
834+
835+ # Asserts
836+ mocked_substrate_get_constant .assert_awaited_once ()
837+ mocked_substrate_get_constant .assert_called_once_with (
838+ module_name = "Balances" ,
839+ constant_name = "ExistentialDeposit" ,
840+ block_hash = fake_block_hash ,
841+ reuse_block_hash = fake_reuse_block_hash ,
842+ )
843+ spy_balance_from_rao .assert_called_once_with (
844+ mocked_substrate_get_constant .return_value
845+ )
846+ assert result == async_subtensor .Balance (mocked_substrate_get_constant .return_value )
847+
848+
849+ @pytest .mark .asyncio
850+ async def test_get_existential_deposit_raise_exception (subtensor , mocker ):
851+ """Tests get_existential_deposit method raise Exception."""
852+ # Preps
853+ fake_block_hash = "block_hash"
854+ fake_reuse_block_hash = True
855+
856+ mocked_substrate_get_constant = mocker .AsyncMock (return_value = None )
857+ subtensor .substrate .get_constant = mocked_substrate_get_constant
858+
859+ spy_balance_from_rao = mocker .spy (async_subtensor .Balance , "from_rao" )
860+
861+ # Call
862+ with pytest .raises (Exception ):
863+ await subtensor .get_existential_deposit (
864+ block_hash = fake_block_hash , reuse_block = fake_reuse_block_hash
865+ )
866+
867+ # Asserts
868+ mocked_substrate_get_constant .assert_awaited_once ()
869+ mocked_substrate_get_constant .assert_called_once_with (
870+ module_name = "Balances" ,
871+ constant_name = "ExistentialDeposit" ,
872+ block_hash = fake_block_hash ,
873+ reuse_block_hash = fake_reuse_block_hash ,
874+ )
875+ spy_balance_from_rao .assert_not_called ()
876+
877+
878+ @pytest .mark .asyncio
879+ async def test_neurons (subtensor , mocker ):
880+ """Tests neurons method."""
881+ # Preps
882+ fake_netuid = 1
883+ fake_block_hash = "block_hash"
884+ fake_neurons = [mocker .Mock (), mocker .Mock ()]
885+ fake_weights = [(1 , [(10 , 20 ), (30 , 40 )]), (2 , [(50 , 60 ), (70 , 80 )])]
886+ fake_bonds = [(1 , [(10 , 20 ), (30 , 40 )]), (2 , [(50 , 60 ), (70 , 80 )])]
887+
888+ mocked_neurons_lite = mocker .AsyncMock (return_value = fake_neurons )
889+ subtensor .neurons_lite = mocked_neurons_lite
890+
891+ mocked_weights = mocker .AsyncMock (return_value = fake_weights )
892+ subtensor .weights = mocked_weights
893+
894+ mocked_bonds = mocker .AsyncMock (return_value = fake_bonds )
895+ subtensor .bonds = mocked_bonds
896+
897+ mocked_neuron_info_method = mocker .Mock ()
898+ async_subtensor .NeuronInfo .from_weights_bonds_and_neuron_lite = (
899+ mocked_neuron_info_method
900+ )
901+
902+ # Call
903+ result = await subtensor .neurons (netuid = fake_netuid , block_hash = fake_block_hash )
904+
905+ # Asserts
906+ mocked_neurons_lite .assert_awaited_once ()
907+ mocked_neurons_lite .assert_called_once_with (
908+ netuid = fake_netuid , block_hash = fake_block_hash
909+ )
910+ mocked_weights .assert_awaited_once ()
911+ mocked_weights .assert_called_once_with (
912+ netuid = fake_netuid , block_hash = fake_block_hash
913+ )
914+ mocked_bonds .assert_awaited_once ()
915+ mocked_bonds .assert_called_once_with (netuid = fake_netuid , block_hash = fake_block_hash )
916+ assert result == [
917+ mocked_neuron_info_method .return_value for _ in range (len (fake_neurons ))
918+ ]
919+
920+
921+ @pytest .mark .parametrize (
922+ "fake_hex_bytes_result, response" ,
923+ [(None , []), ("0xaabbccdd" , b"\xaa \xbb \xcc \xdd " )],
924+ ids = ["none" , "with data" ],
925+ )
926+ @pytest .mark .asyncio
927+ async def test_neurons_lite (subtensor , mocker , fake_hex_bytes_result , response ):
928+ """Tests neurons_lite method."""
929+ # Preps
930+ fake_netuid = 1
931+ fake_block_hash = "block_hash"
932+ fake_reuse_block_hash = True
933+
934+ mocked_query_runtime_api = mocker .AsyncMock (return_value = fake_hex_bytes_result )
935+ subtensor .query_runtime_api = mocked_query_runtime_api
936+
937+ mocked_neuron_info_lite_list_from_vec_u8 = mocker .Mock ()
938+ async_subtensor .NeuronInfoLite .list_from_vec_u8 = (
939+ mocked_neuron_info_lite_list_from_vec_u8
940+ )
941+
942+ # Call
943+ result = await subtensor .neurons_lite (
944+ netuid = fake_netuid ,
945+ block_hash = fake_block_hash ,
946+ reuse_block = fake_reuse_block_hash ,
947+ )
948+
949+ # Assertions
950+ mocked_query_runtime_api .assert_awaited_once ()
951+ mocked_query_runtime_api .assert_called_once_with (
952+ runtime_api = "NeuronInfoRuntimeApi" ,
953+ method = "get_neurons_lite" ,
954+ params = [fake_netuid ],
955+ block_hash = fake_block_hash ,
956+ reuse_block = fake_reuse_block_hash ,
957+ )
958+ if fake_hex_bytes_result :
959+ mocked_neuron_info_lite_list_from_vec_u8 .assert_called_once_with (
960+ bytes .fromhex (fake_hex_bytes_result [2 :])
961+ )
962+ assert result == mocked_neuron_info_lite_list_from_vec_u8 .return_value
963+ else :
964+ mocked_neuron_info_lite_list_from_vec_u8 .assert_not_called ()
965+ assert result == []
0 commit comments