Skip to content

Commit

Permalink
Add try/except around ROOT import (#259)
Browse files Browse the repository at this point in the history
* Add try/except around ROOT import

* Print out an error message if ROOT cannot be imported.
* Add some explanation at the end of the README.md file.
* Correct a typo in the link to reading_scikithep_histogram.ipynb.

* Allow CI to run subset of tests without ROOT

* Add a custom marker to test functions requiring ROOT.
* Run subset of tests using "pytest -m 'not needs_root'".
  • Loading branch information
GraemeWatt authored Apr 11, 2024
1 parent db53815 commit 891d699
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 10 deletions.
29 changes: 26 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
root-version: ["6.24", "6.26", "6.28", "6.30"]
root-version: ["", "6.24", "6.26", "6.28", "6.30"]
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
exclude:
- root-version: "6.24"
Expand Down Expand Up @@ -55,6 +55,7 @@ jobs:
- uses: actions/checkout@v4

- name: Setup Micromamba environment
if: ${{ matrix.root-version }}
uses: mamba-org/setup-micromamba@v1
with:
environment-name: ci
Expand All @@ -68,7 +69,22 @@ jobs:
channels:
- conda-forge
- name: Setup Micromamba environment without ROOT
if: ${{ !matrix.root-version }}
uses: mamba-org/setup-micromamba@v1
with:
environment-name: ci
create-args: >-
python=${{ matrix.python-version }}
imagemagick
ghostscript
pip
condarc: |
channels:
- conda-forge
- name: ROOT info
if: ${{ matrix.root-version }}
run: |
root-config --version
root-config --python-version
Expand All @@ -94,23 +110,30 @@ jobs:

# Use python -m pytest to add current working dir as src/ dir layout not used
- name: Run pytest
if: ${{ matrix.root-version }}
run: |
python -m pytest tests
- name: Run pytest without ROOT
if: ${{ !matrix.root-version }}
run: |
python -m pytest tests -m 'not needs_root'
- name: Report coverage with Codecov
if: ${{ matrix.root-version }}
uses: codecov/codecov-action@v3
with:
files: ./coverage.xml
flags: unittests-${{ matrix.python-version }}

- name: Save notebooks
if: ${{ always() }}
if: ${{ always() && matrix.root-version }}
run: |
python -m jupyter kernelspec list
python -m jupyter nbconvert --ExecutePreprocessor.timeout=600 --ExecutePreprocessor.allow_errors=True --to html --execute examples/*.ipynb
- name: Upload notebooks
if: ${{ always() }}
if: ${{ always() && matrix.root-version }}
uses: actions/upload-artifact@v4
with:
name: notebooks-${{ matrix.root-version }}-${{ matrix.python-version }}-${{ matrix.os }} py3-${{ matrix.root-version }}-${{ matrix.python-version }}-${{ matrix.os }}
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ There are a few more examples available that can directly be run using the [bind
- [Reading TGraph and TGraphError from '.C' files](https://github.com/HEPData/hepdata_lib/blob/main/examples/read_c_file.ipynb)
[![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/HEPData/hepdata_lib/main?filepath=examples/read_c_file.ipynb)
<br/><br/>
- [Preparing scikit-hep histograms](https://github.com/HEPData/hepdata_lib/blob/main/examples/reading_scikithep_histogram.ipynb)
[![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/HEPData/hepdata_lib/main?filepath=examples/reading_scikihep_histogram.ipynb)
- [Preparing scikit-hep histograms](https://github.com/HEPData/hepdata_lib/blob/main/examples/reading_scikithep_histograms.ipynb)
[![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/HEPData/hepdata_lib/main?filepath=examples/reading_scikihep_histograms.ipynb)
<br/><br/>

## External dependencies
Expand All @@ -82,3 +82,8 @@ There are a few more examples available that can directly be run using the [bind
- [ImageMagick](https://www.imagemagick.org)

Make sure that you have `ROOT` in your `$PYTHONPATH` and that the `convert` command is available by adding its location to your `$PATH` if needed.

A ROOT installation is not strictly required if your input data is not in a ROOT format, for example, if
your input data is provided as text files or `scikit-hep/hist` histograms. Most of the `hepdata_lib`
functionality can be used without a ROOT installation, other than the `RootFileReader` and `CFileReader` classes,
and other functions of the `hepdata_lib.root_utils` module.
6 changes: 6 additions & 0 deletions docs/dev.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ To run the tests, move into the ``hepdata_lib`` directory while in your virtual

It is a good idea to run the tests manually to ensure that your changes do not cause any issues.

If you don't have a working ROOT installation, a subset of the tests can still be run without ROOT:

::

pytest tests -m "not needs_root"

Definition of test cases
++++++++++++++++++++++++

Expand Down
5 changes: 4 additions & 1 deletion hepdata_lib/c_file_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
import io
from array import array
from future.utils import raise_from
from ROOT import TGraph, TGraphErrors # pylint: disable=no-name-in-module
try:
from ROOT import TGraph, TGraphErrors # pylint: disable=no-name-in-module
except ImportError as e: # pragma: no cover
print(f'Cannot import ROOT: {str(e)}')
import hepdata_lib.root_utils as ru
from hepdata_lib.helpers import check_file_existence

Expand Down
5 changes: 4 additions & 1 deletion hepdata_lib/root_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import ctypes
from future.utils import raise_from
import numpy as np
import ROOT as r
try:
import ROOT as r
except ImportError as e: # pragma: no cover
print(f'Cannot import ROOT: {str(e)}')
from hepdata_lib.helpers import check_file_existence

class RootFileReader:
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ addopts = [
]
log_cli_level = "info"
testpaths = "tests"
markers = [
"needs_root: requires a ROOT installation"
]
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
],
keywords='HEPData physics OpenData',
packages=find_packages(exclude=['contrib', 'docs', 'tests']),
Expand Down
2 changes: 2 additions & 0 deletions tests/test_cfilereader.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
from unittest import TestCase
import os
import numpy as np
import pytest
from hepdata_lib.c_file_reader import CFileReader

@pytest.mark.needs_root
class TestCFileReader(TestCase):
"""Test the CFileReader class."""

Expand Down
8 changes: 8 additions & 0 deletions tests/test_notebooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def common_kwargs(tmpdir):
'cwd' : 'examples'
}

@pytest.mark.needs_root
def test_correlation(common_kwargs):# pylint: disable=redefined-outer-name
"""Tests examples/correlation.ipynb"""
pm.execute_notebook('examples/correlation.ipynb', **common_kwargs)
Expand All @@ -21,14 +22,21 @@ def test_getting_started(common_kwargs):# pylint: disable=redefined-outer-name
"""Tests examples/Getting_started.ipynb"""
pm.execute_notebook('examples/Getting_started.ipynb', **common_kwargs)

@pytest.mark.needs_root
def test_reading_histograms(common_kwargs):# pylint: disable=redefined-outer-name
"""Tests examples/reading_histograms.ipynb"""
pm.execute_notebook('examples/reading_histograms.ipynb', **common_kwargs)

@pytest.mark.needs_root
def test_combine_limits(common_kwargs):# pylint: disable=redefined-outer-name
"""Tests examples/combine_limits.ipynb"""
pm.execute_notebook('examples/combine_limits.ipynb', **common_kwargs)

@pytest.mark.needs_root
def test_c_file(common_kwargs):# pylint: disable=redefined-outer-name
"""Tests examples/read_c_file.ipynb"""
pm.execute_notebook('examples/read_c_file.ipynb', **common_kwargs)

def test_scikithep_histograms(common_kwargs):# pylint: disable=redefined-outer-name
"""Tests examples/reading_scikithep_histograms.ipynb"""
pm.execute_notebook('examples/reading_scikithep_histograms.ipynb', **common_kwargs)
7 changes: 6 additions & 1 deletion tests/test_rootfilereader.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@
import os
import ctypes
import numpy as np
import ROOT
import pytest
try:
import ROOT
except ImportError as e:
print(f'Cannot import ROOT: {str(e)}')
from hepdata_lib.root_utils import (RootFileReader, get_graph_points,
get_hist_1d_points, get_hist_2d_points)
from .test_utilities import float_compare, tuple_compare, histogram_compare_1d, make_tmp_root_file


@pytest.mark.needs_root
class TestRootFileReader(TestCase):
"""Test the RootFileReader class."""

Expand Down
6 changes: 4 additions & 2 deletions tests/test_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import os
import random
import string

import ROOT
try:
import ROOT
except ImportError as e:
print(f'Cannot import ROOT: {str(e)}')
from future.utils import raise_from


Expand Down

0 comments on commit 891d699

Please sign in to comment.