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.development
|
||||||
.env.test
|
.env.test
|
||||||
.env.production
|
.env.production
|
||||||
LINenv/
|
LINenv*/
|
||||||
WINenv/
|
WINenv*/
|
||||||
MACenv/
|
MACenv*/
|
||||||
|
|
||||||
# Fichiers de dépendances
|
# Fichiers de dépendances
|
||||||
/node_modules/
|
/node_modules/
|
||||||
|
@ -4,7 +4,6 @@ setlocal enabledelayedexpansion
|
|||||||
REM === PATH SETUP ===
|
REM === PATH SETUP ===
|
||||||
set PARENT_DIR=%~dp0
|
set PARENT_DIR=%~dp0
|
||||||
set BUILD_DIR=%~dp0..
|
set BUILD_DIR=%~dp0..
|
||||||
set VENV_PATH=%PARENT_DIR%\WINenv
|
|
||||||
set PYTHON_IN_VENV=%VENV_PATH%\Scripts\python.exe
|
set PYTHON_IN_VENV=%VENV_PATH%\Scripts\python.exe
|
||||||
set ICON_PATH=data/assets/icon.ico
|
set ICON_PATH=data/assets/icon.ico
|
||||||
set CONFIG_FILE=%PARENT_DIR%\config.json
|
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
|
"Get-Content '%CONFIG_FILE%' | ConvertFrom-Json | Select-Object -ExpandProperty app_name"') do set APP_NAME=%%i
|
||||||
for /f "delims=" %%i in ('powershell -NoProfile -Command ^
|
for /f "delims=" %%i in ('powershell -NoProfile -Command ^
|
||||||
"Get-Content '%CONFIG_FILE%' | ConvertFrom-Json | Select-Object -ExpandProperty architecture"') do set ARCHITECTURE=%%i
|
"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%
|
set EXE_NAME=%APP_NAME%-Windows-%ARCHITECTURE%
|
||||||
|
|
||||||
REM === Construct full python path from config.json ===
|
REM === Construct full python path from config.json ===
|
||||||
|
@ -3,5 +3,5 @@
|
|||||||
"python_version": "3.11.7",
|
"python_version": "3.11.7",
|
||||||
"app_os": "Windows",
|
"app_os": "Windows",
|
||||||
"app_version": "1.0.0",
|
"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 sys
|
||||||
import os
|
from PyQt5.QtWidgets import QApplication
|
||||||
import tempfile
|
from ui.windows.main import Main
|
||||||
|
from core.theme import get_sheet
|
||||||
|
|
||||||
def verify_path(path):
|
def main():
|
||||||
# Temporary verification function
|
app = QApplication(sys.argv)
|
||||||
if os.path.exists(path):
|
app.setStyleSheet(get_sheet())
|
||||||
print(f"Path '{path}' exists.")
|
window = Main()
|
||||||
else:
|
|
||||||
print(f"Path '{path}' does not exist.")
|
|
||||||
|
|
||||||
class PathWidget(QWidget):
|
window.show()
|
||||||
def __init__(self):
|
return app.exec()
|
||||||
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())
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app = QApplication(sys.argv)
|
sys.exit(main())
|
||||||
widget = PathWidget()
|
|
||||||
widget.show()
|
|
||||||
sys.exit(app.exec_())
|
|
10
open.bat
10
open.bat
@ -4,8 +4,6 @@ setlocal enabledelayedexpansion
|
|||||||
REM Set file paths
|
REM Set file paths
|
||||||
set CONFIG_FILE=%~dp0config.json
|
set CONFIG_FILE=%~dp0config.json
|
||||||
set REQUIREMENTS=requirements.txt
|
set REQUIREMENTS=requirements.txt
|
||||||
set ENV_NAME=WINenv
|
|
||||||
set ENV_PATH=%~dp0%ENV_NAME%
|
|
||||||
|
|
||||||
REM Extract config.json fields using PowerShell
|
REM Extract config.json fields using PowerShell
|
||||||
for /f "delims=" %%i in ('powershell -NoProfile -Command ^
|
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
|
REM Construct python executable path
|
||||||
set PYTHON_EXEC=C:\Logiciels\Python\%ARCHITECTURE%\%PYTHON_VERSION%\python.exe
|
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%" (
|
if not exist "%PYTHON_EXEC%" (
|
||||||
echo [ERROR] Python introuvable à: %PYTHON_EXEC%
|
echo [ERROR] Python introuvable à: %PYTHON_EXEC%
|
||||||
echo Veuillez vérifier votre config.json ou le dossier d'installation.
|
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" (
|
if not exist "%ENV_PATH%\Scripts\activate.bat" (
|
||||||
echo [INFO] Environnement virtuel introuvable, création...
|
echo [INFO] Environnement virtuel introuvable, création...
|
||||||
"%PYTHON_EXEC%" -m venv "%ENV_NAME%"
|
"%PYTHON_EXEC%" -m venv "%ENV_NAME%"
|
||||||
call "%ENV_PATH%\Scripts\activate.bat"
|
|
||||||
echo [INFO] Installation des dépendances...
|
echo [INFO] Installation des dépendances...
|
||||||
pip install --upgrade pip
|
"%ENV_PATH%\Scripts\pip" install --upgrade pip
|
||||||
pip install -r "%REQUIREMENTS%"
|
"%ENV_PATH%\Scripts\pip" install -r "%REQUIREMENTS%"
|
||||||
) else (
|
) else (
|
||||||
echo [INFO] Environnement virtuel trouvé.
|
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)
|
@ -14,3 +14,9 @@ def resource_path(relative_path: str) -> Path:
|
|||||||
base_path = Path(__file__).parent.parent # Dev environment: source/ folder
|
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