more car info -> car docs (#31885)
This commit is contained in:
parent
3e816e7df8
commit
0b92f4e9ee
|
@ -340,7 +340,7 @@ jobs:
|
|||
- uses: ./.github/workflows/setup-with-retry
|
||||
- name: Get base car info
|
||||
run: |
|
||||
${{ env.RUN }} "scons -j$(nproc) && python selfdrive/debug/dump_car_info.py --path /tmp/openpilot_cache/base_car_info"
|
||||
${{ env.RUN }} "scons -j$(nproc) && python selfdrive/debug/dump_car_docs.py --path /tmp/openpilot_cache/base_car_docs"
|
||||
sudo chown -R $USER:$USER ${{ github.workspace }}
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
@ -352,7 +352,7 @@ jobs:
|
|||
run: |
|
||||
cd current
|
||||
${{ env.RUN }} "scons -j$(nproc)"
|
||||
output=$(${{ env.RUN }} "python selfdrive/debug/print_docs_diff.py --path /tmp/openpilot_cache/base_car_info")
|
||||
output=$(${{ env.RUN }} "python selfdrive/debug/print_docs_diff.py --path /tmp/openpilot_cache/base_car_docs")
|
||||
output="${output//$'\n'/'%0A'}"
|
||||
echo "::set-output name=diff::$output"
|
||||
- name: Find comment
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
from collections import Counter
|
||||
from pprint import pprint
|
||||
|
||||
from openpilot.selfdrive.car.docs import get_all_car_info
|
||||
from openpilot.selfdrive.car.docs import get_all_car_docs
|
||||
|
||||
if __name__ == "__main__":
|
||||
cars = get_all_car_info()
|
||||
cars = get_all_car_docs()
|
||||
make_count = Counter(l.make for l in cars)
|
||||
print("\n", "*" * 20, len(cars), "total", "*" * 20, "\n")
|
||||
pprint(make_count)
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
|
||||
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
|
||||
|
||||
# {{all_car_info | length}} Supported Cars
|
||||
# {{all_car_docs | length}} Supported Cars
|
||||
|
||||
|{{Column | map(attribute='value') | join('|') | replace(hardware_col_name, wide_hardware_col_name)}}|
|
||||
|---|---|---|{% for _ in range((Column | length) - 3) %}{{':---:|'}}{% endfor +%}
|
||||
{% for car_info in all_car_info %}
|
||||
|{% for column in Column %}{{car_info.get_column(column, star_icon, video_icon, footnote_tag)}}|{% endfor %}
|
||||
{% for car_docs in all_car_docs %}
|
||||
|{% for column in Column %}{{car_docs.get_column(column, star_icon, video_icon, footnote_tag)}}|{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
|
|
@ -262,7 +262,7 @@ class CarSpecs:
|
|||
@dataclass(order=True)
|
||||
class PlatformConfig(Freezable):
|
||||
platform_str: str
|
||||
car_info: list[CarDocs]
|
||||
car_docs: list[CarDocs]
|
||||
specs: CarSpecs
|
||||
|
||||
dbc_dict: DbcDict
|
||||
|
|
|
@ -25,43 +25,43 @@ CARS_MD_OUT = os.path.join(BASEDIR, "docs", "CARS.md")
|
|||
CARS_MD_TEMPLATE = os.path.join(BASEDIR, "selfdrive", "car", "CARS_template.md")
|
||||
|
||||
|
||||
def get_all_car_info() -> list[CarDocs]:
|
||||
all_car_info: list[CarDocs] = []
|
||||
def get_all_car_docs() -> list[CarDocs]:
|
||||
all_car_docs: list[CarDocs] = []
|
||||
footnotes = get_all_footnotes()
|
||||
for model, platform in PLATFORMS.items():
|
||||
car_info = platform.config.car_info
|
||||
car_docs = platform.config.car_docs
|
||||
# If available, uses experimental longitudinal limits for the docs
|
||||
CP = interfaces[model][0].get_params(platform, fingerprint=gen_empty_fingerprint(),
|
||||
car_fw=[car.CarParams.CarFw(ecu="unknown")], experimental_long=True, docs=True)
|
||||
|
||||
if CP.dashcamOnly or not len(car_info):
|
||||
if CP.dashcamOnly or not len(car_docs):
|
||||
continue
|
||||
|
||||
# A platform can include multiple car models
|
||||
for _car_info in car_info:
|
||||
if not hasattr(_car_info, "row"):
|
||||
_car_info.init_make(CP)
|
||||
_car_info.init(CP, footnotes)
|
||||
all_car_info.append(_car_info)
|
||||
for _car_docs in car_docs:
|
||||
if not hasattr(_car_docs, "row"):
|
||||
_car_docs.init_make(CP)
|
||||
_car_docs.init(CP, footnotes)
|
||||
all_car_docs.append(_car_docs)
|
||||
|
||||
# Sort cars by make and model + year
|
||||
sorted_cars: list[CarDocs] = natsorted(all_car_info, key=lambda car: car.name.lower())
|
||||
sorted_cars: list[CarDocs] = natsorted(all_car_docs, key=lambda car: car.name.lower())
|
||||
return sorted_cars
|
||||
|
||||
|
||||
def group_by_make(all_car_info: list[CarDocs]) -> dict[str, list[CarDocs]]:
|
||||
sorted_car_info = defaultdict(list)
|
||||
for car_info in all_car_info:
|
||||
sorted_car_info[car_info.make].append(car_info)
|
||||
return dict(sorted_car_info)
|
||||
def group_by_make(all_car_docs: list[CarDocs]) -> dict[str, list[CarDocs]]:
|
||||
sorted_car_docs = defaultdict(list)
|
||||
for car_docs in all_car_docs:
|
||||
sorted_car_docs[car_docs.make].append(car_docs)
|
||||
return dict(sorted_car_docs)
|
||||
|
||||
|
||||
def generate_cars_md(all_car_info: list[CarDocs], template_fn: str) -> str:
|
||||
def generate_cars_md(all_car_docs: list[CarDocs], template_fn: str) -> str:
|
||||
with open(template_fn) as f:
|
||||
template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True)
|
||||
|
||||
footnotes = [fn.value.text for fn in get_all_footnotes()]
|
||||
cars_md: str = template.render(all_car_info=all_car_info, PartType=PartType,
|
||||
cars_md: str = template.render(all_car_docs=all_car_docs, PartType=PartType,
|
||||
group_by_make=group_by_make, footnotes=footnotes,
|
||||
Column=Column)
|
||||
return cars_md
|
||||
|
@ -76,5 +76,5 @@ if __name__ == "__main__":
|
|||
args = parser.parse_args()
|
||||
|
||||
with open(args.out, 'w') as f:
|
||||
f.write(generate_cars_md(get_all_car_info(), args.template))
|
||||
f.write(generate_cars_md(get_all_car_docs(), args.template))
|
||||
print(f"Generated and written to {args.out}")
|
||||
|
|
|
@ -77,13 +77,13 @@ class FordPlatformConfig(PlatformConfig):
|
|||
dbc_dict: DbcDict = field(default_factory=lambda: dbc_dict('ford_lincoln_base_pt', RADAR.DELPHI_MRR))
|
||||
|
||||
def init(self):
|
||||
for car_info in list(self.car_info):
|
||||
if car_info.hybrid:
|
||||
name = f"{car_info.make} {car_info.model} Hybrid {car_info.years}"
|
||||
self.car_info.append(replace(copy.deepcopy(car_info), name=name))
|
||||
if car_info.plug_in_hybrid:
|
||||
name = f"{car_info.make} {car_info.model} Plug-in Hybrid {car_info.years}"
|
||||
self.car_info.append(replace(copy.deepcopy(car_info), name=name))
|
||||
for car_docs in list(self.car_docs):
|
||||
if car_docs.hybrid:
|
||||
name = f"{car_docs.make} {car_docs.model} Hybrid {car_docs.years}"
|
||||
self.car_docs.append(replace(copy.deepcopy(car_docs), name=name))
|
||||
if car_docs.plug_in_hybrid:
|
||||
name = f"{car_docs.make} {car_docs.model} Plug-in Hybrid {car_docs.years}"
|
||||
self.car_docs.append(replace(copy.deepcopy(car_docs), name=name))
|
||||
|
||||
|
||||
@dataclass
|
||||
|
|
|
@ -50,7 +50,7 @@ class CAR(Platforms):
|
|||
)
|
||||
# Leaf with ADAS ECU found behind instrument cluster instead of glovebox
|
||||
# Currently the only known difference between them is the inverted seatbelt signal.
|
||||
LEAF_IC = LEAF.override(platform_str="NISSAN LEAF 2018 Instrument Cluster", car_info=[])
|
||||
LEAF_IC = LEAF.override(platform_str="NISSAN LEAF 2018 Instrument Cluster", car_docs=[])
|
||||
ROGUE = NissanPlaformConfig(
|
||||
"NISSAN ROGUE 2019",
|
||||
[NissanCarDocs("Nissan Rogue 2018-20")],
|
||||
|
|
|
@ -6,18 +6,18 @@ import unittest
|
|||
|
||||
from openpilot.common.basedir import BASEDIR
|
||||
from openpilot.selfdrive.car.car_helpers import interfaces
|
||||
from openpilot.selfdrive.car.docs import CARS_MD_OUT, CARS_MD_TEMPLATE, generate_cars_md, get_all_car_info
|
||||
from openpilot.selfdrive.car.docs import CARS_MD_OUT, CARS_MD_TEMPLATE, generate_cars_md, get_all_car_docs
|
||||
from openpilot.selfdrive.car.docs_definitions import Cable, Column, PartType, Star
|
||||
from openpilot.selfdrive.car.honda.values import CAR as HONDA
|
||||
from openpilot.selfdrive.car.values import PLATFORMS
|
||||
from openpilot.selfdrive.debug.dump_car_info import dump_car_info
|
||||
from openpilot.selfdrive.debug.print_docs_diff import print_car_info_diff
|
||||
from openpilot.selfdrive.debug.dump_car_docs import dump_car_docs
|
||||
from openpilot.selfdrive.debug.print_docs_diff import print_car_docs_diff
|
||||
|
||||
|
||||
class TestCarDocs(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.all_cars = get_all_car_info()
|
||||
cls.all_cars = get_all_car_docs()
|
||||
|
||||
def test_generator(self):
|
||||
generated_cars_md = generate_cars_md(self.all_cars, CARS_MD_TEMPLATE)
|
||||
|
@ -29,24 +29,24 @@ class TestCarDocs(unittest.TestCase):
|
|||
|
||||
def test_docs_diff(self):
|
||||
dump_path = os.path.join(BASEDIR, "selfdrive", "car", "tests", "cars_dump")
|
||||
dump_car_info(dump_path)
|
||||
print_car_info_diff(dump_path)
|
||||
dump_car_docs(dump_path)
|
||||
print_car_docs_diff(dump_path)
|
||||
os.remove(dump_path)
|
||||
|
||||
def test_duplicate_years(self):
|
||||
make_model_years = defaultdict(list)
|
||||
for car in self.all_cars:
|
||||
with self.subTest(car_info_name=car.name):
|
||||
with self.subTest(car_docs_name=car.name):
|
||||
make_model = (car.make, car.model)
|
||||
for year in car.year_list:
|
||||
self.assertNotIn(year, make_model_years[make_model], f"{car.name}: Duplicate model year")
|
||||
make_model_years[make_model].append(year)
|
||||
|
||||
def test_missing_car_info(self):
|
||||
all_car_info_platforms = [name for name, config in PLATFORMS.items()]
|
||||
def test_missing_car_docs(self):
|
||||
all_car_docs_platforms = [name for name, config in PLATFORMS.items()]
|
||||
for platform in sorted(interfaces.keys()):
|
||||
with self.subTest(platform=platform):
|
||||
self.assertTrue(platform in all_car_info_platforms, f"Platform: {platform} doesn't have a CarDocs entry")
|
||||
self.assertTrue(platform in all_car_docs_platforms, f"Platform: {platform} doesn't have a CarDocs entry")
|
||||
|
||||
def test_naming_conventions(self):
|
||||
# Asserts market-standard car naming conventions by brand
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
import argparse
|
||||
import pickle
|
||||
|
||||
from openpilot.selfdrive.car.docs import get_all_car_info
|
||||
from openpilot.selfdrive.car.docs import get_all_car_docs
|
||||
|
||||
|
||||
def dump_car_info(path):
|
||||
def dump_car_docs(path):
|
||||
with open(path, 'wb') as f:
|
||||
pickle.dump(get_all_car_info(), f)
|
||||
pickle.dump(get_all_car_docs(), f)
|
||||
print(f'Dumping car info to {path}')
|
||||
|
||||
|
||||
|
@ -15,4 +15,4 @@ if __name__ == "__main__":
|
|||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--path", required=True)
|
||||
args = parser.parse_args()
|
||||
dump_car_info(args.path)
|
||||
dump_car_docs(args.path)
|
|
@ -4,7 +4,7 @@ from collections import defaultdict
|
|||
import difflib
|
||||
import pickle
|
||||
|
||||
from openpilot.selfdrive.car.docs import get_all_car_info
|
||||
from openpilot.selfdrive.car.docs import get_all_car_docs
|
||||
from openpilot.selfdrive.car.docs_definitions import Column
|
||||
|
||||
FOOTNOTE_TAG = "<sup>{}</sup>"
|
||||
|
@ -17,7 +17,7 @@ COLUMN_HEADER = "|---|---|---|{}|".format("|".join([":---:"] * (len(Column) - 3)
|
|||
ARROW_SYMBOL = "➡️"
|
||||
|
||||
|
||||
def load_base_car_info(path):
|
||||
def load_base_car_docs(path):
|
||||
with open(path, "rb") as f:
|
||||
return pickle.load(f)
|
||||
|
||||
|
@ -57,31 +57,31 @@ def format_row(builder):
|
|||
return "|" + "|".join(builder) + "|"
|
||||
|
||||
|
||||
def print_car_info_diff(path):
|
||||
base_car_info = defaultdict(list)
|
||||
new_car_info = defaultdict(list)
|
||||
def print_car_docs_diff(path):
|
||||
base_car_docs = defaultdict(list)
|
||||
new_car_docs = defaultdict(list)
|
||||
|
||||
for car in load_base_car_info(path):
|
||||
base_car_info[car.car_fingerprint].append(car)
|
||||
for car in get_all_car_info():
|
||||
new_car_info[car.car_fingerprint].append(car)
|
||||
for car in load_base_car_docs(path):
|
||||
base_car_docs[car.car_fingerprint].append(car)
|
||||
for car in get_all_car_docs():
|
||||
new_car_docs[car.car_fingerprint].append(car)
|
||||
|
||||
# Add new platforms to base cars so we can detect additions and removals in one pass
|
||||
base_car_info.update({car: [] for car in new_car_info if car not in base_car_info})
|
||||
base_car_docs.update({car: [] for car in new_car_docs if car not in base_car_docs})
|
||||
|
||||
changes = defaultdict(list)
|
||||
for base_car_model, base_cars in base_car_info.items():
|
||||
for base_car_model, base_cars in base_car_docs.items():
|
||||
# Match car info changes, and get additions and removals
|
||||
new_cars = new_car_info[base_car_model]
|
||||
new_cars = new_car_docs[base_car_model]
|
||||
car_changes, car_additions, car_removals = match_cars(base_cars, new_cars)
|
||||
|
||||
# Removals
|
||||
for car_info in car_removals:
|
||||
changes["removals"].append(format_row([car_info.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) for column in Column]))
|
||||
for car_docs in car_removals:
|
||||
changes["removals"].append(format_row([car_docs.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) for column in Column]))
|
||||
|
||||
# Additions
|
||||
for car_info in car_additions:
|
||||
changes["additions"].append(format_row([car_info.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) for column in Column]))
|
||||
for car_docs in car_additions:
|
||||
changes["additions"].append(format_row([car_docs.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) for column in Column]))
|
||||
|
||||
for new_car, base_car in car_changes:
|
||||
# Column changes
|
||||
|
@ -117,4 +117,4 @@ if __name__ == "__main__":
|
|||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--path", required=True)
|
||||
args = parser.parse_args()
|
||||
print_car_info_diff(args.path)
|
||||
print_car_docs_diff(args.path)
|
||||
|
|
|
@ -146,10 +146,10 @@
|
|||
],
|
||||
"source": [
|
||||
"def test_year_code(platform, year):\n",
|
||||
" car_info = CAR(platform).config.car_info\n",
|
||||
" if isinstance(car_info, list):\n",
|
||||
" car_info = car_info[0]\n",
|
||||
" years = [int(y) for y in car_info.year_list]\n",
|
||||
" car_docs = CAR(platform).config.car_docs\n",
|
||||
" if isinstance(car_docs, list):\n",
|
||||
" car_docs = car_docs[0]\n",
|
||||
" years = [int(y) for y in car_docs.year_list]\n",
|
||||
" correct_year = year in years\n",
|
||||
" print(f\"{correct_year=!s: <6} {platform=: <32} {year=: <5} {years=}\")\n",
|
||||
"\n",
|
||||
|
|
Loading…
Reference in New Issue