it works
This commit is contained in:
parent
73cc0e3ca9
commit
6c69ab37ae
6
.gitignore
vendored
6
.gitignore
vendored
@ -20,9 +20,9 @@ desktop.ini
|
||||
.env.development
|
||||
.env.test
|
||||
.env.production
|
||||
LINenv/
|
||||
WINenv/
|
||||
MACenv/
|
||||
LINenv*/
|
||||
WINenv*/
|
||||
MACenv*/
|
||||
|
||||
# Fichiers de dépendances
|
||||
/node_modules/
|
||||
|
@ -4,7 +4,6 @@ setlocal enabledelayedexpansion
|
||||
REM === PATH SETUP ===
|
||||
set PARENT_DIR=%~dp0
|
||||
set BUILD_DIR=%~dp0..
|
||||
set VENV_PATH=%PARENT_DIR%\WINenv
|
||||
set PYTHON_IN_VENV=%VENV_PATH%\Scripts\python.exe
|
||||
set ICON_PATH=data/assets/icon.ico
|
||||
set CONFIG_FILE=%PARENT_DIR%\config.json
|
||||
@ -16,7 +15,7 @@ for /f "delims=" %%i in ('powershell -NoProfile -Command ^
|
||||
"Get-Content '%CONFIG_FILE%' | ConvertFrom-Json | Select-Object -ExpandProperty app_name"') do set APP_NAME=%%i
|
||||
for /f "delims=" %%i in ('powershell -NoProfile -Command ^
|
||||
"Get-Content '%CONFIG_FILE%' | ConvertFrom-Json | Select-Object -ExpandProperty architecture"') do set ARCHITECTURE=%%i
|
||||
|
||||
set VENV_PATH=%PARENT_DIR%\WINenv_%ARCHITECTURE%
|
||||
set EXE_NAME=%APP_NAME%-Windows-%ARCHITECTURE%
|
||||
|
||||
REM === Construct full python path from config.json ===
|
||||
|
@ -3,5 +3,5 @@
|
||||
"python_version": "3.11.7",
|
||||
"app_os": "Windows",
|
||||
"app_version": "1.0.0",
|
||||
"architecture": "x64"
|
||||
"architecture": "x32"
|
||||
}
|
106
core/theme.py
Normal file
106
core/theme.py
Normal file
@ -0,0 +1,106 @@
|
||||
def get_element_color(element: str) -> str:
|
||||
if element == "background":
|
||||
return "#FFFFFF"
|
||||
if element == "background2":
|
||||
return "#F5F5F5"
|
||||
if element == "background3":
|
||||
return "#E0E0E0"
|
||||
if element == "color":
|
||||
return "#5D5A5A"
|
||||
if element == "text":
|
||||
return "#000000"
|
||||
else:
|
||||
return "#000000"
|
||||
def get_sheet() -> str:
|
||||
return f"""
|
||||
QWidget {{
|
||||
background-color: {get_element_color("background")};
|
||||
color: {get_element_color("text")};
|
||||
}}
|
||||
QPushButton {{
|
||||
background-color: #0A84FF;
|
||||
color: {get_element_color("text")};
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
}}
|
||||
QPushButton:hover {{
|
||||
background-color: #007AFF;
|
||||
}}
|
||||
QLineEdit {{
|
||||
border: 1px solid #3C3C3E;
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
font-size: 14px;
|
||||
background-color: {get_element_color("background2")};
|
||||
color: {get_element_color("text")};
|
||||
}}
|
||||
QLabel {{
|
||||
color: {get_element_color("text")};
|
||||
}}
|
||||
QProgressBar {{
|
||||
border: 1px solid #3C3C3E;
|
||||
border-radius: 5px;
|
||||
background-color: {get_element_color("background2")};
|
||||
text-align: center;
|
||||
color: {get_element_color("text")};
|
||||
}}
|
||||
QProgressBar::chunk {{
|
||||
background-color: #0A84FF;
|
||||
border-radius: 3px;
|
||||
}}
|
||||
QFrame {{
|
||||
background-color: {get_element_color("background2")};
|
||||
border: none;
|
||||
}}
|
||||
QFrame#indicator_bar {{
|
||||
background-color: #0A84FF;
|
||||
}}
|
||||
QScrollBar:vertical {{
|
||||
border: none;
|
||||
background: #E0E0E0;
|
||||
width: 8px;
|
||||
margin: 0px;
|
||||
}}
|
||||
QScrollBar::handle:vertical {{
|
||||
background: #0A84FF;
|
||||
border-radius: 4px;
|
||||
min-height: 20px;
|
||||
}}
|
||||
QScrollBar::handle:vertical:hover {{
|
||||
background: #3B9CFF;
|
||||
}}
|
||||
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {{
|
||||
border: none;
|
||||
background: none;
|
||||
height: 0px;
|
||||
}}
|
||||
QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {{
|
||||
background: none;
|
||||
}}
|
||||
#drag_area {{
|
||||
border: 2px dashed #3498db; border-radius: 10px;
|
||||
}}
|
||||
QSlider::groove:horizontal {{
|
||||
border: 1px solid #3a9bdc;
|
||||
height: 10px;
|
||||
background: transparent;
|
||||
border-radius: 5px;
|
||||
}}
|
||||
QSlider::sub-page:horizontal {{
|
||||
background: #3a9bdc;
|
||||
border-radius: 5px;
|
||||
}}
|
||||
QSlider::add-page:horizontal {{
|
||||
background: {get_element_color("background3")};
|
||||
border-radius: 5px;
|
||||
}}
|
||||
QSlider::handle:horizontal {{
|
||||
background: white;
|
||||
border: 2px solid #3a9bdc;
|
||||
width: 14px;
|
||||
margin: -4px 0;
|
||||
border-radius: 7px;
|
||||
}}
|
||||
"""
|
83
core/verifier.py
Normal file
83
core/verifier.py
Normal file
@ -0,0 +1,83 @@
|
||||
import json, csv
|
||||
from utils.paths import resource_path
|
||||
|
||||
class Patient:
|
||||
def __init__(self, json_data : dict):
|
||||
self.json_data = json_data
|
||||
|
||||
def get_value(self, key):
|
||||
return self.json_data.get(key, None)
|
||||
|
||||
def compare_value(self, key, value):
|
||||
return self.get_value(key) == value
|
||||
|
||||
def __str__(self):
|
||||
return f"Patient({self.json_data})"
|
||||
class Patients:
|
||||
def __init__(self, patients_data : list[dict]):
|
||||
self.patients = [Patient(data) for data in patients_data]
|
||||
|
||||
def get_patients(self):
|
||||
return self.patients
|
||||
|
||||
def trouver(self, to_find):
|
||||
for patient in self.patients:
|
||||
if patient.get_value("Numéro de correspondance") == to_find.get_value("Numéro de correspondance"):
|
||||
return patient
|
||||
return None
|
||||
|
||||
class Verifier:
|
||||
def __init__(self):
|
||||
try:
|
||||
truth_file_path = resource_path("data/truth.json")
|
||||
with open(truth_file_path, 'r', encoding='utf-8') as file:
|
||||
truth_data = json.load(file)
|
||||
self.truth = Patients(truth_data["patients"])
|
||||
except Exception:
|
||||
self.truth = Patients([])
|
||||
|
||||
def verify(self, patients_csv: str):
|
||||
# Read CSV file and convert to list of dictionaries
|
||||
patients_data = []
|
||||
try:
|
||||
with open(patients_csv, 'r', encoding='utf-8') as file:
|
||||
csv_reader = csv.reader(file, delimiter=';')
|
||||
rows = list(csv_reader)
|
||||
|
||||
if not rows:
|
||||
return "CSV file is empty"
|
||||
|
||||
# First row contains column names
|
||||
headers = rows[0]
|
||||
# Convert each subsequent row to a dictionary
|
||||
for row in rows[1:]:
|
||||
patient_dict = {headers[i]: row[i] for i in range(len(headers))}
|
||||
patients_data.append(patient_dict)
|
||||
except FileNotFoundError:
|
||||
return f"Error: File {patients_csv} not found"
|
||||
except Exception as e:
|
||||
return f"Error reading CSV file: {e}"
|
||||
|
||||
self.patients = Patients(patients_data)
|
||||
|
||||
# Check if we have truth data
|
||||
if not self.truth.get_patients():
|
||||
return ["Erreur: Aucune donnée de vérité n'a pu être chargée"]
|
||||
|
||||
key_to_test = self.truth.get_patients()[0].json_data.keys()
|
||||
issues = []
|
||||
|
||||
for patient in self.patients.get_patients():
|
||||
issue_founded = False
|
||||
truth_patient = self.truth.trouver(patient)
|
||||
if truth_patient:
|
||||
for key in key_to_test:
|
||||
if not patient.compare_value(key, truth_patient.get_value(key)):
|
||||
issue_founded = True
|
||||
issues.append(f"Le patient avec le numéro de correspondance n°{patient.get_value('Numéro de correspondance')} a une discordance avec {key}. Attendu : {truth_patient.get_value(key)}, Trouvé : {patient.get_value(key)}")
|
||||
else:
|
||||
issue_founded = True
|
||||
issues.append(f"Le patient avec le numéro de correspondance n°{patient.get_value('Numéro de correspondance')} n'a pas été trouvé dans les données de vérité")
|
||||
if issue_founded:
|
||||
issues.append("")
|
||||
return issues
|
20
data/truth.json
Normal file
20
data/truth.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"patients": [
|
||||
{
|
||||
"Numéro de correspondance": "0",
|
||||
"date_de_la_pose_de_l_endoprothese": "2023-10-01"
|
||||
},
|
||||
{
|
||||
"Numéro de correspondance": "1",
|
||||
"date_de_la_pose_de_l_endoprothese": "2023-10-02"
|
||||
},
|
||||
{
|
||||
"Numéro de correspondance": "2",
|
||||
"date_de_la_pose_de_l_endoprothese": "2023-10-03"
|
||||
},
|
||||
{
|
||||
"Numéro de correspondance": "3",
|
||||
"date_de_la_pose_de_l_endoprothese": "2023-10-04"
|
||||
}
|
||||
]
|
||||
}
|
58
main.py
58
main.py
@ -1,53 +1,15 @@
|
||||
## Interface with only a path widget (combo of QLineEdit and QPushButton to explore the file system)
|
||||
## and a button : verify (call a temp verify function)
|
||||
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QLineEdit, QFileDialog
|
||||
import sys
|
||||
import os
|
||||
import tempfile
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
from ui.windows.main import Main
|
||||
from core.theme import get_sheet
|
||||
|
||||
def verify_path(path):
|
||||
# Temporary verification function
|
||||
if os.path.exists(path):
|
||||
print(f"Path '{path}' exists.")
|
||||
else:
|
||||
print(f"Path '{path}' does not exist.")
|
||||
def main():
|
||||
app = QApplication(sys.argv)
|
||||
app.setStyleSheet(get_sheet())
|
||||
window = Main()
|
||||
|
||||
class PathWidget(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
self.layout = QVBoxLayout()
|
||||
|
||||
# Create a QLineEdit for the path input
|
||||
self.path_input = QLineEdit(self)
|
||||
self.path_input.setPlaceholderText("Enter or select a path")
|
||||
self.layout.addWidget(self.path_input)
|
||||
|
||||
# Create a QPushButton to open the file dialog
|
||||
self.browse_button = QPushButton("Browse", self)
|
||||
self.browse_button.clicked.connect(self.open_file_dialog)
|
||||
self.layout.addWidget(self.browse_button)
|
||||
|
||||
# Create a QPushButton to verify the path
|
||||
self.verify_button = QPushButton("Verify", self)
|
||||
self.verify_button.clicked.connect(self.verify_path)
|
||||
self.layout.addWidget(self.verify_button)
|
||||
|
||||
self.setLayout(self.layout)
|
||||
self.setWindowTitle("Path Widget Example")
|
||||
|
||||
def open_file_dialog(self):
|
||||
path, _ = QFileDialog.getExistingDirectory(self, "Select Directory")
|
||||
if path:
|
||||
self.path_input.setText(path)
|
||||
|
||||
def verify_path(self):
|
||||
verify_path(self.path_input.text())
|
||||
window.show()
|
||||
return app.exec()
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
widget = PathWidget()
|
||||
widget.show()
|
||||
sys.exit(app.exec_())
|
||||
sys.exit(main())
|
10
open.bat
10
open.bat
@ -4,8 +4,6 @@ setlocal enabledelayedexpansion
|
||||
REM Set file paths
|
||||
set CONFIG_FILE=%~dp0config.json
|
||||
set REQUIREMENTS=requirements.txt
|
||||
set ENV_NAME=WINenv
|
||||
set ENV_PATH=%~dp0%ENV_NAME%
|
||||
|
||||
REM Extract config.json fields using PowerShell
|
||||
for /f "delims=" %%i in ('powershell -NoProfile -Command ^
|
||||
@ -16,7 +14,8 @@ for /f "delims=" %%i in ('powershell -NoProfile -Command ^
|
||||
|
||||
REM Construct python executable path
|
||||
set PYTHON_EXEC=C:\Logiciels\Python\%ARCHITECTURE%\%PYTHON_VERSION%\python.exe
|
||||
|
||||
set ENV_NAME=WINenv_%ARCHITECTURE%
|
||||
set ENV_PATH=%~dp0%ENV_NAME%
|
||||
if not exist "%PYTHON_EXEC%" (
|
||||
echo [ERROR] Python introuvable à: %PYTHON_EXEC%
|
||||
echo Veuillez vérifier votre config.json ou le dossier d'installation.
|
||||
@ -32,10 +31,9 @@ REM Check if virtual environment exists
|
||||
if not exist "%ENV_PATH%\Scripts\activate.bat" (
|
||||
echo [INFO] Environnement virtuel introuvable, création...
|
||||
"%PYTHON_EXEC%" -m venv "%ENV_NAME%"
|
||||
call "%ENV_PATH%\Scripts\activate.bat"
|
||||
echo [INFO] Installation des dépendances...
|
||||
pip install --upgrade pip
|
||||
pip install -r "%REQUIREMENTS%"
|
||||
"%ENV_PATH%\Scripts\pip" install --upgrade pip
|
||||
"%ENV_PATH%\Scripts\pip" install -r "%REQUIREMENTS%"
|
||||
) else (
|
||||
echo [INFO] Environnement virtuel trouvé.
|
||||
)
|
||||
|
76
toTest.csv
Normal file
76
toTest.csv
Normal file
File diff suppressed because one or more lines are too long
78
ui/windows/main.py
Normal file
78
ui/windows/main.py
Normal file
@ -0,0 +1,78 @@
|
||||
from PyQt5.QtGui import QIcon
|
||||
import utils.paths as paths
|
||||
from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QPushButton, QLineEdit, QFileDialog, QMainWindow, QWidget, QTextEdit
|
||||
from core.verifier import Verifier # Assuming Verifier is defined in core.verifier
|
||||
class Main(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.verifier = Verifier()
|
||||
|
||||
# Configurer la fenêtre avant de créer les widgets
|
||||
self.setMinimumSize(1000, 600)
|
||||
self.setWindowTitle("HoDA_Verifier")
|
||||
self.setWindowIcon(QIcon(paths.get_asset_path("icon")))
|
||||
self.setup_ui()
|
||||
|
||||
def setup_ui(self):
|
||||
# Create a central widget
|
||||
central_widget = QWidget()
|
||||
|
||||
self.main_layout = QVBoxLayout(central_widget)
|
||||
self.main_layout.setSpacing(20)
|
||||
|
||||
self.browse_layout = QHBoxLayout()
|
||||
self.browse_layout.setSpacing(10)
|
||||
# Create a QLineEdit for the path input
|
||||
self.path_input = QLineEdit(self)
|
||||
self.path_input.setPlaceholderText("Sélectionnes le fichier csv ->")
|
||||
self.browse_layout.addWidget(self.path_input)
|
||||
|
||||
# Create a QPushButton to open the file dialog
|
||||
self.browse_button = QPushButton("Parcourir", self)
|
||||
self.browse_button.clicked.connect(self.open_file_dialog)
|
||||
self.browse_layout.addWidget(self.browse_button)
|
||||
|
||||
# Create a QPushButton to verify the path
|
||||
self.verify_button = QPushButton("Vérifier", self)
|
||||
self.verify_button.clicked.connect(self.verify_file)
|
||||
|
||||
self.main_layout.addLayout(self.browse_layout)
|
||||
|
||||
# Create a QTextEdit for displaying verification results
|
||||
self.results_display = QTextEdit(self)
|
||||
self.results_display.setPlaceholderText("Les résultats de la vérification apparaîtront ici...")
|
||||
self.results_display.setReadOnly(True) # Make it read-only
|
||||
self.results_display.setMinimumHeight(200) # Set minimum height
|
||||
self.main_layout.addWidget(self.results_display)
|
||||
|
||||
self.main_layout.addWidget(self.verify_button)
|
||||
|
||||
# Set the layout on the central widget
|
||||
central_widget.setLayout(self.main_layout)
|
||||
# Set the central widget
|
||||
self.setCentralWidget(central_widget)
|
||||
|
||||
def open_file_dialog(self):
|
||||
path, _ = QFileDialog.getOpenFileName(self, "Select File", "", "CSV Files (*.csv)")
|
||||
if path:
|
||||
self.path_input.setText(path)
|
||||
|
||||
def verify_file(self):
|
||||
file_path = self.path_input.text()
|
||||
if not file_path:
|
||||
self.results_display.setText("Veuillez sélectionner un fichier CSV d'abord.")
|
||||
return
|
||||
|
||||
result = self.verifier.verify(file_path)
|
||||
|
||||
# Clear previous results
|
||||
self.results_display.clear()
|
||||
|
||||
if isinstance(result, list):
|
||||
if result: # If there are issues
|
||||
# Join the list of issues with newlines
|
||||
self.results_display.setText("\n".join(result))
|
||||
else: # No issues found
|
||||
self.results_display.setText("✅ Aucune discordance trouvée ! Toutes les données correspondent.")
|
||||
else: # If result is a string (error message)
|
||||
self.results_display.setText(result)
|
@ -13,4 +13,10 @@ def resource_path(relative_path: str) -> Path:
|
||||
except AttributeError:
|
||||
base_path = Path(__file__).parent.parent # Dev environment: source/ folder
|
||||
|
||||
return path.join(base_path, relative_path)
|
||||
return path.join(base_path, relative_path)
|
||||
|
||||
def get_data_dir() -> Path:
|
||||
return resource_path("data")
|
||||
|
||||
def get_asset_path(asset: str) -> Path:
|
||||
return path.join(get_data_dir(), "assets", f"{asset}.png")
|
Loading…
x
Reference in New Issue
Block a user