diff --git a/.pylintrc b/.pylintrc index 5e182033..2761f1b2 100644 --- a/.pylintrc +++ b/.pylintrc @@ -7,7 +7,6 @@ init-hook='import sys; sys.path.append("./scripts/pylint_checkers/")' load-plugins=check_count, check_docstring, check_header, - pylint.extensions.emptystring, pylint.extensions.check_elif, pylint.extensions.overlapping_exceptions, diff --git a/misc/requirements/requirements_lint.txt b/misc/requirements/requirements_lint.txt index 1c607180..61607781 100644 --- a/misc/requirements/requirements_lint.txt +++ b/misc/requirements/requirements_lint.txt @@ -1,3 +1,3 @@ -pylint==2.17.5 +pylint==3.0.2 black==23.11.0 pydocstyle==6.3.0 diff --git a/scripts/pylint_checkers/check_count.py b/scripts/pylint_checkers/check_count.py index 1333676b..e6adb42d 100644 --- a/scripts/pylint_checkers/check_count.py +++ b/scripts/pylint_checkers/check_count.py @@ -4,15 +4,12 @@ import astroid -from pylint.interfaces import IAstroidChecker from pylint.checkers import BaseChecker class CountComparedWithoutNone(BaseChecker): """Checker to ensure count is compared to None.""" - __implements__ = IAstroidChecker - name = "count-compared-directly" # here we define our messages @@ -43,8 +40,6 @@ def _check_compare_count(self, node): class CountAssignedToZero(BaseChecker): """Checker to inform when default assigning count to zero.""" - __implements__ = IAstroidChecker - name = "count-default-zero" # here we define our messages @@ -65,6 +60,8 @@ def visit_functiondef(self, node): In almost all cases None is what we want instead. """ for name, default in zip(node.args.args[::-1], node.args.defaults[::-1]): + # We explicitly allow None, empty string, ... + # pylint: disable=use-implicit-booleaness-not-comparison-to-zero if name.name == "count" and default.value == 0: self.add_message(self.name, node=node) diff --git a/scripts/pylint_checkers/check_docstring.py b/scripts/pylint_checkers/check_docstring.py index 8510d541..1709b32c 100644 --- a/scripts/pylint_checkers/check_docstring.py +++ b/scripts/pylint_checkers/check_docstring.py @@ -7,15 +7,12 @@ import astroid -from pylint.interfaces import IAstroidChecker from pylint.checkers import BaseChecker class CommandMissingDocumentation(BaseChecker): """Checker to ensure command docstrings include all information for docs.""" - __implements__ = IAstroidChecker - name = "command-docstring" name_ambiguous = "ambiguous-register" @@ -68,9 +65,10 @@ def visit_functiondef(self, node): return argnames = {arg.name.replace("_", "-") for arg in node.args.args} regular_argnames = argnames - {"self", "count"} - self._check_args_section(node, regular_argnames) - self._check_count_section(node, argnames) - self._check_syntax_section(node, regular_argnames) + docstr = node.doc_node.value + self._check_args_section(node, docstr, regular_argnames) + self._check_count_section(node, docstr, argnames) + self._check_syntax_section(node, docstr, regular_argnames) @staticmethod def sections(docstr): @@ -85,25 +83,25 @@ def sections(docstr): content += line return sections - def _check_syntax_section(self, node, argnames): + def _check_syntax_section(self, node, docstr, argnames): """Check if a syntax section is available for commands with arguments.""" if not argnames: return - for section in self.sections(node.doc): + for section in self.sections(docstr): if re.match(r"\*\*syntax:\*\* ``.*``", section.strip()): return self.add_message(self.name_syntax, node=node, args=(node.name,)) - def _check_count_section(self, node, argnames): + def _check_count_section(self, node, docstr, argnames): """Check if a count section is available for commands that support count.""" if "count" not in argnames: return - if "**count:**" not in node.doc: + if "**count:**" not in docstr: self.add_message(self.name_count, node=node, args=(node.name,)) - def _check_args_section(self, node, argnames): + def _check_args_section(self, node, docstr, argnames): """Check if all command arguments are documented.""" - docstring_argnames = self._get_args_from_docstring(node) + docstring_argnames = self._get_args_from_docstring(node, docstr) difference = argnames - docstring_argnames for argname in difference: self.add_message( @@ -145,7 +143,7 @@ def _is_command(self, node) -> bool: return True return False - def _get_args_from_docstring(self, node) -> Set[str]: + def _get_args_from_docstring(self, node, docstr) -> Set[str]: """Retrieve documented arguments from command docstring. If an argument is not correctly formatted in the documentation section, the @@ -154,11 +152,10 @@ def _get_args_from_docstring(self, node) -> Set[str]: Returns: Set of all documented argument names. """ - docstr = node.doc if docstr is None: self.add_message(self.name_missing, node=node, args=(node.name,)) return set() - lines = [line.strip() for line in node.doc.split("\n")] + lines = [line.strip() for line in docstr.split("\n")] def _get_args(identifier, pattern): try: diff --git a/scripts/pylint_checkers/check_header.py b/scripts/pylint_checkers/check_header.py index ee9cc2ef..5a4c9700 100644 --- a/scripts/pylint_checkers/check_header.py +++ b/scripts/pylint_checkers/check_header.py @@ -2,15 +2,12 @@ """Checker to ensure each python file includes a modeline and no copyright notice.""" -from pylint.interfaces import IRawChecker from pylint.checkers import BaseChecker class FileHeaderChecker(BaseChecker): """Checker to ensure each python file includes a modeline and copyright notice.""" - __implements__ = IRawChecker - name = "file-header" name_modeline_missing = "modeline-missing" name_copyright_included = "copyright-included" diff --git a/tests/unit/utils/test_thumbnail_manager.py b/tests/unit/utils/test_thumbnail_manager.py index 67e9c1d0..4e08f847 100644 --- a/tests/unit/utils/test_thumbnail_manager.py +++ b/tests/unit/utils/test_thumbnail_manager.py @@ -74,7 +74,7 @@ def test_do_not_create_thumbnail_for_thumbnail(qtbot, manager): def check_thumbails_created(qtbot, manager, n_paths): def wait_thread(): - assert manager.pool.activeThreadCount() == 0 + assert not manager.pool.activeThreadCount() qtbot.waitUntil(wait_thread, timeout=30000) assert len(os.listdir(manager.directory)) == n_paths diff --git a/vimiv/commands/external.py b/vimiv/commands/external.py index afc04f6a..5b612db7 100644 --- a/vimiv/commands/external.py +++ b/vimiv/commands/external.py @@ -110,7 +110,7 @@ def __call__(self, command: str, *args: str, pipe=False) -> None: def _on_finished(self, exitcode, exitstatus): """Check exit status and possibly process standard output on completion.""" - if exitstatus != QProcess.ExitStatus.NormalExit or exitcode != 0: + if exitstatus != QProcess.ExitStatus.NormalExit or exitcode: log.error( "Error running external process '%s':\n%s", self.program(), diff --git a/vimiv/imutils/_file_handler.py b/vimiv/imutils/_file_handler.py index 320cf6fd..57074bb1 100644 --- a/vimiv/imutils/_file_handler.py +++ b/vimiv/imutils/_file_handler.py @@ -103,7 +103,7 @@ def _load(self, path: str, keep_zoom: bool): # Gif elif reader.is_animation: movie = QMovie(path) - if not movie.isValid() or movie.frameCount() == 0: + if not movie.isValid() or not movie.frameCount(): log.error("Error reading animation %s: invalid data", path) return api.signals.movie_loaded.emit(movie, keep_zoom) diff --git a/vimiv/qt/core.py b/vimiv/qt/core.py index c6f6d155..21038cb7 100644 --- a/vimiv/qt/core.py +++ b/vimiv/qt/core.py @@ -19,6 +19,7 @@ QT_VERSION_STR = qVersion() if qt.USE_PYQT: # Signal aliases + # pylint: disable=used-before-assignment BoundSignal = pyqtBoundSignal Signal = pyqtSignal Slot = pyqtSlot @@ -27,6 +28,7 @@ class Align: """Namespace for easier access to the Qt alignment flags.""" + # pylint: disable=used-before-assignment Center = Qt.AlignmentFlag.AlignCenter Left = Qt.AlignmentFlag.AlignLeft Right = Qt.AlignmentFlag.AlignRight diff --git a/vimiv/utils/__init__.py b/vimiv/utils/__init__.py index 083ebb78..4beba894 100644 --- a/vimiv/utils/__init__.py +++ b/vimiv/utils/__init__.py @@ -423,10 +423,7 @@ def run_qprocess(cmd: str, *args: str, cwd=None) -> str: process.start(cmd, args) if not process.waitForFinished(): raise OSError("Error waiting for process") - if ( - process.exitStatus() != QProcess.ExitStatus.NormalExit - or process.exitCode() != 0 - ): + if process.exitStatus() != QProcess.ExitStatus.NormalExit or process.exitCode(): stderr = qbytearray_to_str(process.readAllStandardError()).strip() raise OSError(stderr) return qbytearray_to_str(process.readAllStandardOutput()).strip()