diff --git a/pyproject.toml b/pyproject.toml index 4a7e58fdb..2021df4cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -133,6 +133,7 @@ select = [ "F", # pyflakes "I", # isort "UP", # pyupgrade + "RUF", # ruff "W", # pycodestyle ] ignore = [ @@ -156,6 +157,12 @@ ignore = [ "D402", # First line should not be the function's signature "D404", # First word of the docstring should not be "This" "D415", # First line should end with a period, question mark, or exclamation point + # ruff ignore + "RUF001", # String contains ambiguous character + "RUF003", # Comment contains ambiguous character + "RUF005", # Consider `(x, *y)` instead of concatenation + "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar` + "RUF015", # Prefer `next(iter(x))` over single element slice ] [tool.ruff.format] diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index 0662eb8cb..12168be60 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -1018,7 +1018,7 @@ class FormattedExcinfo: extraline: Optional[str] = ( "!!! Recursion error detected, but an error occurred locating the origin of recursion.\n" " The following exception happened when comparing locals in the stack frame:\n" - f" {type(e).__name__}: {str(e)}\n" + f" {type(e).__name__}: {e!s}\n" f" Displaying first and last {max_frames} stack frames out of {len(traceback)}." ) # Type ignored because adding two instances of a List subtype diff --git a/src/_pytest/_py/path.py b/src/_pytest/_py/path.py index af02d67b9..554cb4a67 100644 --- a/src/_pytest/_py/path.py +++ b/src/_pytest/_py/path.py @@ -1105,9 +1105,7 @@ class LocalPath: modname = self.purebasename spec = importlib.util.spec_from_file_location(modname, str(self)) if spec is None or spec.loader is None: - raise ImportError( - f"Can't find module {modname} at location {str(self)}" - ) + raise ImportError(f"Can't find module {modname} at location {self!s}") mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) return mod diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index 32e635255..dbe22e4aa 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -27,7 +27,7 @@ _S = TypeVar("_S") # https://www.python.org/dev/peps/pep-0484/#support-for-singleton-types-in-unions class NotSetType(enum.Enum): token = 0 -NOTSET: Final = NotSetType.token # noqa: E305 +NOTSET: Final = NotSetType.token # fmt: on diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 8c2f05239..f5efc8ec9 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -671,7 +671,7 @@ class PytestPluginManager(PluginManager): if dirpath in path.parents or path == dirpath: if mod in mods: raise AssertionError( - f"While trying to load conftest path {str(conftestpath)}, " + f"While trying to load conftest path {conftestpath!s}, " f"found that the module {mod} is already loaded with path {mod.__file__}. " "This is not supposed to happen. Please report this issue to pytest." ) diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index a4e03f80c..b0bbc0e04 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -1225,7 +1225,7 @@ def fixture( @overload -def fixture( # noqa: F811 +def fixture( fixture_function: None = ..., *, scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ..., @@ -1239,7 +1239,7 @@ def fixture( # noqa: F811 ... -def fixture( # noqa: F811 +def fixture( fixture_function: Optional[FixtureFunction] = None, *, scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = "function", @@ -1673,7 +1673,7 @@ class FixtureManager: raise NotImplementedError() @overload - def parsefactories( # noqa: F811 + def parsefactories( self, node_or_obj: object, nodeid: Optional[str], @@ -1682,7 +1682,7 @@ class FixtureManager: ) -> None: raise NotImplementedError() - def parsefactories( # noqa: F811 + def parsefactories( self, node_or_obj: Union[nodes.Node, object], nodeid: Union[str, NotSetType, None] = NOTSET, diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index 7a952231c..51becf97b 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -375,7 +375,7 @@ def record_testsuite_property(request: FixtureRequest) -> Callable[[str, object] xml = request.config.stash.get(xml_key, None) if xml is not None: - record_func = xml.add_global_property # noqa + record_func = xml.add_global_property return record_func diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 4907a4256..c9ef877d7 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -726,12 +726,12 @@ class Session(nodes.Collector): ... @overload - def perform_collect( # noqa: F811 + def perform_collect( self, args: Optional[Sequence[str]] = ..., genitems: bool = ... ) -> Sequence[Union[nodes.Item, nodes.Collector]]: ... - def perform_collect( # noqa: F811 + def perform_collect( self, args: Optional[Sequence[str]] = None, genitems: bool = True ) -> Sequence[Union[nodes.Item, nodes.Collector]]: """Perform the collection phase for this session. diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index 7c8501d73..5a7f9b202 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -406,7 +406,7 @@ def normalize_mark_list( for mark in mark_list: mark_obj = getattr(mark, "mark", mark) if not isinstance(mark_obj, Mark): - raise TypeError(f"got {repr(mark_obj)} instead of Mark") + raise TypeError(f"got {mark_obj!r} instead of Mark") yield mark_obj diff --git a/src/_pytest/python.py b/src/_pytest/python.py index d0d744733..a5ae48134 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -358,7 +358,7 @@ class PyobjMixin(nodes.Node): # hook is not called for them. # fmt: off class _EmptyClass: pass # noqa: E701 -IGNORED_ATTRIBUTES = frozenset.union( # noqa: E305 +IGNORED_ATTRIBUTES = frozenset.union( frozenset(), # Module. dir(types.ModuleType("empty_module")), diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index bd3de2897..336b052fc 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -730,7 +730,7 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase: # Type ignored because the error is wrong -- not unreachable. and not isinstance(expected, STRING_TYPES) # type: ignore[unreachable] ): - msg = f"pytest.approx() only supports ordered sequences, but got: {repr(expected)}" + msg = f"pytest.approx() only supports ordered sequences, but got: {expected!r}" raise TypeError(msg) else: cls = ApproxScalar @@ -780,7 +780,7 @@ def raises( @overload -def raises( # noqa: F811 +def raises( expected_exception: Union[Type[E], Tuple[Type[E], ...]], func: Callable[..., Any], *args: Any, @@ -789,7 +789,7 @@ def raises( # noqa: F811 ... -def raises( # noqa: F811 +def raises( expected_exception: Union[Type[E], Tuple[Type[E], ...]], *args: Any, **kwargs: Any ) -> Union["RaisesContext[E]", _pytest._code.ExceptionInfo[E]]: r"""Assert that a code block/function call raises an exception type, or one of its subclasses. diff --git a/src/_pytest/recwarn.py b/src/_pytest/recwarn.py index ddd4c9a7b..40f6d2e5b 100644 --- a/src/_pytest/recwarn.py +++ b/src/_pytest/recwarn.py @@ -47,13 +47,11 @@ def deprecated_call( @overload -def deprecated_call( # noqa: F811 - func: Callable[..., T], *args: Any, **kwargs: Any -) -> T: +def deprecated_call(func: Callable[..., T], *args: Any, **kwargs: Any) -> T: ... -def deprecated_call( # noqa: F811 +def deprecated_call( func: Optional[Callable[..., Any]] = None, *args: Any, **kwargs: Any ) -> Union["WarningsRecorder", Any]: """Assert that code produces a ``DeprecationWarning`` or ``PendingDeprecationWarning`` or ``FutureWarning``. @@ -97,7 +95,7 @@ def warns( @overload -def warns( # noqa: F811 +def warns( expected_warning: Union[Type[Warning], Tuple[Type[Warning], ...]], func: Callable[..., T], *args: Any, @@ -106,7 +104,7 @@ def warns( # noqa: F811 ... -def warns( # noqa: F811 +def warns( expected_warning: Union[Type[Warning], Tuple[Type[Warning], ...]] = Warning, *args: Any, match: Optional[Union[str, Pattern[str]]] = None, diff --git a/testing/_py/test_local.py b/testing/_py/test_local.py index 57c953f17..11519c7c1 100644 --- a/testing/_py/test_local.py +++ b/testing/_py/test_local.py @@ -17,7 +17,7 @@ import pytest def ignore_encoding_warning(): with warnings.catch_warnings(): with contextlib.suppress(NameError): # new in 3.10 - warnings.simplefilter("ignore", EncodingWarning) # type: ignore [name-defined] # noqa: F821 + warnings.simplefilter("ignore", EncodingWarning) # type: ignore [name-defined] yield diff --git a/testing/logging/test_reporting.py b/testing/logging/test_reporting.py index 7ef334950..24eae19b7 100644 --- a/testing/logging/test_reporting.py +++ b/testing/logging/test_reporting.py @@ -1032,7 +1032,7 @@ def test_log_set_path(pytester: Pytester) -> None: def pytest_runtest_setup(item): config = item.config logging_plugin = config.pluginmanager.get_plugin("logging-plugin") - report_file = os.path.join({repr(report_dir_base)}, item._request.node.name) + report_file = os.path.join({report_dir_base!r}, item._request.node.name) logging_plugin.set_log_path(report_file) return (yield) """ diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py index 62f25cb0b..432c46e8d 100644 --- a/testing/python/fixtures.py +++ b/testing/python/fixtures.py @@ -3086,7 +3086,7 @@ class TestFixtureMarker: def test_other(): pass """ # noqa: UP031 (python syntax issues) - % {"scope": scope} # noqa: UP031 (python syntax issues) + % {"scope": scope} ) reprec = pytester.inline_run("-lvs") reprec.assertoutcome(passed=3) diff --git a/testing/python/raises.py b/testing/python/raises.py index 35d7f1a44..ef6607d96 100644 --- a/testing/python/raises.py +++ b/testing/python/raises.py @@ -147,7 +147,7 @@ class TestRaises: try: pytest.raises(ValueError, int, "0") except pytest.fail.Exception as e: - assert e.msg == f"DID NOT RAISE {repr(ValueError)}" + assert e.msg == f"DID NOT RAISE {ValueError!r}" else: assert False, "Expected pytest.raises.Exception" @@ -155,7 +155,7 @@ class TestRaises: with pytest.raises(ValueError): pass except pytest.fail.Exception as e: - assert e.msg == f"DID NOT RAISE {repr(ValueError)}" + assert e.msg == f"DID NOT RAISE {ValueError!r}" else: assert False, "Expected pytest.raises.Exception" diff --git a/testing/test_assertion.py b/testing/test_assertion.py index f8196efea..167541e1e 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -914,16 +914,16 @@ class TestAssert_reprcompare: assert expl == [ r"'hyv\xe4' == 'hyva\u0308'", "", - f"- {str(right)}", - f"+ {str(left)}", + f"- {right!s}", + f"+ {left!s}", ] expl = callequal(left, right, verbose=2) assert expl == [ r"'hyv\xe4' == 'hyva\u0308'", "", - f"- {str(right)}", - f"+ {str(left)}", + f"- {right!s}", + f"+ {left!s}", ] diff --git a/testing/test_doctest.py b/testing/test_doctest.py index 835e0e1e6..a7a0077ae 100644 --- a/testing/test_doctest.py +++ b/testing/test_doctest.py @@ -190,7 +190,7 @@ class TestDoctests: ) doctest = f""" >>> "{test_string}" - {repr(test_string)} + {test_string!r} """ fn = pytester.path / "test_encoding.txt" fn.write_text(doctest, encoding=encoding) diff --git a/testing/test_pytester.py b/testing/test_pytester.py index 84fb96ccb..9c6081a56 100644 --- a/testing/test_pytester.py +++ b/testing/test_pytester.py @@ -227,7 +227,7 @@ class TestInlineRunModulesCleanup: def spy_factory(self): class SysModulesSnapshotSpy: - instances: List["SysModulesSnapshotSpy"] = [] # noqa: F821 + instances: List["SysModulesSnapshotSpy"] = [] def __init__(self, preserve=None) -> None: SysModulesSnapshotSpy.instances.append(self) @@ -725,7 +725,7 @@ def test_run_result_repr() -> None: # known exit code r = pytester_mod.RunResult(1, outlines, errlines, duration=0.5) assert repr(r) == ( - f"" )