Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

style: apply code quality fixes #1184

Merged
merged 1 commit into from
Jan 12, 2025
Merged

Conversation

github-actions[bot]
Copy link
Contributor

🔍 Code Quality Check Results

Pre-commit Output

trim trailing whitespace.................................................Failed
- hook id: trailing-whitespace
- exit code: 1
- files were modified by this hook

Fixing quality_report.md

fix end of files.........................................................Failed
- hook id: end-of-file-fixer
- exit code: 1
- files were modified by this hook

Fixing .pre-commit-output.txt

check yaml...............................................................Failed
- hook id: check-yaml
- files were modified by this hook
check for added large files..............................................Failed
- hook id: check-added-large-files
- files were modified by this hook
check python ast.........................................................Failed
- hook id: check-ast
- exit code: 1
- files were modified by this hook

tests/pyside6/unsafeconnection.py: failed parsing with CPython 3.12.8:

    Traceback (most recent call last):
      File "/home/runner/.cache/pre-commit/repo60ae3fei/py_env-python3.12/lib/python3.12/site-packages/pre_commit_hooks/check_ast.py", line 21, in main
        ast.parse(f.read(), filename=filename)
      File "/opt/hostedtoolcache/Python/3.12.8/x64/lib/python3.12/ast.py", line 52, in parse
        return compile(source, filename, mode, flags,
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "tests/pyside6/unsafeconnection.py", line 6
        class UnsafeConnection extends FunctionCall {
                               ^^^^^^^
    SyntaxError: invalid syntax

check json...............................................................Failed
- hook id: check-json
- files were modified by this hook
check for merge conflicts................................................Failed
- hook id: check-merge-conflict
- files were modified by this hook
check for case conflicts.................................................Failed
- hook id: check-case-conflict
- files were modified by this hook
check xml................................................................Failed
- hook id: check-xml
- files were modified by this hook
debug statements (python)................................................Failed
- hook id: debug-statements
- exit code: 1
- files were modified by this hook

tests/pyside6/unsafeconnection.py - Could not parse ast

	Traceback (most recent call last):
	  File "/home/runner/.cache/pre-commit/repo60ae3fei/py_env-python3.12/lib/python3.12/site-packages/pre_commit_hooks/debug_statement_hook.py", line 57, in check_file
	    ast_obj = ast.parse(f.read(), filename=filename)
	              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	  File "/opt/hostedtoolcache/Python/3.12.8/x64/lib/python3.12/ast.py", line 52, in parse
	    return compile(source, filename, mode, flags,
	           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	  File "tests/pyside6/unsafeconnection.py", line 6
	    class UnsafeConnection extends FunctionCall {
	                           ^^^^^^^
	SyntaxError: invalid syntax

detect private key.......................................................Failed
- hook id: detect-private-key
- files were modified by this hook
mixed line ending........................................................Failed
- hook id: mixed-line-ending
- files were modified by this hook
check builtin type constructor use.......................................Failed
- hook id: check-builtin-literals
- exit code: 1
- files were modified by this hook

Traceback (most recent call last):
  File "/home/runner/.cache/pre-commit/repo60ae3fei/py_env-python3.12/bin/check-builtin-literals", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/home/runner/.cache/pre-commit/repo60ae3fei/py_env-python3.12/lib/python3.12/site-packages/pre_commit_hooks/check_builtin_literals.py", line 89, in main
    calls = check_file(
            ^^^^^^^^^^^
  File "/home/runner/.cache/pre-commit/repo60ae3fei/py_env-python3.12/lib/python3.12/site-packages/pre_commit_hooks/check_builtin_literals.py", line 62, in check_file
    tree = ast.parse(f.read(), filename=filename)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.8/x64/lib/python3.12/ast.py", line 52, in parse
    return compile(source, filename, mode, flags,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "tests/pyside6/unsafeconnection.py", line 6
    class UnsafeConnection extends FunctionCall {
                           ^^^^^^^
SyntaxError: invalid syntax

Check hooks apply to the repository......................................Failed
- hook id: check-hooks-apply
- files were modified by this hook
Check for useless excludes...............................................Failed
- hook id: check-useless-excludes
- files were modified by this hook
sync-pre-commit-deps.....................................................Failed
- hook id: sync-pre-commit-deps
- files were modified by this hook
black....................................................................Failed
- hook id: black
- exit code: 123
- files were modified by this hook

error: cannot format tests/pyside6/unsafeconnection.py: Cannot parse for target version Python 3.11: 6:23: class UnsafeConnection extends FunctionCall {

Oh no! 💥 💔 💥
40 files left unchanged, 1 file failed to reformat.

isort....................................................................Failed
- hook id: isort
- files were modified by this hook

Fixing /home/runner/work/jmbde-python/jmbde-python/scripts/build_ui.py
Fixing /home/runner/work/jmbde-python/jmbde-python/src/jmbde/__main.py
Fixing /home/runner/work/jmbde-python/jmbde-python/src/jmbde/core/database.py
Fixing /home/runner/work/jmbde-python/jmbde-python/src/jmbde/gui/main_app.py
Fixing /home/runner/work/jmbde-python/jmbde-python/tests/test_main.py
Fixing /home/runner/work/jmbde-python/jmbde-python/tests/unit/test_database.py

prettier.................................................................Failed
- hook id: prettier
- files were modified by this hook

quality_report.md

ruff.....................................................................Failed
- hook id: ruff
- exit code: 1
- files were modified by this hook

warning: The top-level linter settings are deprecated in favour of their counterparts in the `lint` section. Please update the following options in `pyproject.toml`:
  - 'flake8-bugbear' -> 'lint.flake8-bugbear'
  - 'isort' -> 'lint.isort'
  - 'mccabe' -> 'lint.mccabe'
  - 'pep8-naming' -> 'lint.pep8-naming'
  - 'pydocstyle' -> 'lint.pydocstyle'
  - 'per-file-ignores' -> 'lint.per-file-ignores'
scripts/build_ui.py:53:1: T201 `print` found
   |
51 | ]
52 | 
53 | print("Rebuilding PyQt UI files...")
   | ^^^^^ T201
54 | for f in glob(f"{resources_dir}/forms/*.ui"):
55 |     print(
   |
   = help: Remove `print`

scripts/build_ui.py:54:10: PTH207 Replace `glob` with `Path.glob` or `Path.rglob`
   |
53 | print("Rebuilding PyQt UI files...")
54 | for f in glob(f"{resources_dir}/forms/*.ui"):
   |          ^^^^ PTH207
55 |     print(
56 |         "-g python",
   |

scripts/build_ui.py:55:5: T201 `print` found
   |
53 | print("Rebuilding PyQt UI files...")
54 | for f in glob(f"{resources_dir}/forms/*.ui"):
55 |     print(
   |     ^^^^^ T201
56 |         "-g python",
57 |         f"-o {source_dir}{package}/ui/ui_{os.path.basename(f[:-3])}.py {f}",
   |
   = help: Remove `print`

scripts/build_ui.py:57:43: PTH119 `os.path.basename()` should be replaced by `Path.name`
   |
55 |     print(
56 |         "-g python",
57 |         f"-o {source_dir}{package}/ui/ui_{os.path.basename(f[:-3])}.py {f}",
   |                                           ^^^^^^^^^^^^^^^^ PTH119
58 |     )
59 |     Popen(
   |

scripts/build_ui.py:59:5: S603 `subprocess` call: check for execution of untrusted input
   |
57 |         f"-o {source_dir}{package}/ui/ui_{os.path.basename(f[:-3])}.py {f}",
58 |     )
59 |     Popen(
   |     ^^^^^ S603
60 |         [
61 |             "uic",
   |

scripts/build_ui.py:60:9: S607 Starting a process with a partial executable path
   |
58 |       )
59 |       Popen(
60 |           [
   |  _________^
61 | |             "uic",
62 | |             "-g python",
63 | |             f"-o {source_dir}{package}/ui/ui_{os.path.basename(f[:-3])}.py {f}",
64 | |         ],
   | |_________^ S607
65 |       )
   |

scripts/build_ui.py:63:47: PTH119 `os.path.basename()` should be replaced by `Path.name`
   |
61 |             "uic",
62 |             "-g python",
63 |             f"-o {source_dir}{package}/ui/ui_{os.path.basename(f[:-3])}.py {f}",
   |                                               ^^^^^^^^^^^^^^^^ PTH119
64 |         ],
65 |     )
   |

scripts/build_ui.py:67:1: T201 `print` found
   |
65 |     )
66 | 
67 | print("Updating translations...")
   | ^^^^^ T201
68 | Popen(["lupdate", "jmbde.pro"])
69 | lang_files = " ".join(
   |
   = help: Remove `print`

scripts/build_ui.py:68:1: S603 `subprocess` call: check for execution of untrusted input
   |
67 | print("Updating translations...")
68 | Popen(["lupdate", "jmbde.pro"])
   | ^^^^^ S603
69 | lang_files = " ".join(
70 |     f"{resources_dir}/translations/{package}_{lang}.ts" for lang in languages
   |

scripts/build_ui.py:68:7: S607 Starting a process with a partial executable path
   |
67 | print("Updating translations...")
68 | Popen(["lupdate", "jmbde.pro"])
   |       ^^^^^^^^^^^^^^^^^^^^^^^^ S607
69 | lang_files = " ".join(
70 |     f"{resources_dir}/translations/{package}_{lang}.ts" for lang in languages
   |

scripts/build_ui.py:72:1: S603 `subprocess` call: check for execution of untrusted input
   |
70 |     f"{resources_dir}/translations/{package}_{lang}.ts" for lang in languages
71 | )
72 | Popen(["pyside2-lupdate", f"{source_dir}{package}/*.py -ts {lang_files}"])
   | ^^^^^ S603
73 | Popen(["lrelease", f"{resources_dir}/translations/*.ts"])
   |

scripts/build_ui.py:72:7: S607 Starting a process with a partial executable path
   |
70 |     f"{resources_dir}/translations/{package}_{lang}.ts" for lang in languages
71 | )
72 | Popen(["pyside2-lupdate", f"{source_dir}{package}/*.py -ts {lang_files}"])
   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S607
73 | Popen(["lrelease", f"{resources_dir}/translations/*.ts"])
   |

scripts/build_ui.py:73:1: S603 `subprocess` call: check for execution of untrusted input
   |
71 | )
72 | Popen(["pyside2-lupdate", f"{source_dir}{package}/*.py -ts {lang_files}"])
73 | Popen(["lrelease", f"{resources_dir}/translations/*.ts"])
   | ^^^^^ S603
74 | 
75 | print("Rebuilding PyQt resource files in source directory...")
   |

scripts/build_ui.py:73:7: S607 Starting a process with a partial executable path
   |
71 | )
72 | Popen(["pyside2-lupdate", f"{source_dir}{package}/*.py -ts {lang_files}"])
73 | Popen(["lrelease", f"{resources_dir}/translations/*.ts"])
   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S607
74 | 
75 | print("Rebuilding PyQt resource files in source directory...")
   |

scripts/build_ui.py:75:1: T201 `print` found
   |
73 | Popen(["lrelease", f"{resources_dir}/translations/*.ts"])
74 | 
75 | print("Rebuilding PyQt resource files in source directory...")
   | ^^^^^ T201
76 | for f in glob(f"{source_dir}/*.qrc"):
77 |     Popen(
   |
   = help: Remove `print`

scripts/build_ui.py:76:10: PTH207 Replace `glob` with `Path.glob` or `Path.rglob`
   |
75 | print("Rebuilding PyQt resource files in source directory...")
76 | for f in glob(f"{source_dir}/*.qrc"):
   |          ^^^^ PTH207
77 |     Popen(
78 |         [
   |

scripts/build_ui.py:77:5: S603 `subprocess` call: check for execution of untrusted input
   |
75 | print("Rebuilding PyQt resource files in source directory...")
76 | for f in glob(f"{source_dir}/*.qrc"):
77 |     Popen(
   |     ^^^^^ S603
78 |         [
79 |             "rcc",
   |

scripts/build_ui.py:78:9: S607 Starting a process with a partial executable path
   |
76 |   for f in glob(f"{source_dir}/*.qrc"):
77 |       Popen(
78 |           [
   |  _________^
79 | |             "rcc",
80 | |             f" -g python -o {package}/resources/qrc_{os.path.basename(f[:-4])}.py {f}",
81 | |         ],
   | |_________^ S607
82 |       )
   |

scripts/build_ui.py:80:54: PTH119 `os.path.basename()` should be replaced by `Path.name`
   |
78 |         [
79 |             "rcc",
80 |             f" -g python -o {package}/resources/qrc_{os.path.basename(f[:-4])}.py {f}",
   |                                                      ^^^^^^^^^^^^^^^^ PTH119
81 |         ],
82 |     )
   |

scripts/build_ui.py:84:1: T201 `print` found
   |
82 |     )
83 | 
84 | print("Rebuilding PyQt resource files in resources_dir directory...")
   | ^^^^^ T201
85 | for f in glob(f"{resources_dir}/*.qrc"):
86 |     Popen(
   |
   = help: Remove `print`

scripts/build_ui.py:85:10: PTH207 Replace `glob` with `Path.glob` or `Path.rglob`
   |
84 | print("Rebuilding PyQt resource files in resources_dir directory...")
85 | for f in glob(f"{resources_dir}/*.qrc"):
   |          ^^^^ PTH207
86 |     Popen(
87 |         [
   |

scripts/build_ui.py:86:5: S603 `subprocess` call: check for execution of untrusted input
   |
84 | print("Rebuilding PyQt resource files in resources_dir directory...")
85 | for f in glob(f"{resources_dir}/*.qrc"):
86 |     Popen(
   |     ^^^^^ S603
87 |         [
88 |             "rcc",
   |

scripts/build_ui.py:87:9: S607 Starting a process with a partial executable path
   |
85 |   for f in glob(f"{resources_dir}/*.qrc"):
86 |       Popen(
87 |           [
   |  _________^
88 | |             "rcc",
89 | |             f" -g python --verbose -o {source_dir}{package}/qrc_{os.path.basename(f[:-4])}.py {f}",
90 | |         ],
   | |_________^ S607
91 |       )
   |

scripts/build_ui.py:89:66: PTH119 `os.path.basename()` should be replaced by `Path.name`
   |
87 |         [
88 |             "rcc",
89 |             f" -g python --verbose -o {source_dir}{package}/qrc_{os.path.basename(f[:-4])}.py {f}",
   |                                                                  ^^^^^^^^^^^^^^^^ PTH119
90 |         ],
91 |     )
   |

scripts/build_ui.py:89:89: E501 Line too long (99 > 88)
   |
87 |         [
88 |             "rcc",
89 |             f" -g python --verbose -o {source_dir}{package}/qrc_{os.path.basename(f[:-4])}.py {f}",
   |                                                                                         ^^^^^^^^^^^ E501
90 |         ],
91 |     )
   |

scripts/build_ui.py:93:1: T201 `print` found
   |
91 |     )
92 | 
93 | print("Regenerating .pyc files...")
   | ^^^^^ T201
94 | shutil.rmtree(f"{package}/__pycache__", ignore_errors=True)
95 | for f in glob(f"{package}/*.pyc"):
   |
   = help: Remove `print`

scripts/build_ui.py:95:10: PTH207 Replace `glob` with `Path.glob` or `Path.rglob`
   |
93 | print("Regenerating .pyc files...")
94 | shutil.rmtree(f"{package}/__pycache__", ignore_errors=True)
95 | for f in glob(f"{package}/*.pyc"):
   |          ^^^^ PTH207
96 |     os.remove(f)
97 | __import__(f"{package}.__main__")
   |

scripts/build_ui.py:96:5: PTH107 `os.remove()` should be replaced by `Path.unlink()`
   |
94 | shutil.rmtree(f"{package}/__pycache__", ignore_errors=True)
95 | for f in glob(f"{package}/*.pyc"):
96 |     os.remove(f)
   |     ^^^^^^^^^ PTH107
97 | __import__(f"{package}.__main__")
   |

scripts/check_signals.py:1:1: INP001 File `scripts/check_signals.py` is part of an implicit namespace package. Add an `__init__.py`.
scripts/check_signals.py:1:1: D100 Missing docstring in public module
scripts/check_signals.py:5:7: D101 Missing docstring in public class
  |
5 | class SignalCheckVisitor(ast.NodeVisitor):
  |       ^^^^^^^^^^^^^^^^^^ D101
6 |     def __init__(self):
7 |         self.unused_signals = []
  |

scripts/check_signals.py:6:9: ANN204 Missing return type annotation for special method `__init__`
  |
5 | class SignalCheckVisitor(ast.NodeVisitor):
6 |     def __init__(self):
  |         ^^^^^^^^ ANN204
7 |         self.unused_signals = []
  |
  = help: Add return type annotation: `None`

scripts/check_signals.py:9:9: N802 Function name `visit_ClassDef` should be lowercase
   |
 7 |         self.unused_signals = []
 8 | 
 9 |     def visit_ClassDef(self, node):
   |         ^^^^^^^^^^^^^^ N802
10 |         for stmt in node.body:
11 |             if isinstance(stmt, ast.Assign) and any(
   |

scripts/check_signals.py:9:9: ANN201 Missing return type annotation for public function `visit_ClassDef`
   |
 7 |         self.unused_signals = []
 8 | 
 9 |     def visit_ClassDef(self, node):
   |         ^^^^^^^^^^^^^^ ANN201
10 |         for stmt in node.body:
11 |             if isinstance(stmt, ast.Assign) and any(
   |
   = help: Add return type annotation: `None`

scripts/check_signals.py:9:9: D102 Missing docstring in public method
   |
 7 |         self.unused_signals = []
 8 | 
 9 |     def visit_ClassDef(self, node):
   |         ^^^^^^^^^^^^^^ D102
10 |         for stmt in node.body:
11 |             if isinstance(stmt, ast.Assign) and any(
   |

scripts/check_signals.py:9:30: ANN001 Missing type annotation for function argument `node`
   |
 7 |         self.unused_signals = []
 8 | 
 9 |     def visit_ClassDef(self, node):
   |                              ^^^^ ANN001
10 |         for stmt in node.body:
11 |             if isinstance(stmt, ast.Assign) and any(
   |

scripts/check_signals.py:22:5: ANN201 Missing return type annotation for public function `main`
   |
22 | def main():
   |     ^^^^ ANN201
23 |     for filename in sys.argv[1:]:
24 |         with open(filename) as file:
   |
   = help: Add return type annotation: `None`

scripts/check_signals.py:22:5: D103 Missing docstring in public function
   |
22 | def main():
   |     ^^^^ D103
23 |     for filename in sys.argv[1:]:
24 |         with open(filename) as file:
   |

scripts/check_signals.py:24:14: PTH123 `open()` should be replaced by `Path.open()`
   |
22 | def main():
23 |     for filename in sys.argv[1:]:
24 |         with open(filename) as file:
   |              ^^^^ PTH123
25 |             tree = ast.parse(file.read(), filename=filename)
26 |             visitor = SignalCheckVisitor()
   |

scripts/check_signals.py:30:13: T201 `print` found
   |
29 |         if visitor.unused_signals:
30 |             print(f"Unused signals in {filename}: {visitor.unused_signals}")
   |             ^^^^^ T201
31 |             sys.exit(1)
   |
   = help: Remove `print`

src/jmbde/__about__.py:1:1: D100 Missing docstring in public module
src/jmbde/__init__.py:1:1: EXE001 Shebang is present but file is not executable
  |
1 | #!/usr/bin/python3
  | ^^^^^^^^^^^^^^^^^^ EXE001
2 | #
3 | # SPDX-FileCopyrightText: 2023 Jürgen Mülbert <[email protected]>
  |

src/jmbde/__init__.py:7:1: D400 First line should end with a period
  |
5 | # SPDX-License-Identifier: EUPL-1.2
6 | #
7 | """Module for jmbde"""
  | ^^^^^^^^^^^^^^^^^^^^^^ D400
8 | 
9 | """The configs."""
  |
  = help: Add period

src/jmbde/__init__.py:11:12: F821 Undefined name `os`
   |
 9 | """The configs."""
10 | 
11 | BASE_DIR = os.path.join(os.path.dirname(__file__), "..")
   |            ^^ F821
12 | IMAGES_DIR = os.path.join(BASE_DIR, "images")
13 | CONF_DIR = os.path.join(BASE_DIR, "conf")
   |

src/jmbde/__init__.py:11:25: F821 Undefined name `os`
   |
 9 | """The configs."""
10 | 
11 | BASE_DIR = os.path.join(os.path.dirname(__file__), "..")
   |                         ^^ F821
12 | IMAGES_DIR = os.path.join(BASE_DIR, "images")
13 | CONF_DIR = os.path.join(BASE_DIR, "conf")
   |

src/jmbde/__init__.py:12:14: F821 Undefined name `os`
   |
11 | BASE_DIR = os.path.join(os.path.dirname(__file__), "..")
12 | IMAGES_DIR = os.path.join(BASE_DIR, "images")
   |              ^^ F821
13 | CONF_DIR = os.path.join(BASE_DIR, "conf")
14 | TRANSLATION_DIR = os.path.join(BASE_DIR, "translations")
   |

src/jmbde/__init__.py:13:12: F821 Undefined name `os`
   |
11 | BASE_DIR = os.path.join(os.path.dirname(__file__), "..")
12 | IMAGES_DIR = os.path.join(BASE_DIR, "images")
13 | CONF_DIR = os.path.join(BASE_DIR, "conf")
   |            ^^ F821
14 | TRANSLATION_DIR = os.path.join(BASE_DIR, "translations")
15 | UI_DIR = os.path.join(BASE_DIR, "ui")
   |

src/jmbde/__init__.py:14:19: F821 Undefined name `os`
   |
12 | IMAGES_DIR = os.path.join(BASE_DIR, "images")
13 | CONF_DIR = os.path.join(BASE_DIR, "conf")
14 | TRANSLATION_DIR = os.path.join(BASE_DIR, "translations")
   |                   ^^ F821
15 | UI_DIR = os.path.join(BASE_DIR, "ui")
   |

src/jmbde/__init__.py:15:10: F821 Undefined name `os`
   |
13 | CONF_DIR = os.path.join(BASE_DIR, "conf")
14 | TRANSLATION_DIR = os.path.join(BASE_DIR, "translations")
15 | UI_DIR = os.path.join(BASE_DIR, "ui")
   |          ^^ F821
16 | 
17 | __all__ = ["BASE_DIR", "CONF_DIR", "IMAGES_DIR", "TRANSLATION_DIR", "UI_DIR"]
   |

src/jmbde/__main.py:1:1: EXE001 Shebang is present but file is not executable
  |
1 | #!/usr/bin/env python3
  | ^^^^^^^^^^^^^^^^^^^^^^ EXE001
2 | 
3 | """JMBDE - Business Data Management Application
  |

src/jmbde/__main.py:3:1: D400 First line should end with a period
   |
 1 |   #!/usr/bin/env python3
 2 |   
 3 | / """JMBDE - Business Data Management Application
 4 | | 
 5 | | This is the main entry point for the JMBDE application, a comprehensive tool
 6 | | for managing business data and employee information.
 7 | | 
 8 | | Copyright (C) 2018-2024 Jürgen Mülbert
 9 | | 
10 | | This program is free software: you can redistribute it and/or modify
11 | | it under the terms of the GNU General Public License as published by
12 | | the Free Software Foundation, either version 3 of the License, or
13 | | (at your option) any later version.
14 | | """
   | |___^ D400
15 |   
16 |   import logging
   |
   = help: Add period

src/jmbde/__main.py:42:19: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
   |
40 |     def __init__(self) -> None:
41 |         """Initialize the JMBDE application."""
42 |         self.app: Optional[QGuiApplication] = None
   |                   ^^^^^^^^ FA100
43 |         self.engine: Optional[QQmlApplicationEngine] = None
44 |         self.database: Optional[Database] = None
   |

src/jmbde/__main.py:43:22: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
   |
41 |         """Initialize the JMBDE application."""
42 |         self.app: Optional[QGuiApplication] = None
43 |         self.engine: Optional[QQmlApplicationEngine] = None
   |                      ^^^^^^^^ FA100
44 |         self.database: Optional[Database] = None
45 |         self.employee_model: Optional[EmployeeModel] = None
   |

src/jmbde/__main.py:44:24: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
   |
42 |         self.app: Optional[QGuiApplication] = None
43 |         self.engine: Optional[QQmlApplicationEngine] = None
44 |         self.database: Optional[Database] = None
   |                        ^^^^^^^^ FA100
45 |         self.employee_model: Optional[EmployeeModel] = None
46 |         self.main_app: Optional[MainApp] = None
   |

src/jmbde/__main.py:45:30: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
   |
43 |         self.engine: Optional[QQmlApplicationEngine] = None
44 |         self.database: Optional[Database] = None
45 |         self.employee_model: Optional[EmployeeModel] = None
   |                              ^^^^^^^^ FA100
46 |         self.main_app: Optional[MainApp] = None
47 |         self.settings: Optional[Settings] = None
   |

src/jmbde/__main.py:46:24: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
   |
44 |         self.database: Optional[Database] = None
45 |         self.employee_model: Optional[EmployeeModel] = None
46 |         self.main_app: Optional[MainApp] = None
   |                        ^^^^^^^^ FA100
47 |         self.settings: Optional[Settings] = None
   |

src/jmbde/__main.py:47:24: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
   |
45 |         self.employee_model: Optional[EmployeeModel] = None
46 |         self.main_app: Optional[MainApp] = None
47 |         self.settings: Optional[Settings] = None
   |                        ^^^^^^^^ FA100
48 | 
49 |     def initialize_logging(self) -> None:
   |

src/jmbde/__main.py:56:16: BLE001 Do not catch blind exception: `Exception`
   |
54 |             setup_logging(log_dir / "jmbde.log")
55 |             logger.info("Logging initialized successfully")
56 |         except Exception as e:
   |                ^^^^^^^^^ BLE001
57 |             print(f"Failed to initialize logging: {e}", file=sys.stderr)
58 |             sys.exit(1)
   |

src/jmbde/__main.py:57:13: T201 `print` found
   |
55 |             logger.info("Logging initialized successfully")
56 |         except Exception as e:
57 |             print(f"Failed to initialize logging: {e}", file=sys.stderr)
   |             ^^^^^ T201
58 |             sys.exit(1)
   |
   = help: Remove `print`

src/jmbde/__main.py:78:29: G004 Logging statement uses f-string
   |
76 |             logger.info("Application setup completed successfully")
77 |         except Exception as e:
78 |             logger.critical(f"Failed to setup application: {e}")
   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
79 |             raise ApplicationError("Application initialization failed") from e
   |

src/jmbde/__main.py:79:19: TRY003 Avoid specifying long messages outside the exception class
   |
77 |         except Exception as e:
78 |             logger.critical(f"Failed to setup application: {e}")
79 |             raise ApplicationError("Application initialization failed") from e
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY003
80 | 
81 |     def initialize_database(self) -> None:
   |

src/jmbde/__main.py:79:36: EM101 Exception must not use a string literal, assign to variable first
   |
77 |         except Exception as e:
78 |             logger.critical(f"Failed to setup application: {e}")
79 |             raise ApplicationError("Application initialization failed") from e
   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM101
80 | 
81 |     def initialize_database(self) -> None:
   |
   = help: Assign to variable; remove string literal

src/jmbde/__main.py:85:13: ERA001 Found commented-out code
   |
83 |         try:
84 |             self.database = Database()
85 |             # self.database.initialize()
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ERA001
86 |             logger.info("Database initialized successfully")
87 |         except DatabaseError as e:
   |
   = help: Remove commented-out code

src/jmbde/__main.py:88:13: TRY400 Use `logging.exception` instead of `logging.error`
   |
86 |             logger.info("Database initialized successfully")
87 |         except DatabaseError as e:
88 |             logger.error(f"Database initialization failed: {e}")
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400
89 |             raise ApplicationError("Failed to initialize database") from e
   |
   = help: Replace with `exception`

src/jmbde/__main.py:88:26: G004 Logging statement uses f-string
   |
86 |             logger.info("Database initialized successfully")
87 |         except DatabaseError as e:
88 |             logger.error(f"Database initialization failed: {e}")
   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
89 |             raise ApplicationError("Failed to initialize database") from e
   |

src/jmbde/__main.py:89:19: TRY003 Avoid specifying long messages outside the exception class
   |
87 |         except DatabaseError as e:
88 |             logger.error(f"Database initialization failed: {e}")
89 |             raise ApplicationError("Failed to initialize database") from e
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY003
90 | 
91 |     def setup_models(self) -> None:
   |

src/jmbde/__main.py:89:36: EM101 Exception must not use a string literal, assign to variable first
   |
87 |         except DatabaseError as e:
88 |             logger.error(f"Database initialization failed: {e}")
89 |             raise ApplicationError("Failed to initialize database") from e
   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM101
90 | 
91 |     def setup_models(self) -> None:
   |
   = help: Assign to variable; remove string literal

src/jmbde/__main.py:98:13: TRY400 Use `logging.exception` instead of `logging.error`
   |
96 |             logger.info("Models initialized successfully")
97 |         except Exception as e:
98 |             logger.error(f"Failed to initialize models: {e}")
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400
99 |             raise ApplicationError("Model initialization failed") from e
   |
   = help: Replace with `exception`

src/jmbde/__main.py:98:26: G004 Logging statement uses f-string
   |
96 |             logger.info("Models initialized successfully")
97 |         except Exception as e:
98 |             logger.error(f"Failed to initialize models: {e}")
   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
99 |             raise ApplicationError("Model initialization failed") from e
   |

src/jmbde/__main.py:99:19: TRY003 Avoid specifying long messages outside the exception class
    |
 97 |         except Exception as e:
 98 |             logger.error(f"Failed to initialize models: {e}")
 99 |             raise ApplicationError("Model initialization failed") from e
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY003
100 | 
101 |     def setup_qml_engine(self) -> None:
    |

src/jmbde/__main.py:99:36: EM101 Exception must not use a string literal, assign to variable first
    |
 97 |         except Exception as e:
 98 |             logger.error(f"Failed to initialize models: {e}")
 99 |             raise ApplicationError("Model initialization failed") from e
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM101
100 | 
101 |     def setup_qml_engine(self) -> None:
    |
    = help: Assign to variable; remove string literal

src/jmbde/__main.py:117:17: TRY301 Abstract `raise` to an inner function
    |
116 |             if not self.engine.rootObjects():
117 |                 raise ApplicationError("Failed to load QML interface")
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY301
118 | 
119 |             logger.info("QML engine initialized successfully")
    |

src/jmbde/__main.py:117:23: TRY003 Avoid specifying long messages outside the exception class
    |
116 |             if not self.engine.rootObjects():
117 |                 raise ApplicationError("Failed to load QML interface")
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY003
118 | 
119 |             logger.info("QML engine initialized successfully")
    |

src/jmbde/__main.py:117:40: EM101 Exception must not use a string literal, assign to variable first
    |
116 |             if not self.engine.rootObjects():
117 |                 raise ApplicationError("Failed to load QML interface")
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM101
118 | 
119 |             logger.info("QML engine initialized successfully")
    |
    = help: Assign to variable; remove string literal

src/jmbde/__main.py:121:13: TRY400 Use `logging.exception` instead of `logging.error`
    |
119 |             logger.info("QML engine initialized successfully")
120 |         except Exception as e:
121 |             logger.error(f"Failed to initialize QML engine: {e}")
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400
122 |             raise ApplicationError("QML initialization failed") from e
    |
    = help: Replace with `exception`

src/jmbde/__main.py:121:26: G004 Logging statement uses f-string
    |
119 |             logger.info("QML engine initialized successfully")
120 |         except Exception as e:
121 |             logger.error(f"Failed to initialize QML engine: {e}")
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
122 |             raise ApplicationError("QML initialization failed") from e
    |

src/jmbde/__main.py:122:19: TRY003 Avoid specifying long messages outside the exception class
    |
120 |         except Exception as e:
121 |             logger.error(f"Failed to initialize QML engine: {e}")
122 |             raise ApplicationError("QML initialization failed") from e
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY003
123 | 
124 |     def cleanup(self) -> None:
    |

src/jmbde/__main.py:122:36: EM101 Exception must not use a string literal, assign to variable first
    |
120 |         except Exception as e:
121 |             logger.error(f"Failed to initialize QML engine: {e}")
122 |             raise ApplicationError("QML initialization failed") from e
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM101
123 | 
124 |     def cleanup(self) -> None:
    |
    = help: Assign to variable; remove string literal

src/jmbde/__main.py:132:16: BLE001 Do not catch blind exception: `Exception`
    |
130 |                 self.settings.save()
131 |             logger.info("Application cleanup completed successfully")
132 |         except Exception as e:
    |                ^^^^^^^^^ BLE001
133 |             logger.error(f"Cleanup failed: {e}")
    |

src/jmbde/__main.py:133:13: TRY400 Use `logging.exception` instead of `logging.error`
    |
131 |             logger.info("Application cleanup completed successfully")
132 |         except Exception as e:
133 |             logger.error(f"Cleanup failed: {e}")
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400
    |
    = help: Replace with `exception`

src/jmbde/__main.py:133:26: G004 Logging statement uses f-string
    |
131 |             logger.info("Application cleanup completed successfully")
132 |         except Exception as e:
133 |             logger.error(f"Cleanup failed: {e}")
    |                          ^^^^^^^^^^^^^^^^^^^^^^ G004
    |

src/jmbde/__main.py:140:10: FBT001 Boolean-typed positional argument in function definition
    |
138 | @click.option("--debug", is_flag=True, help="Enable debug mode")
139 | @click.option("--config", type=click.Path(), help="Path to configuration file")
140 | def main(debug: bool, config: Optional[str]) -> None:
    |          ^^^^^ FBT001
141 |     """JMBDE - Business Data Management Application.
    |

src/jmbde/__main.py:140:23: ARG001 Unused function argument: `config`
    |
138 | @click.option("--debug", is_flag=True, help="Enable debug mode")
139 | @click.option("--config", type=click.Path(), help="Path to configuration file")
140 | def main(debug: bool, config: Optional[str]) -> None:
    |                       ^^^^^^ ARG001
141 |     """JMBDE - Business Data Management Application.
    |

src/jmbde/__main.py:140:31: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
    |
138 | @click.option("--debug", is_flag=True, help="Enable debug mode")
139 | @click.option("--config", type=click.Path(), help="Path to configuration file")
140 | def main(debug: bool, config: Optional[str]) -> None:
    |                               ^^^^^^^^ FA100
141 |     """JMBDE - Business Data Management Application.
    |

src/jmbde/__main.py:171:25: G004 Logging statement uses f-string
    |
170 |     except ApplicationError as e:
171 |         logger.critical(f"Application failed to start: {e}")
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
172 |         click.echo(f"Error: {e}", err=True)
173 |         sys.exit(1)
    |

src/jmbde/__main.py:174:12: BLE001 Do not catch blind exception: `Exception`
    |
172 |         click.echo(f"Error: {e}", err=True)
173 |         sys.exit(1)
174 |     except Exception as e:
    |            ^^^^^^^^^ BLE001
175 |         logger.critical(f"Unexpected error: {e}", exc_info=True)
176 |         click.echo(
    |

src/jmbde/__main.py:175:25: G004 Logging statement uses f-string
    |
173 |         sys.exit(1)
174 |     except Exception as e:
175 |         logger.critical(f"Unexpected error: {e}", exc_info=True)
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^ G004
176 |         click.echo(
177 |             "Fatal Error: An unexpected error occurred. Check logs for details.",
    |

src/jmbde/__main__.py:13:5: D103 Missing docstring in public function
   |
11 | @click.command()
12 | @click.help_option()
13 | def main() -> None:
   |     ^^^^ D103
14 |     print("Hello, world!")
   |

src/jmbde/__main__.py:14:5: T201 `print` found
   |
12 | @click.help_option()
13 | def main() -> None:
14 |     print("Hello, world!")
   |     ^^^^^ T201
   |
   = help: Remove `print`

src/jmbde/core/__init__.py:1:1: D104 Missing docstring in public package
src/jmbde/core/config.py:1:1: D100 Missing docstring in public module
src/jmbde/core/database.py:1:1: EXE001 Shebang is present but file is not executable
  |
1 | #!/usr/bin/env python3
  | ^^^^^^^^^^^^^^^^^^^^^^ EXE001
2 | 
3 | """Database Management Module for JMBDE
  |

src/jmbde/core/database.py:3:1: D400 First line should end with a period
   |
 1 |   #!/usr/bin/env python3
 2 |   
 3 | / """Database Management Module for JMBDE
 4 | | 
 5 | | This module provides database operations for the JMBDE application,
 6 | | handling employee and device data using SQLite.
 7 | | 
 8 | | Copyright (C) 2018-2024 Jürgen Mülbert
 9 | | License: GPL-3.0
10 | | """
   | |___^ D400
11 |   
12 |   from contextlib import contextmanager
   |
   = help: Add period

src/jmbde/core/database.py:31:9: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
   |
29 |     """Data model for Employee records."""
30 | 
31 |     id: Optional[int]
   |         ^^^^^^^^ FA100
32 |     name: str
33 |     position: str
   |

src/jmbde/core/database.py:44:9: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
   |
42 |     """Data model for Device records."""
43 | 
44 |     id: Optional[int]
   |         ^^^^^^^^ FA100
45 |     employee_id: Optional[int]
46 |     device_name: str
   |

src/jmbde/core/database.py:45:18: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
   |
44 |     id: Optional[int]
45 |     employee_id: Optional[int]
   |                  ^^^^^^^^ FA100
46 |     device_name: str
47 |     device_type: str
   |

src/jmbde/core/database.py:50:23: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
   |
48 |     serial_number: str
49 |     purchase_date: datetime
50 |     warranty_expires: Optional[datetime]
   |                       ^^^^^^^^ FA100
51 |     status: str = "active"
   |

src/jmbde/core/database.py:61:9: ANN204 Missing return type annotation for special method `__init__`
   |
59 |     """
60 | 
61 |     def __init__(self, db_path: Union[str, Path] = Config.DATABASE_PATH):
   |         ^^^^^^^^ ANN204
62 |         """Initialize database connection and setup.
   |
   = help: Add return type annotation: `None`

src/jmbde/core/database.py:61:33: FA100 Add `from __future__ import annotations` to simplify `typing.Union`
   |
59 |     """
60 | 
61 |     def __init__(self, db_path: Union[str, Path] = Config.DATABASE_PATH):
   |                                 ^^^^^ FA100
62 |         """Initialize database connection and setup.
   |

src/jmbde/core/database.py:82:25: G004 Logging statement uses f-string
   |
80 |             self.connection.row_factory = sqlite3.Row
81 |             self._create_tables()
82 |             logger.info(f"Database initialized successfully at {self.db_path}")
   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
83 |         except Exception as e:
84 |             logger.error(f"Failed to initialize database: {e}")
   |

src/jmbde/core/database.py:84:13: TRY400 Use `logging.exception` instead of `logging.error`
   |
82 |             logger.info(f"Database initialized successfully at {self.db_path}")
83 |         except Exception as e:
84 |             logger.error(f"Failed to initialize database: {e}")
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400
85 |             raise DatabaseError(f"Database initialization failed: {e}") from e
   |
   = help: Replace with `exception`

src/jmbde/core/database.py:84:26: G004 Logging statement uses f-string
   |
82 |             logger.info(f"Database initialized successfully at {self.db_path}")
83 |         except Exception as e:
84 |             logger.error(f"Failed to initialize database: {e}")
   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
85 |             raise DatabaseError(f"Database initialization failed: {e}") from e
   |

src/jmbde/core/database.py:85:19: TRY003 Avoid specifying long messages outside the exception class
   |
83 |         except Exception as e:
84 |             logger.error(f"Failed to initialize database: {e}")
85 |             raise DatabaseError(f"Database initialization failed: {e}") from e
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY003
86 | 
87 |     @contextmanager
   |

src/jmbde/core/database.py:85:33: EM102 Exception must not use an f-string literal, assign to variable first
   |
83 |         except Exception as e:
84 |             logger.error(f"Failed to initialize database: {e}")
85 |             raise DatabaseError(f"Database initialization failed: {e}") from e
   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM102
86 | 
87 |     @contextmanager
   |
   = help: Assign to variable; remove f-string literal

src/jmbde/core/database.py:88:9: ANN201 Missing return type annotation for public function `transaction`
   |
87 |     @contextmanager
88 |     def transaction(self):
   |         ^^^^^^^^^^^ ANN201
89 |         """Context manager for database transactions.
   |
   = help: Add return type annotation

src/jmbde/core/database.py:98:13: TRY400 Use `logging.exception` instead of `logging.error`
   |
96 |         except Exception as e:
97 |             self.connection.rollback()
98 |             logger.error(f"Transaction failed: {e}")
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400
99 |             raise DatabaseError(f"Transaction failed: {e}") from e
   |
   = help: Replace with `exception`

src/jmbde/core/database.py:98:26: G004 Logging statement uses f-string
   |
96 |         except Exception as e:
97 |             self.connection.rollback()
98 |             logger.error(f"Transaction failed: {e}")
   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
99 |             raise DatabaseError(f"Transaction failed: {e}") from e
   |

src/jmbde/core/database.py:99:19: TRY003 Avoid specifying long messages outside the exception class
    |
 97 |             self.connection.rollback()
 98 |             logger.error(f"Transaction failed: {e}")
 99 |             raise DatabaseError(f"Transaction failed: {e}") from e
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY003
100 | 
101 |     def _create_tables(self) -> None:
    |

src/jmbde/core/database.py:99:33: EM102 Exception must not use an f-string literal, assign to variable first
    |
 97 |             self.connection.rollback()
 98 |             logger.error(f"Transaction failed: {e}")
 99 |             raise DatabaseError(f"Transaction failed: {e}") from e
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ EM102
100 | 
101 |     def _create_tables(self) -> None:
    |
    = help: Assign to variable; remove f-string literal

src/jmbde/core/database.py:151:89: E501 Line too long (93 > 88)
    |
149 |                 )
150 |                 cursor.execute(
151 |                     "CREATE INDEX IF NOT EXISTS idx_device_serial ON devices(serial_number)",
    |                                                                                         ^^^^^ E501
152 |                 )
    |

src/jmbde/core/database.py:156:13: TRY400 Use `logging.exception` instead of `logging.error`
    |
154 |                 logger.info("Database tables and indices created successfully")
155 |         except Exception as e:
156 |             logger.error(f"Failed to create tables: {e}")
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400
157 |             raise DatabaseError(f"Table creation failed: {e}") from e
    |
    = help: Replace with `exception`

src/jmbde/core/database.py:156:26: G004 Logging statement uses f-string
    |
154 |                 logger.info("Database tables and indices created successfully")
155 |         except Exception as e:
156 |             logger.error(f"Failed to create tables: {e}")
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
157 |             raise DatabaseError(f"Table creation failed: {e}") from e
    |

src/jmbde/core/database.py:157:19: TRY003 Avoid specifying long messages outside the exception class
    |
155 |         except Exception as e:
156 |             logger.error(f"Failed to create tables: {e}")
157 |             raise DatabaseError(f"Table creation failed: {e}") from e
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY003
158 | 
159 |     def add_employee(self, employee: EmployeeModel) -> int:
    |

src/jmbde/core/database.py:157:33: EM102 Exception must not use an f-string literal, assign to variable first
    |
155 |         except Exception as e:
156 |             logger.error(f"Failed to create tables: {e}")
157 |             raise DatabaseError(f"Table creation failed: {e}") from e
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM102
158 | 
159 |     def add_employee(self, employee: EmployeeModel) -> int:
    |
    = help: Assign to variable; remove f-string literal

src/jmbde/core/database.py:195:29: G004 Logging statement uses f-string
    |
193 |                 )
194 |                 employee_id = cursor.lastrowid
195 |                 logger.info(f"Added employee: {employee.name} (ID: {employee_id})")
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
196 |                 return employee_id
197 |         except Exception as e:
    |

src/jmbde/core/database.py:198:13: TRY400 Use `logging.exception` instead of `logging.error`
    |
196 |                 return employee_id
197 |         except Exception as e:
198 |             logger.error(f"Failed to add employee {employee.name}: {e}")
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400
199 |             raise DatabaseError(f"Failed to add employee: {e}") from e
    |
    = help: Replace with `exception`

src/jmbde/core/database.py:198:26: G004 Logging statement uses f-string
    |
196 |                 return employee_id
197 |         except Exception as e:
198 |             logger.error(f"Failed to add employee {employee.name}: {e}")
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
199 |             raise DatabaseError(f"Failed to add employee: {e}") from e
    |

src/jmbde/core/database.py:199:19: TRY003 Avoid specifying long messages outside the exception class
    |
197 |         except Exception as e:
198 |             logger.error(f"Failed to add employee {employee.name}: {e}")
199 |             raise DatabaseError(f"Failed to add employee: {e}") from e
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY003
200 | 
201 |     def get_employee(self, employee_id: int) -> Optional[dict[str, Any]]:
    |

src/jmbde/core/database.py:199:33: EM102 Exception must not use an f-string literal, assign to variable first
    |
197 |         except Exception as e:
198 |             logger.error(f"Failed to add employee {employee.name}: {e}")
199 |             raise DatabaseError(f"Failed to add employee: {e}") from e
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM102
200 | 
201 |     def get_employee(self, employee_id: int) -> Optional[dict[str, Any]]:
    |
    = help: Assign to variable; remove f-string literal

src/jmbde/core/database.py:201:49: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
    |
199 |             raise DatabaseError(f"Failed to add employee: {e}") from e
200 | 
201 |     def get_employee(self, employee_id: int) -> Optional[dict[str, Any]]:
    |                                                 ^^^^^^^^ FA100
202 |         """Retrieve employee data by ID.
    |

src/jmbde/core/database.py:224:13: TRY400 Use `logging.exception` instead of `logging.error`
    |
222 |                 return dict(result) if result else None
223 |         except Exception as e:
224 |             logger.error(f"Failed to retrieve employee {employee_id}: {e}")
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400
225 |             raise DatabaseError(f"Employee retrieval failed: {e}") from e
    |
    = help: Replace with `exception`

src/jmbde/core/database.py:224:26: G004 Logging statement uses f-string
    |
222 |                 return dict(result) if result else None
223 |         except Exception as e:
224 |             logger.error(f"Failed to retrieve employee {employee_id}: {e}")
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
225 |             raise DatabaseError(f"Employee retrieval failed: {e}") from e
    |

src/jmbde/core/database.py:225:19: TRY003 Avoid specifying long messages outside the exception class
    |
223 |         except Exception as e:
224 |             logger.error(f"Failed to retrieve employee {employee_id}: {e}")
225 |             raise DatabaseError(f"Employee retrieval failed: {e}") from e
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY003
226 | 
227 |     def get_employees(
    |

src/jmbde/core/database.py:225:33: EM102 Exception must not use an f-string literal, assign to variable first
    |
223 |         except Exception as e:
224 |             logger.error(f"Failed to retrieve employee {employee_id}: {e}")
225 |             raise DatabaseError(f"Employee retrieval failed: {e}") from e
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM102
226 | 
227 |     def get_employees(
    |
    = help: Assign to variable; remove f-string literal

src/jmbde/core/database.py:229:9: FBT001 Boolean-typed positional argument in function definition
    |
227 |     def get_employees(
228 |         self,
229 |         active_only: bool = True,
    |         ^^^^^^^^^^^ FBT001
230 |         department: Optional[str] = None,
231 |     ) -> list[dict[str, Any]]:
    |

src/jmbde/core/database.py:229:9: FBT002 Boolean default positional argument in function definition
    |
227 |     def get_employees(
228 |         self,
229 |         active_only: bool = True,
    |         ^^^^^^^^^^^ FBT002
230 |         department: Optional[str] = None,
231 |     ) -> list[dict[str, Any]]:
    |

src/jmbde/core/database.py:230:21: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
    |
228 |         self,
229 |         active_only: bool = True,
230 |         department: Optional[str] = None,
    |                     ^^^^^^^^ FA100
231 |     ) -> list[dict[str, Any]]:
232 |         """Retrieve all employees matching the specified criteria.
    |

src/jmbde/core/database.py:262:13: TRY400 Use `logging.exception` instead of `logging.error`
    |
260 |                 return [dict(row) for row in cursor.fetchall()]
261 |         except Exception as e:
262 |             logger.error(f"Failed to retrieve employees: {e}")
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400
263 |             raise DatabaseError(f"Employee retrieval failed: {e}") from e
    |
    = help: Replace with `exception`

src/jmbde/core/database.py:262:26: G004 Logging statement uses f-string
    |
260 |                 return [dict(row) for row in cursor.fetchall()]
261 |         except Exception as e:
262 |             logger.error(f"Failed to retrieve employees: {e}")
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
263 |             raise DatabaseError(f"Employee retrieval failed: {e}") from e
    |

src/jmbde/core/database.py:263:19: TRY003 Avoid specifying long messages outside the exception class
    |
261 |         except Exception as e:
262 |             logger.error(f"Failed to retrieve employees: {e}")
263 |             raise DatabaseError(f"Employee retrieval failed: {e}") from e
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY003
264 | 
265 |     def update_employee(self, employee_id: int, data: dict[str, Any]) -> bool:
    |

src/jmbde/core/database.py:263:33: EM102 Exception must not use an f-string literal, assign to variable first
    |
261 |         except Exception as e:
262 |             logger.error(f"Failed to retrieve employees: {e}")
263 |             raise DatabaseError(f"Employee retrieval failed: {e}") from e
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM102
264 | 
265 |     def update_employee(self, employee_id: int, data: dict[str, Any]) -> bool:
    |
    = help: Assign to variable; remove f-string literal

src/jmbde/core/database.py:298:21: S608 Possible SQL injection vector through string-based query construction
    |
296 |                   return False
297 |   
298 |               query = """
    |  _____________________^
299 | |                 UPDATE employees
300 | |                 SET {}
301 | |                 WHERE id = ?
302 | |             """.format(
303 | |                 ", ".join(f"{field} = ?" for field in update_fields),
304 | |             )
    | |_____________^ S608
305 |   
306 |               with self.transaction() as cursor:
    |

src/jmbde/core/database.py:310:33: G004 Logging statement uses f-string
    |
308 |                 success = cursor.rowcount > 0
309 |                 if success:
310 |                     logger.info(f"Updated employee {employee_id}")
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
311 |                 return success
312 |         except Exception as e:
    |

src/jmbde/core/database.py:313:13: TRY400 Use `logging.exception` instead of `logging.error`
    |
311 |                 return success
312 |         except Exception as e:
313 |             logger.error(f"Failed to update employee {employee_id}: {e}")
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400
314 |             raise DatabaseError(f"Employee update failed: {e}") from e
    |
    = help: Replace with `exception`

src/jmbde/core/database.py:313:26: G004 Logging statement uses f-string
    |
311 |                 return success
312 |         except Exception as e:
313 |             logger.error(f"Failed to update employee {employee_id}: {e}")
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
314 |             raise DatabaseError(f"Employee update failed: {e}") from e
    |

src/jmbde/core/database.py:314:19: TRY003 Avoid specifying long messages outside the exception class
    |
312 |         except Exception as e:
313 |             logger.error(f"Failed to update employee {employee_id}: {e}")
314 |             raise DatabaseError(f"Employee update failed: {e}") from e
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY003
315 | 
316 |     def delete_employee(self, employee_id: int) -> bool:
    |

src/jmbde/core/database.py:314:33: EM102 Exception must not use an f-string literal, assign to variable first
    |
312 |         except Exception as e:
313 |             logger.error(f"Failed to update employee {employee_id}: {e}")
314 |             raise DatabaseError(f"Employee update failed: {e}") from e
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM102
315 | 
316 |     def delete_employee(self, employee_id: int) -> bool:
    |
    = help: Assign to variable; remove f-string literal

src/jmbde/core/database.py:337:33: G004 Logging statement uses f-string
    |
335 |                 success = cursor.rowcount > 0
336 |                 if success:
337 |                     logger.info(f"Deleted employee {employee_id}")
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
338 |                 return success
339 |         except Exception as e:
    |

src/jmbde/core/database.py:340:13: TRY400 Use `logging.exception` instead of `logging.error`
    |
338 |                 return success
339 |         except Exception as e:
340 |             logger.error(f"Failed to delete employee {employee_id}: {e}")
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400
341 |             raise DatabaseError(f"Employee deletion failed: {e}") from e
    |
    = help: Replace with `exception`

src/jmbde/core/database.py:340:26: G004 Logging statement uses f-string
    |
338 |                 return success
339 |         except Exception as e:
340 |             logger.error(f"Failed to delete employee {employee_id}: {e}")
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
341 |             raise DatabaseError(f"Employee deletion failed: {e}") from e
    |

src/jmbde/core/database.py:341:19: TRY003 Avoid specifying long messages outside the exception class
    |
339 |         except Exception as e:
340 |             logger.error(f"Failed to delete employee {employee_id}: {e}")
341 |             raise DatabaseError(f"Employee deletion failed: {e}") from e
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY003
342 | 
343 |     def cleanup(self) -> None:
    |

src/jmbde/core/database.py:341:33: EM102 Exception must not use an f-string literal, assign to variable first
    |
339 |         except Exception as e:
340 |             logger.error(f"Failed to delete employee {employee_id}: {e}")
341 |             raise DatabaseError(f"Employee deletion failed: {e}") from e
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM102
342 | 
343 |     def cleanup(self) -> None:
    |
    = help: Assign to variable; remove f-string literal

src/jmbde/core/database.py:353:13: TRY400 Use `logging.exception` instead of `logging.error`
    |
351 |                 logger.info("Database connection closed successfully")
352 |         except Exception as e:
353 |             logger.error(f"Database cleanup failed: {e}")
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY400
354 |             raise DatabaseError(f"Database cleanup failed: {e}") from e
    |
    = help: Replace with `exception`

src/jmbde/core/database.py:353:26: G004 Logging statement uses f-string
    |
351 |                 logger.info("Database connection closed successfully")
352 |         except Exception as e:
353 |             logger.error(f"Database cleanup failed: {e}")
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G004
354 |             raise DatabaseError(f"Database cleanup failed: {e}") from e
    |

src/jmbde/core/database.py:354:19: TRY003 Avoid specifying long messages outside the exception class
    |
352 |         except Exception as e:
353 |             logger.error(f"Database cleanup failed: {e}")
354 |             raise DatabaseError(f"Database cleanup failed: {e}") from e
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TRY003
355 | 
356 |     def __enter__(self):
    |

src/jmbde/core/database.py:354:33: EM102 Exception must not use an f-string literal, assign to variable first
    |
352 |         except Exception as e:
353 |             logger.error(f"Database cleanup failed: {e}")
354 |             raise DatabaseError(f"Database cleanup failed: {e}") from e
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EM102
355 | 
356 |     def __enter__(self):
    |
    = help: Assign to variable; remove f-string literal

src/jmbde/core/database.py:356:9: ANN204 Missing return type annotation for special method `__enter__`
    |
354 |             raise DatabaseError(f"Database cleanup failed: {e}") from e
355 | 
356 |     def __enter__(self):
    |         ^^^^^^^^^ ANN204
357 |         """Context manager enter."""
358 |         return self
    |
    = help: Add return type annotation

src/jmbde/core/database.py:360:9: ANN204 Missing return type annotation for special method `__exit__`
    |
358 |         return self
359 | 
360 |     def __exit__(self, exc_type, exc_val, exc_tb):
    |         ^^^^^^^^ ANN204
361 |         """Context manager exit."""
362 |         self.cleanup()
    |
    = help: Add return type annotation

src/jmbde/core/database.py:360:24: ANN001 Missing type annotation for function argument `exc_type`
    |
358 |         return self
359 | 
360 |     def __exit__(self, exc_type, exc_val, exc_tb):
    |                        ^^^^^^^^ ANN001
361 |         """Context manager exit."""
362 |         self.cleanup()
    |

src/jmbde/core/database.py:360:34: ANN001 Missing type annotation for function argument `exc_val`
    |
358 |         return self
359 | 
360 |     def __exit__(self, exc_type, exc_val, exc_tb):
    |                                  ^^^^^^^ ANN001
361 |         """Context manager exit."""
362 |         self.cleanup()
    |

src/jmbde/core/database.py:360:43: ANN001 Missing type annotation for function argument `exc_tb`
    |
358 |         return self
359 | 
360 |     def __exit__(self, exc_type, exc_val, exc_tb):
    |                                           ^^^^^^ ANN001
361 |         """Context manager exit."""
362 |         self.cleanup()
    |

src/jmbde/core/security.py:1:1: D100 Missing docstring in public module
src/jmbde/core/security.py:7:7: D101 Missing docstring in public class
  |
7 | class SecurityManager:
  |       ^^^^^^^^^^^^^^^ D101
8 |     def __init__(self, key: Optional[bytes] = None):
9 |         self._key = key or Fernet.generate_key()
  |

src/jmbde/core/security.py:8:9: ANN204 Missing return type annotation for special method `__init__`
   |
 7 | class SecurityManager:
 8 |     def __init__(self, key: Optional[bytes] = None):
   |         ^^^^^^^^ ANN204
 9 |         self._key = key or Fernet.generate_key()
10 |         self._fernet = Fernet(self._key)
   |
   = help: Add return type annotation: `None`

src/jmbde/core/security.py:8:29: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
   |
 7 | class SecurityManager:
 8 |     def __init__(self, key: Optional[bytes] = None):
   |                             ^^^^^^^^ FA100
 9 |         self._key = key or Fernet.generate_key()
10 |         self._fernet = Fernet(self._key)
   |

src/jmbde/core/security.py:12:9: D102 Missing docstring in public method
   |
10 |         self._fernet = Fernet(self._key)
11 | 
12 |     def encrypt_data(self, data: str) -> bytes:
   |         ^^^^^^^^^^^^ D102
13 |         return self._fernet.encrypt(data.encode())
   |

src/jmbde/core/security.py:15:9: D102 Missing docstring in public method
   |
13 |         return self._fernet.encrypt(data.encode())
14 | 
15 |     def decrypt_data(self, encrypted_data: bytes) -> str:
   |         ^^^^^^^^^^^^ D102
16 |         return self._fernet.decrypt(encrypted_data).decode()
   |

src/jmbde/core/settings.py:1:1: EXE001 Shebang is present but file is not executable
  |
1 | #!/usr/bin/env python3
  | ^^^^^^^^^^^^^^^^^^^^^^ EXE001
2 | 
3 | """Settings Management Module for JMBDE
  |

src/jmbde/core/settings.py:3:1: D400 First line should end with a period
   |
 1 |   #!/usr/bin/env python3
 2 |   
 3 | / """Settings Management Module for JMBDE
 4 | | 
 5 | | This module handles application settings and configuration management
 6 | | for the JMBDE application.
 7 | | 
 8 | | Copyright (C) 2018-2024 Jürgen Mülbert
 9 | | License: GPL-3.0
10 | | """
   | |___^ D400
11 |   
12 |   import json
   |
   = help: Add period

src/jmbde/core/settings.py:67:5: N815 Variable `settingsChanged` in class scope should not be mixedCase
   |
66 |     # Qt Signals for settings changes
67 |     settingsChanged = Signal()
   |     ^^^^^^^^^^^^^^^ N815
68 |     themeChanged = Signal(str)
69 |     languageChanged = Signal(str)
   |

src/jmbde/core/settings.py:68:5: N815 Variable `themeChanged` in class scope should not be mixedCase
   |
66 |     # Qt Signals for settings changes
67 |     settingsChanged = Signal()
68 |     themeChanged = Signal(str)
   |     ^^^^^^^^^^^^ N815
69 |     languageChanged = Signal(str)
   |

src/jmbde/core/settings.py:69:5: N815 Variable `languageChanged` in class scope should not be mixedCase
   |
67 |     settingsChanged = Signal()
68 |     themeChanged = Signal(str)
69 |     languageChanged = Signal(str)
   |     ^^^^^^^^^^^^^^^ N815
70 | 
71 |     def __init__(self, config_path: Optional[Path] = None) -> None:
   |

src/jmbde/core/settings.py:71:37: FA100 Add `from __future__ import annotations` to simplify `typing.Optional`
   |
69 |     languageChanged = Signal(str)
70 | 
71 |     def __init__(self, config_path: Optional[Path] = None) -> None:
   |                                     ^^^^^^^^ FA100
72 |         """Initialize Settings manager.
   |

src/jmbde/core/settings.py:88:21: G004 Logging statement uses f-string
   |
86 |         self._application = App

Copy link
Contributor Author

🦙 MegaLinter status: ❌ ERROR

Descriptor Linter Files Fixed Errors Elapsed time
❌ ACTION actionlint 21 1 0.18s
✅ BASH bash-exec 4 0 0.02s
✅ BASH shellcheck 4 0 0.17s
✅ BASH shfmt 4 0 0 0.09s
❌ COPYPASTE jscpd yes 18 3.37s
✅ CSS stylelint 1 0 0 1.34s
❌ DOCKERFILE hadolint 1 1 0.14s
✅ HTML djlint 1 0 1.03s
✅ HTML htmlhint 1 0 0.25s
✅ JSON jsonlint 9 0 0.19s
✅ JSON prettier 14 0 0 0.63s
✅ JSON v8r 6 0 13.31s
⚠️ MARKDOWN markdownlint 42 8 705 6.31s
❌ MARKDOWN markdown-link-check 42 23 79.41s
✅ MARKDOWN markdown-table-formatter 42 9 0 0.28s
❌ PYTHON bandit 41 33 0.87s
⚠️ PYTHON black 41 0 1 0.8s
❌ PYTHON flake8 41 12 0.47s
✅ PYTHON isort 41 9 0 0.25s
❌ PYTHON mypy 41 1 0.23s
❌ PYTHON pylint 41 36 5.76s
❌ PYTHON ruff 41 9 18 0.07s
✅ REPOSITORY checkov yes no 16.6s
❌ REPOSITORY gitleaks yes 1 9.42s
❌ REPOSITORY git_diff yes 1 0.08s
✅ REPOSITORY grype yes no 11.27s
✅ REPOSITORY secretlint yes no 1.72s
✅ REPOSITORY trivy yes no 7.7s
✅ REPOSITORY trivy-sbom yes no 0.11s
✅ REPOSITORY trufflehog yes no 3.6s
❌ SPELL cspell 169 761 25.51s
❌ SPELL lychee 82 27 19.42s
❌ SPELL vale 39 2407 164.35s
❌ SQL sqlfluff 1 53 4.85s
✅ YAML prettier 43 1 0 1.14s
❌ YAML v8r 36 1 60.27s
❌ YAML yamllint 43 37 2.2s

See detailed report in MegaLinter reports

MegaLinter is graciously provided by OX Security

@jmuelbert jmuelbert merged commit 7ee7711 into resolve-wf-issues Jan 12, 2025
4 checks passed
@jmuelbert jmuelbert deleted the fix/code-quality branch January 12, 2025 06:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant