Skip to content

Commit

Permalink
Merge branch 'main' into pre-commit-ci-update-config
Browse files Browse the repository at this point in the history
  • Loading branch information
markbandstra authored May 29, 2024
2 parents 7908705 + a2c38e4 commit 301c7da
Show file tree
Hide file tree
Showing 53 changed files with 648 additions and 603 deletions.
53 changes: 7 additions & 46 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,39 +27,11 @@ repos:
- id: requirements-txt-fixer
- id: sort-simple-yaml
- id: trailing-whitespace
- repo: https://github.com/asottile/pyupgrade
rev: v3.15.2
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.5
hooks:
- id: pyupgrade
args: [--py38-plus]
- repo: https://github.com/asottile/yesqa
rev: v1.5.0
hooks:
- id: yesqa
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
args: [--profile, black, --float-to-top, --color]
- repo: https://github.com/psf/black
rev: 24.4.2
hooks:
- id: black
- repo: https://github.com/PyCQA/autoflake
rev: v2.3.1
hooks:
- id: autoflake
- repo: https://github.com/PyCQA/flake8
rev: 7.0.0
hooks:
- id: flake8
additional_dependencies: [flake8-bugbear]
args: ["--ignore=W503,B015,B028"]
- repo: https://github.com/PyCQA/bandit
rev: 1.7.8
hooks:
- id: bandit
args: [--skip, "B101"]
- id: ruff
- id: ruff-format
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
hooks:
Expand All @@ -82,17 +54,6 @@ repos:
- id: nbqa-check-ast
additional_dependencies: [pre-commit-hooks]
args: [--nbqa-dont-skip-bad-cells]
- id: nbqa-pyupgrade
additional_dependencies: [pyupgrade==v3.15.0]
args: [--py37-plus]
- id: nbqa-isort
additional_dependencies: [isort==5.13.2]
args: [--profile=black, --float-to-top]
- id: nbqa-black
additional_dependencies: [black==24.1.1]
- id: nbqa-pydocstyle
additional_dependencies: [pydocstyle==6.3.0]
args: ["--ignore=D100,D103"]
- id: nbqa-flake8
additional_dependencies: [flake8==7.0.0, flake8-bugbear]
args: [--max-line-length=88, "--ignore=E203,E722,F821,W503,B001,B015"]
- id: nbqa-ruff
additional_dependencies: [ruff==v0.4.5]
args: ["--ignore=E722,F821,S110"]
7 changes: 6 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ Please follow these guidelines when contributing to this project.
## Developer Instructions

```bash
pip install -r requirements.txt
pip install -r requirements-dev.txt
python setup.py develop

Expand All @@ -30,6 +29,12 @@ new code, and it can also be run at any time using the following command:
pre-commit run --all
```

or run on any files not yet committed to the repository using

```bash
pre-commit run --files <filename1> <filename2> ...
```

### Running the tests

(Requires `requirements-dev.txt` to be installed)
Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# becquerel

[![tests](https://github.com/lbl-anp/becquerel/actions/workflows/tests.yaml/badge.svg?branch=)](https://github.com/lbl-anp/becquerel/actions/workflows/tests.yaml)
[![Coverage Status](https://coveralls.io/repos/github/lbl-anp/becquerel/badge.svg?branch=main)](https://coveralls.io/github/lbl-anp/becquerel?branch=main)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![PyPI version](https://img.shields.io/pypi/v/becquerel.svg)](https://pypi.org/project/becquerel)
[![PyPI pyversions](https://img.shields.io/pypi/pyversions/becquerel.svg)](https://pypi.org/project/becquerel)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![PyPI license](https://img.shields.io/pypi/l/becquerel.svg)](https://pypi.python.org/project/becquerel)
[![tests](https://github.com/lbl-anp/becquerel/actions/workflows/tests.yaml/badge.svg?branch=)](https://github.com/lbl-anp/becquerel/actions/workflows/tests.yaml)
[![Coverage Status](https://coveralls.io/repos/github/lbl-anp/becquerel/badge.svg?branch=main)](https://coveralls.io/github/lbl-anp/becquerel?branch=main)

Becquerel is a Python package for analyzing nuclear spectroscopic
measurements. The core functionalities are reading and writing different
Expand Down Expand Up @@ -50,12 +51,13 @@ The dependencies `beautifulsoup4`, `lxml` and `html5lib` are necessary for
[`pandas`][1].

Developers require additional requirements which are listed in
`requirements-dev.txt`. We use [`pytest`][2] for unit testing, [`black`][3] for
code formatting and are converting to [`numpydoc`][4].
`requirements-dev.txt`. We use [`pytest`][2] for unit testing, [`ruff`][3] for
code formatting and linting, and are planning to eventually support
[`numpydoc`][4] docstrings.

[1]: https://pandas.pydata.org/pandas-docs/stable/install.html#dependencies
[2]: https://docs.pytest.org/en/latest/
[3]: https://black.readthedocs.io/en/stable/
[3]: https://docs.astral.sh/ruff/
[4]: https://numpydoc.readthedocs.io/en/latest/format.html

## Copyright Notice
Expand Down
38 changes: 19 additions & 19 deletions becquerel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,44 +34,44 @@
warnings.simplefilter("default", DeprecationWarning)

__all__ = [
"__description__",
"__url__",
"__version__",
"__license__",
"__copyright__",
"core",
"utils",
"fitting",
"AutoCalibrator",
"AutoCalibratorError",
"LinearEnergyCal",
"EnergyCalError",
"BadInput",
"Calibration",
"CalibrationError",
"CalibrationWarning",
"Element",
"EnergyCalError",
"Fitter",
"GaussianPeakFilter",
"Isotope",
"IsotopeQuantity",
"LinearEnergyCal",
"PeakFilter",
"PeakFilterError",
"GaussianPeakFilter",
"PeakFinder",
"PeakFinderError",
"SpectrumPlotter",
"PlottingError",
"rebin",
"RebinError",
"RebinWarning",
"Spectrum",
"SpectrumError",
"UncalibratedError",
"SpectrumPlotter",
"SpectrumWarning",
"UncalibratedError",
"UncertaintiesError",
"__copyright__",
"__description__",
"__license__",
"__url__",
"__version__",
"core",
"fitting",
"materials",
"nndc",
"parsers",
"rebin",
"tools",
"nndc",
"utils",
"xcom",
"materials",
"Element",
"Isotope",
"IsotopeQuantity",
]
1 change: 0 additions & 1 deletion becquerel/__metadata__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""becquerel package metadata."""

__name__ = "becquerel"
__author__ = "The Becquerel Development Team"
__maintainer__ = __author__
__email__ = "[email protected]"
Expand Down
16 changes: 8 additions & 8 deletions becquerel/core/autocal.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def find_best_gain(
snrs = np.array(snrs)
n_req = len(required_energies)
# make sure the required and optional sets do not overlap
optional = sorted(list(set(optional) - set(required_energies)))
optional = sorted(set(optional) - set(required_energies))
n_opt = len(optional)
n_set = n_req + n_opt
best_fom = None
Expand Down Expand Up @@ -187,9 +187,9 @@ def find_best_gain(
"Valid calibration found:\n"
f"FOM: {fom:15.9f}"
f" gain: {gain:6.3f}"
f" ergs: {str(comb_erg):50s}"
f" de: {str(de):50s}"
f" chans: {str(comb_chan):40s}"
f" ergs: {comb_erg!s:50s}"
f" de: {de!s:50s}"
f" chans: {comb_chan!s:40s}"
)
if best_fom is None:
best_fom = fom + 1.0
Expand All @@ -204,15 +204,15 @@ def find_best_gain(
"Best calibration so far:\n"
f"FOM: {best_fom:15.9f}"
f" gain: {best_gain:6.3f}"
f" ergs: {str(best_ergs):50s}"
f" de: {str(de):50s}"
f" chans: {str(best_chans):40s}"
f" ergs: {best_ergs!s:50s}"
f" de: {de!s:50s}"
f" chans: {best_chans!s:40s}"
)
n_set -= 1
if best_gain is None:
return None
else:
print("found best gain: %f keV/channel" % best_gain)
print(f"found best gain: {best_gain:f} keV/channel")
return {
"gain": best_gain,
"channels": best_chans,
Expand Down
30 changes: 15 additions & 15 deletions becquerel/core/calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ def _validate_domain_range(domain, rng):
# must be length-2 iterables
try:
len(domain)
except TypeError:
raise CalibrationError(f"Domain must be length-2 iterable: {domain}")
except TypeError as exc:
raise CalibrationError(f"Domain must be length-2 iterable: {domain}") from exc
domain = np.asarray(domain)
if not (len(domain) == 2 and domain.ndim == 1):
raise CalibrationError(f"Domain must be length-2 iterable: {domain}")
try:
len(rng)
except TypeError:
raise CalibrationError(f"Range must be length-2 iterable: {rng}")
except TypeError as exc:
raise CalibrationError(f"Range must be length-2 iterable: {rng}") from exc
rng = np.asarray(rng)
if not (len(rng) == 2 and rng.ndim == 1):
raise CalibrationError(f"Range must contain two values: {rng}")
Expand Down Expand Up @@ -230,10 +230,10 @@ def _validate_expression(
# apply black formatting for consistency and error checking
try:
expression = black.format_str(expression, mode=black.FileMode())
except (black.InvalidInput, blib2to3.pgen2.tokenize.TokenError):
except (black.InvalidInput, blib2to3.pgen2.tokenize.TokenError) as exc:
raise CalibrationError(
f"Error while running black on expression:\n{expression}"
)
) from exc

# make sure `ind_var` appears in the formula
if ind_var not in ["x", "y"]:
Expand All @@ -252,10 +252,10 @@ def _validate_expression(
# make sure each parameter appears at least once
try:
param_indices = _param_indices(expression)
except ValueError:
except ValueError as exc:
raise CalibrationError(
f"Unable to extract indices to parameters:\n{expression}"
)
) from exc
if len(param_indices) > 0:
if param_indices.min() != 0:
raise CalibrationError(
Expand Down Expand Up @@ -288,11 +288,11 @@ def _validate_expression(
domain=domain,
rng=rng,
)
except CalibrationError:
except CalibrationError as exc:
raise CalibrationError(
f"Cannot evaluate expression for float {ind_var} = {x_val}:\n"
f"{expression}\n{safe_eval.symtable['x']}"
)
) from exc
try:
_eval_expression(
expression,
Expand All @@ -303,11 +303,11 @@ def _validate_expression(
domain=domain,
rng=rng,
)
except CalibrationError:
except CalibrationError as exc:
raise CalibrationError(
f"Cannot evaluate expression for array {ind_var} = {x_arr}:\n"
f"{expression}\n{safe_eval.symtable['x']}"
)
) from exc

return expression.strip()

Expand Down Expand Up @@ -628,7 +628,7 @@ def __repr__(self):
if len(self.attrs) > 0:
for key in self.attrs:
result += ", "
result += f"{key}={repr(self.attrs[key])}"
result += f"{key}={self.attrs[key]!r}"
result += ")"
return result

Expand Down Expand Up @@ -907,7 +907,7 @@ def read(cls, name):
-------
calibration : becquerel.Calibration
"""
dsets, attrs, skipped = io.h5.read_h5(name)
dsets, attrs, _ = io.h5.read_h5(name)
if "params" not in dsets:
raise CalibrationError('Expected dataset "params"')
if "expression" not in dsets:
Expand Down Expand Up @@ -1237,7 +1237,7 @@ def plot(self, ax=None):
has_points = self.points_x.size > 0

if ax is None:
fig, ax = plt.subplots(1 + has_points, 1, sharex=True)
_, ax = plt.subplots(1 + has_points, 1, sharex=True)

if has_points:
assert ax.shape == (2,)
Expand Down
24 changes: 14 additions & 10 deletions becquerel/core/energycal.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""""Energy calibration classes"""
"""Energy calibration classes"""

import warnings
from abc import ABCMeta, abstractmethod, abstractproperty
Expand Down Expand Up @@ -73,8 +73,8 @@ def from_points(cls, chlist, kevlist, include_origin=False):

try:
cond = len(chlist) != len(kevlist)
except TypeError:
raise BadInput("Inputs must be one dimensional iterables")
except TypeError as exc:
raise BadInput("Inputs must be one dimensional iterables") from exc
if cond:
raise BadInput("Channels and energies must be same length")

Expand All @@ -86,8 +86,8 @@ def from_points(cls, chlist, kevlist, include_origin=False):
for ch, kev in zip(chlist, kevlist):
try:
cal.new_calpoint(ch, kev)
except (ValueError, TypeError):
raise BadInput("Inputs must be one dimensional iterables")
except (ValueError, TypeError) as exc:
raise BadInput("Inputs must be one dimensional iterables") from exc
cal.update_fit()
return cal

Expand Down Expand Up @@ -306,7 +306,7 @@ def plot(self, ax=None):
has_points = self.channels.size > 0

if ax is None:
fig, ax = plt.subplots(1 + has_points, 1, sharex=True)
_, ax = plt.subplots(1 + has_points, 1, sharex=True)

if has_points:
assert ax.shape == (2,)
Expand Down Expand Up @@ -389,17 +389,21 @@ def slope(self):

try:
return self._coeffs["b"]
except KeyError:
raise EnergyCalError("Slope coefficient not yet supplied or calculated.")
except KeyError as exc:
raise EnergyCalError(
"Slope coefficient not yet supplied or calculated."
) from exc

@property
def offset(self):
"""Return the offset coefficient value."""

try:
return self._coeffs["c"]
except KeyError:
raise EnergyCalError("Offset coefficient not yet supplied or calculated.")
except KeyError as exc:
raise EnergyCalError(
"Offset coefficient not yet supplied or calculated."
) from exc

def _ch2kev(self, ch):
"""Convert scalar OR np.array of channel(s) to energies.
Expand Down
Loading

0 comments on commit 301c7da

Please sign in to comment.