From e36a992d0d8a2b3d9868f4d669162a51d45e5411 Mon Sep 17 00:00:00 2001
From: Alexandru Fikl <alexfikl@gmail.com>
Date: Wed, 3 Jul 2024 19:41:06 +0300
Subject: [PATCH] pyproject: add and fix ruff RUF issues

---
 pyproject.toml                       |  1 +
 pytools/__init__.py                  | 43 ++++++++++++++--------------
 pytools/batchjob.py                  |  8 +++---
 pytools/datatable.py                 | 13 +++++----
 pytools/debug.py                     |  2 +-
 pytools/graph.py                     |  2 +-
 pytools/lex.py                       |  2 +-
 pytools/spatial_btree.py             |  2 +-
 pytools/tag.py                       |  4 +--
 pytools/test/test_graph_tools.py     |  2 +-
 pytools/test/test_persistent_dict.py |  2 +-
 11 files changed, 42 insertions(+), 39 deletions(-)

diff --git a/pyproject.toml b/pyproject.toml
index 80e34ff..b88601d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -78,6 +78,7 @@ extend-select = [
     "NPY", # numpy
     "Q",   # flake8-quotes
     "UP",  # pyupgrade
+    "RUF", # ruff
     "W",   # pycodestyle
 ]
 extend-ignore = [
diff --git a/pytools/__init__.py b/pytools/__init__.py
index 04a9013..e4c4b50 100644
--- a/pytools/__init__.py
+++ b/pytools/__init__.py
@@ -525,9 +525,10 @@ class ImmutableRecordWithoutPickling(RecordWithoutPickling):
     def __hash__(self):
         # This attribute may vanish during pickling.
         if getattr(self, "_cached_hash", None) is None:
-            self._cached_hash = hash(
-                (type(self),) + tuple(getattr(self, field)
-                    for field in self.__class__.fields))
+            self._cached_hash = hash((
+                    type(self),
+                    *(getattr(self, field) for field in self.__class__.fields)
+                    ))
 
         return self._cached_hash
 
@@ -706,7 +707,7 @@ def memoize(*args: F, **kwargs: Any) -> F:
     default_key_func: Optional[Callable[..., Any]]
 
     if use_kw:
-        def default_key_func(*inner_args, **inner_kwargs):  # noqa pylint:disable=function-redefined
+        def default_key_func(*inner_args, **inner_kwargs):  # pylint:disable=function-redefined
             return inner_args, frozenset(inner_kwargs.items())
     else:
         default_key_func = None
@@ -723,15 +724,15 @@ def memoize(*args: F, **kwargs: Any) -> F:
             def wrapper(*args, **kwargs):
                 key = key_func(*args, **kwargs)
                 try:
-                    return func._memoize_dic[key]  # noqa: E501 # pylint: disable=protected-access
+                    return func._memoize_dic[key]  # pylint: disable=protected-access
                 except AttributeError:
                     # _memoize_dic doesn't exist yet.
                     result = func(*args, **kwargs)
-                    func._memoize_dic = {key: result}  # noqa: E501 # pylint: disable=protected-access
+                    func._memoize_dic = {key: result}  # pylint: disable=protected-access
                     return result
                 except KeyError:
                     result = func(*args, **kwargs)
-                    func._memoize_dic[key] = result  # noqa: E501 # pylint: disable=protected-access
+                    func._memoize_dic[key] = result  # pylint: disable=protected-access
                     return result
 
             from functools import update_wrapper
@@ -742,15 +743,15 @@ def memoize(*args: F, **kwargs: Any) -> F:
         def _decorator(func):
             def wrapper(*args):
                 try:
-                    return func._memoize_dic[args]  # noqa: E501 # pylint: disable=protected-access
+                    return func._memoize_dic[args]  # pylint: disable=protected-access
                 except AttributeError:
                     # _memoize_dic doesn't exist yet.
                     result = func(*args)
-                    func._memoize_dic = {args: result}  # noqa: E501 # pylint:disable=protected-access
+                    func._memoize_dic = {args: result}  # pylint:disable=protected-access
                     return result
                 except KeyError:
                     result = func(*args)
-                    func._memoize_dic[args] = result  # noqa: E501 # pylint: disable=protected-access
+                    func._memoize_dic[args] = result  # pylint: disable=protected-access
                     return result
 
             from functools import update_wrapper
@@ -788,7 +789,7 @@ def memoize_on_first_arg(
 
     def wrapper(obj: T, *args: P.args, **kwargs: P.kwargs) -> R:
         if kwargs:
-            key = (_HasKwargs, frozenset(kwargs.items())) + args
+            key = (_HasKwargs, frozenset(kwargs.items()), *args)
         else:
             key = args
 
@@ -1309,7 +1310,7 @@ def cartesian_product(*args):
     first = args[:-1]
     for prod in cartesian_product(*first):
         for i in args[-1]:
-            yield prod + (i,)
+            yield (*prod, i)
 
 
 def distinct_pairs(list1, list2):
@@ -1423,7 +1424,7 @@ def indices_in_shape(shape):
         remainder = shape[1:]
         for i in range(0, shape[0]):
             for rest in indices_in_shape(remainder):
-                yield (i,)+rest
+                yield (i, *rest)
 
 
 def generate_nonnegative_integer_tuples_below(n, length=None, least=0):
@@ -1470,7 +1471,7 @@ def generate_decreasing_nonnegative_tuples_summing_to(
             # print "SIG", sig, i
             for remainder in generate_decreasing_nonnegative_tuples_summing_to(
                     n-i, length-1, min_value, i):
-                yield (i,) + remainder
+                yield (i, *remainder)
 
 
 def generate_nonnegative_integer_tuples_summing_to_at_most(n, length):
@@ -1485,7 +1486,7 @@ def generate_nonnegative_integer_tuples_summing_to_at_most(n, length):
         for i in range(n+1):
             for remainder in generate_nonnegative_integer_tuples_summing_to_at_most(
                     n-i, length-1):
-                yield remainder + (i,)
+                yield (*remainder, i)
 
 
 # backwards compatibility
@@ -1544,7 +1545,7 @@ def enumerate_basic_directions(dimensions):
 
 # {{{ graph algorithms
 
-from pytools.graph import a_star as a_star_moved  # noqa: E402
+from pytools.graph import a_star as a_star_moved
 
 
 a_star = MovedFunctionDeprecationWrapper(a_star_moved)
@@ -1665,7 +1666,7 @@ class Table:
             :--|-------:
             10 | 20\|\|
 
-        """  # noqa: W605
+        """
         if not self.rows:
             return ""
 
@@ -1823,7 +1824,7 @@ def string_histogram(  # pylint: disable=too-many-arguments,too-many-locals
 
     from bisect import bisect
     for value in iterable:
-        if max_value is not None and value > max_value or value < bin_starts[0]:
+        if (max_value is not None and value > max_value) or value < bin_starts[0]:
             from warnings import warn
             warn("string_histogram: out-of-bounds value ignored", stacklevel=2)
         else:
@@ -2330,7 +2331,7 @@ class UniqueNameGenerator:
 
         # }}}
 
-        for counter, var_name in generate_numbered_unique_names(based_on, counter):  # noqa: B020,B007,E501
+        for counter, var_name in generate_numbered_unique_names(based_on, counter):  # noqa: B020,B007
             if not self.is_name_conflicting(var_name):
                 break
 
@@ -2450,7 +2451,7 @@ def find_git_revision(tree_root):  # pylint: disable=too-many-locals
 
 def find_module_git_revision(module_file, n_levels_up):
     from os.path import dirname, join
-    tree_root = join(*([dirname(module_file)] + [".." * n_levels_up]))
+    tree_root = join(*([dirname(module_file), ".." * n_levels_up]))
 
     return find_git_revision(tree_root)
 
@@ -2895,7 +2896,7 @@ def sphere_sample_fibonacci(
         lattice.
 
     :returns: an :class:`~numpy.ndarray` of shape ``(3, npoints)``.
-    """     # noqa: E501
+    """
 
     import numpy as np
     if optimize is None:
diff --git a/pytools/batchjob.py b/pytools/batchjob.py
index 780efed..90400b4 100644
--- a/pytools/batchjob.py
+++ b/pytools/batchjob.py
@@ -60,7 +60,7 @@ class BatchJob:
         setup.close()
 
 
-class INHERIT:  # noqa
+class INHERIT:
     pass
 
 
@@ -86,7 +86,7 @@ class GridEngineJob(BatchJob):
 
         args.extend(extra_args)
 
-        subproc = Popen(["qsub"] + args + ["run.sh"], cwd=self.path)
+        subproc = Popen(["qsub", *args, "run.sh"], cwd=self.path)
         if subproc.wait() != 0:
             raise RuntimeError(f"Process submission of {self.moniker} failed")
 
@@ -114,7 +114,7 @@ class PBSJob(BatchJob):
 
         args.extend(extra_args)
 
-        subproc = Popen(["qsub"] + args + ["run.sh"], cwd=self.path)
+        subproc = Popen(["qsub", *args, "run.sh"], cwd=self.path)
         if subproc.wait() != 0:
             raise RuntimeError(f"Process submission of {self.moniker} failed")
 
@@ -145,7 +145,7 @@ class ConstructorPlaceholder:
         return "{}({})".format(self.classname,
                 ",".join(
                     [str(arg) for arg in self.args]
-                    + [f"{kw}={repr(val)}"
+                    + [f"{kw}={val!r}"
                         for kw, val in self.kwargs.items()]
                     )
                 )
diff --git a/pytools/datatable.py b/pytools/datatable.py
index 2f36e22..701fb7e 100644
--- a/pytools/datatable.py
+++ b/pytools/datatable.py
@@ -164,7 +164,7 @@ class DataTable:
             this_values = tuple(row[i] for i in gb_indices)
             if first or this_values != last_values:
                 if not first:
-                    result_data.append(last_values + (aggregate_func(agg_values),))
+                    result_data.append((*last_values, aggregate_func(agg_values)))
 
                 agg_values = [row[agg_index]]
                 last_values = this_values
@@ -173,7 +173,7 @@ class DataTable:
                 agg_values.append(row[agg_index])
 
         if not first and agg_values:
-            result_data.append(this_values + (aggregate_func(agg_values),))
+            result_data.append((*this_values, aggregate_func(agg_values)))
 
         return DataTable(
                 [self.column_names[i] for i in gb_indices] + [agg_column],
@@ -243,7 +243,7 @@ class DataTable:
                 if outer:
                     this_batch = [(None,) * len(self.column_names)]
 
-            if run_other and not other_over:  # pylint: disable=used-before-assignment  # noqa: E501
+            if run_other and not other_over:  # pylint: disable=used-before-assignment
                 key = other_key
                 while other_row[other_key_idx] == other_key:
                     other_batch.append(other_row)
@@ -258,9 +258,10 @@ class DataTable:
 
             for this_batch_row in this_batch:
                 for other_batch_row in other_batch:
-                    result_data.append((key,)
-                            + without(this_batch_row, this_key_idx)
-                            + without(other_batch_row, other_key_idx))
+                    result_data.append((
+                            key,
+                            *without(this_batch_row, this_key_idx),
+                            *without(other_batch_row, other_key_idx)))
 
             if outer:
                 if this_over and other_over:
diff --git a/pytools/debug.py b/pytools/debug.py
index b4923f6..3fce9d3 100644
--- a/pytools/debug.py
+++ b/pytools/debug.py
@@ -55,7 +55,7 @@ class RefDebugQuit(Exception):  # noqa: N818
     pass
 
 
-def refdebug(obj, top_level=True, exclude=()):  # noqa: E501  pylint:disable=too-many-locals,too-many-branches,too-many-statements
+def refdebug(obj, top_level=True, exclude=()):  # pylint:disable=too-many-locals,too-many-branches,too-many-statements
     from types import FrameType
 
     def is_excluded(o):
diff --git a/pytools/graph.py b/pytools/graph.py
index 2725bd4..788f600 100644
--- a/pytools/graph.py
+++ b/pytools/graph.py
@@ -137,7 +137,7 @@ def a_star(  # pylint: disable=too-many-locals
                 return 0
 
     class AStarNode:
-        __slots__ = ["state", "parent", "path_cost"]
+        __slots__ = ["parent", "path_cost", "state"]
 
         def __init__(self, state: NodeT, parent: Any, path_cost: float) -> None:
             self.state = state
diff --git a/pytools/lex.py b/pytools/lex.py
index e757d24..2a93501 100644
--- a/pytools/lex.py
+++ b/pytools/lex.py
@@ -151,7 +151,7 @@ class LexIterator:
     def expected(self, what_expected):
         if self.is_at_end():
             self.raise_parse_error(
-                    "{what_expected} expected, end of input found instead")
+                    f"{what_expected} expected, end of input found instead")
         else:
             self.raise_parse_error(
                     f"{what_expected} expected, {self.next_tag()} found instead")
diff --git a/pytools/spatial_btree.py b/pytools/spatial_btree.py
index 5b3634f..435ac46 100644
--- a/pytools/spatial_btree.py
+++ b/pytools/spatial_btree.py
@@ -103,7 +103,7 @@ class SpatialBinaryTreeBucket:
             # No subdivisions yet.
             if len(self.elements) > self.max_elements_per_box:
                 # Too many elements. Need to subdivide.
-                self.all_buckets = []  # noqa: E501 pylint:disable=attribute-defined-outside-init
+                self.all_buckets = []  # pylint:disable=attribute-defined-outside-init
                 self.buckets = make_buckets(
                         self.bottom_left, self.top_right,
                         self.all_buckets,
diff --git a/pytools/tag.py b/pytools/tag.py
index 2130e04..ed337a6 100644
--- a/pytools/tag.py
+++ b/pytools/tag.py
@@ -29,7 +29,7 @@ Internal stuff that is only here because the documentation tool wants it
 """
 
 from dataclasses import dataclass
-from typing import (  # noqa: F401
+from typing import (
     Any,
     FrozenSet,
     Iterable,
@@ -285,7 +285,7 @@ class Taggable:
         # mypy is right: we're not promising this attribute is defined.
         # Once this deprecation expires, this will go back to being an
         # abstract method.
-        return self.copy(tags=tags)  # type: ignore[attr-defined]  # pylint: disable=no-member  # noqa: E501
+        return self.copy(tags=tags)  # type: ignore[attr-defined]  # pylint: disable=no-member
 
     def tagged(self: _Self_Taggable, tags: ToTagSetConvertible) -> _Self_Taggable:
         """
diff --git a/pytools/test/test_graph_tools.py b/pytools/test/test_graph_tools.py
index 688c6e4..a98986e 100644
--- a/pytools/test/test_graph_tools.py
+++ b/pytools/test/test_graph_tools.py
@@ -30,7 +30,7 @@ def test_compute_sccs():
                 result = []
                 for child in graph[node]:
                     result = result + visit(child)
-                return result + [node]
+                return [*result, node]
 
         for scc in sccs:
             scc = set(scc)
diff --git a/pytools/test/test_persistent_dict.py b/pytools/test/test_persistent_dict.py
index 858f22f..c4d3639 100644
--- a/pytools/test/test_persistent_dict.py
+++ b/pytools/test/test_persistent_dict.py
@@ -1,5 +1,5 @@
 import shutil
-import sys  # noqa
+import sys
 import tempfile
 from dataclasses import dataclass
 from enum import Enum, IntEnum
-- 
GitLab