diff --git a/.github/workflows/pythontests.yml b/.github/workflows/pythontests.yml index facad41..0f2965d 100644 --- a/.github/workflows/pythontests.yml +++ b/.github/workflows/pythontests.yml @@ -20,20 +20,15 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies - run: | - python -m pip install --upgrade pip - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - python -m pip install -e .[test] + run: python -m pip install -e .[test,boost,root] - name: Install optional dependencies for tests - run: | - pip install boost-histogram uproot awkward pandas || true + run: pip install pandas - name: Run tests - run: | - python -m pytest -s tests/test.py + run: python -m pytest -s - name: Run CLI run: | histoprint tests/data/1D.txt diff --git a/histoprint/formatter.py b/histoprint/formatter.py index 72d223c..0de94c5 100644 --- a/histoprint/formatter.py +++ b/histoprint/formatter.py @@ -1,12 +1,14 @@ """Module for plotting Numpy-like 1D histograms to the terminal.""" import shutil +from collections.abc import Sequence from itertools import cycle from typing import Optional import click import numpy as np from uhi.numpy_plottable import ensure_plottable_histogram +from uhi.typing.plottable import PlottableHistogram DEFAULT_SYMBOLS = " |=/\\" COMPOSING_SYMBOLS = "/\\" @@ -560,12 +562,23 @@ def get_plottable_protocol_bin_edges(axis): def get_count_edges(hist): """Get bin contents and edges from a compatible histogram.""" - # Make sure we have a PlottableProtocol histogram - hist = ensure_plottable_histogram(hist) + # Support sequence of histograms + if isinstance(hist, Sequence) and isinstance(hist[0], PlottableHistogram): + count = np.stack([h.values() for h in hist]) + edges = get_plottable_protocol_bin_edges(hist[0].axes[0]) + for other_edges in ( + get_plottable_protocol_bin_edges(h.axes[0]) for h in hist[1:] + ): + np.testing.assert_allclose(edges, other_edges) + + else: + # Single histogram or (a,b,c, edges) tuple: + # Make sure we have a PlottableProtocol histogram + hist = ensure_plottable_histogram(hist) - # Use the PlottableProtocol - count = hist.values() - edges = get_plottable_protocol_bin_edges(hist.axes[0]) + # Use the PlottableProtocol + count = hist.values() + edges = get_plottable_protocol_bin_edges(hist.axes[0]) return count, edges diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 0000000..36a95d1 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,35 @@ +from __future__ import annotations + +import nox + +ALL_PYTHONS = ["3.6", "3.7", "3.8", "3.9"] + +nox.options.sessions = ["lint", "tests"] + + +@nox.session +def lint(session): + """ + Run the linter. + """ + session.install("pre-commit") + session.run("pre-commit", "run", "--all-files", *session.posargs) + + +@nox.session(python=ALL_PYTHONS, reuse_venv=True) +def tests(session): + """ + Run the unit and regular tests. + """ + session.install(".[test,boost,root]") + session.run("pytest", "-s", *session.posargs) + + +@nox.session +def build(session): + """ + Build an SDist and wheel. + """ + + session.install("build") + session.run("python", "-m", "build") diff --git a/pyproject.toml b/pyproject.toml index 864e347..5b740ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,12 +10,23 @@ build-backend = "setuptools.build_meta" [tool.setuptools_scm] write_to = "histoprint/version.py" +[tool.pytest.ini_options] +minversion = "6.0" +addopts = "-ra --strict-markers --showlocals --color=yes" +testpaths = [ + "tests", +] + [tool.isort] profile = "black" multi_line_output = 3 [tool.check-manifest] -ignore=[".pre-commit-config.yaml", "histoprint/version.py"] +ignore = [ + ".pre-commit-config.yaml", + "histoprint/version.py", + "noxfile.py", +] [tool.mypy] files = ["histoprint"] diff --git a/setup.cfg b/setup.cfg index 38612e9..77068ec 100644 --- a/setup.cfg +++ b/setup.cfg @@ -41,11 +41,13 @@ console_scripts = histoprint=histoprint.cli:histoprint [options.extras_require] +boost = + boost-histogram>=1.1 root = awkward>=1 uproot>=4 test = - pytest>=4.6 + pytest>=6.0 [flake8] ignore = E203, E231, E501, E722, W503, B950 diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/test.py b/tests/test_basic.py similarity index 59% rename from tests/test.py rename to tests/test_basic.py index 07ac111..afc2ca5 100644 --- a/tests/test.py +++ b/tests/test_basic.py @@ -1,4 +1,8 @@ +import io + import numpy as np +import pytest +from uhi.numpy_plottable import ensure_plottable_histogram import histoprint as hp @@ -59,10 +63,7 @@ def test_nan(): def test_boost(): """Test boost-histogram if it is available.""" - try: - import boost_histogram as bh - except ModuleNotFoundError: - return + bh = pytest.importorskip("boost_histogram") hist = bh.Histogram(bh.axis.Regular(20, -3, 3)) hist.fill(np.random.randn(1000)) @@ -70,14 +71,10 @@ def test_boost(): def test_uproot(): - """Test uproot hsitograms if it is available.""" + """Test uproot histograms if it is available.""" - try: - # Only used to check whether modules are available - import awkward # noqa: F401 - import uproot - except ModuleNotFoundError: - return + pytest.importorskip("awkward") + uproot = pytest.importorskip("uproot") with uproot.open("tests/data/histograms.root") as F: hist = F["one"] @@ -90,7 +87,34 @@ def test_uproot(): hp.print_hist(hist, title="uproot TH1") -if __name__ == "__main__": - test_hist() - test_boost() - test_uproot() +def test_stack(): + A = np.random.randn(1000) - 2 + B = np.random.randn(1000) + C = np.random.randn(1000) + 2 + D = np.random.randn(500) * 2 + + hp.text_hist(B) + hp.text_hist( + B, bins=[-5, -3, -2, -1, -0.5, 0, 0.5, 1, 2, 3, 5], title="Variable bin widths" + ) + + histA = np.histogram(A, bins=15, range=(-5, 5)) + histB = np.histogram(B, bins=15, range=(-5, 5)) + histC = np.histogram(C, bins=15, range=(-5, 5)) + histD = np.histogram(D, bins=15, range=(-5, 5)) + histAll = ([histA[0], histB[0], histC[0], histD[0]], histA[1]) + + hA = ensure_plottable_histogram(histA) + hB = ensure_plottable_histogram(histB) + hC = ensure_plottable_histogram(histC) + hD = ensure_plottable_histogram(histD) + + hist_stack = [hA, hB, hC, hD] + + out1 = io.StringIO() + out2 = io.StringIO() + + hp.print_hist(histAll, file=out1, title="Overlays", labels="ABCD") + hp.print_hist(hist_stack, file=out2, title="Overlays", labels="ABCD") + + assert out1.getvalue() == out2.getvalue()