Repository: scikit-build/scikit-build-core
Pull request #544 (2023-11-06 17:51:38)

chore: add a bit to Ruff config
Adding a little and cleaning up. Tested `--preview` mode and made a few changes based on that, too.



Patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index af98d7a..e8de18b 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -22,7 +22,7 @@ repos:
         exclude: "^tests"
 
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    rev: v0.1.3
+    rev: v0.1.4
     hooks:
       - id: ruff
         args: ["--fix", "--show-fixes"]
diff --git a/docs/ext/conftabs.py b/docs/ext/conftabs.py
index 26ebd8b..eb3083d 100644
--- a/docs/ext/conftabs.py
+++ b/docs/ext/conftabs.py
@@ -2,6 +2,7 @@ from __future__ import annotations
 
 import ast
 import textwrap
+from typing import Any
 
 from docutils import nodes
 from docutils.statemachine import StringList
@@ -12,7 +13,7 @@ class ConfTabs(SphinxDirective):
     required_arguments = 2
     final_argument_whitespace = True
 
-    def run(self):
+    def run(self) -> list[nodes.Node]:
         name, result = self.arguments
         env_name = f"SKBUILD_{name.replace('.', '_').replace('-', '_').upper()}"
         value_result = ast.literal_eval(result)
@@ -82,7 +83,7 @@ class ConfTabs(SphinxDirective):
         return [content]
 
 
-def setup(app):
+def setup(app: Any) -> dict[str, Any]:
     app.add_directive("conftabs", ConfTabs)
 
     return {
diff --git a/pyproject.toml b/pyproject.toml
index cc0dbc8..f45991f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -203,48 +203,59 @@ ignore = ["W002"]  # Triggers on __init__.py's
 
 [tool.ruff]
 src = ["src"]
-exclude = []
+exclude = []  # Required due to "build" module
 
 [tool.ruff.lint]
-select = [
-    "E", "F", "W", # flake8
-    "B",           # flake8-bugbear
-    "I",           # isort
+extend-select = [
+    "ANN",         # flake8-annotations
     "ARG",         # flake8-unused-arguments
+    "B",           # flake8-bugbear
     "C4",          # flake8-comprehensions
     "EM",          # flake8-errmsg
+    "FBT",         # flake8-boolean-trap
+    "FLY",         # flynt
+    "I",           # isort
     "ICN",         # flake8-import-conventions
     "ISC",         # flake8-implicit-str-concat
+    "N",           # flake8-naming
+    "PERF",        # perflint
     "PGH",         # pygrep-hooks
     "PIE",         # flake8-pie
     "PL",          # pylint
     "PT",          # flake8-pytest-style
     "PTH",         # flake8-use-pathlib
+    "PYI",         # flake8-pyi
     "RET",         # flake8-return
     "RUF",         # Ruff-specific
+    "S",        # eval -> literal_eval
     "SIM",         # flake8-simplify
-    "TID251",      # flake8-tidy-imports.banned-api
     "T20",         # flake8-print
-    "UP",          # pyupgrade
-    "YTT",         # flake8-2020
-    "ANN204",      # Add -> None to __init__
-    "S307",        # eval -> literal_eval
     "TCH",         # flake8-type-checking
-    "PERF",        # perflint
-    "FLY",         # flynt
+    "TID251",      # flake8-tidy-imports.banned-api
     "TRY",         # tryceratops
-    "FBT",         # flake8-boolean-trap
-    "PYI",         # flake8-pyi
+    "UP",          # pyupgrade
+    "YTT",         # flake8-2020
+    # (in preview till 0.2.0) "FURB",        # refurb
 ]
 ignore = [
-    "PLR",     # Design rules for pylint
     "PLE1205", # Format check doesn't work with our custom logger
-    "E501",    # Line too long
     "PT004",   # Incorrect, just usefixtures instead.
     "RUF009",  # Too easy to get a false positive
     "PYI025",  # Wants Set to be renamed AbstractSet
+    "ISC001",  # Conflicts with formatter
+    "PLR0911", # Too many return statements
+    "PLR0912", # Too many branches
+    "PLR0913", # Too many arguments
+    "PLR0915", # Too many local statements
+    "PLR2004", # Magic value used in comparison
+    "PLC0415", # Import should be at top of file
+    "ANN101",  # Missing type annotation for `self` in method
+    "ANN102",  # Missing type annotation for `cls` in classmethod
+    "ANN401",  # Disallow dynamically typed expressions
+    "S101",    # Use of assert detected
+    "S603",    # subprocess untrusted input
+    "S607",    # subprocess call
 ]
-unfixable = ["T20", "F841"]
 typing-modules = ["scikit_build_core._compat.typing"]
 
 [tool.ruff.lint.flake8-tidy-imports.banned-api]
@@ -272,13 +283,15 @@ typing-modules = ["scikit_build_core._compat.typing"]
 
 
 [tool.ruff.lint.per-file-ignores]
-"tests/**" = ["T20"]
+"tests/**" = ["T20", "ANN"]
 "noxfile.py" = ["T20", "TID251"]
 "src/scikit_build_core/resources/*.py" = ["PTH", "ARG002", "FBT", "TID251"]
 "src/scikit_build_core/_compat/**.py" = ["TID251"]
 "tests/conftest.py" = ["TID251"]
 "tests/packages/**.py" = ["TID251"]
 "docs/conf.py" = ["TID251"]
+"docs/examples/**" = ["ANN"]
+"src/scikit_build_core/file_api/model/*.py" = ["N"]
 
 
 [tool.check-sdist]
diff --git a/src/scikit_build_core/__init__.py b/src/scikit_build_core/__init__.py
index 7b3d6eb..8f728ef 100644
--- a/src/scikit_build_core/__init__.py
+++ b/src/scikit_build_core/__init__.py
@@ -4,7 +4,6 @@ Copyright (c) 2022 Henry Schreiner. All rights reserved.
 scikit-build-core: PEP 517 builder for Scikit-Build
 """
 
-
 from __future__ import annotations
 
 from ._version import version as __version__
diff --git a/src/scikit_build_core/_compat/typing.py b/src/scikit_build_core/_compat/typing.py
index 2394775..171dea7 100644
--- a/src/scikit_build_core/_compat/typing.py
+++ b/src/scikit_build_core/_compat/typing.py
@@ -19,7 +19,7 @@ if sys.version_info < (3, 11):
     else:
         Self = object
 
-        def assert_never(_: typing.Any) -> None:
+        def assert_never(_: object) -> None:
             msg = "Expected code to be unreachable"
             raise AssertionError(msg)
 
diff --git a/src/scikit_build_core/_logging.py b/src/scikit_build_core/_logging.py
index 0cf84cb..d889418 100644
--- a/src/scikit_build_core/_logging.py
+++ b/src/scikit_build_core/_logging.py
@@ -69,10 +69,10 @@ class ScikitBuildLogger:
     def log(self, level: int, msg: str, *args: object, **kwargs: object) -> None:
         self.logger.log(level, FStringMessage(msg, *args, **kwargs), **opts)
 
-    def setLevel(self, level: int) -> None:
+    def setLevel(self, level: int) -> None:  # noqa: N802
         self.logger.setLevel(level)
 
-    def addHandler(self, handler: logging.Handler) -> None:
+    def addHandler(self, handler: logging.Handler) -> None:  # noqa: N802
         self.logger.addHandler(handler)
 
 
diff --git a/src/scikit_build_core/build/__init__.py b/src/scikit_build_core/build/__init__.py
index 70c68a8..af56207 100644
--- a/src/scikit_build_core/build/__init__.py
+++ b/src/scikit_build_core/build/__init__.py
@@ -2,7 +2,6 @@
 This is the entry point for the build backend. Items in this module are designed for the build backend API.
 """
 
-
 from __future__ import annotations
 
 import sys
diff --git a/src/scikit_build_core/builder/wheel_tag.py b/src/scikit_build_core/builder/wheel_tag.py
index b86d81b..9f28381 100644
--- a/src/scikit_build_core/builder/wheel_tag.py
+++ b/src/scikit_build_core/builder/wheel_tag.py
@@ -116,7 +116,7 @@ class WheelTag:
 
     def as_tags_set(self) -> frozenset[packaging.tags.Tag]:
         vals = itertools.product(self.pyvers, self.abis, self.archs)
-        return frozenset(packaging.tags.Tag(*v) for v in vals)
+        return frozenset(itertools.starmap(packaging.tags.Tag, vals))
 
 
 if __name__ == "__main__":
diff --git a/src/scikit_build_core/file_api/reply.py b/src/scikit_build_core/file_api/reply.py
index 153bf9b..3e061b8 100644
--- a/src/scikit_build_core/file_api/reply.py
+++ b/src/scikit_build_core/file_api/reply.py
@@ -50,7 +50,7 @@ class Converter:
         Convert a dict to a dataclass. Automatically load a few nested jsonFile classes.
         """
         if (
-            target in (CodeModel, Target, Cache, CMakeFiles, Directory)
+            target in {CodeModel, Target, Cache, CMakeFiles, Directory}
             and "jsonFile" in data
             and data["jsonFile"] is not None
         ):
@@ -91,9 +91,9 @@ class Converter:
             return self.make_class(item, target)  # type: ignore[return-value]
         origin = get_origin(target)
         if origin is not None:
-            if origin == list:
+            if origin is list:
                 return [self._convert_any(i, get_args(target)[0]) for i in item]  # type: ignore[return-value]
-            if origin == Union:
+            if origin is Union:
                 return self._convert_any(item, get_args(target)[0])  # type: ignore[no-any-return]
 
         return target(item)  # type: ignore[call-arg]
diff --git a/src/scikit_build_core/resources/_editable_redirect.py b/src/scikit_build_core/resources/_editable_redirect.py
index 9f0ddac..a2e5fb6 100644
--- a/src/scikit_build_core/resources/_editable_redirect.py
+++ b/src/scikit_build_core/resources/_editable_redirect.py
@@ -15,7 +15,7 @@ if TYPE_CHECKING:
     else:
         from typing import TypedDict
 
-    class KWDict_1(TypedDict, total=False):
+    class KWDict_1(TypedDict, total=False):  # noqa: N801
         submodule_search_locations: list[str]
 
 else:
diff --git a/src/scikit_build_core/settings/json_schema.py b/src/scikit_build_core/settings/json_schema.py
index 637e5f8..23d6548 100644
--- a/src/scikit_build_core/settings/json_schema.py
+++ b/src/scikit_build_core/settings/json_schema.py
@@ -11,14 +11,14 @@ from .._compat.builtins import ExceptionGroup
 from .._compat.typing import Literal, get_args, get_origin
 from .documentation import pull_docs
 
-__all__ = ["to_json_schema", "convert_type", "FailedConversion"]
+__all__ = ["to_json_schema", "convert_type", "FailedConversionError"]
 
 
 def __dir__() -> list[str]:
     return __all__
 
 
-class FailedConversion(TypeError):
+class FailedConversionError(TypeError):
     pass
 
 
@@ -36,7 +36,7 @@ def to_json_schema(dclass: type[Any], *, normalize_keys: bool) -> dict[str, Any]
 
         try:
             props[field.name] = convert_type(field.type, normalize_keys=normalize_keys)
-        except FailedConversion as err:
+        except FailedConversionError as err:
             if sys.version_info < (3, 11):
                 notes = "__notes__"  # set so linter's won't try to be clever
                 setattr(err, notes, [*getattr(err, notes, []), f"Field: {field.name}"])
@@ -119,4 +119,4 @@ def convert_type(t: Any, *, normalize_keys: bool) -> dict[str, Any]:
         return {"enum": list(args)}
 
     msg = f"Cannot convert type {t} to JSON Schema"
-    raise FailedConversion(msg)
+    raise FailedConversionError(msg)
diff --git a/src/scikit_build_core/settings/sources.py b/src/scikit_build_core/settings/sources.py
index 19e9856..395fde4 100644
--- a/src/scikit_build_core/settings/sources.py
+++ b/src/scikit_build_core/settings/sources.py
@@ -43,7 +43,6 @@ These are supported for JSON schema generation for the TOML, as well.
 Integers/floats would be easy to add, but haven't been needed yet.
 """
 
-
 from __future__ import annotations
 
 import dataclasses
@@ -125,9 +124,9 @@ def _get_inner_type(__target: type[Any]) -> type[Any]:
 
     raw_target = _get_target_raw_type(__target)
     target = _process_union(__target)
-    if raw_target == list:
+    if raw_target is list:
         return get_args(target)[0]  # type: ignore[no-any-return]
-    if raw_target == dict:
+    if raw_target is dict:
         return get_args(target)[1]  # type: ignore[no-any-return]
     msg = f"Expected a list or dict, got {target!r}"
     raise AssertionError(msg)
@@ -219,11 +218,11 @@ class EnvSource:
         if dataclasses.is_dataclass(raw_target):
             msg = f"Array of dataclasses are not supported in configuration settings ({raw_target})"
             raise TypeError(msg)
-        if raw_target == list:
+        if raw_target is list:
             return [
                 cls.convert(i.strip(), _get_inner_type(target)) for i in item.split(";")
             ]
-        if raw_target == dict:
+        if raw_target is dict:
             items = (i.strip().split("=") for i in item.split(";"))
             return {k: cls.convert(v, _get_inner_type(target)) for k, v in items}
 
@@ -334,7 +333,7 @@ class ConfSource:
         if dataclasses.is_dataclass(raw_target):
             msg = f"Array of dataclasses are not supported in configuration settings ({raw_target})"
             raise TypeError(msg)
-        if raw_target == list:
+        if raw_target is list:
             if isinstance(item, list):
                 return [cls.convert(i, _get_inner_type(target)) for i in item]
             if isinstance(item, dict):
@@ -343,7 +342,7 @@ class ConfSource:
             return [
                 cls.convert(i.strip(), _get_inner_type(target)) for i in item.split(";")
             ]
-        if raw_target == dict:
+        if raw_target is dict:
             assert not isinstance(item, (str, list))
             return {k: cls.convert(v, _get_inner_type(target)) for k, v in item.items()}
         if isinstance(item, (list, dict)):
@@ -379,7 +378,7 @@ class ConfSource:
                 except KeyError:
                     yield keystr
                     continue
-            if _get_target_raw_type(outer_option) == dict:
+            if _get_target_raw_type(outer_option) is dict:
                 continue
 
     def all_option_names(self, target: type[Any]) -> Iterator[str]:
@@ -393,7 +392,8 @@ class TOMLSource:
         self.prefixes = prefixes
         self.settings = _dig_not_strict(settings, *prefixes)
 
-    def _get_name(self, *fields: str) -> list[str]:
+    @staticmethod
+    def _get_name(*fields: str) -> list[str]:
         return [field.replace("_", "-") for field in fields]
 
     def has_item(self, *fields: str, is_dict: bool) -> bool:  # noqa: ARG002
@@ -500,7 +500,7 @@ class SourceChain:
                     errors.append(e)
                 continue
 
-            is_dict = _get_target_raw_type(field.type) == dict
+            is_dict = _get_target_raw_type(field.type) is dict
 
             for source in self.sources:
                 if source.has_item(*prefixes, field.name, is_dict=is_dict):


Test patch:
diff --git a/tests/test_fileapi.py b/tests/test_fileapi.py
index fbd307e..658f8b8 100644
--- a/tests/test_fileapi.py
+++ b/tests/test_fileapi.py
@@ -106,7 +106,7 @@ def test_included_dir():
     assert codemodel.kind == "codemodel"
     assert codemodel.version.major == 2
     assert codemodel.version.minor == 4
-    assert codemodel.configurations[0].name == ""
+    assert not codemodel.configurations[0].name
 
     cache = index.reply.cache_v2
     assert cache is not None
diff --git a/tests/test_get_requires.py b/tests/test_get_requires.py
index 60ab0e6..a3001ac 100644
--- a/tests/test_get_requires.py
+++ b/tests/test_get_requires.py
@@ -20,7 +20,7 @@ ninja = [] if sysconfig.get_platform().startswith("win") else ["ninja>=1.5"]
 
 
 def which_mock(name: str) -> str | None:
-    if name in ("ninja", "ninja-build", "cmake3", "samu", "gmake", "make"):
+    if name in {"ninja", "ninja-build", "cmake3", "samu", "gmake", "make"}:
         return None
     if name == "cmake":
         return "cmake/path"
diff --git a/tests/test_json_schema.py b/tests/test_json_schema.py
index 1541161..d1b9f96 100644
--- a/tests/test_json_schema.py
+++ b/tests/test_json_schema.py
@@ -4,7 +4,7 @@ from typing import Any, Dict, List, Optional, Union
 import pytest
 from packaging.version import Version
 
-from scikit_build_core.settings.json_schema import FailedConversion, convert_type
+from scikit_build_core.settings.json_schema import FailedConversionError, convert_type
 
 
 def test_convert_str():
@@ -57,5 +57,5 @@ def test_convert_dict():
 
 
 def test_convert_invalid():
-    with pytest.raises(FailedConversion):
+    with pytest.raises(FailedConversionError):
         convert_type(object, normalize_keys=False)