Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Drop uproot3 for uproot4 for writing ROOT files #1567

Merged
merged 17 commits into from
Aug 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions .github/workflows/dependencies-head.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,31 +63,6 @@ jobs:
run: |
python -m pytest -r sx --ignore tests/benchmarks/ --ignore tests/contrib --ignore tests/test_notebooks.py

uproot3:

runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
python-version: [3.8]

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip --no-cache-dir --quiet install --upgrade --editable .[test]
python -m pip uninstall --yes uproot3
python -m pip install --upgrade git+git://github.com/scikit-hep/uproot3.git
python -m pip list
- name: Test with pytest
run: |
python -m pytest -r sx --ignore tests/benchmarks/ --ignore tests/contrib --ignore tests/test_notebooks.py

uproot4:

runs-on: ${{ matrix.os }}
Expand Down
3 changes: 1 addition & 2 deletions lower-bound-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ jsonschema==3.0.0
jsonpatch==1.15
pyyaml==5.1
# xmlio
uproot3==3.14.1
uproot==4.0.0
uproot==4.1.1
# minuit
iminuit==2.4.0
# tensorflow
Expand Down
5 changes: 1 addition & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
],
'torch': ['torch~=1.8'],
'jax': ['jax~=0.2.8', 'jaxlib~=0.1.58,!=0.1.68'], # c.f. Issue 1501
'xmlio': [
'uproot3>=3.14.1',
'uproot~=4.0',
], # uproot3 required until writing to ROOT supported in uproot4
'xmlio': ['uproot>=4.1.1'],
'minuit': ['iminuit>=2.4'],
}
extras_require['backends'] = sorted(
Expand Down
22 changes: 10 additions & 12 deletions src/pyhf/writexml.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
import xml.etree.ElementTree as ET
import numpy as np

# TODO: Move to uproot4 when ROOT file writing is supported
import uproot3 as uproot
from uproot3_methods.classes import TH1
import uproot

from pyhf.mixins import _ChannelSummaryMixin

Expand Down Expand Up @@ -47,12 +45,12 @@ def _make_hist_name(channel, sample, modifier='', prefix='hist', suffix=''):
return f"{prefix}{middle}{suffix}"


def _export_root_histogram(histname, data):
hist = TH1.from_numpy((np.asarray(data), np.arange(len(data) + 1)))
hist._fName = histname
matthewfeickert marked this conversation as resolved.
Show resolved Hide resolved
if histname in _ROOT_DATA_FILE:
raise KeyError(f"Duplicate key {histname} being written.")
_ROOT_DATA_FILE[histname] = hist
def _export_root_histogram(hist_name, data):
if hist_name in _ROOT_DATA_FILE:
raise KeyError(f"Duplicate key {hist_name} being written.")
_ROOT_DATA_FILE[hist_name] = uproot.to_writable(
(np.asarray(data), np.arange(len(data) + 1))
)


# https://stackoverflow.com/a/4590052
Expand Down Expand Up @@ -236,7 +234,7 @@ def build_sample(spec, samplespec, channelname):
attrs = {
'Name': samplespec['name'],
'HistoName': histname,
'InputFile': _ROOT_DATA_FILE._path,
'InputFile': _ROOT_DATA_FILE.file_path,
'NormalizeByTheory': 'False',
}
sample = ET.Element('Sample', **attrs)
Expand All @@ -255,7 +253,7 @@ def build_sample(spec, samplespec, channelname):

def build_data(obsspec, channelname):
histname = _make_hist_name(channelname, 'data')
data = ET.Element('Data', HistoName=histname, InputFile=_ROOT_DATA_FILE._path)
data = ET.Element('Data', HistoName=histname, InputFile=_ROOT_DATA_FILE.file_path)

observation = next((obs for obs in obsspec if obs['name'] == channelname), None)
_export_root_histogram(histname, observation['data'])
Expand All @@ -264,7 +262,7 @@ def build_data(obsspec, channelname):

def build_channel(spec, channelspec, obsspec):
channel = ET.Element(
'Channel', Name=channelspec['name'], InputFile=_ROOT_DATA_FILE._path
'Channel', Name=channelspec['name'], InputFile=_ROOT_DATA_FILE.file_path
)
if obsspec:
data = build_data(obsspec, channelspec['name'])
Expand Down
30 changes: 25 additions & 5 deletions tests/test_export.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import pyhf
import pyhf.writexml
import pytest
import json
import xml.etree.ElementTree as ET
import logging
import xml.etree.ElementTree as ET

import pytest
import uproot

import pyhf
import pyhf.writexml


def spec_staterror():
Expand Down Expand Up @@ -392,9 +395,26 @@ def test_export_data(mocker):
assert pyhf.writexml._ROOT_DATA_FILE.__setitem__.called


def test_export_root_histogram(mocker, tmp_path):
"""
Test that pyhf.writexml._export_root_histogram writes out a histogram
in the manner that uproot is expecting and verifies this by reading
the serialized file
"""
mocker.patch("pyhf.writexml._ROOT_DATA_FILE", {})
pyhf.writexml._export_root_histogram("hist", [0, 1, 2, 3, 4, 5, 6, 7, 8])

with uproot.recreate(tmp_path.joinpath("test_export_root_histogram.root")) as file:
file["hist"] = pyhf.writexml._ROOT_DATA_FILE["hist"]

with uproot.open(tmp_path.joinpath("test_export_root_histogram.root")) as file:
assert file["hist"].values().tolist() == [0, 1, 2, 3, 4, 5, 6, 7, 8]
assert file["hist"].axis().edges().tolist() == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
assert file["hist"].name == "hist"


def test_export_duplicate_hist_name(mocker):
mocker.patch('pyhf.writexml._ROOT_DATA_FILE', new={'duplicate_name': True})
mocker.patch.object(pyhf.writexml, 'TH1')

with pytest.raises(KeyError):
pyhf.writexml._export_root_histogram('duplicate_name', [0, 1, 2])
Expand Down