import os
import sys
import pathlib
import argparse
import configparser
import numpy as np
from collections import OrderedDict
from pathlib import Path
from algotom.util import log
LOGS_HOME = Path.home()/'logs'
CONFIG_FILE_NAME = os.path.join(str(pathlib.Path.home()), 'algotom.conf')
SECTIONS = OrderedDict()
SECTIONS['general'] = {
'config': {
'default': CONFIG_FILE_NAME,
'type': str,
'help': "File name of configuration",
'metavar': 'FILE'},
'logs-home': {
'default': LOGS_HOME,
'type': str,
'help': "Log file directory",
'metavar': 'FILE'},
'verbose': {
'default': True,
'help': 'Verbose output',
'action': 'store_true'}}
SECTIONS['explore'] = {
'file-path': {
'type': str,
'default': "D:/data/68067.nxs",
'help': "string"},
'output-base': {
'type': str,
'default': "D:/output/",
'help': "string"},
}
EXPLORE_PARAMS = ('explore', )
NICE_NAMES = ('General', 'Explore')
[docs]def get_config_name():
"""Get the command line --config option."""
name = CONFIG_FILE_NAME
for i, arg in enumerate(sys.argv):
if arg.startswith('--config'):
if arg == '--config':
return sys.argv[i + 1]
else:
name = sys.argv[i].split('--config')[1]
if name[0] == '=':
name = name[1:]
return name
return name
[docs]def parse_known_args(parser, subparser=False):
"""
Parse arguments from file and then override by the ones specified on the
command line. Use *parser* for parsing and is *subparser* is True take into
account that there is a value on the command line specifying the subparser.
"""
if len(sys.argv) > 1:
subparser_value = [sys.argv[1]] if subparser else []
config_values = config_to_list(config_name=get_config_name())
values = subparser_value + config_values + sys.argv[1:]
#print(subparser_value, config_values, values)
else:
values = ""
return parser.parse_known_args(values)[0]
[docs]def config_to_list(config_name=CONFIG_FILE_NAME):
"""
Read arguments from config file and convert them to a list of keys and
values as sys.argv does when they are specified on the command line.
*config_name* is the file name of the config file.
"""
result = []
config = configparser.ConfigParser()
if not config.read([config_name]):
return []
for section in SECTIONS:
for name, opts in ((n, o) for n, o in SECTIONS[section].items() if config.has_option(section, n)):
value = config.get(section, name)
if value != '' and value != 'None':
action = opts.get('action', None)
if action == 'store_true' and value == 'True':
# Only the key is on the command line for this action
result.append('--{}'.format(name))
if not action == 'store_true':
if opts.get('nargs', None) == '+':
result.append('--{}'.format(name))
result.extend((v.strip() for v in value.split(',')))
else:
result.append('--{}={}'.format(name, value))
return result
[docs]class Params(object):
def __init__(self, sections=()):
self.sections = sections + ('general', )
[docs] def add_parser_args(self, parser):
for section in self.sections:
for name in sorted(SECTIONS[section]):
opts = SECTIONS[section][name]
parser.add_argument('--{}'.format(name), **opts)
[docs] def add_arguments(self, parser):
self.add_parser_args(parser)
return parser
[docs] def get_defaults(self):
parser = argparse.ArgumentParser()
self.add_arguments(parser)
return parser.parse_args('')
[docs]def write(config_file, args=None, sections=None):
"""
Write *config_file* with values from *args* if they are specified,
otherwise use the defaults. If *sections* are specified, write values from
*args* only to those sections, use the defaults on the remaining ones.
"""
config = configparser.ConfigParser()
for section in SECTIONS:
config.add_section(section)
for name, opts in SECTIONS[section].items():
if args and sections and section in sections and hasattr(args, name.replace('-', '_')):
value = getattr(args, name.replace('-', '_'))
if isinstance(value, list):
# print(type(value), value)
value = ', '.join(value)
else:
value = opts['default'] if opts['default'] is not None else ''
prefix = '# ' if value == '' else ''
if name != 'config':
config.set(section, prefix + name, str(value))
with open(config_file, 'w') as f:
config.write(f)
[docs]def log_values(args):
"""Log all values set in the args namespace.
Arguments are grouped according to their section and logged alphabetically
using the DEBUG log level thus --verbose is required.
"""
args = args.__dict__
for section, name in zip(SECTIONS, NICE_NAMES):
entries = sorted((k for k in args.keys() if k in SECTIONS[section]))
if entries:
log.info(name)
for entry in entries:
value = args[entry] if args[entry] is not None else "-"
log.info(" {:<16} {}".format(entry, value))
[docs]def show_config(args):
"""Log all values set in the args namespace.
Arguments are grouped according to their section and logged alphabetically
using the DEBUG log level thus --verbose is required.
"""
args = args.__dict__
log.warning('algotom status start')
for section, name in zip(SECTIONS, NICE_NAMES):
entries = sorted((k for k in args.keys() if k.replace('_', '-') in SECTIONS[section]))
if entries:
for entry in entries:
value = args[entry] if args[entry] != None else "-"
log.info(" {:<16} {}".format(entry, value))
log.warning('algotom status end')