import re import unicodedata from iqdbc.car.docs import get_all_footnotes, get_params_for_docs from iqdbc.car.values import PLATFORMS def build_car_catalog() -> dict[str, dict[str, list[str] | str]]: collected_footnote = get_all_footnotes() sorted_list: dict[str, dict[str, list[str] | str]] = collect_car_docs(PLATFORMS, collected_footnote) return sorted_list def _natural_sort_key(s): # NFKD normalization ensures accented characters sort with their base letter (e.g., Š sorts with S) normalized = unicodedata.normalize('NFKD', s) return [int(t) if t.isdigit() else t.lower() for t in re.split(r'(\d+)', normalized) if t] def collect_car_docs(platforms, footnotes) -> dict[str, dict[str, list[str] | str]]: cars: dict[str, dict[str, list[str] | str]] = {} for model, platform in platforms.items(): car_docs = platform.config.get_all_docs() CP, CP_IQ = get_params_for_docs(platform) if CP.dashcamOnly or not len(car_docs): continue # A platform can include multiple car models for _car_docs in car_docs: if not hasattr(_car_docs, "row"): _car_docs.init_make(CP) _car_docs.init(CP, footnotes) cars[_car_docs.name] = model _platform = model _name = _car_docs.name _make = _car_docs.make _brand = _car_docs.brand _model = _car_docs.model _years = _car_docs.year_list _package = _car_docs.package if _car_docs.package else [] cars[_name] = { "platform": _platform, "make": _make, "brand": _brand, "model": _model, "year": _years if _years else [], "package": _package, } # Sort cars by make and model + year sorted_cars = sorted(cars.keys(), key=lambda car: _natural_sort_key(car)) sorted_car_list = {car: cars[car] for car in sorted_cars} return sorted_car_list if __name__ == "__main__": # build_car_catalog() is the raw platform source; the shipped catalog is generated # (and encoded to its on-disk envelope) by the main-repo entry point: print("run: python -m openpilot.iqpilot.selfdrive.car.vehicle_catalog")