From bae69c1645d8dad2e9190f485392f6eb8b9d9e90 Mon Sep 17 00:00:00 2001
From: Karim Ahmed <karim.ahmed@xfel.eu>
Date: Wed, 10 Jun 2020 16:46:04 +0200
Subject: [PATCH] expose karabo-da

---
 webservice/update_config.py | 119 +++++++++++++++++++++++-------------
 webservice/webservice.py    |   4 +-
 2 files changed, 77 insertions(+), 46 deletions(-)

diff --git a/webservice/update_config.py b/webservice/update_config.py
index 01fecad56..be00c979c 100644
--- a/webservice/update_config.py
+++ b/webservice/update_config.py
@@ -8,21 +8,30 @@ import zmq
 
 # Defining available options
 agipd_options = {
-    "force-hg-if-below": float,
-    "rel-gain": bool,
-    "xray-gain": bool,
-    "blc-noise": bool,
-    "blc-stripes": bool,
-    "blc-set-min": bool,
-    "dont-zero-nans": bool,
-    "dont-zero-orange": bool,
-    "max-pulses": list,
-    "calfile": str
+        "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,
-   "MID_DET_AGIPD1M-1": agipd_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(
@@ -32,8 +41,8 @@ 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.')
+                           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 '
@@ -55,21 +64,38 @@ bool_keys = []
 
 # Avoid erros when karabo_id not yet given through the command line.
 if karabo_id is not None:
-    for det, val in available_options[karabo_id].items():
-        if val == bool:
+    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]['no-{}'.format(b)] = bool
-
-    for option, typ in available_options[karabo_id].items():
-        if typ == list:
-            nargs = '+'
-        else:
-            nargs = None
-
-        parser.add_argument(f"--{option}", type=typ, nargs=nargs,
-                            help=f"Type: {typ.__name__}".upper())
+        available_options[karabo_id][0]['no-{}'.format(b)] = {'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.')
@@ -90,30 +116,35 @@ else:
 proposal = args['proposal']
 cycle = args['cycle']
 
-if task is None or instrument is None or proposal is None or cycle is None:
+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("_", "-")
-    if key in available_options[karabo_id] and value is not None:
-
-        if isinstance(value, list):
-            for v in value:
-                value[value.index(v)] = ''.join(v)
-
-        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 = '""'
-
-        new_conf[task][instrument][karabo_id][key] = value
+    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)
 
diff --git a/webservice/webservice.py b/webservice/webservice.py
index 1e3e638f2..59b1f55f7 100644
--- a/webservice/webservice.py
+++ b/webservice/webservice.py
@@ -130,7 +130,7 @@ def merge(source, destination):
     for key, value in source.items():
         if isinstance(value, dict):
             # check if destination (e.g. karabo-id) has none value
-            if destination[key] is None:
+            if key in destination.keys() and destination[key] is None:
                 destination[key] = {}
             # get node or create one
             node = destination.setdefault(key, {})
@@ -785,7 +785,7 @@ async def server_runner(config, mode):
                             logging.error(Errors.MDC_RESPONSE.format(response))
                         return
                 except Exception as corr_e:
-                    logging.error(f"Error while correction: {str(corr_e)}")
+                    logging.error(f"Error during correction: {str(corr_e)}")
                     response = mdc.update_run_api(rid, {
                         'flg_cal_data_status': 'NA',
                         'cal_pipeline_reply': Errors.REQUEST_FAILED})
-- 
GitLab