From 8761e67bf33bae544e57d0df5ee2d42dcd27c49e Mon Sep 17 00:00:00 2001 From: Loom Agent Date: Wed, 8 Jul 2026 22:15:05 +0000 Subject: [PATCH 1/2] fix(subtensor): return None for missing subnet instead of assert blocks_since_last_update, commit_reveal_enabled and difficulty used `assert call is not None` after get_hyperparameter, which raises an unhelpful AssertionError (or TypeError under python -O) when the queried subnet does not exist. Their docstrings already document a None return for that case. Replace the asserts with an explicit None return and widen the return types to Optional to match. --- bittensor/core/subtensor.py | 18 ++++++++++++------ tests/unit_tests/test_subtensor.py | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/bittensor/core/subtensor.py b/bittensor/core/subtensor.py index 17951b9c15..d316c95d27 100644 --- a/bittensor/core/subtensor.py +++ b/bittensor/core/subtensor.py @@ -900,7 +900,8 @@ def blocks_since_last_update( call: Optional[list[int]] = self.get_hyperparameter( param_name="LastUpdate", netuid=netuid, block=block ) - assert call is not None + if call is None: + return None return None if len(call) == 0 else (block - int(call[uid])) def blocks_until_next_epoch( @@ -973,7 +974,9 @@ def bonds( return bond_map - def commit_reveal_enabled(self, netuid: int, block: Optional[int] = None) -> bool: + def commit_reveal_enabled( + self, netuid: int, block: Optional[int] = None + ) -> Optional[bool]: """Check if commit-reveal mechanism is enabled for a given subnet at a specific block. Parameters: @@ -981,7 +984,8 @@ def commit_reveal_enabled(self, netuid: int, block: Optional[int] = None) -> boo block: The block number to query. If `None`, queries the current chain head. Returns: - True if commit-reveal mechanism is enabled, False otherwise. + True if commit-reveal mechanism is enabled, False otherwise, or `None` if the subnet + does not exist. Notes: - @@ -990,10 +994,11 @@ def commit_reveal_enabled(self, netuid: int, block: Optional[int] = None) -> boo call: Optional[bool] = self.get_hyperparameter( param_name="CommitRevealWeightsEnabled", block=block, netuid=netuid ) - assert call is not None + if call is None: + return None return call - def difficulty(self, netuid: int, block: Optional[int] = None) -> int: + def difficulty(self, netuid: int, block: Optional[int] = None) -> Optional[int]: """Retrieves the 'Difficulty' hyperparameter for a specified subnet in the Bittensor network. This parameter determines the computational challenge required for neurons to participate in consensus and @@ -1016,7 +1021,8 @@ def difficulty(self, netuid: int, block: Optional[int] = None) -> int: call: Optional[int] = self.get_hyperparameter( param_name="Difficulty", netuid=netuid, block=block ) - assert call is not None + if call is None: + return None return int(call) def does_hotkey_exist(self, hotkey_ss58: str, block: Optional[int] = None) -> bool: diff --git a/tests/unit_tests/test_subtensor.py b/tests/unit_tests/test_subtensor.py index 4407381deb..c02cc3e8ba 100644 --- a/tests/unit_tests/test_subtensor.py +++ b/tests/unit_tests/test_subtensor.py @@ -1989,6 +1989,27 @@ def test_difficulty_success(subtensor, mocker): assert result == int(mocked_get_hyperparameter.return_value) +@pytest.mark.parametrize( + "getter,param_name,extra_kwargs", + [ + ("difficulty", "Difficulty", {}), + ("commit_reveal_enabled", "CommitRevealWeightsEnabled", {}), + ("blocks_since_last_update", "LastUpdate", {"uid": 0}), + ], +) +def test_subnet_getter_returns_none_when_subnet_missing( + subtensor, mocker, getter, param_name, extra_kwargs +): + """When the subnet/uid is absent, get_hyperparameter returns None; the getter must + return None (honouring its docstring) instead of raising AssertionError.""" + mocker.patch.object(subtensor, "get_hyperparameter", return_value=None) + mocker.patch.object(subtensor, "get_current_block", return_value=1) + + result = getattr(subtensor, getter)(netuid=999, block=1, **extra_kwargs) + + assert result is None + + def test_recycle_success(subtensor, mocker): """Tests recycle method with successfully result.""" # Preps From c02fb08e71fec7d3a523df0fd55cbfa516c5c75e Mon Sep 17 00:00:00 2001 From: Loom Agent Date: Thu, 9 Jul 2026 10:27:07 +0000 Subject: [PATCH 2/2] chore(mypy): skip numpy stubs to keep make check green numpy 2.5 ships PEP 695 'type' aliases in numpy/__init__.pyi which mypy cannot parse when targeting python <3.12 (make check runs mypy for --python-version=3.10..3.14). This makes the project's 'make check' and the py3.10/py3.11 mypy CI jobs red on a fresh install regardless of this change. Skipping numpy stubs in mypy.ini restores the gate without constraining the runtime numpy bound (>=2.0.1,<3.0.0). --- mypy.ini | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mypy.ini b/mypy.ini index d38bdc7172..054851282e 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,6 +1,13 @@ [mypy] ignore_missing_imports = True ignore_errors = True +follow_imports_for_stubs = True + +[mypy-numpy.*] +follow_imports = skip + +[mypy-numpy] +follow_imports = skip [mypy-*.axon.*] ignore_errors = False