diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b49735da..0a51eb77 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,37 +19,9 @@ repos: - id: mixed-line-ending - id: trailing-whitespace -- repo: https://github.com/asottile/pyupgrade - rev: v3.17.0 +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: "v0.6.8" hooks: - - id: pyupgrade - args: ["--py37-plus"] - -- repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - -- repo: https://github.com/PyCQA/flake8 - rev: 7.1.1 - hooks: - - id: flake8 - -- repo: https://github.com/MarcoGorelli/absolufy-imports - rev: v0.3.1 - hooks: - - id: absolufy-imports - -- repo: https://github.com/psf/black-pre-commit-mirror - rev: 24.8.0 - hooks: - - id: black-jupyter - -- repo: https://github.com/nbQA-dev/nbQA - rev: 1.8.7 - hooks: - - id: nbqa-pyupgrade - additional_dependencies: [pyupgrade==3.15.0] - args: ["--py37-plus"] - - id: nbqa-isort - additional_dependencies: [isort==5.12.0] + - id: ruff + args: ["--fix", "--show-fixes"] + - id: ruff-format diff --git a/examples/awkward_example.ipynb b/examples/awkward_example.ipynb index c8a44978..c4e1ad74 100644 --- a/examples/awkward_example.ipynb +++ b/examples/awkward_example.ipynb @@ -6,9 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "import awkward as ak\n", "import hist\n", - "import numpy as np\n", "\n", "import pylhe" ] diff --git a/examples/parquet_cache.ipynb b/examples/parquet_cache.ipynb index 75d7d03c..1657f97b 100644 --- a/examples/parquet_cache.ipynb +++ b/examples/parquet_cache.ipynb @@ -68,7 +68,8 @@ "\n", " # need the file to exist\n", " if not os.path.exists(filepath):\n", - " raise FileNotFoundError(f\"Input LHE file {filepath} does not exist.\")\n", + " msg = f\"Input LHE file {filepath} does not exist.\"\n", + " raise FileNotFoundError(msg)\n", "\n", " # leave early without even thinking about cache if user doesn't want it\n", " if not parquet_cache:\n", diff --git a/examples/zpeak.ipynb b/examples/zpeak.ipynb index 8c080daf..b114f2ef 100644 --- a/examples/zpeak.ipynb +++ b/examples/zpeak.ipynb @@ -20,8 +20,6 @@ }, "outputs": [], "source": [ - "import math\n", - "\n", "import hist\n", "\n", "import pylhe" @@ -386,8 +384,8 @@ ], "metadata": { "kernelspec": { - "name": "pythonjvsc74a57bd073182083f4e2a7a153b1c22bd64054bec714030b17650bd3a885c40287b848ca", - "display_name": "Python 3.7.2 ('_env': venv)" + "display_name": "Python 3.7.2 ('_env': venv)", + "name": "pythonjvsc74a57bd073182083f4e2a7a153b1c22bd64054bec714030b17650bd3a885c40287b848ca" }, "language_info": { "codemirror_mode": { diff --git a/pyproject.toml b/pyproject.toml index 1422ec0c..89a08c75 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,8 +47,7 @@ dependencies = [ [project.optional-dependencies] lint = [ - "black", - "flake8", + "ruff", ] test = [ "pydocstyle", @@ -89,28 +88,34 @@ include = [ [tool.hatch.build.targets.wheel] packages = ["src/pylhe"] -[tool.black] -line-length = 88 -include = '\.pyi?$' -extend-exclude = ''' -/( - \.git - | .eggs - | build - | src/pylhe/_version.py -)/ -''' - -[tool.isort] -profile = "black" - -[tool.nbqa.config] -black = "pyproject.toml" - -[tool.nbqa.mutate] -black = 1 -pyupgrade = 1 -isort = 1 - -[tool.nbqa.addopts] -pyupgrade = ["--py36-plus"] +[tool.ruff.lint] +extend-select = [ + "B", # flake8-bugbear + "I", # isort + "ARG", # flake8-unused-arguments + "C4", # flake8-comprehensions + "EM", # flake8-errmsg + "ICN", # flake8-import-conventions + "G", # flake8-logging-format + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # pylint + "PT", # flake8-pytest-style + "RET", # flake8-return + "RUF", # Ruff-specific + "SIM", # flake8-simplify + "UP", # pyupgrade + "YTT", # flake8-2020 + "EXE", # flake8-executable + "NPY", # NumPy specific rules + "PD", # pandas-vet + "FURB", # refurb + "PYI", # flake8-pyi +] +ignore = [ + "PLR09", # Too many <...> + "PLR2004", # Magic value used in comparison + "ISC001", # Conflicts with formatter + "RUF012", # TODO: mutable class attributes + "SIM115", # TODO: use context manager for opening files +] diff --git a/src/pylhe/__init__.py b/src/pylhe/__init__.py index 3d74f583..5f37498e 100644 --- a/src/pylhe/__init__.py +++ b/src/pylhe/__init__.py @@ -64,18 +64,16 @@ def tolhe(self, rwgt=True, weights=False): str: The event as a string in LHE format. """ sweights = "" - if rwgt: - if self.weights: - sweights = "\n" - for k, v in self.weights.items(): - sweights += f" {v:11.4e}\n" - sweights += "\n" - if weights: - if self.weights: - sweights = "\n" - for k, v in self.weights.items(): - sweights += f"{v:11.4e}\n" - sweights += "\n" + if rwgt and self.weights: + sweights = "\n" + for k, v in self.weights.items(): + sweights += f" {v:11.4e}\n" + sweights += "\n" + if weights and self.weights: + sweights = "\n" + for v in self.weights.values(): + sweights += f"{v:11.4e}\n" + sweights += "\n" return ( "\n" @@ -156,9 +154,8 @@ class LHEEventInfo: def __init__(self, **kwargs): if set(kwargs.keys()) != set(self.fieldnames): - raise RuntimeError( - f"LHEEventInfo constructor expects fields {self.fieldnames}! Got {kwargs.keys()}." - ) + msg = f"LHEEventInfo constructor expects fields {self.fieldnames}! Got {kwargs.keys()}." + raise RuntimeError(msg) for k, v in kwargs.items(): setattr(self, k, v) @@ -198,9 +195,8 @@ class LHEParticle: def __init__(self, **kwargs): if set(kwargs.keys()) != set(self.fieldnames): - raise RuntimeError( - f"LHEParticle constructor expects fields {self.fieldnames}! Got {kwargs.keys()}." - ) + msg = f"LHEParticle constructor expects fields {self.fieldnames}! Got {kwargs.keys()}." + raise RuntimeError(msg) for k, v in kwargs.items(): setattr(self, k, v) @@ -224,7 +220,7 @@ def mothers(self): first_idx = int(self.mother1) - 1 second_idx = int(self.mother2) - 1 return [ - self.event.particles[idx] for idx in {first_idx, second_idx} if idx >= 0 + self.event.particles[idx] for idx in (first_idx, second_idx) if idx >= 0 ] @@ -238,13 +234,13 @@ def _indent(elem, level=0): elem.text = i + " " if not elem.tail or not elem.tail.strip(): elem.tail = i - for elem in elem: - _indent(elem, level + 1) + for inner_elem in elem: + _indent(inner_elem, level + 1) + elem = inner_elem if not elem.tail or not elem.tail.strip(): elem.tail = i - else: - if level and (not elem.tail or not elem.tail.strip()): - elem.tail = i + elif level and (not elem.tail or not elem.tail.strip()): + elem.tail = i class LHEInit(dict): @@ -264,9 +260,9 @@ def tolhe(self): """ # weightgroups to xml root = ET.Element("initrwgt") - for k, v in self["weightgroup"].items(): + for _k, v in self["weightgroup"].items(): weightgroup_elem = ET.SubElement(root, "weightgroup", **v["attrib"]) - for key, value in v["weights"].items(): + for _key, value in v["weights"].items(): weight_elem = ET.SubElement( weightgroup_elem, "weight", **value["attrib"] ) @@ -288,8 +284,7 @@ def tolhe(self): def __getitem__(self, key): if key not in self: return self["initInfo"][key] - else: - return super().__getitem__(key) + return super().__getitem__(key) # custom backwards compatibility set for dict def __setitem__(self, key, value): @@ -404,7 +399,7 @@ def read_lhe_init(filepath): """ initDict = {} with _extract_fileobj(filepath) as fileobj: - for event, element in ET.iterparse(fileobj, events=["start", "end"]): + for _event, element in ET.iterparse(fileobj, events=["start", "end"]): if element.tag == "init": data = element.text.split("\n")[1:-1] initDict["initInfo"] = LHEInitInfo.fromstring(data[0]) @@ -453,7 +448,7 @@ def read_lhe_init(filepath): def read_lhe(filepath): try: with _extract_fileobj(filepath) as fileobj: - for event, element in ET.iterparse(fileobj, events=["end"]): + for _event, element in ET.iterparse(fileobj, events=["end"]): if element.tag == "event": data = element.text.strip().split("\n") eventdata, particles = data[0], data[1:] @@ -495,7 +490,7 @@ def read_lhe_with_attributes(filepath): index_map = None try: with _extract_fileobj(filepath) as fileobj: - for event, element in ET.iterparse(fileobj, events=["end"]): + for _event, element in ET.iterparse(fileobj, events=["end"]): if element.tag == "event": eventdict = {} data = element.text.strip().split("\n") @@ -517,7 +512,7 @@ def read_lhe_with_attributes(filepath): read_lhe_init(filepath) ) for i, w in enumerate(sub.text.split()): - if w and not index_map[i] in eventdict["weights"]: + if w and index_map[i] not in eventdict["weights"]: eventdict["weights"][index_map[i]] = float(w) if sub.tag == "rwgt": for r in sub: @@ -570,7 +565,7 @@ def write_lhe_file(lheinit, lheevents, filepath, gz=False, rwgt=True, weights=Fa Write the LHE file. """ # if filepath suffix is gz, write as gz - if filepath.endswith(".gz") or filepath.endswith(".gzip") or gz: + if filepath.endswith((".gz", ".gzip")) or gz: with gzip.open(filepath, "wt") as f: f.write(write_lhe_string(lheinit, lheevents, rwgt=rwgt, weights=weights)) else: diff --git a/tests/test_lhe_reader.py b/tests/test_lhe_reader.py index c58e20ff..653c7ee6 100644 --- a/tests/test_lhe_reader.py +++ b/tests/test_lhe_reader.py @@ -17,7 +17,7 @@ ) TEST_FILE_LHE_RWGT_WGT = skhep_testdata.data_path("pylhe-testfile-powheg-box-v2-W.lhe") TEST_FILES_LHE_POWHEG = [ - skhep_testdata.data_path("pylhe-testfile-powheg-box-v2-%s.lhe" % (proc)) + skhep_testdata.data_path(f"pylhe-testfile-powheg-box-v2-{proc}.lhe") for proc in ["Z", "W", "Zj", "trijet", "directphoton", "hvq"] ] @@ -28,23 +28,21 @@ def testdata_gzip_file(): tmp_path = Path(NamedTemporaryFile().name) # create what is basically pylhe-testfile-pr29.lhe.gz - with open(test_data, "rb") as readfile: - with gzip.open(tmp_path, "wb") as writefile: - shutil.copyfileobj(readfile, writefile) + with open(test_data, "rb") as readfile, gzip.open(tmp_path, "wb") as writefile: + shutil.copyfileobj(readfile, writefile) yield tmp_path # teardown os.remove(tmp_path) -def test_gzip_open(tmpdir, testdata_gzip_file): +def test_gzip_open(testdata_gzip_file): assert pylhe._extract_fileobj(TEST_FILE_LHE_v1) assert pylhe._extract_fileobj(testdata_gzip_file) # Needs path-like object, not a fileobj - with pytest.raises(TypeError): - with open(TEST_FILE_LHE_v1, "rb") as fileobj: - pylhe._extract_fileobj(fileobj) + with pytest.raises(TypeError), open(TEST_FILE_LHE_v1, "rb") as fileobj: + pylhe._extract_fileobj(fileobj) with open(TEST_FILE_LHE_v1, "rb") as fileobj: assert isinstance(pylhe._extract_fileobj(TEST_FILE_LHE_v1), type(fileobj)) diff --git a/tests/test_lhe_writer.py b/tests/test_lhe_writer.py index d85eeb87..667b5a74 100644 --- a/tests/test_lhe_writer.py +++ b/tests/test_lhe_writer.py @@ -9,7 +9,7 @@ ) TEST_FILE_LHE_RWGT_WGT = skhep_testdata.data_path("pylhe-testfile-powheg-box-v2-W.lhe") TEST_FILES_LHE_POWHEG = [ - skhep_testdata.data_path("pylhe-testfile-powheg-box-v2-%s.lhe" % (proc)) + skhep_testdata.data_path(f"pylhe-testfile-powheg-box-v2-{proc}.lhe") for proc in ["Z", "W", "Zj", "trijet", "directphoton", "hvq"] ]