Skip to content

Commit

Permalink
feat: boost-histogram 1.0 compatibility and typing updates (#204)
Browse files Browse the repository at this point in the history
* support and require boost-histogram>=1.0.0
* improved type checking via pre-commit
* added test for histogram properties
* skip mypy in CI for Python 3.7
  • Loading branch information
alexander-held authored Mar 22, 2021
1 parent 2911813 commit 076c529
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 20 deletions.
8 changes: 5 additions & 3 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ jobs:
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install .[test]
- name: Static code analysis with flake8 and mypy
- name: Static code analysis with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 src/cabinetry --select=E9,F63,F7,F82 --show-source
# check for additional issues flagged by flake8
flake8
# run mypy for type checking
mypy
- name: Type checking with mypy
if: matrix.python-version != 3.7
run: |
mypy # 3.7 not supported due to boost-histogram
- name: Format with Black
run: |
black --check --diff --verbose .
Expand Down
5 changes: 3 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ repos:
hooks:
- id: mypy
files: src/cabinetry
additional_dependencies: ["numpy>=1.20", "boost-histogram>=1.0.1"]
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.4
rev: 3.9.0
hooks:
- id: flake8
additional_dependencies: [flake8-bugbear, flake8-import-order, flake8-print]
- repo: https://github.com/asottile/pyupgrade
rev: v2.10.0
rev: v2.11.0
hooks:
- id: pyupgrade
args: ["--py37-plus"]
Expand Down
5 changes: 1 addition & 4 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ package_dir = =src
python_requires = >=3.7
install_requires =
pyhf[minuit]~=0.6.0 # API updates and iminuit v2 compatibility
boost_histogram~=0.11
boost_histogram>=1.0.0 # subclassing with family
awkward>=1.0 # new API
tabulate>=0.8.1 # multiline text

Expand Down Expand Up @@ -72,9 +72,6 @@ warn_unreachable = True
strict_equality = True
no_implicit_optional = True

[mypy-boost_histogram]
ignore_missing_imports = True

[mypy-uproot]
ignore_missing_imports = True

Expand Down
4 changes: 2 additions & 2 deletions src/cabinetry/contrib/histogram_creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,6 @@ def _bin_data(
"""
hist = bh.Histogram(bh.axis.Variable(bins), storage=bh.storage.Weight())
hist.fill(observables, weight=weights)
yields = hist.view().value
stdev = np.sqrt(hist.view().variance)
yields = hist.values()
stdev = np.sqrt(hist.variances()) # type: ignore
return yields, stdev
14 changes: 8 additions & 6 deletions src/cabinetry/histo.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
import boost_histogram as bh
import numpy as np

import cabinetry


log = logging.getLogger(__name__)


H = TypeVar("H", bound="Histogram")


class Histogram(bh.Histogram):
class Histogram(bh.Histogram, family=cabinetry):
"""Holds histogram information, extends boost_histogram.Histogram."""

@classmethod
Expand Down Expand Up @@ -127,7 +129,7 @@ def yields(self) -> np.ndarray:
Returns:
numpy.ndarray: yields per bin
"""
return self.view().value
return self.values()

@yields.setter
def yields(self, value: np.ndarray) -> None:
Expand All @@ -136,7 +138,7 @@ def yields(self, value: np.ndarray) -> None:
Args:
value (np.ndarray): yields to set
"""
self.view().value = value
self.view().value = value # type: ignore

@property
def stdev(self) -> np.ndarray:
Expand All @@ -145,7 +147,7 @@ def stdev(self) -> np.ndarray:
Returns:
numpy.ndarray: stat. uncertainty per bin
"""
return np.sqrt(self.view().variance)
return np.sqrt(self.variances()) # type: ignore

@stdev.setter
def stdev(self, value: np.ndarray) -> None:
Expand All @@ -154,7 +156,7 @@ def stdev(self, value: np.ndarray) -> None:
Args:
value (numpy.ndarray): the standard deviation
"""
self.view().variance = value ** 2
self.view().variance = value ** 2 # type: ignore

@property
def bins(self) -> np.ndarray:
Expand Down Expand Up @@ -229,7 +231,7 @@ def normalize_to_yield(self, reference_histogram: H) -> float:
current_integrated_yield = sum(self.yields)
normalization_ratio = current_integrated_yield / target_integrated_yield
# update integrated yield to match target
self.view().value /= normalization_ratio
self.view().value /= normalization_ratio # type: ignore
return normalization_ratio


Expand Down
4 changes: 2 additions & 2 deletions src/cabinetry/route.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def register_template_builder(
"""
return self._register_processor(
self.template_builders, region_name, sample_name, systematic_name, template
)
) # type: ignore

@staticmethod
def _find_match(
Expand Down Expand Up @@ -217,7 +217,7 @@ def _find_template_builder_match(

if match is not None:
# if user-defined function was found, wrap and return it
return self.template_builder_wrapper(match)
return self.template_builder_wrapper(match) # type: ignore
return None


Expand Down
18 changes: 18 additions & 0 deletions tests/test_histo.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging

import boost_histogram as bh
import numpy as np
import pytest

Expand Down Expand Up @@ -77,6 +78,23 @@ def histogram_helpers():
return HistogramHelpers


# test properties
def test_Histogram(example_histograms):
bins, yields, stdev = example_histograms.normal()
h_orig = bh.Histogram(bh.axis.Variable(bins), storage=bh.storage.Weight())
h_orig[...] = np.stack([np.asarray(yields), np.asarray(stdev) ** 2], axis=-1)
h = histo.Histogram(h_orig)
np.testing.assert_equal(h.bins, bins)
np.testing.assert_equal(h.yields, yields)
np.testing.assert_equal(h.stdev, stdev)
new_yields = np.asarray([3, 4])
new_stdev = np.asarray([0.5, 0.5])
h.yields = new_yields
h.stdev = new_stdev
np.testing.assert_equal(h.yields, new_yields)
np.testing.assert_equal(h.stdev, new_stdev)


def test_Histogram_from_arrays(example_histograms):
bins, yields, stdev = example_histograms.normal()
h = histo.Histogram.from_arrays(bins, yields, stdev)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_route.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ def example_wrapper(func):
@functools.wraps(func)
def wrapper(reg, sam, sys, tem):
# return the bin yield of the histogram to have something to compare
return func(reg, sam, sys, tem).view().value
return func(reg, sam, sys, tem).values()

return wrapper

Expand Down

0 comments on commit 076c529

Please # to comment.