Repository: scikit-hep/pyhf

Issue:
Config parsing trips on spaces?
# Description

@elskorda has a workspace where the POI name stored in the JSON ends up being `'SigXsecOverSM '` (notice the space). This seems to be a bug in our parsing (related to eventually supporting multi pos with space-separated names)

```
<!DOCTYPE Combination  SYSTEM 'HistFactorySchema.dtd'>

<Combination OutputFilePrefix="output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/output">

<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DSR_BMax200_BMin150_incFat1_Y2015_T2_J2_L0_incJet1_Fat0.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DSR_BMax350_BMin200_incFat1_Y2015_T2_J2_L0_incJet1_Fat0.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DSR_BMax500_BMin350_incFat1_Y2015_T2_J2_L0_incJet1_Fat0.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DSR_BMax750_BMin500_incFat1_Y2015_T20_J0_L0_incJet1_Fat1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DSR_BMin750_incFat1_Y2015_T20_J0_L0_incJet1_Fat1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DSR_BMax200_BMin150_incFat1_Fat0_T3_Y2015_incTag1_J2_L0_incJet1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DSR_BMax350_BMin200_incFat1_Fat0_T3_Y2015_incTag1_J2_L0_incJet1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DSR_BMax500_BMin350_incFat1_Fat0_T3_Y2015_incTag1_J2_L0_incJet1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DSR_BMin500_incFat1_Fat1_T21_Y2015_incTag1_J0_L0_incJet1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distCharge_DCR1_BMax200_BMin150_incFat1_Y2015_T2_J2_L1_incJet1_Fat0.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distCharge_DCR1_BMax350_BMin200_incFat1_Y2015_T2_J2_L1_incJet1_Fat0.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distCharge_DCR1_BMax500_BMin350_incFat1_Y2015_T2_J2_L1_incJet1_Fat0.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distCharge_DCR1_BMin500_incFat1_Y2015_T20_J0_L1_incJet1_Fat1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distCharge_DCR1_BMax200_BMin150_incFat1_Fat0_T3_Y2015_incTag1_J2_L1_incJet1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distCharge_DCR1_BMax350_BMin200_incFat1_Fat0_T3_Y2015_incTag1_J2_L1_incJet1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distCharge_DCR1_BMax500_BMin350_incFat1_Fat0_T3_Y2015_incTag1_J2_L1_incJet1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distCharge_DCR1_BMin500_incFat1_Fat1_T21_Y2015_incTag1_J0_L1_incJet1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DCR2_BMax200_BMin150_incFat1_Y2015_T2_J2_L2_incJet1_Fat0.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DCR2_BMax350_BMin200_incFat1_Y2015_T2_J2_L2_incJet1_Fat0.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DCR2_BMax500_BMin350_incFat1_Y2015_T2_J2_L2_incJet1_Fat0.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DCR2_BMin500_incFat1_Y2015_T20_J0_L2_incJet1_Fat1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DCR2_BMax200_BMin150_incFat1_Fat0_T3_Y2015_incTag1_J2_L2_incJet1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DCR2_BMax350_BMin200_incFat1_Fat0_T3_Y2015_incTag1_J2_L2_incJet1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DCR2_BMax500_BMin350_incFat1_Fat0_T3_Y2015_incTag1_J2_L2_incJet1.xml</Input>
<Input>output/MonoHbb-00-13-00-Paper-ExtendedGrid.monoH_1300_unblinded/xml/1000/Region_distmBB_DCR2_BMin500_incFat1_Fat1_T21_Y2015_incTag1_J0_L2_incJet1.xml</Input>

<Measurement Name="VH" Lumi="1" LumiRelErr="0.0001" ExportOnly="True">
<POI>SigXsecOverSM </POI>
<ParamSetting Const="True">Lumi </ParamSetting>
</Measurement>
</Combination>
```




Discussion:
> This seems to be a bug in our parsing (related to eventually supporting multi pos with space-separated names)

What's the actual error? Does it just fail or does it do just create nonsense?
NB: the same is true for parsing parameter configs



Resolving patch:
diff --git a/src/pyhf/readxml.py b/src/pyhf/readxml.py
--- a/src/pyhf/readxml.py
+++ b/src/pyhf/readxml.py
@@ -266,7 +266,7 @@ def process_measurements(toplvl, other_parameter_configs=None):
         result = {
             'name': x.attrib['Name'],
             'config': {
-                'poi': x.findall('POI')[0].text,
+                'poi': x.findall('POI')[0].text.strip(),
                 'parameters': [
                     {
                         'name': 'lumi',
@@ -289,7 +289,7 @@ def process_measurements(toplvl, other_parameter_configs=None):
 
             # might be specifying multiple parameters in the same ParamSetting
             if param.text:
-                for param_name in param.text.split(' '):
+                for param_name in param.text.strip().split(' '):
                     param_name = utils.remove_prefix(param_name, 'alpha_')
                     if param_name.startswith('gamma_') and re.search(
                         r'^gamma_.+_\d+$', param_name


Test patch:
diff --git a/tests/test_import.py b/tests/test_import.py
--- a/tests/test_import.py
+++ b/tests/test_import.py
@@ -148,6 +148,31 @@ def test_import_measurements():
     assert lumi_param_config['sigmas'] == [0.1]
 
 
+@pytest.mark.parametrize("const", ['False', 'True'])
+def test_spaces_in_measurement_config(const):
+    toplvl = ET.Element("Combination")
+    meas = ET.Element(
+        "Measurement",
+        Name='NormalMeasurement',
+        Lumi=str(1.0),
+        LumiRelErr=str(0.017),
+        ExportOnly=str(True),
+    )
+    poiel = ET.Element('POI')
+    poiel.text = 'mu_SIG '  # space
+    meas.append(poiel)
+
+    setting = ET.Element('ParamSetting', Const=const)
+    setting.text = ' '.join(['Lumi', 'alpha_mu_both']) + ' '  # spacces
+    meas.append(setting)
+
+    toplvl.append(meas)
+
+    meas_json = pyhf.readxml.process_measurements(toplvl)[0]
+    assert meas_json['config']['poi'] == 'mu_SIG'
+    assert [x['name'] for x in meas_json['config']['parameters']] == ['lumi', 'mu_both']
+
+
 @pytest.mark.parametrize("const", ['False', 'True'])
 def test_import_measurement_gamma_bins(const):
     toplvl = ET.Element("Combination")