From c9f28dba91502e287e558add75e6b42c89c6263e Mon Sep 17 00:00:00 2001
From: Philipp Schmidt <philipp.schmidt@xfel.eu>
Date: Tue, 22 Aug 2023 09:42:56 +0200
Subject: [PATCH] Add automatic detection of cycle if omitted in update_config
 script

---
 tests/test_update_config.py | 21 ++++++++++++++++++++-
 webservice/update_config.py | 33 ++++++++++++++++++++++++---------
 2 files changed, 44 insertions(+), 10 deletions(-)

diff --git a/tests/test_update_config.py b/tests/test_update_config.py
index 6e319f679..ac8e6a026 100644
--- a/tests/test_update_config.py
+++ b/tests/test_update_config.py
@@ -9,6 +9,7 @@ import yaml
 import zmq
 
 from webservice.update_config import (
+    _find_cycle,
     _add_available_configs_to_arg_parser,
     _create_new_config_from_args_input,
     main,
@@ -40,7 +41,7 @@ def test_main_sys_exit(capsys):
         with pytest.raises(SystemExit):
             main()
         out, _ = capsys.readouterr()
-    assert out == "Need to define all fields\n"
+    assert out == "Need to define all required fields\n"
 
 
 EXPECTED_ZMQ_REQ = [
@@ -85,6 +86,7 @@ def test_main(capsys):
 
 EXPECTED_CONF = [
     {
+        'common-mode': {'type': bool},
         'force-hg-if-below': {'type': int},
         'rel-gain': {'type': bool},
         'xray-gain': {'type': bool},
@@ -99,6 +101,7 @@ EXPECTED_CONF = [
         'use-litframe-finder': {'type': str},
         'litframe-device-id': {'type': str},
         'energy-threshold': {'type': int},
+        'no-common-mode': {'type': bool},
         'no-rel-gain': {'type': bool},
         'no-xray-gain': {'type': bool},
         'no-blc-noise': {'type': bool},
@@ -174,3 +177,19 @@ def test_create_new_config_from_args_input(instrument, args, expected):
         available_conf=EXPECTED_CONF,
     )
     assert new_conf == expected
+
+
+def test_find_cycle(tmp_path):
+    proposal_path = tmp_path / 'CALLAB' / '202301' / 'p002003'
+    proposal_path.mkdir(parents=True, exist_ok=True)
+
+    assert _find_cycle('2003', tmp_path) == '202301'
+    assert _find_cycle('002003', tmp_path) == '202301'
+
+    with pytest.raises(ValueError):
+        # Not existing proposal.
+        _find_cycle('2004', tmp_path)
+
+    with pytest.raises(ValueError):
+        # Not a number.
+        _find_cycle('p2004', tmp_path)
diff --git a/webservice/update_config.py b/webservice/update_config.py
index 23a343a8b..acfbd2c05 100755
--- a/webservice/update_config.py
+++ b/webservice/update_config.py
@@ -1,6 +1,7 @@
 #!/usr/bin/env python3
 
 
+from pathlib import Path
 import argparse
 import json
 import sys
@@ -113,8 +114,9 @@ required_args.add_argument(
     choices=list(AVAILABLE_DETECTORS.keys()))
 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.')
+    help='The proposal number, without leading p, but with leading zeros. ')
+required_args.add_argument('--cycle', type=str, help='The facility cycle, '
+                           'detected automatically if omitted')
 
 action_group = required_args.add_mutually_exclusive_group()
 action_group.add_argument(
@@ -143,6 +145,21 @@ parser.add_argument(
 )
 
 
+def _find_cycle(proposal: str, exp_root: Path = Path('/gpfs/exfel/exp')) -> str:
+    try:
+        proposal_no = int(proposal)
+    except ValueError:
+        raise ValueError('proposal number cannot be converted to a number')
+
+    # /gpfs/exfel/exp/<instrument>/<cycle>/p<proposal>/
+    proposal_path = next(exp_root.glob(f'*/*/p{proposal_no:06d}'), None)
+
+    if proposal_path is None:
+        raise ValueError('could not locate proposal on GPFS')
+
+    return proposal_path.parts[-2]
+
+
 def _add_available_configs_to_arg_parser(karabo_id: str, action: str):
     """Add the available configuration for the selected detector
     to the argument parser.
@@ -265,13 +282,11 @@ def main():
 
     args = vars(parser.parse_args(argv))
 
-    if (
-        instrument is None or
-        proposal is None or
-        cycle is None
-    ):
-        print("Need to define all fields")
+    if instrument is None or proposal is None:
+        print("Need to define all required fields")
         sys.exit(1)
+    elif cycle is None:
+        cycle = _find_cycle(proposal)
 
     new_conf = _create_new_config_from_args_input(
         instrument=instrument,
@@ -297,7 +312,7 @@ def main():
         "SASEX",
         args["karabo_id"],
         instrument,
-        args["cycle"],
+        cycle,
         args["proposal"],
         json.dumps(new_conf),
         str(args["apply"]),
-- 
GitLab