Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions gittensor/cli/issue_commands/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -625,13 +625,17 @@ def resolve_network(network: Optional[str] = None, rpc_url: Optional[str] = None
# override a user who set `network: finney` to point at mainnet.
config = load_config()

config_network = config.get('network', '').lower()
# `or ''` guards a null/absent `network` value (e.g. `"network": null` in a
# hand-edited config) — `config.get('network', '')` returns None when the
# key is present but null, and None.lower() would crash every issue
# command. Mirrors the guard in miner_commands.helpers._resolve_endpoint.
config_network = (config.get('network') or '').lower()
if config_network and config_network in NETWORK_MAP:
return NETWORK_MAP[config_network], config_network

if config.get('ws_endpoint'):
endpoint = config['ws_endpoint']
name = _URL_TO_NETWORK.get(endpoint, config.get('network', 'custom'))
name = _URL_TO_NETWORK.get(endpoint, config.get('network') or 'custom')
return endpoint, name

# Default: finney (mainnet)
Expand Down
36 changes: 36 additions & 0 deletions tests/cli/test_cli_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@
STATUS_COLORS,
colorize_status,
format_alpha,
resolve_network,
validate_bounty_amount,
validate_github_issue,
validate_repository,
validate_ss58_address,
)
from gittensor.cli.issue_commands.vote import parse_pr_number
from gittensor.cli.json_output import emit_json
from gittensor.constants import NETWORK_MAP

# =============================================================================
# format_alpha
Expand Down Expand Up @@ -919,3 +921,37 @@ def test_non_native_types_serialized_via_default(self, value, capsys):
captured = capsys.readouterr()
parsed = json.loads(captured.out)
assert parsed['field'] == str(value)


class TestResolveNetwork:
"""resolve_network config-file fallback, including a null `network` value.

A hand-edited or externally-written ~/.gittensor/config.json can carry
`"network": null`; `config.get('network', '')` returns None for that (the
key exists, so the default is unused) and must not crash every issue
command with `AttributeError: 'NoneType' object has no attribute 'lower'`.
"""

def _resolve_with_config(self, config):
with patch('gittensor.cli.issue_commands.helpers.load_config', return_value=config):
return resolve_network()

def test_null_network_falls_back_to_default(self):
endpoint, name = self._resolve_with_config({'network': None})
assert endpoint == NETWORK_MAP['finney']
assert name == 'finney'

def test_null_network_with_ws_endpoint_uses_endpoint(self):
endpoint, name = self._resolve_with_config({'network': None, 'ws_endpoint': 'ws://localhost:9944'})
assert endpoint == 'ws://localhost:9944'
assert name == 'custom'

def test_recognized_config_network(self):
endpoint, name = self._resolve_with_config({'network': 'test'})
assert endpoint == NETWORK_MAP['test']
assert name == 'test'

def test_empty_config_falls_back_to_default(self):
endpoint, name = self._resolve_with_config({})
assert endpoint == NETWORK_MAP['finney']
assert name == 'finney'