diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 61c1cf16..910ea8c6 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -3,3 +3,6 @@ b6a24debb78b953117a3f637db18942f370a4b85 # Run pre-commit after adding ruff 24e1dd5c561bc3da972e41e6fd61961f12a2fc9f + +# Apply ruff sort settings +ba9f1bd3d77dbd0b9efeb1f2f91c743b97ec558e diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a533eaf8..40156ba5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,9 +22,9 @@ jobs: python-version: 3.11 pre-commit: true - - name: Test formatting with Flake8, ruff and Black + - name: Test formatting with ruff shell: bash - run: make lint + run: pre-commit run --all-files --show-diff-on-failure prepare-matrix: runs-on: ubuntu-latest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 61afc63e..d9dcc242 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,17 +29,19 @@ repos: - id: requirements-txt-fixer - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: "v0.0.257" + rev: v0.7.0 hooks: + # Run the linter. - id: ruff - args: [--fix, --exit-non-zero-on-fix] + # Run the formatter. + - id: ruff-format # format python files - - repo: https://github.com/psf/black - rev: 22.12.0 - hooks: - - id: black - files: ^(src/vorta/|tests) + # - repo: https://github.com/psf/black + # rev: 22.12.0 + # hooks: + # - id: black + # files: ^(src/vorta/|tests) # # run black on code embedded in docstrings # - repo: https://github.com/asottile/blacken-docs @@ -56,12 +58,6 @@ repos: # py39, # ] - # check pep8 conformity using flake8 - - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 - hooks: - - id: flake8 - # configuration for the pre-commit.ci bot # only relevant when actually using the bot ci: diff --git a/bin/.gitkeep b/bin/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/package/fix_app_qt_folder_names_for_codesign.py b/package/fix_app_qt_folder_names_for_codesign.py index cbd5805d..40089674 100644 --- a/package/fix_app_qt_folder_names_for_codesign.py +++ b/package/fix_app_qt_folder_names_for_codesign.py @@ -11,6 +11,7 @@ import sys from pathlib import Path from typing import Generator, List, Optional + from macholib.MachO import MachO diff --git a/pyproject.toml b/pyproject.toml index b7ddd68e..a071960c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,14 +1,23 @@ -[tool.black] -line-length = 120 -skip-string-normalization = true -target-version = ['py39'] -include = "(src/vorta/|tests).*.py$" - [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.ruff] -select = ["T", "I"] -exclude = ["package"] -fixable = ["I"] +line-length = 120 +# exclude = ["package", "build", "dist", ".git", ".idea", ".cache", ".tox", ".eggs", "./src/vorta/__init__.py", ".direnv", "env"] +include = ["src/**/*.py", "tests/**/*.py"] + +[tool.ruff.lint] +select = [ + "E", # Error + "F", # pyflakes + "I", # isort + "W", # Warning + "YTT", # flake8-2020 +] +ignore = [ + "F401", +] + +[tool.ruff.format] +quote-style = "preserve" diff --git a/requirements.d/dev.txt b/requirements.d/dev.txt index 5391c54a..3a9af3ea 100644 --- a/requirements.d/dev.txt +++ b/requirements.d/dev.txt @@ -1,6 +1,4 @@ -black==22.* coverage -flake8 macholib nox pkgconfig diff --git a/setup.cfg b/setup.cfg index e0cdd931..f0c94da3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -72,16 +72,8 @@ source = vorta omit = tests/* relative_files = true -[flake8] -ignore = -max-line-length = 120 -extend-ignore = E203,E121,E123,E126,E226,E24,E704,W503,W504 -exclude = - build,dist,.git,.idea,.cache,.tox,.eggs, - ./src/vorta/__init__.py,.direnv,env - [tox:tox] -envlist = py36,py37,py38,flake8 +envlist = py36,py37,py38 skip_missing_interpreters = true [testenv] @@ -92,10 +84,10 @@ deps = commands=pytest passenv = DISPLAY -[testenv:flake8] +[testenv:ruff] deps = - flake8 -commands=flake8 src tests + ruff +commands=ruff check src tests [pycodestyle] max_line_length = 120 diff --git a/src/vorta/assets/exclusion_presets/browsers.json b/src/vorta/assets/exclusion_presets/browsers.json index a799ce7f..17d591d2 100644 --- a/src/vorta/assets/exclusion_presets/browsers.json +++ b/src/vorta/assets/exclusion_presets/browsers.json @@ -135,7 +135,7 @@ ], "tags": ["application:firefox", "type:browser", "os:linux"], "author": "Divi, Renner0E" - } + }, { "name": "Mozilla Firefox Snap cache and config files", "slug": "firefox-snap-cache", diff --git a/src/vorta/autostart.py b/src/vorta/autostart.py index b89ecf37..67488611 100644 --- a/src/vorta/autostart.py +++ b/src/vorta/autostart.py @@ -31,7 +31,6 @@ def open_app_at_startup(enabled=True): while on Linux it adds a .desktop file at ~/.config/autostart """ if sys.platform == 'darwin': - url = NSURL.alloc().initFileURLWithPath_(APP_PATH) login_items = LSSharedFileListCreate(kCFAllocatorDefault, kLSSharedFileListSessionLoginItems, None) props = NSDictionary.dictionaryWithObject_forKey_(True, kLSSharedFileListItemHidden) diff --git a/src/vorta/borg/init.py b/src/vorta/borg/init.py index a88a5ea0..c752aab5 100644 --- a/src/vorta/borg/init.py +++ b/src/vorta/borg/init.py @@ -10,7 +10,6 @@ def started_event(self): @classmethod def prepare(cls, params): - # Build fake profile because we don't have it in the DB yet. profile = FakeProfile( 999, diff --git a/src/vorta/i18n/__init__.py b/src/vorta/i18n/__init__.py index 54f96c17..01e68705 100644 --- a/src/vorta/i18n/__init__.py +++ b/src/vorta/i18n/__init__.py @@ -1,6 +1,7 @@ """ internationalisation (i18n) support code """ + import logging import os diff --git a/src/vorta/keyring/darwin.py b/src/vorta/keyring/darwin.py index 91f93610..4d4fb2d5 100644 --- a/src/vorta/keyring/darwin.py +++ b/src/vorta/keyring/darwin.py @@ -1,4 +1,4 @@ -# flake8: noqa +# ruff: noqa """ A dirty objc implementation to access the macOS Keychain. Because the @@ -7,11 +7,14 @@ Adapted from https://gist.github.com/apettinen/5dc7bf1f6a07d148b2075725db6b1950 """ + import logging import sys from ctypes import c_char + import objc from Foundation import NSBundle + from .abc import VortaKeyring logger = logging.getLogger(__name__) @@ -47,14 +50,14 @@ def _set_keychain(self): objc.loadBundleFunctions(Security, globals(), S_functions) - SecKeychainRef = objc.registerCFSignature('SecKeychainRef', b'^{OpaqueSecKeychainRef=}', SecKeychainGetTypeID()) - SecKeychainItemRef = objc.registerCFSignature( + objc.registerCFSignature('SecKeychainRef', b'^{OpaqueSecKeychainRef=}', SecKeychainGetTypeID()) + objc.registerCFSignature( 'SecKeychainItemRef', b'^{OpaqueSecKeychainItemRef=}', SecKeychainItemGetTypeID(), ) - PassBuffRef = objc.createOpaquePointerType('PassBuffRef', b'^{OpaquePassBuff=}', None) + objc.createOpaquePointerType('PassBuffRef', b'^{OpaquePassBuff=}', None) # Get the login keychain result, login_keychain = SecKeychainOpen(b'login.keychain', None) @@ -81,7 +84,12 @@ def get_password(self, service, repo_url): if not self.login_keychain: self._set_keychain() - (result, password_length, password_buffer, keychain_item,) = SecKeychainFindGenericPassword( + ( + result, + password_length, + password_buffer, + keychain_item, + ) = SecKeychainFindGenericPassword( self.login_keychain, len(service), service.encode(), diff --git a/src/vorta/qt_single_application.py b/src/vorta/qt_single_application.py index cb9f65a8..cc8350ee 100644 --- a/src/vorta/qt_single_application.py +++ b/src/vorta/qt_single_application.py @@ -40,7 +40,6 @@ class QtSingleApplication(QApplication): message_received_event = pyqtSignal(str) def __init__(self, id, *argv): - super().__init__(*argv) self._id = id diff --git a/src/vorta/utils.py b/src/vorta/utils.py index a666b9fd..fbe1e43f 100644 --- a/src/vorta/utils.py +++ b/src/vorta/utils.py @@ -469,7 +469,6 @@ def extract_mount_points_v1(proc, repo_url): for idx, parameter in enumerate(proc.cmdline()): if parameter.startswith(repo_url): - if len(proc.cmdline()) > idx + 1: mount_point = proc.cmdline()[idx + 1] diff --git a/src/vorta/views/exclude_dialog.py b/src/vorta/views/exclude_dialog.py index 5e1a3920..261d2667 100644 --- a/src/vorta/views/exclude_dialog.py +++ b/src/vorta/views/exclude_dialog.py @@ -154,7 +154,7 @@ def populate_custom_exclusions_list(self): .order_by(ExclusionModel.name) } - for (exclude, enabled) in user_excluded_patterns.items(): + for exclude, enabled in user_excluded_patterns.items(): item = QStandardItem(exclude) item.setCheckable(True) item.setCheckState(Qt.CheckState.Checked if enabled else Qt.CheckState.Unchecked) diff --git a/src/vorta/views/partials/treemodel.py b/src/vorta/views/partials/treemodel.py index ceff3eb4..8fa3dafa 100644 --- a/src/vorta/views/partials/treemodel.py +++ b/src/vorta/views/partials/treemodel.py @@ -909,12 +909,10 @@ def __init__(self, parent=None) -> None: self.folders_on_top = False @overload - def keepFoldersOnTop(self) -> bool: - ... + def keepFoldersOnTop(self) -> bool: ... @overload - def keepFoldersOnTop(self, value: bool) -> bool: - ... + def keepFoldersOnTop(self, value: bool) -> bool: ... def keepFoldersOnTop(self, value=None) -> bool: """ diff --git a/tests/conftest.py b/tests/conftest.py index 0f781026..a4d1f19c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,10 +2,11 @@ import sys import pytest +from peewee import SqliteDatabase + import vorta import vorta.application import vorta.borg.jobs_manager -from peewee import SqliteDatabase def pytest_configure(config): diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 683271f5..54d9b23e 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -2,11 +2,12 @@ import subprocess import pytest +from peewee import SqliteDatabase +from pkg_resources import parse_version + import vorta import vorta.application import vorta.borg.jobs_manager -from peewee import SqliteDatabase -from pkg_resources import parse_version from vorta.store.models import ( ArchiveModel, BackupProfileModel, diff --git a/tests/integration/test_archives.py b/tests/integration/test_archives.py index a32df06d..2a259300 100644 --- a/tests/integration/test_archives.py +++ b/tests/integration/test_archives.py @@ -7,10 +7,11 @@ import psutil import pytest +from PyQt6 import QtCore + import vorta.borg import vorta.utils import vorta.views.archive_tab -from PyQt6 import QtCore from vorta.store.models import ArchiveModel diff --git a/tests/integration/test_borg.py b/tests/integration/test_borg.py index 0af84a96..79f8e967 100644 --- a/tests/integration/test_borg.py +++ b/tests/integration/test_borg.py @@ -5,6 +5,7 @@ from pathlib import Path import pytest + import vorta.borg import vorta.store.models from vorta.borg.info_archive import BorgInfoArchiveJob diff --git a/tests/integration/test_diff.py b/tests/integration/test_diff.py index 28e8037b..d2a4dacf 100644 --- a/tests/integration/test_diff.py +++ b/tests/integration/test_diff.py @@ -3,10 +3,11 @@ """ import pytest +from pkg_resources import parse_version + import vorta.borg import vorta.utils import vorta.views.archive_tab -from pkg_resources import parse_version from vorta.borg.diff import BorgDiffJob from vorta.views.diff_result import ( ChangeType, diff --git a/tests/integration/test_init.py b/tests/integration/test_init.py index 7312a420..172604cc 100644 --- a/tests/integration/test_init.py +++ b/tests/integration/test_init.py @@ -6,11 +6,12 @@ from pathlib import PurePath import pytest +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QMessageBox + import vorta.borg import vorta.utils import vorta.views.repo_add_dialog -from PyQt6.QtCore import Qt -from PyQt6.QtWidgets import QMessageBox LONG_PASSWORD = 'long-password-long' TEST_REPO_NAME = 'TEST - REPONAME' diff --git a/tests/integration/test_repo.py b/tests/integration/test_repo.py index 277aace5..49a5a293 100644 --- a/tests/integration/test_repo.py +++ b/tests/integration/test_repo.py @@ -4,6 +4,7 @@ import pytest from PyQt6 import QtCore + from vorta.store.models import ArchiveModel, EventLogModel diff --git a/tests/network_manager/test_darwin.py b/tests/network_manager/test_darwin.py index 7d900dd4..a65cc79f 100644 --- a/tests/network_manager/test_darwin.py +++ b/tests/network_manager/test_darwin.py @@ -1,6 +1,7 @@ from unittest.mock import MagicMock import pytest + from vorta.network_status import darwin diff --git a/tests/network_manager/test_network_manager.py b/tests/network_manager/test_network_manager.py index 9e787a86..da56c2be 100644 --- a/tests/network_manager/test_network_manager.py +++ b/tests/network_manager/test_network_manager.py @@ -2,6 +2,7 @@ from unittest.mock import MagicMock import pytest + from vorta.network_status.abc import SystemWifiInfo from vorta.network_status.network_manager import ( ActiveConnectionInfo, diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index e622a211..bde3f83f 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -2,10 +2,11 @@ from datetime import datetime as dt import pytest +from peewee import SqliteDatabase + import vorta import vorta.application import vorta.borg.jobs_manager -from peewee import SqliteDatabase from vorta.store.models import ( ArchiveModel, BackupProfileModel, diff --git a/tests/unit/test_archives.py b/tests/unit/test_archives.py index e0a7fb1a..16a6cc45 100644 --- a/tests/unit/test_archives.py +++ b/tests/unit/test_archives.py @@ -2,11 +2,12 @@ import psutil import pytest +from PyQt6 import QtCore +from PyQt6.QtWidgets import QMenu + import vorta.borg import vorta.utils import vorta.views.archive_tab -from PyQt6 import QtCore -from PyQt6.QtWidgets import QMenu from vorta.store.models import ArchiveModel, BackupProfileModel diff --git a/tests/unit/test_borg.py b/tests/unit/test_borg.py index 5e822436..a5ef7527 100644 --- a/tests/unit/test_borg.py +++ b/tests/unit/test_borg.py @@ -1,4 +1,5 @@ import pytest + import vorta.borg import vorta.store.models from vorta.borg.prune import BorgPruneJob diff --git a/tests/unit/test_diff.py b/tests/unit/test_diff.py index e7ef9fd9..9877ad6f 100644 --- a/tests/unit/test_diff.py +++ b/tests/unit/test_diff.py @@ -1,11 +1,12 @@ from pathlib import PurePath import pytest +from PyQt6.QtCore import QDateTime, QItemSelectionModel, Qt +from PyQt6.QtWidgets import QMenu + import vorta.borg import vorta.utils import vorta.views.archive_tab -from PyQt6.QtCore import QDateTime, QItemSelectionModel, Qt -from PyQt6.QtWidgets import QMenu from vorta.store.models import ArchiveModel from vorta.views.diff_result import ( ChangeType, diff --git a/tests/unit/test_extract.py b/tests/unit/test_extract.py index e68da0d2..eb02b0b9 100644 --- a/tests/unit/test_extract.py +++ b/tests/unit/test_extract.py @@ -1,6 +1,7 @@ import pytest -import vorta.borg from PyQt6.QtCore import QModelIndex, Qt + +import vorta.borg from vorta.store.models import ArchiveModel from vorta.views.extract_dialog import ( ExtractDialog, diff --git a/tests/unit/test_import_export.py b/tests/unit/test_import_export.py index d7987ab7..6ecfb858 100644 --- a/tests/unit/test_import_export.py +++ b/tests/unit/test_import_export.py @@ -4,6 +4,7 @@ import pytest from PyQt6 import QtCore from PyQt6.QtWidgets import QDialogButtonBox, QFileDialog, QMessageBox + from vorta.profile_export import VersionException from vorta.store.models import BackupProfileModel, SourceFileModel from vorta.views.import_window import ImportWindow diff --git a/tests/unit/test_lock.py b/tests/unit/test_lock.py index 44d66cdf..3157a230 100644 --- a/tests/unit/test_lock.py +++ b/tests/unit/test_lock.py @@ -1,7 +1,8 @@ import pytest +from PyQt6 import QtCore + import vorta.application import vorta.borg.borg_job -from PyQt6 import QtCore def test_create_perm_error(qapp, borg_json_output, mocker, qtbot): diff --git a/tests/unit/test_misc.py b/tests/unit/test_misc.py index d354af05..4044ed9c 100644 --- a/tests/unit/test_misc.py +++ b/tests/unit/test_misc.py @@ -4,10 +4,11 @@ from unittest.mock import Mock import pytest -import vorta.store.models from PyQt6 import QtCore from PyQt6.QtGui import QCloseEvent from PyQt6.QtWidgets import QCheckBox, QFormLayout, QMessageBox + +import vorta.store.models from vorta.store.models import SettingsModel diff --git a/tests/unit/test_notifications.py b/tests/unit/test_notifications.py index c6ea1292..bba30daf 100644 --- a/tests/unit/test_notifications.py +++ b/tests/unit/test_notifications.py @@ -1,9 +1,10 @@ import sys import pytest +from PyQt6 import QtDBus + import vorta.borg import vorta.notifications -from PyQt6 import QtDBus @pytest.mark.skipif(sys.platform != 'linux', reason="DBus notifications only on Linux") diff --git a/tests/unit/test_password_input.py b/tests/unit/test_password_input.py index 218a1dac..cc016a7f 100644 --- a/tests/unit/test_password_input.py +++ b/tests/unit/test_password_input.py @@ -1,5 +1,6 @@ import pytest from PyQt6.QtWidgets import QFormLayout, QWidget + from vorta.views.partials.password_input import PasswordInput, PasswordLineEdit diff --git a/tests/unit/test_profile.py b/tests/unit/test_profile.py index c757dc89..09ccae77 100644 --- a/tests/unit/test_profile.py +++ b/tests/unit/test_profile.py @@ -2,6 +2,7 @@ from PyQt6 import QtCore from PyQt6.QtWidgets import QDialogButtonBox, QFileDialog, QMessageBox, QToolTip + from vorta.store.models import BackupProfileModel, SourceFileModel from vorta.views.export_window import ExportWindow diff --git a/tests/unit/test_repo.py b/tests/unit/test_repo.py index 053834e9..241851c8 100644 --- a/tests/unit/test_repo.py +++ b/tests/unit/test_repo.py @@ -3,9 +3,10 @@ from typing import Any, Dict import pytest -import vorta.borg.borg_job from PyQt6 import QtCore from PyQt6.QtWidgets import QMessageBox + +import vorta.borg.borg_job from vorta.keyring.abc import VortaKeyring from vorta.store.models import ArchiveModel, EventLogModel, RepoModel diff --git a/tests/unit/test_schedule.py b/tests/unit/test_schedule.py index 1f030a5a..adee7d9c 100644 --- a/tests/unit/test_schedule.py +++ b/tests/unit/test_schedule.py @@ -3,8 +3,9 @@ from unittest.mock import MagicMock import pytest -import vorta.scheduler from PyQt6 import QtCore + +import vorta.scheduler from vorta.application import VortaApp from vorta.store.models import BackupProfileModel, EventLogModel diff --git a/tests/unit/test_scheduler.py b/tests/unit/test_scheduler.py index 0adee402..d72d17fe 100644 --- a/tests/unit/test_scheduler.py +++ b/tests/unit/test_scheduler.py @@ -4,9 +4,10 @@ from unittest.mock import MagicMock import pytest +from pytest import mark + import vorta.borg import vorta.scheduler -from pytest import mark from vorta.scheduler import ScheduleStatus, ScheduleStatusType, VortaScheduler from vorta.store.models import BackupProfileModel, EventLogModel diff --git a/tests/unit/test_source.py b/tests/unit/test_source.py index 70b01961..a8fbb32c 100644 --- a/tests/unit/test_source.py +++ b/tests/unit/test_source.py @@ -1,7 +1,8 @@ import pytest -import vorta.views from PyQt6 import QtCore from PyQt6.QtWidgets import QMessageBox + +import vorta.views from vorta.views.main_window import MainWindow from vorta.views.source_tab import SourceTab diff --git a/tests/unit/test_treemodel.py b/tests/unit/test_treemodel.py index dd2b9717..0f6b356e 100644 --- a/tests/unit/test_treemodel.py +++ b/tests/unit/test_treemodel.py @@ -2,6 +2,7 @@ import pytest from PyQt6.QtCore import QModelIndex + from vorta.views.partials.treemodel import FileSystemItem, FileTreeModel diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index ea529c08..40d7cb65 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -2,6 +2,7 @@ import uuid import pytest + from vorta.keyring.abc import VortaKeyring from vorta.utils import ( find_best_unit_for_sizes,