Refactor extraction-scripts to reduce code-duplication (#2592)

extract_configs.py now supports reading min, max or default values
from a #define value (which reduces false-positives)
This commit is contained in:
Andrew Scheller 2025-07-25 15:14:31 +01:00 committed by GitHub
parent de5fb4f71f
commit 4f5ebb8d26
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 211 additions and 170 deletions

View file

@ -46,7 +46,17 @@ BASE_BUILD_DEFINE_RE = re.compile(r'\b{}\b'.format(BASE_BUILD_DEFINE_NAME))
BUILD_DEFINE_RE = re.compile(r'#\s+{}:\s+(\w+),\s+([^,]+)(?:,\s+(.*))?$'.format(BASE_BUILD_DEFINE_NAME)) BUILD_DEFINE_RE = re.compile(r'#\s+{}:\s+(\w+),\s+([^,]+)(?:,\s+(.*))?$'.format(BASE_BUILD_DEFINE_NAME))
ALLOWED_CONFIG_PROPERTIES = set(['type', 'default', 'min', 'max', 'group']) PROPERTY_TYPE = 'type'
PROPERTY_DEFAULT = 'default'
PROPERTY_MIN = 'min'
PROPERTY_MAX = 'max'
PROPERTY_GROUP = 'group'
ALLOWED_CONFIG_PROPERTIES = set([PROPERTY_TYPE, PROPERTY_DEFAULT, PROPERTY_MIN, PROPERTY_MAX, PROPERTY_GROUP])
PROPERTY_TYPE_INT = 'int'
PROPERTY_TYPE_BOOL = 'bool'
PROPERTY_TYPE_STRING = 'string'
PROPERTY_TYPE_LIST = 'list'
CHIP_NAMES = ["rp2040", "rp2350"] CHIP_NAMES = ["rp2040", "rp2350"]
@ -57,7 +67,7 @@ chips_all_descriptions = defaultdict(dict)
def ValidateAttrs(config_name, config_attrs, file_path, linenum): def ValidateAttrs(config_name, config_attrs, file_path, linenum):
_type = config_attrs.get('type') type_str = config_attrs.get(PROPERTY_TYPE)
errors = [] errors = []
# Validate attrs # Validate attrs
@ -65,65 +75,57 @@ def ValidateAttrs(config_name, config_attrs, file_path, linenum):
if key not in ALLOWED_CONFIG_PROPERTIES: if key not in ALLOWED_CONFIG_PROPERTIES:
errors.append(Exception('{} at {}:{} has unexpected property "{}"'.format(config_name, file_path, linenum, key))) errors.append(Exception('{} at {}:{} has unexpected property "{}"'.format(config_name, file_path, linenum, key)))
if _type == 'int': str_values = dict()
_min = _max = _default = None parsed_values = dict()
if config_attrs.get('min', None) is not None: if type_str == PROPERTY_TYPE_INT:
value = config_attrs['min'] for attr_name in (PROPERTY_MIN, PROPERTY_MAX, PROPERTY_DEFAULT):
m = re.match(r'^(\d+)e(\d+)$', value.lower()) str_values[attr_name] = config_attrs.get(attr_name, None)
if m: if str_values[attr_name] is not None:
_min = int(m.group(1)) * 10**int(m.group(2))
else:
_min = int(value, 0)
if config_attrs.get('max', None) is not None:
value = config_attrs['max']
m = re.match(r'^(\d+)e(\d+)$', value.lower())
if m:
_max = int(m.group(1)) * 10**int(m.group(2))
else:
_max = int(value, 0)
if config_attrs.get('default', None) is not None:
if '/' not in config_attrs['default']:
try: try:
value = config_attrs['default'] m = re.match(r'^(\d+)e(\d+)$', str_values[attr_name].lower())
m = re.match(r'^(\d+)e(\d+)$', value.lower())
if m: if m:
_default = int(m.group(1)) * 10**int(m.group(2)) parsed_values[attr_name] = int(m.group(1)) * 10**int(m.group(2))
else: else:
_default = int(value, 0) parsed_values[attr_name] = int(str_values[attr_name], 0)
except ValueError: except ValueError:
pass logger.info('{} at {}:{} has non-integer {} value "{}"'.format(config_name, file_path, linenum, attr_name, str_values[attr_name]))
if _min is not None and _max is not None: for (small_attr, large_attr) in (
if _min > _max: (PROPERTY_MIN, PROPERTY_MAX),
errors.append(Exception('{} at {}:{} has min {} > max {}'.format(config_name, file_path, linenum, config_attrs['min'], config_attrs['max']))) (PROPERTY_MIN, PROPERTY_DEFAULT),
if _min is not None and _default is not None: (PROPERTY_DEFAULT, PROPERTY_MAX),
if _min > _default: ):
errors.append(Exception('{} at {}:{} has min {} > default {}'.format(config_name, file_path, linenum, config_attrs['min'], config_attrs['default']))) if small_attr in parsed_values and large_attr in parsed_values and parsed_values[small_attr] > parsed_values[large_attr]:
if _default is not None and _max is not None: errors.append(Exception('{} at {}:{} has {} {} > {} {}'.format(config_name, file_path, linenum, small_attr, str_values[small_attr], large_attr, str_values[large_attr])))
if _default > _max:
errors.append(Exception('{} at {}:{} has default {} > max {}'.format(config_name, file_path, linenum, config_attrs['default'], config_attrs['max']))) elif type_str == PROPERTY_TYPE_BOOL:
elif _type == 'bool': assert PROPERTY_MIN not in config_attrs
assert 'min' not in config_attrs assert PROPERTY_MAX not in config_attrs
assert 'max' not in config_attrs
_default = config_attrs.get('default', None) attr_name = PROPERTY_DEFAULT
if _default is not None: str_values[attr_name] = config_attrs.get(attr_name, None)
if '/' not in _default: if str_values[attr_name] is not None:
if (_default not in ('0', '1')) and (_default not in all_config_names): if (str_values[attr_name] not in ('0', '1')) and (str_values[attr_name] not in all_config_names):
logger.info('{} at {}:{} has non-integer default value "{}"'.format(config_name, file_path, linenum, config_attrs['default'])) logger.info('{} at {}:{} has non-integer {} value "{}"'.format(config_name, file_path, linenum, attr_name, str_values[attr_name]))
elif type_str == PROPERTY_TYPE_STRING:
assert PROPERTY_MIN not in config_attrs
assert PROPERTY_MAX not in config_attrs
attr_name = PROPERTY_DEFAULT
str_values[attr_name] = config_attrs.get(attr_name, None)
elif type_str == PROPERTY_TYPE_LIST:
assert PROPERTY_MIN not in config_attrs
assert PROPERTY_MAX not in config_attrs
attr_name = PROPERTY_DEFAULT
str_values[attr_name] = config_attrs.get(attr_name, None)
elif _type == 'string':
assert 'min' not in config_attrs
assert 'max' not in config_attrs
_default = config_attrs.get('default', None)
elif _type == 'list':
assert 'min' not in config_attrs
assert 'max' not in config_attrs
_default = config_attrs.get('default', None)
else: else:
errors.append(Exception("Found unknown {} type {} at {}:{}".format(BASE_BUILD_DEFINE_NAME, _type, file_path, linenum))) errors.append(Exception("Found unknown {} type {} at {}:{}".format(BASE_BUILD_DEFINE_NAME, type_str, file_path, linenum)))
return errors return errors
errors = [] errors = []
# Scan all CMakeLists.txt and .cmake files in the specific path, recursively. # Scan all CMakeLists.txt and .cmake files in the specific path, recursively.

View file

@ -7,7 +7,7 @@
# #
# Script to scan the Raspberry Pi Pico SDK tree searching for CMake configuration items # Script to scan the Raspberry Pi Pico SDK tree searching for CMake configuration items
# Outputs a tab separated file of the configuration item: # Outputs a tab separated file of the configuration item:
# name location platform chip description type advanced default docref group # name location platform chip description type advanced default docref group max
# #
# Usage: # Usage:
# #
@ -46,7 +46,19 @@ BASE_BUILD_DEFINE_RE = re.compile(r'\b{}\b'.format(BASE_BUILD_DEFINE_NAME))
CMAKE_CONFIG_RE = re.compile(r'#\s+{}:\s+(\w+),\s+([^,]+)(?:,\s+(.*))?$'.format(BASE_CMAKE_CONFIG_NAME)) CMAKE_CONFIG_RE = re.compile(r'#\s+{}:\s+(\w+),\s+([^,]+)(?:,\s+(.*))?$'.format(BASE_CMAKE_CONFIG_NAME))
ALLOWED_CONFIG_PROPERTIES = set(['type', 'default', 'min', 'max', 'group', 'advanced', 'docref']) PROPERTY_TYPE = 'type'
PROPERTY_DEFAULT = 'default'
PROPERTY_MIN = 'min'
PROPERTY_MAX = 'max'
PROPERTY_GROUP = 'group'
PROPERTY_ADVANCED = 'advanced'
PROPERTY_DOCREF = 'docref'
ALLOWED_CONFIG_PROPERTIES = set([PROPERTY_TYPE, PROPERTY_DEFAULT, PROPERTY_MIN, PROPERTY_MAX, PROPERTY_GROUP, PROPERTY_ADVANCED, PROPERTY_DOCREF])
PROPERTY_TYPE_INT = 'int'
PROPERTY_TYPE_BOOL = 'bool'
PROPERTY_TYPE_STRING = 'string'
PROPERTY_TYPE_LIST = 'list'
CHIP_NAMES = ["rp2040", "rp2350"] CHIP_NAMES = ["rp2040", "rp2350"]
@ -57,7 +69,7 @@ chips_all_descriptions = defaultdict(dict)
def ValidateAttrs(config_name, config_attrs, file_path, linenum): def ValidateAttrs(config_name, config_attrs, file_path, linenum):
_type = config_attrs.get('type') type_str = config_attrs.get(PROPERTY_TYPE)
errors = [] errors = []
# Validate attrs # Validate attrs
@ -65,61 +77,55 @@ def ValidateAttrs(config_name, config_attrs, file_path, linenum):
if key not in ALLOWED_CONFIG_PROPERTIES: if key not in ALLOWED_CONFIG_PROPERTIES:
errors.append(Exception('{} at {}:{} has unexpected property "{}"'.format(config_name, file_path, linenum, key))) errors.append(Exception('{} at {}:{} has unexpected property "{}"'.format(config_name, file_path, linenum, key)))
if _type == 'int': str_values = dict()
_min = _max = _default = None parsed_values = dict()
if config_attrs.get('min', None) is not None: if type_str == PROPERTY_TYPE_INT:
value = config_attrs['min'] for attr_name in (PROPERTY_MIN, PROPERTY_MAX, PROPERTY_DEFAULT):
m = re.match(r'^(\d+)e(\d+)$', value.lower()) str_values[attr_name] = config_attrs.get(attr_name, None)
if m: if str_values[attr_name] is not None:
_min = int(m.group(1)) * 10**int(m.group(2))
else:
_min = int(value, 0)
if config_attrs.get('max', None) is not None:
value = config_attrs['max']
m = re.match(r'^(\d+)e(\d+)$', value.lower())
if m:
_max = int(m.group(1)) * 10**int(m.group(2))
else:
_max = int(value, 0)
if config_attrs.get('default', None) is not None:
if '/' not in config_attrs['default']:
try: try:
value = config_attrs['default'] m = re.match(r'^(\d+)e(\d+)$', str_values[attr_name].lower())
m = re.match(r'^(\d+)e(\d+)$', value.lower())
if m: if m:
_default = int(m.group(1)) * 10**int(m.group(2)) parsed_values[attr_name] = int(m.group(1)) * 10**int(m.group(2))
else: else:
_default = int(value, 0) parsed_values[attr_name] = int(str_values[attr_name], 0)
except ValueError: except ValueError:
pass # pass
if _min is not None and _max is not None: logger.info('{} at {}:{} has non-integer {} value "{}"'.format(config_name, file_path, linenum, attr_name, str_values[attr_name]))
if _min > _max: for (small_attr, large_attr) in (
errors.append(Exception('{} at {}:{} has min {} > max {}'.format(config_name, file_path, linenum, config_attrs['min'], config_attrs['max']))) (PROPERTY_MIN, PROPERTY_MAX),
if _min is not None and _default is not None: (PROPERTY_MIN, PROPERTY_DEFAULT),
if _min > _default: (PROPERTY_DEFAULT, PROPERTY_MAX),
errors.append(Exception('{} at {}:{} has min {} > default {}'.format(config_name, file_path, linenum, config_attrs['min'], config_attrs['default']))) ):
if _default is not None and _max is not None: if small_attr in parsed_values and large_attr in parsed_values and parsed_values[small_attr] > parsed_values[large_attr]:
if _default > _max: errors.append(Exception('{} at {}:{} has {} {} > {} {}'.format(config_name, file_path, linenum, small_attr, str_values[small_attr], large_attr, str_values[large_attr])))
errors.append(Exception('{} at {}:{} has default {} > max {}'.format(config_name, file_path, linenum, config_attrs['default'], config_attrs['max'])))
elif _type == 'bool': elif type_str == PROPERTY_TYPE_BOOL:
assert 'min' not in config_attrs assert PROPERTY_MIN not in config_attrs
assert 'max' not in config_attrs assert PROPERTY_MAX not in config_attrs
_default = config_attrs.get('default', None)
if _default is not None: attr_name = PROPERTY_DEFAULT
if '/' not in _default: str_values[attr_name] = config_attrs.get(attr_name, None)
if (_default not in ('0', '1')) and (_default not in all_config_names): if str_values[attr_name] is not None:
logger.info('{} at {}:{} has non-integer default value "{}"'.format(config_name, file_path, linenum, config_attrs['default'])) if (str_values[attr_name] not in ('0', '1')) and (str_values[attr_name] not in all_config_names):
logger.info('{} at {}:{} has non-integer {} value "{}"'.format(config_name, file_path, linenum, attr_name, str_values[attr_name]))
elif type_str == PROPERTY_TYPE_STRING:
assert PROPERTY_MIN not in config_attrs
assert PROPERTY_MAX not in config_attrs
attr_name = PROPERTY_DEFAULT
str_values[attr_name] = config_attrs.get(attr_name, None)
elif type_str == PROPERTY_TYPE_LIST:
assert PROPERTY_MIN not in config_attrs
assert PROPERTY_MAX not in config_attrs
attr_name = PROPERTY_DEFAULT
str_values[attr_name] = config_attrs.get(attr_name, None)
elif _type == 'string':
assert 'min' not in config_attrs
assert 'max' not in config_attrs
_default = config_attrs.get('default', None)
elif _type == 'list':
assert 'min' not in config_attrs
assert 'max' not in config_attrs
_default = config_attrs.get('default', None)
else: else:
errors.append(Exception("Found unknown {} type {} at {}:{}".format(BASE_CMAKE_CONFIG_NAME, _type, file_path, linenum))) errors.append(Exception("Found unknown {} type {} at {}:{}".format(BASE_CMAKE_CONFIG_NAME, type_str, file_path, linenum)))
return errors return errors

View file

@ -47,7 +47,19 @@ BASE_BUILD_DEFINE_RE = re.compile(r'\b{}\b'.format(BASE_BUILD_DEFINE_NAME))
CONFIG_RE = re.compile(r'//\s+{}:\s+(\w+),\s+([^,]+)(?:,\s+(.*))?$'.format(BASE_CONFIG_NAME)) CONFIG_RE = re.compile(r'//\s+{}:\s+(\w+),\s+([^,]+)(?:,\s+(.*))?$'.format(BASE_CONFIG_NAME))
DEFINE_RE = re.compile(r'#define\s+(\w+)\s+(.+?)(\s*///.*)?$') DEFINE_RE = re.compile(r'#define\s+(\w+)\s+(.+?)(\s*///.*)?$')
ALLOWED_CONFIG_PROPERTIES = set(['type', 'default', 'min', 'max', 'enumvalues', 'group', 'advanced', 'depends']) PROPERTY_TYPE = 'type'
PROPERTY_DEFAULT = 'default'
PROPERTY_MIN = 'min'
PROPERTY_MAX = 'max'
PROPERTY_ENUMVALUES = 'enumvalues'
PROPERTY_GROUP = 'group'
PROPERTY_ADVANCED = 'advanced'
PROPERTY_DEPENDS = 'depends'
ALLOWED_CONFIG_PROPERTIES = set([PROPERTY_TYPE, PROPERTY_DEFAULT, PROPERTY_MIN, PROPERTY_MAX, PROPERTY_ENUMVALUES, PROPERTY_GROUP, PROPERTY_ADVANCED, PROPERTY_DEPENDS])
PROPERTY_TYPE_INT = 'int'
PROPERTY_TYPE_BOOL = 'bool'
PROPERTY_TYPE_ENUM = 'enum'
CHIP_NAMES = ["rp2040", "rp2350"] CHIP_NAMES = ["rp2040", "rp2350"]
@ -57,9 +69,37 @@ chips_all_descriptions = defaultdict(dict)
chips_all_defines = defaultdict(dict) chips_all_defines = defaultdict(dict)
def get_first_dict_key(some_dict):
return list(some_dict.keys())[0]
def ValidateAttrs(config_name, config_attrs, file_path, linenum): def look_for_integer_define(config_name, attr_name, attr_str, file_path, linenum, applicable):
_type = config_attrs.get('type', 'int') defined_str = None
if re.match('^\w+$', attr_str):
# See if we have a matching define
all_defines = chips_all_defines[applicable]
if attr_str in all_defines:
# There _may_ be multiple matching defines, but arbitrarily choose just one
defined_str = get_first_dict_key(all_defines[attr_str])
else:
if applicable == 'all':
# Look for it in the chip-specific defines
found_chips = []
missing_chips = []
for chip in CHIP_NAMES:
all_defines = chips_all_defines[chip]
if attr_str in all_defines:
found_chips.append(chip)
# There _may_ be multiple matching defines, but arbitrarily choose just one
defined_str = get_first_dict_key(all_defines[attr_str])
else:
missing_chips.append(chip)
# Report if it's found for some chips but not others (but ignore if it's missing for all)
if found_chips and missing_chips:
logger.info('{} at {}:{} has {} value "{}" which has a matching define for {} but not for {}'.format(config_name, file_path, linenum, attr_name, attr_str, found_chips, missing_chips))
return defined_str
def ValidateAttrs(config_name, config_attrs, file_path, linenum, applicable):
type_str = config_attrs.get(PROPERTY_TYPE, PROPERTY_TYPE_INT)
errors = [] errors = []
# Validate attrs # Validate attrs
@ -67,76 +107,69 @@ def ValidateAttrs(config_name, config_attrs, file_path, linenum):
if key not in ALLOWED_CONFIG_PROPERTIES: if key not in ALLOWED_CONFIG_PROPERTIES:
errors.append(Exception('{} at {}:{} has unexpected property "{}"'.format(config_name, file_path, linenum, key))) errors.append(Exception('{} at {}:{} has unexpected property "{}"'.format(config_name, file_path, linenum, key)))
if _type == 'int': str_values = dict()
assert 'enumvalues' not in config_attrs parsed_values = dict()
_min = _max = _default = None if type_str == PROPERTY_TYPE_INT:
if config_attrs.get('min', None) is not None: assert PROPERTY_ENUMVALUES not in config_attrs
for attr_name in (PROPERTY_MIN, PROPERTY_MAX, PROPERTY_DEFAULT):
str_values[attr_name] = config_attrs.get(attr_name, None)
if str_values[attr_name] is not None:
try: try:
value = config_attrs['min'] m = re.match(r'^(\d+)e(\d+)$', str_values[attr_name].lower())
m = re.match(r'^(\d+)e(\d+)$', value.lower())
if m: if m:
_min = int(m.group(1)) * 10**int(m.group(2)) parsed_values[attr_name] = int(m.group(1)) * 10**int(m.group(2))
else: else:
_min = int(value, 0) parsed_values[attr_name] = int(str_values[attr_name], 0)
except ValueError: except ValueError:
logger.info('{} at {}:{} has non-integer min value "{}"'.format(config_name, file_path, linenum, config_attrs['min'])) defined_str = look_for_integer_define(config_name, attr_name, str_values[attr_name], file_path, linenum, applicable)
if config_attrs.get('max', None) is not None: if defined_str is not None:
try: try:
value = config_attrs['max'] m = re.match(r'^(\d+)e(\d+)$', str_values[attr_name].lower())
m = re.match(r'^(\d+)e(\d+)$', value.lower())
if m: if m:
_max = int(m.group(1)) * 10**int(m.group(2)) parsed_values[attr_name] = int(m.group(1)) * 10**int(m.group(2))
else: else:
_max = int(value, 0) parsed_values[attr_name] = int(defined_str, 0)
except ValueError: except ValueError:
logger.info('{} at {}:{} has non-integer max value "{}"'.format(config_name, file_path, linenum, config_attrs['max'])) logger.info('{} at {}:{} has {} value "{}" which resolves to the non-integer value "{}"'.format(config_name, file_path, linenum, attr_name, str_values[attr_name], defined_str))
if config_attrs.get('default', None) is not None:
if '/' not in config_attrs['default']:
try:
value = config_attrs['default']
m = re.match(r'^(\d+)e(\d+)$', value.lower())
if m:
_default = int(m.group(1)) * 10**int(m.group(2))
else: else:
_default = int(value, 0) logger.info('{} at {}:{} has non-integer {} value "{}"'.format(config_name, file_path, linenum, attr_name, str_values[attr_name]))
except ValueError: for (small_attr, large_attr) in (
logger.info('{} at {}:{} has non-integer default value "{}"'.format(config_name, file_path, linenum, config_attrs['default'])) (PROPERTY_MIN, PROPERTY_MAX),
if _min is not None and _max is not None: (PROPERTY_MIN, PROPERTY_DEFAULT),
if _min > _max: (PROPERTY_DEFAULT, PROPERTY_MAX),
errors.append(Exception('{} at {}:{} has min {} > max {}'.format(config_name, file_path, linenum, config_attrs['min'], config_attrs['max']))) ):
if _min is not None and _default is not None: if small_attr in parsed_values and large_attr in parsed_values and parsed_values[small_attr] > parsed_values[large_attr]:
if _min > _default: errors.append(Exception('{} at {}:{} has {} {} > {} {}'.format(config_name, file_path, linenum, small_attr, str_values[small_attr], large_attr, str_values[large_attr])))
errors.append(Exception('{} at {}:{} has min {} > default {}'.format(config_name, file_path, linenum, config_attrs['min'], config_attrs['default'])))
if _default is not None and _max is not None:
if _default > _max:
errors.append(Exception('{} at {}:{} has default {} > max {}'.format(config_name, file_path, linenum, config_attrs['default'], config_attrs['max'])))
elif _type == 'bool':
assert 'min' not in config_attrs elif type_str == PROPERTY_TYPE_BOOL:
assert 'max' not in config_attrs assert PROPERTY_MIN not in config_attrs
assert 'enumvalues' not in config_attrs assert PROPERTY_MAX not in config_attrs
assert PROPERTY_ENUMVALUES not in config_attrs
_default = config_attrs.get('default', None) attr_name = PROPERTY_DEFAULT
if _default is not None: str_values[attr_name] = config_attrs.get(attr_name, None)
if '/' not in _default: if str_values[attr_name] is not None:
if (_default not in ('0', '1')) and (_default not in all_config_names): if (str_values[attr_name] not in ('0', '1')) and (str_values[attr_name] not in all_config_names):
logger.info('{} at {}:{} has non-integer default value "{}"'.format(config_name, file_path, linenum, config_attrs['default'])) logger.info('{} at {}:{} has non-integer {} value "{}"'.format(config_name, file_path, linenum, attr_name, str_values[attr_name]))
elif _type == 'enum': elif type_str == PROPERTY_TYPE_ENUM:
assert PROPERTY_ENUMVALUES in config_attrs
assert PROPERTY_MIN not in config_attrs
assert PROPERTY_MAX not in config_attrs
assert 'min' not in config_attrs attr_name = PROPERTY_ENUMVALUES
assert 'max' not in config_attrs str_values[attr_name] = config_attrs[attr_name]
assert 'enumvalues' in config_attrs parsed_values[attr_name] = tuple(str_values[attr_name].split('|'))
attr_name = PROPERTY_DEFAULT
str_values[attr_name] = config_attrs.get(attr_name, None)
if str_values[attr_name] is not None:
if str_values[attr_name] not in _enumvalues:
errors.append(Exception('{} at {}:{} has {} value {} which isn\'t in list of {} {}'.format(config_name, file_path, linenum, attr_name, str_values[attr_name], PROPERTY_ENUMVALUES, str_values[PROPERTY_ENUMVALUES])))
_enumvalues = tuple(config_attrs['enumvalues'].split('|'))
_default = None
if config_attrs.get('default', None) is not None:
_default = config_attrs['default']
if _default is not None:
if _default not in _enumvalues:
errors.append(Exception('{} at {}:{} has default value {} which isn\'t in list of enumvalues {}'.format(config_name, file_path, linenum, config_attrs['default'], config_attrs['enumvalues'])))
else: else:
errors.append(Exception("Found unknown {} type {} at {}:{}".format(BASE_CONFIG_NAME, _type, file_path, linenum))) errors.append(Exception("Found unknown {} type {} at {}:{}".format(BASE_CONFIG_NAME, type_str, file_path, linenum)))
return errors return errors
@ -256,7 +289,7 @@ for applicable, all_configs in chips_all_configs.items():
file_path = os.path.join(scandir, config_obj['filename']) file_path = os.path.join(scandir, config_obj['filename'])
linenum = config_obj['line_number'] linenum = config_obj['line_number']
errors.extend(ValidateAttrs(config_name, config_obj['attrs'], file_path, linenum)) errors.extend(ValidateAttrs(config_name, config_obj['attrs'], file_path, linenum, applicable))
# Check that default values match up # Check that default values match up
if 'default' in config_obj['attrs']: if 'default' in config_obj['attrs']:
@ -267,7 +300,7 @@ for applicable, all_configs in chips_all_configs.items():
if '/' in config_default or ' ' in config_default: if '/' in config_default or ' ' in config_default:
continue continue
# There _may_ be multiple matching defines, but arbitrarily display just one in the error message # There _may_ be multiple matching defines, but arbitrarily display just one in the error message
first_define_value = list(defines_obj.keys())[0] first_define_value = get_first_dict_key(defines_obj)
first_define_file_path, first_define_linenum = defines_obj[first_define_value] first_define_file_path, first_define_linenum = defines_obj[first_define_value]
errors.append(Exception('Found {} at {}:{} with a default of {}, but #define says {} (at {}:{})'.format(config_name, file_path, linenum, config_default, first_define_value, first_define_file_path, first_define_linenum))) errors.append(Exception('Found {} at {}:{} with a default of {}, but #define says {} (at {}:{})'.format(config_name, file_path, linenum, config_default, first_define_value, first_define_file_path, first_define_linenum)))
else: else: