79 @brief Every inline set of string choices in the CLI package.
81 @details Two shapes are recognised: a membership test against a literal collection,
82 and an argparse `choices=` literal. Both are how a closed public set gets
83 written without a name.
84 @return Mapping of waiver key to the list of sites that produced it.
87 for module
in MODULES:
88 path = REPO_ROOT / module
89 if not path.is_file():
91 dotted = MODULE_DOTTED.get(module, module.replace(
"/",
".")[: -len(
".py")])
92 tree = ast.parse(path.read_text(encoding=
"utf-8"))
93 for node
in ast.walk(tree):
96 if isinstance(node, ast.Compare)
and node.ops
and \
97 isinstance(node.ops[0], (ast.In, ast.NotIn)):
98 collection = node.comparators[0]
99 if isinstance(collection, (ast.Set, ast.List, ast.Tuple)):
101 elif isinstance(node, ast.Call):
102 for keyword
in node.keywords:
103 if keyword.arg ==
"choices" and \
104 isinstance(keyword.value, (ast.Set, ast.List, ast.Tuple)):
106 if values
and len(values) >= MINIMUM_CHOICE_SIZE:
108 found.setdefault(key, []).append(f
"{module}:{node.lineno} ({shape})")
125 @brief Fail when an inline choice set is neither named nor classified.
126 @return Process status code.
128 document = json.loads(WAIVERS.read_text(encoding=
"utf-8"))
129 waivers = document[
"inline_choices"]
133 for key
in sorted(found):
134 entry = waivers.get(key)
137 f
"{key}\n at {', '.join(found[key])}\n"
138 f
" Give this set a name so the family census can see it, or "
139 f
"classify it in inline_choice_waivers.json."
142 classification = entry.get(
"classification")
143 if classification
not in VALID_CLASSIFICATIONS:
144 problems.append(f
"{key}: classification {classification!r} is not one of "
145 f
"{list(VALID_CLASSIFICATIONS)}")
146 elif len(str(entry.get(
"reason",
"")).strip()) < MIN_REASON_CHARS:
147 problems.append(f
"{key}: classified {classification} without a stated reason")
148 for stale
in sorted(set(waivers) - set(found)):
149 problems.append(f
"{stale}: waived, but no such inline literal exists any more")
152 print(
"Inline choice-set violations:", file=sys.stderr)
153 for problem
in problems:
154 print(f
" {problem}", file=sys.stderr)
157 from collections
import Counter
158 spread = Counter(waivers[key][
"classification"]
for key
in found)
159 summary =
", ".join(f
"{count} {name}" for name, count
in sorted(spread.items()))
160 print(f
"Inline choice audit passed: {len(found)} inline set(s), every one classified "