Skip to content

Commit

Permalink
btcli/bt.config: various improvements
Browse files Browse the repository at this point in the history
- implement recursive apply function for (sub^n)argparser
- use recursive apply to eliminate repeated code
- move adding standard bt.config args to separate function
- *use recursive apply to add standard bt.config args to all parsers
- *make strict=True the default
- eliminate redundant COMMANDS.item.name field
- remove obsolete COMMANDS looping code
- remove redundant dest= argument
- fix some comments

The changes marked * implement a functional improvement, the rest is for
improved maintainability.
  • Loading branch information
µ committed Aug 12, 2024
1 parent 98d0af6 commit a87e7f8
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 94 deletions.
33 changes: 11 additions & 22 deletions bittensor/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
}
COMMANDS = {
"subnets": {
"name": "subnets",
"aliases": ["s", "subnet"],
"help": "Commands for managing and viewing subnetworks.",
"commands": {
Expand All @@ -118,7 +117,6 @@
},
},
"root": {
"name": "root",
"aliases": ["r", "roots"],
"help": "Commands for managing and viewing the root network.",
"commands": {
Expand All @@ -140,7 +138,6 @@
},
},
"wallet": {
"name": "wallet",
"aliases": ["w", "wallets"],
"help": "Commands for managing and viewing wallets.",
"commands": {
Expand All @@ -165,7 +162,6 @@
},
},
"stake": {
"name": "stake",
"aliases": ["st", "stakes"],
"help": "Commands for staking and removing stake and setting child hotkey accounts.",
"commands": {
Expand All @@ -178,7 +174,6 @@
},
},
"weights": {
"name": "weights",
"aliases": ["wt", "weight"],
"help": "Commands for managing weight for subnets.",
"commands": {
Expand All @@ -187,7 +182,6 @@
},
},
"sudo": {
"name": "sudo",
"aliases": ["su", "sudos"],
"help": "Commands for subnet management",
"commands": {
Expand All @@ -197,7 +191,6 @@
},
},
"legacy": {
"name": "legacy",
"aliases": ["l"],
"help": "Miscellaneous commands.",
"commands": {
Expand All @@ -206,7 +199,6 @@
},
},
"info": {
"name": "info",
"aliases": ["i"],
"help": "Instructions for enabling autocompletion for the CLI.",
"commands": {
Expand Down Expand Up @@ -300,21 +292,18 @@ def __create_parser__() -> "argparse.ArgumentParser":
# Add arguments for each sub-command.
cmd_parsers = parser.add_subparsers(dest="command")
# Add argument parsers for all available commands.
for command in COMMANDS.values():
if isinstance(command, dict):
subcmd_parser = cmd_parsers.add_parser(
name=command["name"],
aliases=command["aliases"],
help=command["help"],
)
subparser = subcmd_parser.add_subparsers(
help=command["help"], dest="subcommand", required=True
)
for name, command in COMMANDS.items():
subcmd_parser = cmd_parsers.add_parser(
name=name,
aliases=command["aliases"],
help=command["help"],
)
subparser = subcmd_parser.add_subparsers(
help=command["help"], dest="subcommand", required=True
)

for subcommand in command["commands"].values():
subcommand.add_args(subparser)
else:
command.add_args(cmd_parsers)
for subcommand in command["commands"].values():
subcommand.add_args(subparser)

return parser

Expand Down
142 changes: 70 additions & 72 deletions bittensor/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def __init__(
self,
parser: argparse.ArgumentParser = None,
args: Optional[List[str]] = None,
strict: bool = False,
strict: bool = True,
default: Optional[Any] = None,
) -> None:
super().__init__(default)
Expand All @@ -74,50 +74,7 @@ def __init__(
if parser == None:
return None

# Optionally add config specific arguments
try:
parser.add_argument(
"--config",
type=str,
help="If set, defaults are overridden by passed file.",
)
except:
# this can fail if --config has already been added.
pass

try:
parser.add_argument(
"--strict",
action="store_true",
help="""If flagged, config will check that only exact arguments have been set.""",
default=False,
)
except:
# this can fail if --strict has already been added.
pass

try:
parser.add_argument(
"--no_version_checking",
action="store_true",
help="Set ``true`` to stop cli version checking.",
default=False,
)
except:
# this can fail if --no_version_checking has already been added.
pass

try:
parser.add_argument(
"--no_prompt",
dest="no_prompt",
action="store_true",
help="Set ``true`` to stop cli from prompting the user.",
default=False,
)
except:
# this can fail if --no_version_checking has already been added.
pass
config.apply_to_parser_recursive(parser, config.add_standard_args)

# Get args from argv if not passed in.
if args == None:
Expand Down Expand Up @@ -182,37 +139,21 @@ def __init__(
default_param_args = [_config.get("command"), _config.get("subcommand")]

## Get all args by name
default_params = parser.parse_args(args=default_param_args)
parser_no_required = copy.deepcopy(parser)
for i in range(len(parser_no_required._actions)):
parser_no_required._actions[i].required = False
default_params = parser_no_required.parse_args(args=default_param_args)

all_default_args = default_params.__dict__.keys() | []
## Make a dict with keys as args and values as argparse.SUPPRESS
defaults_as_suppress = {key: argparse.SUPPRESS for key in all_default_args}
## Set the defaults to argparse.SUPPRESS, should remove them from the namespace
parser_no_defaults.set_defaults(**defaults_as_suppress)
parser_no_defaults._defaults.clear() # Needed for quirk of argparse

### Check for subparsers and do the same
if parser_no_defaults._subparsers != None:
for action in parser_no_defaults._subparsers._actions:
# Should only be the "command" subparser action
if isinstance(action, argparse._SubParsersAction):
# Set the defaults to argparse.SUPPRESS, should remove them from the namespace
# Each choice is the keyword for a command, we need to set the defaults for each of these
## Note: we also need to clear the _defaults dict for each, this is a quirk of argparse
cmd_parser: argparse.ArgumentParser
for cmd_parser in action.choices.values():
# If this choice is also a subparser, set defaults recursively
if cmd_parser._subparsers:
for action in cmd_parser._subparsers._actions:
# Should only be the "command" subparser action
if isinstance(action, argparse._SubParsersAction):
cmd_parser: argparse.ArgumentParser
for cmd_parser in action.choices.values():
cmd_parser.set_defaults(**defaults_as_suppress)
cmd_parser._defaults.clear() # Needed for quirk of argparse
else:
cmd_parser.set_defaults(**defaults_as_suppress)
cmd_parser._defaults.clear() # Needed for quirk of argparse

def l_set_defaults(l_parser):
## Set the defaults to argparse.SUPPRESS, should remove them from the namespace
l_parser.set_defaults(**defaults_as_suppress)
l_parser._defaults.clear() # Needed for quirk of argparse

config.apply_to_parser_recursive(parser_no_defaults, l_set_defaults)

## Reparse the args, but this time with the defaults as argparse.SUPPRESS
params_no_defaults = config.__parse_args__(
Expand All @@ -231,6 +172,63 @@ def __init__(
]
}

@staticmethod
def apply_to_parser_recursive(parser, callback, depth=0):
callback(parser)
if not parser._subparsers:
return
for action in parser._subparsers._actions:
if not isinstance(action, argparse._SubParsersAction):
continue
for cmd_parser in action.choices.values():
config.apply_to_parser_recursive(cmd_parser, callback, depth=depth + 1)

@staticmethod
def add_standard_args(parser):
# Optionally add config specific arguments
try:
parser.add_argument(
"--config",
type=str,
help="If set, defaults are overridden by passed file.",
)
except:
# this can fail if --config has already been added.
pass

try:
parser.add_argument(
"--strict",
action="store_true",
help="If flagged, config will check that only exact arguments have been set.",
default=False,
)
except:
# this can fail if --strict has already been added.
pass

try:
parser.add_argument(
"--no_version_checking",
action="store_true",
help="Set ``true`` to stop cli version checking.",
default=False,
)
except:
# this can fail if --no_version_checking has already been added.
pass

try:
parser.add_argument(
"--no_prompt",
action="store_true",
help="Set ``true`` to stop cli from prompting the user.",
default=False,
)
except Exception as e:
# this can fail if --no_prompt has already been added.
pass

@staticmethod
def __split_params__(params: argparse.Namespace, _config: "config"):
# Splits params on dot syntax i.e neuron.axon_port and adds to _config
Expand Down

0 comments on commit a87e7f8

Please sign in to comment.