Skip to content

Commit 8aab05f

Browse files
committed
Enhance GUI to support generating CSV file and specifying log level
1 parent 5beefd3 commit 8aab05f

File tree

2 files changed

+74
-14
lines changed

2 files changed

+74
-14
lines changed

gui.py

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,27 @@
11
import PySimpleGUI as sg
2+
from uuid import uuid4
3+
from os import path
24
from main import main
35

46
sg.theme('Default1') # alternatives include, e.g., 'DarkGrey9'
57

6-
layout = [[sg.Text('Select a folder and CSV file, then click the Launch button.')],
7-
[sg.Text('Folder', size=(8, 1)), sg.Input(), sg.FolderBrowse()],
8-
[sg.Text('CSV File', size=(8, 1)), sg.Input(), sg.FileBrowse(file_types=["CSV .csv"])],
9-
[sg.Button('Launch')]]
8+
layout = [[sg.Text('Select a folder, a CSV file and, optionally, an output folder, then click the Launch button.')],
9+
[sg.Text('Folder', size=(17, 1)), sg.Input(key="-FOLDER-"), sg.FolderBrowse()],
10+
[sg.Text('CSV File', size=(17, 1)), sg.Input(key="-CSV_FILE-"), sg.FileBrowse(file_types=["CSV .csv"])],
11+
[
12+
sg.Text('Output Folder (optional)', size=(17, 1), tooltip='If specified, the main script will generate '
13+
'a CSV file in this folder'),
14+
sg.Input(key="-OUTPUT_FOLDER-"),
15+
sg.FolderBrowse()
16+
],
17+
[
18+
sg.Text('Log level', size=(17, 1)),
19+
sg.Radio('NOTSET (default)', "log_level_radio_group", key="-NOTSET-", default=True),
20+
sg.Radio('DEBUG', "log_level_radio_group", key="-DEBUG-"),
21+
sg.Radio('INFO', "log_level_radio_group", key="-INFO-"),
22+
sg.Radio('WARNING', "log_level_radio_group", key="-WARNING-"),
23+
],
24+
[sg.Button('Launch', tooltip='Launch the main script with the specified parameters')]]
1025

1126
# Create the Window
1227
window = sg.Window('dupeguru-post-processor (Graphical Launcher)', layout)
@@ -19,10 +34,52 @@
1934
break
2035
# Else, if the user clicked the Launch button, invoke the script's main function.
2136
elif event == 'Launch':
22-
path_to_folder = values[0]
23-
path_to_csv_file = values[1]
37+
# Retrieve and strip input values.
38+
path_to_folder = values["-FOLDER-"].strip()
39+
path_to_csv_file = values["-CSV_FILE-"].strip()
40+
path_to_output_folder = values["-OUTPUT_FOLDER-"].strip()
2441

25-
print("\nLaunching dupeguru-post-processor...\n")
26-
main(path_to_folder, path_to_csv_file)
42+
# Normalize the log level.
43+
log_level = "DEBUG" if values["-DEBUG-"] \
44+
else "INFO" if values["-INFO-"] \
45+
else "WARNING" if values["-WARNING-"] \
46+
else "NOTSET"
47+
48+
# Validate stripped input values.
49+
if not path.isdir(path_to_folder):
50+
sg.Popup("Folder path is invalid", keep_on_top=True)
51+
continue # end this iteration
52+
elif not path.isfile(path_to_csv_file):
53+
sg.Popup("CSV file path is invalid", keep_on_top=True)
54+
continue
55+
elif len(path_to_output_folder) > 0 and not path.isdir(path_to_output_folder):
56+
sg.Popup("Output folder (optional) path was specified, but is invalid", keep_on_top=True)
57+
continue
58+
59+
# If the user specified an output _folder_, generate an output file path; otherwise, default to None.
60+
path_to_output_file = None
61+
if len(path_to_output_folder) > 0:
62+
# Keep trying to generate a random file name that does not already exist.
63+
#
64+
# Note: This is not a foolproof way of preventing naming collisions. It is technically possible that some
65+
# other process creates a file at the same path, between now (i.e. the time we perform this name
66+
# collision check) and the time the main script creates a file at that path.
67+
#
68+
while True:
69+
random_file_name = f"{uuid4().hex}.csv"
70+
path_to_output_file = path.join(path_to_output_folder, random_file_name)
71+
if not path.isfile(path_to_output_file):
72+
break # stop iterating once we have a unique file name
73+
print(f"Output file path: {path.normpath(path_to_output_file)}\n")
74+
75+
print("Launching dupeguru-post-processor...\n")
76+
main(
77+
path.normpath(path_to_folder),
78+
path.normpath(path_to_csv_file),
79+
path.normpath(path_to_output_file),
80+
log_level=log_level
81+
)
82+
83+
sg.Popup("Done.", keep_on_top=True)
2784

2885
window.close()

main.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,13 @@ def get_file_paths_from_csv_file(path_to_csv_file):
6868
return file_paths
6969

7070

71-
def main(path_to_folder, path_to_csv_file, path_to_output_file=None):
71+
def main(path_to_folder, path_to_csv_file, path_to_output_file=None, log_level=logging.NOTSET):
7272
"""Entrypoint to the script."""
7373

74+
# Configure logging so entries are sent to STDOUT and so the threshold level is the one specified.
75+
level = logging.getLevelName(log_level) if type(log_level) is str else log_level
76+
logging.basicConfig(stream=sys.stdout, level=level)
77+
7478
logging.info(f'Folder : {path_to_folder}')
7579
logging.info(f'dupeGuru CSV : {path_to_csv_file}')
7680
logging.info(f'Output file : {path_to_output_file}')
@@ -95,13 +99,15 @@ def main(path_to_folder, path_to_csv_file, path_to_output_file=None):
9599

96100
# Either write the results to a CSV file or print them to STDOUT.
97101
if type(path_to_output_file) is str:
98-
with open(path_to_output_file, 'w', newline='') as f:
102+
with open(path_to_output_file, 'w', encoding='utf-8', newline='') as f:
99103
writer = csv.writer(f)
100104
rows = [[path] for path in sorted_differences] # gives `rows` the shape: `[ [path_1], [path_2], ... ]`
101105
writer.writerows(rows)
102106
else:
103107
print('\n'.join(sorted_differences))
104108

109+
print("\nDone.\n")
110+
105111

106112
if __name__ == '__main__':
107113
parser = argparse.ArgumentParser(description='Compares a folder to a CSV file exported from dupeGuru. Displays the '
@@ -118,7 +124,4 @@ def main(path_to_folder, path_to_csv_file, path_to_output_file=None):
118124
help='specify a logging level for the script')
119125
args = parser.parse_args()
120126

121-
# Configure logging so entries are sent to STDOUT and so the threshold level is the one specified.
122-
logging.basicConfig(stream=sys.stdout, level=logging.getLevelName(args.log_level))
123-
124-
main(args.folder, args.csv_file, args.output_csv_file)
127+
main(args.folder, args.csv_file, args.output_csv_file, args.log_level)

0 commit comments

Comments
 (0)