diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml index 3f4d4cb074..22209764cb 100644 --- a/.github/workflows/bump-version.yml +++ b/.github/workflows/bump-version.yml @@ -12,11 +12,9 @@ on: - minor - major release_candidate: - type: choice - description: 'Release candidate?' - options: - - false - - true + type: boolean + description: 'Release candidate' + default: false new_version: description: 'New version to bump to' required: true @@ -27,17 +25,13 @@ on: required: true type: string force: - type: choice - description: 'Force override check?' - options: - - false - - true + type: boolean + description: 'Force override check' + default: false dry_run: - type: choice - description: 'Perform a dry run to check?' - options: - - true - - false + type: boolean + description: 'Perform a dry run to check' + default: true jobs: bump-version: diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml index c45d90d53e..ac2068c20e 100644 --- a/.github/workflows/publish-package.yml +++ b/.github/workflows/publish-package.yml @@ -17,11 +17,9 @@ on: workflow_dispatch: inputs: publish: - type: choice - description: 'Publish to TestPyPI?' - options: - - false - - true + type: boolean + description: 'Publish to TestPyPI' + default: false concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 92d2a4223b..8012c467c0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: check-added-large-files - id: check-case-conflict @@ -35,13 +35,13 @@ repos: - id: rst-inline-touching-normal - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.1.9" + rev: "v0.4.3" hooks: - id: ruff args: ["--fix", "--show-fixes"] - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.12.1 + rev: 24.4.2 hooks: - id: black-jupyter types_or: [python, pyi, jupyter] @@ -50,10 +50,10 @@ repos: rev: 1.16.0 hooks: - id: blacken-docs - additional_dependencies: [black==23.12.1] + additional_dependencies: [black==24.4.2] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.8.0 + rev: v1.10.0 # check the oldest and newest supported Pythons hooks: - &mypy @@ -64,8 +64,8 @@ repos: ['numpy', 'types-tqdm', 'click', 'types-jsonpatch', 'types-pyyaml', 'types-jsonschema', 'importlib_metadata', 'packaging'] args: ["--python-version=3.8"] - <<: *mypy - name: mypy with Python 3.11 - args: ["--python-version=3.11"] + name: mypy with Python 3.12 + args: ["--python-version=3.12"] - repo: https://github.com/codespell-project/codespell rev: v2.2.6 @@ -73,3 +73,11 @@ repos: - id: codespell files: ^.*\.(py|md|rst)$ args: ["-w", "-L", "hist,gaus"] + +- repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.28.4 + hooks: + - id: check-readthedocs + args: ["--verbose"] + - id: check-github-workflows + args: ["--verbose"] diff --git a/docs/examples/notebooks/ImpactPlot.ipynb b/docs/examples/notebooks/ImpactPlot.ipynb index aa045c124f..3a3fdd9019 100644 --- a/docs/examples/notebooks/ImpactPlot.ipynb +++ b/docs/examples/notebooks/ImpactPlot.ipynb @@ -172,9 +172,11 @@ " model, _, b, e = fitresults()\n", " widths = pyhf.tensorlib.concatenate(\n", " [\n", - " model.config.param_set(k).width()\n", - " if model.config.param_set(k).constrained\n", - " else [None] * model.config.param_set(k).n_parameters\n", + " (\n", + " model.config.param_set(k).width()\n", + " if model.config.param_set(k).constrained\n", + " else [None] * model.config.param_set(k).n_parameters\n", + " )\n", " for k, v in model.config.par_map.items()\n", " ]\n", " )\n", diff --git a/src/pyhf/cli/__init__.py b/src/pyhf/cli/__init__.py index 0d65039661..ed53c296af 100644 --- a/src/pyhf/cli/__init__.py +++ b/src/pyhf/cli/__init__.py @@ -1,4 +1,5 @@ """The pyhf command line interface.""" + from pyhf.cli.cli import pyhf as cli from pyhf.cli.rootio import cli as rootio from pyhf.cli.spec import cli as spec diff --git a/src/pyhf/cli/cli.py b/src/pyhf/cli/cli.py index a1a486fe54..cd458a6329 100644 --- a/src/pyhf/cli/cli.py +++ b/src/pyhf/cli/cli.py @@ -1,4 +1,5 @@ """The pyhf Command Line Interface.""" + import logging import click diff --git a/src/pyhf/cli/complete.py b/src/pyhf/cli/complete.py index 58fda5604f..c39e6e9784 100644 --- a/src/pyhf/cli/complete.py +++ b/src/pyhf/cli/complete.py @@ -1,4 +1,5 @@ '''Shell completions for pyhf.''' + import click try: diff --git a/src/pyhf/cli/infer.py b/src/pyhf/cli/infer.py index a877469efc..f2b0dce107 100644 --- a/src/pyhf/cli/infer.py +++ b/src/pyhf/cli/infer.py @@ -1,4 +1,5 @@ """The inference CLI group.""" + import logging import click diff --git a/src/pyhf/cli/patchset.py b/src/pyhf/cli/patchset.py index 75bdb56887..4d31d4963d 100644 --- a/src/pyhf/cli/patchset.py +++ b/src/pyhf/cli/patchset.py @@ -1,4 +1,5 @@ """The pyhf spec CLI subcommand.""" + import logging import click diff --git a/src/pyhf/cli/rootio.py b/src/pyhf/cli/rootio.py index 95d8872a84..c5d5840762 100644 --- a/src/pyhf/cli/rootio.py +++ b/src/pyhf/cli/rootio.py @@ -1,4 +1,5 @@ """CLI subapps to handle conversion from ROOT.""" + import logging import click diff --git a/src/pyhf/cli/spec.py b/src/pyhf/cli/spec.py index 9e4e609b80..dc6116a860 100644 --- a/src/pyhf/cli/spec.py +++ b/src/pyhf/cli/spec.py @@ -1,4 +1,5 @@ """The pyhf spec CLI subcommand.""" + import logging import click @@ -149,9 +150,11 @@ def inspect(workspace, output_file, measurement): ('(*) ' if measurement_name == default_measurement['name'] else '') + measurement_name, measurement_poi, - ','.join(measurement_parameters) - if measurement_parameters - else '(none)', + ( + ','.join(measurement_parameters) + if measurement_parameters + else '(none)' + ), ) ) diff --git a/src/pyhf/contrib/cli.py b/src/pyhf/contrib/cli.py index eaf2bb7e23..5bba47e4d4 100644 --- a/src/pyhf/contrib/cli.py +++ b/src/pyhf/contrib/cli.py @@ -1,4 +1,5 @@ """CLI for functionality that will get migrated out eventually.""" + import logging import click from pathlib import Path diff --git a/src/pyhf/contrib/viz/brazil.py b/src/pyhf/contrib/viz/brazil.py index ad39a7648d..18b25d87bd 100644 --- a/src/pyhf/contrib/viz/brazil.py +++ b/src/pyhf/contrib/viz/brazil.py @@ -1,4 +1,5 @@ """Brazil Band Plots.""" + from collections import namedtuple import matplotlib.pyplot as plt diff --git a/src/pyhf/infer/calculators.py b/src/pyhf/infer/calculators.py index 1889dec0c7..f9922c6d89 100644 --- a/src/pyhf/infer/calculators.py +++ b/src/pyhf/infer/calculators.py @@ -7,6 +7,7 @@ Using the calculators hypothesis tests can then be performed. """ + from pyhf.infer.mle import fixed_poi_fit from pyhf import get_backend from pyhf.infer import utils diff --git a/src/pyhf/infer/intervals/__init__.py b/src/pyhf/infer/intervals/__init__.py index 0f2f928cdd..2acdfd3165 100644 --- a/src/pyhf/infer/intervals/__init__.py +++ b/src/pyhf/infer/intervals/__init__.py @@ -1,4 +1,5 @@ """Interval estimation""" + import pyhf.infer.intervals.upper_limits __all__ = ["upper_limits.upper_limit"] diff --git a/src/pyhf/infer/intervals/upper_limits.py b/src/pyhf/infer/intervals/upper_limits.py index 1169786df2..b2099089fd 100644 --- a/src/pyhf/infer/intervals/upper_limits.py +++ b/src/pyhf/infer/intervals/upper_limits.py @@ -1,4 +1,5 @@ """Interval estimation""" + import numpy as np from scipy.optimize import toms748 diff --git a/src/pyhf/infer/mle.py b/src/pyhf/infer/mle.py index 61559b0ed0..c269eb47c8 100644 --- a/src/pyhf/infer/mle.py +++ b/src/pyhf/infer/mle.py @@ -1,4 +1,5 @@ """Module for Maximum Likelihood Estimation.""" + from pyhf import get_backend from pyhf.exceptions import UnspecifiedPOI diff --git a/src/pyhf/interpolators/code0.py b/src/pyhf/interpolators/code0.py index ff972d506b..52d87fefba 100644 --- a/src/pyhf/interpolators/code0.py +++ b/src/pyhf/interpolators/code0.py @@ -1,4 +1,5 @@ """Piecewise-linear Interpolation. (Code 0).""" + import logging import pyhf from pyhf.tensor.manager import get_backend diff --git a/src/pyhf/interpolators/code1.py b/src/pyhf/interpolators/code1.py index f5bbe71ff0..a9fa41c011 100644 --- a/src/pyhf/interpolators/code1.py +++ b/src/pyhf/interpolators/code1.py @@ -1,4 +1,5 @@ """Piecewise-Exponential Interpolation (Code 1).""" + import logging import math import pyhf diff --git a/src/pyhf/interpolators/code2.py b/src/pyhf/interpolators/code2.py index ed305c44da..8dff3278e7 100644 --- a/src/pyhf/interpolators/code2.py +++ b/src/pyhf/interpolators/code2.py @@ -1,4 +1,5 @@ """Quadratic Interpolation (Code 2).""" + import logging import pyhf from pyhf.tensor.manager import get_backend diff --git a/src/pyhf/interpolators/code4.py b/src/pyhf/interpolators/code4.py index a120bdf295..0290d0c52d 100644 --- a/src/pyhf/interpolators/code4.py +++ b/src/pyhf/interpolators/code4.py @@ -1,4 +1,5 @@ """Polynomial Interpolation (Code 4).""" + import logging import math import pyhf diff --git a/src/pyhf/interpolators/code4p.py b/src/pyhf/interpolators/code4p.py index ec8b63afa7..8841eb0dd0 100644 --- a/src/pyhf/interpolators/code4p.py +++ b/src/pyhf/interpolators/code4p.py @@ -1,4 +1,5 @@ """Piecewise-Linear + Polynomial Interpolation (Code 4p).""" + import logging import pyhf from pyhf.tensor.manager import get_backend diff --git a/src/pyhf/modifiers/shapesys.py b/src/pyhf/modifiers/shapesys.py index 39740e4cf8..c18ac90149 100644 --- a/src/pyhf/modifiers/shapesys.py +++ b/src/pyhf/modifiers/shapesys.py @@ -165,9 +165,9 @@ def _reindex_access_field(self, pdfconfig): sample_mask = self._shapesys_mask[syst_index][singular_sample_index][0] access_field_for_syst_and_batch[sample_mask] = selection - self._access_field[ - syst_index, batch_index - ] = access_field_for_syst_and_batch + self._access_field[syst_index, batch_index] = ( + access_field_for_syst_and_batch + ) def _precompute(self): tensorlib, _ = get_backend() diff --git a/src/pyhf/modifiers/staterror.py b/src/pyhf/modifiers/staterror.py index 497eba21d6..3faad92a6c 100644 --- a/src/pyhf/modifiers/staterror.py +++ b/src/pyhf/modifiers/staterror.py @@ -92,9 +92,12 @@ def finalize(self): relerrs = default_backend.sum( [ [ - (modifier_data['data']['uncrt'][binnr] / nomsall[binnr]) ** 2 - if nomsall[binnr] > 0 - else 0.0 + ( + (modifier_data['data']['uncrt'][binnr] / nomsall[binnr]) + ** 2 + if nomsall[binnr] > 0 + else 0.0 + ) for binnr in range(len(modifier_data['data']['nom_data'])) ] for modifier_data in self.builder_data[modname].values() @@ -184,9 +187,9 @@ def _reindex_access_field(self, pdfconfig): sample_mask = self._staterror_mask[syst_index][singular_sample_index][0] access_field_for_syst_and_batch[sample_mask] = selection - self._access_field[ - syst_index, batch_index - ] = access_field_for_syst_and_batch + self._access_field[syst_index, batch_index] = ( + access_field_for_syst_and_batch + ) def _precompute(self): if not self.param_viewer.index_selection: diff --git a/src/pyhf/optimize/common.py b/src/pyhf/optimize/common.py index 61eeafd889..2049939159 100644 --- a/src/pyhf/optimize/common.py +++ b/src/pyhf/optimize/common.py @@ -1,4 +1,5 @@ """Common Backend Shim to prepare minimization for optimizer.""" + from pyhf.tensor.manager import get_backend from pyhf.tensor.common import _TensorViewer diff --git a/src/pyhf/optimize/mixins.py b/src/pyhf/optimize/mixins.py index 4b727d09c2..6ace358412 100644 --- a/src/pyhf/optimize/mixins.py +++ b/src/pyhf/optimize/mixins.py @@ -1,4 +1,5 @@ """Helper Classes for use of automatic differentiation.""" + import logging import numpy as np diff --git a/src/pyhf/optimize/opt_minuit.py b/src/pyhf/optimize/opt_minuit.py index db7b7c5011..4ab7eacf69 100644 --- a/src/pyhf/optimize/opt_minuit.py +++ b/src/pyhf/optimize/opt_minuit.py @@ -1,4 +1,5 @@ """Minuit Optimizer Class.""" + from pyhf import exceptions from pyhf.optimize.mixins import OptimizerMixin import scipy diff --git a/src/pyhf/optimize/opt_scipy.py b/src/pyhf/optimize/opt_scipy.py index 7efbee3a5d..8d0b25e866 100644 --- a/src/pyhf/optimize/opt_scipy.py +++ b/src/pyhf/optimize/opt_scipy.py @@ -1,4 +1,5 @@ """SciPy Optimizer Class.""" + from pyhf import exceptions from pyhf.optimize.mixins import OptimizerMixin import scipy diff --git a/src/pyhf/optimize/opt_tflow.py b/src/pyhf/optimize/opt_tflow.py index fd2965fb3e..178bc332ac 100644 --- a/src/pyhf/optimize/opt_tflow.py +++ b/src/pyhf/optimize/opt_tflow.py @@ -1,4 +1,5 @@ """Tensorflow Backend Function Shim.""" + from pyhf import get_backend import tensorflow as tf diff --git a/src/pyhf/parameters/paramview.py b/src/pyhf/parameters/paramview.py index cac057f8b5..0238832747 100644 --- a/src/pyhf/parameters/paramview.py +++ b/src/pyhf/parameters/paramview.py @@ -44,9 +44,11 @@ def extract_index_access(baseviewer, subviewer, indices): # the transpose is here so that modifier code doesn't have to do it indices_concatenated = tensorlib.astensor( - tensorlib.einsum('ij->ji', stitched) - if len(tensorlib.shape(stitched)) > 1 - else stitched, + ( + tensorlib.einsum('ij->ji', stitched) + if len(tensorlib.shape(stitched)) > 1 + else stitched + ), dtype='int', ) return index_selection, stitched, indices_concatenated diff --git a/src/pyhf/patchset.py b/src/pyhf/patchset.py index b72118835b..86acaef693 100644 --- a/src/pyhf/patchset.py +++ b/src/pyhf/patchset.py @@ -1,6 +1,7 @@ """ pyhf patchset provides a user-friendly interface for interacting with patchsets. """ + import logging import jsonpatch from pyhf import exceptions diff --git a/src/pyhf/probability.py b/src/pyhf/probability.py index 7851127ae3..0cc0330272 100644 --- a/src/pyhf/probability.py +++ b/src/pyhf/probability.py @@ -1,4 +1,5 @@ """The probability density function module.""" + from pyhf import get_backend __all__ = ["Independent", "Normal", "Poisson", "Simultaneous"] diff --git a/src/pyhf/schema/__init__.py b/src/pyhf/schema/__init__.py index 61bb01c78e..0c08f018b2 100644 --- a/src/pyhf/schema/__init__.py +++ b/src/pyhf/schema/__init__.py @@ -1,6 +1,7 @@ """ See :class:`~pyhf.schema.Schema` for documentation. """ + import pathlib import sys from pyhf.schema.loader import load_schema diff --git a/src/pyhf/tensor/numpy_backend.py b/src/pyhf/tensor/numpy_backend.py index 69e45c507c..4839cec6e5 100644 --- a/src/pyhf/tensor/numpy_backend.py +++ b/src/pyhf/tensor/numpy_backend.py @@ -1,4 +1,5 @@ """NumPy Tensor Library Module.""" + from __future__ import annotations import logging diff --git a/src/pyhf/tensor/pytorch_backend.py b/src/pyhf/tensor/pytorch_backend.py index b7cb96dcf8..95434bb5f0 100644 --- a/src/pyhf/tensor/pytorch_backend.py +++ b/src/pyhf/tensor/pytorch_backend.py @@ -1,4 +1,5 @@ """PyTorch Tensor Library Module.""" + import torch import torch.autograd from torch.distributions.utils import broadcast_all diff --git a/src/pyhf/tensor/tensorflow_backend.py b/src/pyhf/tensor/tensorflow_backend.py index 7a7a997a5d..48f66656e2 100644 --- a/src/pyhf/tensor/tensorflow_backend.py +++ b/src/pyhf/tensor/tensorflow_backend.py @@ -1,4 +1,5 @@ """Tensorflow Tensor Library Module.""" + import logging import tensorflow as tf import tensorflow_probability as tfp diff --git a/src/pyhf/typing.py b/src/pyhf/typing.py index ee874d5b17..c6d89caa97 100644 --- a/src/pyhf/typing.py +++ b/src/pyhf/typing.py @@ -146,8 +146,7 @@ class TensorBackend(Protocol): precision: str default_do_grad: bool - def _setup(self) -> None: - ... + def _setup(self) -> None: ... class Optimizer(Protocol): @@ -155,8 +154,6 @@ class Optimizer(Protocol): class PDF(Protocol): - def sample(self, sample_shape: Shape) -> Any: - ... + def sample(self, sample_shape: Shape) -> Any: ... - def log_prob(self, value: Any) -> Any: - ... + def log_prob(self, value: Any) -> Any: ... diff --git a/src/pyhf/workspace.py b/src/pyhf/workspace.py index 301e5e55e2..fb0ac1a6b2 100644 --- a/src/pyhf/workspace.py +++ b/src/pyhf/workspace.py @@ -5,6 +5,7 @@ * the observed data (optional) * fit configurations ("measurements") """ + from __future__ import annotations import collections @@ -17,6 +18,8 @@ from pyhf import exceptions, schema from pyhf.mixins import _ChannelSummaryMixin from pyhf.pdf import Model +import functools +import operator log = logging.getLogger(__name__) @@ -464,8 +467,8 @@ def data(self, model, include_auxdata=True): """ try: - observed_data = sum( - (self.observations[c] for c in model.config.channels), [] + observed_data = functools.reduce( + operator.iadd, (self.observations[c] for c in model.config.channels), [] ) except KeyError: log.error( diff --git a/tests/test_interpolate.py b/tests/test_interpolate.py index ef8e382b66..52b5830f12 100644 --- a/tests/test_interpolate.py +++ b/tests/test_interpolate.py @@ -178,9 +178,7 @@ def test_code0_validation(backend, do_tensorized_calc): def test_code1_validation(backend, do_tensorized_calc): histogramssets = [[[[0.9], [1.0], [1.1]]]] alphasets = pyhf.tensorlib.astensor([[-2, -1, 0, 1, 2]]) - expected = pyhf.tensorlib.astensor( - [[[[0.9**2], [0.9], [1.0], [1.1], [1.1**2]]]] - ) + expected = pyhf.tensorlib.astensor([[[[0.9**2], [0.9], [1.0], [1.1], [1.1**2]]]]) interpolator = pyhf.interpolators.get(1, do_tensorized_calc=do_tensorized_calc)( histogramssets, subscribe=False