simplify parser and config with getattr, fiddle with args

This commit is contained in:
John Burwell 2023-04-25 22:07:35 -05:00
parent 00b2f54381
commit deae9af4c6
5 changed files with 50 additions and 36 deletions

View File

@ -29,10 +29,9 @@ class Commands():
# aliases,
# helpmsg,
# function,
# callback,
# {arg:
# {arg attributes},
# ...})
# arg:
# arg attributes...,
# )
('bye',
['b', 'q'],
'Sign off and disconnect',
@ -94,7 +93,7 @@ class Commands():
'Send a new message to a user',
self.responder.send,
{
'callsign': {'help': 'Message recipient callsign'},
'--callsign': {'help': 'Message recipient callsign'},
'--subject': {'help': 'Message subject'},
'--message': {'help': 'Message'},
},),
@ -104,7 +103,7 @@ class Commands():
'Send a private message to a user',
self.responder.send_private,
{
'callsign': {'help': 'Message recipient callsign'},
'--callsign': {'help': 'Message recipient callsign'},
'--subject': {'help': 'Message subject'},
'--message': {'help': 'Message'},
},),]

View File

@ -25,45 +25,52 @@ import yaml
class Config():
def __init__(self, app_name, args):
self._app_name = app_name
self._config_file_path = args.config_file
self.app_name = app_name
self._argv_config_file = args.config_file
self._load_config()
# Put the messages db file in the system's user data directory
self.config['db_path'] = os.path.join(
platformdirs.user_data_dir(appname=app_name, ensure_exists=True),
platformdirs.user_data_dir(
appname=self.app_name,
ensure_exists=True),
'messages.db')
self.config['debug'] = args.debug
# Grab some config from the command line for convenience
self.config['args'] = args
self.config['calling_station'] = args.calling_station.upper() or None
self.config['debug'] = args.debug
# The main thing people want from Config is config values, so let's pretend
# everything anyone asks of Config that isn't otherwise defined is probably
# a config value they want
def __getattr__(self, __name: str):
return self.config[__name]
@property
def config_path(self):
def config_file(self):
# Use either the specified file or a file in a system config location
config_path = self._config_file_path or os.path.join(
config_file = self._argv_config_file or os.path.join(
platformdirs.user_config_dir(
appname=self._app_name,
appname=self.app_name,
ensure_exists=True),
'config.yaml'
)
return config_path
return config_file
def _init_config_file(self):
# If the file doesn't exist there, create it from the default file
# included in the package
if not os.path.exists(self.config_path):
config_default_file_path = pkg_resources.resource_filename(
if not os.path.exists(self.config_file):
config_default_file = pkg_resources.resource_filename(
__name__,
'config_default.yaml')
try:
with open(config_default_file_path, 'r') as f:
config_template = yaml.load(f, Loader=yaml.FullLoader)
with open(self.config_path, 'w') as f:
yaml.dump(config_template, f)
with open(config_default_file, 'r') as f:
config_default = yaml.load(f, Loader=yaml.FullLoader)
with open(self.config_file, 'w') as f:
yaml.dump(config_default, f)
except Exception as e:
print(f"Error creating configuration file: {e}")
exit(1)
@ -77,7 +84,7 @@ class Config():
"""
# Load it
try:
with open(self.config_path, 'r') as f:
with open(self.config_file, 'r') as f:
self.config = yaml.load(f, Loader=yaml.FullLoader)
except Exception as e:
print(f"Error loading configuration file: {e}")

View File

@ -174,7 +174,7 @@ class Console():
self._write_output(f"Heard stations not available.")
def help(self, args):
self.parser.parser.print_help()
self.parser.print_help()
def list(self, args):
"""List all public messages and private messages to the caller."""
@ -267,7 +267,7 @@ class Console():
# Parse the BBS interactive commands for the rest of time
for line in sys.stdin:
try:
args = self.parser.parser.parse_args(line.split())
args = self.parser.parse_args(line.split())
args.func(args)
except Exception:
if self.config.debug:

View File

@ -21,15 +21,12 @@ import argparse
from rsbbs.commands import Commands
# We want to override the error and exit methods of ArgumentParser
# to prevent it exiting unexpectedly or spewing error data over the air
class BBSArgumentParser(argparse.ArgumentParser):
# Override the error handler to prevent exiting on error
# Override the error handler to prevent spewing error cruft over the air
# def error(self, message):
# print(message)
# raise
# Override the exit handler to prevent disconnecting unexpectedly
def exit(self, arg1, arg2):
pass
@ -37,9 +34,17 @@ class BBSArgumentParser(argparse.ArgumentParser):
class Parser(BBSArgumentParser):
def __init__(self, commands: Commands):
self.init_parser(commands)
self._init_parser(commands)
def init_parser(self, commands):
# The only thing anyone should ever access from Parser is its parser
# attribute, so let's save everyone a step.
def __getattribute__(self, attr):
try:
return object.__getattribute__(self, attr)
except AttributeError:
return getattr(self.parser, attr)
def _init_parser(self, commands):
# Root parser for BBS commands
self.parser = BBSArgumentParser(
description='BBS Main Menu',
@ -55,11 +60,14 @@ class Parser(BBSArgumentParser):
# Loop through the commands and add each as a subparser
for name, aliases, help_msg, func, arguments in commands.commands:
# Add the command attributes
subparser = subparsers.add_parser(
name,
aliases=aliases,
help=help_msg,
)
# Add the command parameters
for arg_name, options in arguments.items():
subparser.add_argument(arg_name, **options)
# Trick to pass a function to call when the command is entered
subparser.set_defaults(func=func)

View File

@ -30,7 +30,7 @@ from rsbbs.parser import Parser
def main():
# Parse and handle the system invocation arguments
sysv_parser = argparse.ArgumentParser(
argv_parser = argparse.ArgumentParser(
description=("The BBS for ax.25 and packet radio "
"that is really simple."))
@ -45,23 +45,23 @@ def main():
'Path to config.yaml file', False],
]
for arg in args_list:
sysv_parser.add_argument(
argv_parser.add_argument(
arg[0], arg[1], action=arg[2], default=arg[3], dest=arg[4],
help=arg[5], required=arg[6])
# Version arg is special:
sysv_parser.add_argument(
argv_parser.add_argument(
'-v', '--version',
action='version',
version=f"{sysv_parser.prog} version {__version__}")
version=f"{argv_parser.prog} version {__version__}")
# Parse the args from the system
sysv_args = sysv_parser.parse_args(sys.argv[1:])
argv_args = argv_parser.parse_args(sys.argv[1:])
# Load configuration
config = Config(
app_name='rsbbs',
args=sysv_args)
args=argv_args)
# Init the contoller
controller = Controller(config)