11import json
22import re
33from pathlib import Path
4- from typing import Optional
4+ from typing import Optional , get_type_hints
55
66import yaml
77from pydantic import ValidationError
1212
1313# Create a console object for pretty printing
1414console = Console ()
15+ machine_config_types : dict = get_type_hints (MachineConfig )
1516
1617
1718def prompt (message : str , style : str = "" ) -> str :
@@ -24,55 +25,48 @@ def prompt(message: str, style: str = "") -> str:
2425
2526
2627def print_field_info (field : ModelField ):
27- console .print (field .name , style = "bold cyan" )
28- console .print (field .field_info .description , style = "cyan" )
28+ """
29+ Helper function to print out the name of the key being set up, along with a short
30+ description of what purpose the key serves.
31+ """
32+ console .print (
33+ f"{ field .name .replace ('_' , ' ' ).title ()} ({ field .name } )" ,
34+ style = "bold bright_cyan" ,
35+ )
36+ console .print (field .field_info .description , style = "italic bright_cyan" )
2937 if not isinstance (field .field_info .default , UndefinedType ):
30- console .print (f"Default: { field .field_info .default !r} " , style = "cyan " )
38+ console .print (f"Default: { field .field_info .default !r} " , style = "bright_cyan " )
3139
3240
3341def ask_for_input (category : str , again : bool = False ):
3442 """
35- Short while loop when to facilitate adding more than one value to a field in the
36- config .
43+ Perform a Boolean check to see if another value is to be appended to the current
44+ parameter being set up .
3745 """
3846 message = (
3947 "Would you like to add " + ("another" if again else "a" ) + f" { category } ? (y/n)"
4048 )
4149 while True :
42- answer = (
43- prompt (
44- message ,
45- )
46- .lower ()
47- .strip ()
48- )
50+ answer = prompt (message , style = "yellow" ).lower ().strip ()
4951 if answer in ("y" , "yes" ):
5052 return True
51- elif answer in ("n" , "no" ):
53+ if answer in ("n" , "no" ):
5254 return False
53- else :
54- console .print ("Invalid input. Please try again." , style = "red" )
55+ console .print ("Invalid input. Please try again." , style = "red" )
5556
5657
5758def confirm_overwrite (key : str ):
5859 """
59- Check whether a key should be overwritten if a duplicate is detected
60+ Check whether a key should be overwritten if a duplicate is detected.
6061 """
6162 message = f"{ key !r} already exists; do you wish to overwrite it? (y/n)"
6263 while True :
63- answer = (
64- prompt (
65- message ,
66- )
67- .lower ()
68- .strip ()
69- )
64+ answer = prompt (message , style = "yellow" ).lower ().strip ()
7065 if answer in ("y" , "yes" ):
7166 return True
72- elif answer in ("n" , "no" ):
67+ if answer in ("n" , "no" ):
7368 return False
74- else :
75- console .print ("Invalid input. Please try again." , style = "red" )
69+ console .print ("Invalid input. Please try again." , style = "red" )
7670
7771
7872def populate_field (key : str , field : ModelField ):
@@ -85,17 +79,22 @@ def populate_field(key: str, field: ModelField):
8579 print_field_info (field )
8680 message = "Please provide a value (press Enter to leave it blank as '')."
8781 while True :
88- # Validate fields as you key them in
89- value , error = field .validate (
90- prompt (message ),
91- {},
92- loc = key ,
82+ # Get value
83+ answer = prompt (message , style = "yellow" )
84+ # Translate empty string into None for fields that take Path values
85+ value = (
86+ None
87+ if (not answer and machine_config_types .get (key ) in (Path , Optional [Path ]))
88+ else answer
9389 )
90+
91+ validated_value , error = field .validate (value , {}, loc = key )
9492 if not error :
9593 console .print (
96- f"{ key !r} validated as { type (value )} : { value !r} " , style = "green"
94+ f"{ key !r} validated as { type (validated_value )} : { validated_value !r} " ,
95+ style = "bright_green" ,
9796 )
98- return value
97+ return validated_value
9998 else :
10099 console .print ("Invalid input. Please try again." , style = "red" )
101100
@@ -162,7 +161,7 @@ def get_calibration():
162161 calibrations [calibration_type ] = calibration_values
163162 console .print (
164163 f"Added { calibration_type } to the calibrations field: { calibration_values } " ,
165- style = "green " ,
164+ style = "bright_green " ,
166165 )
167166
168167 # Check if any more calibrations need to be added
@@ -173,7 +172,7 @@ def get_calibration():
173172 if not error :
174173 console .print (
175174 f"{ key !r} validated as { type (validated_calibrations )} : { validated_calibrations !r} " ,
176- style = "green " ,
175+ style = "bright_green " ,
177176 )
178177 return validated_calibrations
179178 else :
@@ -309,22 +308,22 @@ def get_file_substring() -> str:
309308 return sorted_dict
310309
311310 # Start of add_software_packages
312- console .print ("acquisition_software" , style = "bold cyan " )
311+ console .print ("acquisition_software" , style = "bold bright_cyan " )
313312 console .print (
314313 "This is where aquisition software packages present on the instrument "
315314 "machine can be set." ,
316- style = "cyan " ,
315+ style = "bright_cyan " ,
317316 )
318317 console .print (
319318 "Options: 'epu', 'tomo', 'serialem', 'autotem', 'leica'" ,
320- style = "cyan " ,
319+ style = "bright_cyan " ,
321320 )
322321 package_info : dict = {}
323322 category = "software package"
324323 add_input = ask_for_input (category , again = False )
325324 while add_input :
326325 # Collect inputs
327- console .print ("acquisition_software" , style = "bold cyan " )
326+ console .print ("acquisition_software" , style = "bold bright_cyan " )
328327 name = get_software_name ()
329328 if name in package_info .keys ():
330329 if confirm_overwrite (name ) is False :
@@ -336,11 +335,11 @@ def get_file_substring() -> str:
336335 "it blank if you're unsure." ,
337336 )
338337
339- console .print ("software_settings_output_directories" , style = "bold cyan " )
338+ console .print ("software_settings_output_directories" , style = "bold bright_cyan " )
340339 console .print (
341340 "Some software packages will have settings files that require modification "
342341 "in order to ensure files are saved to the desired folders." ,
343- style = "cyan " ,
342+ style = "bright_cyan " ,
344343 )
345344 if ask_about_xml_path () is True :
346345 xml_file = get_xml_file ()
@@ -349,12 +348,12 @@ def get_file_substring() -> str:
349348 xml_file = None
350349 xml_tree_path = ""
351350
352- console .print ("data_required_substrings" , style = "bold cyan " )
351+ console .print ("data_required_substrings" , style = "bold bright_cyan " )
353352 console .print (
354353 "Different software packages will generate different output files. Only "
355354 "files with certain extensions and keywords in their filenames are needed "
356355 "for data processing. They are listed out here." ,
357- style = "cyan " ,
356+ style = "bright_cyan " ,
358357 )
359358 file_ext_ss = get_extensions_and_substrings ()
360359
@@ -402,7 +401,7 @@ def get_file_substring() -> str:
402401 config [field_name ] = validated_value
403402 console .print (
404403 f"{ field_name !r} validated as { type (validated_value )} : { validated_value !r} " ,
405- style = "green " ,
404+ style = "bright_green " ,
406405 )
407406 else :
408407 console .print (
@@ -519,8 +518,7 @@ def run():
519518
520519 # Validate the entire config again and convert into JSON/YAML-safe dict
521520 try :
522- new_config_json = MachineConfig (** new_config ).json ()
523- new_config_safe = json .loads (new_config_json )
521+ new_config_safe : dict = json .loads (MachineConfig (** new_config ).json ())
524522 except ValidationError as exception :
525523 # Print out validation errors found
526524 console .print ("Validation failed" , style = "red" )
@@ -561,23 +559,23 @@ def run():
561559 for key in master_config .keys ():
562560 # Check if overwriting of existing config is needed
563561 if key in old_config .keys () and confirm_overwrite (key ) is False :
564- old_config [key ].update (new_config [key ])
562+ old_config [key ].update (master_config [key ])
565563 # Add new machine config
566564 else :
567- old_config [key ] = new_config [key ]
565+ old_config [key ] = master_config [key ]
568566 # Overwrite
569567 master_config = old_config
570568 with open (config_file , "w" ) as save_file :
571569 yaml .dump (master_config , save_file , default_flow_style = False )
572570 console .print (
573- f"Machine configuration for { new_config ['instrument_name' ]!r} "
571+ f"Machine configuration for { new_config_safe ['instrument_name' ]!r} "
574572 f"successfully saved as { str (config_file )!r} " ,
575- style = "green " ,
573+ style = "bright_green " ,
576574 )
577- console .print ("Machine configuration complete" , style = "green " )
575+ console .print ("Machine configuration complete" , style = "bright_green " )
578576
579577 # Provide option to set up another machine configuration
580578 if ask_for_input ("machine configuration" , True ) is True :
581579 return run ()
582- console .print ("Exiting machine configuration setup guide" )
580+ console .print ("Exiting machine configuration setup guide" , style = "bright_green" )
583581 exit ()
0 commit comments