From 14fe9cf75a089d57807a9a077de3bfc7b7116663 Mon Sep 17 00:00:00 2001 From: Markus Meissner Date: Tue, 11 Nov 2025 23:15:56 +0100 Subject: [PATCH 1/4] introduce ruff instead of flake8, black, isort --- .flake8 | 6 -- Makefile | 12 +-- poetry.lock | 195 ++++++++----------------------------------------- pyproject.toml | 26 ++++--- 4 files changed, 55 insertions(+), 184 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 62db7e32..00000000 --- a/.flake8 +++ /dev/null @@ -1,6 +0,0 @@ -[flake8] -ignore = E203, E266, E501, W503 -max-line-length = 80 -max-complexity = 30 -select = B,C,E,F,W,T4,B9 -exclude = nitrokeyapp/ui diff --git a/Makefile b/Makefile index 9721537c..5189f5e4 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ update-venv: ifeq (, $(shell which poetry)) $(error "No poetry in $(PATH)") endif - poetry install --sync --without=deploy + poetry sync --without=deploy # clean environment semi-clean: @@ -37,13 +37,13 @@ build-pyinstaller-onedir: # code checks check-format: - poetry run black --check $(PACKAGE_NAME)/ + poetry run ruff format --check $(PACKAGE_NAME)/ check-import-sorting: - poetry run isort --check-only $(PACKAGE_NAME)/ + poetry run ruff check --select I --diff $(PACKAGE_NAME)/ check-style: - poetry run flake8 $(PACKAGE_NAME)/ + poetry run ruff check $(PACKAGE_NAME)/ check-typing: poetry run mypy $(PACKAGE_NAME)/ @@ -51,5 +51,5 @@ check-typing: check: check-format check-import-sorting check-style check-typing fix: - poetry run black $(PACKAGE_NAME)/ - poetry run isort $(PACKAGE_NAME)/ + poetry run ruff format $(PACKAGE_NAME)/ + poetry run ruff check --fix $(PACKAGE_NAME)/ diff --git a/poetry.lock b/poetry.lock index 2f44e0e3..cc4bbdad 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. [[package]] name = "altgraph" @@ -12,41 +12,6 @@ files = [ {file = "altgraph-0.17.4.tar.gz", hash = "sha256:1b5afbb98f6c4dcadb2e2ae6ab9fa994bbb8c1d75f4fa96d340f9437ae454406"}, ] -[[package]] -name = "black" -version = "22.12.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, - {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, - {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, - {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, - {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, - {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, - {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, - {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, - {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, - {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, - {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, - {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "certifi" version = "2024.8.30" @@ -255,34 +220,6 @@ files = [ {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] -[[package]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["dev"] -markers = "platform_system == \"Windows\"" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - [[package]] name = "crcmod" version = "1.7" @@ -362,23 +299,6 @@ cryptography = ">=2.6,<35 || >35,<48" [package.extras] pcsc = ["pyscard (>=1.9,<3)"] -[[package]] -name = "flake8" -version = "6.1.0" -description = "the modular source code checker: pep8 pyflakes and co" -optional = false -python-versions = ">=3.8.1" -groups = ["dev"] -files = [ - {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"}, - {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"}, -] - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.11.0,<2.12.0" -pyflakes = ">=3.1.0,<3.2.0" - [[package]] name = "hidapi" version = "0.14.0.post2" @@ -476,21 +396,6 @@ files = [ [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] -[[package]] -name = "isort" -version = "5.13.2" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -groups = ["dev"] -files = [ - {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, - {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, -] - -[package.extras] -colors = ["colorama (>=0.4.6)"] - [[package]] name = "jinja2" version = "3.1.4" @@ -598,18 +503,6 @@ files = [ {file = "markupsafe-3.0.1.tar.gz", hash = "sha256:3e683ee4f5d0fa2dde4db77ed8dd8a876686e3fc417655c2ece9a90576905344"}, ] -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -optional = false -python-versions = ">=3.6" -groups = ["dev"] -files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] - [[package]] name = "mypy" version = "1.4.1" @@ -704,18 +597,6 @@ files = [ {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - [[package]] name = "pefile" version = "2023.2.7" @@ -729,23 +610,6 @@ files = [ {file = "pefile-2023.2.7.tar.gz", hash = "sha256:82e6114004b3d6911c77c3953e3838654b04511b8b66e8583db70c65998017dc"}, ] -[[package]] -name = "platformdirs" -version = "4.3.6" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, - {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, -] - -[package.extras] -docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] -type = ["mypy (>=1.11.2)"] - [[package]] name = "protobuf" version = "5.28.2" @@ -767,18 +631,6 @@ files = [ {file = "protobuf-5.28.2.tar.gz", hash = "sha256:59379674ff119717404f7454647913787034f03fe7049cbef1d74a97bb4593f0"}, ] -[[package]] -name = "pycodestyle" -version = "2.11.1" -description = "Python style guide checker" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, - {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, -] - [[package]] name = "pycparser" version = "2.22" @@ -792,18 +644,6 @@ files = [ {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] -[[package]] -name = "pyflakes" -version = "3.1.0" -description = "passive checker of Python programs" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, - {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, -] - [[package]] name = "pyinstaller" version = "6.11.0" @@ -1104,6 +944,35 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "ruff" +version = "0.14.4" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "ruff-0.14.4-py3-none-linux_armv6l.whl", hash = "sha256:e6604613ffbcf2297cd5dcba0e0ac9bd0c11dc026442dfbb614504e87c349518"}, + {file = "ruff-0.14.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d99c0b52b6f0598acede45ee78288e5e9b4409d1ce7f661f0fa36d4cbeadf9a4"}, + {file = "ruff-0.14.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:9358d490ec030f1b51d048a7fd6ead418ed0826daf6149e95e30aa67c168af33"}, + {file = "ruff-0.14.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81b40d27924f1f02dfa827b9c0712a13c0e4b108421665322218fc38caf615c2"}, + {file = "ruff-0.14.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f5e649052a294fe00818650712083cddc6cc02744afaf37202c65df9ea52efa5"}, + {file = "ruff-0.14.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa082a8f878deeba955531f975881828fd6afd90dfa757c2b0808aadb437136e"}, + {file = "ruff-0.14.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1043c6811c2419e39011890f14d0a30470f19d47d197c4858b2787dfa698f6c8"}, + {file = "ruff-0.14.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a9f3a936ac27fb7c2a93e4f4b943a662775879ac579a433291a6f69428722649"}, + {file = "ruff-0.14.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:95643ffd209ce78bc113266b88fba3d39e0461f0cbc8b55fb92505030fb4a850"}, + {file = "ruff-0.14.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:456daa2fa1021bc86ca857f43fe29d5d8b3f0e55e9f90c58c317c1dcc2afc7b5"}, + {file = "ruff-0.14.4-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:f911bba769e4a9f51af6e70037bb72b70b45a16db5ce73e1f72aefe6f6d62132"}, + {file = "ruff-0.14.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:76158a7369b3979fa878612c623a7e5430c18b2fd1c73b214945c2d06337db67"}, + {file = "ruff-0.14.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f3b8f3b442d2b14c246e7aeca2e75915159e06a3540e2f4bed9f50d062d24469"}, + {file = "ruff-0.14.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c62da9a06779deecf4d17ed04939ae8b31b517643b26370c3be1d26f3ef7dbde"}, + {file = "ruff-0.14.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5a443a83a1506c684e98acb8cb55abaf3ef725078be40237463dae4463366349"}, + {file = "ruff-0.14.4-py3-none-win32.whl", hash = "sha256:643b69cb63cd996f1fc7229da726d07ac307eae442dd8974dbc7cf22c1e18fff"}, + {file = "ruff-0.14.4-py3-none-win_amd64.whl", hash = "sha256:26673da283b96fe35fa0c939bf8411abec47111644aa9f7cfbd3c573fb125d2c"}, + {file = "ruff-0.14.4-py3-none-win_arm64.whl", hash = "sha256:dd09c292479596b0e6fec8cd95c65c3a6dc68e9ad17b8f2382130f87ff6a75bb"}, + {file = "ruff-0.14.4.tar.gz", hash = "sha256:f459a49fe1085a749f15414ca76f61595f1a2cc8778ed7c279b6ca2e1fd19df3"}, +] + [[package]] name = "semver" version = "3.0.2" @@ -1169,7 +1038,7 @@ description = "A lil' TOML parser" optional = false python-versions = ">=3.8" groups = ["dev"] -markers = "python_full_version < \"3.11.0a7\"" +markers = "python_version == \"3.10\"" files = [ {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, @@ -1248,4 +1117,4 @@ tests = ["pytest"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<3.14" -content-hash = "32df52a418b80a3bcedd0f282cacf203b83743752af632f11d5f12a74ceb4bef" +content-hash = "7f450e1f37a0dedf7baa5fb309cdd667154cb1681066d514a98b7ed22a2527cf" diff --git a/pyproject.toml b/pyproject.toml index 5ddbf832..dc71142b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,22 +40,30 @@ usb-monitor = "^1.21" [tool.poetry.group.dev.dependencies] PySide6-stubs = "^6.4.2" -black = ">=22.1.0,<23" -flake8 = "^6.1.0" -isort = "^5.12.0" +ruff = "^0.14" mypy = ">=1.4,<1.5" [tool.poetry.group.deploy.dependencies] pyinstaller = "^6.3.0" pyinstaller-versionfile = { version = "2.1.1", markers = "sys_platform=='win32'" } -[tool.isort] -py_version = "310" -profile = "black" -line_length = 80 +[tool.ruff] +line-length = 100 +target-version = "py310" -[tool.black] -target-version = ["py310"] +[tool.ruff.lint] +select = ["B", "C", "E", "F", "W", "B9", "I"] +ignore = ["E203", "E266", "E501"] + +[tool.ruff.lint.mccabe] +max-complexity = 30 + +[tool.ruff.lint.isort] +known-first-party = ["nitrokeyapp"] + +[tool.ruff.format] +quote-style = "double" +indent-style = "space" [tool.mypy] show_error_codes = true From d1fd3fe3252b4b8f0f9564ca3559ae087915ffe1 Mon Sep 17 00:00:00 2001 From: Markus Meissner Date: Tue, 11 Nov 2025 23:26:45 +0100 Subject: [PATCH 2/4] ruff: apply fixes and formatting --- nitrokeyapp/device_manager.py | 6 +---- nitrokeyapp/device_view.py | 18 +++++-------- nitrokeyapp/error_dialog.py | 4 +-- nitrokeyapp/gui.py | 1 - nitrokeyapp/information_box.py | 8 ++---- nitrokeyapp/logger.py | 4 +-- nitrokeyapp/nk3_button.py | 4 +-- nitrokeyapp/overview_tab/__init__.py | 4 +-- nitrokeyapp/overview_tab/worker.py | 4 +-- nitrokeyapp/prompt_box.py | 3 +-- nitrokeyapp/qt_utils_mix_in.py | 8 ++---- nitrokeyapp/secrets_tab/__init__.py | 27 +++++-------------- nitrokeyapp/secrets_tab/ui.py | 2 +- nitrokeyapp/secrets_tab/worker.py | 35 ++++++------------------- nitrokeyapp/settings_tab/__init__.py | 39 +++++++--------------------- nitrokeyapp/settings_tab/worker.py | 4 +-- nitrokeyapp/update.py | 19 +++++--------- nitrokeyapp/welcome_tab.py | 4 +-- nitrokeyapp/windows_notification.py | 4 +-- 19 files changed, 51 insertions(+), 147 deletions(-) diff --git a/nitrokeyapp/device_manager.py b/nitrokeyapp/device_manager.py index 53f6ad81..5c38331a 100644 --- a/nitrokeyapp/device_manager.py +++ b/nitrokeyapp/device_manager.py @@ -53,11 +53,7 @@ def add(self) -> List[DeviceData]: new_devices = [] for candidate in all_devs: # ignore bootloader device during update - if ( - len(self._devices) == 1 - and self._devices[0].updating - and candidate.is_bootloader - ): + if len(self._devices) == 1 and self._devices[0].updating and candidate.is_bootloader: continue # handle from bootloader-device updating diff --git a/nitrokeyapp/device_view.py b/nitrokeyapp/device_view.py index 75d19d4a..d2bdd0d1 100644 --- a/nitrokeyapp/device_view.py +++ b/nitrokeyapp/device_view.py @@ -9,23 +9,17 @@ class DeviceView(Protocol): @property - def common_ui(self) -> CommonUi: - ... + def common_ui(self) -> CommonUi: ... @property - def title(self) -> str: - ... + def title(self) -> str: ... @property - def widget(self) -> QWidget: - ... + def widget(self) -> QWidget: ... @property - def worker(self) -> Optional[Worker]: - ... + def worker(self) -> Optional[Worker]: ... - def reset(self) -> None: - ... + def reset(self) -> None: ... - def refresh(self, data: DeviceData) -> None: - ... + def refresh(self, data: DeviceData) -> None: ... diff --git a/nitrokeyapp/error_dialog.py b/nitrokeyapp/error_dialog.py index e8f9b3cc..ea5b758c 100644 --- a/nitrokeyapp/error_dialog.py +++ b/nitrokeyapp/error_dialog.py @@ -22,9 +22,7 @@ def __init__(self, log_file: str, parent: Optional[QWidget] = None) -> None: self.button_save_log = QPushButton("Save Log File", self) self.button_save_log.pressed.connect(self.save_log) - self.ui.buttonBox.addButton( - self.button_save_log, QDialogButtonBox.ButtonRole.ActionRole - ) + self.ui.buttonBox.addButton(self.button_save_log, QDialogButtonBox.ButtonRole.ActionRole) def set_exception( self, diff --git a/nitrokeyapp/gui.py b/nitrokeyapp/gui.py index 0f06db1a..a4291896 100644 --- a/nitrokeyapp/gui.py +++ b/nitrokeyapp/gui.py @@ -90,7 +90,6 @@ def __init__(self, qt_app: QtWidgets.QApplication, log_file: str): ] for view in self.views: if view.worker: - view.worker.busy_state_changed.connect(self.set_busy) view.common_ui.touch.start.connect(self.touch_dialog.start) diff --git a/nitrokeyapp/information_box.py b/nitrokeyapp/information_box.py index 01c18a22..4638c41b 100644 --- a/nitrokeyapp/information_box.py +++ b/nitrokeyapp/information_box.py @@ -59,9 +59,7 @@ def __init__( self.hide_timer.timeout.connect(self.hide_status) @Slot(str, int, str) - def set_status( - self, text: str, timeout: int = 7000, icon: Optional[str] = None - ) -> None: + def set_status(self, text: str, timeout: int = 7000, icon: Optional[str] = None) -> None: self.status.setText(text) self.status.show() self.information_frame.show() @@ -88,9 +86,7 @@ def hide_status(self) -> None: @Slot() def set_touch_status(self) -> None: - self.set_status( - "Press your Nitrokey to confirm...", timeout=15000, icon="touch.svg" - ) + self.set_status("Press your Nitrokey to confirm...", timeout=15000, icon="touch.svg") @Slot() def hide_touch(self) -> None: diff --git a/nitrokeyapp/logger.py b/nitrokeyapp/logger.py index 95f0658f..b99c1931 100644 --- a/nitrokeyapp/logger.py +++ b/nitrokeyapp/logger.py @@ -22,9 +22,7 @@ def init_logging() -> Generator[str, None, None]: log_format = "%(relativeCreated)-8d %(levelname)6s %(name)10s %(message)s" try: - handler = logging.FileHandler( - filename=log_file.name, delay=True, encoding="utf-8" - ) + handler = logging.FileHandler(filename=log_file.name, delay=True, encoding="utf-8") console_handler = logging.StreamHandler(sys.stdout) handlers = [handler] diff --git a/nitrokeyapp/nk3_button.py b/nitrokeyapp/nk3_button.py index 48b27b11..a97ee21a 100644 --- a/nitrokeyapp/nk3_button.py +++ b/nitrokeyapp/nk3_button.py @@ -7,9 +7,7 @@ class Nk3Button(QtWidgets.QToolButton): - def __init__( - self, data: DeviceData, on_click: Callable[[DeviceData], None] - ) -> None: + def __init__(self, data: DeviceData, on_click: Callable[[DeviceData], None]) -> None: super().__init__() self.setIcon(QtUtilsMixIn.get_qicon("nitrokey.svg")) diff --git a/nitrokeyapp/overview_tab/__init__.py b/nitrokeyapp/overview_tab/__init__.py index c58451fb..aa106ab8 100644 --- a/nitrokeyapp/overview_tab/__init__.py +++ b/nitrokeyapp/overview_tab/__init__.py @@ -224,9 +224,7 @@ def device_updated(self, result: UpdateResult) -> None: elif result.status == UpdateStatus.ABORTED: self.common_ui.info.error.emit(f"Nitrokey 3 update aborted{msg}") else: - self.common_ui.info.error.emit( - f"Unexpected update result: {result.status}{msg}" - ) + self.common_ui.info.error.emit(f"Unexpected update result: {result.status}{msg}") self.common_ui.gui.refresh_devices.emit() diff --git a/nitrokeyapp/overview_tab/worker.py b/nitrokeyapp/overview_tab/worker.py index 13b73388..eae76f9e 100644 --- a/nitrokeyapp/overview_tab/worker.py +++ b/nitrokeyapp/overview_tab/worker.py @@ -63,9 +63,7 @@ def update_device(self, data: DeviceData, is_qubesos: bool) -> None: self.run(job) @Slot(DeviceData, str) - def update_device_file( - self, data: DeviceData, filename: str, is_qubesos: bool - ) -> None: + def update_device_file(self, data: DeviceData, filename: str, is_qubesos: bool) -> None: job = UpdateDevice(self.common_ui, data, is_qubesos) job.image = filename job.device_updated.connect(self.device_updated) diff --git a/nitrokeyapp/prompt_box.py b/nitrokeyapp/prompt_box.py index 90edcb88..378680cc 100644 --- a/nitrokeyapp/prompt_box.py +++ b/nitrokeyapp/prompt_box.py @@ -29,8 +29,7 @@ def confirm(self, title: str, desc: str) -> None: self.setText(desc) self.setWindowTitle(title) self.setStandardButtons( - QtWidgets.QMessageBox.StandardButton.Ok - | QtWidgets.QMessageBox.StandardButton.Cancel + QtWidgets.QMessageBox.StandardButton.Ok | QtWidgets.QMessageBox.StandardButton.Cancel ) self.setIcon(QtWidgets.QMessageBox.Icon.Information) diff --git a/nitrokeyapp/qt_utils_mix_in.py b/nitrokeyapp/qt_utils_mix_in.py index 5673a911..f48421fa 100644 --- a/nitrokeyapp/qt_utils_mix_in.py +++ b/nitrokeyapp/qt_utils_mix_in.py @@ -18,9 +18,7 @@ def __init__(self) -> None: assert isinstance(self, QObject) @staticmethod - def load_ui( - filename: str, base_instance: Optional[QtWidgets.QWidget] = None - ) -> Any: + def load_ui(filename: str, base_instance: Optional[QtWidgets.QWidget] = None) -> Any: # returning `Any` to avoid `mypy` going crazy due to monkey-patching loader = UiLoader(base_instance, customWidgets=None) p_dir = (Path(__file__).parent / "ui").absolute() @@ -80,9 +78,7 @@ def get_widget(self, qt_cls: Type[Q], name: str = "") -> Q: self.widgets[name] = widget return widget # type: ignore - def collapse( - self, frame: QtWidgets.QWidget, expand_button: QtWidgets.QPushButton - ) -> None: + def collapse(self, frame: QtWidgets.QWidget, expand_button: QtWidgets.QPushButton) -> None: # Find out if the state is on or off state = expand_button.isChecked() if not state: diff --git a/nitrokeyapp/secrets_tab/__init__.py b/nitrokeyapp/secrets_tab/__init__.py index 21ff6c15..c52d8801 100644 --- a/nitrokeyapp/secrets_tab/__init__.py +++ b/nitrokeyapp/secrets_tab/__init__.py @@ -137,14 +137,10 @@ def __init__(self, parent: Optional[QWidget] = None) -> None: self.action_password_show.triggered.connect(self.act_password_show) self.action_comment_copy = self.ui.comment.addAction(icon_copy, loc) - self.action_comment_copy.triggered.connect( - lambda: self.act_copy_line_edit(self.ui.comment) - ) + self.action_comment_copy.triggered.connect(lambda: self.act_copy_line_edit(self.ui.comment)) self.action_otp_copy = self.ui.otp.addAction(icon_copy, loc) - self.action_otp_copy.triggered.connect( - lambda: self.act_copy_line_edit(self.ui.otp) - ) + self.action_otp_copy.triggered.connect(lambda: self.act_copy_line_edit(self.ui.otp)) self.action_otp_gen = self.ui.otp.addAction(icon_refresh, loc) self.action_otp_gen.triggered.connect(self.generate_otp) @@ -499,9 +495,7 @@ def edit_credential(self, credential: Credential) -> None: if credential.otp or credential.other: self.ui.otp.setReadOnly(True) - self.ui.select_algorithm.setCurrentText( - str(credential.otp or credential.other) - ) + self.ui.select_algorithm.setCurrentText(str(credential.otp or credential.other)) self.ui.select_algorithm.setEnabled(False) self.action_hmac_gen.setVisible(False) @@ -546,7 +540,6 @@ def act_enable_otp_edit(self) -> None: @Slot() def add_new_credential(self) -> None: - if not self.data: return @@ -661,9 +654,7 @@ def check_credential(self) -> None: self.show_hmac_view() if len(check_secret) != 32: can_save = False - self.common_ui.info.info.emit( - "The HMAC-Secret is not 32 chars long" - ) + self.common_ui.info.info.emit("The HMAC-Secret is not 32 chars long") tool_Tip = tool_Tip + "\n- The HMAC-Secret is not 32 chars long" else: self.hide_hmac_view() @@ -694,9 +685,7 @@ def act_copy_line_edit(self, obj: QLineEdit) -> None: self.line2copy_action[obj].setIcon(self.get_qicon("done.svg")) QTimer.singleShot( 5000, - lambda: self.line2copy_action[obj].setIcon( - self.get_qicon("content_copy.svg") - ), + lambda: self.line2copy_action[obj].setIcon(self.get_qicon("content_copy.svg")), ) def act_password_show(self) -> None: @@ -723,7 +712,6 @@ def hide_credential(self) -> None: self.active_credential = None def show_hmac_view(self) -> None: - name_hmac = "HmacSlot2" if self.active_credential is None: @@ -754,7 +742,6 @@ def show_hmac_view(self) -> None: self.ui.is_touch_protected.hide() def hide_hmac_view(self) -> None: - if self.active_credential is None and self.ui.name_label.text() == "HmacSlot2": self.ui.name_label.clear() self.ui.name_label.hide() @@ -873,9 +860,7 @@ def save_credential(self) -> None: if self.active_credential is None: self.trigger_add_credential.emit(self.data, cred, secret) else: - self.trigger_edit_credential.emit( - self.data, cred, secret, self.active_credential.id - ) + self.trigger_edit_credential.emit(self.data, cred, secret, self.active_credential.id) @Slot() def generate_otp(self) -> None: diff --git a/nitrokeyapp/secrets_tab/ui.py b/nitrokeyapp/secrets_tab/ui.py index 8aa67293..e6389447 100644 --- a/nitrokeyapp/secrets_tab/ui.py +++ b/nitrokeyapp/secrets_tab/ui.py @@ -20,7 +20,7 @@ def query(self, attempts: int) -> None: pin, ok = QInputDialog.getText( self.parent_widget, "Enter Passwords PIN", - "Please enter the Passwords PIN (remaining retries: " f"{attempts}):", + f"Please enter the Passwords PIN (remaining retries: {attempts}):", QLineEdit.EchoMode.Password, ) if ok and pin: diff --git a/nitrokeyapp/secrets_tab/worker.py b/nitrokeyapp/secrets_tab/worker.py index 446500ae..610fd46b 100644 --- a/nitrokeyapp/secrets_tab/worker.py +++ b/nitrokeyapp/secrets_tab/worker.py @@ -210,15 +210,10 @@ def check_credential(self, credentials: list[Credential]) -> None: # ids = set([credential.id for credential in credentials]) if self.old_cred_id not in self.all_credentials: - self.trigger_error( - f"A credential with the name {self.old_cred_id!r} does not exists." - ) + self.trigger_error(f"A credential with the name {self.old_cred_id!r} does not exists.") return - if ( - self.credential.id != self.old_cred_id - and self.credential.id in self.all_credentials - ): + if self.credential.id != self.old_cred_id and self.credential.id in self.all_credentials: self.trigger_error( f"A credential with the name {self.credential.name} does already exist." ) @@ -258,9 +253,7 @@ def edit_credential(self, successful: bool = True) -> None: temp_cred_id = self.temp_rename_credential(self.old_cred_id) self.add_credential(self.credential, self.secret, temp_cred_id) - def add_credential( - self, cred: Credential, secret: bytes, then_delete_id: bytes - ) -> None: + def add_credential(self, cred: Credential, secret: bytes, then_delete_id: bytes) -> None: add_job = AddCredentialJob( self.common_ui, self.pin_cache, @@ -269,9 +262,7 @@ def add_credential( credential=cred, secret=secret, ) - add_job.credential_added.connect( - lambda cred: self.handle_created(cred, then_delete_id) - ) + add_job.credential_added.connect(lambda cred: self.handle_created(cred, then_delete_id)) self.spawn(add_job) @Slot(Credential) @@ -320,7 +311,6 @@ def edit_credential_final(self) -> None: with self.data.open() as device: secrets = SecretsApp(device) with self.touch_prompt(): - reg_data = dict( cred_id=self.old_cred_id, touch_button=self.credential.touch_required, @@ -382,9 +372,7 @@ def run(self) -> None: def check_credential(self, credentials: list[Credential]) -> None: ids = set([credential.id for credential in credentials]) if self.credential.id in ids: - self.trigger_error( - f"A credential with the name {self.credential.name} already exists." - ) + self.trigger_error(f"A credential with the name {self.credential.name} already exists.") elif self.credential.protected: verify_pin_job = VerifyPinJob( self.common_ui, @@ -407,7 +395,6 @@ def add_credential(self, successful: bool = True) -> None: with self.data.open() as device: secrets = SecretsApp(device) with self.touch_prompt(): - reg_data = dict( credid=self.credential.id, touch_button_required=self.credential.touch_required, @@ -536,9 +523,7 @@ def generate_otp(self) -> None: valid_until = datetime.fromtimestamp((challenge + 1) * period) validity = (valid_from, valid_until) else: - self.trigger_exception( - RuntimeError(f"Unexpected OTP kind: {self.credential.otp}") - ) + self.trigger_exception(RuntimeError(f"Unexpected OTP kind: {self.credential.otp}")) try: with self.touch_prompt(): @@ -573,9 +558,7 @@ def __init__( def run(self) -> None: if self.pin_protected: - verify_pin_job = VerifyPinJob( - self.common_ui, self.pin_cache, self.pin_ui, self.data - ) + verify_pin_job = VerifyPinJob(self.common_ui, self.pin_cache, self.pin_ui, self.data) verify_pin_job.pin_verified.connect(self.list_protected_credentials) self.spawn(verify_pin_job) else: @@ -675,9 +658,7 @@ def check_device(self, data: DeviceData) -> None: self.run(job) @Slot(DeviceData, Credential, bytes) - def add_credential( - self, data: DeviceData, credential: Credential, secret: bytes - ) -> None: + def add_credential(self, data: DeviceData, credential: Credential, secret: bytes) -> None: job = AddCredentialJob( self.common_ui, self.pin_cache, diff --git a/nitrokeyapp/settings_tab/__init__.py b/nitrokeyapp/settings_tab/__init__.py index 19b4bf11..356e119e 100644 --- a/nitrokeyapp/settings_tab/__init__.py +++ b/nitrokeyapp/settings_tab/__init__.py @@ -78,8 +78,7 @@ class State(Enum): "parent": State.Passwords, "icon": RESET_ICON, "name": "Factory Reset", - "desc": "This operation will unevitably remove all your credentials " - + "in Passwords!", + "desc": "This operation will unevitably remove all your credentials " + "in Passwords!", }, } @@ -196,38 +195,20 @@ def field_btn(self) -> None: icon_false = self.get_qicon("close.svg") loc = QLineEdit.ActionPosition.TrailingPosition - self.action_current_password_show = self.ui.current_password.addAction( - icon_visibility, loc - ) - self.action_current_password_show.triggered.connect( - self.act_current_password_show - ) + self.action_current_password_show = self.ui.current_password.addAction(icon_visibility, loc) + self.action_current_password_show.triggered.connect(self.act_current_password_show) - self.action_new_password_show = self.ui.new_password.addAction( - icon_visibility, loc - ) + self.action_new_password_show = self.ui.new_password.addAction(icon_visibility, loc) self.action_new_password_show.triggered.connect(self.act_new_password_show) - self.action_repeat_password_show = self.ui.repeat_password.addAction( - icon_visibility, loc - ) - self.action_repeat_password_show.triggered.connect( - self.act_repeat_password_show - ) + self.action_repeat_password_show = self.ui.repeat_password.addAction(icon_visibility, loc) + self.action_repeat_password_show.triggered.connect(self.act_repeat_password_show) - self.show_current_password_check = self.ui.current_password.addAction( - icon_check, loc - ) - self.show_current_password_false = self.ui.current_password.addAction( - icon_false, loc - ) + self.show_current_password_check = self.ui.current_password.addAction(icon_check, loc) + self.show_current_password_false = self.ui.current_password.addAction(icon_false, loc) - self.show_repeat_password_check = self.ui.repeat_password.addAction( - icon_check, loc - ) - self.show_repeat_password_false = self.ui.repeat_password.addAction( - icon_false, loc - ) + self.show_repeat_password_check = self.ui.repeat_password.addAction(icon_check, loc) + self.show_repeat_password_false = self.ui.repeat_password.addAction(icon_false, loc) self.action_current_password_show.setVisible(False) self.action_new_password_show.setVisible(False) diff --git a/nitrokeyapp/settings_tab/worker.py b/nitrokeyapp/settings_tab/worker.py index 1b2a0b80..e8c03cba 100644 --- a/nitrokeyapp/settings_tab/worker.py +++ b/nitrokeyapp/settings_tab/worker.py @@ -217,9 +217,7 @@ def run(self) -> None: try: with self.touch_prompt(): secrets.reset() - self.common_ui.info.info.emit( - "PASSWORDS function reset successfully!" - ) + self.common_ui.info.info.emit("PASSWORDS function reset successfully!") except SecretsAppException as e: self.trigger_error(f"Passwords reset failed: {e}") self.reset_passwords.emit() diff --git a/nitrokeyapp/update.py b/nitrokeyapp/update.py index 5b10c3b1..9f40dbcb 100644 --- a/nitrokeyapp/update.py +++ b/nitrokeyapp/update.py @@ -73,7 +73,8 @@ def raise_warning(self, warning: Warning) -> Exception: def show_warning(self, warning: Warning) -> None: res = self.run_confirm_dialog( - "DANGER - You can ignore this warning by pressing ok", warning.message + "DANGER - You can ignore this warning by pressing ok", + warning.message, ) if not res: logger.info("Cancel clicked (during warning)") @@ -82,9 +83,7 @@ def show_warning(self, warning: Warning) -> None: logger.info("OK clicked (warning dialog)") def abort_downgrade(self, current: Version, image: Version) -> Exception: - return self.abort( - f"firmware {image} is older than the firmware on the device ({current})" - ) + return self.abort(f"firmware {image} is older than the firmware on the device ({current})") def run_confirm_dialog(self, title: str, desc: str) -> bool: self.common_ui.prompt.confirm.emit(title, desc) @@ -160,9 +159,7 @@ def confirm_extra_information(self, txt: List[str]) -> None: logger.info("OK clicked (confirm same version)") - def abort_pynitrokey_version( - self, current: Version, required: Version - ) -> Exception: + def abort_pynitrokey_version(self, current: Version, required: Version) -> Exception: raise self.abort(f"pynitrokey {required} too old, need: {current}") def confirm_pynitrokey_version(self, current: Version, required: Version) -> None: @@ -266,9 +263,7 @@ def update( try: with self.connect() as device: updater = Updater(ui, self) - _, status = updater.update( - device=device, image=image, update_version=None - ) + _, status = updater.update(device=device, image=image, update_version=None) except UpdateException as e: return UpdateResult(status=e.status, message=str(e)) except Exception as e: @@ -276,9 +271,7 @@ def update( if status.init_status is not None: if status.init_status & InitStatus.EXT_FLASH_NEED_REFORMAT: - logger.error( - f"Problematic init status after update: {status.init_status}" - ) + logger.error(f"Problematic init status after update: {status.init_status}") return UpdateResult( status=UpdateStatus.ERROR, message="External filesystem needs to be reformatted." diff --git a/nitrokeyapp/welcome_tab.py b/nitrokeyapp/welcome_tab.py index 430ab520..a468f212 100644 --- a/nitrokeyapp/welcome_tab.py +++ b/nitrokeyapp/welcome_tab.py @@ -48,9 +48,7 @@ def check_update(self) -> None: if Version.__lt__(self.c_version_v, self.n_version_v): self.ui.CheckUpdate.setText("update available") self.ui.CheckUpdate.pressed.connect( - lambda: webbrowser.open( - "https://github.com/Nitrokey/nitrokey-app2/releases" - ) + lambda: webbrowser.open("https://github.com/Nitrokey/nitrokey-app2/releases") ) else: self.ui.CheckUpdate.setText("App is up to date") diff --git a/nitrokeyapp/windows_notification.py b/nitrokeyapp/windows_notification.py index 7084686c..6c223c41 100644 --- a/nitrokeyapp/windows_notification.py +++ b/nitrokeyapp/windows_notification.py @@ -10,9 +10,7 @@ class WindowsUSBNotifi: WORD = c_ushort DWORD = c_ulong - def __init__( - self, detect_nk3: Callable[[], None], remove_nk3: Callable[[], None] - ) -> None: + def __init__(self, detect_nk3: Callable[[], None], remove_nk3: Callable[[], None]) -> None: import win32api import win32con import win32gui From 676c8d96ad5d81efa0145c9a56c0eaf0ba459121 Mon Sep 17 00:00:00 2001 From: Markus Meissner Date: Tue, 11 Nov 2025 23:27:49 +0100 Subject: [PATCH 3/4] ruff: apply unsafe fixes --- nitrokeyapp/gui.py | 2 +- nitrokeyapp/secrets_tab/worker.py | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/nitrokeyapp/gui.py b/nitrokeyapp/gui.py index a4291896..d7e261ba 100644 --- a/nitrokeyapp/gui.py +++ b/nitrokeyapp/gui.py @@ -148,7 +148,7 @@ def detect_added_devices( device_info: Optional[Dict[str, str]] = None, ) -> None: # retry for up to 2secs - for tries in range(8): + for _tries in range(8): devs = self.device_manager.add() if devs: break diff --git a/nitrokeyapp/secrets_tab/worker.py b/nitrokeyapp/secrets_tab/worker.py index 610fd46b..86f2aaba 100644 --- a/nitrokeyapp/secrets_tab/worker.py +++ b/nitrokeyapp/secrets_tab/worker.py @@ -311,11 +311,11 @@ def edit_credential_final(self) -> None: with self.data.open() as device: secrets = SecretsApp(device) with self.touch_prompt(): - reg_data = dict( - cred_id=self.old_cred_id, - touch_button=self.credential.touch_required, + reg_data = { + "cred_id": self.old_cred_id, + "touch_button": self.credential.touch_required, # pin_based_encryption=self.credential.protected, - ) + } if self.old_cred_id != self.credential.id: reg_data["new_name"] = self.credential.id @@ -370,7 +370,7 @@ def run(self) -> None: @Slot(list) def check_credential(self, credentials: list[Credential]) -> None: - ids = set([credential.id for credential in credentials]) + ids = {credential.id for credential in credentials} if self.credential.id in ids: self.trigger_error(f"A credential with the name {self.credential.name} already exists.") elif self.credential.protected: @@ -395,11 +395,11 @@ def add_credential(self, successful: bool = True) -> None: with self.data.open() as device: secrets = SecretsApp(device) with self.touch_prompt(): - reg_data = dict( - credid=self.credential.id, - touch_button_required=self.credential.touch_required, - pin_based_encryption=self.credential.protected, - ) + reg_data = { + "credid": self.credential.id, + "touch_button_required": self.credential.touch_required, + "pin_based_encryption": self.credential.protected, + } if self.credential.other: reg_data["secret"] = self.secret From 6b77651747982d37d66ffac06fbea4d7db64742b Mon Sep 17 00:00:00 2001 From: Markus Meissner Date: Tue, 11 Nov 2025 23:30:31 +0100 Subject: [PATCH 4/4] ruff: final fix in except re-raise --- nitrokeyapp/ui_loader.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nitrokeyapp/ui_loader.py b/nitrokeyapp/ui_loader.py index 07e286c6..5d89e622 100644 --- a/nitrokeyapp/ui_loader.py +++ b/nitrokeyapp/ui_loader.py @@ -59,12 +59,12 @@ def createWidget( # @fixme? in fact QWidget is callable widget = self.customWidgets[class_name](parent) # type: ignore - except (TypeError, KeyError): + except (TypeError, KeyError) as e: raise Exception( "No custom widget " + class_name + " found in customWidgets param of UiLoader __init__." - ) + ) from e if self.baseinstance: # set an attribute for the new child widget on the base