diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 251d2767..b5605949 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -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"
@@ -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
@@ -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
@@ -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 }}
diff --git a/README.md b/README.md
index 6f9ba74e..4b716ce1 100644
--- a/README.md
+++ b/README.md
@@ -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)
-- [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)
## External dependencies
@@ -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.
\ No newline at end of file
diff --git a/docs/dev.rst b/docs/dev.rst
index 86e1f5f9..e3a5e1b5 100644
--- a/docs/dev.rst
+++ b/docs/dev.rst
@@ -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
++++++++++++++++++++++++
diff --git a/hepdata_lib/c_file_reader.py b/hepdata_lib/c_file_reader.py
index a07c7148..2c957e39 100644
--- a/hepdata_lib/c_file_reader.py
+++ b/hepdata_lib/c_file_reader.py
@@ -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
diff --git a/hepdata_lib/root_utils.py b/hepdata_lib/root_utils.py
index c6d0269a..ff1dd288 100644
--- a/hepdata_lib/root_utils.py
+++ b/hepdata_lib/root_utils.py
@@ -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:
diff --git a/pyproject.toml b/pyproject.toml
index 456e710a..afbb9505 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -14,3 +14,6 @@ addopts = [
]
log_cli_level = "info"
testpaths = "tests"
+markers = [
+ "needs_root: requires a ROOT installation"
+]
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 088f89d6..70911595 100644
--- a/setup.py
+++ b/setup.py
@@ -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']),
diff --git a/tests/test_cfilereader.py b/tests/test_cfilereader.py
index b77511f6..d19c47ab 100644
--- a/tests/test_cfilereader.py
+++ b/tests/test_cfilereader.py
@@ -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."""
diff --git a/tests/test_notebooks.py b/tests/test_notebooks.py
index 7783579a..b74b0dee 100644
--- a/tests/test_notebooks.py
+++ b/tests/test_notebooks.py
@@ -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)
@@ -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)
diff --git a/tests/test_rootfilereader.py b/tests/test_rootfilereader.py
index 4cd0c52c..23d1d947 100644
--- a/tests/test_rootfilereader.py
+++ b/tests/test_rootfilereader.py
@@ -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."""
diff --git a/tests/test_utilities.py b/tests/test_utilities.py
index eee8d9d4..21ebbb00 100644
--- a/tests/test_utilities.py
+++ b/tests/test_utilities.py
@@ -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