Skip to content
Snippets Groups Projects
update_config.py 5.98 KiB
import argparse
import json
import sys

import yaml
import zmq

# Defining available options
agipd_options = {
        "force-hg-if-below": {'typ': int},
        "rel-gain": {'typ': bool},
        "xray-gain": {'typ': bool},
        "blc-noise": {'typ': bool},
        "blc-set-min": {'typ': bool},
        "dont-zero-nans": {'typ': bool},
        "dont-zero-orange": {'typ': bool},
        "max-pulses": {'typ': list,
                       'msg': "Range list of maximum pulse indices "
                              "(--max-pulses start end step). "
                              "3 max input elements. "},
        "calfile": {'typ': str},
    }

data_mapping = {
        "karabo-da": {'typ': list,
                      'choices': ["AGIPD{:02d}".format(i) for i in range(16)],
                      'msg': "Choices: [AGIPD00 ... AGIPD15]. "}
}

available_options = {
    "SPB_DET_AGIPD1M-1": [agipd_options, data_mapping],
    "MID_DET_AGIPD1M-1": [agipd_options, data_mapping]
}

formatter = lambda prog: argparse.HelpFormatter(prog, max_help_position=52)
parser = argparse.ArgumentParser(
    description='Request update of configuration', formatter_class=formatter)
required_args = parser.add_argument_group('required arguments')
required_args.add_argument('--karabo-id', type=str,
                           choices=['SPB_DET_AGIPD1M-1',
                                    'MID_DET_AGIPD1M-1'])
required_args.add_argument('--proposal', type=str,
                           help='The proposal number, without leading p, '
                                'but with leading zeros.')
required_args.add_argument('--cycle', type=str, help='The facility cycle.')
parser.add_argument('--apply', action='store_true',
                    help='Apply and push the requested '
                         'configuration update to the git.')
# remove help calls as they will cause the argument parser to exit
add_help = False
if "-h" in sys.argv:
    sys.argv.remove("-h")
    add_help = True
if "--help" in sys.argv:
    sys.argv.remove("--help")
    add_help = True

known, remaining = parser.parse_known_args()
args = vars(known)
karabo_id = args["karabo_id"]
bool_keys = []


# Avoid erros when karabo_id not yet given through the command line.
if karabo_id is not None:
    # adding "no" bools to available options
    for det, val in available_options[karabo_id][0].items():
        if val['typ'] == bool:
            bool_keys.append(det)

    for b in bool_keys:
        available_options[karabo_id][0]['no-{}'.format(det)] = {'typ': bool}

    for exposed_options in available_options[karabo_id]:
        for option, info in exposed_options.items():
            metavar = None
            if info['typ'] == list:
                nargs = '+'
                typ = str
                action = 'append'
                # Avoid having a big line of choices in the help message.
                if 'choices' in info.keys():
                    metavar = option.upper()
            else:
                action = None
                nargs = None
                typ = info['typ']
            # Add help messages
            help_msg = ""
            if 'msg' in info.keys():
                help_msg += info['msg']
            if 'choices' in info.keys():
                choices = info['choices']
            else:
                choices = None
            help_msg += f"Type: {info['typ'].__name__} ".upper()
            parser.add_argument(f"--{option}", type=typ, action=action,
                                metavar=metavar, nargs=nargs, choices=choices,
                                help=help_msg)

parser.add_argument('--instrument', type=str, choices=["CALLAB"],
                    help='This is only used for testing purposes.')

if add_help:
    sys.argv.append("--help")

args = vars(parser.parse_args())

task = "correct"
# check if instrument is not given from CLI (e.g. CALLAB)
if args['instrument'] is None:
    # extract instrument from karabo_id
    instrument = karabo_id.split("_")[0]
else:
    instrument = args['instrument']

proposal = args['proposal']
cycle = args['cycle']

if instrument is None or proposal is None or cycle is None:
    print("Need to define all fields")
    exit()

new_conf = {task: {instrument: {karabo_id: {}}}}
for key, value in args.items():
    key = key.replace("_", "-")
    for exposed_options in available_options[karabo_id]:
        if key in exposed_options and value is not None:

            if isinstance(value, list):
                value = value[0]
            # convert no arguments to bool false
            if 'no-' in key and isinstance(value, bool):
                if key not in bool_keys:
                    new_conf[task][instrument][karabo_id][key.replace('no-', '')] = False  # noqa
                # avoid saving the "no-"key into the updated config
                continue
            # Assure adding an empty string for new empty
            # str. updates (e.g. calfile)
            if isinstance(key, str) and (value == '' or value == ' '):
                value = '""'
            # checking if data-mapping was updated.
            if key in data_mapping.keys():
                if 'data-mapping' not in new_conf.keys():
                    new_conf['data-mapping'] = {karabo_id: {key: {}}}
                new_conf['data-mapping'][karabo_id][key] = value
            else:
                new_conf[task][instrument][karabo_id][key] = value

pyaml = yaml.dump(new_conf, default_flow_style=False)

if not args["apply"]:
    print("\n")
    print("-" * 80)
    print("THIS IS A DRY RUN ONLY, NO CHANGES ARE MADE")
    print("\n")
    print("-" * 80)

print(f"Sending the following update: \n {pyaml}")
print("-" * 80)
con = zmq.Context()
socket = con.socket(zmq.REQ)
con = socket.connect("tcp://max-exfl016:5555")
msg = "','".join(["update_conf", "SASEX", args["karabo_id"],
                  instrument, args["cycle"], args["proposal"],
                  json.dumps(new_conf), str(args["apply"])])
socket.send("['{}']".format(msg).encode())
resp = socket.recv_multipart()[0]
print("Configuration now in place is:")
print(resp.decode())