Skip to content

Using ruff for linting #04 #82

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,32 +73,39 @@ isort.lines-after-imports = 2
select = [
"C", # Complexity checks (e.g., McCabe complexity, comprehensions)
# "ANN001", "ANN201", "ANN401", # flake8-annotations (required strict type annotations for public functions)
# "S", # flake8-bandit (checks basic security issues in code)
"S", # flake8-bandit (checks basic security issues in code)
# "BLE", # flake8-blind-except (checks the except blocks that do not specify exception)
# "FBT", # flake8-boolean-trap (ensure that boolean args can be used with kw only)
# "E", # pycodestyle errors (PEP 8 style guide violations)
"E", # pycodestyle errors (PEP 8 style guide violations)
"W", # pycodestyle warnings (e.g., extra spaces, indentation issues)
# "DOC", # pydoclint issues (e.g., extra or missing return, yield, warnings)
# "A", # flake8-buitins (check variable and function names to not shadow builtins)
# "N", # Naming convention checks (e.g., PEP 8 variable and function names)
"A", # flake8-buitins (check variable and function names to not shadow builtins)
"N", # Naming convention checks (e.g., PEP 8 variable and function names)
"F", # Pyflakes errors (e.g., unused imports, undefined variables)
# "I", # isort (Ensures imports are sorted properly)
# "B", # flake8-bugbear (Detects likely bugs and bad practices)
"I", # isort (Ensures imports are sorted properly)
"B", # flake8-bugbear (Detects likely bugs and bad practices)
"TID", # flake8-tidy-imports (Checks for banned or misplaced imports)
"UP", # pyupgrade (Automatically updates old Python syntax)
# "YTT", # flake8-2020 (Detects outdated Python 2/3 compatibility issues)
# "FLY", # flynt (Converts old-style string formatting to f-strings)
# "PIE", # flake8-pie
"YTT", # flake8-2020 (Detects outdated Python 2/3 compatibility issues)
"FLY", # flynt (Converts old-style string formatting to f-strings)
"PIE", # flake8-pie
# "PL", # pylint
# "RUF", # Ruff-specific rules (Additional optimizations and best practices)
]

ignore = [
"PLR2004", # [magic-value-comparision](https://docs.astral.sh/ruff/rules/magic-value-comparison)
"C90", # [mccabe](https://docs.astral.sh/ruff/rules/#mccabe-c90)
"PLR2004", # [magic-value-comparision](https://docs.astral.sh/ruff/rules/magic-value-comparison)
"S311", # [suspicious-non-cryptographic-random-usage](https://docs.astral.sh/ruff/rules/suspicious-non-cryptographic-random-usage/)
"S404", # [suspicious-subprocess-import](https://docs.astral.sh/ruff/rules/suspicious-subprocess-import/)
"S603", # [subprocess-without-shell-equals-true](https://docs.astral.sh/ruff/rules/subprocess-without-shell-equals-true/)
]

[tool.ruff.lint.per-file-ignores]
# non-lowercase-variable-in-function (N806)
"{femzip_api,femzip_mapper,d3plot,}.py" = ["N806"]
# error-suffix-on-exception-name (N818)
"{femzip_api}.py" = ["N818"]

[tool.ruff.format]
docstring-code-format = true
Expand Down
3 changes: 2 additions & 1 deletion src/lasso/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from importlib.metadata import version, PackageNotFoundError
from importlib.metadata import PackageNotFoundError, version


try:
__version__ = version("lasso-python")
Expand Down
1 change: 1 addition & 0 deletions src/lasso/diffcrash/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .diffcrash_run import DiffcrashRun


__all__ = ["DiffcrashRun"]
54 changes: 28 additions & 26 deletions src/lasso/diffcrash/diffcrash_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@
import time
import typing
from concurrent import futures
from typing import Union
from pathlib import Path
from typing import Union

import psutil

# from ..logging import str_error, str_info, str_running, str_success, str_warn
from lasso.logging import str_error, str_info, str_running, str_success, str_warn


# pylint: disable = too-many-lines

DC_STAGE_SETUP = "SETUP"
Expand Down Expand Up @@ -337,9 +338,7 @@ def _parse_crash_code(self, crash_code) -> str:
self.logger.info(self._msg_option.format("crash-code", crash_code))

if not crash_code_ok:
err_msg = (
f"Invalid crash code '{crash_code}'. Please use one of: {str(valid_crash_codes)}"
)
err_msg = f"Invalid crash code '{crash_code}'. Please use one of: {valid_crash_codes!s}"
self.logger.error(err_msg)
raise RuntimeError(str_error(err_msg))

Expand Down Expand Up @@ -647,22 +646,21 @@ def run_import(self, pool: futures.ThreadPoolExecutor):
str(i_filepath + counter_offset),
]
# indeed there is a parameter file
elif self.use_id_mapping:
args = [
self.diffcrash_home / f"DFC_Import_{self.crash_code}",
"-ID",
self.simulation_runs[i_filepath],
self.project_dir,
str(i_filepath + counter_offset),
]
else:
if self.use_id_mapping:
args = [
self.diffcrash_home / f"DFC_Import_{self.crash_code}",
"-ID",
self.simulation_runs[i_filepath],
self.project_dir,
str(i_filepath + counter_offset),
]
else:
args = [
self.diffcrash_home / f"DFC_Import_{self.crash_code}",
self.simulation_runs[i_filepath],
self.project_dir,
str(i_filepath + counter_offset),
]
args = [
self.diffcrash_home / f"DFC_Import_{self.crash_code}",
self.simulation_runs[i_filepath],
self.project_dir,
str(i_filepath + counter_offset),
]

# append args to list
import_arguments.append(args)
Expand All @@ -689,7 +687,11 @@ def run_import(self, pool: futures.ThreadPoolExecutor):

if n_imports_finished != n_new_imports_finished:
# pylint: disable = consider-using-f-string
msg = f"Running Imports ... [{n_new_imports_finished}/{len(return_code_futures)}] - {percentage:3.2f}%\r"
msg = (
f"Running Imports ... [{n_new_imports_finished}/{len(return_code_futures)}] - "
f"{percentage:3.2f}%\r"
)

print(str_running(msg), end="", flush=True)
self.logger.info(msg)

Expand Down Expand Up @@ -1206,7 +1208,7 @@ def read_config_file(self, config_file: str) -> list[str]:
conf_lines = conf.readlines()
line = 0

for i in range(0, len(conf_lines)):
for i in range(len(conf_lines)):
if conf_lines[i].find("FUNCTION") >= 0:
line = i + 1
break
Expand All @@ -1216,7 +1218,7 @@ def read_config_file(self, config_file: str) -> list[str]:
if line != 0:
while 1:
while 1:
for i in range(0, len(conf_lines[line])):
for i in range(len(conf_lines[line])):
if conf_lines[line][i] == "<":
element_start = i + 1
if conf_lines[line][i] == ">":
Expand All @@ -1231,7 +1233,7 @@ def read_config_file(self, config_file: str) -> list[str]:
j += 1
items = check.split(" ")
pos = -1
for n in range(0, len(items)):
for n in range(len(items)):
if items[n].startswith("!"):
msg = f"FOUND at {n}"
print(msg)
Expand All @@ -1240,7 +1242,7 @@ def read_config_file(self, config_file: str) -> list[str]:
break
pos = len(items)

for n in range(0, pos):
for n in range(pos):
if items[n] == "PDMX" or items[n] == "pdmx":
break
if items[n] == "PDXMX" or items[n] == "pdxmx":
Expand All @@ -1262,7 +1264,7 @@ def read_config_file(self, config_file: str) -> list[str]:

for k in range(n, pos):
postval = None
for m in range(0, n):
for m in range(n):
if items[m] == "coordinates":
items[m] = "geometry"
if postval is None:
Expand Down
1 change: 0 additions & 1 deletion src/lasso/diffcrash/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
DiffcrashRun,
parse_diffcrash_args,
)

from lasso.logging import str_error


Expand Down
1 change: 1 addition & 0 deletions src/lasso/dimred/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .dimred_run import DimredRun, DimredStage


__all__ = ["DimredRun", "DimredStage"]
26 changes: 15 additions & 11 deletions src/lasso/dimred/dimred_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
import shutil
import sys
import time
from collections.abc import Sequence
from concurrent.futures.process import ProcessPoolExecutor
from typing import Union
from collections.abc import Sequence

import h5py
import numpy as np
Expand All @@ -18,7 +18,6 @@
from rich.table import Table
from rich.text import Text

from lasso.utils.rich_progress_bars import PlaceHolderBar, WorkingDots
from lasso.dimred.svd.clustering_betas import (
create_cluster_arg_dict,
create_detector_arg_dict,
Expand All @@ -27,6 +26,8 @@
from lasso.dimred.svd.plot_beta_clusters import plot_clusters_js
from lasso.dimred.svd.pod_functions import calculate_v_and_betas
from lasso.dimred.svd.subsampling_methods import create_reference_subsample, remap_random_subsample
from lasso.utils.rich_progress_bars import PlaceHolderBar, WorkingDots


# pylint: disable = too-many-lines

Expand Down Expand Up @@ -505,7 +506,8 @@ def _parse_part_ids(self, part_ids: Union[Sequence[int], None]) -> Sequence[int]
if not part_ids:
return ()

assert all(isinstance(pid, int) for pid in part_ids), "All part ids must be of type 'int'"
if not all(isinstance(pid, int) for pid in part_ids):
raise TypeError("All part ids must be of type 'int'")

return part_ids

Expand Down Expand Up @@ -583,14 +585,13 @@ def _parse_simulation_and_reference_runs(
self.raise_error(err_msg)

reference_run = os.path.normpath(reference_run_pattern)
# use first simulation run if no reference run was provided
# check if enough simulation runs remain
elif len(simulation_runs) > 1:
reference_run = simulation_runs[0]
else:
# use first simulation run if no reference run was provided
# check if enough simulation runs remain
if len(simulation_runs) > 1:
reference_run = simulation_runs[0]
else:
err_msg = "Number of Simulation runs after using first as reference run is zero."
self.raise_error(err_msg)
err_msg = "Number of Simulation runs after using first as reference run is zero."
self.raise_error(err_msg)

# add to table
table.add_row("reference-run", reference_run)
Expand Down Expand Up @@ -804,7 +805,10 @@ def subsample_to_reference_run(self):
h5_sample.attrs[HDF5FileNames.SUBSAMPLE_PROCESS_TIME.value] = sub[
1
].result()[1]
submitted_samples.pop(i)
# FIXME: loop-iterator-mutation (B909)
# Mutation to loop iterable `submitted_samples` during iteration
# See: https://docs.astral.sh/ruff/rules/loop-iterator-mutation/
submitted_samples.pop(i) # noqa B909
prog.advance(task1) # type: ignore
t_cum_io += sub[1].result()[2]
t_cum += sub[1].result()[1]
Expand Down
6 changes: 4 additions & 2 deletions src/lasso/dimred/graph_laplacian.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ def _laplacian_gauss_idw(
L: array-like, shape (n_points, n_points)
The laplacian matrix for manifold given by its sampling `points`.
"""
assert 2 == points.ndim
if points.ndim != 2:
raise TypeError("Only 2D arrays are supported.")

if min_neighbors is None:
min_neighbors = points.shape[1]
Expand Down Expand Up @@ -110,7 +111,8 @@ def _laplacian_gauss_idw(
graph[i, j] = d = np.exp(d)
graph[j, i] = d[:, np.newaxis]

assert 0 == (graph != graph.T).sum()
if not np.array_equal(graph, graph.T):
raise RuntimeError("graph matrix is not symetric.")

return csgraph.laplacian(graph, normed=True)

Expand Down
21 changes: 16 additions & 5 deletions src/lasso/dimred/hashing.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import multiprocessing
import os
import time
from typing import Union
from collections.abc import Sequence
from typing import Union

import h5py
import numpy as np
Expand Down Expand Up @@ -83,7 +83,10 @@ def is_orientation_flip_required(eigenvectors1: np.ndarray, eigenvectors2: np.nd
The eigenmodes require switching if the dot product of the knn-eigenfields yield
a negative result.
"""
assert eigenvectors1.shape == eigenvectors2.shape
if eigenvectors1.shape != eigenvectors2.shape:
raise AssertionError(
f"shape mismatch detected. {eigenvectors1.shape} not equal to {eigenvectors2.shape}"
)

# one eigenmode only
if eigenvectors1.ndim == 1:
Expand Down Expand Up @@ -133,7 +136,10 @@ def _compute_mode_similarities(

mode_similarities = []
for i_hash, j_hash in matches:
assert hashes1.shape[2] == hashes2.shape[2]
if hashes1.shape[2] != hashes2.shape[2]:
raise AssertionError(
f"Unequal number of columns. {hashes1.shape[2]} is not equal to {hashes2.shape[2]}"
)

field1 = eigenvectors_sub1[:, i_hash]
field2 = eigenvectors_sub2[:, j_hash]
Expand Down Expand Up @@ -238,7 +244,8 @@ def run_hash_comparison(

# pylint: disable = too-many-locals, too-many-statements

assert n_threads > 0
if n_threads <= 0:
raise ValueError("Number of threads cannot be negative or zero.")

# fixed settings
hdf5_dataset_compression = "gzip"
Expand Down Expand Up @@ -621,7 +628,11 @@ def compute_hashes(
For comparison, only y is usually used.
"""

assert eig_vecs.shape[0] == len(result_field), f"{eig_vecs.shape[0]} != {len(result_field)}"
if eig_vecs.shape[0] != len(result_field):
raise AssertionError(
f"Unequal number of rows detected. {eig_vecs.shape[0]} "
f"is not equal to {len(result_field)}"
)

# Note: needs to be vectorized to speed it up

Expand Down
19 changes: 13 additions & 6 deletions src/lasso/dimred/hashing_sphere.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from scipy.stats import binned_statistic_2d
from sklearn.preprocessing import normalize


warnings.simplefilter(action="ignore", category=FutureWarning)


Expand All @@ -31,7 +32,8 @@ def _create_sphere_mesh(diameter: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
beta bin boundaries
"""

assert diameter.dtype == np.float32
if diameter.dtype != np.float32:
raise TypeError("diameter array must be of type `np.float32`.")

# partition latitude
n_alpha = 145
Expand Down Expand Up @@ -59,8 +61,7 @@ def _create_sphere_mesh(diameter: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
bin_beta = 1 - tmp

# In case of trailing floats (-1.00000004 for example)
if bin_beta[-1] < -1:
bin_beta[-1] = -1
bin_beta[-1] = max(bin_beta[-1], -1)

bin_beta = np.arccos(bin_beta)

Expand Down Expand Up @@ -139,10 +140,16 @@ def sphere_hashing(
"""
# bin_numbers holds the bin_number for its respective index and must have
# same length as the number of points
assert len(bin_numbers[0] == len(field))
if not len(bin_numbers[0] == len(field)):
raise AssertionError(
"bin_numbers holds the bin_number for its respective index and"
"must have same length as the number of points."
)
# check data types
assert bin_numbers.dtype == np.int
assert bin_counts.dtype == np.float32
if not np.issubdtype(bin_numbers.dtype, np.integer):
raise TypeError(f"Expected int dtype got {bin_numbers.dtype}")
if not np.issubdtype(bin_counts.dtype, np.floating):
raise TypeError(f"Expected float dtype got {bin_counts.dtype}.")

n_rows = bin_counts.shape[0]
n_cols = bin_counts.shape[1]
Expand Down
Loading