From 0744b42a86c89f6564e1f8ae2a9c99044ae907ab Mon Sep 17 00:00:00 2001 From: Matthew Feickert Date: Wed, 16 Aug 2023 12:03:12 -0500 Subject: [PATCH] chore(backport): Move to using Ruff for pre-commit (#2282) * Backport components of: - https://github.com/scikit-hep/pyhf/pull/2124 - https://github.com/scikit-hep/pyhf/pull/2238 - https://github.com/scikit-hep/pyhf/pull/2240 - https://github.com/scikit-hep/pyhf/pull/2273 --- .flake8 | 9 --------- .pre-commit-config.yaml | 30 +++++++----------------------- pyproject.toml | 30 ++++++++++++++++++++++++------ src/pyhf/cli/spec.py | 2 +- src/pyhf/contrib/utils.py | 2 +- src/pyhf/contrib/viz/brazil.py | 4 ++-- src/pyhf/workspace.py | 16 ++++++++++------ tests/test_workspace.py | 6 +++--- 8 files changed, 48 insertions(+), 51 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 19876bf1a1..0000000000 --- a/.flake8 +++ /dev/null @@ -1,9 +0,0 @@ -[flake8] -# E203: whitespace before ':' -# E402: module level import not at top of file -# E501: line too long -extend-ignore = E203, E402, E501 -max-line-length = 88 - -per-file-ignores = - docs/lite/jupyterlite.py:F401,F704 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8d21b9c254..215cbd085c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,16 +26,11 @@ repos: # exclude generated files exclude: ^validation/|\.dtd$|\.xml$ -- repo: https://github.com/asottile/pyupgrade - rev: v3.3.1 +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: "v0.0.281" hooks: - - id: pyupgrade - args: ["--py37-plus"] - -- repo: https://github.com/MarcoGorelli/absolufy-imports - rev: v0.3.1 - hooks: - - id: absolufy-imports + - id: ruff + args: ["--fix", "--show-fixes"] - repo: https://github.com/psf/black rev: 23.3.0 @@ -48,18 +43,6 @@ repos: - id: blacken-docs additional_dependencies: [black==23.3.0] -- repo: https://github.com/asottile/yesqa - rev: v1.4.0 - hooks: - - id: yesqa - -- repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 - hooks: - - id: flake8 - args: ["--count", "--statistics"] - additional_dependencies: [flake8-encodings==0.5.0.post1] - - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.2.0 # check the oldest and newest supported Pythons @@ -81,8 +64,9 @@ repos: - repo: https://github.com/nbQA-dev/nbQA rev: 1.7.0 hooks: - - id: nbqa-pyupgrade - additional_dependencies: [pyupgrade==3.3.1] + - id: nbqa-ruff + additional_dependencies: [ruff==0.0.281] + args: ["--extend-ignore=F821,F401,F841,F811"] - repo: https://github.com/codespell-project/codespell rev: v2.2.4 diff --git a/pyproject.toml b/pyproject.toml index 6a40b1dccc..e83bed128f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -225,12 +225,6 @@ filterwarnings = [ "ignore:module 'sre_constants' is deprecated:DeprecationWarning", # tensorflow v2.12.0+ for Python 3.11+ ] -[tool.nbqa.mutate] -pyupgrade = 1 - -[tool.nbqa.addopts] -pyupgrade = ["--py37-plus"] - [tool.mypy] files = "src" python_version = "3.11" @@ -281,3 +275,27 @@ module = [ 'pyhf.tensor.pytorch_backend.*', ] ignore_errors = true + +[tool.ruff] +select = [ + "E", "F", "W", # flake8 + "UP", # pyupgrade + "RUF", # Ruff-specific + "TID", # flake8-tidy-imports +] +line-length = 88 +ignore = [ + "E402", + "E501", + "RUF001", # String contains ambiguous unicode character + "RUF005", # unpack-instead-of-concatenating-to-collection-literal +] +src = ["src"] +typing-modules = ["pyhf.typing"] +unfixable = [ + "F841", # Removes unused variables +] +flake8-tidy-imports.ban-relative-imports = "all" + +[tool.ruff.per-file-ignores] +"docs/lite/jupyterlite.py" = ["F401", "F704"] diff --git a/src/pyhf/cli/spec.py b/src/pyhf/cli/spec.py index a39176670f..9e4e609b80 100644 --- a/src/pyhf/cli/spec.py +++ b/src/pyhf/cli/spec.py @@ -108,7 +108,7 @@ def inspect(workspace, output_file, measurement): ) # summary - fmtStr = '{{0: >{0:d}s}} {{1:s}}'.format(maxlen + len('Summary')) + fmtStr = '{{: >{:d}s}} {{:s}}'.format(maxlen + len('Summary')) click.echo(fmtStr.format(' Summary ', '')) click.echo(fmtStr.format('-' * 18, '')) fmtStr = f'{{0: >{maxlen:d}s}} {{1:s}}' diff --git a/src/pyhf/contrib/utils.py b/src/pyhf/contrib/utils.py index b810b94aa6..079bc55db9 100644 --- a/src/pyhf/contrib/utils.py +++ b/src/pyhf/contrib/utils.py @@ -115,7 +115,7 @@ def download(archive_url, output_directory, force=False, compress=False): # directory up and then renamed as the name of the # zipfile directory is set at zipfile creation time and # isn't knowable in advance. - child_path = [child for child in output_directory.iterdir()][0] + child_path = next(iter(output_directory.iterdir())) _tmp_path = output_directory.parent.joinpath( Path(output_directory.name + "__tmp__") ) diff --git a/src/pyhf/contrib/viz/brazil.py b/src/pyhf/contrib/viz/brazil.py index da492485d2..4e25a63c1b 100644 --- a/src/pyhf/contrib/viz/brazil.py +++ b/src/pyhf/contrib/viz/brazil.py @@ -361,9 +361,9 @@ def plot_results(test_pois, tests, test_size=0.05, ax=None, **kwargs): handles, labels = ax.get_legend_handles_labels() if not no_cls: for label_part in ["exp", "pm1", "pm2", "alpha"]: - label_idx = [ + label_idx = next( idx for idx, label in enumerate(labels) if label_part in label - ][0] + ) handles.append(handles.pop(label_idx)) labels.append(labels.pop(label_idx)) diff --git a/src/pyhf/workspace.py b/src/pyhf/workspace.py index 2eec7bb4b9..301e5e55e2 100644 --- a/src/pyhf/workspace.py +++ b/src/pyhf/workspace.py @@ -5,14 +5,18 @@ * the observed data (optional) * fit configurations ("measurements") """ +from __future__ import annotations + +import collections +import copy import logging +from typing import ClassVar + import jsonpatch -import copy -import collections -from pyhf import exceptions -from pyhf import schema -from pyhf.pdf import Model + +from pyhf import exceptions, schema from pyhf.mixins import _ChannelSummaryMixin +from pyhf.pdf import Model log = logging.getLogger(__name__) @@ -284,7 +288,7 @@ class Workspace(_ChannelSummaryMixin, dict): A JSON-serializable object that is built from an object that follows the :obj:`workspace.json` `schema `__. """ - valid_joins = ['none', 'outer', 'left outer', 'right outer'] + valid_joins: ClassVar[list[str]] = ['none', 'outer', 'left outer', 'right outer'] def __init__(self, spec, validate: bool = True, **config_kwargs): """ diff --git a/tests/test_workspace.py b/tests/test_workspace.py index 737e77021c..55ee0df046 100644 --- a/tests/test_workspace.py +++ b/tests/test_workspace.py @@ -378,7 +378,7 @@ def test_join_items_outer_deep(join_items): joined = pyhf.workspace._join_items( 'outer', left_items, right_items, key='name', deep_merge_key='deep' ) - assert [k['deep'] for k in joined if k['name'] == 'common'][0] == [ + assert next(k['deep'] for k in joined if k['name'] == 'common') == [ {'name': 1}, {'name': 2}, ] @@ -389,7 +389,7 @@ def test_join_items_left_outer_deep(join_items): joined = pyhf.workspace._join_items( 'left outer', left_items, right_items, key='name', deep_merge_key='deep' ) - assert [k['deep'] for k in joined if k['name'] == 'common'][0] == [ + assert next(k['deep'] for k in joined if k['name'] == 'common') == [ {'name': 1}, {'name': 2}, ] @@ -400,7 +400,7 @@ def test_join_items_right_outer_deep(join_items): joined = pyhf.workspace._join_items( 'right outer', left_items, right_items, key='name', deep_merge_key='deep' ) - assert [k['deep'] for k in joined if k['name'] == 'common'][0] == [ + assert next(k['deep'] for k in joined if k['name'] == 'common') == [ {'name': 2}, {'name': 1}, ]