Repository: scikit-hep/pyhf

Issue:
Use of `del` for staterror in writexml necessary?
In PR #435 the use of `del` was added in 

https://github.com/scikit-hep/pyhf/blob/e3d879f3e4982ac629bec7bf92d78b00025e52dc/src/pyhf/writexml.py#L186-L191

I assume because later on in the PR it mentions

https://github.com/scikit-hep/pyhf/blob/e3d879f3e4982ac629bec7bf92d78b00025e52dc/tests/test_export.py#L257-L259

However, if you remove that `del` statement

```
pytest -sx tests/test_export.py -k test_export_modifier
```

still passes.

Do we still need it? @kratsg have any thoughts here?


Discussion:
It's needed -- https://github.com/scikit-hep/pyhf/blob/569f51257c6a895508f9c026bd61a2e723cb339c/src/pyhf/schemas/HistFactorySchema.dtd#L105-L112

We do need a test to assert that the exported staterror XML does not have a `Name` attribute. HiFa doesn't support staterror having names.

Resolving patch:
diff --git a/src/pyhf/writexml.py b/src/pyhf/writexml.py
--- a/src/pyhf/writexml.py
+++ b/src/pyhf/writexml.py
@@ -188,6 +188,7 @@ def build_modifier(spec, modifierspec, channelname, samplename, sampledata):
         attrs['HistoName'] = _make_hist_name(
             channelname, samplename, modifierspec['name']
         )
+        # must be deleted, HiFa XML specification does not support 'Name'
         del attrs['Name']
         # need to make this a relative uncertainty stored in ROOT file
         _export_root_histogram(


Test patch:
diff --git a/tests/test_export.py b/tests/test_export.py
--- a/tests/test_export.py
+++ b/tests/test_export.py
@@ -224,17 +224,17 @@ def test_export_measurement():
 
 
 @pytest.mark.parametrize(
-    "spec, has_root_data, attrs",
+    "spec, has_root_data, attrs, modtype",
     [
-        (spec_staterror(), True, ['Activate', 'HistoName']),
-        (spec_histosys(), True, ['HistoNameHigh', 'HistoNameLow']),
-        (spec_normsys(), False, ['High', 'Low']),
-        (spec_shapesys(), True, ['ConstraintType', 'HistoName']),
-        (spec_shapefactor(), False, []),
+        (spec_staterror(), True, ['Activate', 'HistoName'], 'staterror'),
+        (spec_histosys(), True, ['HistoNameHigh', 'HistoNameLow'], 'histosys'),
+        (spec_normsys(), False, ['High', 'Low'], 'normsys'),
+        (spec_shapesys(), True, ['ConstraintType', 'HistoName'], 'shapesys'),
+        (spec_shapefactor(), False, [], 'shapefactor'),
     ],
     ids=['staterror', 'histosys', 'normsys', 'shapesys', 'shapefactor'],
 )
-def test_export_modifier(mocker, caplog, spec, has_root_data, attrs):
+def test_export_modifier(mocker, caplog, spec, has_root_data, attrs, modtype):
     channelspec = spec['channels'][0]
     channelname = channelspec['name']
     samplespec = channelspec['samples'][1]
@@ -242,6 +242,8 @@ def test_export_modifier(mocker, caplog, spec, has_root_data, attrs):
     sampledata = samplespec['data']
     modifierspec = samplespec['modifiers'][0]
 
+    assert modifierspec['type'] == modtype
+
     mocker.patch('pyhf.writexml._ROOT_DATA_FILE')
 
     with caplog.at_level(logging.DEBUG, 'pyhf.writexml'):
@@ -255,7 +257,9 @@ def test_export_modifier(mocker, caplog, spec, has_root_data, attrs):
     assert "Skipping modifier" not in caplog.text
 
     # if the modifier is a staterror, it has no Name
-    if 'Name' in modifier.attrib:
+    if modtype == 'staterror':
+        assert 'Name' not in modifier.attrib
+    else:
         assert modifier.attrib['Name'] == modifierspec['name']
     assert all(attr in modifier.attrib for attr in attrs)
     assert pyhf.writexml._ROOT_DATA_FILE.__setitem__.called == has_root_data