Qualite : pyproject.toml (ruff/pytest/pyright) + CI Gitea (lint/tests/build)

pyproject.toml devient le point d'entree unique de configuration des outils
(pytest.ini supprime, sa config y est deplacee). Les dependances restent dans
requirements.txt/requirements-dev.txt (deja utilises par setup.bat) plutot que
dupliquees ici : ce projet se distribue par PyInstaller, pas par "pip install".

ruff : configure puis passe sur tout app/ + tests/ (154 corrections
automatiques, purement mecaniques - tri des imports, imports multiples sur une
ligne separes, alias depreciees) suivies de 7 corrections manuelles ciblees :
  - app/ssh_connection.py : `raise ... from None` pour le refus explicite de
    passphrase (ce n'est pas un echec a diagnostiquer).
  - app/controllers/workspace_manager.py : zip() sans strict= documente en
    commentaire (deliberement tolerant a un workspace legerement perime).
  - tests/test_ai_redaction.py : nom de variable ambigu renomme.
  - E702 (construction compacte "widget = X(); widget.setY(...)" dans
    sftp_panel.py/tunnel_dialog.py) et E402 (quelques tests qui importent un
    symbole juste avant la section qui l'utilise) : ignores explicitement, ce
    sont des styles deliberes preexistants, pas des oublis.
`ruff check app main.py tests` est desormais propre.

pyright : mode "basic" (le code n'a jamais ete type). Plus de 200 signalements
sur ~300 etaient le meme faux positif connu de l'ecosysteme PySide6 (acces
plat aux enums Qt, ex. Qt.UserRole, valide a l'execution mais que les stubs ne
reconnaissent que sous leur forme imbriquee) : desactive avec justification en
commentaire. Reste un socle de 77 signalements reels (surtout des acces
Optional non filtres dans app/ui/tabs.py et app/ssh_connection.py) : non
corrige dans cette phase - resserrer le typage la ou pyright a raison est un
travail a part, pas une consequence automatique de l'ajout de l'outil. La CI
le lance en mode informatif (continue-on-error) tant que ce socle n'est pas
resorbe.

.gitea/workflows/ci.yml : lint (ruff, bloquant), tests (pytest, bloquant),
typecheck (pyright, informatif), build (PyInstaller, sur main uniquement,
artefact du dossier portable). Necessite un runner Gitea Actions Windows
enregistre - PySide6/pywinpty/Credential Manager/ACL NTFS sont Windows
uniquement, comme l'application elle-meme ; non verifiable depuis ce poste.

Suite complete revalidee apres coup (33/33) pour confirmer qu'aucune des 154
corrections automatiques n'a modifie de comportement.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Florian
2026-09-05 07:46:50 +02:00
parent 09b7ed092c
commit c39ef9c038
72 changed files with 697 additions and 268 deletions

61
pyproject.toml Normal file
View File

@@ -0,0 +1,61 @@
[project]
name = "pyssh-client"
version = "0.1.0"
description = "Client SSH/SFTP local (PySide6) : terminaux, tunnels, snippets, workspaces, assistant IA optionnel"
readme = "README.md"
requires-python = ">=3.10"
# Les dependances (runtime et dev) restent dans requirements.txt /
# requirements-dev.txt, deja utilises par setup.bat et la CI : les dupliquer
# ici cree un risque de desynchronisation pour aucun benefice reel, puisque
# le projet se distribue par PyInstaller (voir PySSHClient.spec), pas par
# "pip install". Ce fichier sert de point d'entree unique pour la
# configuration des outils (ruff, pytest, pyright).
[tool.ruff]
line-length = 110
target-version = "py310"
extend-exclude = ["venv", "build", "dist"]
[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B"]
ignore = [
"E501", # ligne trop longue : laisse au formateur, pas bloquant en l'etat
"E702", # construction compacte "widget = X(); widget.setY(...)" deliberee
# dans les panneaux SFTP/tunnels (un widget + sa config tiennent sur
# une ligne) : reecrire l'existant pour ca serait pur churn.
"E402", # plusieurs tests importent un symbole juste avant la section qui
# l'utilise pour la premiere fois, plutot qu'en haut du fichier -
# lisible dans des scripts sequentiels longs, et sans risque tant
# que l'import n'a pas d'effet de bord ordonne.
]
[tool.ruff.lint.isort]
known-first-party = ["app"]
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_all_scripts.py"]
[tool.pyright]
include = ["app", "main.py"]
exclude = ["venv", "build", "dist", "tests"]
venvPath = "."
venv = "venv"
# "basic" plutot que "strict" : le code n'a jamais ete type jusqu'ici, un mode
# strict noierait les vrais signaux sous des milliers d'avertissements de
# typage progressif. A resserrer progressivement, fichier par fichier.
typeCheckingMode = "basic"
pythonVersion = "3.10"
reportMissingImports = true
# Desactive : plus de 200 occurrences sont l'acces "plat" aux enums Qt
# (Qt.UserRole, QToolButton.InstantPopup...) - un style PyQt5 historique que
# PySide6 continue de supporter a l'execution, mais que ses stubs ne
# reconnaissent qu'a travers leur forme imbriquee (Qt.ItemDataRole.UserRole).
# Utilise partout dans ce projet, sans exception, et sans le moindre risque
# reel : le desactiver evite de noyer les vrais signaux. Le reste (une
# vingtaine de cas ou pyright perd le fil sur des patterns dynamiques - le
# monkey-patching de pyte dans terminal_widget.py, les QWidget generiques de
# split_pane.py) reste dans le rapport, a regarder au cas par cas plutot que
# supprime en bloc.
reportAttributeAccessIssue = false