diff --git a/scripts/count_cars.py b/scripts/count_cars.py index 46d8499461..25bad2c9b4 100755 --- a/scripts/count_cars.py +++ b/scripts/count_cars.py @@ -2,12 +2,10 @@ from collections import Counter from pprint import pprint -from selfdrive.car.docs import get_tier_car_info +from selfdrive.car.docs import get_all_car_info if __name__ == "__main__": - tiers = get_tier_car_info() - cars = [car for tier_cars in tiers.values() for car in tier_cars] - + cars = get_all_car_info() make_count = Counter(l.make for l in cars) print("\n", "*" * 20, len(cars), "total", "*" * 20, "\n") pprint(make_count) diff --git a/selfdrive/car/docs.py b/selfdrive/car/docs.py index a39e8df805..64d4dbfef4 100755 --- a/selfdrive/car/docs.py +++ b/selfdrive/car/docs.py @@ -26,9 +26,8 @@ CARS_MD_OUT = os.path.join(BASEDIR, "docs", "CARS.md") CARS_MD_TEMPLATE = os.path.join(BASEDIR, "selfdrive", "car", "CARS_template.md") -def get_tier_car_info() -> Dict[Tier, List[CarInfo]]: - tier_car_info: Dict[Tier, List[CarInfo]] = {tier: [] for tier in Tier} - +def get_all_car_info() -> List[CarInfo]: + all_car_info: List[CarInfo] = [] for models in get_interface_attr("CAR_INFO").values(): for model, car_info in models.items(): # Hyundai exception: those with radar have openpilot longitudinal @@ -43,8 +42,16 @@ def get_tier_car_info() -> Dict[Tier, List[CarInfo]]: car_info = (car_info,) for _car_info in car_info: - _car_info.init(CP, non_tested_cars, ALL_FOOTNOTES) - tier_car_info[_car_info.tier].append(_car_info) + all_car_info.append(_car_info.init(CP, non_tested_cars, ALL_FOOTNOTES)) + + # Sort cars by make and model + year + return natsorted(all_car_info, key=lambda car: (car.make + car.model).lower()) + + +def sort_by_tier(all_car_info: List[CarInfo]) -> Dict[Tier, List[CarInfo]]: + tier_car_info: Dict[Tier, List[CarInfo]] = {tier: [] for tier in Tier} + for car_info in all_car_info: + tier_car_info[car_info.tier].append(car_info) # Sort cars by make and model + year for tier, cars in tier_car_info.items(): @@ -53,12 +60,12 @@ def get_tier_car_info() -> Dict[Tier, List[CarInfo]]: return tier_car_info -def generate_cars_md(tier_car_info: Dict[Tier, List[CarInfo]], template_fn: str) -> str: +def generate_cars_md(all_car_info: List[CarInfo], template_fn: str) -> str: with open(template_fn, "r") as f: template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True) footnotes = [fn.value.text for fn in ALL_FOOTNOTES] - return template.render(tiers=tier_car_info, footnotes=footnotes, Star=Star, Column=Column) + return template.render(tiers=sort_by_tier(all_car_info), footnotes=footnotes, Star=Star, Column=Column) if __name__ == "__main__": @@ -70,5 +77,5 @@ if __name__ == "__main__": args = parser.parse_args() with open(args.out, 'w') as f: - f.write(generate_cars_md(get_tier_car_info(), args.template)) + f.write(generate_cars_md(get_all_car_info(), args.template)) print(f"Generated and written to {args.out}") diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index e406422981..1ca2205ce5 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -91,6 +91,7 @@ class CarInfo: self.row[column] = footnote.value.star self.tier = {5: Tier.GOLD, 4: Tier.SILVER}.get(list(self.row.values()).count(Star.FULL), Tier.BRONZE) + return self @no_type_check def get_column(self, column: Column, star_icon: str, footnote_tag: str) -> str: diff --git a/selfdrive/car/tests/test_docs.py b/selfdrive/car/tests/test_docs.py index 6c7ae1fdac..1530eb18af 100755 --- a/selfdrive/car/tests/test_docs.py +++ b/selfdrive/car/tests/test_docs.py @@ -1,15 +1,15 @@ #!/usr/bin/env python3 import unittest -from selfdrive.car.docs import CARS_MD_OUT, CARS_MD_TEMPLATE, generate_cars_md, get_tier_car_info +from selfdrive.car.docs import CARS_MD_OUT, CARS_MD_TEMPLATE, generate_cars_md, get_all_car_info class TestCarDocs(unittest.TestCase): def setUp(self): - self.tier_cars = get_tier_car_info() + self.all_cars = get_all_car_info() def test_generator(self): - generated_cars_md = generate_cars_md(self.tier_cars, CARS_MD_TEMPLATE) + generated_cars_md = generate_cars_md(self.all_cars, CARS_MD_TEMPLATE) with open(CARS_MD_OUT, "r") as f: current_cars_md = f.read() @@ -18,15 +18,14 @@ class TestCarDocs(unittest.TestCase): def test_naming_conventions(self): # Asserts market-standard car naming conventions by make - for cars in self.tier_cars.values(): - for car in cars: - if car.car_name == "hyundai": - tokens = car.model.lower().split(" ") - self.assertNotIn("phev", tokens, "Use `Plug-in Hybrid`") - self.assertNotIn("hev", tokens, "Use `Hybrid`") - self.assertNotIn("ev", tokens, "Use `Electric`") - if "plug-in hybrid" in car.model.lower(): - self.assertIn("Plug-in Hybrid", car.model, "Use correct capitalization") + for car in self.all_cars: + if car.car_name == "hyundai": + tokens = car.model.lower().split(" ") + self.assertNotIn("phev", tokens, "Use `Plug-in Hybrid`") + self.assertNotIn("hev", tokens, "Use `Hybrid`") + self.assertNotIn("ev", tokens, "Use `Electric`") + if "plug-in hybrid" in car.model.lower(): + self.assertIn("Plug-in Hybrid", car.model, "Use correct capitalization") if __name__ == "__main__":