Skip to content
Snippets Groups Projects
Commit e6d9fb1d authored by David Fairbrother's avatar David Fairbrother
Browse files

Re #19156 Print allowed values on missing enum param

parent bee481ca
No related branches found
No related tags found
No related merge requests found
......@@ -32,17 +32,16 @@ class InstrumentSettings(object):
# were going to throw at this point unless the attribute was optional.
def __getattr__(self, item):
# Check if it is in our parameter mapping
is_known_internally = next((param_entry for param_entry in self._param_map if item == param_entry.int_name), None)
known_param = next((param_entry for param_entry in self._param_map if item == param_entry.int_name), None)
if is_known_internally:
if is_known_internally.optional:
if known_param:
if known_param.optional:
# Optional param return none
return None
else:
# User forgot to enter the param:
raise AttributeError(
"The parameter with name: '" + str(is_known_internally.ext_name) + "' is required but "
"was not set or passed.\nPlease set this configuration option and try again")
self._raise_user_param_missing_error(known_param)
else:
# If you have got here from a grep or something similar this error message means the line caller
# has asked for a class attribute which does not exist. These attributes are set in a mapping file which
......@@ -92,6 +91,19 @@ class InstrumentSettings(object):
_print_known_keys(self._param_map)
raise ValueError("Unknown configuration key: " + str(config_key))
@staticmethod
def _raise_user_param_missing_error(param_entry):
err_text = "The parameter with name: '" + str(param_entry.ext_name) + "' is required but "
err_text += "was not set or passed.\n"
# If this item is an enum print known values
if param_entry.enum_class:
known_vals = _get_enum_values(param_entry.enum_class)
err_text += "Acceptable values for this parameter are: " + str(known_vals[0])
for val in known_vals[1:]:
err_text += ", " + str(val)
raise AttributeError(err_text)
def _update_attribute(self, param_map, param_val, suppress_warnings):
attribute_name = param_map.int_name
......@@ -126,18 +138,14 @@ def _check_value_is_in_enum(val, enum):
enum_known_vals = []
lower_string_val = str(val).lower()
for k, enum_val in iteritems(enum.__dict__):
# Get all class attribute and value pairs except enum_friendly_name
if k.startswith("__") or k.lower() == "enum_friendly_name":
continue
enum_known_vals.append(enum_val)
known_values = _get_enum_values(enum_cls=enum)
for enum_val in known_values:
if lower_string_val == enum_val.lower():
# Get the correctly capitalised value so we no longer have to call lower
val = enum_val
seen_val_in_enum = True
# Have to keep looping here in case we hit the err so all known keys are added
break
# Check to see if the value was seen
if seen_val_in_enum:
......@@ -152,6 +160,23 @@ def _check_value_is_in_enum(val, enum):
raise ValueError(e_msg)
def _get_enum_values(enum_cls):
"""
Gets all acceptable values for the specified enum class and returns them as a list
:param enum_cls: The enum to process
:return: List of accepted values for this enum
"""
enum_known_vals = []
for k, enum_val in iteritems(enum_cls.__dict__):
# Get all class attribute and value pairs except enum_friendly_name
if k.startswith("__") or k.lower() == "enum_friendly_name":
continue
enum_known_vals.append(enum_val)
return enum_known_vals
def _print_known_keys(master_mapping):
print ("\nKnown keys are:")
print("----------------------------------")
......
......@@ -15,7 +15,7 @@ def create_run_details_object(run_number_string, inst_settings, is_vanadium_run,
calibration_dir = os.path.normpath(os.path.expanduser(inst_settings.calibration_dir))
label = common.cal_map_dictionary_key_helper(dictionary=cal_map_dict, key="label")
offset_file_name = common.cal_map_dictionary_key_helper(dictionary=cal_map_dict, key="offset_file_name")
# Always make sure the offset file name is included
if splined_name_list:
splined_name_list.append(offset_file_name)
......
......@@ -20,6 +20,16 @@ class ISISPowderInstrumentSettingsTest(unittest.TestCase):
foo = inst_settings_obj.script_facing_name
del foo
def test_user_missing_attribute_prints_enum_values(self):
param_entry = ParamMapEntry.ParamMapEntry(ext_name="user_facing_name", int_name="script_facing_name",
enum_class=SampleEnum)
inst_settings_obj = InstrumentSettings.InstrumentSettings(param_map=[param_entry])
# Check it still prints the acceptable values when it fails
with assertRaisesRegex(self, AttributeError, "a foo, A BAR"):
foo = inst_settings_obj.script_facing_name
del foo
def test_developer_missing_attribute_is_detected(self):
param_entry = ParamMapEntry.ParamMapEntry(ext_name="user_facing_name", int_name="script_facing_name")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment