From a3ec54fa5a45c00414c936fec25c7b0bc9b40eea Mon Sep 17 00:00:00 2001 From: adeebshihadeh Date: Tue, 20 Jan 2026 08:10:23 +0000 Subject: [PATCH 01/77] docs: Scheduled auto-update CARS.md --- docs/CARS.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index f3ee8696..cd8d210b 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -1,6 +1,6 @@ -# Support Information for 384 Known Cars +# Support Information for 385 Known Cars |Make|Model|Package|Support Level| |---|---|---|:---:| @@ -10,7 +10,7 @@ |Acura|MDX 2015-16|Advance Package|[Community](#community)| |Acura|MDX 2017-20|All|[Community](#community)| |Acura|MDX 2022-24|All|[Community](#community)| -|Acura|MDX 2025|All except Type S|[Upstream](#upstream)| +|Acura|MDX 2025-26|All except Type S|[Upstream](#upstream)| |Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|[Upstream](#upstream)| |Acura|RDX 2019-21|All|[Upstream](#upstream)| |Acura|RDX 2022-25|All|[Community](#community)| @@ -103,7 +103,7 @@ |Honda|CR-V 2017-22|Honda Sensing|[Upstream](#upstream)| |Honda|CR-V 2023-26|All|[Upstream](#upstream)| |Honda|CR-V Hybrid 2017-22|Honda Sensing|[Upstream](#upstream)| -|Honda|CR-V Hybrid 2023-25|All|[Upstream](#upstream)| +|Honda|CR-V Hybrid 2023-26|All|[Upstream](#upstream)| |Honda|e 2020|All|[Upstream](#upstream)| |Honda|Fit 2018-20|Honda Sensing|[Upstream](#upstream)| |Honda|Freed 2020|Honda Sensing|[Upstream](#upstream)| @@ -218,7 +218,8 @@ |Lexus|IS 2017-19|All|[Upstream](#upstream)| |Lexus|IS 2022-24|All|[Upstream](#upstream)| |Lexus|LC 2024-25|All|[Upstream](#upstream)| -|Lexus|NS 2022-25|Any|[Not compatible](#can-bus-security)| +|Lexus|LS 2018|All except Lexus Safety System+ A|[Upstream](#upstream)| +|Lexus|NS 2022-25|All|[Not compatible](#can-bus-security)| |Lexus|NX 2018-19|All|[Upstream](#upstream)| |Lexus|NX 2020-21|All|[Upstream](#upstream)| |Lexus|NX Hybrid 2018-19|All|[Upstream](#upstream)| @@ -273,7 +274,7 @@ |Subaru|Outback 2018-19|EyeSight Driver Assistance|[Dashcam mode](#dashcam)| |Subaru|Outback 2020-22|All|[Upstream](#upstream)| |Subaru|Outback 2023|All|[Dashcam mode](#dashcam)| -|Subaru|Solterra 2023-25|Any|[Not compatible](#can-bus-security)| +|Subaru|Solterra 2023-25|All|[Not compatible](#can-bus-security)| |Subaru|XV 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)| |Subaru|XV 2020-21|EyeSight Driver Assistance|[Upstream](#upstream)| |Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| @@ -298,19 +299,19 @@ |Toyota|Avalon 2022|All|[Upstream](#upstream)| |Toyota|Avalon Hybrid 2019-21|All|[Upstream](#upstream)| |Toyota|Avalon Hybrid 2022|All|[Upstream](#upstream)| -|Toyota|bZ4x 2023-25|Any|[Not compatible](#can-bus-security)| +|Toyota|bZ4x 2023-25|All|[Not compatible](#can-bus-security)| |Toyota|C-HR 2017-20|All|[Upstream](#upstream)| |Toyota|C-HR 2021|All|[Upstream](#upstream)| |Toyota|C-HR Hybrid 2017-20|All|[Upstream](#upstream)| |Toyota|C-HR Hybrid 2021-22|All|[Upstream](#upstream)| |Toyota|Camry 2018-20|All|[Upstream](#upstream)| |Toyota|Camry 2021-24|All|[Upstream](#upstream)| -|Toyota|Camry 2025|Any|[Not compatible](#can-bus-security)| +|Toyota|Camry 2025|All|[Not compatible](#can-bus-security)| |Toyota|Camry Hybrid 2018-20|All|[Upstream](#upstream)| |Toyota|Camry Hybrid 2021-24|All|[Upstream](#upstream)| |Toyota|Corolla 2017-19|All|[Upstream](#upstream)| |Toyota|Corolla 2020-22|All|[Upstream](#upstream)| -|Toyota|Corolla Cross 2022-25|Any|[Not compatible](#can-bus-security)| +|Toyota|Corolla Cross 2022-25|All|[Not compatible](#can-bus-security)| |Toyota|Corolla Cross (Non-US only) 2020-23|All|[Upstream](#upstream)| |Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|[Upstream](#upstream)| |Toyota|Corolla Hatchback 2019-22|All|[Upstream](#upstream)| @@ -318,7 +319,7 @@ |Toyota|Corolla Hybrid (South America only) 2020-23|All|[Upstream](#upstream)| |Toyota|Highlander 2017-19|All|[Upstream](#upstream)| |Toyota|Highlander 2020-23|All|[Upstream](#upstream)| -|Toyota|Highlander 2025|Any|[Not compatible](#can-bus-security)| +|Toyota|Highlander 2025|All|[Not compatible](#can-bus-security)| |Toyota|Highlander Hybrid 2017-19|All|[Upstream](#upstream)| |Toyota|Highlander Hybrid 2020-23|All|[Upstream](#upstream)| |Toyota|Mirai 2021|All|[Upstream](#upstream)| @@ -339,13 +340,13 @@ |Toyota|RAV4 Hybrid 2022|All|[Upstream](#upstream)| |Toyota|RAV4 Hybrid 2023-25|All|[Upstream](#upstream)| |Toyota|RAV4 Prime 2021-23|All|[Custom](#secoc-cars-with-recoverable-keys)| -|Toyota|RAV4 Prime 2024-25|Any|[Not compatible](#can-bus-security)| -|Toyota|Sequoia 2023-25|Any|[Not compatible](#can-bus-security)| +|Toyota|RAV4 Prime 2024-25|All|[Not compatible](#can-bus-security)| +|Toyota|Sequoia 2023-25|All|[Not compatible](#can-bus-security)| |Toyota|Sienna 2018-20|All|[Upstream](#upstream)| |Toyota|Sienna 2021-23|All|[Custom](#secoc-cars-with-recoverable-keys)| -|Toyota|Sienna 2024-25|Any|[Not compatible](#can-bus-security)| -|Toyota|Tundra 2022-25|Any|[Not compatible](#can-bus-security)| -|Toyota|Venza 2021-25|Any|[Not compatible](#can-bus-security)| +|Toyota|Sienna 2024-25|All|[Not compatible](#can-bus-security)| +|Toyota|Tundra 2022-25|All|[Not compatible](#can-bus-security)| +|Toyota|Venza 2021-25|All|[Not compatible](#can-bus-security)| |Toyota|Yaris (Non-US only) 2020, 2023|All|[Custom](#secoc-cars-with-recoverable-keys)| |Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| From 4ec3892bcdd7c02a88e694df81db5a34f1164728 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 20 Jan 2026 09:30:31 -0800 Subject: [PATCH 02/77] pin python dependencies (#3047) * check in uv.lock * ty fixes --- .github/workflows/update-uv-lock.yml | 30 + .gitignore | 1 - opendbc/car/ccp.py | 8 +- opendbc/car/vehicle_model.py | 2 +- uv.lock | 1078 ++++++++++++++++++++++++++ 5 files changed, 1113 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/update-uv-lock.yml create mode 100644 uv.lock diff --git a/.github/workflows/update-uv-lock.yml b/.github/workflows/update-uv-lock.yml new file mode 100644 index 00000000..3dd4e6f7 --- /dev/null +++ b/.github/workflows/update-uv-lock.yml @@ -0,0 +1,30 @@ +name: Update uv.lock + +on: + schedule: + - cron: "0 14 * * 1" # every Monday at 2am UTC (6am PST) + workflow_dispatch: + +jobs: + update-uv-lock: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v5 + - name: Update uv.lock + run: uv lock --upgrade + - name: Create Pull Request + uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83 + with: + author: Vehicle Researcher + token: ${{ secrets.ACTIONS_CREATE_PR_PAT }} + commit-message: "[bot] Update uv.lock" + title: "[bot] Update uv.lock" + body: "Weekly update of uv.lock dependencies" + branch: "update-uv-lock" + base: "master" + delete-branch: true + labels: bot diff --git a/.gitignore b/.gitignore index 5b2213fd..269017bf 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ *.gcno *.dump *.gcov -uv.lock /dist/ .vscode/ __pycache__/ diff --git a/opendbc/car/ccp.py b/opendbc/car/ccp.py index c94acb80..577c4768 100644 --- a/opendbc/car/ccp.py +++ b/opendbc/car/ccp.py @@ -217,7 +217,7 @@ class CcpClient: resp = self._recv_dto(0.025) # mta_addr_ext = resp[0] mta_addr = struct.unpack(f"{self.byte_order.value}I", resp[1:5])[0] - return mta_addr # type: ignore + return mta_addr def download_6_bytes(self, data: bytes) -> int: if len(data) != 6: @@ -226,7 +226,7 @@ class CcpClient: resp = self._recv_dto(0.025) # mta_addr_ext = resp[0] mta_addr = struct.unpack(f"{self.byte_order.value}I", resp[1:5])[0] - return mta_addr # type: ignore + return mta_addr def upload(self, size: int) -> bytes: if size > 5: @@ -325,7 +325,7 @@ class CcpClient: resp = self._recv_dto(0.1) # mta_addr_ext = resp[0] mta_addr = struct.unpack(f"{self.byte_order.value}I", resp[1:5])[0] - return mta_addr # type: ignore + return mta_addr def program_6_bytes(self, data: bytes) -> int: if len(data) != 6: @@ -334,7 +334,7 @@ class CcpClient: resp = self._recv_dto(0.1) # mta_addr_ext = resp[0] mta_addr = struct.unpack(f"{self.byte_order.value}I", resp[1:5])[0] - return mta_addr # type: ignore + return mta_addr def move_memory_block(self, size: int) -> None: self._send_cro(COMMAND_CODE.MOVE, struct.pack(f"{self.byte_order.value}I", size)) diff --git a/opendbc/car/vehicle_model.py b/opendbc/car/vehicle_model.py index bc87503a..c7d0494b 100755 --- a/opendbc/car/vehicle_model.py +++ b/opendbc/car/vehicle_model.py @@ -219,7 +219,7 @@ def dyn_ss_sol(sa: float, u: float, roll: float, VM: VehicleModel) -> np.ndarray """ A, B = create_dyn_state_matrices(u, VM) inp = np.array([[sa], [roll]]) - return -solve(A, B) @ inp # type: ignore + return -solve(A, B) @ inp def calc_slip_factor(VM: VehicleModel) -> float: diff --git a/uv.lock b/uv.lock new file mode 100644 index 00000000..4b016c13 --- /dev/null +++ b/uv.lock @@ -0,0 +1,1078 @@ +version = 1 +revision = 3 +requires-python = ">=3.11, <3.13" + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, +] + +[[package]] +name = "certifi" +version = "2026.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" }, + { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" }, + { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" }, + { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" }, + { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" }, + { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" }, + { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" }, + { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" }, + { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" }, + { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" }, + { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" }, + { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" }, + { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" }, + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "codespell" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/e0/709453393c0ea77d007d907dd436b3ee262e28b30995ea1aa36c6ffbccaf/codespell-2.4.1.tar.gz", hash = "sha256:299fcdcb09d23e81e35a671bbe746d5ad7e8385972e65dbb833a2eaac33c01e5", size = 344740, upload-time = "2025-01-28T18:52:39.411Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/01/b394922252051e97aab231d416c86da3d8a6d781eeadcdca1082867de64e/codespell-2.4.1-py3-none-any.whl", hash = "sha256:3dadafa67df7e4a3dbf51e0d7315061b80d265f9552ebd699b3dd6834b47e425", size = 344501, upload-time = "2025-01-28T18:52:37.057Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "colorlog" +version = "6.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162, upload-time = "2025-10-16T16:14:11.978Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" }, +] + +[[package]] +name = "comma-car-segments" +version = "0.1.0" +source = { url = "https://huggingface.co/datasets/commaai/commaCarSegments/resolve/main/dist/comma_car_segments-0.1.0-py3-none-any.whl" } +dependencies = [ + { name = "requests" }, +] +wheels = [ + { url = "https://huggingface.co/datasets/commaai/commaCarSegments/resolve/main/dist/comma_car_segments-0.1.0-py3-none-any.whl", hash = "sha256:6c6483558cd90d3e9152ff7930394bb13678a7ab50ef2c79601d818c66235352" }, +] + +[package.metadata] +requires-dist = [{ name = "requests" }] + +[[package]] +name = "contourpy" +version = "1.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1", size = 288773, upload-time = "2025-07-26T12:01:02.277Z" }, + { url = "https://files.pythonhosted.org/packages/0d/44/c4b0b6095fef4dc9c420e041799591e3b63e9619e3044f7f4f6c21c0ab24/contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381", size = 270149, upload-time = "2025-07-26T12:01:04.072Z" }, + { url = "https://files.pythonhosted.org/packages/30/2e/dd4ced42fefac8470661d7cb7e264808425e6c5d56d175291e93890cce09/contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7", size = 329222, upload-time = "2025-07-26T12:01:05.688Z" }, + { url = "https://files.pythonhosted.org/packages/f2/74/cc6ec2548e3d276c71389ea4802a774b7aa3558223b7bade3f25787fafc2/contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1", size = 377234, upload-time = "2025-07-26T12:01:07.054Z" }, + { url = "https://files.pythonhosted.org/packages/03/b3/64ef723029f917410f75c09da54254c5f9ea90ef89b143ccadb09df14c15/contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a", size = 380555, upload-time = "2025-07-26T12:01:08.801Z" }, + { url = "https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db", size = 355238, upload-time = "2025-07-26T12:01:10.319Z" }, + { url = "https://files.pythonhosted.org/packages/98/56/f914f0dd678480708a04cfd2206e7c382533249bc5001eb9f58aa693e200/contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620", size = 1326218, upload-time = "2025-07-26T12:01:12.659Z" }, + { url = "https://files.pythonhosted.org/packages/fb/d7/4a972334a0c971acd5172389671113ae82aa7527073980c38d5868ff1161/contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f", size = 1392867, upload-time = "2025-07-26T12:01:15.533Z" }, + { url = "https://files.pythonhosted.org/packages/75/3e/f2cc6cd56dc8cff46b1a56232eabc6feea52720083ea71ab15523daab796/contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff", size = 183677, upload-time = "2025-07-26T12:01:17.088Z" }, + { url = "https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42", size = 225234, upload-time = "2025-07-26T12:01:18.256Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b6/71771e02c2e004450c12b1120a5f488cad2e4d5b590b1af8bad060360fe4/contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470", size = 193123, upload-time = "2025-07-26T12:01:19.848Z" }, + { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" }, + { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" }, + { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" }, + { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" }, + { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" }, + { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" }, + { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" }, + { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" }, + { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" }, + { url = "https://files.pythonhosted.org/packages/a5/29/8dcfe16f0107943fa92388c23f6e05cff0ba58058c4c95b00280d4c75a14/contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497", size = 278809, upload-time = "2025-07-26T12:02:52.74Z" }, + { url = "https://files.pythonhosted.org/packages/85/a9/8b37ef4f7dafeb335daee3c8254645ef5725be4d9c6aa70b50ec46ef2f7e/contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8", size = 261593, upload-time = "2025-07-26T12:02:54.037Z" }, + { url = "https://files.pythonhosted.org/packages/0a/59/ebfb8c677c75605cc27f7122c90313fd2f375ff3c8d19a1694bda74aaa63/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e", size = 302202, upload-time = "2025-07-26T12:02:55.947Z" }, + { url = "https://files.pythonhosted.org/packages/3c/37/21972a15834d90bfbfb009b9d004779bd5a07a0ec0234e5ba8f64d5736f4/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989", size = 329207, upload-time = "2025-07-26T12:02:57.468Z" }, + { url = "https://files.pythonhosted.org/packages/0c/58/bd257695f39d05594ca4ad60df5bcb7e32247f9951fd09a9b8edb82d1daa/contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77", size = 225315, upload-time = "2025-07-26T12:02:58.801Z" }, +] + +[[package]] +name = "coverage" +version = "7.13.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/f9/e92df5e07f3fc8d4c7f9a0f146ef75446bf870351cd37b788cf5897f8079/coverage-7.13.1.tar.gz", hash = "sha256:b7593fe7eb5feaa3fbb461ac79aac9f9fc0387a5ca8080b0c6fe2ca27b091afd", size = 825862, upload-time = "2025-12-28T15:42:56.969Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/9b/77baf488516e9ced25fc215a6f75d803493fc3f6a1a1227ac35697910c2a/coverage-7.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a55d509a1dc5a5b708b5dad3b5334e07a16ad4c2185e27b40e4dba796ab7f88", size = 218755, upload-time = "2025-12-28T15:40:30.812Z" }, + { url = "https://files.pythonhosted.org/packages/d7/cd/7ab01154e6eb79ee2fab76bf4d89e94c6648116557307ee4ebbb85e5c1bf/coverage-7.13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4d010d080c4888371033baab27e47c9df7d6fb28d0b7b7adf85a4a49be9298b3", size = 219257, upload-time = "2025-12-28T15:40:32.333Z" }, + { url = "https://files.pythonhosted.org/packages/01/d5/b11ef7863ffbbdb509da0023fad1e9eda1c0eaea61a6d2ea5b17d4ac706e/coverage-7.13.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d938b4a840fb1523b9dfbbb454f652967f18e197569c32266d4d13f37244c3d9", size = 249657, upload-time = "2025-12-28T15:40:34.1Z" }, + { url = "https://files.pythonhosted.org/packages/f7/7c/347280982982383621d29b8c544cf497ae07ac41e44b1ca4903024131f55/coverage-7.13.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bf100a3288f9bb7f919b87eb84f87101e197535b9bd0e2c2b5b3179633324fee", size = 251581, upload-time = "2025-12-28T15:40:36.131Z" }, + { url = "https://files.pythonhosted.org/packages/82/f6/ebcfed11036ade4c0d75fa4453a6282bdd225bc073862766eec184a4c643/coverage-7.13.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef6688db9bf91ba111ae734ba6ef1a063304a881749726e0d3575f5c10a9facf", size = 253691, upload-time = "2025-12-28T15:40:37.626Z" }, + { url = "https://files.pythonhosted.org/packages/02/92/af8f5582787f5d1a8b130b2dcba785fa5e9a7a8e121a0bb2220a6fdbdb8a/coverage-7.13.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0b609fc9cdbd1f02e51f67f51e5aee60a841ef58a68d00d5ee2c0faf357481a3", size = 249799, upload-time = "2025-12-28T15:40:39.47Z" }, + { url = "https://files.pythonhosted.org/packages/24/aa/0e39a2a3b16eebf7f193863323edbff38b6daba711abaaf807d4290cf61a/coverage-7.13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c43257717611ff5e9a1d79dce8e47566235ebda63328718d9b65dd640bc832ef", size = 251389, upload-time = "2025-12-28T15:40:40.954Z" }, + { url = "https://files.pythonhosted.org/packages/73/46/7f0c13111154dc5b978900c0ccee2e2ca239b910890e674a77f1363d483e/coverage-7.13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e09fbecc007f7b6afdfb3b07ce5bd9f8494b6856dd4f577d26c66c391b829851", size = 249450, upload-time = "2025-12-28T15:40:42.489Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ca/e80da6769e8b669ec3695598c58eef7ad98b0e26e66333996aee6316db23/coverage-7.13.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:a03a4f3a19a189919c7055098790285cc5c5b0b3976f8d227aea39dbf9f8bfdb", size = 249170, upload-time = "2025-12-28T15:40:44.279Z" }, + { url = "https://files.pythonhosted.org/packages/af/18/9e29baabdec1a8644157f572541079b4658199cfd372a578f84228e860de/coverage-7.13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3820778ea1387c2b6a818caec01c63adc5b3750211af6447e8dcfb9b6f08dbba", size = 250081, upload-time = "2025-12-28T15:40:45.748Z" }, + { url = "https://files.pythonhosted.org/packages/00/f8/c3021625a71c3b2f516464d322e41636aea381018319050a8114105872ee/coverage-7.13.1-cp311-cp311-win32.whl", hash = "sha256:ff10896fa55167371960c5908150b434b71c876dfab97b69478f22c8b445ea19", size = 221281, upload-time = "2025-12-28T15:40:47.232Z" }, + { url = "https://files.pythonhosted.org/packages/27/56/c216625f453df6e0559ed666d246fcbaaa93f3aa99eaa5080cea1229aa3d/coverage-7.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:a998cc0aeeea4c6d5622a3754da5a493055d2d95186bad877b0a34ea6e6dbe0a", size = 222215, upload-time = "2025-12-28T15:40:49.19Z" }, + { url = "https://files.pythonhosted.org/packages/5c/9a/be342e76f6e531cae6406dc46af0d350586f24d9b67fdfa6daee02df71af/coverage-7.13.1-cp311-cp311-win_arm64.whl", hash = "sha256:fea07c1a39a22614acb762e3fbbb4011f65eedafcb2948feeef641ac78b4ee5c", size = 220886, upload-time = "2025-12-28T15:40:51.067Z" }, + { url = "https://files.pythonhosted.org/packages/ce/8a/87af46cccdfa78f53db747b09f5f9a21d5fc38d796834adac09b30a8ce74/coverage-7.13.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6f34591000f06e62085b1865c9bc5f7858df748834662a51edadfd2c3bfe0dd3", size = 218927, upload-time = "2025-12-28T15:40:52.814Z" }, + { url = "https://files.pythonhosted.org/packages/82/a8/6e22fdc67242a4a5a153f9438d05944553121c8f4ba70cb072af4c41362e/coverage-7.13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b67e47c5595b9224599016e333f5ec25392597a89d5744658f837d204e16c63e", size = 219288, upload-time = "2025-12-28T15:40:54.262Z" }, + { url = "https://files.pythonhosted.org/packages/d0/0a/853a76e03b0f7c4375e2ca025df45c918beb367f3e20a0a8e91967f6e96c/coverage-7.13.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e7b8bd70c48ffb28461ebe092c2345536fb18bbbf19d287c8913699735f505c", size = 250786, upload-time = "2025-12-28T15:40:56.059Z" }, + { url = "https://files.pythonhosted.org/packages/ea/b4/694159c15c52b9f7ec7adf49d50e5f8ee71d3e9ef38adb4445d13dd56c20/coverage-7.13.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c223d078112e90dc0e5c4e35b98b9584164bea9fbbd221c0b21c5241f6d51b62", size = 253543, upload-time = "2025-12-28T15:40:57.585Z" }, + { url = "https://files.pythonhosted.org/packages/96/b2/7f1f0437a5c855f87e17cf5d0dc35920b6440ff2b58b1ba9788c059c26c8/coverage-7.13.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:794f7c05af0763b1bbd1b9e6eff0e52ad068be3b12cd96c87de037b01390c968", size = 254635, upload-time = "2025-12-28T15:40:59.443Z" }, + { url = "https://files.pythonhosted.org/packages/e9/d1/73c3fdb8d7d3bddd9473c9c6a2e0682f09fc3dfbcb9c3f36412a7368bcab/coverage-7.13.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0642eae483cc8c2902e4af7298bf886d605e80f26382124cddc3967c2a3df09e", size = 251202, upload-time = "2025-12-28T15:41:01.328Z" }, + { url = "https://files.pythonhosted.org/packages/66/3c/f0edf75dcc152f145d5598329e864bbbe04ab78660fe3e8e395f9fff010f/coverage-7.13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f5e772ed5fef25b3de9f2008fe67b92d46831bd2bc5bdc5dd6bfd06b83b316f", size = 252566, upload-time = "2025-12-28T15:41:03.319Z" }, + { url = "https://files.pythonhosted.org/packages/17/b3/e64206d3c5f7dcbceafd14941345a754d3dbc78a823a6ed526e23b9cdaab/coverage-7.13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:45980ea19277dc0a579e432aef6a504fe098ef3a9032ead15e446eb0f1191aee", size = 250711, upload-time = "2025-12-28T15:41:06.411Z" }, + { url = "https://files.pythonhosted.org/packages/dc/ad/28a3eb970a8ef5b479ee7f0c484a19c34e277479a5b70269dc652b730733/coverage-7.13.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f18eca6028ffa62adbd185a8f1e1dd242f2e68164dba5c2b74a5204850b4cf", size = 250278, upload-time = "2025-12-28T15:41:08.285Z" }, + { url = "https://files.pythonhosted.org/packages/54/e3/c8f0f1a93133e3e1291ca76cbb63565bd4b5c5df63b141f539d747fff348/coverage-7.13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8dca5590fec7a89ed6826fce625595279e586ead52e9e958d3237821fbc750c", size = 252154, upload-time = "2025-12-28T15:41:09.969Z" }, + { url = "https://files.pythonhosted.org/packages/d0/bf/9939c5d6859c380e405b19e736321f1c7d402728792f4c752ad1adcce005/coverage-7.13.1-cp312-cp312-win32.whl", hash = "sha256:ff86d4e85188bba72cfb876df3e11fa243439882c55957184af44a35bd5880b7", size = 221487, upload-time = "2025-12-28T15:41:11.468Z" }, + { url = "https://files.pythonhosted.org/packages/fa/dc/7282856a407c621c2aad74021680a01b23010bb8ebf427cf5eacda2e876f/coverage-7.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:16cc1da46c04fb0fb128b4dc430b78fa2aba8a6c0c9f8eb391fd5103409a6ac6", size = 222299, upload-time = "2025-12-28T15:41:13.386Z" }, + { url = "https://files.pythonhosted.org/packages/10/79/176a11203412c350b3e9578620013af35bcdb79b651eb976f4a4b32044fa/coverage-7.13.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d9bc218650022a768f3775dd7fdac1886437325d8d295d923ebcfef4892ad5c", size = 220941, upload-time = "2025-12-28T15:41:14.975Z" }, + { url = "https://files.pythonhosted.org/packages/cc/48/d9f421cb8da5afaa1a64570d9989e00fb7955e6acddc5a12979f7666ef60/coverage-7.13.1-py3-none-any.whl", hash = "sha256:2016745cb3ba554469d02819d78958b571792bb68e31302610e898f80dd3a573", size = 210722, upload-time = "2025-12-28T15:42:54.901Z" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "cpplint" +version = "2.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/83/47a9e7513ba4d943a9dac2f6752b444377c91880f4f4968799b4f42d89cc/cpplint-2.0.2.tar.gz", hash = "sha256:8a5971e4b5490133e425284f0c566c7ade0b959e61018d2c9af3ff7f357ddc57", size = 373781, upload-time = "2025-04-08T01:22:26.017Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/65/08d3a5039b565231c501b31d1a973d4222e9803c03b2c31a9c08bdec3e30/cpplint-2.0.2-py3-none-any.whl", hash = "sha256:7ec188b5a08e604294ae7e7f88ec3ece2699de857f0533b305620c8cf237cad5", size = 81987, upload-time = "2025-04-08T01:22:24.101Z" }, +] + +[[package]] +name = "crcmod-plus" +version = "2.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/0c/71733bbaf38e9f1eaecfdf7f8e350993f3dcac208a5297c41503ae66e513/crcmod_plus-2.3.1.tar.gz", hash = "sha256:732ffe3c3ce3ef9b272e1827d8fb894590c4d6ff553f2a2b41ae30f4f94b0f5d", size = 22319, upload-time = "2025-10-10T22:14:21.691Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/e0/2dad2e6f0cd4914b4144496d9785780ec820e200816c080df785cfa34da6/crcmod_plus-2.3.1-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:b7e35e0f7d93d7571c2c9c3d6760e456999ea4c1eae5ead6acac247b5a79e469", size = 23279, upload-time = "2025-10-10T22:13:47.281Z" }, + { url = "https://files.pythonhosted.org/packages/66/76/53c0b65b9679b903f98fc54efa32b0e5a19634712a45200c7a80674aa6f5/crcmod_plus-2.3.1-cp311-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6853243120db84677b94b625112116f0ef69cd581741d20de58dce4c34242654", size = 20185, upload-time = "2025-10-10T22:13:48.06Z" }, + { url = "https://files.pythonhosted.org/packages/98/79/2b4dc9bb26394873d7699737124408b5106264ae33053fdec600e9a9fa65/crcmod_plus-2.3.1-cp311-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:17735bc4e944d552ea18c8609fc6d08a5e64ee9b29cc216ba4d623754029cc3a", size = 26999, upload-time = "2025-10-10T22:13:48.854Z" }, + { url = "https://files.pythonhosted.org/packages/bb/e8/f5d66778b5a1bff915807016561a02b5cebf6b3840fb8a2be40bbb0c8575/crcmod_plus-2.3.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8ac755040a2a35f43ab331978c48a9acb4ff64b425f282a296be467a410f00c3", size = 27536, upload-time = "2025-10-10T22:13:49.956Z" }, + { url = "https://files.pythonhosted.org/packages/f3/2c/0113ad30cadad40c22eef08c0f2618f2446dd282f02268fecbcfc9fda3c1/crcmod_plus-2.3.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bdcfb838ca093ca673a3bbb37f62d1e5ec7182e00cc5ee2d00759f9f9f8ab11", size = 27385, upload-time = "2025-10-10T22:13:50.765Z" }, + { url = "https://files.pythonhosted.org/packages/8e/ba/501ef1b02119402cf1a31c01eb2cb8399660bca863c2f4dd3dc060220284/crcmod_plus-2.3.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9166bc3c9b5e7b07b4e6854cac392b4a451b31d58d3950e48c140ab7b5d05394", size = 27135, upload-time = "2025-10-10T22:13:51.889Z" }, + { url = "https://files.pythonhosted.org/packages/49/90/d4556c9db69c83e726c5b88da3d656fdaac7d60c4d27b43cb939bed80069/crcmod_plus-2.3.1-cp311-abi3-win32.whl", hash = "sha256:cb99b694cce5c862560cf332a8b5e793620e28f0de3726995608bbd6f9b6e09a", size = 22384, upload-time = "2025-10-10T22:13:53.016Z" }, + { url = "https://files.pythonhosted.org/packages/4d/7e/57bb97a8c7b4e19900744f58b67dc83bc9c83aaac670deeede9fb3bfab6a/crcmod_plus-2.3.1-cp311-abi3-win_amd64.whl", hash = "sha256:82b0f7e968c430c5a80fe0fc59e75cb54f2e84df2ed0cee5a3ff9cadfbf8a220", size = 22912, upload-time = "2025-10-10T22:13:53.849Z" }, + { url = "https://files.pythonhosted.org/packages/76/66/419ae3991bb68943cb752e2f4d317c555e3f02a298dd498f26113874ee59/crcmod_plus-2.3.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9397324da1be2729f894744d9031a21ed97584c17fb0289e69e0c3c60916fc5f", size = 19880, upload-time = "2025-10-10T22:14:17.269Z" }, + { url = "https://files.pythonhosted.org/packages/18/f0/d10c9b859927b2cdc38eafc33c8b66e4ede02eaa174df4575681dab5a0f1/crcmod_plus-2.3.1-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:073c7a3b832652e66c41c8b8705eaecda704d1cbe850b9fa05fdee36cd50745a", size = 21120, upload-time = "2025-10-10T22:14:18.117Z" }, + { url = "https://files.pythonhosted.org/packages/6c/68/cbd8f1707b37b80f9a0bf643e04747b0196f69cf065b52ed56639afbecef/crcmod_plus-2.3.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e5f4c62553f772ea7ae12d9484801b752622c9c288e49ee7ea34a20b94e4920", size = 21698, upload-time = "2025-10-10T22:14:20.044Z" }, + { url = "https://files.pythonhosted.org/packages/41/1b/4ab1681ecbfc48d7e4641fb178c97374eb475ae4109255bdd832110cbbe2/crcmod_plus-2.3.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:5e80a9860f66f339956f540d86a768f4fe8c8bfcb139811f14be864425c48d64", size = 23289, upload-time = "2025-10-10T22:14:20.875Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "execnet" +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" }, +] + +[[package]] +name = "fonttools" +version = "4.61.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69", size = 3565756, upload-time = "2025-12-12T17:31:24.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/12/bf9f4eaa2fad039356cc627587e30ed008c03f1cebd3034376b5ee8d1d44/fonttools-4.61.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c6604b735bb12fef8e0efd5578c9fb5d3d8532d5001ea13a19cddf295673ee09", size = 2852213, upload-time = "2025-12-12T17:29:46.675Z" }, + { url = "https://files.pythonhosted.org/packages/ac/49/4138d1acb6261499bedde1c07f8c2605d1d8f9d77a151e5507fd3ef084b6/fonttools-4.61.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5ce02f38a754f207f2f06557523cd39a06438ba3aafc0639c477ac409fc64e37", size = 2401689, upload-time = "2025-12-12T17:29:48.769Z" }, + { url = "https://files.pythonhosted.org/packages/e5/fe/e6ce0fe20a40e03aef906af60aa87668696f9e4802fa283627d0b5ed777f/fonttools-4.61.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77efb033d8d7ff233385f30c62c7c79271c8885d5c9657d967ede124671bbdfb", size = 5058809, upload-time = "2025-12-12T17:29:51.701Z" }, + { url = "https://files.pythonhosted.org/packages/79/61/1ca198af22f7dd22c17ab86e9024ed3c06299cfdb08170640e9996d501a0/fonttools-4.61.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:75c1a6dfac6abd407634420c93864a1e274ebc1c7531346d9254c0d8f6ca00f9", size = 5036039, upload-time = "2025-12-12T17:29:53.659Z" }, + { url = "https://files.pythonhosted.org/packages/99/cc/fa1801e408586b5fce4da9f5455af8d770f4fc57391cd5da7256bb364d38/fonttools-4.61.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0de30bfe7745c0d1ffa2b0b7048fb7123ad0d71107e10ee090fa0b16b9452e87", size = 5034714, upload-time = "2025-12-12T17:29:55.592Z" }, + { url = "https://files.pythonhosted.org/packages/bf/aa/b7aeafe65adb1b0a925f8f25725e09f078c635bc22754f3fecb7456955b0/fonttools-4.61.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:58b0ee0ab5b1fc9921eccfe11d1435added19d6494dde14e323f25ad2bc30c56", size = 5158648, upload-time = "2025-12-12T17:29:57.861Z" }, + { url = "https://files.pythonhosted.org/packages/99/f9/08ea7a38663328881384c6e7777bbefc46fd7d282adfd87a7d2b84ec9d50/fonttools-4.61.1-cp311-cp311-win32.whl", hash = "sha256:f79b168428351d11e10c5aeb61a74e1851ec221081299f4cf56036a95431c43a", size = 2280681, upload-time = "2025-12-12T17:29:59.943Z" }, + { url = "https://files.pythonhosted.org/packages/07/ad/37dd1ae5fa6e01612a1fbb954f0927681f282925a86e86198ccd7b15d515/fonttools-4.61.1-cp311-cp311-win_amd64.whl", hash = "sha256:fe2efccb324948a11dd09d22136fe2ac8a97d6c1347cf0b58a911dcd529f66b7", size = 2331951, upload-time = "2025-12-12T17:30:02.254Z" }, + { url = "https://files.pythonhosted.org/packages/6f/16/7decaa24a1bd3a70c607b2e29f0adc6159f36a7e40eaba59846414765fd4/fonttools-4.61.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f3cb4a569029b9f291f88aafc927dd53683757e640081ca8c412781ea144565e", size = 2851593, upload-time = "2025-12-12T17:30:04.225Z" }, + { url = "https://files.pythonhosted.org/packages/94/98/3c4cb97c64713a8cf499b3245c3bf9a2b8fd16a3e375feff2aed78f96259/fonttools-4.61.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41a7170d042e8c0024703ed13b71893519a1a6d6e18e933e3ec7507a2c26a4b2", size = 2400231, upload-time = "2025-12-12T17:30:06.47Z" }, + { url = "https://files.pythonhosted.org/packages/b7/37/82dbef0f6342eb01f54bca073ac1498433d6ce71e50c3c3282b655733b31/fonttools-4.61.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10d88e55330e092940584774ee5e8a6971b01fc2f4d3466a1d6c158230880796", size = 4954103, upload-time = "2025-12-12T17:30:08.432Z" }, + { url = "https://files.pythonhosted.org/packages/6c/44/f3aeac0fa98e7ad527f479e161aca6c3a1e47bb6996b053d45226fe37bf2/fonttools-4.61.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:15acc09befd16a0fb8a8f62bc147e1a82817542d72184acca9ce6e0aeda9fa6d", size = 5004295, upload-time = "2025-12-12T17:30:10.56Z" }, + { url = "https://files.pythonhosted.org/packages/14/e8/7424ced75473983b964d09f6747fa09f054a6d656f60e9ac9324cf40c743/fonttools-4.61.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e6bcdf33aec38d16508ce61fd81838f24c83c90a1d1b8c68982857038673d6b8", size = 4944109, upload-time = "2025-12-12T17:30:12.874Z" }, + { url = "https://files.pythonhosted.org/packages/c8/8b/6391b257fa3d0b553d73e778f953a2f0154292a7a7a085e2374b111e5410/fonttools-4.61.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5fade934607a523614726119164ff621e8c30e8fa1ffffbbd358662056ba69f0", size = 5093598, upload-time = "2025-12-12T17:30:15.79Z" }, + { url = "https://files.pythonhosted.org/packages/d9/71/fd2ea96cdc512d92da5678a1c98c267ddd4d8c5130b76d0f7a80f9a9fde8/fonttools-4.61.1-cp312-cp312-win32.whl", hash = "sha256:75da8f28eff26defba42c52986de97b22106cb8f26515b7c22443ebc9c2d3261", size = 2269060, upload-time = "2025-12-12T17:30:18.058Z" }, + { url = "https://files.pythonhosted.org/packages/80/3b/a3e81b71aed5a688e89dfe0e2694b26b78c7d7f39a5ffd8a7d75f54a12a8/fonttools-4.61.1-cp312-cp312-win_amd64.whl", hash = "sha256:497c31ce314219888c0e2fce5ad9178ca83fe5230b01a5006726cdf3ac9f24d9", size = 2319078, upload-time = "2025-12-12T17:30:22.862Z" }, + { url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371", size = 1148996, upload-time = "2025-12-12T17:31:21.03Z" }, +] + +[[package]] +name = "gcovr" +version = "8.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorlog" }, + { name = "jinja2" }, + { name = "lxml" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/37/b4a87dff166dc0a5002e9d03fcb6ca8eeff048247b011b67f047e31122c9/gcovr-8.6.tar.gz", hash = "sha256:b2e7042abca9321cadbab8a06eb34d19f801b831557b28cdc30a029313de8b9e", size = 199997, upload-time = "2026-01-13T20:04:30.019Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/be/f722c843e7875c7cf92cf0e0c1604cddda55a70278c768c6327a78fdba79/gcovr-8.6-py3-none-any.whl", hash = "sha256:dbf9d87c38042752ad6f530aa8210427e22b526611bb7b7bfed0e81977d1f1ef", size = 254618, upload-time = "2026-01-13T20:04:28.15Z" }, +] + +[[package]] +name = "hypothesis" +version = "6.47.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "sortedcontainers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/45/f2/f77da8271b1abb630cb2090ead2f5aa4acc9639d632e8e68187f52527e4b/hypothesis-6.47.5.tar.gz", hash = "sha256:e0c1e253fc97e7ecdb9e2bbff2cf815d8739e0d1d3d093d67c3af5bb6a7211b0", size = 326641, upload-time = "2022-06-25T20:58:48.926Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/a7/389bbaade2cbbb2534cb2715986041ed01c6d792152c527e71f7f68e93b5/hypothesis-6.47.5-py3-none-any.whl", hash = "sha256:87049b781ee11ec1c7948565b889ab02e428a1e32d427ab4de8fdb3649242d06", size = 387311, upload-time = "2022-06-25T20:58:45.281Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "inputs" +version = "0.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/cd/5f434220920f76eb73d19bb7aab8d857445f40aa642718e6e51e850cd663/inputs-0.5.tar.gz", hash = "sha256:a31d5b96a3525f1232f326be9e7ce8ccaf873c6b1fb84d9f3c9bc3d79b23eae4", size = 33393, upload-time = "2018-10-05T22:38:14.206Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/94/040a0d9c81f018c39bd887b7b825013b024deb0a6c795f9524797e2cd41b/inputs-0.5-py2.py3-none-any.whl", hash = "sha256:13f894564e52134cf1e3862b1811da034875eb1f2b62e6021e3776e9669a96ec", size = 33630, upload-time = "2018-10-05T22:38:28.28Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "kiwisolver" +version = "1.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/ab/c80b0d5a9d8a1a65f4f815f2afff9798b12c3b9f31f1d304dd233dd920e2/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eb14a5da6dc7642b0f3a18f13654847cd8b7a2550e2645a5bda677862b03ba16", size = 124167, upload-time = "2025-08-10T21:25:53.403Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c0/27fe1a68a39cf62472a300e2879ffc13c0538546c359b86f149cc19f6ac3/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39a219e1c81ae3b103643d2aedb90f1ef22650deb266ff12a19e7773f3e5f089", size = 66579, upload-time = "2025-08-10T21:25:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/31/a2/a12a503ac1fd4943c50f9822678e8015a790a13b5490354c68afb8489814/kiwisolver-1.4.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2405a7d98604b87f3fc28b1716783534b1b4b8510d8142adca34ee0bc3c87543", size = 65309, upload-time = "2025-08-10T21:25:55.76Z" }, + { url = "https://files.pythonhosted.org/packages/66/e1/e533435c0be77c3f64040d68d7a657771194a63c279f55573188161e81ca/kiwisolver-1.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dc1ae486f9abcef254b5618dfb4113dd49f94c68e3e027d03cf0143f3f772b61", size = 1435596, upload-time = "2025-08-10T21:25:56.861Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/51b73c7347f9aabdc7215aa79e8b15299097dc2f8e67dee2b095faca9cb0/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a1f570ce4d62d718dce3f179ee78dac3b545ac16c0c04bb363b7607a949c0d1", size = 1246548, upload-time = "2025-08-10T21:25:58.246Z" }, + { url = "https://files.pythonhosted.org/packages/21/aa/72a1c5d1e430294f2d32adb9542719cfb441b5da368d09d268c7757af46c/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb27e7b78d716c591e88e0a09a2139c6577865d7f2e152488c2cc6257f460872", size = 1263618, upload-time = "2025-08-10T21:25:59.857Z" }, + { url = "https://files.pythonhosted.org/packages/a3/af/db1509a9e79dbf4c260ce0cfa3903ea8945f6240e9e59d1e4deb731b1a40/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:15163165efc2f627eb9687ea5f3a28137217d217ac4024893d753f46bce9de26", size = 1317437, upload-time = "2025-08-10T21:26:01.105Z" }, + { url = "https://files.pythonhosted.org/packages/e0/f2/3ea5ee5d52abacdd12013a94130436e19969fa183faa1e7c7fbc89e9a42f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bdee92c56a71d2b24c33a7d4c2856bd6419d017e08caa7802d2963870e315028", size = 2195742, upload-time = "2025-08-10T21:26:02.675Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9b/1efdd3013c2d9a2566aa6a337e9923a00590c516add9a1e89a768a3eb2fc/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:412f287c55a6f54b0650bd9b6dce5aceddb95864a1a90c87af16979d37c89771", size = 2290810, upload-time = "2025-08-10T21:26:04.009Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e5/cfdc36109ae4e67361f9bc5b41323648cb24a01b9ade18784657e022e65f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2c93f00dcba2eea70af2be5f11a830a742fe6b579a1d4e00f47760ef13be247a", size = 2461579, upload-time = "2025-08-10T21:26:05.317Z" }, + { url = "https://files.pythonhosted.org/packages/62/86/b589e5e86c7610842213994cdea5add00960076bef4ae290c5fa68589cac/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f117e1a089d9411663a3207ba874f31be9ac8eaa5b533787024dc07aeb74f464", size = 2268071, upload-time = "2025-08-10T21:26:06.686Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c6/f8df8509fd1eee6c622febe54384a96cfaf4d43bf2ccec7a0cc17e4715c9/kiwisolver-1.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:be6a04e6c79819c9a8c2373317d19a96048e5a3f90bec587787e86a1153883c2", size = 73840, upload-time = "2025-08-10T21:26:07.94Z" }, + { url = "https://files.pythonhosted.org/packages/e2/2d/16e0581daafd147bc11ac53f032a2b45eabac897f42a338d0a13c1e5c436/kiwisolver-1.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:0ae37737256ba2de764ddc12aed4956460277f00c4996d51a197e72f62f5eec7", size = 65159, upload-time = "2025-08-10T21:26:09.048Z" }, + { url = "https://files.pythonhosted.org/packages/86/c9/13573a747838aeb1c76e3267620daa054f4152444d1f3d1a2324b78255b5/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ac5a486ac389dddcc5bef4f365b6ae3ffff2c433324fb38dd35e3fab7c957999", size = 123686, upload-time = "2025-08-10T21:26:10.034Z" }, + { url = "https://files.pythonhosted.org/packages/51/ea/2ecf727927f103ffd1739271ca19c424d0e65ea473fbaeea1c014aea93f6/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2ba92255faa7309d06fe44c3a4a97efe1c8d640c2a79a5ef728b685762a6fd2", size = 66460, upload-time = "2025-08-10T21:26:11.083Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/51f5464373ce2aeb5194508298a508b6f21d3867f499556263c64c621914/kiwisolver-1.4.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a2899935e724dd1074cb568ce7ac0dce28b2cd6ab539c8e001a8578eb106d14", size = 64952, upload-time = "2025-08-10T21:26:12.058Z" }, + { url = "https://files.pythonhosted.org/packages/70/90/6d240beb0f24b74371762873e9b7f499f1e02166a2d9c5801f4dbf8fa12e/kiwisolver-1.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f6008a4919fdbc0b0097089f67a1eb55d950ed7e90ce2cc3e640abadd2757a04", size = 1474756, upload-time = "2025-08-10T21:26:13.096Z" }, + { url = "https://files.pythonhosted.org/packages/12/42/f36816eaf465220f683fb711efdd1bbf7a7005a2473d0e4ed421389bd26c/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67bb8b474b4181770f926f7b7d2f8c0248cbcb78b660fdd41a47054b28d2a752", size = 1276404, upload-time = "2025-08-10T21:26:14.457Z" }, + { url = "https://files.pythonhosted.org/packages/2e/64/bc2de94800adc830c476dce44e9b40fd0809cddeef1fde9fcf0f73da301f/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2327a4a30d3ee07d2fbe2e7933e8a37c591663b96ce42a00bc67461a87d7df77", size = 1294410, upload-time = "2025-08-10T21:26:15.73Z" }, + { url = "https://files.pythonhosted.org/packages/5f/42/2dc82330a70aa8e55b6d395b11018045e58d0bb00834502bf11509f79091/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a08b491ec91b1d5053ac177afe5290adacf1f0f6307d771ccac5de30592d198", size = 1343631, upload-time = "2025-08-10T21:26:17.045Z" }, + { url = "https://files.pythonhosted.org/packages/22/fd/f4c67a6ed1aab149ec5a8a401c323cee7a1cbe364381bb6c9c0d564e0e20/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8fc5c867c22b828001b6a38d2eaeb88160bf5783c6cb4a5e440efc981ce286d", size = 2224963, upload-time = "2025-08-10T21:26:18.737Z" }, + { url = "https://files.pythonhosted.org/packages/45/aa/76720bd4cb3713314677d9ec94dcc21ced3f1baf4830adde5bb9b2430a5f/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3b3115b2581ea35bb6d1f24a4c90af37e5d9b49dcff267eeed14c3893c5b86ab", size = 2321295, upload-time = "2025-08-10T21:26:20.11Z" }, + { url = "https://files.pythonhosted.org/packages/80/19/d3ec0d9ab711242f56ae0dc2fc5d70e298bb4a1f9dfab44c027668c673a1/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858e4c22fb075920b96a291928cb7dea5644e94c0ee4fcd5af7e865655e4ccf2", size = 2487987, upload-time = "2025-08-10T21:26:21.49Z" }, + { url = "https://files.pythonhosted.org/packages/39/e9/61e4813b2c97e86b6fdbd4dd824bf72d28bcd8d4849b8084a357bc0dd64d/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed0fecd28cc62c54b262e3736f8bb2512d8dcfdc2bcf08be5f47f96bf405b145", size = 2291817, upload-time = "2025-08-10T21:26:22.812Z" }, + { url = "https://files.pythonhosted.org/packages/a0/41/85d82b0291db7504da3c2defe35c9a8a5c9803a730f297bd823d11d5fb77/kiwisolver-1.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:f68208a520c3d86ea51acf688a3e3002615a7f0238002cccc17affecc86a8a54", size = 73895, upload-time = "2025-08-10T21:26:24.37Z" }, + { url = "https://files.pythonhosted.org/packages/e2/92/5f3068cf15ee5cb624a0c7596e67e2a0bb2adee33f71c379054a491d07da/kiwisolver-1.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:2c1a4f57df73965f3f14df20b80ee29e6a7930a57d2d9e8491a25f676e197c60", size = 64992, upload-time = "2025-08-10T21:26:25.732Z" }, + { url = "https://files.pythonhosted.org/packages/a3/0f/36d89194b5a32c054ce93e586d4049b6c2c22887b0eb229c61c68afd3078/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:720e05574713db64c356e86732c0f3c5252818d05f9df320f0ad8380641acea5", size = 60104, upload-time = "2025-08-10T21:27:43.287Z" }, + { url = "https://files.pythonhosted.org/packages/52/ba/4ed75f59e4658fd21fe7dde1fee0ac397c678ec3befba3fe6482d987af87/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:17680d737d5335b552994a2008fab4c851bcd7de33094a82067ef3a576ff02fa", size = 58592, upload-time = "2025-08-10T21:27:44.314Z" }, + { url = "https://files.pythonhosted.org/packages/33/01/a8ea7c5ea32a9b45ceeaee051a04c8ed4320f5add3c51bfa20879b765b70/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85b5352f94e490c028926ea567fc569c52ec79ce131dadb968d3853e809518c2", size = 80281, upload-time = "2025-08-10T21:27:45.369Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/dbd2ecdce306f1d07a1aaf324817ee993aab7aee9db47ceac757deabafbe/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:464415881e4801295659462c49461a24fb107c140de781d55518c4b80cb6790f", size = 78009, upload-time = "2025-08-10T21:27:46.376Z" }, + { url = "https://files.pythonhosted.org/packages/da/e9/0d4add7873a73e462aeb45c036a2dead2562b825aa46ba326727b3f31016/kiwisolver-1.4.9-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:fb940820c63a9590d31d88b815e7a3aa5915cad3ce735ab45f0c730b39547de1", size = 73929, upload-time = "2025-08-10T21:27:48.236Z" }, +] + +[[package]] +name = "lefthook" +version = "2.0.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/8f/e90724128f481c637b7e9343b6535622cfa136541959a49f8a3de0d0e7a5/lefthook-2.0.15.tar.gz", hash = "sha256:8a32c9f2d44f0ff0f3e3ab48f9802ca10f1222b491f3f14e03f577ec175b6649", size = 50175274, upload-time = "2026-01-13T10:02:58.76Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/d5/243d967f541d422a7252f92dbcc201cfd588bd404a66935baacc83be49c5/lefthook-2.0.15-py3-none-any.whl", hash = "sha256:54b174520f18a4fa2545ff1e5eae4c4d2515539fb25b8c4fe04b9224a2ff07ee", size = 50416709, upload-time = "2026-01-13T10:02:55.761Z" }, +] + +[[package]] +name = "lxml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/d5/becbe1e2569b474a23f0c672ead8a29ac50b2dc1d5b9de184831bda8d14c/lxml-6.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:13e35cbc684aadf05d8711a5d1b5857c92e5e580efa9a0d2be197199c8def607", size = 8634365, upload-time = "2025-09-22T04:00:45.672Z" }, + { url = "https://files.pythonhosted.org/packages/28/66/1ced58f12e804644426b85d0bb8a4478ca77bc1761455da310505f1a3526/lxml-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b1675e096e17c6fe9c0e8c81434f5736c0739ff9ac6123c87c2d452f48fc938", size = 4650793, upload-time = "2025-09-22T04:00:47.783Z" }, + { url = "https://files.pythonhosted.org/packages/11/84/549098ffea39dfd167e3f174b4ce983d0eed61f9d8d25b7bf2a57c3247fc/lxml-6.0.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac6e5811ae2870953390452e3476694196f98d447573234592d30488147404d", size = 4944362, upload-time = "2025-09-22T04:00:49.845Z" }, + { url = "https://files.pythonhosted.org/packages/ac/bd/f207f16abf9749d2037453d56b643a7471d8fde855a231a12d1e095c4f01/lxml-6.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5aa0fc67ae19d7a64c3fe725dc9a1bb11f80e01f78289d05c6f62545affec438", size = 5083152, upload-time = "2025-09-22T04:00:51.709Z" }, + { url = "https://files.pythonhosted.org/packages/15/ae/bd813e87d8941d52ad5b65071b1affb48da01c4ed3c9c99e40abb266fbff/lxml-6.0.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de496365750cc472b4e7902a485d3f152ecf57bd3ba03ddd5578ed8ceb4c5964", size = 5023539, upload-time = "2025-09-22T04:00:53.593Z" }, + { url = "https://files.pythonhosted.org/packages/02/cd/9bfef16bd1d874fbe0cb51afb00329540f30a3283beb9f0780adbb7eec03/lxml-6.0.2-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:200069a593c5e40b8f6fc0d84d86d970ba43138c3e68619ffa234bc9bb806a4d", size = 5344853, upload-time = "2025-09-22T04:00:55.524Z" }, + { url = "https://files.pythonhosted.org/packages/b8/89/ea8f91594bc5dbb879734d35a6f2b0ad50605d7fb419de2b63d4211765cc/lxml-6.0.2-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d2de809c2ee3b888b59f995625385f74629707c9355e0ff856445cdcae682b7", size = 5225133, upload-time = "2025-09-22T04:00:57.269Z" }, + { url = "https://files.pythonhosted.org/packages/b9/37/9c735274f5dbec726b2db99b98a43950395ba3d4a1043083dba2ad814170/lxml-6.0.2-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:b2c3da8d93cf5db60e8858c17684c47d01fee6405e554fb55018dd85fc23b178", size = 4677944, upload-time = "2025-09-22T04:00:59.052Z" }, + { url = "https://files.pythonhosted.org/packages/20/28/7dfe1ba3475d8bfca3878365075abe002e05d40dfaaeb7ec01b4c587d533/lxml-6.0.2-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:442de7530296ef5e188373a1ea5789a46ce90c4847e597856570439621d9c553", size = 5284535, upload-time = "2025-09-22T04:01:01.335Z" }, + { url = "https://files.pythonhosted.org/packages/e7/cf/5f14bc0de763498fc29510e3532bf2b4b3a1c1d5d0dff2e900c16ba021ef/lxml-6.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2593c77efde7bfea7f6389f1ab249b15ed4aa5bc5cb5131faa3b843c429fbedb", size = 5067343, upload-time = "2025-09-22T04:01:03.13Z" }, + { url = "https://files.pythonhosted.org/packages/1c/b0/bb8275ab5472f32b28cfbbcc6db7c9d092482d3439ca279d8d6fa02f7025/lxml-6.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3e3cb08855967a20f553ff32d147e14329b3ae70ced6edc2f282b94afbc74b2a", size = 4725419, upload-time = "2025-09-22T04:01:05.013Z" }, + { url = "https://files.pythonhosted.org/packages/25/4c/7c222753bc72edca3b99dbadba1b064209bc8ed4ad448af990e60dcce462/lxml-6.0.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ed6c667fcbb8c19c6791bbf40b7268ef8ddf5a96940ba9404b9f9a304832f6c", size = 5275008, upload-time = "2025-09-22T04:01:07.327Z" }, + { url = "https://files.pythonhosted.org/packages/6c/8c/478a0dc6b6ed661451379447cdbec77c05741a75736d97e5b2b729687828/lxml-6.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b8f18914faec94132e5b91e69d76a5c1d7b0c73e2489ea8929c4aaa10b76bbf7", size = 5248906, upload-time = "2025-09-22T04:01:09.452Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d9/5be3a6ab2784cdf9accb0703b65e1b64fcdd9311c9f007630c7db0cfcce1/lxml-6.0.2-cp311-cp311-win32.whl", hash = "sha256:6605c604e6daa9e0d7f0a2137bdc47a2e93b59c60a65466353e37f8272f47c46", size = 3610357, upload-time = "2025-09-22T04:01:11.102Z" }, + { url = "https://files.pythonhosted.org/packages/e2/7d/ca6fb13349b473d5732fb0ee3eec8f6c80fc0688e76b7d79c1008481bf1f/lxml-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e5867f2651016a3afd8dd2c8238baa66f1e2802f44bc17e236f547ace6647078", size = 4036583, upload-time = "2025-09-22T04:01:12.766Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a2/51363b5ecd3eab46563645f3a2c3836a2fc67d01a1b87c5017040f39f567/lxml-6.0.2-cp311-cp311-win_arm64.whl", hash = "sha256:4197fb2534ee05fd3e7afaab5d8bfd6c2e186f65ea7f9cd6a82809c887bd1285", size = 3680591, upload-time = "2025-09-22T04:01:14.874Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c8/8ff2bc6b920c84355146cd1ab7d181bc543b89241cfb1ebee824a7c81457/lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456", size = 8661887, upload-time = "2025-09-22T04:01:17.265Z" }, + { url = "https://files.pythonhosted.org/packages/37/6f/9aae1008083bb501ef63284220ce81638332f9ccbfa53765b2b7502203cf/lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924", size = 4667818, upload-time = "2025-09-22T04:01:19.688Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ca/31fb37f99f37f1536c133476674c10b577e409c0a624384147653e38baf2/lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f", size = 4950807, upload-time = "2025-09-22T04:01:21.487Z" }, + { url = "https://files.pythonhosted.org/packages/da/87/f6cb9442e4bada8aab5ae7e1046264f62fdbeaa6e3f6211b93f4c0dd97f1/lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534", size = 5109179, upload-time = "2025-09-22T04:01:23.32Z" }, + { url = "https://files.pythonhosted.org/packages/c8/20/a7760713e65888db79bbae4f6146a6ae5c04e4a204a3c48896c408cd6ed2/lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564", size = 5023044, upload-time = "2025-09-22T04:01:25.118Z" }, + { url = "https://files.pythonhosted.org/packages/a2/b0/7e64e0460fcb36471899f75831509098f3fd7cd02a3833ac517433cb4f8f/lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f", size = 5359685, upload-time = "2025-09-22T04:01:27.398Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e1/e5df362e9ca4e2f48ed6411bd4b3a0ae737cc842e96877f5bf9428055ab4/lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0", size = 5654127, upload-time = "2025-09-22T04:01:29.629Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d1/232b3309a02d60f11e71857778bfcd4acbdb86c07db8260caf7d008b08f8/lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192", size = 5253958, upload-time = "2025-09-22T04:01:31.535Z" }, + { url = "https://files.pythonhosted.org/packages/35/35/d955a070994725c4f7d80583a96cab9c107c57a125b20bb5f708fe941011/lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0", size = 4711541, upload-time = "2025-09-22T04:01:33.801Z" }, + { url = "https://files.pythonhosted.org/packages/1e/be/667d17363b38a78c4bd63cfd4b4632029fd68d2c2dc81f25ce9eb5224dd5/lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092", size = 5267426, upload-time = "2025-09-22T04:01:35.639Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/62c70aa4a1c26569bc958c9ca86af2bb4e1f614e8c04fb2989833874f7ae/lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f", size = 5064917, upload-time = "2025-09-22T04:01:37.448Z" }, + { url = "https://files.pythonhosted.org/packages/bd/55/6ceddaca353ebd0f1908ef712c597f8570cc9c58130dbb89903198e441fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8", size = 4788795, upload-time = "2025-09-22T04:01:39.165Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e8/fd63e15da5e3fd4c2146f8bbb3c14e94ab850589beab88e547b2dbce22e1/lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f", size = 5676759, upload-time = "2025-09-22T04:01:41.506Z" }, + { url = "https://files.pythonhosted.org/packages/76/47/b3ec58dc5c374697f5ba37412cd2728f427d056315d124dd4b61da381877/lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6", size = 5255666, upload-time = "2025-09-22T04:01:43.363Z" }, + { url = "https://files.pythonhosted.org/packages/19/93/03ba725df4c3d72afd9596eef4a37a837ce8e4806010569bedfcd2cb68fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322", size = 5277989, upload-time = "2025-09-22T04:01:45.215Z" }, + { url = "https://files.pythonhosted.org/packages/c6/80/c06de80bfce881d0ad738576f243911fccf992687ae09fd80b734712b39c/lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849", size = 3611456, upload-time = "2025-09-22T04:01:48.243Z" }, + { url = "https://files.pythonhosted.org/packages/f7/d7/0cdfb6c3e30893463fb3d1e52bc5f5f99684a03c29a0b6b605cfae879cd5/lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f", size = 4011793, upload-time = "2025-09-22T04:01:50.042Z" }, + { url = "https://files.pythonhosted.org/packages/ea/7b/93c73c67db235931527301ed3785f849c78991e2e34f3fd9a6663ffda4c5/lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6", size = 3672836, upload-time = "2025-09-22T04:01:52.145Z" }, + { url = "https://files.pythonhosted.org/packages/0b/11/29d08bc103a62c0eba8016e7ed5aeebbf1e4312e83b0b1648dd203b0e87d/lxml-6.0.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1c06035eafa8404b5cf475bb37a9f6088b0aca288d4ccc9d69389750d5543700", size = 3949829, upload-time = "2025-09-22T04:04:45.608Z" }, + { url = "https://files.pythonhosted.org/packages/12/b3/52ab9a3b31e5ab8238da241baa19eec44d2ab426532441ee607165aebb52/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c7d13103045de1bdd6fe5d61802565f1a3537d70cd3abf596aa0af62761921ee", size = 4226277, upload-time = "2025-09-22T04:04:47.754Z" }, + { url = "https://files.pythonhosted.org/packages/a0/33/1eaf780c1baad88224611df13b1c2a9dfa460b526cacfe769103ff50d845/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a3c150a95fbe5ac91de323aa756219ef9cf7fde5a3f00e2281e30f33fa5fa4f", size = 4330433, upload-time = "2025-09-22T04:04:49.907Z" }, + { url = "https://files.pythonhosted.org/packages/7a/c1/27428a2ff348e994ab4f8777d3a0ad510b6b92d37718e5887d2da99952a2/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60fa43be34f78bebb27812ed90f1925ec99560b0fa1decdb7d12b84d857d31e9", size = 4272119, upload-time = "2025-09-22T04:04:51.801Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d0/3020fa12bcec4ab62f97aab026d57c2f0cfd480a558758d9ca233bb6a79d/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21c73b476d3cfe836be731225ec3421fa2f048d84f6df6a8e70433dff1376d5a", size = 4417314, upload-time = "2025-09-22T04:04:55.024Z" }, + { url = "https://files.pythonhosted.org/packages/6c/77/d7f491cbc05303ac6801651aabeb262d43f319288c1ea96c66b1d2692ff3/lxml-6.0.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:27220da5be049e936c3aca06f174e8827ca6445a4353a1995584311487fc4e3e", size = 3518768, upload-time = "2025-09-22T04:04:57.097Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.10.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269, upload-time = "2025-12-10T22:56:51.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/86/de7e3a1cdcfc941483af70609edc06b83e7c8a0e0dc9ac325200a3f4d220/matplotlib-3.10.8-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6be43b667360fef5c754dda5d25a32e6307a03c204f3c0fc5468b78fa87b4160", size = 8251215, upload-time = "2025-12-10T22:55:16.175Z" }, + { url = "https://files.pythonhosted.org/packages/fd/14/baad3222f424b19ce6ad243c71de1ad9ec6b2e4eb1e458a48fdc6d120401/matplotlib-3.10.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2b336e2d91a3d7006864e0990c83b216fcdca64b5a6484912902cef87313d78", size = 8139625, upload-time = "2025-12-10T22:55:17.712Z" }, + { url = "https://files.pythonhosted.org/packages/8f/a0/7024215e95d456de5883e6732e708d8187d9753a21d32f8ddb3befc0c445/matplotlib-3.10.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:efb30e3baaea72ce5928e32bab719ab4770099079d66726a62b11b1ef7273be4", size = 8712614, upload-time = "2025-12-10T22:55:20.8Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f4/b8347351da9a5b3f41e26cf547252d861f685c6867d179a7c9d60ad50189/matplotlib-3.10.8-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d56a1efd5bfd61486c8bc968fa18734464556f0fb8e51690f4ac25d85cbbbbc2", size = 9540997, upload-time = "2025-12-10T22:55:23.258Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c0/c7b914e297efe0bc36917bf216b2acb91044b91e930e878ae12981e461e5/matplotlib-3.10.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:238b7ce5717600615c895050239ec955d91f321c209dd110db988500558e70d6", size = 9596825, upload-time = "2025-12-10T22:55:25.217Z" }, + { url = "https://files.pythonhosted.org/packages/6f/d3/a4bbc01c237ab710a1f22b4da72f4ff6d77eb4c7735ea9811a94ae239067/matplotlib-3.10.8-cp311-cp311-win_amd64.whl", hash = "sha256:18821ace09c763ec93aef5eeff087ee493a24051936d7b9ebcad9662f66501f9", size = 8135090, upload-time = "2025-12-10T22:55:27.162Z" }, + { url = "https://files.pythonhosted.org/packages/89/dd/a0b6588f102beab33ca6f5218b31725216577b2a24172f327eaf6417d5c9/matplotlib-3.10.8-cp311-cp311-win_arm64.whl", hash = "sha256:bab485bcf8b1c7d2060b4fcb6fc368a9e6f4cd754c9c2fea281f4be21df394a2", size = 8012377, upload-time = "2025-12-10T22:55:29.185Z" }, + { url = "https://files.pythonhosted.org/packages/9e/67/f997cdcbb514012eb0d10cd2b4b332667997fb5ebe26b8d41d04962fa0e6/matplotlib-3.10.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:64fcc24778ca0404ce0cb7b6b77ae1f4c7231cdd60e6778f999ee05cbd581b9a", size = 8260453, upload-time = "2025-12-10T22:55:30.709Z" }, + { url = "https://files.pythonhosted.org/packages/7e/65/07d5f5c7f7c994f12c768708bd2e17a4f01a2b0f44a1c9eccad872433e2e/matplotlib-3.10.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b9a5ca4ac220a0cdd1ba6bcba3608547117d30468fefce49bb26f55c1a3d5c58", size = 8148321, upload-time = "2025-12-10T22:55:33.265Z" }, + { url = "https://files.pythonhosted.org/packages/3e/f3/c5195b1ae57ef85339fd7285dfb603b22c8b4e79114bae5f4f0fcf688677/matplotlib-3.10.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3ab4aabc72de4ff77b3ec33a6d78a68227bf1123465887f9905ba79184a1cc04", size = 8716944, upload-time = "2025-12-10T22:55:34.922Z" }, + { url = "https://files.pythonhosted.org/packages/00/f9/7638f5cc82ec8a7aa005de48622eecc3ed7c9854b96ba15bd76b7fd27574/matplotlib-3.10.8-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24d50994d8c5816ddc35411e50a86ab05f575e2530c02752e02538122613371f", size = 9550099, upload-time = "2025-12-10T22:55:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/57/61/78cd5920d35b29fd2a0fe894de8adf672ff52939d2e9b43cb83cd5ce1bc7/matplotlib-3.10.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:99eefd13c0dc3b3c1b4d561c1169e65fe47aab7b8158754d7c084088e2329466", size = 9613040, upload-time = "2025-12-10T22:55:38.715Z" }, + { url = "https://files.pythonhosted.org/packages/30/4e/c10f171b6e2f44d9e3a2b96efa38b1677439d79c99357600a62cc1e9594e/matplotlib-3.10.8-cp312-cp312-win_amd64.whl", hash = "sha256:dd80ecb295460a5d9d260df63c43f4afbdd832d725a531f008dad1664f458adf", size = 8142717, upload-time = "2025-12-10T22:55:41.103Z" }, + { url = "https://files.pythonhosted.org/packages/f1/76/934db220026b5fef85f45d51a738b91dea7d70207581063cd9bd8fafcf74/matplotlib-3.10.8-cp312-cp312-win_arm64.whl", hash = "sha256:3c624e43ed56313651bc18a47f838b60d7b8032ed348911c54906b130b20071b", size = 8012751, upload-time = "2025-12-10T22:55:42.684Z" }, + { url = "https://files.pythonhosted.org/packages/04/30/3afaa31c757f34b7725ab9d2ba8b48b5e89c2019c003e7d0ead143aabc5a/matplotlib-3.10.8-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6da7c2ce169267d0d066adcf63758f0604aa6c3eebf67458930f9d9b79ad1db1", size = 8249198, upload-time = "2025-12-10T22:56:45.584Z" }, + { url = "https://files.pythonhosted.org/packages/48/2f/6334aec331f57485a642a7c8be03cb286f29111ae71c46c38b363230063c/matplotlib-3.10.8-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9153c3292705be9f9c64498a8872118540c3f4123d1a1c840172edf262c8be4a", size = 8136817, upload-time = "2025-12-10T22:56:47.339Z" }, + { url = "https://files.pythonhosted.org/packages/73/e4/6d6f14b2a759c622f191b2d67e9075a3f56aaccb3be4bb9bb6890030d0a0/matplotlib-3.10.8-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ae029229a57cd1e8fe542485f27e7ca7b23aa9e8944ddb4985d0bc444f1eca2", size = 8713867, upload-time = "2025-12-10T22:56:48.954Z" }, +] + +[[package]] +name = "natsort" +version = "8.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e2/a9/a0c57aee75f77794adaf35322f8b6404cbd0f89ad45c87197a937764b7d0/natsort-8.4.0.tar.gz", hash = "sha256:45312c4a0e5507593da193dedd04abb1469253b601ecaf63445ad80f0a1ea581", size = 76575, upload-time = "2023-06-20T04:17:19.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/82/7a9d0550484a62c6da82858ee9419f3dd1ccc9aa1c26a1e43da3ecd20b0d/natsort-8.4.0-py3-none-any.whl", hash = "sha256:4732914fb471f56b5cce04d7bae6f164a592c7712e1c85f9ef585e197299521c", size = 38268, upload-time = "2023-06-20T04:17:17.522Z" }, +] + +[[package]] +name = "numpy" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/62/ae72ff66c0f1fd959925b4c11f8c2dea61f47f6acaea75a08512cdfe3fed/numpy-2.4.1.tar.gz", hash = "sha256:a1ceafc5042451a858231588a104093474c6a5c57dcc724841f5c888d237d690", size = 20721320, upload-time = "2026-01-10T06:44:59.619Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/34/2b1bc18424f3ad9af577f6ce23600319968a70575bd7db31ce66731bbef9/numpy-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0cce2a669e3c8ba02ee563c7835f92c153cf02edff1ae05e1823f1dde21b16a5", size = 16944563, upload-time = "2026-01-10T06:42:14.615Z" }, + { url = "https://files.pythonhosted.org/packages/2c/57/26e5f97d075aef3794045a6ca9eada6a4ed70eb9a40e7a4a93f9ac80d704/numpy-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:899d2c18024984814ac7e83f8f49d8e8180e2fbe1b2e252f2e7f1d06bea92425", size = 12645658, upload-time = "2026-01-10T06:42:17.298Z" }, + { url = "https://files.pythonhosted.org/packages/8e/ba/80fc0b1e3cb2fd5c6143f00f42eb67762aa043eaa05ca924ecc3222a7849/numpy-2.4.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:09aa8a87e45b55a1c2c205d42e2808849ece5c484b2aab11fecabec3841cafba", size = 5474132, upload-time = "2026-01-10T06:42:19.637Z" }, + { url = "https://files.pythonhosted.org/packages/40/ae/0a5b9a397f0e865ec171187c78d9b57e5588afc439a04ba9cab1ebb2c945/numpy-2.4.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:edee228f76ee2dab4579fad6f51f6a305de09d444280109e0f75df247ff21501", size = 6804159, upload-time = "2026-01-10T06:42:21.44Z" }, + { url = "https://files.pythonhosted.org/packages/86/9c/841c15e691c7085caa6fd162f063eff494099c8327aeccd509d1ab1e36ab/numpy-2.4.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a92f227dbcdc9e4c3e193add1a189a9909947d4f8504c576f4a732fd0b54240a", size = 14708058, upload-time = "2026-01-10T06:42:23.546Z" }, + { url = "https://files.pythonhosted.org/packages/5d/9d/7862db06743f489e6a502a3b93136d73aea27d97b2cf91504f70a27501d6/numpy-2.4.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:538bf4ec353709c765ff75ae616c34d3c3dca1a68312727e8f2676ea644f8509", size = 16651501, upload-time = "2026-01-10T06:42:25.909Z" }, + { url = "https://files.pythonhosted.org/packages/a6/9c/6fc34ebcbd4015c6e5f0c0ce38264010ce8a546cb6beacb457b84a75dfc8/numpy-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ac08c63cb7779b85e9d5318e6c3518b424bc1f364ac4cb2c6136f12e5ff2dccc", size = 16492627, upload-time = "2026-01-10T06:42:28.938Z" }, + { url = "https://files.pythonhosted.org/packages/aa/63/2494a8597502dacda439f61b3c0db4da59928150e62be0e99395c3ad23c5/numpy-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f9c360ecef085e5841c539a9a12b883dff005fbd7ce46722f5e9cef52634d82", size = 18585052, upload-time = "2026-01-10T06:42:31.312Z" }, + { url = "https://files.pythonhosted.org/packages/6a/93/098e1162ae7522fc9b618d6272b77404c4656c72432ecee3abc029aa3de0/numpy-2.4.1-cp311-cp311-win32.whl", hash = "sha256:0f118ce6b972080ba0758c6087c3617b5ba243d806268623dc34216d69099ba0", size = 6236575, upload-time = "2026-01-10T06:42:33.872Z" }, + { url = "https://files.pythonhosted.org/packages/8c/de/f5e79650d23d9e12f38a7bc6b03ea0835b9575494f8ec94c11c6e773b1b1/numpy-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:18e14c4d09d55eef39a6ab5b08406e84bc6869c1e34eef45564804f90b7e0574", size = 12604479, upload-time = "2026-01-10T06:42:35.778Z" }, + { url = "https://files.pythonhosted.org/packages/dd/65/e1097a7047cff12ce3369bd003811516b20ba1078dbdec135e1cd7c16c56/numpy-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:6461de5113088b399d655d45c3897fa188766415d0f568f175ab071c8873bd73", size = 10578325, upload-time = "2026-01-10T06:42:38.518Z" }, + { url = "https://files.pythonhosted.org/packages/78/7f/ec53e32bf10c813604edf07a3682616bd931d026fcde7b6d13195dfb684a/numpy-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d3703409aac693fa82c0aee023a1ae06a6e9d065dba10f5e8e80f642f1e9d0a2", size = 16656888, upload-time = "2026-01-10T06:42:40.913Z" }, + { url = "https://files.pythonhosted.org/packages/b8/e0/1f9585d7dae8f14864e948fd7fa86c6cb72dee2676ca2748e63b1c5acfe0/numpy-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7211b95ca365519d3596a1d8688a95874cc94219d417504d9ecb2df99fa7bfa8", size = 12373956, upload-time = "2026-01-10T06:42:43.091Z" }, + { url = "https://files.pythonhosted.org/packages/8e/43/9762e88909ff2326f5e7536fa8cb3c49fb03a7d92705f23e6e7f553d9cb3/numpy-2.4.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5adf01965456a664fc727ed69cc71848f28d063217c63e1a0e200a118d5eec9a", size = 5202567, upload-time = "2026-01-10T06:42:45.107Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ee/34b7930eb61e79feb4478800a4b95b46566969d837546aa7c034c742ef98/numpy-2.4.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:26f0bcd9c79a00e339565b303badc74d3ea2bd6d52191eeca5f95936cad107d0", size = 6549459, upload-time = "2026-01-10T06:42:48.152Z" }, + { url = "https://files.pythonhosted.org/packages/79/e3/5f115fae982565771be994867c89bcd8d7208dbfe9469185497d70de5ddf/numpy-2.4.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0093e85df2960d7e4049664b26afc58b03236e967fb942354deef3208857a04c", size = 14404859, upload-time = "2026-01-10T06:42:49.947Z" }, + { url = "https://files.pythonhosted.org/packages/d9/7d/9c8a781c88933725445a859cac5d01b5871588a15969ee6aeb618ba99eee/numpy-2.4.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ad270f438cbdd402c364980317fb6b117d9ec5e226fff5b4148dd9aa9fc6e02", size = 16371419, upload-time = "2026-01-10T06:42:52.409Z" }, + { url = "https://files.pythonhosted.org/packages/a6/d2/8aa084818554543f17cf4162c42f162acbd3bb42688aefdba6628a859f77/numpy-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:297c72b1b98100c2e8f873d5d35fb551fce7040ade83d67dd51d38c8d42a2162", size = 16182131, upload-time = "2026-01-10T06:42:54.694Z" }, + { url = "https://files.pythonhosted.org/packages/60/db/0425216684297c58a8df35f3284ef56ec4a043e6d283f8a59c53562caf1b/numpy-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf6470d91d34bf669f61d515499859fa7a4c2f7c36434afb70e82df7217933f9", size = 18295342, upload-time = "2026-01-10T06:42:56.991Z" }, + { url = "https://files.pythonhosted.org/packages/31/4c/14cb9d86240bd8c386c881bafbe43f001284b7cce3bc01623ac9475da163/numpy-2.4.1-cp312-cp312-win32.whl", hash = "sha256:b6bcf39112e956594b3331316d90c90c90fb961e39696bda97b89462f5f3943f", size = 5959015, upload-time = "2026-01-10T06:42:59.631Z" }, + { url = "https://files.pythonhosted.org/packages/51/cf/52a703dbeb0c65807540d29699fef5fda073434ff61846a564d5c296420f/numpy-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:e1a27bb1b2dee45a2a53f5ca6ff2d1a7f135287883a1689e930d44d1ff296c87", size = 12310730, upload-time = "2026-01-10T06:43:01.627Z" }, + { url = "https://files.pythonhosted.org/packages/69/80/a828b2d0ade5e74a9fe0f4e0a17c30fdc26232ad2bc8c9f8b3197cf7cf18/numpy-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:0e6e8f9d9ecf95399982019c01223dc130542960a12edfa8edd1122dfa66a8a8", size = 10312166, upload-time = "2026-01-10T06:43:03.673Z" }, + { url = "https://files.pythonhosted.org/packages/1e/48/d86f97919e79314a1cdee4c832178763e6e98e623e123d0bada19e92c15a/numpy-2.4.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8ad35f20be147a204e28b6a0575fbf3540c5e5f802634d4258d55b1ff5facce1", size = 16822202, upload-time = "2026-01-10T06:44:43.738Z" }, + { url = "https://files.pythonhosted.org/packages/51/e9/1e62a7f77e0f37dcfb0ad6a9744e65df00242b6ea37dfafb55debcbf5b55/numpy-2.4.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:8097529164c0f3e32bb89412a0905d9100bf434d9692d9fc275e18dcf53c9344", size = 12569985, upload-time = "2026-01-10T06:44:45.945Z" }, + { url = "https://files.pythonhosted.org/packages/c7/7e/914d54f0c801342306fdcdce3e994a56476f1b818c46c47fc21ae968088c/numpy-2.4.1-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:ea66d2b41ca4a1630aae5507ee0a71647d3124d1741980138aa8f28f44dac36e", size = 5398484, upload-time = "2026-01-10T06:44:48.012Z" }, + { url = "https://files.pythonhosted.org/packages/1c/d8/9570b68584e293a33474e7b5a77ca404f1dcc655e40050a600dee81d27fb/numpy-2.4.1-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:d3f8f0df9f4b8be57b3bf74a1d087fec68f927a2fab68231fdb442bf2c12e426", size = 6713216, upload-time = "2026-01-10T06:44:49.725Z" }, + { url = "https://files.pythonhosted.org/packages/33/9b/9dd6e2db8d49eb24f86acaaa5258e5f4c8ed38209a4ee9de2d1a0ca25045/numpy-2.4.1-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2023ef86243690c2791fd6353e5b4848eedaa88ca8a2d129f462049f6d484696", size = 14538937, upload-time = "2026-01-10T06:44:51.498Z" }, + { url = "https://files.pythonhosted.org/packages/53/87/d5bd995b0f798a37105b876350d346eea5838bd8f77ea3d7a48392f3812b/numpy-2.4.1-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8361ea4220d763e54cff2fbe7d8c93526b744f7cd9ddab47afeff7e14e8503be", size = 16479830, upload-time = "2026-01-10T06:44:53.931Z" }, + { url = "https://files.pythonhosted.org/packages/5b/c7/b801bf98514b6ae6475e941ac05c58e6411dd863ea92916bfd6d510b08c1/numpy-2.4.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:4f1b68ff47680c2925f8063402a693ede215f0257f02596b1318ecdfb1d79e33", size = 12492579, upload-time = "2026-01-10T06:44:57.094Z" }, +] + +[[package]] +name = "opendbc" +version = "0.2.1" +source = { editable = "." } +dependencies = [ + { name = "crcmod-plus" }, + { name = "numpy" }, + { name = "pycapnp" }, + { name = "pycryptodome" }, + { name = "scons" }, + { name = "tqdm" }, +] + +[package.optional-dependencies] +docs = [ + { name = "jinja2" }, + { name = "natsort" }, +] +examples = [ + { name = "inputs" }, + { name = "matplotlib" }, +] +testing = [ + { name = "cffi" }, + { name = "codespell" }, + { name = "comma-car-segments" }, + { name = "cpplint" }, + { name = "gcovr" }, + { name = "hypothesis" }, + { name = "lefthook" }, + { name = "parameterized" }, + { name = "pytest" }, + { name = "pytest-coverage" }, + { name = "pytest-mock" }, + { name = "pytest-randomly" }, + { name = "pytest-subtests" }, + { name = "pytest-xdist" }, + { name = "ruff" }, + { name = "ty" }, + { name = "zstandard" }, +] + +[package.metadata] +requires-dist = [ + { name = "cffi", marker = "extra == 'testing'" }, + { name = "codespell", marker = "extra == 'testing'" }, + { name = "comma-car-segments", marker = "extra == 'testing'", url = "https://huggingface.co/datasets/commaai/commaCarSegments/resolve/main/dist/comma_car_segments-0.1.0-py3-none-any.whl" }, + { name = "cpplint", marker = "extra == 'testing'" }, + { name = "crcmod-plus" }, + { name = "gcovr", marker = "extra == 'testing'" }, + { name = "hypothesis", marker = "extra == 'testing'", specifier = "==6.47.*" }, + { name = "inputs", marker = "extra == 'examples'" }, + { name = "jinja2", marker = "extra == 'docs'" }, + { name = "lefthook", marker = "extra == 'testing'" }, + { name = "matplotlib", marker = "extra == 'examples'" }, + { name = "natsort", marker = "extra == 'docs'" }, + { name = "numpy" }, + { name = "parameterized", marker = "extra == 'testing'", specifier = ">=0.8,<0.9" }, + { name = "pycapnp", specifier = "==2.1.0" }, + { name = "pycryptodome" }, + { name = "pytest", marker = "extra == 'testing'", specifier = "==8.4.2" }, + { name = "pytest-coverage", marker = "extra == 'testing'" }, + { name = "pytest-mock", marker = "extra == 'testing'" }, + { name = "pytest-randomly", marker = "extra == 'testing'" }, + { name = "pytest-subtests", marker = "extra == 'testing'" }, + { name = "pytest-xdist", marker = "extra == 'testing'", git = "https://github.com/sshane/pytest-xdist?rev=2b4372bd62699fb412c4fe2f95bf9f01bd2018da" }, + { name = "ruff", marker = "extra == 'testing'" }, + { name = "scons" }, + { name = "tqdm" }, + { name = "ty", marker = "extra == 'testing'" }, + { name = "zstandard", marker = "extra == 'testing'" }, +] +provides-extras = ["testing", "docs", "examples"] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "parameterized" +version = "0.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/23/2288f308d238b4f261c039cafcd650435d624de97c6ffc903f06ea8af50f/parameterized-0.8.1.tar.gz", hash = "sha256:41bbff37d6186430f77f900d777e5bb6a24928a1c46fb1de692f8b52b8833b5c", size = 23936, upload-time = "2021-01-09T20:35:18.235Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/13/fe468c8c7400a8eca204e6e160a29bf7dcd45a76e20f1c030f3eaa690d93/parameterized-0.8.1-py2.py3-none-any.whl", hash = "sha256:9cbb0b69a03e8695d68b3399a8a5825200976536fe1cb79db60ed6a4c8c9efe9", size = 26354, upload-time = "2021-01-09T20:35:16.307Z" }, +] + +[[package]] +name = "pillow" +version = "12.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/02/d52c733a2452ef1ffcc123b68e6606d07276b0e358db70eabad7e40042b7/pillow-12.1.0.tar.gz", hash = "sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9", size = 46977283, upload-time = "2026-01-02T09:13:29.892Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/c4/bf8328039de6cc22182c3ef007a2abfbbdab153661c0a9aa78af8d706391/pillow-12.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:a83e0850cb8f5ac975291ebfc4170ba481f41a28065277f7f735c202cd8e0af3", size = 5304057, upload-time = "2026-01-02T09:10:46.627Z" }, + { url = "https://files.pythonhosted.org/packages/43/06/7264c0597e676104cc22ca73ee48f752767cd4b1fe084662620b17e10120/pillow-12.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b6e53e82ec2db0717eabb276aa56cf4e500c9a7cec2c2e189b55c24f65a3e8c0", size = 4657811, upload-time = "2026-01-02T09:10:49.548Z" }, + { url = "https://files.pythonhosted.org/packages/72/64/f9189e44474610daf83da31145fa56710b627b5c4c0b9c235e34058f6b31/pillow-12.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:40a8e3b9e8773876d6e30daed22f016509e3987bab61b3b7fe309d7019a87451", size = 6232243, upload-time = "2026-01-02T09:10:51.62Z" }, + { url = "https://files.pythonhosted.org/packages/ef/30/0df458009be6a4caca4ca2c52975e6275c387d4e5c95544e34138b41dc86/pillow-12.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:800429ac32c9b72909c671aaf17ecd13110f823ddb7db4dfef412a5587c2c24e", size = 8037872, upload-time = "2026-01-02T09:10:53.446Z" }, + { url = "https://files.pythonhosted.org/packages/e4/86/95845d4eda4f4f9557e25381d70876aa213560243ac1a6d619c46caaedd9/pillow-12.1.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b022eaaf709541b391ee069f0022ee5b36c709df71986e3f7be312e46f42c84", size = 6345398, upload-time = "2026-01-02T09:10:55.426Z" }, + { url = "https://files.pythonhosted.org/packages/5c/1f/8e66ab9be3aaf1435bc03edd1ebdf58ffcd17f7349c1d970cafe87af27d9/pillow-12.1.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f345e7bc9d7f368887c712aa5054558bad44d2a301ddf9248599f4161abc7c0", size = 7034667, upload-time = "2026-01-02T09:10:57.11Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f6/683b83cb9b1db1fb52b87951b1c0b99bdcfceaa75febf11406c19f82cb5e/pillow-12.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d70347c8a5b7ccd803ec0c85c8709f036e6348f1e6a5bf048ecd9c64d3550b8b", size = 6458743, upload-time = "2026-01-02T09:10:59.331Z" }, + { url = "https://files.pythonhosted.org/packages/9a/7d/de833d63622538c1d58ce5395e7c6cb7e7dce80decdd8bde4a484e095d9f/pillow-12.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1fcc52d86ce7a34fd17cb04e87cfdb164648a3662a6f20565910a99653d66c18", size = 7159342, upload-time = "2026-01-02T09:11:01.82Z" }, + { url = "https://files.pythonhosted.org/packages/8c/40/50d86571c9e5868c42b81fe7da0c76ca26373f3b95a8dd675425f4a92ec1/pillow-12.1.0-cp311-cp311-win32.whl", hash = "sha256:3ffaa2f0659e2f740473bcf03c702c39a8d4b2b7ffc629052028764324842c64", size = 6328655, upload-time = "2026-01-02T09:11:04.556Z" }, + { url = "https://files.pythonhosted.org/packages/6c/af/b1d7e301c4cd26cd45d4af884d9ee9b6fab893b0ad2450d4746d74a6968c/pillow-12.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:806f3987ffe10e867bab0ddad45df1148a2b98221798457fa097ad85d6e8bc75", size = 7031469, upload-time = "2026-01-02T09:11:06.538Z" }, + { url = "https://files.pythonhosted.org/packages/48/36/d5716586d887fb2a810a4a61518a327a1e21c8b7134c89283af272efe84b/pillow-12.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:9f5fefaca968e700ad1a4a9de98bf0869a94e397fe3524c4c9450c1445252304", size = 2452515, upload-time = "2026-01-02T09:11:08.226Z" }, + { url = "https://files.pythonhosted.org/packages/20/31/dc53fe21a2f2996e1b7d92bf671cdb157079385183ef7c1ae08b485db510/pillow-12.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a332ac4ccb84b6dde65dbace8431f3af08874bf9770719d32a635c4ef411b18b", size = 5262642, upload-time = "2026-01-02T09:11:10.138Z" }, + { url = "https://files.pythonhosted.org/packages/ab/c1/10e45ac9cc79419cedf5121b42dcca5a50ad2b601fa080f58c22fb27626e/pillow-12.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:907bfa8a9cb790748a9aa4513e37c88c59660da3bcfffbd24a7d9e6abf224551", size = 4657464, upload-time = "2026-01-02T09:11:12.319Z" }, + { url = "https://files.pythonhosted.org/packages/ad/26/7b82c0ab7ef40ebede7a97c72d473bda5950f609f8e0c77b04af574a0ddb/pillow-12.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:efdc140e7b63b8f739d09a99033aa430accce485ff78e6d311973a67b6bf3208", size = 6234878, upload-time = "2026-01-02T09:11:14.096Z" }, + { url = "https://files.pythonhosted.org/packages/76/25/27abc9792615b5e886ca9411ba6637b675f1b77af3104710ac7353fe5605/pillow-12.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bef9768cab184e7ae6e559c032e95ba8d07b3023c289f79a2bd36e8bf85605a5", size = 8044868, upload-time = "2026-01-02T09:11:15.903Z" }, + { url = "https://files.pythonhosted.org/packages/0a/ea/f200a4c36d836100e7bc738fc48cd963d3ba6372ebc8298a889e0cfc3359/pillow-12.1.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:742aea052cf5ab5034a53c3846165bc3ce88d7c38e954120db0ab867ca242661", size = 6349468, upload-time = "2026-01-02T09:11:17.631Z" }, + { url = "https://files.pythonhosted.org/packages/11/8f/48d0b77ab2200374c66d344459b8958c86693be99526450e7aee714e03e4/pillow-12.1.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6dfc2af5b082b635af6e08e0d1f9f1c4e04d17d4e2ca0ef96131e85eda6eb17", size = 7041518, upload-time = "2026-01-02T09:11:19.389Z" }, + { url = "https://files.pythonhosted.org/packages/1d/23/c281182eb986b5d31f0a76d2a2c8cd41722d6fb8ed07521e802f9bba52de/pillow-12.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:609e89d9f90b581c8d16358c9087df76024cf058fa693dd3e1e1620823f39670", size = 6462829, upload-time = "2026-01-02T09:11:21.28Z" }, + { url = "https://files.pythonhosted.org/packages/25/ef/7018273e0faac099d7b00982abdcc39142ae6f3bd9ceb06de09779c4a9d6/pillow-12.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:43b4899cfd091a9693a1278c4982f3e50f7fb7cff5153b05174b4afc9593b616", size = 7166756, upload-time = "2026-01-02T09:11:23.559Z" }, + { url = "https://files.pythonhosted.org/packages/8f/c8/993d4b7ab2e341fe02ceef9576afcf5830cdec640be2ac5bee1820d693d4/pillow-12.1.0-cp312-cp312-win32.whl", hash = "sha256:aa0c9cc0b82b14766a99fbe6084409972266e82f459821cd26997a488a7261a7", size = 6328770, upload-time = "2026-01-02T09:11:25.661Z" }, + { url = "https://files.pythonhosted.org/packages/a7/87/90b358775a3f02765d87655237229ba64a997b87efa8ccaca7dd3e36e7a7/pillow-12.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:d70534cea9e7966169ad29a903b99fc507e932069a881d0965a1a84bb57f6c6d", size = 7033406, upload-time = "2026-01-02T09:11:27.474Z" }, + { url = "https://files.pythonhosted.org/packages/5d/cf/881b457eccacac9e5b2ddd97d5071fb6d668307c57cbf4e3b5278e06e536/pillow-12.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:65b80c1ee7e14a87d6a068dd3b0aea268ffcabfe0498d38661b00c5b4b22e74c", size = 2452612, upload-time = "2026-01-02T09:11:29.309Z" }, + { url = "https://files.pythonhosted.org/packages/8b/bc/224b1d98cffd7164b14707c91aac83c07b047fbd8f58eba4066a3e53746a/pillow-12.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ca94b6aac0d7af2a10ba08c0f888b3d5114439b6b3ef39968378723622fed377", size = 5228605, upload-time = "2026-01-02T09:13:14.084Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ca/49ca7769c4550107de049ed85208240ba0f330b3f2e316f24534795702ce/pillow-12.1.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:351889afef0f485b84078ea40fe33727a0492b9af3904661b0abbafee0355b72", size = 4622245, upload-time = "2026-01-02T09:13:15.964Z" }, + { url = "https://files.pythonhosted.org/packages/73/48/fac807ce82e5955bcc2718642b94b1bd22a82a6d452aea31cbb678cddf12/pillow-12.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb0984b30e973f7e2884362b7d23d0a348c7143ee559f38ef3eaab640144204c", size = 5247593, upload-time = "2026-01-02T09:13:17.913Z" }, + { url = "https://files.pythonhosted.org/packages/d2/95/3e0742fe358c4664aed4fd05d5f5373dcdad0b27af52aa0972568541e3f4/pillow-12.1.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:84cabc7095dd535ca934d57e9ce2a72ffd216e435a84acb06b2277b1de2689bd", size = 6989008, upload-time = "2026-01-02T09:13:20.083Z" }, + { url = "https://files.pythonhosted.org/packages/5a/74/fe2ac378e4e202e56d50540d92e1ef4ff34ed687f3c60f6a121bcf99437e/pillow-12.1.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53d8b764726d3af1a138dd353116f774e3862ec7e3794e0c8781e30db0f35dfc", size = 5313824, upload-time = "2026-01-02T09:13:22.405Z" }, + { url = "https://files.pythonhosted.org/packages/f3/77/2a60dee1adee4e2655ac328dd05c02a955c1cd683b9f1b82ec3feb44727c/pillow-12.1.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5da841d81b1a05ef940a8567da92decaa15bc4d7dedb540a8c219ad83d91808a", size = 5963278, upload-time = "2026-01-02T09:13:24.706Z" }, + { url = "https://files.pythonhosted.org/packages/2d/71/64e9b1c7f04ae0027f788a248e6297d7fcc29571371fe7d45495a78172c0/pillow-12.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:75af0b4c229ac519b155028fa1be632d812a519abba9b46b20e50c6caa184f19", size = 7029809, upload-time = "2026-01-02T09:13:26.541Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pycapnp" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/86/a57e3c92acd3e1d2fc3dcad683ada191f722e4ac927e1a384b228ec2780a/pycapnp-2.1.0.tar.gz", hash = "sha256:69cc3d861fee1c9b26c73ad2e8a5d51e76ad87e4ff9be33a4fd2fc72f5846aec", size = 689734, upload-time = "2025-09-05T03:50:40.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/7c/934750a0ca77431a22e68e11521dcc6b801bea3ff37331d6a519e5ad142e/pycapnp-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:efacc439ec287d9e8a0ebf01a515404eff795659401e65ba6f1819c7b24f4380", size = 1628855, upload-time = "2025-09-05T03:48:32.317Z" }, + { url = "https://files.pythonhosted.org/packages/2e/a2/fd2c10b3f2e5010c747aa946b27fe09f665d65d5dc2afdd31838a3ef2f5d/pycapnp-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f3d8af535a8b44dfd71731a191386c6b821b8a4915806948893d18c79f547a8e", size = 1496942, upload-time = "2025-09-05T03:48:34.905Z" }, + { url = "https://files.pythonhosted.org/packages/0b/8a/42bd0e4c094ef534ac6890d34adae580cbbf5b0497fc0a6340bea833a617/pycapnp-2.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:117d1d5ebfc08cc189aca4f771b34fedc1291a3f9417167bd2d9b2a4e607e640", size = 5200170, upload-time = "2025-09-05T03:48:36.502Z" }, + { url = "https://files.pythonhosted.org/packages/af/30/2e92268383135082191c3dea4a9ad184d20b7fb2dda1477fd6ee520fd88e/pycapnp-2.1.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:d881ccc69e381863a88c7b6c7092a6baecb6dfc8c5558d66bc967c7f778fe7bc", size = 5684026, upload-time = "2025-09-05T03:48:38.063Z" }, + { url = "https://files.pythonhosted.org/packages/46/9c/bca1cbd7711c9c0f0f62ca95a49835369a61c4f6527a6900c8982045bf2f/pycapnp-2.1.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:8a4ea330e38ba83f6f03fbdc1f58642eb53e6f6f66734a426fa592dc988d70e9", size = 5709307, upload-time = "2025-09-05T03:48:40.127Z" }, + { url = "https://files.pythonhosted.org/packages/2d/29/cd14676d992c7b166baa7e022b369c15240d408b202410d105b23b25f737/pycapnp-2.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:fb2563de4619d359820de9d47b4704e4f7eda193ffc4a56e39cdcd2c8301c336", size = 5386505, upload-time = "2025-09-05T03:48:41.785Z" }, + { url = "https://files.pythonhosted.org/packages/ae/dd/2fc57cebe9be7e4cd3d6aec0b9c8a0db9772c1b17c37cfe4f04c050422cf/pycapnp-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5265d1ae34f9c089fa6983f6c1be404ce480c82b927017290bd703328fa3f5df", size = 6095180, upload-time = "2025-09-05T03:48:43.795Z" }, + { url = "https://files.pythonhosted.org/packages/5a/16/da8c1ada7770a532c859df475533eec5a1b2f5e81a269466a2fe670c5747/pycapnp-2.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b0a56370a868f752375a785bfb7e06b55cbe71605972615d1220c380bc452380", size = 6603414, upload-time = "2025-09-05T03:48:45.457Z" }, + { url = "https://files.pythonhosted.org/packages/f0/e6/a36eacaf2da6a5ac9c6565600e559edf95115ff990aa3379aee8dd7ba4fe/pycapnp-2.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5d7403c25275cf4badf6f9d0c07b1cb94fcdd599df81aba9b621c32b3dcefae9", size = 6621440, upload-time = "2025-09-05T03:48:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/81/54/9150c03638cf4ecdf1664867382d0049146c658d6de30f189817c502df1a/pycapnp-2.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dea5d0d250fe4851b42cd380a207d773ebae76a990e542a888a5f1442f4c247e", size = 6354219, upload-time = "2025-09-05T03:48:49.336Z" }, + { url = "https://files.pythonhosted.org/packages/66/3e/e49ba2d74456d53b570c8d30a660c3b29ecfea075d5dd663132ff9049f19/pycapnp-2.1.0-cp311-cp311-win32.whl", hash = "sha256:593844c3cd92937eb5e7cd47ea3a62cde2d49a1fc05dba644f513c68f60f1318", size = 1053647, upload-time = "2025-09-05T03:48:51.108Z" }, + { url = "https://files.pythonhosted.org/packages/53/de/2b61908dc6abf25b17fed6b5a3b42a2226ec09467a3944f1d845ac29ef9b/pycapnp-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac13dd30062bb9985ae9ec4feca106af2b4fdac6468a09c7b74ad754f3921a06", size = 1208911, upload-time = "2025-09-05T03:48:53.219Z" }, + { url = "https://files.pythonhosted.org/packages/74/0e/66b41ba600e5f2523e900b7cc0d2e8496b397a1f2d6a5b7b323ab83418b7/pycapnp-2.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d2ec561bc948d11f64f43bf9601bede5d6a603d105ae311bd5583c7130624a4", size = 1619223, upload-time = "2025-09-05T03:48:54.64Z" }, + { url = "https://files.pythonhosted.org/packages/40/6e/9bcb30180bd40cb0534124ff7f8ba8746a735018d593f608bf40c97821c0/pycapnp-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:132cd97f57f6b6636323ca9b68d389dd90b96e87af38cde31e2b5c5a064f277e", size = 1484321, upload-time = "2025-09-05T03:48:55.85Z" }, + { url = "https://files.pythonhosted.org/packages/14/0a/9ee1c9ecaff499e4fd1df2f0335bc20f666ec6ce5cd80f8ab055007f3c9b/pycapnp-2.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:568e79268ba7c02a71fe558a8aec1ae3c0f0e6aff809ff618a46afe4964957d2", size = 5143502, upload-time = "2025-09-05T03:48:57.733Z" }, + { url = "https://files.pythonhosted.org/packages/4d/50/65837e1416f7a8861ca1e8fe4582a5aef37192d7ef5e2ecfe46880bfdf9c/pycapnp-2.1.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:bcbf6f882d78d368c8e4bb792295392f5c4d71ddffa13a48da27e7bd47b99e37", size = 5508134, upload-time = "2025-09-05T03:48:59.383Z" }, + { url = "https://files.pythonhosted.org/packages/a1/59/46df6db800e77dbc3cc940723fb3fd7bc837327c858edf464a0f904bf547/pycapnp-2.1.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:dc25b96e393410dde25c61c1df3ce644700ef94826c829426d58c2c6b3e2d2f5", size = 5631794, upload-time = "2025-09-05T03:49:03.511Z" }, + { url = "https://files.pythonhosted.org/packages/63/9d/18e978500d5f6bd8d152f4d6919e3cfb83ead8a71c14613bbb54322df8b9/pycapnp-2.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:48938e0436ab1be615fc0a41434119a2065490a6212b9a5e56949e89b0588b76", size = 5369378, upload-time = "2025-09-05T03:49:05.539Z" }, + { url = "https://files.pythonhosted.org/packages/96/dc/726f1917e9996dc29f9fd1cf30674a14546cdbdfa0777e1982b6bd1ad628/pycapnp-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0c20de0f6e0b3fa9fa1df3864cf46051db3511b63bc29514d1092af65f2b82a0", size = 5999140, upload-time = "2025-09-05T03:49:07.341Z" }, + { url = "https://files.pythonhosted.org/packages/fd/3a/3bbc4c5776fc32fbf8a59df5c7c5810efd292b933cd6545eb4b16d896268/pycapnp-2.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:18caca6527862475167c10ea0809531130585aa8a86cc76cd1629eb87ee30637", size = 6454308, upload-time = "2025-09-05T03:49:08.998Z" }, + { url = "https://files.pythonhosted.org/packages/bf/dd/17e2d7808424f10ffddc47329b980488ed83ec716c504791787e593a7a93/pycapnp-2.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9dcc11237697007b66e3bfc500d2ad892bd79672c9b50d61fbf728c6aaf936de", size = 6544212, upload-time = "2025-09-05T03:49:10.675Z" }, + { url = "https://files.pythonhosted.org/packages/6a/5b/68090013128d7853f34c43828dd4dc80a7c8516fd1b56057b134e1e4c2c0/pycapnp-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c151edf78155b6416e7cb31e2e333d302d742ba52bb37d4dbdf71e75cc999d46", size = 6295279, upload-time = "2025-09-05T03:49:12.712Z" }, + { url = "https://files.pythonhosted.org/packages/5b/52/7d85212b4fcf127588888f71d3dbf5558ee7dc302eba760b12b1b325f9a3/pycapnp-2.1.0-cp312-cp312-win32.whl", hash = "sha256:c09b28419321dafafc644d60c57ff8ccaf3c3e686801b6060c612a7a3c580944", size = 1038995, upload-time = "2025-09-05T03:49:14.165Z" }, + { url = "https://files.pythonhosted.org/packages/f2/12/25d283ebf5c28717364647672e7494dc46196ca7a662f5420e4866f45687/pycapnp-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:560cb69cc02b0347e85b0629e4c2f0a316240900aa905392f9df6bab0a359989", size = 1176620, upload-time = "2025-09-05T03:49:15.545Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + +[[package]] +name = "pycryptodome" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" }, + { url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" }, + { url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" }, + { url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" }, + { url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" }, + { url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" }, + { url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" }, + { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/33/c1/1d9de9aeaa1b89b0186e5fe23294ff6517fce1bc69149185577cd31016b2/pyparsing-3.3.1.tar.gz", hash = "sha256:47fad0f17ac1e2cad3de3b458570fbc9b03560aa029ed5e16ee5554da9a2251c", size = 1550512, upload-time = "2025-12-23T03:14:04.391Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/40/2614036cdd416452f5bf98ec037f38a1afb17f327cb8e6b652d4729e0af8/pyparsing-3.3.1-py3-none-any.whl", hash = "sha256:023b5e7e5520ad96642e2c6db4cb683d3970bd640cdf7115049a6e9c3682df82", size = 121793, upload-time = "2025-12-23T03:14:02.103Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + +[[package]] +name = "pytest-cover" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest-cov" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/27/20964101a7cdb260f8d6c4e854659026968321d10c90552b1fe7f6c5f913/pytest-cover-3.0.0.tar.gz", hash = "sha256:5bdb6c1cc3dd75583bb7bc2c57f5e1034a1bfcb79d27c71aceb0b16af981dbf4", size = 3211, upload-time = "2015-08-01T19:20:22.562Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/9b/7b4700c462628e169bd859c6368d596a6aedc87936bde733bead9f875fce/pytest_cover-3.0.0-py2.py3-none-any.whl", hash = "sha256:578249955eb3b5f3991209df6e532bb770b647743b7392d3d97698dc02f39ebb", size = 3769, upload-time = "2015-08-01T19:20:18.534Z" }, +] + +[[package]] +name = "pytest-coverage" +version = "0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest-cover" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/01/81/1d954849aed17b254d1c397eb4447a05eedce612a56b627c071df2ce00c1/pytest-coverage-0.0.tar.gz", hash = "sha256:db6af2cbd7e458c7c9fd2b4207cee75258243c8a81cad31a7ee8cfad5be93c05", size = 873, upload-time = "2015-06-17T21:50:38.956Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/4b/d95b052f87db89a2383233c0754c45f6d3b427b7a4bcb771ac9316a6fae1/pytest_coverage-0.0-py2.py3-none-any.whl", hash = "sha256:dedd084c5e74d8e669355325916dc011539b190355021b037242514dee546368", size = 2013, upload-time = "2015-06-17T22:08:36.771Z" }, +] + +[[package]] +name = "pytest-mock" +version = "3.15.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/14/eb014d26be205d38ad5ad20d9a80f7d201472e08167f0bb4361e251084a9/pytest_mock-3.15.1.tar.gz", hash = "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f", size = 34036, upload-time = "2025-09-16T16:37:27.081Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/cc/06253936f4a7fa2e0f48dfe6d851d9c56df896a9ab09ac019d70b760619c/pytest_mock-3.15.1-py3-none-any.whl", hash = "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d", size = 10095, upload-time = "2025-09-16T16:37:25.734Z" }, +] + +[[package]] +name = "pytest-randomly" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c4/1d/258a4bf1109258c00c35043f40433be5c16647387b6e7cd5582d638c116b/pytest_randomly-4.0.1.tar.gz", hash = "sha256:174e57bb12ac2c26f3578188490bd333f0e80620c3f47340158a86eca0593cd8", size = 14130, upload-time = "2025-09-12T15:23:00.085Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/3e/a4a9227807b56869790aad3e24472a554b585974fe7e551ea350f50897ae/pytest_randomly-4.0.1-py3-none-any.whl", hash = "sha256:e0dfad2fd4f35e07beff1e47c17fbafcf98f9bf4531fd369d9260e2f858bfcb7", size = 8304, upload-time = "2025-09-12T15:22:58.946Z" }, +] + +[[package]] +name = "pytest-subtests" +version = "0.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/d9/20097971a8d315e011e055d512fa120fd6be3bdb8f4b3aa3e3c6bf77bebc/pytest_subtests-0.15.0.tar.gz", hash = "sha256:cb495bde05551b784b8f0b8adfaa27edb4131469a27c339b80fd8d6ba33f887c", size = 18525, upload-time = "2025-10-20T16:26:18.358Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/23/64/bba465299b37448b4c1b84c7a04178399ac22d47b3dc5db1874fe55a2bd3/pytest_subtests-0.15.0-py3-none-any.whl", hash = "sha256:da2d0ce348e1f8d831d5a40d81e3aeac439fec50bd5251cbb7791402696a9493", size = 9185, upload-time = "2025-10-20T16:26:17.239Z" }, +] + +[[package]] +name = "pytest-xdist" +version = "3.7.1.dev24+g2b4372bd6" +source = { git = "https://github.com/sshane/pytest-xdist?rev=2b4372bd62699fb412c4fe2f95bf9f01bd2018da#2b4372bd62699fb412c4fe2f95bf9f01bd2018da" } +dependencies = [ + { name = "execnet" }, + { name = "pytest" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/50/0a/1914efb7903174b381ee2ffeebb4253e729de57f114e63595114c8ca451f/ruff-0.14.13.tar.gz", hash = "sha256:83cd6c0763190784b99650a20fec7633c59f6ebe41c5cc9d45ee42749563ad47", size = 6059504, upload-time = "2026-01-15T20:15:16.918Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/ae/0deefbc65ca74b0ab1fd3917f94dc3b398233346a74b8bbb0a916a1a6bf6/ruff-0.14.13-py3-none-linux_armv6l.whl", hash = "sha256:76f62c62cd37c276cb03a275b198c7c15bd1d60c989f944db08a8c1c2dbec18b", size = 13062418, upload-time = "2026-01-15T20:14:50.779Z" }, + { url = "https://files.pythonhosted.org/packages/47/df/5916604faa530a97a3c154c62a81cb6b735c0cb05d1e26d5ad0f0c8ac48a/ruff-0.14.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:914a8023ece0528d5cc33f5a684f5f38199bbb566a04815c2c211d8f40b5d0ed", size = 13442344, upload-time = "2026-01-15T20:15:07.94Z" }, + { url = "https://files.pythonhosted.org/packages/4c/f3/e0e694dd69163c3a1671e102aa574a50357536f18a33375050334d5cd517/ruff-0.14.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d24899478c35ebfa730597a4a775d430ad0d5631b8647a3ab368c29b7e7bd063", size = 12354720, upload-time = "2026-01-15T20:15:09.854Z" }, + { url = "https://files.pythonhosted.org/packages/c3/e8/67f5fcbbaee25e8fc3b56cc33e9892eca7ffe09f773c8e5907757a7e3bdb/ruff-0.14.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aaf3870f14d925bbaf18b8a2347ee0ae7d95a2e490e4d4aea6813ed15ebc80e", size = 12774493, upload-time = "2026-01-15T20:15:20.908Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ce/d2e9cb510870b52a9565d885c0d7668cc050e30fa2c8ac3fb1fda15c083d/ruff-0.14.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac5b7f63dd3b27cc811850f5ffd8fff845b00ad70e60b043aabf8d6ecc304e09", size = 12815174, upload-time = "2026-01-15T20:15:05.74Z" }, + { url = "https://files.pythonhosted.org/packages/88/00/c38e5da58beebcf4fa32d0ddd993b63dfacefd02ab7922614231330845bf/ruff-0.14.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d2b1097750d90ba82ce4ba676e85230a0ed694178ca5e61aa9b459970b3eb9", size = 13680909, upload-time = "2026-01-15T20:15:14.537Z" }, + { url = "https://files.pythonhosted.org/packages/61/61/cd37c9dd5bd0a3099ba79b2a5899ad417d8f3b04038810b0501a80814fd7/ruff-0.14.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d0bf87705acbbcb8d4c24b2d77fbb73d40210a95c3903b443cd9e30824a5032", size = 15144215, upload-time = "2026-01-15T20:15:22.886Z" }, + { url = "https://files.pythonhosted.org/packages/56/8a/85502d7edbf98c2df7b8876f316c0157359165e16cdf98507c65c8d07d3d/ruff-0.14.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3eb5da8e2c9e9f13431032fdcbe7681de9ceda5835efee3269417c13f1fed5c", size = 14706067, upload-time = "2026-01-15T20:14:48.271Z" }, + { url = "https://files.pythonhosted.org/packages/7e/2f/de0df127feb2ee8c1e54354dc1179b4a23798f0866019528c938ba439aca/ruff-0.14.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:642442b42957093811cd8d2140dfadd19c7417030a7a68cf8d51fcdd5f217427", size = 14133916, upload-time = "2026-01-15T20:14:57.357Z" }, + { url = "https://files.pythonhosted.org/packages/0d/77/9b99686bb9fe07a757c82f6f95e555c7a47801a9305576a9c67e0a31d280/ruff-0.14.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4acdf009f32b46f6e8864af19cbf6841eaaed8638e65c8dac845aea0d703c841", size = 13859207, upload-time = "2026-01-15T20:14:55.111Z" }, + { url = "https://files.pythonhosted.org/packages/7d/46/2bdcb34a87a179a4d23022d818c1c236cb40e477faf0d7c9afb6813e5876/ruff-0.14.13-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:591a7f68860ea4e003917d19b5c4f5ac39ff558f162dc753a2c5de897fd5502c", size = 14043686, upload-time = "2026-01-15T20:14:52.841Z" }, + { url = "https://files.pythonhosted.org/packages/1a/a9/5c6a4f56a0512c691cf143371bcf60505ed0f0860f24a85da8bd123b2bf1/ruff-0.14.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:774c77e841cc6e046fc3e91623ce0903d1cd07e3a36b1a9fe79b81dab3de506b", size = 12663837, upload-time = "2026-01-15T20:15:18.921Z" }, + { url = "https://files.pythonhosted.org/packages/fe/bb/b920016ece7651fa7fcd335d9d199306665486694d4361547ccb19394c44/ruff-0.14.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:61f4e40077a1248436772bb6512db5fc4457fe4c49e7a94ea7c5088655dd21ae", size = 12805867, upload-time = "2026-01-15T20:14:59.272Z" }, + { url = "https://files.pythonhosted.org/packages/7d/b3/0bd909851e5696cd21e32a8fc25727e5f58f1934b3596975503e6e85415c/ruff-0.14.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6d02f1428357fae9e98ac7aa94b7e966fd24151088510d32cf6f902d6c09235e", size = 13208528, upload-time = "2026-01-15T20:15:03.732Z" }, + { url = "https://files.pythonhosted.org/packages/3b/3b/e2d94cb613f6bbd5155a75cbe072813756363eba46a3f2177a1fcd0cd670/ruff-0.14.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e399341472ce15237be0c0ae5fbceca4b04cd9bebab1a2b2c979e015455d8f0c", size = 13929242, upload-time = "2026-01-15T20:15:11.918Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c5/abd840d4132fd51a12f594934af5eba1d5d27298a6f5b5d6c3be45301caf/ruff-0.14.13-py3-none-win32.whl", hash = "sha256:ef720f529aec113968b45dfdb838ac8934e519711da53a0456038a0efecbd680", size = 12919024, upload-time = "2026-01-15T20:14:43.647Z" }, + { url = "https://files.pythonhosted.org/packages/c2/55/6384b0b8ce731b6e2ade2b5449bf07c0e4c31e8a2e68ea65b3bafadcecc5/ruff-0.14.13-py3-none-win_amd64.whl", hash = "sha256:6070bd026e409734b9257e03e3ef18c6e1a216f0435c6751d7a8ec69cb59abef", size = 14097887, upload-time = "2026-01-15T20:15:01.48Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e1/7348090988095e4e39560cfc2f7555b1b2a7357deba19167b600fdf5215d/ruff-0.14.13-py3-none-win_arm64.whl", hash = "sha256:7ab819e14f1ad9fe39f246cfcc435880ef7a9390d81a2b6ac7e01039083dd247", size = 13080224, upload-time = "2026-01-15T20:14:45.853Z" }, +] + +[[package]] +name = "scons" +version = "4.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/c9/2f430bb39e4eccba32ce8008df4a3206df651276422204e177a09e12b30b/scons-4.10.1.tar.gz", hash = "sha256:99c0e94a42a2c1182fa6859b0be697953db07ba936ecc9817ae0d218ced20b15", size = 3258403, upload-time = "2025-11-16T22:43:39.258Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/bf/931fb9fbb87234c32b8b1b1c15fba23472a10777c12043336675633809a7/scons-4.10.1-py3-none-any.whl", hash = "sha256:bd9d1c52f908d874eba92a8c0c0a8dcf2ed9f3b88ab956d0fce1da479c4e7126", size = 4136069, upload-time = "2025-11-16T22:43:35.933Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" }, + { url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" }, + { url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" }, + { url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" }, + { url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" }, + { url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" }, + { url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" }, + { url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" }, + { url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" }, + { url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" }, + { url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" }, + { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" }, +] + +[[package]] +name = "tqdm" +version = "4.67.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, +] + +[[package]] +name = "ty" +version = "0.0.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/78/ba1a4ad403c748fbba8be63b7e774a90e80b67192f6443d624c64fe4aaab/ty-0.0.12.tar.gz", hash = "sha256:cd01810e106c3b652a01b8f784dd21741de9fdc47bd595d02c122a7d5cefeee7", size = 4981303, upload-time = "2026-01-14T22:30:48.537Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/8f/c21314d074dda5fb13d3300fa6733fd0d8ff23ea83a721818740665b6314/ty-0.0.12-py3-none-linux_armv6l.whl", hash = "sha256:eb9da1e2c68bd754e090eab39ed65edf95168d36cbeb43ff2bd9f86b4edd56d1", size = 9614164, upload-time = "2026-01-14T22:30:44.016Z" }, + { url = "https://files.pythonhosted.org/packages/09/28/f8a4d944d13519d70c486e8f96d6fa95647ac2aa94432e97d5cfec1f42f6/ty-0.0.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c181f42aa19b0ed7f1b0c2d559980b1f1d77cc09419f51c8321c7ddf67758853", size = 9542337, upload-time = "2026-01-14T22:30:05.687Z" }, + { url = "https://files.pythonhosted.org/packages/e1/9c/f576e360441de7a8201daa6dc4ebc362853bc5305e059cceeb02ebdd9a48/ty-0.0.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1f829e1eecd39c3e1b032149db7ae6a3284f72fc36b42436e65243a9ed1173db", size = 8909582, upload-time = "2026-01-14T22:30:46.089Z" }, + { url = "https://files.pythonhosted.org/packages/d6/13/0898e494032a5d8af3060733d12929e3e7716db6c75eac63fa125730a3e7/ty-0.0.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45162e7826e1789cf3374627883cdeb0d56b82473a0771923e4572928e90be3", size = 9384932, upload-time = "2026-01-14T22:30:13.769Z" }, + { url = "https://files.pythonhosted.org/packages/e4/1a/b35b6c697008a11d4cedfd34d9672db2f0a0621ec80ece109e13fca4dfef/ty-0.0.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d11fec40b269bec01e751b2337d1c7ffa959a2c2090a950d7e21c2792442cccd", size = 9453140, upload-time = "2026-01-14T22:30:11.131Z" }, + { url = "https://files.pythonhosted.org/packages/dd/1e/71c9edbc79a3c88a0711324458f29c7dbf6c23452c6e760dc25725483064/ty-0.0.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09d99e37e761a4d2651ad9d5a610d11235fbcbf35dc6d4bc04abf54e7cf894f1", size = 9960680, upload-time = "2026-01-14T22:30:33.621Z" }, + { url = "https://files.pythonhosted.org/packages/0e/75/39375129f62dd22f6ad5a99cd2a42fd27d8b91b235ce2db86875cdad397d/ty-0.0.12-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d9ca0cdb17bd37397da7b16a7cd23423fc65c3f9691e453ad46c723d121225a1", size = 10904518, upload-time = "2026-01-14T22:30:08.464Z" }, + { url = "https://files.pythonhosted.org/packages/32/5e/26c6d88fafa11a9d31ca9f4d12989f57782ec61e7291d4802d685b5be118/ty-0.0.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcf2757b905e7eddb7e456140066335b18eb68b634a9f72d6f54a427ab042c64", size = 10525001, upload-time = "2026-01-14T22:30:16.454Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a5/2f0b91894af13187110f9ad7ee926d86e4e6efa755c9c88a820ed7f84c85/ty-0.0.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00cf34c1ebe1147efeda3021a1064baa222c18cdac114b7b050bbe42deb4ca80", size = 10307103, upload-time = "2026-01-14T22:30:41.221Z" }, + { url = "https://files.pythonhosted.org/packages/4b/77/13d0410827e4bc713ebb7fdaf6b3590b37dcb1b82e0a81717b65548f2442/ty-0.0.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb3a655bd869352e9a22938d707631ac9fbca1016242b1f6d132d78f347c851", size = 10072737, upload-time = "2026-01-14T22:30:51.783Z" }, + { url = "https://files.pythonhosted.org/packages/e1/dd/fc36d8bac806c74cf04b4ca735bca14d19967ca84d88f31e121767880df1/ty-0.0.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4658e282c7cb82be304052f8f64f9925f23c3c4f90eeeb32663c74c4b095d7ba", size = 9368726, upload-time = "2026-01-14T22:30:18.683Z" }, + { url = "https://files.pythonhosted.org/packages/54/70/9e8e461647550f83e2fe54bc632ccbdc17a4909644783cdbdd17f7296059/ty-0.0.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:c167d838eaaa06e03bb66a517f75296b643d950fbd93c1d1686a187e5a8dbd1f", size = 9454704, upload-time = "2026-01-14T22:30:22.759Z" }, + { url = "https://files.pythonhosted.org/packages/04/9b/6292cf7c14a0efeca0539cf7d78f453beff0475cb039fbea0eb5d07d343d/ty-0.0.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2956e0c9ab7023533b461d8a0e6b2ea7b78e01a8dde0688e8234d0fce10c4c1c", size = 9649829, upload-time = "2026-01-14T22:30:31.234Z" }, + { url = "https://files.pythonhosted.org/packages/49/bd/472a5d2013371e4870886cff791c94abdf0b92d43d305dd0f8e06b6ff719/ty-0.0.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5c6a3fd7479580009f21002f3828320621d8a82d53b7ba36993234e3ccad58c8", size = 10162814, upload-time = "2026-01-14T22:30:36.174Z" }, + { url = "https://files.pythonhosted.org/packages/31/e9/2ecbe56826759845a7c21d80aa28187865ea62bc9757b056f6cbc06f78ed/ty-0.0.12-py3-none-win32.whl", hash = "sha256:a91c24fd75c0f1796d8ede9083e2c0ec96f106dbda73a09fe3135e075d31f742", size = 9140115, upload-time = "2026-01-14T22:30:38.903Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6d/d9531eff35a5c0ec9dbc10231fac21f9dd6504814048e81d6ce1c84dc566/ty-0.0.12-py3-none-win_amd64.whl", hash = "sha256:df151894be55c22d47068b0f3b484aff9e638761e2267e115d515fcc9c5b4a4b", size = 9884532, upload-time = "2026-01-14T22:30:25.112Z" }, + { url = "https://files.pythonhosted.org/packages/e9/f3/20b49e75967023b123a221134548ad7000f9429f13fdcdda115b4c26305f/ty-0.0.12-py3-none-win_arm64.whl", hash = "sha256:cea99d334b05629de937ce52f43278acf155d3a316ad6a35356635f886be20ea", size = 9313974, upload-time = "2026-01-14T22:30:27.44Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, +] + +[[package]] +name = "zstandard" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/83/c3ca27c363d104980f1c9cee1101cc8ba724ac8c28a033ede6aab89585b1/zstandard-0.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:933b65d7680ea337180733cf9e87293cc5500cc0eb3fc8769f4d3c88d724ec5c", size = 795254, upload-time = "2025-09-14T22:16:26.137Z" }, + { url = "https://files.pythonhosted.org/packages/ac/4d/e66465c5411a7cf4866aeadc7d108081d8ceba9bc7abe6b14aa21c671ec3/zstandard-0.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3f79487c687b1fc69f19e487cd949bf3aae653d181dfb5fde3bf6d18894706f", size = 640559, upload-time = "2025-09-14T22:16:27.973Z" }, + { url = "https://files.pythonhosted.org/packages/12/56/354fe655905f290d3b147b33fe946b0f27e791e4b50a5f004c802cb3eb7b/zstandard-0.25.0-cp311-cp311-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:0bbc9a0c65ce0eea3c34a691e3c4b6889f5f3909ba4822ab385fab9057099431", size = 5348020, upload-time = "2025-09-14T22:16:29.523Z" }, + { url = "https://files.pythonhosted.org/packages/3b/13/2b7ed68bd85e69a2069bcc72141d378f22cae5a0f3b353a2c8f50ef30c1b/zstandard-0.25.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01582723b3ccd6939ab7b3a78622c573799d5d8737b534b86d0e06ac18dbde4a", size = 5058126, upload-time = "2025-09-14T22:16:31.811Z" }, + { url = "https://files.pythonhosted.org/packages/c9/dd/fdaf0674f4b10d92cb120ccff58bbb6626bf8368f00ebfd2a41ba4a0dc99/zstandard-0.25.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5f1ad7bf88535edcf30038f6919abe087f606f62c00a87d7e33e7fc57cb69fcc", size = 5405390, upload-time = "2025-09-14T22:16:33.486Z" }, + { url = "https://files.pythonhosted.org/packages/0f/67/354d1555575bc2490435f90d67ca4dd65238ff2f119f30f72d5cde09c2ad/zstandard-0.25.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:06acb75eebeedb77b69048031282737717a63e71e4ae3f77cc0c3b9508320df6", size = 5452914, upload-time = "2025-09-14T22:16:35.277Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1f/e9cfd801a3f9190bf3e759c422bbfd2247db9d7f3d54a56ecde70137791a/zstandard-0.25.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9300d02ea7c6506f00e627e287e0492a5eb0371ec1670ae852fefffa6164b072", size = 5559635, upload-time = "2025-09-14T22:16:37.141Z" }, + { url = "https://files.pythonhosted.org/packages/21/88/5ba550f797ca953a52d708c8e4f380959e7e3280af029e38fbf47b55916e/zstandard-0.25.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfd06b1c5584b657a2892a6014c2f4c20e0db0208c159148fa78c65f7e0b0277", size = 5048277, upload-time = "2025-09-14T22:16:38.807Z" }, + { url = "https://files.pythonhosted.org/packages/46/c0/ca3e533b4fa03112facbe7fbe7779cb1ebec215688e5df576fe5429172e0/zstandard-0.25.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f373da2c1757bb7f1acaf09369cdc1d51d84131e50d5fa9863982fd626466313", size = 5574377, upload-time = "2025-09-14T22:16:40.523Z" }, + { url = "https://files.pythonhosted.org/packages/12/9b/3fb626390113f272abd0799fd677ea33d5fc3ec185e62e6be534493c4b60/zstandard-0.25.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c0e5a65158a7946e7a7affa6418878ef97ab66636f13353b8502d7ea03c8097", size = 4961493, upload-time = "2025-09-14T22:16:43.3Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d3/23094a6b6a4b1343b27ae68249daa17ae0651fcfec9ed4de09d14b940285/zstandard-0.25.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c8e167d5adf59476fa3e37bee730890e389410c354771a62e3c076c86f9f7778", size = 5269018, upload-time = "2025-09-14T22:16:45.292Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a7/bb5a0c1c0f3f4b5e9d5b55198e39de91e04ba7c205cc46fcb0f95f0383c1/zstandard-0.25.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:98750a309eb2f020da61e727de7d7ba3c57c97cf6213f6f6277bb7fb42a8e065", size = 5443672, upload-time = "2025-09-14T22:16:47.076Z" }, + { url = "https://files.pythonhosted.org/packages/27/22/503347aa08d073993f25109c36c8d9f029c7d5949198050962cb568dfa5e/zstandard-0.25.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22a086cff1b6ceca18a8dd6096ec631e430e93a8e70a9ca5efa7561a00f826fa", size = 5822753, upload-time = "2025-09-14T22:16:49.316Z" }, + { url = "https://files.pythonhosted.org/packages/e2/be/94267dc6ee64f0f8ba2b2ae7c7a2df934a816baaa7291db9e1aa77394c3c/zstandard-0.25.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:72d35d7aa0bba323965da807a462b0966c91608ef3a48ba761678cb20ce5d8b7", size = 5366047, upload-time = "2025-09-14T22:16:51.328Z" }, + { url = "https://files.pythonhosted.org/packages/7b/a3/732893eab0a3a7aecff8b99052fecf9f605cf0fb5fb6d0290e36beee47a4/zstandard-0.25.0-cp311-cp311-win32.whl", hash = "sha256:f5aeea11ded7320a84dcdd62a3d95b5186834224a9e55b92ccae35d21a8b63d4", size = 436484, upload-time = "2025-09-14T22:16:55.005Z" }, + { url = "https://files.pythonhosted.org/packages/43/a3/c6155f5c1cce691cb80dfd38627046e50af3ee9ddc5d0b45b9b063bfb8c9/zstandard-0.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:daab68faadb847063d0c56f361a289c4f268706b598afbf9ad113cbe5c38b6b2", size = 506183, upload-time = "2025-09-14T22:16:52.753Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3e/8945ab86a0820cc0e0cdbf38086a92868a9172020fdab8a03ac19662b0e5/zstandard-0.25.0-cp311-cp311-win_arm64.whl", hash = "sha256:22a06c5df3751bb7dc67406f5374734ccee8ed37fc5981bf1ad7041831fa1137", size = 462533, upload-time = "2025-09-14T22:16:53.878Z" }, + { url = "https://files.pythonhosted.org/packages/82/fc/f26eb6ef91ae723a03e16eddb198abcfce2bc5a42e224d44cc8b6765e57e/zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b", size = 795738, upload-time = "2025-09-14T22:16:56.237Z" }, + { url = "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00", size = 640436, upload-time = "2025-09-14T22:16:57.774Z" }, + { url = "https://files.pythonhosted.org/packages/53/6c/288c3f0bd9fcfe9ca41e2c2fbfd17b2097f6af57b62a81161941f09afa76/zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64", size = 5343019, upload-time = "2025-09-14T22:16:59.302Z" }, + { url = "https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea", size = 5063012, upload-time = "2025-09-14T22:17:01.156Z" }, + { url = "https://files.pythonhosted.org/packages/b7/37/a6ce629ffdb43959e92e87ebdaeebb5ac81c944b6a75c9c47e300f85abdf/zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb", size = 5394148, upload-time = "2025-09-14T22:17:03.091Z" }, + { url = "https://files.pythonhosted.org/packages/e3/79/2bf870b3abeb5c070fe2d670a5a8d1057a8270f125ef7676d29ea900f496/zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a", size = 5451652, upload-time = "2025-09-14T22:17:04.979Z" }, + { url = "https://files.pythonhosted.org/packages/53/60/7be26e610767316c028a2cbedb9a3beabdbe33e2182c373f71a1c0b88f36/zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902", size = 5546993, upload-time = "2025-09-14T22:17:06.781Z" }, + { url = "https://files.pythonhosted.org/packages/85/c7/3483ad9ff0662623f3648479b0380d2de5510abf00990468c286c6b04017/zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f", size = 5046806, upload-time = "2025-09-14T22:17:08.415Z" }, + { url = "https://files.pythonhosted.org/packages/08/b3/206883dd25b8d1591a1caa44b54c2aad84badccf2f1de9e2d60a446f9a25/zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b", size = 5576659, upload-time = "2025-09-14T22:17:10.164Z" }, + { url = "https://files.pythonhosted.org/packages/9d/31/76c0779101453e6c117b0ff22565865c54f48f8bd807df2b00c2c404b8e0/zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6", size = 4953933, upload-time = "2025-09-14T22:17:11.857Z" }, + { url = "https://files.pythonhosted.org/packages/18/e1/97680c664a1bf9a247a280a053d98e251424af51f1b196c6d52f117c9720/zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91", size = 5268008, upload-time = "2025-09-14T22:17:13.627Z" }, + { url = "https://files.pythonhosted.org/packages/1e/73/316e4010de585ac798e154e88fd81bb16afc5c5cb1a72eeb16dd37e8024a/zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708", size = 5433517, upload-time = "2025-09-14T22:17:16.103Z" }, + { url = "https://files.pythonhosted.org/packages/5b/60/dd0f8cfa8129c5a0ce3ea6b7f70be5b33d2618013a161e1ff26c2b39787c/zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512", size = 5814292, upload-time = "2025-09-14T22:17:17.827Z" }, + { url = "https://files.pythonhosted.org/packages/fc/5f/75aafd4b9d11b5407b641b8e41a57864097663699f23e9ad4dbb91dc6bfe/zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa", size = 5360237, upload-time = "2025-09-14T22:17:19.954Z" }, + { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922, upload-time = "2025-09-14T22:17:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276, upload-time = "2025-09-14T22:17:21.429Z" }, + { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679, upload-time = "2025-09-14T22:17:23.147Z" }, +] From 63b25261aa05fde04ef8c6af21f93d2ed5c25c92 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 20 Jan 2026 23:32:34 -0800 Subject: [PATCH 03/77] Subaru: fix RPM size and label neutral (#3048) fix rpm size and label neutral --- opendbc/dbc/generator/subaru/_subaru_global.dbc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opendbc/dbc/generator/subaru/_subaru_global.dbc b/opendbc/dbc/generator/subaru/_subaru_global.dbc index 69c83619..39fcda0a 100644 --- a/opendbc/dbc/generator/subaru/_subaru_global.dbc +++ b/opendbc/dbc/generator/subaru/_subaru_global.dbc @@ -45,8 +45,8 @@ BO_ 64 Throttle: 8 XXX SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX SG_ Signal1 : 12|4@1+ (1,0) [0|15] "" XXX - SG_ Engine_RPM : 16|12@1+ (1,0) [0|4095] "" XXX - SG_ Signal2 : 28|4@1+ (1,0) [0|15] "" XXX + SG_ Engine_RPM : 16|13@1+ (1,0) [0|8191] "" XXX + SG_ Neutral : 31|1@1+ (1,0) [0|15] "" XXX SG_ Throttle_Pedal : 32|8@1+ (1,0) [0|255] "" XXX SG_ Throttle_Cruise : 40|8@1+ (1,0) [0|255] "" XXX SG_ Throttle_Combo : 48|8@1+ (1,0) [0|255] "" XXX From 3b75bd8536a3a503447f8455b12ede304ff929ab Mon Sep 17 00:00:00 2001 From: Daniel Koepping Date: Wed, 21 Jan 2026 04:05:53 -0800 Subject: [PATCH 04/77] Car diff: fix PR comment (#3045) fix PR comment --- .github/workflows/car_diff.yml | 42 ++++++++++++++++++++++++++++++++++ .github/workflows/tests.yml | 9 ++++---- opendbc/car/tests/car_diff.py | 2 +- 3 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/car_diff.yml diff --git a/.github/workflows/car_diff.yml b/.github/workflows/car_diff.yml new file mode 100644 index 00000000..c6f94216 --- /dev/null +++ b/.github/workflows/car_diff.yml @@ -0,0 +1,42 @@ +name: car diff + +on: + pull_request_target: + types: [opened, synchronize, reopened] + +jobs: + comment: + name: comment + runs-on: ubuntu-latest + timeout-minutes: 10 + continue-on-error: true + permissions: + contents: read + pull-requests: write + actions: read + steps: + - name: Wait for car diff + uses: lewagon/wait-on-check-action@v1.3.4 + with: + ref: ${{ github.event.pull_request.head.sha }} + check-name: car diff + repo-token: ${{ secrets.GITHUB_TOKEN }} + allowed-conclusions: success + wait-interval: 20 + - name: Download car diff + uses: dawidd6/action-download-artifact@v6 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + workflow: tests.yml + workflow_conclusion: '' + pr: ${{ github.event.number }} + name: car_diff_${{ github.event.number }} + path: . + allow_forks: true + - name: Comment car diff on PR + uses: thollander/actions-comment-pull-request@v2 + with: + filePath: diff.txt + comment_tag: car_diff + pr_number: ${{ github.event.number }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4328ffd2..6b9806b4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -77,11 +77,12 @@ jobs: - name: Test car diff if: github.event_name == 'pull_request' run: source setup.sh && python opendbc/car/tests/car_diff.py | tee diff.txt - - name: Comment PR + - name: Upload diff if: always() && github.event_name == 'pull_request' - env: - GH_TOKEN: ${{ github.token }} - run: '[ -s diff.txt ] && gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} -F diff.txt || true' + uses: actions/upload-artifact@v4 + with: + name: car_diff_${{ github.event.number }} + path: diff.txt - name: Update refs if: github.repository == 'commaai/opendbc' && github.ref == 'refs/heads/master' run: source setup.sh && python opendbc/car/tests/car_diff.py --update-refs diff --git a/opendbc/car/tests/car_diff.py b/opendbc/car/tests/car_diff.py index a75b8f95..9a2bd250 100644 --- a/opendbc/car/tests/car_diff.py +++ b/opendbc/car/tests/car_diff.py @@ -262,7 +262,7 @@ def main(platform=None, segments_per_platform=10, update_refs=False, all_platfor platforms = get_changed_platforms(cwd, database, interfaces) if not platforms: - print("No car changes detected", file=sys.stderr) + print("No car changes detected") return 0 segments = {p: database.get(p, [])[:segments_per_platform] for p in platforms} From 839d2396167998b369d5f65150a6e834a9c4164b Mon Sep 17 00:00:00 2001 From: Alexandre Nobuharu Sato <66435071+AlexandreSato@users.noreply.github.com> Date: Wed, 21 Jan 2026 17:28:31 -0300 Subject: [PATCH 05/77] fingerprint subaru impreza 2019 (#2980) fp subaru impreza Co-authored-by: Daniel Koepping --- opendbc/car/subaru/fingerprints.py | 1 + 1 file changed, 1 insertion(+) diff --git a/opendbc/car/subaru/fingerprints.py b/opendbc/car/subaru/fingerprints.py index 9addabaa..db735980 100644 --- a/opendbc/car/subaru/fingerprints.py +++ b/opendbc/car/subaru/fingerprints.py @@ -146,6 +146,7 @@ FW_VERSIONS = { b'\xc5!ap\x07', b'\xc5!ar\x07', b'\xc5!as\x07', + b'\xc5!au\x07', b'\xc5!dr\x07', b'\xc5!ds\x07', b'\xca\x01b0\x07', From 6ba695cfd5391de18e56d9c53498ae0c6a47131e Mon Sep 17 00:00:00 2001 From: eFini Date: Thu, 22 Jan 2026 04:47:22 +0800 Subject: [PATCH 06/77] Honda: Taiwan 2025 HR-V Fingerprint (#2969) * Taiwan 2025 HR-V Fingerprint * fix ordering (via auto_fingerprint) --------- Co-authored-by: Daniel Koepping Co-authored-by: Jason Young --- opendbc/car/honda/fingerprints.py | 1 + 1 file changed, 1 insertion(+) diff --git a/opendbc/car/honda/fingerprints.py b/opendbc/car/honda/fingerprints.py index 9b5b6899..aac2a601 100644 --- a/opendbc/car/honda/fingerprints.py +++ b/opendbc/car/honda/fingerprints.py @@ -855,6 +855,7 @@ FW_VERSIONS = { b'77959-3V0-A910\x00\x00', ], (Ecu.fwdRadar, 0x18dab0f1, None): [ + b'8S102-3M1-T050\x00\x00', b'8S102-3M3-T050\x00\x00', b'8S102-3M6-P030\x00\x00', b'8S102-3M6-PA20\x00\x00', From 23b15a7569652879c899f3be5a7156e2725d3b90 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 21 Jan 2026 15:55:21 -0800 Subject: [PATCH 07/77] Subaru: add additional steering angle and clutch depressed (#3051) add clutch and angle --- opendbc/dbc/generator/subaru/_subaru_global.dbc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/opendbc/dbc/generator/subaru/_subaru_global.dbc b/opendbc/dbc/generator/subaru/_subaru_global.dbc index 39fcda0a..cb06822c 100644 --- a/opendbc/dbc/generator/subaru/_subaru_global.dbc +++ b/opendbc/dbc/generator/subaru/_subaru_global.dbc @@ -46,7 +46,7 @@ BO_ 64 Throttle: 8 XXX SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX SG_ Signal1 : 12|4@1+ (1,0) [0|15] "" XXX SG_ Engine_RPM : 16|13@1+ (1,0) [0|8191] "" XXX - SG_ Neutral : 31|1@1+ (1,0) [0|15] "" XXX + SG_ Neutral : 31|1@1+ (1,0) [0|1] "" XXX SG_ Throttle_Pedal : 32|8@1+ (1,0) [0|255] "" XXX SG_ Throttle_Cruise : 40|8@1+ (1,0) [0|255] "" XXX SG_ Throttle_Combo : 48|8@1+ (1,0) [0|255] "" XXX @@ -110,6 +110,7 @@ BO_ 282 Steering_2: 8 XXX BO_ 312 Brake_Pressure_L_R: 8 XXX SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX + SG_ Steering_Angle : 16|16@1- (-0.1,0) [-3276.8|3276.7] "" XXX SG_ Brake_1 : 48|8@1+ (1,0) [0|255] "" XXX SG_ Brake_2 : 56|8@1+ (1,0) [0|255] "" XXX @@ -158,6 +159,7 @@ BO_ 544 ES_Brake: 8 XXX BO_ 577 Cruise_Status: 8 XXX SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX + SG_ Clutch_Depressed : 47|1@0+ (1,0) [0|1] "" XXX SG_ Cruise_Set_Speed : 51|12@0+ (1,0) [0|120] "" XXX SG_ Cruise_On : 54|1@1+ (1,0) [0|1] "" XXX SG_ Cruise_Activated : 55|1@1+ (1,0) [0|1] "" XXX From f64e0bfe8ae3c0a2473dc0f78c288b4f5f5bab09 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 21 Jan 2026 22:34:30 -0800 Subject: [PATCH 08/77] Add misc bug template (#3057) * misc bug * rm --- .github/ISSUE_TEMPLATE/misc.yml | 36 +++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/misc.yml diff --git a/.github/ISSUE_TEMPLATE/misc.yml b/.github/ISSUE_TEMPLATE/misc.yml new file mode 100644 index 00000000..3f4a1f61 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/misc.yml @@ -0,0 +1,36 @@ +name: Miscellaneous +description: For tools or test bugs, or enhancements +labels: ["bug"] +body: + + - type: markdown + attributes: + value: > + * If the issue likely only affects your car model or make, go back and open a **car bug report** instead. + Before creating a **miscellaneous bug report**, please check the following: + * Ensure there isn't an existing issue for your bug. If there is, leave a comment on the existing issue. + + - type: textarea + attributes: + label: Describe the bug or enhancement + description: Also include a description of how to reproduce the bug or how the enhancement would work + validations: + required: true + + - type: input + id: route + attributes: + label: Provide a route where the issue occurs if applicable + description: Ensure the route is fully uploaded at https://useradmin.comma.ai + placeholder: 77611a1fac303767|2020-05-11--16-37-07 + + - type: input + id: version + attributes: + label: openpilot version if applicable + description: If you're not on release, provide the commit hash + placeholder: 0.8.10 + + - type: textarea + attributes: + label: Additional info From 01a29844a6f6f072ab28fd9172e0e22eaf33660d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 21 Jan 2026 23:04:35 -0800 Subject: [PATCH 09/77] Fixup car differ (#3056) * start * start * carfw * use existing can fp infra * run on all * tqdm is nice to have * rm * sort too * clean up * exe --- opendbc/car/tests/car_diff.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) mode change 100644 => 100755 opendbc/car/tests/car_diff.py diff --git a/opendbc/car/tests/car_diff.py b/opendbc/car/tests/car_diff.py old mode 100644 new mode 100755 index 9a2bd250..09110238 --- a/opendbc/car/tests/car_diff.py +++ b/opendbc/car/tests/car_diff.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 import argparse import os import pickle @@ -6,9 +7,10 @@ import subprocess import sys import tempfile import zstandard as zstd +from tqdm import tqdm +from tqdm.contrib.concurrent import process_map from urllib.request import urlopen from collections import defaultdict -from concurrent.futures import ProcessPoolExecutor from pathlib import Path from comma_car_segments import get_comma_car_segments_database, get_url @@ -42,20 +44,21 @@ def dict_diff(d1, d2, path="", ignore=None, tolerance=0): def load_can_messages(seg): parts = seg.split("/") url = get_url(f"{parts[0]}/{parts[1]}", parts[2]) - msgs = LogReader(url, only_union_types=True) + msgs = LogReader(url, only_union_types=True, sort_by_time=True) return [m for m in msgs if m.which() == 'can'] def replay_segment(platform, can_msgs): - from opendbc.car import gen_empty_fingerprint, structs + from opendbc.car import structs from opendbc.car.can_definitions import CanData - from opendbc.car.car_helpers import FRAME_FINGERPRINT, interfaces + from opendbc.car.car_helpers import interfaces, can_fingerprint - fingerprint = gen_empty_fingerprint() - for msg in can_msgs[:FRAME_FINGERPRINT]: - for m in msg.can: - if m.src < 64: - fingerprint[m.src][m.address] = len(m.dat) + _can_msgs = ([CanData(can.address, can.dat, can.src) for can in m.can] for m in can_msgs) + + def can_recv(wait_for_one: bool = False) -> list[list[CanData]]: + return [next(_can_msgs, [])] + + _, fingerprint = can_fingerprint(can_recv) CarInterface = interfaces[platform] CP = CarInterface.get_params(platform, fingerprint, [], False, False, False) @@ -111,7 +114,7 @@ def get_changed_platforms(cwd, database, interfaces): def download_refs(ref_path, platforms, segments): base_url = f"https://raw.githubusercontent.com/commaai/ci-artifacts/refs/heads/{DIFF_BUCKET}" - for platform in platforms: + for platform in tqdm(platforms): for seg in segments.get(platform, []): filename = f"{platform}_{seg.replace('/', '_')}.zst" try: @@ -124,8 +127,7 @@ def download_refs(ref_path, platforms, segments): def run_replay(platforms, segments, ref_path, update, workers=4): work = [(platform, seg, ref_path, update) for platform in platforms for seg in segments.get(platform, [])] - with ProcessPoolExecutor(max_workers=workers) as pool: - return list(pool.map(process_segment, work)) + return process_map(process_segment, work, max_workers=workers) # ASCII waveforms helpers From 33c1840d0466c2983d4c87b55a73d81861289c15 Mon Sep 17 00:00:00 2001 From: MVL Date: Thu, 22 Jan 2026 11:08:17 -0500 Subject: [PATCH 10/77] Honda - CANFD Acura TLX 2025 (#3037) * add 25 TLX fingerprints * Add 25 TLX values * temp testroute exception * temporary torque data until testdrive * add 2025 TLX initial torque numbers * adding 25 TLX initial testroute * fix testroute typo * increase steermax to 3840 * Increase TLX 2G MMR steermax based on testroute * Update TLX 2G MMR torque data based on testroute * Newer TLX 2G MMR testroute * Revising torque parameters a bit more after hours of driving * Revising steer ratio a bit more after hours of driving * Clean test route for Acura TLX 2G MMR --------- Co-authored-by: Daniel Koepping Co-authored-by: Jason Young --- opendbc/car/honda/fingerprints.py | 8 ++++++++ opendbc/car/honda/interface.py | 5 +++++ opendbc/car/honda/values.py | 5 +++++ opendbc/car/tests/routes.py | 1 + opendbc/car/torque_data/override.toml | 1 + 5 files changed, 20 insertions(+) diff --git a/opendbc/car/honda/fingerprints.py b/opendbc/car/honda/fingerprints.py index aac2a601..19bbcbe0 100644 --- a/opendbc/car/honda/fingerprints.py +++ b/opendbc/car/honda/fingerprints.py @@ -1068,4 +1068,12 @@ FW_VERSIONS = { b'36161-TGV-A030\x00\x00', ], }, + CAR.ACURA_TLX_2G_MMR: { + (Ecu.fwdRadar, 0x18dab0f1, None): [ + b'8S302-TGV-A030\x00\x00', + ], + (Ecu.fwdCamera, 0x18dab5f1, None): [ + b'8S102-TGV-A030\x00\x00', + ], + }, } diff --git a/opendbc/car/honda/interface.py b/opendbc/car/honda/interface.py index 59e300c4..18fd2fbc 100755 --- a/opendbc/car/honda/interface.py +++ b/opendbc/car/honda/interface.py @@ -191,6 +191,11 @@ class CarInterface(CarInterfaceBase): # When using stock ACC, the radar intercepts and filters steering commands the EPS would otherwise accept ret.minSteerSpeed = 70. * CV.KPH_TO_MS + elif candidate == CAR.ACURA_TLX_2G_MMR: + ret.steerActuatorDelay = 0.15 + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]] + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + else: ret.steerActuatorDelay = 0.15 ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]] diff --git a/opendbc/car/honda/values.py b/opendbc/car/honda/values.py index 3cdccc1e..80958c8b 100644 --- a/opendbc/car/honda/values.py +++ b/opendbc/car/honda/values.py @@ -277,6 +277,11 @@ class CAR(Platforms): {Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'}, flags=HondaFlags.BOSCH_ALT_RADAR, ) + # mid-model refresh + ACURA_TLX_2G_MMR = HondaBoschCANFDPlatformConfig( + [HondaCarDocs("Acura TLX 2025", "All")], + CarSpecs(mass=3990 * CV.LB_TO_KG, wheelbase=2.87, centerToFrontRatio=0.43, steerRatio=13.7), + ) # Nidec Cars ACURA_ILX = HondaNidecPlatformConfig( diff --git a/opendbc/car/tests/routes.py b/opendbc/car/tests/routes.py index 3fef40ef..9202da7a 100644 --- a/opendbc/car/tests/routes.py +++ b/opendbc/car/tests/routes.py @@ -127,6 +127,7 @@ routes = [ # CarTestRoute("56b2cf1dacdcd033/00000017--d24ffdb376", HONDA.HONDA_CITY_7G), # Brazilian model CarTestRoute("2dc4489d7e1410ca/00000001--bbec3f5117", HONDA.HONDA_CRV_6G), CarTestRoute("a703d058f4e05aeb/00000008--f169423024", HONDA.HONDA_PASSPORT_4G), + CarTestRoute("ad9840558640c31d/000001f2--026c4f6275", HONDA.ACURA_TLX_2G_MMR), CarTestRoute("87d7f06ade479c2e/2023-09-11--23-30-11", HYUNDAI.HYUNDAI_AZERA_6TH_GEN), CarTestRoute("66189dd8ec7b50e6/2023-09-20--07-02-12", HYUNDAI.HYUNDAI_AZERA_HEV_6TH_GEN), diff --git a/opendbc/car/torque_data/override.toml b/opendbc/car/torque_data/override.toml index 69cc6048..d2416afc 100644 --- a/opendbc/car/torque_data/override.toml +++ b/opendbc/car/torque_data/override.toml @@ -91,6 +91,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "HONDA_ODYSSEY_5G_MMR" = [0.9, 0.9, 0.2] "HONDA_NBOX_2G" = [1.2, 1.2, 0.2] "ACURA_TLX_2G" = [1.2, 1.2, 0.15] +"ACURA_TLX_2G_MMR" = [1.7, 1.7, 0.16] "PORSCHE_MACAN_MK1" = [2.0, 2.0, 0.2] # Dashcam or fallback configured as ideal car From d56dd7f6a71577c6730e28f57700ed7c4d1bd02c Mon Sep 17 00:00:00 2001 From: Nikita Pylypyuk <147505783+nikitap066@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:27:08 +0000 Subject: [PATCH 11/77] Chrysler: correct radar lateral position sign (#3043) align radar yRel with left-positive convention Co-authored-by: Daniel Koepping --- opendbc/car/chrysler/radar_interface.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opendbc/car/chrysler/radar_interface.py b/opendbc/car/chrysler/radar_interface.py index 4ad4afa1..ff5d7680 100755 --- a/opendbc/car/chrysler/radar_interface.py +++ b/opendbc/car/chrysler/radar_interface.py @@ -73,8 +73,8 @@ class RadarInterface(RadarInterfaceBase): if 'LONG_DIST' in cpt: # c_* message self.pts[trackId].dRel = cpt['LONG_DIST'] # from front of car # our lat_dist is positive to the right in car's frame. - # TODO what does yRel want? - self.pts[trackId].yRel = cpt['LAT_DIST'] # in car frame's y axis, left is positive + # LAT_DIST is right-positive, yRel is left-positive + self.pts[trackId].yRel = -cpt['LAT_DIST'] # in car frame's y axis, left is positive else: # d_* message self.pts[trackId].vRel = cpt['REL_SPEED'] From 8f5e3204e01fa9c3750f2bdb4773f25edbe5ac76 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 22 Jan 2026 16:31:09 -0800 Subject: [PATCH 12/77] Tesla: add FSD 14 failsafe detection (#3053) * add fsd 14 failsafe detection * fix logic * dont perm set if FSD 13 user starts op with FSD/autosteer, engages to get a noEntry, and then swaps to correct TACC --- opendbc/car/tesla/carstate.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/opendbc/car/tesla/carstate.py b/opendbc/car/tesla/carstate.py index 3b71ae69..5158a40f 100644 --- a/opendbc/car/tesla/carstate.py +++ b/opendbc/car/tesla/carstate.py @@ -1,10 +1,11 @@ import copy from opendbc.can import CANDefine, CANParser from opendbc.car import Bus, structs +from opendbc.car.carlog import carlog from opendbc.car.common.conversions import Conversions as CV from opendbc.car.interfaces import CarStateBase from opendbc.car.tesla.teslacan import get_steer_ctrl_type -from opendbc.car.tesla.values import DBC, CANBUS, GEAR_MAP, STEER_THRESHOLD, CAR +from opendbc.car.tesla.values import DBC, CANBUS, GEAR_MAP, STEER_THRESHOLD, CAR, TeslaFlags ButtonType = structs.CarState.ButtonEvent.Type @@ -18,6 +19,8 @@ class CarState(CarStateBase): self.autopark = False self.autopark_prev = False self.cruise_enabled_prev = False + self.fsd14_error_logged = False + self.suspected_fsd14 = False self.hands_on_level = 0 self.das_control = None @@ -113,10 +116,23 @@ class CarState(CarStateBase): ret.stockLkas = cp_ap_party.vl["DAS_steeringControl"]["DAS_steeringControlType"] == lkas_ctrl_type # LANE_KEEP_ASSIST # Stock Autosteer should be off (includes FSD) + # TODO: find for TESLA_MODEL_X if self.CP.carFingerprint in (CAR.TESLA_MODEL_3, CAR.TESLA_MODEL_Y): ret.invalidLkasSetting = cp_ap_party.vl["DAS_settings"]["DAS_autosteerEnabled"] != 0 - else: - pass + + # Because we don't have FSD 14 detection outside of a set of FW, we should check if this FW is accidentally missing from FSD_14_FW + # 1. If in Autosteer or FSD, already caught by invalidLkasSetting + # 2. If in TACC and DAS ever sends ANGLE_CONTROL (1), we can infer it's trying to do LKAS on FSD 14+ + angle_control = cp_ap_party.vl["DAS_steeringControl"]["DAS_steeringControlType"] == 1 # ANGLE_CONTROL + if not ret.invalidLkasSetting and angle_control and not self.CP.flags & TeslaFlags.FSD_14: + self.suspected_fsd14 = True + + if self.suspected_fsd14: + ret.invalidLkasSetting = True + if not self.fsd14_error_logged: + carlog.error("FSD 14 detected, but FW not in FSD_14_FW set") + self.fsd14_error_logged = True + # Buttons # ToDo: add Gap adjust button # Messages needed by carcontroller From fd5e5b5c3ffdd6b48c1475fe96d3e21345c49903 Mon Sep 17 00:00:00 2001 From: MVL Date: Thu, 22 Jan 2026 23:58:16 -0500 Subject: [PATCH 13/77] Honda: Allow manual for 10G Civic (#3025) * Add manual transmission to CIVIC_BOSCH * Add 19 Civic Hatchback MT fingerprint --------- Co-authored-by: Daniel Koepping --- opendbc/car/honda/fingerprints.py | 1 + opendbc/car/honda/values.py | 1 + 2 files changed, 2 insertions(+) diff --git a/opendbc/car/honda/fingerprints.py b/opendbc/car/honda/fingerprints.py index 19bbcbe0..4d5134b9 100644 --- a/opendbc/car/honda/fingerprints.py +++ b/opendbc/car/honda/fingerprints.py @@ -220,6 +220,7 @@ FW_VERSIONS = { b'57114-TBG-A340\x00\x00', b'57114-TBG-A350\x00\x00', b'57114-TGG-A340\x00\x00', + b'57114-TGG-C120\x00\x00', b'57114-TGG-C320\x00\x00', b'57114-TGG-G320\x00\x00', b'57114-TGG-L320\x00\x00', diff --git a/opendbc/car/honda/values.py b/opendbc/car/honda/values.py index 80958c8b..389af02b 100644 --- a/opendbc/car/honda/values.py +++ b/opendbc/car/honda/values.py @@ -185,6 +185,7 @@ class CAR(Platforms): ], CarSpecs(mass=1326, wheelbase=2.7, steerRatio=15.38, centerToFrontRatio=0.4), # steerRatio: 10.93 is end-to-end spec {Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'}, + flags=HondaFlags.ALLOW_MANUAL_TRANS, ) HONDA_CIVIC_BOSCH_DIESEL = HondaBoschPlatformConfig( [], # don't show in docs From 0020a2f5191e7a0b73dc2337ac5d40035dd8e3a7 Mon Sep 17 00:00:00 2001 From: Javier Fernandez Date: Fri, 23 Jan 2026 06:20:25 +0100 Subject: [PATCH 14/77] HKG: add FW Hyundai Tucson HEV 2022 EUR (#3061) * Update fing Update fingerprints.py hyundai Tucson EUR 2022 Hybriderprints.py The 2022-2024 Hyundai Tucson NX4 Hybrid in the European version with Can-FD and the Hyundai N harness was not detected by the official openpilot branch, it had to be selected manually. After following the steps to create a new fingerprints, I added the corresponding lines to the fingerprints.py file, and now the official branch works on this car model, it automatically selects the model. Also the file values.py was modified to add Ecu.eps to non_essential_ecus * Update values.py hyundai Tucson EUR 2022 Hybrid The 2022-2024 Hyundai Tucson NX4 Hybrid in the European version with Can-FD and the Hyundai N harness was not detected by the official openpilot branch, it had to be selected manually. After following the steps to create a new fingerprints, I added the corresponding lines to the fingerprints.py file, and now the official branch works on this car model and it automatically selects the model. Also the file values.py was modified to add Ecu.eps to non_essential_ecus * Apply suggestions from code review --------- Co-authored-by: Shane Smiskol --- opendbc/car/hyundai/fingerprints.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/opendbc/car/hyundai/fingerprints.py b/opendbc/car/hyundai/fingerprints.py index 7b4bb1c7..4db215b7 100644 --- a/opendbc/car/hyundai/fingerprints.py +++ b/opendbc/car/hyundai/fingerprints.py @@ -1084,12 +1084,14 @@ FW_VERSIONS = { b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9260 14Y', b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9100 14A', b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9240 14T', + b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 1.00 99211-N9240 14Q', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00NX4__ 1.00 1.00 99110-N9100 ', b'\xf1\x00NX4__ 1.00 1.01 99110-N9000 ', b'\xf1\x00NX4__ 1.00 1.02 99110-N9000 ', b'\xf1\x00NX4__ 1.01 1.00 99110-N9100 ', + b'\xf1\x00NX4__ 1.01 1.02 99110-N9000 ', ], }, CAR.HYUNDAI_SANTA_CRUZ_1ST_GEN: { From 3657bc3232ce1fbb704a50c8af06655961305da0 Mon Sep 17 00:00:00 2001 From: MVL Date: Fri, 23 Jan 2026 00:24:02 -0500 Subject: [PATCH 15/77] Honda - Euro Civic Type R FK8 support (#2986) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update fingerprints.py Added params from here {'carParams': {'alphaLongitudinalAvailable': False, 'alternativeExperience': 0, 'autoResumeSng': True, 'brand': 'mock', 'carFingerprint': 'MOCK', 'carFw': [{'address': 417001457, 'brand': 'honda', 'bus': 1, 'ecu': 'gateway', 'fwVersion': b'38897-TBA-A020\x00\x00', 'logging': False, 'obdMultiplexing': True, 'request': [b'"\xf1\x81'], 'responseAddress': 417001967, 'subAddress': 0}, {'address': 416952561, 'brand': 'honda', 'bus': 1, 'ecu': 'eps', 'fwVersion': b'39990-TGH-J020\x00\x00', 'logging': False, 'obdMultiplexing': True, 'request': [b'"\xf1\x81'], 'responseAddress': 417001776, 'subAddress': 0}, {'address': 416944369, 'brand': 'honda', 'bus': 1, 'ecu': 'programmedFuelInjection', 'fwVersion': b'37805-5BF-E030\x00\x00', 'logging': True, 'obdMultiplexing': True, 'request': [b'"\xf1\x81'], 'responseAddress': 417001744, 'subAddress': 0}, {'address': 416964849, 'brand': 'honda', 'bus': 1, 'ecu': 'combinationMeter', 'fwVersion': b'78109-TGH-E310\x00\x00', 'logging': True, 'obdMultiplexing': True, 'request': [b'"\xf1\x81'], 'responseAddress': 417001824, 'subAddress': 0}, {'address': 416950513, 'brand': 'honda', 'bus': 1, 'ecu': 'vsa', 'fwVersion': b'57114-TGH-A130\x00\x00', 'logging': False, 'obdMultiplexing': True, 'request': [b'"\xf1\x81'], 'responseAddress': 417001768, 'subAddress': 0}, {'address': 416986609, 'brand': 'honda', 'bus': 1, 'ecu': 'fwdCamera', 'fwVersion': b'36161-TGH-A020\x00\x00', 'logging': False, 'obdMultiplexing': True, 'request': [b'"\xf1\x81'], 'responseAddress': 417001909, 'subAddress': 0}, {'address': 416985329, 'brand': 'honda', 'bus': 1, 'ecu': 'fwdRadar', 'fwVersion': b'36802-TGH-A030\x00\x00', 'logging': False, 'obdMultiplexing': True, 'request': [b'"\xf1\x81'], 'responseAddress': 417001904, 'subAddress': 0}, {'address': 416961521, 'brand': 'honda', 'bus': 1, 'ecu': 'srs', 'fwVersion': b'77959-TGH-E220\x00\x00', 'logging': False, 'obdMultiplexing': True, 'request': [b'"\xf1\x81'], 'responseAddress': 417001811, 'subAddress': 0}, {'address': 417001457, 'brand': 'honda', 'bus': 1, 'ecu': 'gateway', 'fwVersion': b'\x0cH2462012\x00\x00\x00\x00 ', 'logging': True, 'obdMultiplexing': True, 'request': [b'"\xf1\x12'], 'responseAddress': 417001967, 'subAddress': 0}, {'address': 416952561, 'brand': 'honda', 'bus': 1, 'ecu': 'eps', 'fwVersion': b'\x0c BK7G255772C ', 'logging': True, 'obdMultiplexing': True, 'request': [b'"\xf1\x12'], 'responseAddress': 417001776, 'subAddress': 0}, {'address': 416944369, 'brand': 'honda', 'bus': 1, 'ecu': 'programmedFuelInjection', 'fwVersion': b'\x0e17-11-06 0131\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 'logging': True, 'obdMultiplexing': True, 'request': [b'"\xf1\x12'], 'responseAddress': 417001744, 'subAddress': 0}, {'address': 416950513, 'brand': 'honda', 'bus': 1, 'ecu': 'vsa', 'fwVersion': b'\x0b72920747323\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 'logging': True, 'obdMultiplexing': True, 'request': [b'"\xf1\x12'], 'responseAddress': 417001768, 'subAddress': 0}, {'address': 416986609, 'brand': 'honda', 'bus': 1, 'ecu': 'fwdCamera', 'fwVersion': b'\x0e11101711261084\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 'logging': True, 'obdMultiplexing': True, 'request': [b'"\xf1\x12'], 'responseAddress': 417001909, 'subAddress': 0}, {'address': 416964849, 'brand': 'honda', 'bus': 1, 'ecu': 'combinationMeter', 'fwVersion': b'\x18H3344390\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 'logging': True, 'obdMultiplexing': True, 'request': [b'"\xf1\x12'], 'responseAddress': 417001824, 'subAddress': 0}, {'address': 416985329, 'brand': 'honda', 'bus': 1, 'ecu': 'fwdRadar', 'fwVersion': b'\x0e04641711160A26\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 'logging': True, 'obdMultiplexing': True, 'request': [b'"\xf1\x12'], 'responseAddress': 417001904, 'subAddress': 0}, {'address': 416961521, 'brand': 'honda', 'bus': 1, 'ecu': 'srs', 'fwVersion': b'\x0bC1DQ009B14Y\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 'logging': True, 'obdMultiplexing': True, 'request': [b'"\xf1\x12'], 'responseAddress': 417001811, 'subAddress': 0}, {'address': 416952561, 'brand': 'honda', 'bus': 1, 'ecu': 'eps', 'fwVersion': b'39990-TGH-J020\x00\x00', 'logging': False, 'obdMultiplexing': False, 'request': [b'"\xf1\x81'], 'responseAddress': 417001776, 'subAddress': 0}, {'address': 416986609, 'brand': 'honda', 'bus': 1, 'ecu': 'fwdCamera', 'fwVersion': b'36161-TGH-A020\x00\x00', 'logging': False, 'obdMultiplexing': False, 'request': [b'"\xf1\x81'], 'responseAddress': 417001909, 'subAddress': 0}, {'address': 416985329, 'brand': 'honda', 'bus': 1, 'ecu': 'fwdRadar', 'fwVersion': b'36802-TGH-A030\x00\x00', 'logging': False, 'obdMultiplexing': False, 'request': [b'"\xf1\x81'], 'responseAddress': 417001904, 'subAddress': 0}, {'address': 416961521, 'brand': 'honda', 'bus': 1, 'ecu': 'srs', 'fwVersion': b'77959-TGH-E220\x00\x00', 'logging': False, 'obdMultiplexing': False, 'request': [b'"\xf1\x81'], 'responseAddress': 417001811, 'subAddress': 0}], 'carVin': 'SHHFK8790HU003163', * Update fingerprints.py Checked over them again * Update values.py Added whole new Civic Section * Update fingerprints.py CAR.HONDA_CIVIC_TYPE_R_FK8: {     (Ecu.gateway, 0x18DAF1EF, 0): [b'38897-TBA-A020\x00\x00'], # Gateway     (Ecu.abs, 0x18DAF128, 0): [b'57114-TGH-A130\x00\x00'], # VSA / ABS / ESP     (Ecu.eps, 0x18DAF130, 0): [b'39990-TGH-J020\x00\x00'], # Electric Power Steering     (Ecu.fwdCamera, 0x18DAF1B5, 0): [b'36161-TGH-A020\x00\x00'], # Forward Camera     (Ecu.engine, 0x18DAF110, 0): [b'37805-5BF-E030\x00\x00'], # Programmed Fuel Injection / ECM     (Ecu.combinationMeter, 0x18DAF160, 0): [b'78109-TGH-E310\x00\x00'],# Combination Meter     (Ecu.fwdRadar, 0x18DAF1B0, 0): [b'36802-TGH-A030\x00\x00'], # Forward Radar     (Ecu.srs, 0x18DAF153, 0): [b'77959-TGH-E220\x00\x00'], # SRS / Airbag   }, * Update values.py HONDA_CIVIC_TYPE_R_FK8 = HondaBoschPlatformConfig( [ HondaCarDocs( "Honda Civic Type R 2017-21", "EU Manual", min_steer_speed=12.0 * CV.MPH_TO_MS, ), ], CarSpecs( mass=1380, wheelbase=2.7, steerRatio=15.1, # Tuned via test drives (started at ~15.38 from stock Civic) centerToFrontRatio=0.4, # Recommended: matches standard Civic Bosch – helps lateral tuning ), {Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'}, # Same DBC as other FK8-era Civics ) * Update fingerprints.py Put the Honda_Civic_Bosch back as it was * Update fingerprints.py From ChatGPT checking * Update values.py Added Manual Trans to FK8 * Update fingerprints.py CAR.HONDA_CIVIC_TYPE_R_FK8: { (Ecu.gateway, 0x18daeff1, None): [b'38897-TBA-A020\x00\x00'], (Ecu.vsa, 0x18da28f1, None): [b'57114-TGH-A130\x00\x00'], (Ecu.eps, 0x18da30f1, None): [b'39990-TGH-J020\x00\x00'], (Ecu.programmedFuelInjection, 0x18da10f1, None): [b'37805-5BF-E030\x00\x00'], (Ecu.combinationMeter, 0x18da60f1, None): [b'78109-TGH-E310\x00\x00'], (Ecu.fwdRadar, 0x18dab0f1, None): [b'36802-TGH-A030\x00\x00'], (Ecu.fwdCamera, 0x18dab5f1, None): [b'36161-TGH-A020\x00\x00'], (Ecu.srs, 0x18da53f1, None): [b'77959-TGH-E220\x00\x00'], }, * Update values.py Added flags=HondaFlags.BOSCH | HondaFlags.ALLOW_MANUAL_TRANS, To FK8 * Keep CTR fingerprints under Bosch Civic * List FK8 as manual variant within Bosch Civic * Resort Euro FK8 fingerprints and remove duplicates --------- Co-authored-by: atmezferix Co-authored-by: Daniel Koepping Co-authored-by: Shane Smiskol --- opendbc/car/honda/fingerprints.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/opendbc/car/honda/fingerprints.py b/opendbc/car/honda/fingerprints.py index 4d5134b9..071c8774 100644 --- a/opendbc/car/honda/fingerprints.py +++ b/opendbc/car/honda/fingerprints.py @@ -225,6 +225,7 @@ FW_VERSIONS = { b'57114-TGG-G320\x00\x00', b'57114-TGG-L320\x00\x00', b'57114-TGG-L330\x00\x00', + b'57114-TGH-A130\x00\x00', b'57114-TGH-L130\x00\x00', b'57114-TGJ-Q330\x00\x00', b'57114-TGK-T320\x00\x00', @@ -239,6 +240,7 @@ FW_VERSIONS = { b'39990-TGG-A020\x00\x00', b'39990-TGG-A120\x00\x00', b'39990-TGG-J510\x00\x00', + b'39990-TGH-J020\x00\x00', b'39990-TGH-J530\x00\x00', b'39990-TGL-E130\x00\x00', b'39990-TGN-E120\x00\x00', @@ -255,6 +257,7 @@ FW_VERSIONS = { b'77959-TGG-J320\x00\x00', b'77959-TGG-Q810\x00\x00', b'77959-TGG-Z820\x00\x00', + b'77959-TGH-E220\x00\x00', b'77959-TGH-J110\x00\x00', ], (Ecu.fwdRadar, 0x18dab0f1, None): [ @@ -267,6 +270,7 @@ FW_VERSIONS = { b'36802-TGG-A130\x00\x00', b'36802-TGG-G040\x00\x00', b'36802-TGG-G130\x00\x00', + b'36802-TGH-A030\x00\x00', b'36802-TGH-A140\x00\x00', b'36802-TGK-Q030\x00\x00', b'36802-TGK-Q120\x00\x00', @@ -283,6 +287,7 @@ FW_VERSIONS = { b'36161-TGG-G070\x00\x00', b'36161-TGG-G130\x00\x00', b'36161-TGG-G140\x00\x00', + b'36161-TGH-A020\x00\x00', b'36161-TGH-A140\x00\x00', b'36161-TGK-Q040\x00\x00', b'36161-TGK-Q120\x00\x00', From 0185a52154b1b38276cf073a805b2e0d2a3537d8 Mon Sep 17 00:00:00 2001 From: Warren Togami Date: Fri, 23 Jan 2026 00:07:06 -0600 Subject: [PATCH 16/77] Toyota: Prevent EPS fault during unwind after sharp turn (#2859) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 2019-2021 RAV4 * 2021-2023 RAV4 Prime * 2021-2023 Sienna These Toyota models can experience a rare EPS fault. After a sharp, low-speed manual turn the human lets go of the wheel. During or shortly after the unwind the EPS faults. It can be difficult to reproduce. PR #24067 "Toyota: remove 100°/sec steering lockout" attempted to prevent this high angle rate EPS fault by cutting torque if more than 18 frames. I found reducing this threshold by just one frame fixes the problem. Co-authored-by: Jason Young --- opendbc/car/toyota/carcontroller.py | 2 +- opendbc/safety/modes/toyota.h | 4 ++-- opendbc/safety/tests/test_toyota.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/opendbc/car/toyota/carcontroller.py b/opendbc/car/toyota/carcontroller.py index 380c64b3..e5e3df96 100644 --- a/opendbc/car/toyota/carcontroller.py +++ b/opendbc/car/toyota/carcontroller.py @@ -29,7 +29,7 @@ MAX_PITCH_COMPENSATION = 1.5 # m/s^2 # LKA limits # EPS faults if you apply torque while the steering rate is above 100 deg/s for too long MAX_STEER_RATE = 100 # deg/s -MAX_STEER_RATE_FRAMES = 18 # tx control frames needed before torque can be cut +MAX_STEER_RATE_FRAMES = 17 # tx control frames needed before torque can be cut # EPS allows user torque above threshold for 50 frames before permanently faulting MAX_USER_TORQUE = 500 diff --git a/opendbc/safety/modes/toyota.h b/opendbc/safety/modes/toyota.h index 430726d8..3e0a8b7c 100644 --- a/opendbc/safety/modes/toyota.h +++ b/opendbc/safety/modes/toyota.h @@ -168,9 +168,9 @@ static bool toyota_tx_hook(const CANPacket_t *msg) { // the EPS faults when the steering angle rate is above a certain threshold for too long. to prevent this, // we allow setting STEER_REQUEST bit to 0 while maintaining the requested torque value for a single frame - .min_valid_request_frames = 18, + .min_valid_request_frames = 17, .max_invalid_request_frames = 1, - .min_valid_request_rt_interval = 171000, // 171ms; a ~10% buffer on cutting every 19 frames + .min_valid_request_rt_interval = 162000, // 162ms; a ~10% buffer on cutting every 18 frames .has_steer_req_tolerance = true, }; diff --git a/opendbc/safety/tests/test_toyota.py b/opendbc/safety/tests/test_toyota.py index dc94ddbe..35f1c2b1 100755 --- a/opendbc/safety/tests/test_toyota.py +++ b/opendbc/safety/tests/test_toyota.py @@ -133,7 +133,7 @@ class TestToyotaSafetyTorque(TestToyotaSafetyBase, common.MotorTorqueSteeringSaf TORQUE_MEAS_TOLERANCE = 1 # toyota safety adds one to be conservative for rounding # Safety around steering req bit - MIN_VALID_STEERING_FRAMES = 18 + MIN_VALID_STEERING_FRAMES = 17 MAX_INVALID_STEERING_FRAMES = 1 def setUp(self): From 1908668b05691564ea5fc80bc11b784a9dee0714 Mon Sep 17 00:00:00 2001 From: adeebshihadeh Date: Fri, 23 Jan 2026 08:09:41 +0000 Subject: [PATCH 17/77] docs: Scheduled auto-update CARS.md --- docs/CARS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CARS.md b/docs/CARS.md index cd8d210b..792cad67 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -1,6 +1,6 @@ -# Support Information for 385 Known Cars +# Support Information for 386 Known Cars |Make|Model|Package|Support Level| |---|---|---|:---:| @@ -19,6 +19,7 @@ |Acura|TLX 2018-20|All|[Community](#community)| |Acura|TLX 2021|All|[Upstream](#upstream)| |Acura|TLX 2022-23|All|[Community](#community)| +|Acura|TLX 2025|All|[Upstream](#upstream)| |Acura|ZDX 2024|All|[Not compatible](#can-bus-security)| |Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| From 32bb2ac0a5d1eac060d65a436ccf69564cf99c54 Mon Sep 17 00:00:00 2001 From: gs450h Date: Fri, 23 Jan 2026 17:48:54 -0600 Subject: [PATCH 18/77] Added GS_450h ECU details to fingerprints.py file under GS_F (#3015) * Added GS_450h ECU details to fingerprints.py file under GS_F * Update opendbc/car/toyota/fingerprints.py --------- Co-authored-by: Raul Rodriguez Jr Co-authored-by: Daniel Koepping Co-authored-by: Shane Smiskol --- opendbc/car/toyota/fingerprints.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/opendbc/car/toyota/fingerprints.py b/opendbc/car/toyota/fingerprints.py index 65396df2..67bd6665 100644 --- a/opendbc/car/toyota/fingerprints.py +++ b/opendbc/car/toyota/fingerprints.py @@ -1439,21 +1439,26 @@ FW_VERSIONS = { CAR.LEXUS_GS_F: { (Ecu.engine, 0x7e0, None): [ b'\x0233075200\x00\x00\x00\x00\x00\x00\x00\x00530B9000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x02330Y8000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x7b0, None): [ b'F152630700\x00\x00\x00\x00\x00\x00', + b'F152630400\x00\x00\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ b'881513016200\x00\x00\x00\x00', + b'881513011300\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B30551\x00\x00\x00\x00\x00\x00', + b'8965B30431\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'8821F4702000\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'8646F3002100\x00\x00\x00\x00', + b'8646F3001200\x00\x00\x00\x00', ], }, CAR.LEXUS_NX: { From 1b3e0ceab5d422345a3622dd57c51c3260c0b448 Mon Sep 17 00:00:00 2001 From: ugtthis <142481257+ugtthis@users.noreply.github.com> Date: Fri, 23 Jan 2026 22:35:45 -0600 Subject: [PATCH 19/77] CarDocs: Update car package name (#3065) update naming --- opendbc/car/extra_cars.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opendbc/car/extra_cars.py b/opendbc/car/extra_cars.py index fed2f5a4..a2dd470e 100644 --- a/opendbc/car/extra_cars.py +++ b/opendbc/car/extra_cars.py @@ -55,8 +55,8 @@ class CAR(Platforms): EXTRA_HYUNDAI = ExtraPlatformConfig( [ - CommunityCarDocs("Hyundai Palisade 2023-24", package="HDA2"), - CommunityCarDocs("Kia Telluride 2023-24", package="HDA2"), + CommunityCarDocs("Hyundai Palisade 2023-24", "Highway Driving Assist II"), + CommunityCarDocs("Kia Telluride 2023-24", "Highway Driving Assist II"), ], ) From 2000d7dafc19a5ca454553d79eb5af56e786321a Mon Sep 17 00:00:00 2001 From: smurf88sys Date: Fri, 23 Jan 2026 23:38:10 -0500 Subject: [PATCH 20/77] Tesla: Add support for Model 3 (#3050) Co-authored-by: Daniel Koepping --- opendbc/car/tesla/fingerprints.py | 1 + 1 file changed, 1 insertion(+) diff --git a/opendbc/car/tesla/fingerprints.py b/opendbc/car/tesla/fingerprints.py index 2ebaef0b..8d4b185e 100644 --- a/opendbc/car/tesla/fingerprints.py +++ b/opendbc/car/tesla/fingerprints.py @@ -18,6 +18,7 @@ FW_VERSIONS = { b'TeMYG4_Main_0.0.0 (59),E4H014.29.0', b'TeMYG4_Main_0.0.0 (65),E4H015.01.0', b'TeMYG4_Main_0.0.0 (67),E4H015.02.1', + b'TeMYG4_Main_0.0.0 (77),E4H015.04.5', b'TeMYG4_SingleECU_0.0.0 (33),E4S014.27', ], }, From 703b9efc527e16cedd2ade791f8c360e3955e774 Mon Sep 17 00:00:00 2001 From: Daniel Koepping Date: Fri, 23 Jan 2026 20:51:20 -0800 Subject: [PATCH 21/77] Car diff: rm except (#3062) * import to top * no except --- opendbc/car/tests/car_diff.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/opendbc/car/tests/car_diff.py b/opendbc/car/tests/car_diff.py index 09110238..12b3af05 100755 --- a/opendbc/car/tests/car_diff.py +++ b/opendbc/car/tests/car_diff.py @@ -15,6 +15,9 @@ from pathlib import Path from comma_car_segments import get_comma_car_segments_database, get_url +from opendbc.car import structs +from opendbc.car.can_definitions import CanData +from opendbc.car.car_helpers import can_fingerprint, interfaces from opendbc.car.logreader import LogReader, decompress_stream @@ -49,10 +52,6 @@ def load_can_messages(seg): def replay_segment(platform, can_msgs): - from opendbc.car import structs - from opendbc.car.can_definitions import CanData - from opendbc.car.car_helpers import interfaces, can_fingerprint - _can_msgs = ([CanData(can.address, can.dat, can.src) for can in m.can] for m in can_msgs) def can_recv(wait_for_one: bool = False) -> list[list[CanData]]: @@ -117,11 +116,8 @@ def download_refs(ref_path, platforms, segments): for platform in tqdm(platforms): for seg in segments.get(platform, []): filename = f"{platform}_{seg.replace('/', '_')}.zst" - try: - with urlopen(f"{base_url}/{filename}") as resp: - (Path(ref_path) / filename).write_bytes(resp.read()) - except Exception: - pass + with urlopen(f"{base_url}/{filename}") as resp: + (Path(ref_path) / filename).write_bytes(resp.read()) def run_replay(platforms, segments, ref_path, update, workers=4): @@ -246,8 +242,6 @@ def format_diff(diffs): def main(platform=None, segments_per_platform=10, update_refs=False, all_platforms=False): - from opendbc.car.car_helpers import interfaces - cwd = Path(__file__).resolve().parents[3] ref_path = cwd / DIFF_BUCKET if not update_refs: From 1538c5351a54967f6412e020b324308bcc5c9d9a Mon Sep 17 00:00:00 2001 From: MVL Date: Fri, 23 Jan 2026 23:51:55 -0500 Subject: [PATCH 22/77] Honda - support RDX 3G variants with brake booster (alt_brake) (#2973) Add ACURA_RDX_3G to alternate brake message check Co-authored-by: Daniel Koepping --- opendbc/car/honda/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc/car/honda/interface.py b/opendbc/car/honda/interface.py index 18fd2fbc..f8c60a5c 100755 --- a/opendbc/car/honda/interface.py +++ b/opendbc/car/honda/interface.py @@ -202,7 +202,7 @@ class CarInterface(CarInterfaceBase): CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) # These cars use alternate user brake msg (0x1BE) - if 0x1BE in fingerprint[CAN.pt] and candidate in (CAR.HONDA_ACCORD, CAR.HONDA_HRV_3G, *HONDA_BOSCH_CANFD): + if 0x1BE in fingerprint[CAN.pt] and candidate in (CAR.HONDA_ACCORD, CAR.HONDA_HRV_3G, CAR.ACURA_RDX_3G, *HONDA_BOSCH_CANFD): ret.flags |= HondaFlags.BOSCH_ALT_BRAKE.value if ret.flags & HondaFlags.BOSCH_ALT_BRAKE: From 2dc68791400ea0d65af50e69ffe0e8dec38ef224 Mon Sep 17 00:00:00 2001 From: royjr Date: Fri, 23 Jan 2026 23:58:31 -0500 Subject: [PATCH 23/77] HKG: add FW for 2022 Hyundai Kona Electric (#2981) Update fingerprints.py Co-authored-by: Daniel Koepping --- opendbc/car/hyundai/fingerprints.py | 1 + 1 file changed, 1 insertion(+) diff --git a/opendbc/car/hyundai/fingerprints.py b/opendbc/car/hyundai/fingerprints.py index 4db215b7..98da5215 100644 --- a/opendbc/car/hyundai/fingerprints.py +++ b/opendbc/car/hyundai/fingerprints.py @@ -698,6 +698,7 @@ FW_VERSIONS = { b'\xf1\x00OSP MDPS C 1.00 1.02 56310-K4271 4OEPC102', b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4271 4OEPC102', b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4970 4OEPC102', + b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4971 4OEPC102', b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4260\x00 4OEPC102', b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4261\x00 4OEPC102', b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4971\x00 4OEPC102', From eaba233b3502b8f8ce25f3eff92a3efa880fad34 Mon Sep 17 00:00:00 2001 From: Daniel Koepping Date: Fri, 23 Jan 2026 21:28:00 -0800 Subject: [PATCH 24/77] Car diff: add trace (#3066) --- opendbc/car/tests/car_diff.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/opendbc/car/tests/car_diff.py b/opendbc/car/tests/car_diff.py index 12b3af05..482d6743 100755 --- a/opendbc/car/tests/car_diff.py +++ b/opendbc/car/tests/car_diff.py @@ -6,6 +6,7 @@ import re import subprocess import sys import tempfile +import traceback import zstandard as zstd from tqdm import tqdm from tqdm.contrib.concurrent import process_map @@ -94,8 +95,8 @@ def process_segment(args): for diff in dict_diff(ref_state.to_dict(), state.to_dict(), ignore=IGNORE_FIELDS, tolerance=TOLERANCE): diffs.append((diff[1], i, diff[2], ts)) return (platform, seg, diffs, None) - except Exception as e: - return (platform, seg, [], str(e)) + except Exception: + return (platform, seg, [], traceback.format_exc()) def get_changed_platforms(cwd, database, interfaces): From f88c531576bb62a30edd9090c3e2c60efbd20061 Mon Sep 17 00:00:00 2001 From: commaci-public <60409688+commaci-public@users.noreply.github.com> Date: Fri, 23 Jan 2026 21:55:27 -0800 Subject: [PATCH 25/77] [bot] Update cppcheck to 2.19.1 (#2982) * [bot] Update cppcheck to 2.19.1 * update table * try assistance * not needed with --platform? * rm --------- Co-authored-by: Vehicle Researcher Co-authored-by: Shane Smiskol --- opendbc/safety/tests/misra/coverage_table | 2 +- opendbc/safety/tests/misra/install.sh | 2 +- opendbc/safety/tests/misra/test_misra.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/opendbc/safety/tests/misra/coverage_table b/opendbc/safety/tests/misra/coverage_table index 0395aba0..8753003f 100644 --- a/opendbc/safety/tests/misra/coverage_table +++ b/opendbc/safety/tests/misra/coverage_table @@ -9,7 +9,7 @@ 2.6 X (Cppcheck) 2.7 X (Addon) 3.1 X (Addon) -3.2 X (Addon) +3.2 4.1 X (Addon) 4.2 X (Addon) 5.1 X (Addon) diff --git a/opendbc/safety/tests/misra/install.sh b/opendbc/safety/tests/misra/install.sh index 25bb5a4e..f586fc32 100755 --- a/opendbc/safety/tests/misra/install.sh +++ b/opendbc/safety/tests/misra/install.sh @@ -15,7 +15,7 @@ fi cd $CPPCHECK_DIR -VERS="2.18.3" +VERS="2.19.1" if [ "$(git describe --tags --always)" != "$VERS" ]; then git fetch --all --tags --force git checkout $VERS diff --git a/opendbc/safety/tests/misra/test_misra.sh b/opendbc/safety/tests/misra/test_misra.sh index 072c51b0..67078428 100755 --- a/opendbc/safety/tests/misra/test_misra.sh +++ b/opendbc/safety/tests/misra/test_misra.sh @@ -37,7 +37,7 @@ cppcheck() { OPENDBC_ROOT=${OPENDBC_ROOT:-$BASEDIR} $CPPCHECK_DIR/cppcheck --inline-suppr -I $OPENDBC_ROOT \ - -I "$(gcc -print-file-name=include)" --suppress=*:/usr/lib/gcc/* --suppress=*:*/usr/lib/clang/* \ + --suppress=missingIncludeSystem \ --suppressions-list=$DIR/suppressions.txt \ --error-exitcode=2 --check-level=exhaustive --safety \ --platform=arm32-wchar_t4 $COMMON_DEFINES --checkers-report=$CHECKLIST.tmp \ From 1196a244b74751fd75b93c730e8430a3bdd0646b Mon Sep 17 00:00:00 2001 From: Greg Hogan Date: Sat, 24 Jan 2026 01:31:31 -0500 Subject: [PATCH 26/77] tesla: add radar CAN parsing and radar interface for model 3 (#3011) * tesla radar interface * add cmt --------- Co-authored-by: Daniel Koepping Co-authored-by: Shane Smiskol --- opendbc/car/tesla/interface.py | 14 ++++- opendbc/car/tesla/radar_interface.py | 89 +++++++++++++++++++++++++++ opendbc/car/tesla/tests/__init__.py | 0 opendbc/car/tesla/tests/test_tesla.py | 24 ++++++++ opendbc/car/tesla/values.py | 2 + 5 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 opendbc/car/tesla/radar_interface.py create mode 100644 opendbc/car/tesla/tests/__init__.py create mode 100644 opendbc/car/tesla/tests/test_tesla.py diff --git a/opendbc/car/tesla/interface.py b/opendbc/car/tesla/interface.py index c53ad621..a6e69528 100644 --- a/opendbc/car/tesla/interface.py +++ b/opendbc/car/tesla/interface.py @@ -1,13 +1,15 @@ -from opendbc.car import get_safety_config, structs +from opendbc.car import Bus, get_safety_config, structs from opendbc.car.interfaces import CarInterfaceBase from opendbc.car.tesla.carcontroller import CarController from opendbc.car.tesla.carstate import CarState -from opendbc.car.tesla.values import TeslaSafetyFlags, TeslaFlags, CAR, FSD_14_FW, Ecu +from opendbc.car.tesla.values import TeslaSafetyFlags, TeslaFlags, CAR, DBC, FSD_14_FW, Ecu +from opendbc.car.tesla.radar_interface import RadarInterface, RADAR_START_ADDR class CarInterface(CarInterfaceBase): CarState = CarState CarController = CarController + RadarInterface = RadarInterface @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: @@ -20,7 +22,13 @@ class CarInterface(CarInterfaceBase): ret.steerAtStandstill = True ret.steerControlType = structs.CarParams.SteerControlType.angle - ret.radarUnavailable = True + + # Radar support is intended to work for: + # - Tesla Model 3 vehicles built approximately mid-2017 through early-2021 + # - Tesla Model Y vehicles built approximately mid-2020 through early-2021 + # - Vehicles equipped with the Continental ARS4-B radar (used on HW2 / HW2.5 / early HW3) + # - Radar CAN lines must be tapped and connected to CAN bus 1 (normally not used for tesla vehicles) + ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or Bus.radar not in DBC[candidate] ret.alphaLongitudinalAvailable = True if alpha_long: diff --git a/opendbc/car/tesla/radar_interface.py b/opendbc/car/tesla/radar_interface.py new file mode 100644 index 00000000..e0cfcd1b --- /dev/null +++ b/opendbc/car/tesla/radar_interface.py @@ -0,0 +1,89 @@ +from opendbc.can import CANParser +from opendbc.car import Bus, structs +from opendbc.car.interfaces import RadarInterfaceBase +from opendbc.car.tesla.values import DBC + +RADAR_START_ADDR = 0x410 +RADAR_MSG_COUNT = 80 # 40 points * 2 messages each + + +def get_radar_can_parser(CP): + if Bus.radar not in DBC[CP.carFingerprint]: + return None + + messages = [('RadarStatus', 16)] + for i in range(RADAR_MSG_COUNT // 2): + messages.extend([ + (f'RadarPoint{i}_A', 16), + (f'RadarPoint{i}_B', 16), + ]) + + return CANParser(DBC[CP.carFingerprint][Bus.radar], messages, 1) + + +class RadarInterface(RadarInterfaceBase): + def __init__(self, CP): + super().__init__(CP) + self.updated_messages = set() + self.trigger_msg = RADAR_START_ADDR + RADAR_MSG_COUNT - 1 + self.track_id = 0 + + self.radar_off_can = CP.radarUnavailable + self.rcp = get_radar_can_parser(CP) + + def update(self, can_strings): + if self.radar_off_can or self.rcp is None: + return super().update(None) + + vls = self.rcp.update(can_strings) + self.updated_messages.update(vls) + + if self.trigger_msg not in self.updated_messages: + return None + + rr = self._update(self.updated_messages) + self.updated_messages.clear() + + return rr + + def _update(self, updated_messages): + ret = structs.RadarData() + if self.rcp is None: + return ret + + if not self.rcp.can_valid: + ret.errors.canError = True + + radar_status = self.rcp.vl['RadarStatus'] + if radar_status['shortTermUnavailable']: + ret.errors.radarUnavailableTemporary = True + if radar_status['sensorBlocked'] or radar_status['vehDynamicsError']: + ret.errors.radarFault = True + + for i in range(RADAR_MSG_COUNT // 2): + msg_a = self.rcp.vl[f'RadarPoint{i}_A'] + msg_b = self.rcp.vl[f'RadarPoint{i}_B'] + + # Make sure msg A and B are together + if msg_a['Index'] != msg_b['Index2']: + continue + + if not msg_a['Tracked']: + if i in self.pts: + del self.pts[i] + continue + + if i not in self.pts: + self.pts[i] = structs.RadarData.RadarPoint() + self.pts[i].trackId = self.track_id + self.track_id += 1 + + self.pts[i].dRel = msg_a['LongDist'] + self.pts[i].yRel = msg_a['LatDist'] + self.pts[i].vRel = msg_a['LongSpeed'] + self.pts[i].aRel = msg_a['LongAccel'] + self.pts[i].yvRel = msg_b['LatSpeed'] + self.pts[i].measured = bool(msg_a['Meas']) + + ret.points = list(self.pts.values()) + return ret diff --git a/opendbc/car/tesla/tests/__init__.py b/opendbc/car/tesla/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/opendbc/car/tesla/tests/test_tesla.py b/opendbc/car/tesla/tests/test_tesla.py new file mode 100644 index 00000000..2ccc777f --- /dev/null +++ b/opendbc/car/tesla/tests/test_tesla.py @@ -0,0 +1,24 @@ +from opendbc.car import gen_empty_fingerprint +from opendbc.car.tesla.interface import CarInterface +from opendbc.car.tesla.radar_interface import RADAR_START_ADDR +from opendbc.car.tesla.values import CAR + + +class TestTeslaFingerprint: + def test_radar_detection(self): + # Test radar availability detection for cars with radar DBC defined + for radar in (True, False): + fingerprint = gen_empty_fingerprint() + if radar: + fingerprint[1][RADAR_START_ADDR] = 8 + CP = CarInterface.get_params(CAR.TESLA_MODEL_3, fingerprint, [], False, False, False) + assert CP.radarUnavailable != radar + + def test_no_radar_car(self): + # Model X doesn't have radar DBC defined, should always be unavailable + for radar in (True, False): + fingerprint = gen_empty_fingerprint() + if radar: + fingerprint[1][RADAR_START_ADDR] = 8 + CP = CarInterface.get_params(CAR.TESLA_MODEL_X, fingerprint, [], False, False, False) + assert CP.radarUnavailable # Always unavailable since no radar DBC diff --git a/opendbc/car/tesla/values.py b/opendbc/car/tesla/values.py index 58635a9a..c8e1e2a9 100644 --- a/opendbc/car/tesla/values.py +++ b/opendbc/car/tesla/values.py @@ -48,6 +48,7 @@ class CAR(Platforms): TeslaCarDocsHW4("Tesla Model 3 (with HW4) 2024-25"), ], CarSpecs(mass=1899., wheelbase=2.875, steerRatio=12.0), + {Bus.party: 'tesla_model3_party', Bus.radar: 'tesla_radar_continental_generated'}, ) TESLA_MODEL_Y = TeslaPlatformConfig( [ @@ -55,6 +56,7 @@ class CAR(Platforms): TeslaCarDocsHW4("Tesla Model Y (with HW4) 2024-25"), ], CarSpecs(mass=2072., wheelbase=2.890, steerRatio=12.0), + {Bus.party: 'tesla_model3_party', Bus.radar: 'tesla_radar_continental_generated'}, ) TESLA_MODEL_X = TeslaPlatformConfig( [TeslaCarDocsHW4("Tesla Model X (with HW4) 2024")], From d424d1f247384b68923b8093875e1a370ef8221d Mon Sep 17 00:00:00 2001 From: adeebshihadeh Date: Sat, 24 Jan 2026 08:08:20 +0000 Subject: [PATCH 27/77] docs: Scheduled auto-update CARS.md --- docs/CARS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 792cad67..da8cb49c 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -150,7 +150,7 @@ |Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Nexo 2021|All|[Upstream](#upstream)| |Hyundai|Palisade 2020-22|All|[Upstream](#upstream)| -|Hyundai|Palisade 2023-24|HDA2|[Community](#community)| +|Hyundai|Palisade 2023-24|Highway Driving Assist II|[Community](#community)| |Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Santa Fe 2019-20|All|[Upstream](#upstream)| |Hyundai|Santa Fe 2021-23|All|[Upstream](#upstream)| @@ -209,7 +209,7 @@ |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Stinger 2022-23|All|[Upstream](#upstream)| |Kia|Telluride 2020-22|All|[Upstream](#upstream)| -|Kia|Telluride 2023-24|HDA2|[Community](#community)| +|Kia|Telluride 2023-24|Highway Driving Assist II|[Community](#community)| |Lexus|CT Hybrid 2017-18|Lexus Safety System+|[Upstream](#upstream)| |Lexus|ES 2017-18|All|[Upstream](#upstream)| |Lexus|ES 2019-25|All|[Upstream](#upstream)| From 2a1ba5e40bd56b7c5211c45bb6df01906f5e9313 Mon Sep 17 00:00:00 2001 From: Nikita Pylypyuk <147505783+nikitap066@users.noreply.github.com> Date: Tue, 27 Jan 2026 03:57:31 +0000 Subject: [PATCH 28/77] Mazda: Add cruise button events for accel and decel (#3027) * added button events for accel and decel * move down --------- Co-authored-by: Daniel Koepping Co-authored-by: Shane Smiskol --- opendbc/car/mazda/carstate.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/opendbc/car/mazda/carstate.py b/opendbc/car/mazda/carstate.py index 074a13c2..34919e04 100644 --- a/opendbc/car/mazda/carstate.py +++ b/opendbc/car/mazda/carstate.py @@ -19,6 +19,8 @@ class CarState(CarStateBase): self.lkas_allowed_speed = False self.distance_button = 0 + self.accel_button = 0 + self.decel_button = 0 def update(self, can_parsers) -> structs.CarState: cp = can_parsers[Bus.pt] @@ -26,9 +28,6 @@ class CarState(CarStateBase): ret = structs.CarState() - prev_distance_button = self.distance_button - self.distance_button = cp.vl["CRZ_BTNS"]["DISTANCE_LESS"] - self.parse_wheel_speeds(ret, cp.vl["WHEEL_SPEEDS"]["FL"], cp.vl["WHEEL_SPEEDS"]["FR"], @@ -112,8 +111,19 @@ class CarState(CarStateBase): self.cam_laneinfo = cp_cam.vl["CAM_LANEINFO"] ret.steerFaultPermanent = cp_cam.vl["CAM_LKAS"]["ERR_BIT_1"] == 1 - # TODO: add button types for inc and dec - ret.buttonEvents = create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise}) + # cruise control button events: distance, inc, and dec + prev_distance_button = self.distance_button + prev_accel_button = self.accel_button + prev_decel_button = self.decel_button + self.distance_button = cp.vl["CRZ_BTNS"]["DISTANCE_LESS"] + self.accel_button = cp.vl["CRZ_BTNS"]["RES"] + self.decel_button = cp.vl["CRZ_BTNS"]["SET_M"] + + ret.buttonEvents = [ + *create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise}), + *create_button_events(self.accel_button, prev_accel_button, {1: ButtonType.accelCruise}), + *create_button_events(self.decel_button, prev_decel_button, {1: ButtonType.decelCruise}), + ] return ret From dd606ee88b273a77415fb1d46cca5c7d0b5b39da Mon Sep 17 00:00:00 2001 From: FELMONON <125313419+FELMONON@users.noreply.github.com> Date: Mon, 26 Jan 2026 22:00:38 -0700 Subject: [PATCH 29/77] car tests: cache hypothesis strategies (#3052) * car tests: cache hypothesis strategies at module level Move strategy creation from inside get_fuzzy_car_interface() to module level to avoid recreating strategies on every test call. Strategy creation is expensive and doing it once at import time significantly speeds up test execution. This addresses commaai/openpilot#32536 - "Speedup test_car_interfaces" Co-Authored-By: Claude Opus 4.5 * use cache instead --------- Co-authored-by: Felmon Fekadu Co-authored-by: Claude Opus 4.5 Co-authored-by: Shane Smiskol --- opendbc/car/tests/test_car_interfaces.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/opendbc/car/tests/test_car_interfaces.py b/opendbc/car/tests/test_car_interfaces.py index a329ee3b..1945bb5a 100644 --- a/opendbc/car/tests/test_car_interfaces.py +++ b/opendbc/car/tests/test_car_interfaces.py @@ -2,6 +2,7 @@ import os import math import hypothesis.strategies as st import pytest +from functools import cache from hypothesis import Phase, given, settings from collections.abc import Callable from typing import Any @@ -27,7 +28,8 @@ DLC_TO_LEN = [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64] MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '15')) -def get_fuzzy_car_interface(car_name: str, draw: DrawType) -> CarInterfaceBase: +@cache +def get_fuzzy_strategy(): # Fuzzy CAN fingerprints and FW versions to test more states of the CarInterface fingerprint_strategy = st.fixed_dictionaries({0: st.dictionaries(st.integers(min_value=0, max_value=0x800), st.sampled_from(DLC_TO_LEN))}) @@ -44,8 +46,11 @@ def get_fuzzy_car_interface(car_name: str, draw: DrawType) -> CarInterfaceBase: 'car_fw': car_fw_strategy, 'alpha_long': st.booleans(), }) + return params_strategy - params: dict = draw(params_strategy) + +def get_fuzzy_car_interface(car_name: str, draw: DrawType) -> CarInterfaceBase: + params: dict = draw(get_fuzzy_strategy()) # reduce search space by duplicating CAN fingerprints across all buses params['fingerprints'] |= {key + 1: params['fingerprints'][0] for key in range(6)} From c7319ff209432598de41879b6c1f670c20d685a9 Mon Sep 17 00:00:00 2001 From: commaci-public <60409688+commaci-public@users.noreply.github.com> Date: Mon, 26 Jan 2026 21:02:10 -0800 Subject: [PATCH 30/77] [bot] Update uv.lock (#3071) Co-authored-by: Vehicle Researcher --- uv.lock | 153 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 76 insertions(+), 77 deletions(-) diff --git a/uv.lock b/uv.lock index 4b016c13..a5a81f54 100644 --- a/uv.lock +++ b/uv.lock @@ -181,37 +181,37 @@ wheels = [ [[package]] name = "coverage" -version = "7.13.1" +version = "7.13.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/23/f9/e92df5e07f3fc8d4c7f9a0f146ef75446bf870351cd37b788cf5897f8079/coverage-7.13.1.tar.gz", hash = "sha256:b7593fe7eb5feaa3fbb461ac79aac9f9fc0387a5ca8080b0c6fe2ca27b091afd", size = 825862, upload-time = "2025-12-28T15:42:56.969Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ad/49/349848445b0e53660e258acbcc9b0d014895b6739237920886672240f84b/coverage-7.13.2.tar.gz", hash = "sha256:044c6951ec37146b72a50cc81ef02217d27d4c3640efd2640311393cbbf143d3", size = 826523, upload-time = "2026-01-25T13:00:04.889Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/9b/77baf488516e9ced25fc215a6f75d803493fc3f6a1a1227ac35697910c2a/coverage-7.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a55d509a1dc5a5b708b5dad3b5334e07a16ad4c2185e27b40e4dba796ab7f88", size = 218755, upload-time = "2025-12-28T15:40:30.812Z" }, - { url = "https://files.pythonhosted.org/packages/d7/cd/7ab01154e6eb79ee2fab76bf4d89e94c6648116557307ee4ebbb85e5c1bf/coverage-7.13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4d010d080c4888371033baab27e47c9df7d6fb28d0b7b7adf85a4a49be9298b3", size = 219257, upload-time = "2025-12-28T15:40:32.333Z" }, - { url = "https://files.pythonhosted.org/packages/01/d5/b11ef7863ffbbdb509da0023fad1e9eda1c0eaea61a6d2ea5b17d4ac706e/coverage-7.13.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d938b4a840fb1523b9dfbbb454f652967f18e197569c32266d4d13f37244c3d9", size = 249657, upload-time = "2025-12-28T15:40:34.1Z" }, - { url = "https://files.pythonhosted.org/packages/f7/7c/347280982982383621d29b8c544cf497ae07ac41e44b1ca4903024131f55/coverage-7.13.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bf100a3288f9bb7f919b87eb84f87101e197535b9bd0e2c2b5b3179633324fee", size = 251581, upload-time = "2025-12-28T15:40:36.131Z" }, - { url = "https://files.pythonhosted.org/packages/82/f6/ebcfed11036ade4c0d75fa4453a6282bdd225bc073862766eec184a4c643/coverage-7.13.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef6688db9bf91ba111ae734ba6ef1a063304a881749726e0d3575f5c10a9facf", size = 253691, upload-time = "2025-12-28T15:40:37.626Z" }, - { url = "https://files.pythonhosted.org/packages/02/92/af8f5582787f5d1a8b130b2dcba785fa5e9a7a8e121a0bb2220a6fdbdb8a/coverage-7.13.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0b609fc9cdbd1f02e51f67f51e5aee60a841ef58a68d00d5ee2c0faf357481a3", size = 249799, upload-time = "2025-12-28T15:40:39.47Z" }, - { url = "https://files.pythonhosted.org/packages/24/aa/0e39a2a3b16eebf7f193863323edbff38b6daba711abaaf807d4290cf61a/coverage-7.13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c43257717611ff5e9a1d79dce8e47566235ebda63328718d9b65dd640bc832ef", size = 251389, upload-time = "2025-12-28T15:40:40.954Z" }, - { url = "https://files.pythonhosted.org/packages/73/46/7f0c13111154dc5b978900c0ccee2e2ca239b910890e674a77f1363d483e/coverage-7.13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e09fbecc007f7b6afdfb3b07ce5bd9f8494b6856dd4f577d26c66c391b829851", size = 249450, upload-time = "2025-12-28T15:40:42.489Z" }, - { url = "https://files.pythonhosted.org/packages/ac/ca/e80da6769e8b669ec3695598c58eef7ad98b0e26e66333996aee6316db23/coverage-7.13.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:a03a4f3a19a189919c7055098790285cc5c5b0b3976f8d227aea39dbf9f8bfdb", size = 249170, upload-time = "2025-12-28T15:40:44.279Z" }, - { url = "https://files.pythonhosted.org/packages/af/18/9e29baabdec1a8644157f572541079b4658199cfd372a578f84228e860de/coverage-7.13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3820778ea1387c2b6a818caec01c63adc5b3750211af6447e8dcfb9b6f08dbba", size = 250081, upload-time = "2025-12-28T15:40:45.748Z" }, - { url = "https://files.pythonhosted.org/packages/00/f8/c3021625a71c3b2f516464d322e41636aea381018319050a8114105872ee/coverage-7.13.1-cp311-cp311-win32.whl", hash = "sha256:ff10896fa55167371960c5908150b434b71c876dfab97b69478f22c8b445ea19", size = 221281, upload-time = "2025-12-28T15:40:47.232Z" }, - { url = "https://files.pythonhosted.org/packages/27/56/c216625f453df6e0559ed666d246fcbaaa93f3aa99eaa5080cea1229aa3d/coverage-7.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:a998cc0aeeea4c6d5622a3754da5a493055d2d95186bad877b0a34ea6e6dbe0a", size = 222215, upload-time = "2025-12-28T15:40:49.19Z" }, - { url = "https://files.pythonhosted.org/packages/5c/9a/be342e76f6e531cae6406dc46af0d350586f24d9b67fdfa6daee02df71af/coverage-7.13.1-cp311-cp311-win_arm64.whl", hash = "sha256:fea07c1a39a22614acb762e3fbbb4011f65eedafcb2948feeef641ac78b4ee5c", size = 220886, upload-time = "2025-12-28T15:40:51.067Z" }, - { url = "https://files.pythonhosted.org/packages/ce/8a/87af46cccdfa78f53db747b09f5f9a21d5fc38d796834adac09b30a8ce74/coverage-7.13.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6f34591000f06e62085b1865c9bc5f7858df748834662a51edadfd2c3bfe0dd3", size = 218927, upload-time = "2025-12-28T15:40:52.814Z" }, - { url = "https://files.pythonhosted.org/packages/82/a8/6e22fdc67242a4a5a153f9438d05944553121c8f4ba70cb072af4c41362e/coverage-7.13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b67e47c5595b9224599016e333f5ec25392597a89d5744658f837d204e16c63e", size = 219288, upload-time = "2025-12-28T15:40:54.262Z" }, - { url = "https://files.pythonhosted.org/packages/d0/0a/853a76e03b0f7c4375e2ca025df45c918beb367f3e20a0a8e91967f6e96c/coverage-7.13.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e7b8bd70c48ffb28461ebe092c2345536fb18bbbf19d287c8913699735f505c", size = 250786, upload-time = "2025-12-28T15:40:56.059Z" }, - { url = "https://files.pythonhosted.org/packages/ea/b4/694159c15c52b9f7ec7adf49d50e5f8ee71d3e9ef38adb4445d13dd56c20/coverage-7.13.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c223d078112e90dc0e5c4e35b98b9584164bea9fbbd221c0b21c5241f6d51b62", size = 253543, upload-time = "2025-12-28T15:40:57.585Z" }, - { url = "https://files.pythonhosted.org/packages/96/b2/7f1f0437a5c855f87e17cf5d0dc35920b6440ff2b58b1ba9788c059c26c8/coverage-7.13.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:794f7c05af0763b1bbd1b9e6eff0e52ad068be3b12cd96c87de037b01390c968", size = 254635, upload-time = "2025-12-28T15:40:59.443Z" }, - { url = "https://files.pythonhosted.org/packages/e9/d1/73c3fdb8d7d3bddd9473c9c6a2e0682f09fc3dfbcb9c3f36412a7368bcab/coverage-7.13.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0642eae483cc8c2902e4af7298bf886d605e80f26382124cddc3967c2a3df09e", size = 251202, upload-time = "2025-12-28T15:41:01.328Z" }, - { url = "https://files.pythonhosted.org/packages/66/3c/f0edf75dcc152f145d5598329e864bbbe04ab78660fe3e8e395f9fff010f/coverage-7.13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f5e772ed5fef25b3de9f2008fe67b92d46831bd2bc5bdc5dd6bfd06b83b316f", size = 252566, upload-time = "2025-12-28T15:41:03.319Z" }, - { url = "https://files.pythonhosted.org/packages/17/b3/e64206d3c5f7dcbceafd14941345a754d3dbc78a823a6ed526e23b9cdaab/coverage-7.13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:45980ea19277dc0a579e432aef6a504fe098ef3a9032ead15e446eb0f1191aee", size = 250711, upload-time = "2025-12-28T15:41:06.411Z" }, - { url = "https://files.pythonhosted.org/packages/dc/ad/28a3eb970a8ef5b479ee7f0c484a19c34e277479a5b70269dc652b730733/coverage-7.13.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f18eca6028ffa62adbd185a8f1e1dd242f2e68164dba5c2b74a5204850b4cf", size = 250278, upload-time = "2025-12-28T15:41:08.285Z" }, - { url = "https://files.pythonhosted.org/packages/54/e3/c8f0f1a93133e3e1291ca76cbb63565bd4b5c5df63b141f539d747fff348/coverage-7.13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8dca5590fec7a89ed6826fce625595279e586ead52e9e958d3237821fbc750c", size = 252154, upload-time = "2025-12-28T15:41:09.969Z" }, - { url = "https://files.pythonhosted.org/packages/d0/bf/9939c5d6859c380e405b19e736321f1c7d402728792f4c752ad1adcce005/coverage-7.13.1-cp312-cp312-win32.whl", hash = "sha256:ff86d4e85188bba72cfb876df3e11fa243439882c55957184af44a35bd5880b7", size = 221487, upload-time = "2025-12-28T15:41:11.468Z" }, - { url = "https://files.pythonhosted.org/packages/fa/dc/7282856a407c621c2aad74021680a01b23010bb8ebf427cf5eacda2e876f/coverage-7.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:16cc1da46c04fb0fb128b4dc430b78fa2aba8a6c0c9f8eb391fd5103409a6ac6", size = 222299, upload-time = "2025-12-28T15:41:13.386Z" }, - { url = "https://files.pythonhosted.org/packages/10/79/176a11203412c350b3e9578620013af35bcdb79b651eb976f4a4b32044fa/coverage-7.13.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d9bc218650022a768f3775dd7fdac1886437325d8d295d923ebcfef4892ad5c", size = 220941, upload-time = "2025-12-28T15:41:14.975Z" }, - { url = "https://files.pythonhosted.org/packages/cc/48/d9f421cb8da5afaa1a64570d9989e00fb7955e6acddc5a12979f7666ef60/coverage-7.13.1-py3-none-any.whl", hash = "sha256:2016745cb3ba554469d02819d78958b571792bb68e31302610e898f80dd3a573", size = 210722, upload-time = "2025-12-28T15:42:54.901Z" }, + { url = "https://files.pythonhosted.org/packages/6c/01/abca50583a8975bb6e1c59eff67ed8e48bb127c07dad5c28d9e96ccc09ec/coverage-7.13.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:060ebf6f2c51aff5ba38e1f43a2095e087389b1c69d559fde6049a4b0001320e", size = 218971, upload-time = "2026-01-25T12:57:36.953Z" }, + { url = "https://files.pythonhosted.org/packages/eb/0e/b6489f344d99cd1e5b4d5e1be52dfd3f8a3dc5112aa6c33948da8cabad4e/coverage-7.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1ea8ca9db5e7469cd364552985e15911548ea5b69c48a17291f0cac70484b2e", size = 219473, upload-time = "2026-01-25T12:57:38.934Z" }, + { url = "https://files.pythonhosted.org/packages/17/11/db2f414915a8e4ec53f60b17956c27f21fb68fcf20f8a455ce7c2ccec638/coverage-7.13.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b780090d15fd58f07cf2011943e25a5f0c1c894384b13a216b6c86c8a8a7c508", size = 249896, upload-time = "2026-01-25T12:57:40.365Z" }, + { url = "https://files.pythonhosted.org/packages/80/06/0823fe93913663c017e508e8810c998c8ebd3ec2a5a85d2c3754297bdede/coverage-7.13.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:88a800258d83acb803c38175b4495d293656d5fac48659c953c18e5f539a274b", size = 251810, upload-time = "2026-01-25T12:57:42.045Z" }, + { url = "https://files.pythonhosted.org/packages/61/dc/b151c3cc41b28cdf7f0166c5fa1271cbc305a8ec0124cce4b04f74791a18/coverage-7.13.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6326e18e9a553e674d948536a04a80d850a5eeefe2aae2e6d7cf05d54046c01b", size = 253920, upload-time = "2026-01-25T12:57:44.026Z" }, + { url = "https://files.pythonhosted.org/packages/2d/35/e83de0556e54a4729a2b94ea816f74ce08732e81945024adee46851c2264/coverage-7.13.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:59562de3f797979e1ff07c587e2ac36ba60ca59d16c211eceaa579c266c5022f", size = 250025, upload-time = "2026-01-25T12:57:45.624Z" }, + { url = "https://files.pythonhosted.org/packages/39/67/af2eb9c3926ce3ea0d58a0d2516fcbdacf7a9fc9559fe63076beaf3f2596/coverage-7.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:27ba1ed6f66b0e2d61bfa78874dffd4f8c3a12f8e2b5410e515ab345ba7bc9c3", size = 251612, upload-time = "2026-01-25T12:57:47.713Z" }, + { url = "https://files.pythonhosted.org/packages/26/62/5be2e25f3d6c711d23b71296f8b44c978d4c8b4e5b26871abfc164297502/coverage-7.13.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8be48da4d47cc68754ce643ea50b3234557cbefe47c2f120495e7bd0a2756f2b", size = 249670, upload-time = "2026-01-25T12:57:49.378Z" }, + { url = "https://files.pythonhosted.org/packages/b3/51/400d1b09a8344199f9b6a6fc1868005d766b7ea95e7882e494fa862ca69c/coverage-7.13.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2a47a4223d3361b91176aedd9d4e05844ca67d7188456227b6bf5e436630c9a1", size = 249395, upload-time = "2026-01-25T12:57:50.86Z" }, + { url = "https://files.pythonhosted.org/packages/e0/36/f02234bc6e5230e2f0a63fd125d0a2093c73ef20fdf681c7af62a140e4e7/coverage-7.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c6f141b468740197d6bd38f2b26ade124363228cc3f9858bd9924ab059e00059", size = 250298, upload-time = "2026-01-25T12:57:52.287Z" }, + { url = "https://files.pythonhosted.org/packages/b0/06/713110d3dd3151b93611c9cbfc65c15b4156b44f927fced49ac0b20b32a4/coverage-7.13.2-cp311-cp311-win32.whl", hash = "sha256:89567798404af067604246e01a49ef907d112edf2b75ef814b1364d5ce267031", size = 221485, upload-time = "2026-01-25T12:57:53.876Z" }, + { url = "https://files.pythonhosted.org/packages/16/0c/3ae6255fa1ebcb7dec19c9a59e85ef5f34566d1265c70af5b2fc981da834/coverage-7.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:21dd57941804ae2ac7e921771a5e21bbf9aabec317a041d164853ad0a96ce31e", size = 222421, upload-time = "2026-01-25T12:57:55.433Z" }, + { url = "https://files.pythonhosted.org/packages/b5/37/fabc3179af4d61d89ea47bd04333fec735cd5e8b59baad44fed9fc4170d7/coverage-7.13.2-cp311-cp311-win_arm64.whl", hash = "sha256:10758e0586c134a0bafa28f2d37dd2cdb5e4a90de25c0fc0c77dabbad46eca28", size = 221088, upload-time = "2026-01-25T12:57:57.41Z" }, + { url = "https://files.pythonhosted.org/packages/46/39/e92a35f7800222d3f7b2cbb7bbc3b65672ae8d501cb31801b2d2bd7acdf1/coverage-7.13.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f106b2af193f965d0d3234f3f83fc35278c7fb935dfbde56ae2da3dd2c03b84d", size = 219142, upload-time = "2026-01-25T12:58:00.448Z" }, + { url = "https://files.pythonhosted.org/packages/45/7a/8bf9e9309c4c996e65c52a7c5a112707ecdd9fbaf49e10b5a705a402bbb4/coverage-7.13.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78f45d21dc4d5d6bd29323f0320089ef7eae16e4bef712dff79d184fa7330af3", size = 219503, upload-time = "2026-01-25T12:58:02.451Z" }, + { url = "https://files.pythonhosted.org/packages/87/93/17661e06b7b37580923f3f12406ac91d78aeed293fb6da0b69cc7957582f/coverage-7.13.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fae91dfecd816444c74531a9c3d6ded17a504767e97aa674d44f638107265b99", size = 251006, upload-time = "2026-01-25T12:58:04.059Z" }, + { url = "https://files.pythonhosted.org/packages/12/f0/f9e59fb8c310171497f379e25db060abef9fa605e09d63157eebec102676/coverage-7.13.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:264657171406c114787b441484de620e03d8f7202f113d62fcd3d9688baa3e6f", size = 253750, upload-time = "2026-01-25T12:58:05.574Z" }, + { url = "https://files.pythonhosted.org/packages/e5/b1/1935e31add2232663cf7edd8269548b122a7d100047ff93475dbaaae673e/coverage-7.13.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae47d8dcd3ded0155afbb59c62bd8ab07ea0fd4902e1c40567439e6db9dcaf2f", size = 254862, upload-time = "2026-01-25T12:58:07.647Z" }, + { url = "https://files.pythonhosted.org/packages/af/59/b5e97071ec13df5f45da2b3391b6cdbec78ba20757bc92580a5b3d5fa53c/coverage-7.13.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8a0b33e9fd838220b007ce8f299114d406c1e8edb21336af4c97a26ecfd185aa", size = 251420, upload-time = "2026-01-25T12:58:09.309Z" }, + { url = "https://files.pythonhosted.org/packages/3f/75/9495932f87469d013dc515fb0ce1aac5fa97766f38f6b1a1deb1ee7b7f3a/coverage-7.13.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b3becbea7f3ce9a2d4d430f223ec15888e4deb31395840a79e916368d6004cce", size = 252786, upload-time = "2026-01-25T12:58:10.909Z" }, + { url = "https://files.pythonhosted.org/packages/6a/59/af550721f0eb62f46f7b8cb7e6f1860592189267b1c411a4e3a057caacee/coverage-7.13.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f819c727a6e6eeb8711e4ce63d78c620f69630a2e9d53bc95ca5379f57b6ba94", size = 250928, upload-time = "2026-01-25T12:58:12.449Z" }, + { url = "https://files.pythonhosted.org/packages/9b/b1/21b4445709aae500be4ab43bbcfb4e53dc0811c3396dcb11bf9f23fd0226/coverage-7.13.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:4f7b71757a3ab19f7ba286e04c181004c1d61be921795ee8ba6970fd0ec91da5", size = 250496, upload-time = "2026-01-25T12:58:14.047Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b1/0f5d89dfe0392990e4f3980adbde3eb34885bc1effb2dc369e0bf385e389/coverage-7.13.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b7fc50d2afd2e6b4f6f2f403b70103d280a8e0cb35320cbbe6debcda02a1030b", size = 252373, upload-time = "2026-01-25T12:58:15.976Z" }, + { url = "https://files.pythonhosted.org/packages/01/c9/0cf1a6a57a9968cc049a6b896693faa523c638a5314b1fc374eb2b2ac904/coverage-7.13.2-cp312-cp312-win32.whl", hash = "sha256:292250282cf9bcf206b543d7608bda17ca6fc151f4cbae949fc7e115112fbd41", size = 221696, upload-time = "2026-01-25T12:58:17.517Z" }, + { url = "https://files.pythonhosted.org/packages/4d/05/d7540bf983f09d32803911afed135524570f8c47bb394bf6206c1dc3a786/coverage-7.13.2-cp312-cp312-win_amd64.whl", hash = "sha256:eeea10169fac01549a7921d27a3e517194ae254b542102267bef7a93ed38c40e", size = 222504, upload-time = "2026-01-25T12:58:19.115Z" }, + { url = "https://files.pythonhosted.org/packages/15/8b/1a9f037a736ced0a12aacf6330cdaad5008081142a7070bc58b0f7930cbc/coverage-7.13.2-cp312-cp312-win_arm64.whl", hash = "sha256:2a5b567f0b635b592c917f96b9a9cb3dbd4c320d03f4bf94e9084e494f2e8894", size = 221120, upload-time = "2026-01-25T12:58:21.334Z" }, + { url = "https://files.pythonhosted.org/packages/d2/db/d291e30fdf7ea617a335531e72294e0c723356d7fdde8fba00610a76bda9/coverage-7.13.2-py3-none-any.whl", hash = "sha256:40ce1ea1e25125556d8e76bd0b61500839a07944cc287ac21d5626f3e620cad5", size = 210943, upload-time = "2026-01-25T13:00:02.388Z" }, ] [package.optional-dependencies] @@ -642,11 +642,11 @@ provides-extras = ["testing", "docs", "examples"] [[package]] name = "packaging" -version = "25.0" +version = "26.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, ] [[package]] @@ -738,11 +738,11 @@ wheels = [ [[package]] name = "pycparser" -version = "2.23" +version = "3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, ] [[package]] @@ -775,11 +775,11 @@ wheels = [ [[package]] name = "pyparsing" -version = "3.3.1" +version = "3.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/33/c1/1d9de9aeaa1b89b0186e5fe23294ff6517fce1bc69149185577cd31016b2/pyparsing-3.3.1.tar.gz", hash = "sha256:47fad0f17ac1e2cad3de3b458570fbc9b03560aa029ed5e16ee5554da9a2251c", size = 1550512, upload-time = "2025-12-23T03:14:04.391Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/40/2614036cdd416452f5bf98ec037f38a1afb17f327cb8e6b652d4729e0af8/pyparsing-3.3.1-py3-none-any.whl", hash = "sha256:023b5e7e5520ad96642e2c6db4cb683d3970bd640cdf7115049a6e9c3682df82", size = 121793, upload-time = "2025-12-23T03:14:02.103Z" }, + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, ] [[package]] @@ -911,28 +911,28 @@ wheels = [ [[package]] name = "ruff" -version = "0.14.13" +version = "0.14.14" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/0a/1914efb7903174b381ee2ffeebb4253e729de57f114e63595114c8ca451f/ruff-0.14.13.tar.gz", hash = "sha256:83cd6c0763190784b99650a20fec7633c59f6ebe41c5cc9d45ee42749563ad47", size = 6059504, upload-time = "2026-01-15T20:15:16.918Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size = 4515732, upload-time = "2026-01-22T22:30:17.527Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/ae/0deefbc65ca74b0ab1fd3917f94dc3b398233346a74b8bbb0a916a1a6bf6/ruff-0.14.13-py3-none-linux_armv6l.whl", hash = "sha256:76f62c62cd37c276cb03a275b198c7c15bd1d60c989f944db08a8c1c2dbec18b", size = 13062418, upload-time = "2026-01-15T20:14:50.779Z" }, - { url = "https://files.pythonhosted.org/packages/47/df/5916604faa530a97a3c154c62a81cb6b735c0cb05d1e26d5ad0f0c8ac48a/ruff-0.14.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:914a8023ece0528d5cc33f5a684f5f38199bbb566a04815c2c211d8f40b5d0ed", size = 13442344, upload-time = "2026-01-15T20:15:07.94Z" }, - { url = "https://files.pythonhosted.org/packages/4c/f3/e0e694dd69163c3a1671e102aa574a50357536f18a33375050334d5cd517/ruff-0.14.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d24899478c35ebfa730597a4a775d430ad0d5631b8647a3ab368c29b7e7bd063", size = 12354720, upload-time = "2026-01-15T20:15:09.854Z" }, - { url = "https://files.pythonhosted.org/packages/c3/e8/67f5fcbbaee25e8fc3b56cc33e9892eca7ffe09f773c8e5907757a7e3bdb/ruff-0.14.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aaf3870f14d925bbaf18b8a2347ee0ae7d95a2e490e4d4aea6813ed15ebc80e", size = 12774493, upload-time = "2026-01-15T20:15:20.908Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ce/d2e9cb510870b52a9565d885c0d7668cc050e30fa2c8ac3fb1fda15c083d/ruff-0.14.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac5b7f63dd3b27cc811850f5ffd8fff845b00ad70e60b043aabf8d6ecc304e09", size = 12815174, upload-time = "2026-01-15T20:15:05.74Z" }, - { url = "https://files.pythonhosted.org/packages/88/00/c38e5da58beebcf4fa32d0ddd993b63dfacefd02ab7922614231330845bf/ruff-0.14.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d2b1097750d90ba82ce4ba676e85230a0ed694178ca5e61aa9b459970b3eb9", size = 13680909, upload-time = "2026-01-15T20:15:14.537Z" }, - { url = "https://files.pythonhosted.org/packages/61/61/cd37c9dd5bd0a3099ba79b2a5899ad417d8f3b04038810b0501a80814fd7/ruff-0.14.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d0bf87705acbbcb8d4c24b2d77fbb73d40210a95c3903b443cd9e30824a5032", size = 15144215, upload-time = "2026-01-15T20:15:22.886Z" }, - { url = "https://files.pythonhosted.org/packages/56/8a/85502d7edbf98c2df7b8876f316c0157359165e16cdf98507c65c8d07d3d/ruff-0.14.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3eb5da8e2c9e9f13431032fdcbe7681de9ceda5835efee3269417c13f1fed5c", size = 14706067, upload-time = "2026-01-15T20:14:48.271Z" }, - { url = "https://files.pythonhosted.org/packages/7e/2f/de0df127feb2ee8c1e54354dc1179b4a23798f0866019528c938ba439aca/ruff-0.14.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:642442b42957093811cd8d2140dfadd19c7417030a7a68cf8d51fcdd5f217427", size = 14133916, upload-time = "2026-01-15T20:14:57.357Z" }, - { url = "https://files.pythonhosted.org/packages/0d/77/9b99686bb9fe07a757c82f6f95e555c7a47801a9305576a9c67e0a31d280/ruff-0.14.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4acdf009f32b46f6e8864af19cbf6841eaaed8638e65c8dac845aea0d703c841", size = 13859207, upload-time = "2026-01-15T20:14:55.111Z" }, - { url = "https://files.pythonhosted.org/packages/7d/46/2bdcb34a87a179a4d23022d818c1c236cb40e477faf0d7c9afb6813e5876/ruff-0.14.13-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:591a7f68860ea4e003917d19b5c4f5ac39ff558f162dc753a2c5de897fd5502c", size = 14043686, upload-time = "2026-01-15T20:14:52.841Z" }, - { url = "https://files.pythonhosted.org/packages/1a/a9/5c6a4f56a0512c691cf143371bcf60505ed0f0860f24a85da8bd123b2bf1/ruff-0.14.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:774c77e841cc6e046fc3e91623ce0903d1cd07e3a36b1a9fe79b81dab3de506b", size = 12663837, upload-time = "2026-01-15T20:15:18.921Z" }, - { url = "https://files.pythonhosted.org/packages/fe/bb/b920016ece7651fa7fcd335d9d199306665486694d4361547ccb19394c44/ruff-0.14.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:61f4e40077a1248436772bb6512db5fc4457fe4c49e7a94ea7c5088655dd21ae", size = 12805867, upload-time = "2026-01-15T20:14:59.272Z" }, - { url = "https://files.pythonhosted.org/packages/7d/b3/0bd909851e5696cd21e32a8fc25727e5f58f1934b3596975503e6e85415c/ruff-0.14.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6d02f1428357fae9e98ac7aa94b7e966fd24151088510d32cf6f902d6c09235e", size = 13208528, upload-time = "2026-01-15T20:15:03.732Z" }, - { url = "https://files.pythonhosted.org/packages/3b/3b/e2d94cb613f6bbd5155a75cbe072813756363eba46a3f2177a1fcd0cd670/ruff-0.14.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e399341472ce15237be0c0ae5fbceca4b04cd9bebab1a2b2c979e015455d8f0c", size = 13929242, upload-time = "2026-01-15T20:15:11.918Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c5/abd840d4132fd51a12f594934af5eba1d5d27298a6f5b5d6c3be45301caf/ruff-0.14.13-py3-none-win32.whl", hash = "sha256:ef720f529aec113968b45dfdb838ac8934e519711da53a0456038a0efecbd680", size = 12919024, upload-time = "2026-01-15T20:14:43.647Z" }, - { url = "https://files.pythonhosted.org/packages/c2/55/6384b0b8ce731b6e2ade2b5449bf07c0e4c31e8a2e68ea65b3bafadcecc5/ruff-0.14.13-py3-none-win_amd64.whl", hash = "sha256:6070bd026e409734b9257e03e3ef18c6e1a216f0435c6751d7a8ec69cb59abef", size = 14097887, upload-time = "2026-01-15T20:15:01.48Z" }, - { url = "https://files.pythonhosted.org/packages/4d/e1/7348090988095e4e39560cfc2f7555b1b2a7357deba19167b600fdf5215d/ruff-0.14.13-py3-none-win_arm64.whl", hash = "sha256:7ab819e14f1ad9fe39f246cfcc435880ef7a9390d81a2b6ac7e01039083dd247", size = 13080224, upload-time = "2026-01-15T20:14:45.853Z" }, + { url = "https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size = 10467650, upload-time = "2026-01-22T22:30:08.578Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size = 10883245, upload-time = "2026-01-22T22:30:04.155Z" }, + { url = "https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size = 10231273, upload-time = "2026-01-22T22:30:34.642Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size = 10585753, upload-time = "2026-01-22T22:30:31.781Z" }, + { url = "https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size = 10286052, upload-time = "2026-01-22T22:30:24.827Z" }, + { url = "https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size = 11043637, upload-time = "2026-01-22T22:30:13.239Z" }, + { url = "https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size = 12194761, upload-time = "2026-01-22T22:30:22.542Z" }, + { url = "https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size = 12005701, upload-time = "2026-01-22T22:30:20.499Z" }, + { url = "https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size = 11282455, upload-time = "2026-01-22T22:29:59.679Z" }, + { url = "https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size = 11215882, upload-time = "2026-01-22T22:29:57.032Z" }, + { url = "https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size = 11180549, upload-time = "2026-01-22T22:30:27.175Z" }, + { url = "https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size = 10543416, upload-time = "2026-01-22T22:30:01.964Z" }, + { url = "https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size = 10285491, upload-time = "2026-01-22T22:30:29.51Z" }, + { url = "https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size = 10733525, upload-time = "2026-01-22T22:30:06.499Z" }, + { url = "https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size = 11315626, upload-time = "2026-01-22T22:30:36.848Z" }, + { url = "https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size = 10502442, upload-time = "2026-01-22T22:30:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size = 11630486, upload-time = "2026-01-22T22:30:10.852Z" }, + { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" }, ] [[package]] @@ -1003,27 +1003,26 @@ wheels = [ [[package]] name = "ty" -version = "0.0.12" +version = "0.0.13" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/78/ba1a4ad403c748fbba8be63b7e774a90e80b67192f6443d624c64fe4aaab/ty-0.0.12.tar.gz", hash = "sha256:cd01810e106c3b652a01b8f784dd21741de9fdc47bd595d02c122a7d5cefeee7", size = 4981303, upload-time = "2026-01-14T22:30:48.537Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/dc/b607f00916f5a7c52860b84a66dc17bc6988e8445e96b1d6e175a3837397/ty-0.0.13.tar.gz", hash = "sha256:7a1d135a400ca076407ea30012d1f75419634160ed3b9cad96607bf2956b23b3", size = 4999183, upload-time = "2026-01-21T13:21:16.133Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/8f/c21314d074dda5fb13d3300fa6733fd0d8ff23ea83a721818740665b6314/ty-0.0.12-py3-none-linux_armv6l.whl", hash = "sha256:eb9da1e2c68bd754e090eab39ed65edf95168d36cbeb43ff2bd9f86b4edd56d1", size = 9614164, upload-time = "2026-01-14T22:30:44.016Z" }, - { url = "https://files.pythonhosted.org/packages/09/28/f8a4d944d13519d70c486e8f96d6fa95647ac2aa94432e97d5cfec1f42f6/ty-0.0.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c181f42aa19b0ed7f1b0c2d559980b1f1d77cc09419f51c8321c7ddf67758853", size = 9542337, upload-time = "2026-01-14T22:30:05.687Z" }, - { url = "https://files.pythonhosted.org/packages/e1/9c/f576e360441de7a8201daa6dc4ebc362853bc5305e059cceeb02ebdd9a48/ty-0.0.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1f829e1eecd39c3e1b032149db7ae6a3284f72fc36b42436e65243a9ed1173db", size = 8909582, upload-time = "2026-01-14T22:30:46.089Z" }, - { url = "https://files.pythonhosted.org/packages/d6/13/0898e494032a5d8af3060733d12929e3e7716db6c75eac63fa125730a3e7/ty-0.0.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45162e7826e1789cf3374627883cdeb0d56b82473a0771923e4572928e90be3", size = 9384932, upload-time = "2026-01-14T22:30:13.769Z" }, - { url = "https://files.pythonhosted.org/packages/e4/1a/b35b6c697008a11d4cedfd34d9672db2f0a0621ec80ece109e13fca4dfef/ty-0.0.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d11fec40b269bec01e751b2337d1c7ffa959a2c2090a950d7e21c2792442cccd", size = 9453140, upload-time = "2026-01-14T22:30:11.131Z" }, - { url = "https://files.pythonhosted.org/packages/dd/1e/71c9edbc79a3c88a0711324458f29c7dbf6c23452c6e760dc25725483064/ty-0.0.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09d99e37e761a4d2651ad9d5a610d11235fbcbf35dc6d4bc04abf54e7cf894f1", size = 9960680, upload-time = "2026-01-14T22:30:33.621Z" }, - { url = "https://files.pythonhosted.org/packages/0e/75/39375129f62dd22f6ad5a99cd2a42fd27d8b91b235ce2db86875cdad397d/ty-0.0.12-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d9ca0cdb17bd37397da7b16a7cd23423fc65c3f9691e453ad46c723d121225a1", size = 10904518, upload-time = "2026-01-14T22:30:08.464Z" }, - { url = "https://files.pythonhosted.org/packages/32/5e/26c6d88fafa11a9d31ca9f4d12989f57782ec61e7291d4802d685b5be118/ty-0.0.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcf2757b905e7eddb7e456140066335b18eb68b634a9f72d6f54a427ab042c64", size = 10525001, upload-time = "2026-01-14T22:30:16.454Z" }, - { url = "https://files.pythonhosted.org/packages/c2/a5/2f0b91894af13187110f9ad7ee926d86e4e6efa755c9c88a820ed7f84c85/ty-0.0.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00cf34c1ebe1147efeda3021a1064baa222c18cdac114b7b050bbe42deb4ca80", size = 10307103, upload-time = "2026-01-14T22:30:41.221Z" }, - { url = "https://files.pythonhosted.org/packages/4b/77/13d0410827e4bc713ebb7fdaf6b3590b37dcb1b82e0a81717b65548f2442/ty-0.0.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb3a655bd869352e9a22938d707631ac9fbca1016242b1f6d132d78f347c851", size = 10072737, upload-time = "2026-01-14T22:30:51.783Z" }, - { url = "https://files.pythonhosted.org/packages/e1/dd/fc36d8bac806c74cf04b4ca735bca14d19967ca84d88f31e121767880df1/ty-0.0.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4658e282c7cb82be304052f8f64f9925f23c3c4f90eeeb32663c74c4b095d7ba", size = 9368726, upload-time = "2026-01-14T22:30:18.683Z" }, - { url = "https://files.pythonhosted.org/packages/54/70/9e8e461647550f83e2fe54bc632ccbdc17a4909644783cdbdd17f7296059/ty-0.0.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:c167d838eaaa06e03bb66a517f75296b643d950fbd93c1d1686a187e5a8dbd1f", size = 9454704, upload-time = "2026-01-14T22:30:22.759Z" }, - { url = "https://files.pythonhosted.org/packages/04/9b/6292cf7c14a0efeca0539cf7d78f453beff0475cb039fbea0eb5d07d343d/ty-0.0.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2956e0c9ab7023533b461d8a0e6b2ea7b78e01a8dde0688e8234d0fce10c4c1c", size = 9649829, upload-time = "2026-01-14T22:30:31.234Z" }, - { url = "https://files.pythonhosted.org/packages/49/bd/472a5d2013371e4870886cff791c94abdf0b92d43d305dd0f8e06b6ff719/ty-0.0.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5c6a3fd7479580009f21002f3828320621d8a82d53b7ba36993234e3ccad58c8", size = 10162814, upload-time = "2026-01-14T22:30:36.174Z" }, - { url = "https://files.pythonhosted.org/packages/31/e9/2ecbe56826759845a7c21d80aa28187865ea62bc9757b056f6cbc06f78ed/ty-0.0.12-py3-none-win32.whl", hash = "sha256:a91c24fd75c0f1796d8ede9083e2c0ec96f106dbda73a09fe3135e075d31f742", size = 9140115, upload-time = "2026-01-14T22:30:38.903Z" }, - { url = "https://files.pythonhosted.org/packages/5d/6d/d9531eff35a5c0ec9dbc10231fac21f9dd6504814048e81d6ce1c84dc566/ty-0.0.12-py3-none-win_amd64.whl", hash = "sha256:df151894be55c22d47068b0f3b484aff9e638761e2267e115d515fcc9c5b4a4b", size = 9884532, upload-time = "2026-01-14T22:30:25.112Z" }, - { url = "https://files.pythonhosted.org/packages/e9/f3/20b49e75967023b123a221134548ad7000f9429f13fdcdda115b4c26305f/ty-0.0.12-py3-none-win_arm64.whl", hash = "sha256:cea99d334b05629de937ce52f43278acf155d3a316ad6a35356635f886be20ea", size = 9313974, upload-time = "2026-01-14T22:30:27.44Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/3632f1918f4c0a33184f107efc5d436ab6da147fd3d3b94b3af6461efbf4/ty-0.0.13-py3-none-linux_armv6l.whl", hash = "sha256:1b2b8e02697c3a94c722957d712a0615bcc317c9b9497be116ef746615d892f2", size = 9993501, upload-time = "2026-01-21T13:21:26.628Z" }, + { url = "https://files.pythonhosted.org/packages/92/87/6a473ced5ac280c6ce5b1627c71a8a695c64481b99aabc798718376a441e/ty-0.0.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f15cdb8e233e2b5adfce673bb21f4c5e8eaf3334842f7eea3c70ac6fda8c1de5", size = 9860986, upload-time = "2026-01-21T13:21:24.425Z" }, + { url = "https://files.pythonhosted.org/packages/5d/9b/d89ae375cf0a7cd9360e1164ce017f8c753759be63b6a11ed4c944abe8c6/ty-0.0.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:0819e89ac9f0d8af7a062837ce197f0461fee2fc14fd07e2c368780d3a397b73", size = 9350748, upload-time = "2026-01-21T13:21:28.502Z" }, + { url = "https://files.pythonhosted.org/packages/a8/a6/9ad58518056fab344b20c0bb2c1911936ebe195318e8acc3bc45ac1c6b6b/ty-0.0.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1de79f481084b7cc7a202ba0d7a75e10970d10ffa4f025b23f2e6b7324b74886", size = 9849884, upload-time = "2026-01-21T13:21:21.886Z" }, + { url = "https://files.pythonhosted.org/packages/b1/c3/8add69095fa179f523d9e9afcc15a00818af0a37f2b237a9b59bc0046c34/ty-0.0.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4fb2154cff7c6e95d46bfaba283c60642616f20d73e5f96d0c89c269f3e1bcec", size = 9822975, upload-time = "2026-01-21T13:21:14.292Z" }, + { url = "https://files.pythonhosted.org/packages/a4/05/4c0927c68a0a6d43fb02f3f0b6c19c64e3461dc8ed6c404dde0efb8058f7/ty-0.0.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00be58d89337c27968a20d58ca553458608c5b634170e2bec82824c2e4cf4d96", size = 10294045, upload-time = "2026-01-21T13:21:30.505Z" }, + { url = "https://files.pythonhosted.org/packages/b4/86/6dc190838aba967557fe0bfd494c595d00b5081315a98aaf60c0e632aaeb/ty-0.0.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:72435eade1fa58c6218abb4340f43a6c3ff856ae2dc5722a247d3a6dd32e9737", size = 10916460, upload-time = "2026-01-21T13:21:07.788Z" }, + { url = "https://files.pythonhosted.org/packages/04/40/9ead96b7c122e1109dfcd11671184c3506996bf6a649306ec427e81d9544/ty-0.0.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:77a548742ee8f621d718159e7027c3b555051d096a49bb580249a6c5fc86c271", size = 10597154, upload-time = "2026-01-21T13:21:18.064Z" }, + { url = "https://files.pythonhosted.org/packages/aa/7d/e832a2c081d2be845dc6972d0c7998914d168ccbc0b9c86794419ab7376e/ty-0.0.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da067c57c289b7cf914669704b552b6207c2cc7f50da4118c3e12388642e6b3f", size = 10410710, upload-time = "2026-01-21T13:21:12.388Z" }, + { url = "https://files.pythonhosted.org/packages/31/e3/898be3a96237a32f05c4c29b43594dc3b46e0eedfe8243058e46153b324f/ty-0.0.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d1b50a01fffa140417fca5a24b658fbe0734074a095d5b6f0552484724474343", size = 9826299, upload-time = "2026-01-21T13:21:00.845Z" }, + { url = "https://files.pythonhosted.org/packages/bb/eb/db2d852ce0ed742505ff18ee10d7d252f3acfd6fc60eca7e9c7a0288a6d8/ty-0.0.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0f33c46f52e5e9378378eca0d8059f026f3c8073ace02f7f2e8d079ddfe5207e", size = 9831610, upload-time = "2026-01-21T13:21:05.842Z" }, + { url = "https://files.pythonhosted.org/packages/9e/61/149f59c8abaddcbcbb0bd13b89c7741ae1c637823c5cf92ed2c644fcadef/ty-0.0.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:168eda24d9a0b202cf3758c2962cc295878842042b7eca9ed2965259f59ce9f2", size = 9978885, upload-time = "2026-01-21T13:21:10.306Z" }, + { url = "https://files.pythonhosted.org/packages/a0/cd/026d4e4af60a80918a8d73d2c42b8262dd43ab2fa7b28d9743004cb88d57/ty-0.0.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d4917678b95dc8cb399cc459fab568ba8d5f0f33b7a94bf840d9733043c43f29", size = 10506453, upload-time = "2026-01-21T13:20:56.633Z" }, + { url = "https://files.pythonhosted.org/packages/63/06/8932833a4eca2df49c997a29afb26721612de8078ae79074c8fe87e17516/ty-0.0.13-py3-none-win32.whl", hash = "sha256:c1f2ec40daa405508b053e5b8e440fbae5fdb85c69c9ab0ee078f8bc00eeec3d", size = 9433482, upload-time = "2026-01-21T13:20:58.717Z" }, + { url = "https://files.pythonhosted.org/packages/aa/fd/e8d972d1a69df25c2cecb20ea50e49ad5f27a06f55f1f5f399a563e71645/ty-0.0.13-py3-none-win_amd64.whl", hash = "sha256:8b7b1ab9f187affbceff89d51076038363b14113be29bda2ddfa17116de1d476", size = 10319156, upload-time = "2026-01-21T13:21:03.266Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c2/05fdd64ac003a560d4fbd1faa7d9a31d75df8f901675e5bed1ee2ceeff87/ty-0.0.13-py3-none-win_arm64.whl", hash = "sha256:1c9630333497c77bb9bcabba42971b96ee1f36c601dd3dcac66b4134f9fa38f0", size = 9808316, upload-time = "2026-01-21T13:20:54.053Z" }, ] [[package]] From d88e0aa827133d910f2506758c1676168cd3595f Mon Sep 17 00:00:00 2001 From: Daniel Koepping Date: Mon, 26 Jan 2026 21:04:37 -0800 Subject: [PATCH 31/77] Car diff: padding (#3068) padding --- opendbc/car/tests/car_diff.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/opendbc/car/tests/car_diff.py b/opendbc/car/tests/car_diff.py index 482d6743..f4b5bd68 100755 --- a/opendbc/car/tests/car_diff.py +++ b/opendbc/car/tests/car_diff.py @@ -25,6 +25,7 @@ from opendbc.car.logreader import LogReader, decompress_stream TOLERANCE = 1e-4 DIFF_BUCKET = "car_diff" IGNORE_FIELDS = ["cumLagMs", "canErrorCounter"] +PADDING = 5 def dict_diff(d1, d2, path="", ignore=None, tolerance=0): @@ -182,8 +183,8 @@ def group_frames(diffs, max_gap=15): def build_signals(group): _, first_frame, _, _ = group[0] _, last_frame, (final_master, _), _ = group[-1] - start = max(0, first_frame - 5) - end = last_frame + 6 + start = max(0, first_frame - PADDING) + end = last_frame + PADDING + 1 init = not final_master diff_at = {frame: (m, p) for _, frame, (m, p), _ in group} master_vals = [] From b038e6e19964bb6c06184afac61dac028e44eb8f Mon Sep 17 00:00:00 2001 From: Daniel Koepping Date: Mon, 26 Jan 2026 21:04:55 -0800 Subject: [PATCH 32/77] Car diff: skip comment on first timer PR (#3067) skip comment if tests.yml never ran --- .github/workflows/car_diff.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/car_diff.yml b/.github/workflows/car_diff.yml index c6f94216..bb8d8832 100644 --- a/.github/workflows/car_diff.yml +++ b/.github/workflows/car_diff.yml @@ -9,13 +9,14 @@ jobs: name: comment runs-on: ubuntu-latest timeout-minutes: 10 - continue-on-error: true permissions: contents: read pull-requests: write actions: read steps: - name: Wait for car diff + id: wait + continue-on-error: true uses: lewagon/wait-on-check-action@v1.3.4 with: ref: ${{ github.event.pull_request.head.sha }} @@ -24,6 +25,7 @@ jobs: allowed-conclusions: success wait-interval: 20 - name: Download car diff + if: steps.wait.outcome == 'success' uses: dawidd6/action-download-artifact@v6 with: github_token: ${{ secrets.GITHUB_TOKEN }} @@ -34,6 +36,7 @@ jobs: path: . allow_forks: true - name: Comment car diff on PR + if: steps.wait.outcome == 'success' uses: thollander/actions-comment-pull-request@v2 with: filePath: diff.txt From 8a25621e97fc022a56d0f3eb47be691832169cf7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 27 Jan 2026 20:34:30 -0800 Subject: [PATCH 33/77] Toyota: clean up alpha long (#3074) * toyota: clean up alpha long * yes we have a test --- opendbc/car/toyota/interface.py | 9 ++++----- opendbc/car/toyota/tests/test_toyota.py | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/opendbc/car/toyota/interface.py b/opendbc/car/toyota/interface.py index 9e2d332f..bda0a03a 100644 --- a/opendbc/car/toyota/interface.py +++ b/opendbc/car/toyota/interface.py @@ -106,12 +106,11 @@ class CarInterface(CarInterfaceBase): # TODO: make an adas dbc file for dsu-less models ret.radarUnavailable = Bus.radar not in DBC[candidate] or candidate in (NO_DSU_CAR - TSS2_CAR) - # since we don't yet parse radar on TSS2/TSS-P radar-based ACC cars, gate longitudinal behind experimental toggle - if candidate in (RADAR_ACC_CAR | NO_DSU_CAR): - ret.alphaLongitudinalAvailable = candidate in RADAR_ACC_CAR + # since we don't yet parse radar on TSS2 radar-based ACC cars, gate longitudinal behind experimental toggle + if candidate in RADAR_ACC_CAR: + ret.alphaLongitudinalAvailable = True - # Disabling radar is only supported on TSS2 radar-ACC cars - if alpha_long and candidate in RADAR_ACC_CAR: + if alpha_long: ret.flags |= ToyotaFlags.DISABLE_RADAR.value # openpilot longitudinal enabled by default: diff --git a/opendbc/car/toyota/tests/test_toyota.py b/opendbc/car/toyota/tests/test_toyota.py index 5ab47f35..2d07af54 100644 --- a/opendbc/car/toyota/tests/test_toyota.py +++ b/opendbc/car/toyota/tests/test_toyota.py @@ -18,6 +18,7 @@ def check_fw_version(fw_version: bytes) -> bool: class TestToyotaInterfaces: def test_car_sets(self): + # Angle and radar-ACC cars are always TSS2 cars assert len(ANGLE_CONTROL_CAR - TSS2_CAR) == 0 assert len(RADAR_ACC_CAR - TSS2_CAR) == 0 From cbff382e5bb42a705ba880ca8feaf20298df8f7a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 27 Jan 2026 20:48:17 -0800 Subject: [PATCH 34/77] Toyota: clean up radarUnavailable (#3075) * toyota: clean up alpha long * yes we have a test * not critical * test the differ * add more * this stems back to /one, so maybe they do * un print * it doesn't detect --- opendbc/car/toyota/interface.py | 9 +++------ opendbc/car/toyota/values.py | 5 +++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/opendbc/car/toyota/interface.py b/opendbc/car/toyota/interface.py index bda0a03a..c86b8bee 100644 --- a/opendbc/car/toyota/interface.py +++ b/opendbc/car/toyota/interface.py @@ -2,9 +2,8 @@ from opendbc.car import Bus, structs, get_safety_config, uds from opendbc.car.toyota.carstate import CarState from opendbc.car.toyota.carcontroller import CarController from opendbc.car.toyota.radar_interface import RadarInterface -from opendbc.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \ - MIN_ACC_SPEED, EPS_SCALE, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR, \ - ToyotaSafetyFlags +from opendbc.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, MIN_ACC_SPEED, \ + EPS_SCALE, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR, ToyotaSafetyFlags from opendbc.car.disable_ecu import disable_ecu from opendbc.car.interfaces import CarInterfaceBase @@ -102,9 +101,7 @@ class CarInterface(CarInterfaceBase): # Detect flipped signals and enable for C-HR and others ret.enableBsm = 0x3F6 in fingerprint[0] and candidate in TSS2_CAR - # No radar dbc for cars without DSU which are not TSS 2.0 - # TODO: make an adas dbc file for dsu-less models - ret.radarUnavailable = Bus.radar not in DBC[candidate] or candidate in (NO_DSU_CAR - TSS2_CAR) + ret.radarUnavailable = Bus.radar not in DBC[candidate] # since we don't yet parse radar on TSS2 radar-based ACC cars, gate longitudinal behind experimental toggle if candidate in RADAR_ACC_CAR: diff --git a/opendbc/car/toyota/values.py b/opendbc/car/toyota/values.py index b7206ba8..e482e86f 100644 --- a/opendbc/car/toyota/values.py +++ b/opendbc/car/toyota/values.py @@ -156,13 +156,14 @@ class CAR(Platforms): ], TOYOTA_AVALON.specs, ) + # TODO: determine if TSS-P NO_DSU cars can work with toyota_adas radar DBC and re-enable TOYOTA_CAMRY = PlatformConfig( [ ToyotaCarDocs("Toyota Camry 2018-20", video="https://www.youtube.com/watch?v=fkcjviZY9CM", footnotes=[Footnote.CAMRY]), ToyotaCarDocs("Toyota Camry Hybrid 2018-20", video="https://www.youtube.com/watch?v=Q2DYY0AWKgk"), ], CarSpecs(mass=3400. * CV.LB_TO_KG, wheelbase=2.82448, steerRatio=13.7, tireStiffnessFactor=0.7933), - dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), + {Bus.pt: 'toyota_nodsu_pt_generated'}, flags=ToyotaFlags.NO_DSU, ) TOYOTA_CAMRY_TSS2 = ToyotaTSS2PlatformConfig( # TSS 2.5 @@ -178,7 +179,7 @@ class CAR(Platforms): ToyotaCarDocs("Toyota C-HR Hybrid 2017-20"), ], CarSpecs(mass=3300. * CV.LB_TO_KG, wheelbase=2.63906, steerRatio=13.6, tireStiffnessFactor=0.7933), - dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), + {Bus.pt: 'toyota_nodsu_pt_generated'}, flags=ToyotaFlags.NO_DSU, ) TOYOTA_CHR_TSS2 = ToyotaTSS2PlatformConfig( From c3dd56199d2ee0a8c3cbf4d1aa6b1ddde949bda7 Mon Sep 17 00:00:00 2001 From: Daniel Koepping Date: Tue, 27 Jan 2026 21:03:19 -0800 Subject: [PATCH 35/77] Car diff: add typing (#3073) * typing * add alias --- opendbc/car/tests/car_diff.py | 39 ++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/opendbc/car/tests/car_diff.py b/opendbc/car/tests/car_diff.py index f4b5bd68..a7221490 100755 --- a/opendbc/car/tests/car_diff.py +++ b/opendbc/car/tests/car_diff.py @@ -13,6 +13,7 @@ from tqdm.contrib.concurrent import process_map from urllib.request import urlopen from collections import defaultdict from pathlib import Path +from typing import Any from comma_car_segments import get_comma_car_segments_database, get_url @@ -27,8 +28,12 @@ DIFF_BUCKET = "car_diff" IGNORE_FIELDS = ["cumLagMs", "canErrorCounter"] PADDING = 5 +Diff = tuple[str, int, tuple[Any, Any], int] +Ref = tuple[int, structs.CarState] +Result = tuple[str, str, list[Diff], str | None] -def dict_diff(d1, d2, path="", ignore=None, tolerance=0): + +def dict_diff(d1: dict[str, Any], d2: dict[str, Any], path: str = "", ignore: list[str] | None = None, tolerance: float = 0) -> list[tuple]: ignore = ignore or [] diffs = [] for key in d1.keys() | d2.keys(): @@ -46,14 +51,14 @@ def dict_diff(d1, d2, path="", ignore=None, tolerance=0): return diffs -def load_can_messages(seg): +def load_can_messages(seg: str) -> list[Any]: parts = seg.split("/") url = get_url(f"{parts[0]}/{parts[1]}", parts[2]) msgs = LogReader(url, only_union_types=True, sort_by_time=True) return [m for m in msgs if m.which() == 'can'] -def replay_segment(platform, can_msgs): +def replay_segment(platform: str, can_msgs: list[Any]) -> tuple[list[structs.CarState], list[int]]: _can_msgs = ([CanData(can.address, can.dat, can.src) for can in m.can] for m in can_msgs) def can_recv(wait_for_one: bool = False) -> list[list[CanData]]: @@ -75,7 +80,7 @@ def replay_segment(platform, can_msgs): return states, timestamps -def process_segment(args): +def process_segment(args: tuple) -> Result: platform, seg, ref_path, update = args try: can_msgs = load_can_messages(seg) @@ -90,7 +95,7 @@ def process_segment(args): if not ref_file.exists(): return (platform, seg, [], "no ref") - ref = pickle.loads(decompress_stream(ref_file.read_bytes())) + ref: list[Ref] = pickle.loads(decompress_stream(ref_file.read_bytes())) diffs = [] for i, ((ts, ref_state), state) in enumerate(zip(ref, states, strict=True)): for diff in dict_diff(ref_state.to_dict(), state.to_dict(), ignore=IGNORE_FIELDS, tolerance=TOLERANCE): @@ -100,7 +105,7 @@ def process_segment(args): return (platform, seg, [], traceback.format_exc()) -def get_changed_platforms(cwd, database, interfaces): +def get_changed_platforms(cwd: Path, database: dict[str, Any], interfaces: dict[str, Any]) -> list[str]: git_ref = os.environ.get("GIT_REF", "origin/master") changed = subprocess.check_output(["git", "diff", "--name-only", f"{git_ref}...HEAD"], cwd=cwd, encoding='utf8').strip() brands = set() @@ -113,7 +118,7 @@ def get_changed_platforms(cwd, database, interfaces): return [p for p in interfaces if any(b in p.lower() for b in brands) and p in database] -def download_refs(ref_path, platforms, segments): +def download_refs(ref_path: Path, platforms: list[str], segments: dict[str, list[str]]) -> None: base_url = f"https://raw.githubusercontent.com/commaai/ci-artifacts/refs/heads/{DIFF_BUCKET}" for platform in tqdm(platforms): for seg in segments.get(platform, []): @@ -122,14 +127,14 @@ def download_refs(ref_path, platforms, segments): (Path(ref_path) / filename).write_bytes(resp.read()) -def run_replay(platforms, segments, ref_path, update, workers=4): +def run_replay(platforms: list[str], segments: dict[str, list[str]], ref_path: Path, update: bool, workers: int = 4) -> list[Result]: work = [(platform, seg, ref_path, update) for platform in platforms for seg in segments.get(platform, [])] return process_map(process_segment, work, max_workers=workers) # ASCII waveforms helpers -def find_edges(vals, init): +def find_edges(vals: list[bool], init: bool) -> tuple[list[int], list[int]]: rises = [] falls = [] prev = init @@ -142,7 +147,7 @@ def find_edges(vals, init): return rises, falls -def render_waveform(label, vals, init): +def render_waveform(label: str, vals: list[bool], init: bool) -> str: wave = {(False, False): "_", (True, True): "‾", (False, True): "/", (True, False): "\\"} line = f" {label}:".ljust(12) prev = init @@ -154,7 +159,7 @@ def render_waveform(label, vals, init): return line -def format_timing(edge_type, master_edges, pr_edges, ms_per_frame): +def format_timing(edge_type: str, master_edges: list[int], pr_edges: list[int], ms_per_frame: float) -> str | None: if not master_edges or not pr_edges: return None delta = pr_edges[0] - master_edges[0] @@ -165,7 +170,7 @@ def format_timing(edge_type, master_edges, pr_edges, ms_per_frame): return " " * 12 + f"{edge_type}: PR {direction} by {abs(delta)} frames ({ms}ms)" -def group_frames(diffs, max_gap=15): +def group_frames(diffs: list[Diff], max_gap: int = 15) -> list[list[Diff]]: groups = [] current = [diffs[0]] for diff in diffs[1:]: @@ -180,7 +185,7 @@ def group_frames(diffs, max_gap=15): return groups -def build_signals(group): +def build_signals(group: list[Diff]) -> tuple[list[bool], list[bool], bool, int, int]: _, first_frame, _, _ = group[0] _, last_frame, (final_master, _), _ = group[-1] start = max(0, first_frame - PADDING) @@ -201,7 +206,7 @@ def build_signals(group): return master_vals, pr_vals, init, start, end -def format_numeric_diffs(diffs): +def format_numeric_diffs(diffs: list[Diff]) -> list[str]: lines = [] for _, frame, (old_val, new_val), _ in diffs[:10]: lines.append(f" frame {frame}: {old_val} -> {new_val}") @@ -210,7 +215,7 @@ def format_numeric_diffs(diffs): return lines -def format_boolean_diffs(diffs): +def format_boolean_diffs(diffs: list[Diff]) -> list[str]: _, first_frame, _, first_ts = diffs[0] _, last_frame, _, last_ts = diffs[-1] frame_time = last_frame - first_frame @@ -233,7 +238,7 @@ def format_boolean_diffs(diffs): return lines -def format_diff(diffs): +def format_diff(diffs: list[Diff]) -> list[str]: if not diffs: return [] _, _, (old, new), _ = diffs[0] @@ -243,7 +248,7 @@ def format_diff(diffs): return format_numeric_diffs(diffs) -def main(platform=None, segments_per_platform=10, update_refs=False, all_platforms=False): +def main(platform: str | None = None, segments_per_platform: int = 10, update_refs: bool = False, all_platforms: bool = False) -> int: cwd = Path(__file__).resolve().parents[3] ref_path = cwd / DIFF_BUCKET if not update_refs: From 1cd92abbf86b50ccd0a5782e6a5d598c14d94e7e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 27 Jan 2026 22:11:29 -0800 Subject: [PATCH 36/77] Toyota: remove NO_STOP_TIMER flag (#3076) * move inside op long control * this isn't a real code path anymore * fully remove NO_STOP_TIMER * we'll turn this around * rev --- opendbc/car/toyota/carcontroller.py | 29 +++++++---------------------- opendbc/car/toyota/carstate.py | 13 +++++-------- opendbc/car/toyota/interface.py | 9 ++++----- opendbc/car/toyota/values.py | 15 ++++----------- 4 files changed, 20 insertions(+), 46 deletions(-) diff --git a/opendbc/car/toyota/carcontroller.py b/opendbc/car/toyota/carcontroller.py index e5e3df96..82371d43 100644 --- a/opendbc/car/toyota/carcontroller.py +++ b/opendbc/car/toyota/carcontroller.py @@ -8,9 +8,7 @@ from opendbc.car.common.pid import PIDController from opendbc.car.secoc import add_mac, build_sync_mac from opendbc.car.interfaces import CarControllerBase from opendbc.car.toyota import toyotacan -from opendbc.car.toyota.values import CAR, NO_STOP_TIMER_CAR, TSS2_CAR, \ - CarControllerParams, ToyotaFlags, \ - UNSUPPORTED_DSU_CAR +from opendbc.car.toyota.values import CAR, TSS2_CAR, UNSUPPORTED_DSU_CAR, CarControllerParams, ToyotaFlags from opendbc.can import CANPacker Ecu = structs.CarParams.Ecu @@ -55,7 +53,6 @@ class CarController(CarControllerBase): self.last_torque = 0 self.last_angle = 0 self.alert_active = False - self.last_standstill = False self.standstill_req = False self.permit_braking = True self.steer_rate_counter = 0 @@ -168,17 +165,13 @@ class CarController(CarControllerBase): self.secoc_lta_message_counter += 1 can_sends.append(lta_steer_2) + # handle UI messages + fcw_alert = hud_control.visualAlert == VisualAlert.fcw + steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) + lead = hud_control.leadVisible or CS.out.vEgo < 12. # at low speed we always assume the lead is present so ACC can be engaged + # *** gas and brake *** - - # on entering standstill, send standstill request for older TSS-P cars that aren't designed to stay engaged at a stop - if self.CP.carFingerprint not in NO_STOP_TIMER_CAR: - if CS.out.standstill and not self.last_standstill: - self.standstill_req = True - if CS.pcm_acc_status != 8: - # pcm entered standstill or it's disabled - self.standstill_req = False - - else: + if self.CP.openpilotLongitudinalControl: # if user engages at a stop with foot on brake, PCM starts in a special cruise standstill mode. on resume press, # brakes can take a while to ramp up causing a lurch forward. prevent resume press until planner wants to move. # don't use CC.cruiseControl.resume since it is gated on CS.cruiseState.standstill which goes false for 3s after resume press @@ -191,14 +184,6 @@ class CarController(CarControllerBase): if not should_resume and CS.out.cruiseState.standstill: self.standstill_req = True - self.last_standstill = CS.out.standstill - - # handle UI messages - fcw_alert = hud_control.visualAlert == VisualAlert.fcw - steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) - lead = hud_control.leadVisible or CS.out.vEgo < 12. # at low speed we always assume the lead is present so ACC can be engaged - - if self.CP.openpilotLongitudinalControl: if self.frame % 3 == 0: # Press distance button until we are at the correct bar length. Only change while enabled to avoid skipping startup popup if self.frame % 6 == 0 and self.CP.openpilotLongitudinalControl: diff --git a/opendbc/car/toyota/carstate.py b/opendbc/car/toyota/carstate.py index 3fb22740..ca50e70b 100644 --- a/opendbc/car/toyota/carstate.py +++ b/opendbc/car/toyota/carstate.py @@ -5,9 +5,8 @@ from opendbc.car import Bus, DT_CTRL, create_button_events, structs from opendbc.car.common.conversions import Conversions as CV from opendbc.car.common.filter_simple import FirstOrderFilter from opendbc.car.interfaces import CarStateBase -from opendbc.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \ - TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR, \ - SECOC_CAR +from opendbc.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, TSS2_CAR, RADAR_ACC_CAR, \ + EPS_SCALE, UNSUPPORTED_DSU_CAR, SECOC_CAR ButtonType = structs.CarState.ButtonEvent.Type SteerControlType = structs.CarParams.SteerControlType @@ -160,12 +159,10 @@ class CarState(CarStateBase): if self.CP.openpilotLongitudinalControl: ret.accFaulted = ret.accFaulted or cp.vl["PCM_CRUISE_2"]["LOW_SPEED_LOCKOUT"] == 2 - self.pcm_acc_status = cp.vl["PCM_CRUISE"]["CRUISE_STATE"] - if self.CP.carFingerprint not in (NO_STOP_TIMER_CAR - TSS2_CAR): - # ignore standstill state in certain vehicles, since pcm allows to restart with just an acceleration request - ret.cruiseState.standstill = self.pcm_acc_status == 7 + pcm_acc_status = cp.vl["PCM_CRUISE"]["CRUISE_STATE"] + ret.cruiseState.standstill = pcm_acc_status == 7 ret.cruiseState.enabled = bool(cp.vl["PCM_CRUISE"]["CRUISE_ACTIVE"]) - ret.cruiseState.nonAdaptive = self.pcm_acc_status in (1, 2, 3, 4, 5, 6) + ret.cruiseState.nonAdaptive = pcm_acc_status in (1, 2, 3, 4, 5, 6) ret.genericToggle = bool(cp.vl["LIGHT_STALK"]["AUTO_HIGH_BEAM"]) ret.espDisabled = cp.vl["ESP_CONTROL"]["TC_DISABLED"] != 0 diff --git a/opendbc/car/toyota/interface.py b/opendbc/car/toyota/interface.py index c86b8bee..9d3e82dd 100644 --- a/opendbc/car/toyota/interface.py +++ b/opendbc/car/toyota/interface.py @@ -3,7 +3,7 @@ from opendbc.car.toyota.carstate import CarState from opendbc.car.toyota.carcontroller import CarController from opendbc.car.toyota.radar_interface import RadarInterface from opendbc.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, MIN_ACC_SPEED, \ - EPS_SCALE, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR, ToyotaSafetyFlags + EPS_SCALE, ANGLE_CONTROL_CAR, ToyotaSafetyFlags from opendbc.car.disable_ecu import disable_ecu from opendbc.car.interfaces import CarInterfaceBase @@ -103,7 +103,7 @@ class CarInterface(CarInterfaceBase): ret.radarUnavailable = Bus.radar not in DBC[candidate] - # since we don't yet parse radar on TSS2 radar-based ACC cars, gate longitudinal behind experimental toggle + # since we don't yet parse radar on TSS2 radar-based ACC cars, gate longitudinal behind alpha toggle if candidate in RADAR_ACC_CAR: ret.alphaLongitudinalAvailable = True @@ -111,15 +111,14 @@ class CarInterface(CarInterfaceBase): ret.flags |= ToyotaFlags.DISABLE_RADAR.value # openpilot longitudinal enabled by default: - # - cars w/ DSU disconnected # - TSS2 cars with camera sending ACC_CONTROL where we can block it - # openpilot longitudinal behind experimental long toggle: + # openpilot longitudinal behind alpha long toggle: # - TSS2 radar ACC cars (disables radar) ret.openpilotLongitudinalControl = (candidate in (TSS2_CAR - RADAR_ACC_CAR) or bool(ret.flags & ToyotaFlags.DISABLE_RADAR.value)) - ret.autoResumeSng = ret.openpilotLongitudinalControl and candidate in NO_STOP_TIMER_CAR + ret.autoResumeSng = ret.openpilotLongitudinalControl if not ret.openpilotLongitudinalControl: ret.safetyConfigs[0].safetyParam |= ToyotaSafetyFlags.STOCK_LONGITUDINAL.value diff --git a/opendbc/car/toyota/values.py b/opendbc/car/toyota/values.py index e482e86f..69d9b330 100644 --- a/opendbc/car/toyota/values.py +++ b/opendbc/car/toyota/values.py @@ -70,7 +70,6 @@ class ToyotaFlags(IntFlag): RADAR_ACC = 64 # these cars use the Lane Tracing Assist (LTA) message for lateral control ANGLE_CONTROL = 128 - NO_STOP_TIMER = 256 # these cars can utilize 2.0 m/s^2 RAISED_ACCEL_LIMIT = 1024 SECOC = 2048 @@ -78,6 +77,8 @@ class ToyotaFlags(IntFlag): # deprecated flags # these cars are speculated to allow stop and go when the DSU is unplugged SNG_WITHOUT_DSU_DEPRECATED = 512 + # no resume button press required + NO_STOP_TIMER_DEPRECATED = 256 def dbc_dict(pt, radar): @@ -107,7 +108,7 @@ class ToyotaTSS2PlatformConfig(PlatformConfig): dbc_dict: dict = field(default_factory=lambda: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas')) def init(self): - self.flags |= ToyotaFlags.TSS2 | ToyotaFlags.NO_STOP_TIMER | ToyotaFlags.NO_DSU + self.flags |= ToyotaFlags.TSS2 | ToyotaFlags.NO_DSU if self.flags & ToyotaFlags.RADAR_ACC: self.dbc_dict = {Bus.pt: 'toyota_nodsu_pt_generated'} @@ -118,7 +119,7 @@ class ToyotaSecOCPlatformConfig(PlatformConfig): dbc_dict: dict = field(default_factory=lambda: dbc_dict('toyota_secoc_pt_generated', 'toyota_tss2_adas')) def init(self): - self.flags |= ToyotaFlags.TSS2 | ToyotaFlags.NO_STOP_TIMER | ToyotaFlags.NO_DSU | ToyotaFlags.SECOC + self.flags |= ToyotaFlags.TSS2 | ToyotaFlags.NO_DSU | ToyotaFlags.SECOC if self.flags & ToyotaFlags.RADAR_ACC: self.dbc_dict = {Bus.pt: 'toyota_secoc_pt_generated'} @@ -216,7 +217,6 @@ class CAR(Platforms): ], CarSpecs(mass=4516. * CV.LB_TO_KG, wheelbase=2.8194, steerRatio=16.0, tireStiffnessFactor=0.8), dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'), - flags=ToyotaFlags.NO_STOP_TIMER, ) TOYOTA_HIGHLANDER_TSS2 = ToyotaTSS2PlatformConfig( [ @@ -238,7 +238,6 @@ class CAR(Platforms): [ToyotaCarDocs("Toyota Prius v 2017", "Toyota Safety Sense P", min_enable_speed=MIN_ACC_SPEED)], CarSpecs(mass=3340. * CV.LB_TO_KG, wheelbase=2.78, steerRatio=17.4, tireStiffnessFactor=0.5533), dbc_dict('toyota_new_mc_pt_generated', 'toyota_adas'), - flags=ToyotaFlags.NO_STOP_TIMER, ) TOYOTA_PRIUS_TSS2 = ToyotaTSS2PlatformConfig( [ @@ -262,8 +261,6 @@ class CAR(Platforms): ], TOYOTA_RAV4.specs, dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'), - # Note that the ICE RAV4 does not respect positive acceleration commands under 19 mph - flags=ToyotaFlags.NO_STOP_TIMER, ) TOYOTA_RAV4_TSS2 = ToyotaTSS2PlatformConfig( [ @@ -305,7 +302,6 @@ class CAR(Platforms): [ToyotaCarDocs("Toyota Sienna 2018-20", video="https://www.youtube.com/watch?v=q1UPOo4Sh68", min_enable_speed=MIN_ACC_SPEED)], CarSpecs(mass=4590. * CV.LB_TO_KG, wheelbase=3.03, steerRatio=15.5, tireStiffnessFactor=0.444), dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'), - flags=ToyotaFlags.NO_STOP_TIMER, ) TOYOTA_SIENNA_4TH_GEN = ToyotaSecOCPlatformConfig( [ToyotaSecOcCarDocs("Toyota Sienna 2021-23", min_enable_speed=MIN_ACC_SPEED)], @@ -605,7 +601,4 @@ ANGLE_CONTROL_CAR = CAR.with_flags(ToyotaFlags.ANGLE_CONTROL) SECOC_CAR = CAR.with_flags(ToyotaFlags.SECOC) -# no resume button press required -NO_STOP_TIMER_CAR = CAR.with_flags(ToyotaFlags.NO_STOP_TIMER) - DBC = CAR.create_dbc_map() From c79e6758aa8e63b4b793c56c9482ea7e5a8277cd Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 27 Jan 2026 22:51:45 -0800 Subject: [PATCH 37/77] honda: init class variables in __init__ --- opendbc/car/honda/carstate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/opendbc/car/honda/carstate.py b/opendbc/car/honda/carstate.py index 33449196..3794ed7b 100644 --- a/opendbc/car/honda/carstate.py +++ b/opendbc/car/honda/carstate.py @@ -48,6 +48,8 @@ class CarState(CarStateBase): # When available we use cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] to populate vEgoCluster # However, on cars without a digital speedometer this is not always present (HRV, FIT, CRV 2016, ILX and RDX) self.dash_speed_seen = False + self.is_metric = False + self.v_cruise_factor = 1. def update(self, can_parsers) -> structs.CarState: cp = can_parsers[Bus.pt] From d8d9e9b0de3565b64ee6b12cd2b4223f19c2e51a Mon Sep 17 00:00:00 2001 From: eFini Date: Wed, 28 Jan 2026 14:56:53 +0800 Subject: [PATCH 38/77] Honda: Taiwan Odyssey 2019 (#2985) * Taiwan Honda Odyssey 2019 Port * refactor per review comments * flip * can do detection, but only if there we support one more car to avoid early generilzation --------- Co-authored-by: Shane Smiskol --- opendbc/car/honda/carstate.py | 12 +++++++----- opendbc/car/honda/fingerprints.py | 11 +++++++++++ opendbc/car/honda/interface.py | 11 ++++++++++- opendbc/car/honda/values.py | 6 ++++++ opendbc/car/tests/routes.py | 1 + opendbc/car/tests/test_docs.py | 2 +- opendbc/car/torque_data/substitute.toml | 1 + .../dbc/generator/honda/_steering_control_c.dbc | 17 +++++++++++++++++ .../dbc/generator/honda/_steering_sensors_c.dbc | 7 +++++++ .../generator/honda/honda_odyssey_twn_2018.dbc | 7 +++++++ 10 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 opendbc/dbc/generator/honda/_steering_control_c.dbc create mode 100644 opendbc/dbc/generator/honda/_steering_sensors_c.dbc create mode 100644 opendbc/dbc/generator/honda/honda_odyssey_twn_2018.dbc diff --git a/opendbc/car/honda/carstate.py b/opendbc/car/honda/carstate.py index 3794ed7b..52519eef 100644 --- a/opendbc/car/honda/carstate.py +++ b/opendbc/car/honda/carstate.py @@ -70,7 +70,8 @@ class CarState(CarStateBase): self.cruise_buttons = cp.vl["SCM_BUTTONS"]["CRUISE_BUTTONS"] # used for car hud message - self.is_metric = not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"] + # TODO: find CAR_SPEED for HONDA_ODYSSEY_TWN or use ACC_HUD w/ detection + self.is_metric = self.CP.carFingerprint in (CAR.HONDA_ODYSSEY_TWN,) or not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"] self.v_cruise_factor = CV.MPH_TO_MS if self.dynamic_v_cruise_units and not self.is_metric else CV.KPH_TO_MS # ******************* parse out can ******************* @@ -129,10 +130,11 @@ class CarState(CarStateBase): ret.espDisabled = cp.vl["VSA_STATUS"]["ESP_DISABLED"] != 0 - self.dash_speed_seen = self.dash_speed_seen or cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] > 1e-3 - if self.dash_speed_seen: - conversion = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS - ret.vEgoCluster = cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] * conversion + if self.CP.carFingerprint not in (CAR.HONDA_ODYSSEY_TWN,): + self.dash_speed_seen = self.dash_speed_seen or cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] > 1e-3 + if self.dash_speed_seen: + conversion = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS + ret.vEgoCluster = cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] * conversion ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEER_ANGLE"] ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEER_ANGLE_RATE"] diff --git a/opendbc/car/honda/fingerprints.py b/opendbc/car/honda/fingerprints.py index 071c8774..00806105 100644 --- a/opendbc/car/honda/fingerprints.py +++ b/opendbc/car/honda/fingerprints.py @@ -583,6 +583,17 @@ FW_VERSIONS = { b'54008-THR-A020\x00\x00', ], }, + CAR.HONDA_ODYSSEY_TWN: { + (Ecu.eps, 0x18da30f1, None): [ + b'39990-T6A-J210\x00\x00', + ], + (Ecu.srs, 0x18da53f1, None): [ + b'77959-T6A-P110\x00\x00', + ], + (Ecu.fwdRadar, 0x18dab0f1, None): [ + b'36161-T6A-P040\x00\x00', + ], + }, CAR.HONDA_ODYSSEY_5G_MMR: { (Ecu.vsa, 0x18da28f1, None): [ b'57114-THR-A240\x00\x00', diff --git a/opendbc/car/honda/interface.py b/opendbc/car/honda/interface.py index f8c60a5c..3ee165d5 100755 --- a/opendbc/car/honda/interface.py +++ b/opendbc/car/honda/interface.py @@ -163,6 +163,10 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]] ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end + elif candidate == CAR.HONDA_ODYSSEY_TWN: + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]] + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 32767], [0, 32767]] # TODO: determine if there is a dead zone at the top end + elif candidate == CAR.HONDA_PILOT: ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]] @@ -220,7 +224,12 @@ class CarInterface(CarInterfaceBase): # to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not # conflict with PCM acc ret.autoResumeSng = candidate in (HONDA_BOSCH | {CAR.HONDA_CIVIC}) - ret.minEnableSpeed = -1. if ret.autoResumeSng else 25.51 * CV.MPH_TO_MS + if ret.autoResumeSng: + ret.minEnableSpeed = -1. + elif candidate == CAR.HONDA_ODYSSEY_TWN: + ret.minEnableSpeed = 19. * CV.MPH_TO_MS + else: + ret.minEnableSpeed = 25.51 * CV.MPH_TO_MS ret.steerLimitTimer = 0.8 ret.radarDelay = 0.1 diff --git a/opendbc/car/honda/values.py b/opendbc/car/honda/values.py index 389af02b..48214f58 100644 --- a/opendbc/car/honda/values.py +++ b/opendbc/car/honda/values.py @@ -330,6 +330,12 @@ class CAR(Platforms): radar_dbc_dict('honda_odyssey_exl_2018_generated'), flags=HondaFlags.NIDEC_ALT_PCM_ACCEL | HondaFlags.HAS_ALL_DOOR_STATES, ) + HONDA_ODYSSEY_TWN = HondaNidecPlatformConfig( + [HondaCarDocs("Honda Odyssey (Taiwan) 2018-19")], + CarSpecs(mass=1865, wheelbase=2.9, steerRatio=14.35, centerToFrontRatio=0.44, tireStiffnessFactor=0.82), + radar_dbc_dict('honda_odyssey_twn_2018_generated'), + flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES, + ) ACURA_RDX = HondaNidecPlatformConfig( [HondaCarDocs("Acura RDX 2016-18", "AcuraWatch Plus or Advance Package", min_steer_speed=12. * CV.MPH_TO_MS)], CarSpecs(mass=3925 * CV.LB_TO_KG, wheelbase=2.68, steerRatio=15.0, centerToFrontRatio=0.38, tireStiffnessFactor=0.444), # as spec diff --git a/opendbc/car/tests/routes.py b/opendbc/car/tests/routes.py index 9202da7a..1120026d 100644 --- a/opendbc/car/tests/routes.py +++ b/opendbc/car/tests/routes.py @@ -110,6 +110,7 @@ routes = [ CarTestRoute("f29e2b57a55e7ad5/2021-03-24--20-52-38", HONDA.HONDA_ACCORD), # hybrid, 2021 with new style HUD msgs CarTestRoute("1ad763dd22ef1a0e/2020-02-29--18-37-03", HONDA.HONDA_CRV_5G), CarTestRoute("0a96f86fcfe35964/2020-02-05--07-25-51", HONDA.HONDA_ODYSSEY), + CarTestRoute("7817fe954aff07b8/00000001--fdaaf36c4f", HONDA.HONDA_ODYSSEY_TWN), CarTestRoute("d7233a428eb7d0b5/00000001--9b99b04d43", HONDA.HONDA_ODYSSEY_5G_MMR), CarTestRoute("d83f36766f8012a5/2020-02-05--18-42-21", HONDA.HONDA_CIVIC_BOSCH_DIESEL), CarTestRoute("f0890d16a07a236b/2021-05-25--17-27-22", HONDA.HONDA_INSIGHT), diff --git a/opendbc/car/tests/test_docs.py b/opendbc/car/tests/test_docs.py index 8f0d862c..940f117f 100644 --- a/opendbc/car/tests/test_docs.py +++ b/opendbc/car/tests/test_docs.py @@ -52,7 +52,7 @@ class TestCarDocs: for car in self.all_cars: with subtests.test(car=car.name): # honda sanity check, it's the definition of a no torque star - if car.car_fingerprint in (HONDA.HONDA_ACCORD, HONDA.HONDA_CIVIC, HONDA.HONDA_CRV, HONDA.HONDA_ODYSSEY, HONDA.HONDA_PILOT): + if car.car_fingerprint in (HONDA.HONDA_ACCORD, HONDA.HONDA_CIVIC, HONDA.HONDA_CRV, HONDA.HONDA_ODYSSEY, HONDA.HONDA_ODYSSEY_TWN, HONDA.HONDA_PILOT): assert car.row[Column.STEERING_TORQUE] == Star.EMPTY, f"{car.name} has full torque star" elif car.brand in ("toyota", "hyundai"): assert car.row[Column.STEERING_TORQUE] != Star.EMPTY, f"{car.name} has no torque star" diff --git a/opendbc/car/torque_data/substitute.toml b/opendbc/car/torque_data/substitute.toml index d27476e6..bbbf7f97 100644 --- a/opendbc/car/torque_data/substitute.toml +++ b/opendbc/car/torque_data/substitute.toml @@ -52,6 +52,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "HONDA_CRV_EU" = "HONDA_CRV" "HONDA_CIVIC_BOSCH_DIESEL" = "HONDA_CIVIC_BOSCH" "HONDA_E" = "HONDA_CIVIC_BOSCH" +"HONDA_ODYSSEY_TWN" = "HONDA_ODYSSEY" "BUICK_LACROSSE" = "CHEVROLET_VOLT" "BUICK_REGAL" = "CHEVROLET_VOLT" diff --git a/opendbc/dbc/generator/honda/_steering_control_c.dbc b/opendbc/dbc/generator/honda/_steering_control_c.dbc new file mode 100644 index 00000000..6dc4b6dc --- /dev/null +++ b/opendbc/dbc/generator/honda/_steering_control_c.dbc @@ -0,0 +1,17 @@ +BO_ 404 STEERING_CONTROL: 4 EON + SG_ SET_ME_X00 : 22|7@0+ (1,0) [0|127] "" EPS + SG_ STEER_TORQUE_REQUEST : 23|1@0+ (1,0) [0|1] "" EPS + SG_ COUNTER : 29|2@0+ (1,0) [0|15] "" EPS + SG_ CHECKSUM : 27|4@0+ (1,0) [0|3] "" EPS + SG_ STEER_TORQUE : 7|16@0- (-1,0) [-32767|32767] "" EPS + +BO_ 399 STEER_STATUS: 7 EPS + SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-2985|2985] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON + SG_ STEER_STATUS : 43|4@0+ (1,0) [0|15] "" EON + SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON + SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON + SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON + +VAL_ 399 STEER_STATUS 7 "permanent_fault" 6 "tmp_fault" 5 "fault_1" 4 "no_torque_alert_2" 3 "low_speed_lockout" 2 "no_torque_alert_1" 1 "driver_steering" 0 "normal" ; \ No newline at end of file diff --git a/opendbc/dbc/generator/honda/_steering_sensors_c.dbc b/opendbc/dbc/generator/honda/_steering_sensors_c.dbc new file mode 100644 index 00000000..8d70ac93 --- /dev/null +++ b/opendbc/dbc/generator/honda/_steering_sensors_c.dbc @@ -0,0 +1,7 @@ +CM_ "steer_angle_rate is negative vs _steering_sensors_b.dbc"; + +BO_ 342 STEERING_SENSORS: 6 EPS + SG_ STEER_ANGLE : 7|16@0- (-0.1,0) [-500|500] "deg" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (1,0) [-3000|3000] "deg/s" EON + SG_ COUNTER : 45|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 43|4@0+ (1,0) [0|15] "" EON diff --git a/opendbc/dbc/generator/honda/honda_odyssey_twn_2018.dbc b/opendbc/dbc/generator/honda/honda_odyssey_twn_2018.dbc new file mode 100644 index 00000000..4dc4ea5c --- /dev/null +++ b/opendbc/dbc/generator/honda/honda_odyssey_twn_2018.dbc @@ -0,0 +1,7 @@ +CM_ "IMPORT _honda_common.dbc"; +CM_ "IMPORT _nidec_common.dbc"; +CM_ "IMPORT _lkas_hud_5byte.dbc"; +CM_ "IMPORT _nidec_scm_group_a.dbc"; +CM_ "IMPORT _steering_sensors_c.dbc"; +CM_ "IMPORT _steering_control_c.dbc"; +CM_ "IMPORT _gearbox_common.dbc"; From 9b3aef1def4c765ecc25f0a3e2f8c15393f5a187 Mon Sep 17 00:00:00 2001 From: adeebshihadeh Date: Wed, 28 Jan 2026 08:10:04 +0000 Subject: [PATCH 39/77] docs: Scheduled auto-update CARS.md --- docs/CARS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CARS.md b/docs/CARS.md index da8cb49c..4d3f6b4c 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -1,6 +1,6 @@ -# Support Information for 386 Known Cars +# Support Information for 387 Known Cars |Make|Model|Package|Support Level| |---|---|---|:---:| @@ -115,6 +115,7 @@ |Honda|N-Box 2018|All|[Upstream](#upstream)| |Honda|Odyssey 2018-20|Honda Sensing|[Upstream](#upstream)| |Honda|Odyssey 2021-26|All|[Upstream](#upstream)| +|Honda|Odyssey (Taiwan) 2018-19|Honda Sensing|[Upstream](#upstream)| |Honda|Passport 2019-25|All|[Upstream](#upstream)| |Honda|Passport 2026|All|[Upstream](#upstream)| |Honda|Pilot 2016-22|Honda Sensing|[Upstream](#upstream)| From 0702326e7c027c5bd3aebb5cfcbf299cb921259d Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Wed, 28 Jan 2026 14:14:15 -0500 Subject: [PATCH 40/77] VW MLB: Add FW for 2023 Porsche Macan S (#3078) --- opendbc/car/volkswagen/fingerprints.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/opendbc/car/volkswagen/fingerprints.py b/opendbc/car/volkswagen/fingerprints.py index 5aa37c94..a9b12184 100644 --- a/opendbc/car/volkswagen/fingerprints.py +++ b/opendbc/car/volkswagen/fingerprints.py @@ -974,11 +974,13 @@ FW_VERSIONS = { b'\xf1\x8795B906259BM\xf1\x890001', b'\xf1\x8795B90652013\xf1\x893485', b'\xf1\x8795B90654002\xf1\x893495', + b'\xf1\x8795B907551AD\xf1\x890001', b'\xf1\x8795B907551D \xf1\x890006', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x8795B927156CE\xf1\x890022', b'\xf1\x8795B927156JH\xf1\x890001', + b'\xf1\x8795B927156KD\xf1\x890001', b'\xf1\x8795B927156KK\xf1\x890001', b'\xf1\x8795B927156KP\xf1\x890001', b'\xf1\x8795B927156R \xf1\x890021', @@ -987,6 +989,7 @@ FW_VERSIONS = { b'\xf1\x8795B959655F \xf1\x890130\xf1\x82\x05065Q033513', b'\xf1\x8795B959655F \xf1\x890130\xf1\x82\x050682033514', b'\xf1\x8795B959655G \xf1\x890150\xf1\x82\x0506B1033514', + b'\xf1\x8795B959655G \xf1\x890150\xf1\x82\x0506CG033517', b'\xf1\x8795B959655G \xf1\x890150\xf1\x82\x0506CJ02D417', ], (Ecu.eps, 0x712, None): [ @@ -996,6 +999,7 @@ FW_VERSIONS = { (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x8795B907567B\x00\xf1\x890800\xf1\x82108', b'\xf1\x8795B907567G\x00\xf1\x890410\xf1\x82104', + b'\xf1\x8795B907567H\x00\xf1\x890430\xf1\x82104', b'\xf1\x8795B907567J \xf1\x890440\xf1\x82104', ], }, From ffbe6094a3d9dd9a043d2b16dab3a84ae30a9276 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 28 Jan 2026 19:31:52 -0800 Subject: [PATCH 41/77] Tesla: detect missing DAS_settings (#3082) * detect das_settings * clean up * rm * clean up --- opendbc/car/tesla/carstate.py | 6 +++--- opendbc/car/tesla/interface.py | 6 +++++- opendbc/car/tesla/values.py | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/opendbc/car/tesla/carstate.py b/opendbc/car/tesla/carstate.py index 5158a40f..86308978 100644 --- a/opendbc/car/tesla/carstate.py +++ b/opendbc/car/tesla/carstate.py @@ -5,7 +5,7 @@ from opendbc.car.carlog import carlog from opendbc.car.common.conversions import Conversions as CV from opendbc.car.interfaces import CarStateBase from opendbc.car.tesla.teslacan import get_steer_ctrl_type -from opendbc.car.tesla.values import DBC, CANBUS, GEAR_MAP, STEER_THRESHOLD, CAR, TeslaFlags +from opendbc.car.tesla.values import DBC, CANBUS, GEAR_MAP, STEER_THRESHOLD, TeslaFlags ButtonType = structs.CarState.ButtonEvent.Type @@ -116,8 +116,8 @@ class CarState(CarStateBase): ret.stockLkas = cp_ap_party.vl["DAS_steeringControl"]["DAS_steeringControlType"] == lkas_ctrl_type # LANE_KEEP_ASSIST # Stock Autosteer should be off (includes FSD) - # TODO: find for TESLA_MODEL_X - if self.CP.carFingerprint in (CAR.TESLA_MODEL_3, CAR.TESLA_MODEL_Y): + # TODO: find for TESLA_MODEL_X and HW2.5 vehicles + if not (self.CP.flags & TeslaFlags.MISSING_DAS_SETTINGS): ret.invalidLkasSetting = cp_ap_party.vl["DAS_settings"]["DAS_autosteerEnabled"] != 0 # Because we don't have FSD 14 detection outside of a set of FW, we should check if this FW is accidentally missing from FSD_14_FW diff --git a/opendbc/car/tesla/interface.py b/opendbc/car/tesla/interface.py index a6e69528..c43baad0 100644 --- a/opendbc/car/tesla/interface.py +++ b/opendbc/car/tesla/interface.py @@ -2,7 +2,7 @@ from opendbc.car import Bus, get_safety_config, structs from opendbc.car.interfaces import CarInterfaceBase from opendbc.car.tesla.carcontroller import CarController from opendbc.car.tesla.carstate import CarState -from opendbc.car.tesla.values import TeslaSafetyFlags, TeslaFlags, CAR, DBC, FSD_14_FW, Ecu +from opendbc.car.tesla.values import TeslaSafetyFlags, TeslaFlags, CANBUS, CAR, DBC, FSD_14_FW, Ecu from opendbc.car.tesla.radar_interface import RadarInterface, RADAR_START_ADDR @@ -23,6 +23,10 @@ class CarInterface(CarInterfaceBase): ret.steerControlType = structs.CarParams.SteerControlType.angle + # Model X and HW 2.5 vehicles are missing DAS_settings + if 0x293 not in fingerprint[CANBUS.autopilot_party]: + ret.flags |= TeslaFlags.MISSING_DAS_SETTINGS.value + # Radar support is intended to work for: # - Tesla Model 3 vehicles built approximately mid-2017 through early-2021 # - Tesla Model Y vehicles built approximately mid-2020 through early-2021 diff --git a/opendbc/car/tesla/values.py b/opendbc/car/tesla/values.py index c8e1e2a9..8f5e1ec9 100644 --- a/opendbc/car/tesla/values.py +++ b/opendbc/car/tesla/values.py @@ -135,6 +135,7 @@ class TeslaSafetyFlags(IntFlag): class TeslaFlags(IntFlag): LONG_CONTROL = 1 FSD_14 = 2 + MISSING_DAS_SETTINGS = 4 DBC = CAR.create_dbc_map() From 9b93deb8a7429dbd1db1e317b97fddaf594f7da6 Mon Sep 17 00:00:00 2001 From: Gavin Phratsachack <37220586+gncnpk@users.noreply.github.com> Date: Wed, 28 Jan 2026 22:03:55 -0600 Subject: [PATCH 42/77] Nissan: Enable steering at standstill (#2812) * Enable steering at standstill for Nissan cars * Update LKAS_MAX_TORQUE value to improve steering speed Increased LKAS_MAX_TORQUE from 1 to 2.54 for better performance. * Update carcontroller.py * Revert "Update LKAS_MAX_TORQUE value to improve steering speed" This reverts commit d490162da4a47cca6683c5c9a710b291cce61080. * Revert "Update carcontroller.py" This reverts commit 431b6c021b1f3523e30693e4dcf41819ee8819a1. --- opendbc/car/nissan/interface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/opendbc/car/nissan/interface.py b/opendbc/car/nissan/interface.py index 12c217fe..3ac55c54 100644 --- a/opendbc/car/nissan/interface.py +++ b/opendbc/car/nissan/interface.py @@ -15,6 +15,7 @@ class CarInterface(CarInterfaceBase): ret.brand = "nissan" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.nissan)] ret.autoResumeSng = False + ret.steerAtStandstill = True ret.steerLimitTimer = 1.0 From 900cb87c6146487338215d4978008a1da600d8e1 Mon Sep 17 00:00:00 2001 From: Hacheoy <124492751+Hacheoy@users.noreply.github.com> Date: Thu, 29 Jan 2026 15:20:11 +1100 Subject: [PATCH 43/77] Toyota: Add SnG to Lexus LS, update torque data. (#3080) * Add Lexus LS 2018 platform configuration * Add fingerprints for Lexus LS ECUs * Add LEXUS_LS to torque substitute * Update steer ratio for Lexus LS 2018 configuration * LS steer ratio back to 13.0 * Update steer ratio for Lexus LS 2018 based on live params * Add test route for Lexus LS * Update LS car docs to exclude LSS+ A package * Fix formatting in Lexus LS 2018 documentation * Remove LEXUS_LS mapping from substitute.toml * Add better torque data for LEXUS_LS * Modify torque values for LEXUS_LS Better torque values for LEXUS_LS based on learned values after long drive. * Add Lexus LS 2018 to sng = true * Update MAX_LAT_ACCEL_MEASURED for LEXUS_LS --- opendbc/car/torque_data/override.toml | 1 + opendbc/car/torque_data/substitute.toml | 1 - opendbc/car/toyota/interface.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/opendbc/car/torque_data/override.toml b/opendbc/car/torque_data/override.toml index d2416afc..2471b278 100644 --- a/opendbc/car/torque_data/override.toml +++ b/opendbc/car/torque_data/override.toml @@ -93,6 +93,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "ACURA_TLX_2G" = [1.2, 1.2, 0.15] "ACURA_TLX_2G_MMR" = [1.7, 1.7, 0.16] "PORSCHE_MACAN_MK1" = [2.0, 2.0, 0.2] +"LEXUS_LS" = [1.35, 1.7, 0.17] # Dashcam or fallback configured as ideal car "MOCK" = [10.0, 10, 0.0] diff --git a/opendbc/car/torque_data/substitute.toml b/opendbc/car/torque_data/substitute.toml index bbbf7f97..678d4018 100644 --- a/opendbc/car/torque_data/substitute.toml +++ b/opendbc/car/torque_data/substitute.toml @@ -17,7 +17,6 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "LEXUS_RC" = "LEXUS_NX_TSS2" "LEXUS_RC_TSS2" = "LEXUS_NX_TSS2" "LEXUS_LC_TSS2" = "LEXUS_NX_TSS2" -"LEXUS_LS" = "LEXUS_NX" "KIA_OPTIMA_G4" = "HYUNDAI_SONATA" "KIA_OPTIMA_G4_FL" = "HYUNDAI_SONATA" diff --git a/opendbc/car/toyota/interface.py b/opendbc/car/toyota/interface.py index 9d3e82dd..d4404046 100644 --- a/opendbc/car/toyota/interface.py +++ b/opendbc/car/toyota/interface.py @@ -91,7 +91,7 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kf = 0.00004 break - elif candidate in (CAR.TOYOTA_CHR, CAR.TOYOTA_CAMRY, CAR.TOYOTA_SIENNA, CAR.LEXUS_CTH, CAR.LEXUS_NX): + elif candidate in (CAR.TOYOTA_CHR, CAR.TOYOTA_CAMRY, CAR.TOYOTA_SIENNA, CAR.LEXUS_CTH, CAR.LEXUS_LS, CAR.LEXUS_NX): # TODO: Some of these platforms are not advertised to have full range ACC, do they really all have sng? stop_and_go = True From 5e71fde25ae660e563ddedc96cd2d80285b78b60 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 29 Jan 2026 14:10:12 -0800 Subject: [PATCH 44/77] Toyota SecOC platforms should use torque control (#3086) * use torque control for secoc platforms * checked 5 dongles for each platform. sienna was closer to 1.5, but within margin of error --- opendbc/car/torque_data/override.toml | 1 + opendbc/car/torque_data/substitute.toml | 3 +-- opendbc/car/toyota/interface.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/opendbc/car/torque_data/override.toml b/opendbc/car/torque_data/override.toml index 2471b278..e1e9c7e1 100644 --- a/opendbc/car/torque_data/override.toml +++ b/opendbc/car/torque_data/override.toml @@ -94,6 +94,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "ACURA_TLX_2G_MMR" = [1.7, 1.7, 0.16] "PORSCHE_MACAN_MK1" = [2.0, 2.0, 0.2] "LEXUS_LS" = [1.35, 1.7, 0.17] +"TOYOTA_RAV4_PRIME" = [1.7, 2.0, 0.14] # Dashcam or fallback configured as ideal car "MOCK" = [10.0, 10, 0.0] diff --git a/opendbc/car/torque_data/substitute.toml b/opendbc/car/torque_data/substitute.toml index 678d4018..134f85a2 100644 --- a/opendbc/car/torque_data/substitute.toml +++ b/opendbc/car/torque_data/substitute.toml @@ -9,8 +9,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "TOYOTA_ALPHARD_TSS2" = "TOYOTA_SIENNA" "TOYOTA_PRIUS_V" = "TOYOTA_PRIUS" -"TOYOTA_RAV4_PRIME" = "TOYOTA_RAV4_TSS2" -"TOYOTA_SIENNA_4TH_GEN" = "TOYOTA_RAV4_TSS2" +"TOYOTA_SIENNA_4TH_GEN" = "TOYOTA_RAV4_PRIME" "LEXUS_IS" = "LEXUS_NX" "LEXUS_CTH" = "LEXUS_NX" "LEXUS_ES" = "TOYOTA_CAMRY" diff --git a/opendbc/car/toyota/interface.py b/opendbc/car/toyota/interface.py index d4404046..d1a3a2b9 100644 --- a/opendbc/car/toyota/interface.py +++ b/opendbc/car/toyota/interface.py @@ -74,7 +74,7 @@ class CarInterface(CarInterfaceBase): # https://engage.toyota.com/static/images/toyota_safety_sense/TSS_Applicability_Chart.pdf stop_and_go = candidate != CAR.TOYOTA_AVALON - elif candidate in (CAR.TOYOTA_RAV4_TSS2, CAR.TOYOTA_RAV4_TSS2_2022, CAR.TOYOTA_RAV4_TSS2_2023, CAR.TOYOTA_RAV4_PRIME, CAR.TOYOTA_SIENNA_4TH_GEN): + elif candidate in (CAR.TOYOTA_RAV4_TSS2, CAR.TOYOTA_RAV4_TSS2_2022, CAR.TOYOTA_RAV4_TSS2_2023): ret.lateralTuning.init('pid') ret.lateralTuning.pid.kiBP = [0.0] ret.lateralTuning.pid.kpBP = [0.0] From 83614718e2cb3fe54da6b3489aa23ea249a31c1f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 29 Jan 2026 14:11:32 -0800 Subject: [PATCH 45/77] Remove angle RAV4 platform from PID list (#3085) * rm * just * rm --- opendbc/car/toyota/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc/car/toyota/interface.py b/opendbc/car/toyota/interface.py index d1a3a2b9..c3ab9348 100644 --- a/opendbc/car/toyota/interface.py +++ b/opendbc/car/toyota/interface.py @@ -74,7 +74,7 @@ class CarInterface(CarInterfaceBase): # https://engage.toyota.com/static/images/toyota_safety_sense/TSS_Applicability_Chart.pdf stop_and_go = candidate != CAR.TOYOTA_AVALON - elif candidate in (CAR.TOYOTA_RAV4_TSS2, CAR.TOYOTA_RAV4_TSS2_2022, CAR.TOYOTA_RAV4_TSS2_2023): + elif candidate in (CAR.TOYOTA_RAV4_TSS2, CAR.TOYOTA_RAV4_TSS2_2022): ret.lateralTuning.init('pid') ret.lateralTuning.pid.kiBP = [0.0] ret.lateralTuning.pid.kpBP = [0.0] From c8e92d046324be54cfedccd2a27101060861e82b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 29 Jan 2026 15:46:41 -0800 Subject: [PATCH 46/77] Remove RAV4 2022 from PID lateral control (#3087) * this platform doesn't have any known special eps fw * bump down to 1.9 --- opendbc/car/torque_data/override.toml | 1 + opendbc/car/torque_data/params.toml | 1 - opendbc/car/toyota/interface.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/opendbc/car/torque_data/override.toml b/opendbc/car/torque_data/override.toml index e1e9c7e1..d2a6ece9 100644 --- a/opendbc/car/torque_data/override.toml +++ b/opendbc/car/torque_data/override.toml @@ -95,6 +95,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "PORSCHE_MACAN_MK1" = [2.0, 2.0, 0.2] "LEXUS_LS" = [1.35, 1.7, 0.17] "TOYOTA_RAV4_PRIME" = [1.7, 2.0, 0.14] +"TOYOTA_RAV4_TSS2_2022" = [1.9, 1.9304407208090029, 0.112174] # Dashcam or fallback configured as ideal car "MOCK" = [10.0, 10, 0.0] diff --git a/opendbc/car/torque_data/params.toml b/opendbc/car/torque_data/params.toml index fde2ca22..7d37f466 100644 --- a/opendbc/car/torque_data/params.toml +++ b/opendbc/car/torque_data/params.toml @@ -71,7 +71,6 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "TOYOTA_RAV4" = [2.085695074355425, 2.2142832316984733, 0.13339165270103975] "TOYOTA_RAV4_TSS2" = [2.279239424615458, 2.087101966779332, 0.13682208413446817] "TOYOTA_RAV4H" = [1.9796257271652042, 1.7503987331707576, 0.14628860048885406] -"TOYOTA_RAV4_TSS2_2022" = [2.241883248393209, 1.9304407208090029, 0.112174] "TOYOTA_SIENNA" = [1.689726, 1.3208264576110418, 0.140456] "TOYOTA_YARIS" = [2.22984, 1.86145, 0.168189] "VOLKSWAGEN_ARTEON_MK1" = [1.45136518053819, 1.3639364049316804, 0.23806361745695032] diff --git a/opendbc/car/toyota/interface.py b/opendbc/car/toyota/interface.py index c3ab9348..66b78d11 100644 --- a/opendbc/car/toyota/interface.py +++ b/opendbc/car/toyota/interface.py @@ -74,7 +74,7 @@ class CarInterface(CarInterfaceBase): # https://engage.toyota.com/static/images/toyota_safety_sense/TSS_Applicability_Chart.pdf stop_and_go = candidate != CAR.TOYOTA_AVALON - elif candidate in (CAR.TOYOTA_RAV4_TSS2, CAR.TOYOTA_RAV4_TSS2_2022): + elif candidate == CAR.TOYOTA_RAV4_TSS2: ret.lateralTuning.init('pid') ret.lateralTuning.pid.kiBP = [0.0] ret.lateralTuning.pid.kpBP = [0.0] From 7d7cf050e92e721973a6a238133fc91462612430 Mon Sep 17 00:00:00 2001 From: Daniel Koepping Date: Thu, 29 Jan 2026 19:39:45 -0800 Subject: [PATCH 47/77] Car diff: add CarParams (#3077) * signals from refs * use vals as prev * show all waveforms * get nested * use full refs * use explicit pr signal * Update opendbc/car/tests/car_diff.py Co-authored-by: Shane Smiskol * var names * hints * more * more * Revert "more" This reverts commit aa31c7ddb0cdbc7f236126887ad964f12d731665. * Revert "more" This reverts commit b998c6049d68c6a94dec6f7a4a54db647e30d27b. * Revert "hints" This reverts commit 1cbfb879b05be572ccf2ddc099c861b3bba175fe. * add typing * typing * add CarParams --------- Co-authored-by: Shane Smiskol --- opendbc/car/tests/car_diff.py | 87 +++++++++++++++++------------------ 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/opendbc/car/tests/car_diff.py b/opendbc/car/tests/car_diff.py index a7221490..66cee6c3 100755 --- a/opendbc/car/tests/car_diff.py +++ b/opendbc/car/tests/car_diff.py @@ -30,7 +30,7 @@ PADDING = 5 Diff = tuple[str, int, tuple[Any, Any], int] Ref = tuple[int, structs.CarState] -Result = tuple[str, str, list[Diff], str | None] +Result = tuple[str, str, list[Diff], list[Ref] | None, list[structs.CarState] | None, str | None] def dict_diff(d1: dict[str, Any], d2: dict[str, Any], path: str = "", ignore: list[str] | None = None, tolerance: float = 0) -> list[tuple]: @@ -58,7 +58,7 @@ def load_can_messages(seg: str) -> list[Any]: return [m for m in msgs if m.which() == 'can'] -def replay_segment(platform: str, can_msgs: list[Any]) -> tuple[list[structs.CarState], list[int]]: +def replay_segment(platform: str, can_msgs: list[Any]) -> tuple[structs.CarParams, list[structs.CarState], list[int]]: _can_msgs = ([CanData(can.address, can.dat, can.src) for can in m.can] for m in can_msgs) def can_recv(wait_for_one: bool = False) -> list[list[CanData]]: @@ -77,32 +77,36 @@ def replay_segment(platform: str, can_msgs: list[Any]) -> tuple[list[structs.Car states.append(CI.update([(msg.logMonoTime, frames)])) CI.apply(CC, msg.logMonoTime) timestamps.append(msg.logMonoTime) - return states, timestamps + return CP, states, timestamps def process_segment(args: tuple) -> Result: platform, seg, ref_path, update = args try: can_msgs = load_can_messages(seg) - states, timestamps = replay_segment(platform, can_msgs) + CP, states, timestamps = replay_segment(platform, can_msgs) ref_file = Path(ref_path) / f"{platform}_{seg.replace('/', '_')}.zst" if update: - data = list(zip(timestamps, states, strict=True)) + data = {"cp": CP.to_dict(), "frames": list(zip(timestamps, states, strict=True))} ref_file.write_bytes(zstd.compress(pickle.dumps(data), 10)) - return (platform, seg, [], None) + return (platform, seg, [], None, None, None) if not ref_file.exists(): - return (platform, seg, [], "no ref") + return (platform, seg, [], None, None, "no ref") - ref: list[Ref] = pickle.loads(decompress_stream(ref_file.read_bytes())) + ref_data = pickle.loads(decompress_stream(ref_file.read_bytes())) + cp: dict[str, Any] = ref_data["cp"] + ref: list[Ref] = ref_data["frames"] diffs = [] + for diff in dict_diff(cp, CP.to_dict(), path="carParams", ignore=IGNORE_FIELDS, tolerance=TOLERANCE): + diffs.append((diff[1], -1, diff[2], 0)) for i, ((ts, ref_state), state) in enumerate(zip(ref, states, strict=True)): for diff in dict_diff(ref_state.to_dict(), state.to_dict(), ignore=IGNORE_FIELDS, tolerance=TOLERANCE): diffs.append((diff[1], i, diff[2], ts)) - return (platform, seg, diffs, None) + return (platform, seg, diffs, ref, states, None) except Exception: - return (platform, seg, [], traceback.format_exc()) + return (platform, seg, [], None, None, traceback.format_exc()) def get_changed_platforms(cwd: Path, database: dict[str, Any], interfaces: dict[str, Any]) -> list[str]: @@ -134,10 +138,10 @@ def run_replay(platforms: list[str], segments: dict[str, list[str]], ref_path: P # ASCII waveforms helpers -def find_edges(vals: list[bool], init: bool) -> tuple[list[int], list[int]]: +def find_edges(vals: list[bool]) -> tuple[list[int], list[int]]: rises = [] falls = [] - prev = init + prev = vals[0] for i, val in enumerate(vals): if val and not prev: rises.append(i) @@ -147,10 +151,10 @@ def find_edges(vals: list[bool], init: bool) -> tuple[list[int], list[int]]: return rises, falls -def render_waveform(label: str, vals: list[bool], init: bool) -> str: +def render_waveform(label: str, vals: list[bool]) -> str: wave = {(False, False): "_", (True, True): "‾", (False, True): "/", (True, False): "\\"} line = f" {label}:".ljust(12) - prev = init + prev = vals[0] for val in vals: line += wave[(prev, val)] prev = val @@ -185,25 +189,22 @@ def group_frames(diffs: list[Diff], max_gap: int = 15) -> list[list[Diff]]: return groups -def build_signals(group: list[Diff]) -> tuple[list[bool], list[bool], bool, int, int]: +def build_signals(group: list[Diff], ref: list[Ref], states: list[structs.CarState], field: str) -> tuple[list[Any], list[Any], int, int]: _, first_frame, _, _ = group[0] - _, last_frame, (final_master, _), _ = group[-1] + _, last_frame, _, _ = group[-1] start = max(0, first_frame - PADDING) - end = last_frame + PADDING + 1 - init = not final_master - diff_at = {frame: (m, p) for _, frame, (m, p), _ in group} + end = min(last_frame + PADDING + 1, len(ref)) master_vals = [] pr_vals = [] - master = init - pr = init for frame in range(start, end): - if frame in diff_at: - master, pr = diff_at[frame] - elif frame > last_frame: - master = pr = final_master - master_vals.append(master) - pr_vals.append(pr) - return master_vals, pr_vals, init, start, end + mval = ref[frame][1].to_dict() + pval = states[frame].to_dict() + for k in field.split("."): + mval = mval.get(k) if isinstance(mval, dict) else None + pval = pval.get(k) if isinstance(pval, dict) else None + master_vals.append(mval) + pr_vals.append(pval) + return master_vals, pr_vals, start, end def format_numeric_diffs(diffs: list[Diff]) -> list[str]: @@ -215,7 +216,7 @@ def format_numeric_diffs(diffs: list[Diff]) -> list[str]: return lines -def format_boolean_diffs(diffs: list[Diff]) -> list[str]: +def format_boolean_diffs(diffs: list[Diff], ref: list[Ref], states: list[structs.CarState], field: str) -> list[str]: _, first_frame, _, first_ts = diffs[0] _, last_frame, _, last_ts = diffs[-1] frame_time = last_frame - first_frame @@ -223,14 +224,12 @@ def format_boolean_diffs(diffs: list[Diff]) -> list[str]: ms = time_ms / frame_time if frame_time else 10.0 lines = [] for group in group_frames(diffs): - master_vals, pr_vals, init, start, end = build_signals(group) - master_rises, master_falls = find_edges(master_vals, init) - pr_rises, pr_falls = find_edges(pr_vals, init) - if bool(master_rises) != bool(pr_rises) or bool(master_falls) != bool(pr_falls): - continue + master_vals, pr_vals, start, end = build_signals(group, ref, states, field) + master_rises, master_falls = find_edges(master_vals) + pr_rises, pr_falls = find_edges(pr_vals) lines.append(f"\n frames {start}-{end - 1}") - lines.append(render_waveform("master", master_vals, init)) - lines.append(render_waveform("PR", pr_vals, init)) + lines.append(render_waveform("master", master_vals)) + lines.append(render_waveform("PR", pr_vals)) for edge_type, master_edges, pr_edges in [("rise", master_rises, pr_rises), ("fall", master_falls, pr_falls)]: msg = format_timing(edge_type, master_edges, pr_edges, ms) if msg: @@ -238,13 +237,13 @@ def format_boolean_diffs(diffs: list[Diff]) -> list[str]: return lines -def format_diff(diffs: list[Diff]) -> list[str]: +def format_diff(diffs: list[Diff], ref: list[Ref], states: list[structs.CarState], field: str) -> list[str]: if not diffs: return [] _, _, (old, new), _ = diffs[0] is_bool = isinstance(old, bool) and isinstance(new, bool) if is_bool: - return format_boolean_diffs(diffs) + return format_boolean_diffs(diffs, ref, states, field) return format_numeric_diffs(diffs) @@ -274,16 +273,16 @@ def main(platform: str | None = None, segments_per_platform: int = 10, update_re if update_refs: results = run_replay(platforms, segments, ref_path, update=True) - errors = [e for _, _, _, e in results if e] + errors = [e for _, _, _, _, _, e in results if e] assert len(errors) == 0, f"Segment failures: {errors}" print(f"Generated {n_segments} refs to {ref_path}") return 0 download_refs(ref_path, platforms, segments) results = run_replay(platforms, segments, ref_path, update=False) - - with_diffs = [(p, s, d) for p, s, d, e in results if d] - errors = [(p, s, e) for p, s, d, e in results if e] + with_diffs = [(platform, seg, diffs, ref, states) + for platform, seg, diffs, ref, states, err in results if diffs] + errors = [(platform, seg, err) for platform, seg, diffs, ref, states, err in results if err] n_passed = len(results) - len(with_diffs) - len(errors) print(f"\nResults: {n_passed} passed, {len(with_diffs)} with diffs, {len(errors)} errors") @@ -293,14 +292,14 @@ def main(platform: str | None = None, segments_per_platform: int = 10, update_re if with_diffs: print("```") - for plat, seg, diffs in with_diffs: + for plat, seg, diffs, ref, states in with_diffs: print(f"\n{plat} - {seg}") by_field = defaultdict(list) for d in diffs: by_field[d[0]].append(d) for field, fd in sorted(by_field.items()): print(f" {field} ({len(fd)} diffs)") - for line in format_diff(fd): + for line in format_diff(fd, ref, states, field): print(line) print("```") From e76c2cf5bb0042bc5822efa78fff0362feed7b54 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 30 Jan 2026 00:13:10 -0800 Subject: [PATCH 48/77] Toyota: make RAV4 TSS2 use torque control (#3091) * need to do fric * it's real params * wrong one * wtf --- opendbc/car/torque_data/params.toml | 2 +- opendbc/car/toyota/interface.py | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/opendbc/car/torque_data/params.toml b/opendbc/car/torque_data/params.toml index 7d37f466..1fbabf6f 100644 --- a/opendbc/car/torque_data/params.toml +++ b/opendbc/car/torque_data/params.toml @@ -69,7 +69,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "TOYOTA_PRIUS" = [1.60, 1.5023147650693636, 0.151515] "TOYOTA_PRIUS_TSS2" = [1.972600, 1.9104337425537743, 0.170968] "TOYOTA_RAV4" = [2.085695074355425, 2.2142832316984733, 0.13339165270103975] -"TOYOTA_RAV4_TSS2" = [2.279239424615458, 2.087101966779332, 0.13682208413446817] +"TOYOTA_RAV4_TSS2" = [1.9557514786720276, 2.087101966779332, 0.12075843289494514] "TOYOTA_RAV4H" = [1.9796257271652042, 1.7503987331707576, 0.14628860048885406] "TOYOTA_SIENNA" = [1.689726, 1.3208264576110418, 0.140456] "TOYOTA_YARIS" = [2.22984, 1.86145, 0.168189] diff --git a/opendbc/car/toyota/interface.py b/opendbc/car/toyota/interface.py index 66b78d11..5f44a58e 100644 --- a/opendbc/car/toyota/interface.py +++ b/opendbc/car/toyota/interface.py @@ -74,23 +74,6 @@ class CarInterface(CarInterfaceBase): # https://engage.toyota.com/static/images/toyota_safety_sense/TSS_Applicability_Chart.pdf stop_and_go = candidate != CAR.TOYOTA_AVALON - elif candidate == CAR.TOYOTA_RAV4_TSS2: - ret.lateralTuning.init('pid') - ret.lateralTuning.pid.kiBP = [0.0] - ret.lateralTuning.pid.kpBP = [0.0] - ret.lateralTuning.pid.kpV = [0.6] - ret.lateralTuning.pid.kiV = [0.1] - ret.lateralTuning.pid.kf = 0.00007818594 - - # 2019+ RAV4 TSS2 uses two different steering racks and specific tuning seems to be necessary. - # See https://github.com/commaai/openpilot/pull/21429#issuecomment-873652891 - for fw in car_fw: - if fw.ecu == "eps" and (fw.fwVersion.startswith(b'\x02') or fw.fwVersion in [b'8965B42181\x00\x00\x00\x00\x00\x00']): - ret.lateralTuning.pid.kpV = [0.15] - ret.lateralTuning.pid.kiV = [0.05] - ret.lateralTuning.pid.kf = 0.00004 - break - elif candidate in (CAR.TOYOTA_CHR, CAR.TOYOTA_CAMRY, CAR.TOYOTA_SIENNA, CAR.LEXUS_CTH, CAR.LEXUS_LS, CAR.LEXUS_NX): # TODO: Some of these platforms are not advertised to have full range ACC, do they really all have sng? stop_and_go = True From 3b342d76aa6e92306384ed61a4df5e297b038c10 Mon Sep 17 00:00:00 2001 From: MVL Date: Fri, 30 Jan 2026 17:08:30 -0500 Subject: [PATCH 49/77] Honda - move brakehold_alt to honda_common (#2758) * add brakehold_hybrid_alt * remove brake hold --- opendbc/dbc/generator/honda/_honda_common.dbc | 7 +++++++ opendbc/dbc/generator/honda/_nidec_common.dbc | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/opendbc/dbc/generator/honda/_honda_common.dbc b/opendbc/dbc/generator/honda/_honda_common.dbc index 24d3ed56..fdf86ec7 100644 --- a/opendbc/dbc/generator/honda/_honda_common.dbc +++ b/opendbc/dbc/generator/honda/_honda_common.dbc @@ -85,6 +85,13 @@ BO_ 490 VEHICLE_DYNAMICS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" EON +BO_ 547 BRAKE_HOLD_HYBRID_ALT: 6 XXX + SG_ BRAKE_HOLD_FAULT_BIT : 33|1@0+ (1,0) [0|1] "" XXX + SG_ BRAKE_HOLD_ENABLED : 37|2@0+ (1,0) [0|7] "" XXX + SG_ BRAKE_HOLD_ACTIVE : 38|1@0+ (1,0) [0|1] "" XXX + SG_ CHECKSUM : 43|4@0+ (1,0) [0|15] "" XXX + SG_ COUNTER : 45|2@0+ (1,0) [0|3] "" XXX + BO_ 597 ROUGH_WHEEL_SPEED: 8 VSA SG_ WHEEL_SPEED_FL : 7|8@0+ (1,0) [0|255] "kph" EON SG_ WHEEL_SPEED_FR : 15|8@0+ (1,0) [0|255] "kph" EON diff --git a/opendbc/dbc/generator/honda/_nidec_common.dbc b/opendbc/dbc/generator/honda/_nidec_common.dbc index d22c28a5..12896d8f 100644 --- a/opendbc/dbc/generator/honda/_nidec_common.dbc +++ b/opendbc/dbc/generator/honda/_nidec_common.dbc @@ -35,13 +35,6 @@ BO_ 506 BRAKE_COMMAND: 8 ADAS SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EBCM SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EBCM -BO_ 547 BRAKE_HOLD_HYBRID_ALT: 6 XXX - SG_ BRAKE_HOLD_FAULT_BIT : 33|1@0+ (1,0) [0|1] "" XXX - SG_ BRAKE_HOLD_ENABLED : 37|2@0+ (1,0) [0|7] "" XXX - SG_ BRAKE_HOLD_ACTIVE : 38|1@0+ (1,0) [0|1] "" XXX - SG_ CHECKSUM : 43|4@0+ (1,0) [0|15] "" XXX - SG_ COUNTER : 45|2@0+ (1,0) [0|3] "" XXX - BO_ 892 CRUISE_PARAMS: 8 PCM SG_ CRUISE_SPEED_OFFSET : 31|8@0- (0.1,0) [-128|127] "kph" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" EON From f80dc22894f719a3bb96261c537384318c28c885 Mon Sep 17 00:00:00 2001 From: Alexandre Nobuharu Sato <66435071+AlexandreSato@users.noreply.github.com> Date: Fri, 30 Jan 2026 19:19:32 -0300 Subject: [PATCH 50/77] add STEERING_DIRECTION bit to gwm_haval_h6_phev_2024.dbc (#3093) * add STEERING_DIRECTION bit to gwm_haval_h6_phev_2024.dbc * add back crc --------- Co-authored-by: Shane Smiskol --- opendbc/dbc/gwm_haval_h6_phev_2024.dbc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/opendbc/dbc/gwm_haval_h6_phev_2024.dbc b/opendbc/dbc/gwm_haval_h6_phev_2024.dbc index 960f3e87..b9f85d7a 100644 --- a/opendbc/dbc/gwm_haval_h6_phev_2024.dbc +++ b/opendbc/dbc/gwm_haval_h6_phev_2024.dbc @@ -23,8 +23,9 @@ BO_ 147 IMPRECISE_SPEED_INFORMATION: 8 XXX BO_ 161 STEER_AND_AP_STALK: 8 XXX SG_ CRC : 7|8@0+ (1,0) [0|255] "" XXX - SG_ STEERING_ANGLE : 15|16@0+ (0.05,0) [0|65535] "degs" XXX - SG_ STEERING_TORQUE : 31|16@0+ (1,0) [0|65535] "??" XXX + SG_ STEERING_ANGLE : 13|13@0+ (0.05,0) [0|65535] "degs" XXX + SG_ STEERING_DIRECTION : 16|1@0+ (1,0) [0|1] "" XXX + SG_ STEERING_TORQUE : 29|14@0+ (1,0) [0|65535] "??" XXX SG_ AP_REDUCE_DISTANCE_COMMAND : 44|1@0+ (1,0) [0|1] "" XXX SG_ AP_INCREASE_DISTANCE_COMMAND : 45|1@0+ (1,0) [0|1] "AUTOPILOT_STALK" XXX SG_ AP_CANCEL_COMMAND : 46|1@0+ (1,0) [0|1] "" XXX From 6a18a5f470e81d8534ac3f62f5d4b12ba849f775 Mon Sep 17 00:00:00 2001 From: MVL Date: Fri, 30 Jan 2026 17:31:01 -0500 Subject: [PATCH 51/77] Honda: Update to latest community car support (#3089) Update to latest community car support --- opendbc/car/extra_cars.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/opendbc/car/extra_cars.py b/opendbc/car/extra_cars.py index a2dd470e..cbc2b33d 100644 --- a/opendbc/car/extra_cars.py +++ b/opendbc/car/extra_cars.py @@ -37,9 +37,11 @@ class CAR(Platforms): EXTRA_HONDA = ExtraPlatformConfig( [ + CommunityCarDocs("Acura ADX 2025-26"), CommunityCarDocs("Acura Integra 2023-25"), CommunityCarDocs("Acura MDX 2015-16", "Advance Package"), CommunityCarDocs("Acura MDX 2017-20"), + CommunityCarDocs("Acura MDX Hybrid 2017-20"), CommunityCarDocs("Acura MDX 2022-24"), CommunityCarDocs("Acura RDX 2022-25"), CommunityCarDocs("Acura RLX 2017", "Advance Package or Technology Package"), @@ -48,6 +50,7 @@ class CAR(Platforms): CommunityCarDocs("Acura TLX 2022-23"), GMSecurityCarDocs("Acura ZDX 2024"), CommunityCarDocs("Honda Accord 2016-17", "Honda Sensing"), + CommunityCarDocs("Honda Accord Hybrid 2017"), CommunityCarDocs("Honda Clarity 2018-21"), GMSecurityCarDocs("Honda Prologue 2024-25"), ], From 2da21d7b4a15d350fcf6824c02d193c3ebd8ff04 Mon Sep 17 00:00:00 2001 From: Kevin Turcios <106575910+KRRT7@users.noreply.github.com> Date: Sat, 31 Jan 2026 00:51:47 +0000 Subject: [PATCH 52/77] body: optimize CRC-8 checksum with lookup table (#3028) * body: optimize CRC-8 checksum with lookup table * Add CRC8BODY lookup table for body checksum Generate CRC-8 table with polynomial 0xD5 at import time, following the existing pattern for other CRC tables. * Use CRC8BODY from crc module in body checksum Replace hardcoded 256-entry lookup table with import from shared crc module, following reviewer feedback. --------- Co-authored-by: Daniel Koepping --- opendbc/car/body/bodycan.py | 11 ++++------- opendbc/car/crc.py | 1 + 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/opendbc/car/body/bodycan.py b/opendbc/car/body/bodycan.py index 201bfe71..bec099fc 100644 --- a/opendbc/car/body/bodycan.py +++ b/opendbc/car/body/bodycan.py @@ -1,3 +1,6 @@ +from opendbc.car.crc import CRC8BODY + + def create_control(packer, torque_l, torque_r): values = { "TORQUE_L": torque_l, @@ -9,12 +12,6 @@ def create_control(packer, torque_l, torque_r): def body_checksum(address: int, sig, d: bytearray) -> int: crc = 0xFF - poly = 0xD5 for i in range(len(d) - 2, -1, -1): - crc ^= d[i] - for _ in range(8): - if crc & 0x80: - crc = ((crc << 1) ^ poly) & 0xFF - else: - crc = (crc << 1) & 0xFF + crc = CRC8BODY[crc ^ d[i]] return crc diff --git a/opendbc/car/crc.py b/opendbc/car/crc.py index 2518286d..4aa721aa 100644 --- a/opendbc/car/crc.py +++ b/opendbc/car/crc.py @@ -27,4 +27,5 @@ def _gen_crc16_table(poly: int) -> list[int]: CRC8H2F = _gen_crc8_table(0x2F) CRC8J1850 = _gen_crc8_table(0x1D) +CRC8BODY = _gen_crc8_table(0xD5) CRC16_XMODEM = _gen_crc16_table(0x1021) From 7048ac6bfa44d93f6af75d059e251c0bebd485d6 Mon Sep 17 00:00:00 2001 From: Daniel Koepping Date: Fri, 30 Jan 2026 16:53:07 -0800 Subject: [PATCH 53/77] Car Diff: better comment (#3090) * add explainer * func * change text * icons * lines * test changes * Revert "test changes" This reverts commit 2b71f820025e6f857ae01e9847859a1b444b80e1. * test change * Revert "test change" This reverts commit d3c4f3d425977965b4cfb8ba96b8dc9c01e79650. * Update opendbc/car/tests/car_diff.py Co-authored-by: Shane Smiskol * Update opendbc/car/tests/car_diff.py Co-authored-by: Shane Smiskol * Update opendbc/car/tests/car_diff.py Co-authored-by: Shane Smiskol --------- Co-authored-by: Shane Smiskol --- opendbc/car/tests/car_diff.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/opendbc/car/tests/car_diff.py b/opendbc/car/tests/car_diff.py index 66cee6c3..fe9a138a 100755 --- a/opendbc/car/tests/car_diff.py +++ b/opendbc/car/tests/car_diff.py @@ -263,8 +263,12 @@ def main(platform: str | None = None, segments_per_platform: int = 10, update_re else: platforms = get_changed_platforms(cwd, database, interfaces) + print("## Car behavior report") + print("Replays driving segments through this PR and compares the behavior to master.") + print("Please review any changes carefully to ensure they are expected.\n") + if not platforms: - print("No car changes detected") + print("✅ No changes detected") return 0 segments = {p: database.get(p, [])[:segments_per_platform] for p in platforms} @@ -285,7 +289,8 @@ def main(platform: str | None = None, segments_per_platform: int = 10, update_re errors = [(platform, seg, err) for platform, seg, diffs, ref, states, err in results if err] n_passed = len(results) - len(with_diffs) - len(errors) - print(f"\nResults: {n_passed} passed, {len(with_diffs)} with diffs, {len(errors)} errors") + icon = "⚠️" if with_diffs else "✅" + print(f"\n{icon} {len(with_diffs)} changed, {n_passed} passed, {len(errors)} errors") for plat, seg, err in errors: print(f"\nERROR {plat} - {seg}: {err}") @@ -298,7 +303,7 @@ def main(platform: str | None = None, segments_per_platform: int = 10, update_re for d in diffs: by_field[d[0]].append(d) for field, fd in sorted(by_field.items()): - print(f" {field} ({len(fd)} diffs)") + print(f"\n {field} ({len(fd)} diffs)") for line in format_diff(fd, ref, states, field): print(line) print("```") From 50f1b43fd6c2ee068c78e1596e69dbf34a88fae0 Mon Sep 17 00:00:00 2001 From: Daniel Koepping Date: Fri, 30 Jan 2026 19:29:24 -0800 Subject: [PATCH 54/77] Car diff: lazy load (#3092) lazy load to import from openpilot --- opendbc/car/tests/car_diff.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/opendbc/car/tests/car_diff.py b/opendbc/car/tests/car_diff.py index fe9a138a..74c9c959 100755 --- a/opendbc/car/tests/car_diff.py +++ b/opendbc/car/tests/car_diff.py @@ -15,7 +15,6 @@ from collections import defaultdict from pathlib import Path from typing import Any -from comma_car_segments import get_comma_car_segments_database, get_url from opendbc.car import structs from opendbc.car.can_definitions import CanData @@ -52,6 +51,7 @@ def dict_diff(d1: dict[str, Any], d2: dict[str, Any], path: str = "", ignore: li def load_can_messages(seg: str) -> list[Any]: + from comma_car_segments import get_url parts = seg.split("/") url = get_url(f"{parts[0]}/{parts[1]}", parts[2]) msgs = LogReader(url, only_union_types=True, sort_by_time=True) @@ -248,6 +248,7 @@ def format_diff(diffs: list[Diff], ref: list[Ref], states: list[structs.CarState def main(platform: str | None = None, segments_per_platform: int = 10, update_refs: bool = False, all_platforms: bool = False) -> int: + from comma_car_segments import get_comma_car_segments_database cwd = Path(__file__).resolve().parents[3] ref_path = cwd / DIFF_BUCKET if not update_refs: From 8a60a647d7e77d6e6f1c2c701e0849cdd80e154c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 30 Jan 2026 20:38:00 -0800 Subject: [PATCH 55/77] Subaru global: use universal angle signal for angle cars (#3094) * swap * self explan * combine into if right below * split by lkas angle --- opendbc/car/subaru/carstate.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/opendbc/car/subaru/carstate.py b/opendbc/car/subaru/carstate.py index 76bc4ff8..1cc42da0 100644 --- a/opendbc/car/subaru/carstate.py +++ b/opendbc/car/subaru/carstate.py @@ -60,7 +60,13 @@ class CarState(CarStateBase): can_gear = int(cp_transmission.vl["Transmission"]["Gear"]) ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(can_gear, None)) - ret.steeringAngleDeg = cp.vl["Steering_Torque"]["Steering_Angle"] + if not (self.CP.flags & SubaruFlags.LKAS_ANGLE): + ret.steeringAngleDeg = cp.vl["Steering_Torque"]["Steering_Angle"] + else: + # Steering_Torque->Steering_Angle exists on SUBARU_FORESTER_2022, SUBARU_OUTBACK_2023, SUBARU_ASCENT_2023 where + # it is identical to Steering_2's signal. However, it is always zero on newer LKAS_ANGLE cars + # such as 2024+ Crosstrek, 2023+ Ascent, etc. Use a universal signal for LKAS_ANGLE cars. + ret.steeringAngleDeg = cp.vl["Steering_2"]["Steering_Angle"] if not (self.CP.flags & SubaruFlags.PREGLOBAL): # ideally we get this from the car, but unclear if it exists. diagnostic software doesn't even have it From b5a90e97d018082f556e1880583469d9399d93bf Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 30 Jan 2026 20:44:03 -0800 Subject: [PATCH 56/77] Fix Subaru steering angle rate (#3095) what is going on --- opendbc/car/__init__.py | 8 +++----- opendbc/car/subaru/carstate.py | 4 +++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/opendbc/car/__init__.py b/opendbc/car/__init__.py index a45e1e83..376b27c3 100644 --- a/opendbc/car/__init__.py +++ b/opendbc/car/__init__.py @@ -131,17 +131,15 @@ class CanSignalRateCalculator: Calculates the instantaneous rate of a CAN signal by using the counter variable and the known frequency of the CAN message that contains it. """ - def __init__(self, frequency): + def __init__(self, frequency: int): self.frequency = frequency - self.previous_counter = 0 self.previous_value = 0 self.rate = 0 - def update(self, current_value, current_counter): - if current_counter != self.previous_counter: + def update(self, current_value: float, updated: bool): + if updated: self.rate = (current_value - self.previous_value) * self.frequency - self.previous_counter = current_counter self.previous_value = current_value return self.rate diff --git a/opendbc/car/subaru/carstate.py b/opendbc/car/subaru/carstate.py index 1cc42da0..fdef22e4 100644 --- a/opendbc/car/subaru/carstate.py +++ b/opendbc/car/subaru/carstate.py @@ -62,15 +62,17 @@ class CarState(CarStateBase): if not (self.CP.flags & SubaruFlags.LKAS_ANGLE): ret.steeringAngleDeg = cp.vl["Steering_Torque"]["Steering_Angle"] + steering_updated = len(cp.vl_all["Steering_Torque"]["Steering_Angle"]) > 0 else: # Steering_Torque->Steering_Angle exists on SUBARU_FORESTER_2022, SUBARU_OUTBACK_2023, SUBARU_ASCENT_2023 where # it is identical to Steering_2's signal. However, it is always zero on newer LKAS_ANGLE cars # such as 2024+ Crosstrek, 2023+ Ascent, etc. Use a universal signal for LKAS_ANGLE cars. ret.steeringAngleDeg = cp.vl["Steering_2"]["Steering_Angle"] + steering_updated = len(cp.vl_all["Steering_2"]["Steering_Angle"]) > 0 if not (self.CP.flags & SubaruFlags.PREGLOBAL): # ideally we get this from the car, but unclear if it exists. diagnostic software doesn't even have it - ret.steeringRateDeg = self.angle_rate_calulator.update(ret.steeringAngleDeg, cp.vl["Steering_Torque"]["COUNTER"]) + ret.steeringRateDeg = self.angle_rate_calulator.update(ret.steeringAngleDeg, steering_updated) ret.steeringTorque = cp.vl["Steering_Torque"]["Steer_Torque_Sensor"] ret.steeringTorqueEps = cp.vl["Steering_Torque"]["Steer_Torque_Output"] From 197b55eb0d03d9107c233ec134fe63a7e61a6f9a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 30 Jan 2026 22:12:01 -0800 Subject: [PATCH 57/77] Subaru hybrid: fix cruise enabled signal (#3097) * brake or status works * hmm which name * better * rest * cmt * cmt * what --- opendbc/car/subaru/carstate.py | 4 +++- opendbc/car/subaru/subarucan.py | 9 +++++---- opendbc/dbc/generator/subaru/_subaru_global.dbc | 5 +++-- opendbc/dbc/generator/subaru/subaru_forester_2017.dbc | 2 +- opendbc/dbc/generator/subaru/subaru_outback_2015.dbc | 2 +- opendbc/dbc/generator/subaru/subaru_outback_2019.dbc | 2 +- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/opendbc/car/subaru/carstate.py b/opendbc/car/subaru/carstate.py index fdef22e4..01b92925 100644 --- a/opendbc/car/subaru/carstate.py +++ b/opendbc/car/subaru/carstate.py @@ -81,8 +81,10 @@ class CarState(CarStateBase): ret.steeringPressed = abs(ret.steeringTorque) > steer_threshold cp_cruise = cp_alt if self.CP.flags & SubaruFlags.GLOBAL_GEN2 else cp + # ES_DashStatus->Cruise_Activated_Dash is likely intended for the dash display only, as it falls + # during user gas override and at standstill. ES_Status is missing on hybrid, so we use ES_Brake instead if self.CP.flags & SubaruFlags.HYBRID: - ret.cruiseState.enabled = cp_cam.vl["ES_DashStatus"]['Cruise_Activated'] != 0 + ret.cruiseState.enabled = cp_cam.vl["ES_Brake"]['Cruise_Activated'] != 0 ret.cruiseState.available = cp_cam.vl["ES_DashStatus"]['Cruise_On'] != 0 else: ret.cruiseState.enabled = cp_cruise.vl["CruiseControl"]["Cruise_Activated"] != 0 diff --git a/opendbc/car/subaru/subarucan.py b/opendbc/car/subaru/subarucan.py index 64cab421..09b552ab 100644 --- a/opendbc/car/subaru/subarucan.py +++ b/opendbc/car/subaru/subarucan.py @@ -147,8 +147,8 @@ def create_es_dashstatus(packer, frame, dashstatus_msg, enabled, long_enabled, l "Signal4", "Conventional_Cruise", "Signal5", - "Cruise_Disengaged", - "Cruise_Activated", + "Cruise_Disengaged_Dash", + "Cruise_Activated_Dash", "Signal6", "Cruise_Set_Speed", "Cruise_Fault", @@ -165,8 +165,9 @@ def create_es_dashstatus(packer, frame, dashstatus_msg, enabled, long_enabled, l if long_enabled: values["Cruise_State"] = 0 - values["Cruise_Activated"] = enabled - values["Cruise_Disengaged"] = 0 + # TODO: Cruise_Activated_dash should respect gas pressed and standstill stock behavior + values["Cruise_Activated_Dash"] = enabled + values["Cruise_Disengaged_Dash"] = 0 values["Car_Follow"] = int(lead_visible) values["PCB_Off"] = 1 # AEB is not presevered, so show the PCB_Off on dash diff --git a/opendbc/dbc/generator/subaru/_subaru_global.dbc b/opendbc/dbc/generator/subaru/_subaru_global.dbc index cb06822c..67f63216 100644 --- a/opendbc/dbc/generator/subaru/_subaru_global.dbc +++ b/opendbc/dbc/generator/subaru/_subaru_global.dbc @@ -213,8 +213,8 @@ BO_ 801 ES_DashStatus: 8 XXX SG_ Signal4 : 31|1@1+ (1,0) [0|1] "" XXX SG_ Conventional_Cruise : 32|1@1+ (1,0) [0|1] "" XXX SG_ Signal5 : 33|2@1+ (1,0) [0|3] "" XXX - SG_ Cruise_Disengaged : 35|1@1+ (1,0) [0|1] "" XXX - SG_ Cruise_Activated : 36|1@1+ (1,0) [0|1] "" XXX + SG_ Cruise_Disengaged_Dash : 35|1@1+ (1,0) [0|1] "" XXX + SG_ Cruise_Activated_Dash : 36|1@1+ (1,0) [0|1] "" XXX SG_ Signal6 : 37|3@1+ (1,0) [0|1] "" XXX SG_ Cruise_Set_Speed : 40|8@1+ (1,0) [0|255] "" XXX SG_ Cruise_Fault : 48|1@1+ (1,0) [0|1] "" XXX @@ -285,6 +285,7 @@ CM_ SG_ 544 Cruise_Brake_Lights "1 = switch on brake lights"; CM_ SG_ 544 Brake_Pressure "Winds down after cruise disabled. Also can be non-zero when likely preparing for AEB"; CM_ SG_ 544 Signal3 "Usually goes to 2 if AEB_Status is 4"; CM_ SG_ 544 AEB_Status "Occasionally is 4 instead of 8 while Brake_Pressure is non-zero, unsure why"; +CM_ SG_ 801 Cruise_Activated_Dash "Falls during user gas or standstill. This is likely only a UI signal to the dash to show if ACC is actually actuating"; CM_ SG_ 801 PCB_Off "Pre-Collision Braking off"; CM_ SG_ 801 Brake_Lights "Driver or Cruise brake on"; CM_ SG_ 801 Cruise_State "0 = Normal, 1 = Hold+User Brake, 2 = Ready, 3 = Hold"; diff --git a/opendbc/dbc/generator/subaru/subaru_forester_2017.dbc b/opendbc/dbc/generator/subaru/subaru_forester_2017.dbc index 6d5d46bc..34dc730a 100644 --- a/opendbc/dbc/generator/subaru/subaru_forester_2017.dbc +++ b/opendbc/dbc/generator/subaru/subaru_forester_2017.dbc @@ -3,7 +3,7 @@ CM_ "IMPORT _subaru_preglobal_2015.dbc"; BO_ 355 ES_DashStatus: 8 XXX SG_ Not_Ready_Startup : 4|2@1+ (1,0) [0|3] "" XXX SG_ Cruise_On : 16|1@1+ (1,0) [0|1] "" XXX - SG_ Cruise_Activated : 17|1@0+ (1,0) [0|1] "" XXX + SG_ Cruise_Activated_Dash : 17|1@0+ (1,0) [0|1] "" XXX SG_ Cruise_Set_Speed : 24|8@1+ (1,0) [0|255] "" XXX SG_ COUNTER : 40|3@1+ (1,0) [0|7] "" XXX SG_ Brake : 43|1@1+ (1,0) [0|1] "" XXX diff --git a/opendbc/dbc/generator/subaru/subaru_outback_2015.dbc b/opendbc/dbc/generator/subaru/subaru_outback_2015.dbc index cc1fa16d..8134dd42 100644 --- a/opendbc/dbc/generator/subaru/subaru_outback_2015.dbc +++ b/opendbc/dbc/generator/subaru/subaru_outback_2015.dbc @@ -5,7 +5,7 @@ BO_ 358 ES_DashStatus: 8 XXX SG_ Seatbelt_Disengage : 12|2@1+ (1,0) [0|3] "" XXX SG_ Disengage_Alert : 14|2@1+ (1,0) [0|3] "" XXX SG_ Cruise_On : 16|1@1+ (1,0) [0|1] "" XXX - SG_ Cruise_Activated : 17|1@1+ (1,0) [0|1] "" XXX + SG_ Cruise_Activated_Dash : 17|1@1+ (1,0) [0|1] "" XXX SG_ Signal1 : 18|1@1+ (1,0) [0|1] "" XXX SG_ WHEELS_MOVING_2015 : 19|1@1+ (1,0) [0|1] "" XXX SG_ Driver_Input : 20|1@1+ (1,0) [0|1] "" XXX diff --git a/opendbc/dbc/generator/subaru/subaru_outback_2019.dbc b/opendbc/dbc/generator/subaru/subaru_outback_2019.dbc index d886954c..b04142fb 100644 --- a/opendbc/dbc/generator/subaru/subaru_outback_2019.dbc +++ b/opendbc/dbc/generator/subaru/subaru_outback_2019.dbc @@ -5,7 +5,7 @@ BO_ 358 ES_DashStatus: 8 XXX SG_ Seatbelt_Disengage : 12|2@1+ (1,0) [0|3] "" XXX SG_ Disengage_Alert : 14|2@1+ (1,0) [0|3] "" XXX SG_ Cruise_On : 16|1@1+ (1,0) [0|1] "" XXX - SG_ Cruise_Activated : 17|1@1+ (1,0) [0|1] "" XXX + SG_ Cruise_Activated_Dash : 17|1@1+ (1,0) [0|1] "" XXX SG_ Signal1 : 18|1@1+ (1,0) [0|1] "" XXX SG_ WHEELS_MOVING_2015 : 19|1@1+ (1,0) [0|1] "" XXX SG_ Driver_Input : 20|1@1+ (1,0) [0|1] "" XXX From 497727cbed95e9fd77de7f2483eed0e446aa0a5a Mon Sep 17 00:00:00 2001 From: adeebshihadeh Date: Sat, 31 Jan 2026 08:09:39 +0000 Subject: [PATCH 58/77] docs: Scheduled auto-update CARS.md --- docs/CARS.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/CARS.md b/docs/CARS.md index 4d3f6b4c..88514042 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -1,9 +1,10 @@ -# Support Information for 387 Known Cars +# Support Information for 390 Known Cars |Make|Model|Package|Support Level| |---|---|---|:---:| +|Acura|ADX 2025-26|All|[Community](#community)| |Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|[Upstream](#upstream)| |Acura|ILX 2019|All|[Upstream](#upstream)| |Acura|Integra 2023-25|All|[Community](#community)| @@ -11,6 +12,7 @@ |Acura|MDX 2017-20|All|[Community](#community)| |Acura|MDX 2022-24|All|[Community](#community)| |Acura|MDX 2025-26|All except Type S|[Upstream](#upstream)| +|Acura|MDX Hybrid 2017-20|All|[Community](#community)| |Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|[Upstream](#upstream)| |Acura|RDX 2019-21|All|[Upstream](#upstream)| |Acura|RDX 2022-25|All|[Community](#community)| @@ -87,6 +89,7 @@ |Honda|Accord 2016-17|Honda Sensing|[Community](#community)| |Honda|Accord 2018-22|All|[Upstream](#upstream)| |Honda|Accord 2023-25|All|[Upstream](#upstream)| +|Honda|Accord Hybrid 2017|All|[Community](#community)| |Honda|Accord Hybrid 2018-22|All|[Upstream](#upstream)| |Honda|Accord Hybrid 2023-25|All|[Upstream](#upstream)| |Honda|City (Brazil only) 2023|All|[Upstream](#upstream)| From 3392232f3236ff5b1bb95e6be7793b0f9e2f8d83 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 31 Jan 2026 01:52:37 -0800 Subject: [PATCH 59/77] Subaru ANGLE_LKAS: fix cruise control signals (#3096) * outback is always zero? * move inside * fix bus --- opendbc/car/subaru/carstate.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/opendbc/car/subaru/carstate.py b/opendbc/car/subaru/carstate.py index 01b92925..adb4f7b6 100644 --- a/opendbc/car/subaru/carstate.py +++ b/opendbc/car/subaru/carstate.py @@ -81,10 +81,12 @@ class CarState(CarStateBase): ret.steeringPressed = abs(ret.steeringTorque) > steer_threshold cp_cruise = cp_alt if self.CP.flags & SubaruFlags.GLOBAL_GEN2 else cp - # ES_DashStatus->Cruise_Activated_Dash is likely intended for the dash display only, as it falls - # during user gas override and at standstill. ES_Status is missing on hybrid, so we use ES_Brake instead - if self.CP.flags & SubaruFlags.HYBRID: - ret.cruiseState.enabled = cp_cam.vl["ES_Brake"]['Cruise_Activated'] != 0 + cp_es_brake = cp_alt if self.CP.flags & SubaruFlags.GLOBAL_GEN2 else cp_cam + + if self.CP.flags & (SubaruFlags.HYBRID | SubaruFlags.LKAS_ANGLE): + # ES_DashStatus->Cruise_Activated_Dash is likely intended for the dash display only, as it falls + # during user gas override and at standstill. ES_Status is missing on hybrid, so we use ES_Brake instead + ret.cruiseState.enabled = cp_es_brake.vl["ES_Brake"]['Cruise_Activated'] != 0 ret.cruiseState.available = cp_cam.vl["ES_DashStatus"]['Cruise_On'] != 0 else: ret.cruiseState.enabled = cp_cruise.vl["CruiseControl"]["Cruise_Activated"] != 0 @@ -113,9 +115,7 @@ class CarState(CarStateBase): (cp_cam.vl["ES_LKAS_State"]["LKAS_Alert"] == 2) self.es_lkas_state_msg = copy.copy(cp_cam.vl["ES_LKAS_State"]) - cp_es_brake = cp_alt if self.CP.flags & SubaruFlags.GLOBAL_GEN2 else cp_cam self.es_brake_msg = copy.copy(cp_es_brake.vl["ES_Brake"]) - cp_es_status = cp_alt if self.CP.flags & SubaruFlags.GLOBAL_GEN2 else cp_cam # TODO: Hybrid cars don't have ES_Distance, need a replacement if not (self.CP.flags & SubaruFlags.HYBRID): @@ -123,7 +123,7 @@ class CarState(CarStateBase): ret.stockAeb = (cp_es_distance.vl["ES_Brake"]["AEB_Status"] == 8) and \ (cp_es_distance.vl["ES_Brake"]["Brake_Pressure"] != 0) - self.es_status_msg = copy.copy(cp_es_status.vl["ES_Status"]) + self.es_status_msg = copy.copy(cp_es_brake.vl["ES_Status"]) self.cruise_control_msg = copy.copy(cp_cruise.vl["CruiseControl"]) if not (self.CP.flags & SubaruFlags.HYBRID): From 3676621a723232ddcaf578efd15c5554f98892a7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 31 Jan 2026 02:07:43 -0800 Subject: [PATCH 60/77] Clean up Subaru interface/angle cars (#3099) * clean up * unset too?1 * prob fine at 0.1 --- opendbc/car/subaru/interface.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/opendbc/car/subaru/interface.py b/opendbc/car/subaru/interface.py index b11a987d..5b16f17d 100644 --- a/opendbc/car/subaru/interface.py +++ b/opendbc/car/subaru/interface.py @@ -37,12 +37,13 @@ class CarInterface(CarInterfaceBase): ret.steerLimitTimer = 0.4 ret.steerActuatorDelay = 0.1 - if ret.flags & SubaruFlags.LKAS_ANGLE: - ret.steerControlType = structs.CarParams.SteerControlType.angle - else: + if not (ret.flags & SubaruFlags.LKAS_ANGLE): CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) - if candidate in (CAR.SUBARU_ASCENT, CAR.SUBARU_ASCENT_2023): + if ret.flags & SubaruFlags.LKAS_ANGLE: + ret.steerControlType = structs.CarParams.SteerControlType.angle + + elif candidate == CAR.SUBARU_ASCENT: ret.steerActuatorDelay = 0.3 # end-to-end angle controller ret.lateralTuning.init('pid') ret.lateralTuning.pid.kf = 0.00003 @@ -65,13 +66,13 @@ class CarInterface(CarInterfaceBase): elif candidate == CAR.SUBARU_CROSSTREK_HYBRID: ret.steerActuatorDelay = 0.1 - elif candidate in (CAR.SUBARU_FORESTER, CAR.SUBARU_FORESTER_2022, CAR.SUBARU_FORESTER_HYBRID): + elif candidate in (CAR.SUBARU_FORESTER, CAR.SUBARU_FORESTER_HYBRID): ret.lateralTuning.init('pid') ret.lateralTuning.pid.kf = 0.000038 ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 14., 23.], [0., 14., 23.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01, 0.065, 0.2], [0.001, 0.015, 0.025]] - elif candidate in (CAR.SUBARU_OUTBACK, CAR.SUBARU_LEGACY, CAR.SUBARU_OUTBACK_2023): + elif candidate in (CAR.SUBARU_OUTBACK, CAR.SUBARU_LEGACY): ret.steerActuatorDelay = 0.1 elif candidate in (CAR.SUBARU_FORESTER_PREGLOBAL, CAR.SUBARU_OUTBACK_PREGLOBAL_2018): From cc29c459792c491c39b1bf19353c6267a2e95d84 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 31 Jan 2026 02:14:39 -0800 Subject: [PATCH 61/77] Subaru: remove unused safety angle measurement (#3100) * we simply don't use this * as well --- opendbc/safety/modes/subaru.h | 5 ----- opendbc/safety/tests/test_subaru.py | 4 ---- 2 files changed, 9 deletions(-) diff --git a/opendbc/safety/modes/subaru.h b/opendbc/safety/modes/subaru.h index 9b01d39d..f5487a67 100644 --- a/opendbc/safety/modes/subaru.h +++ b/opendbc/safety/modes/subaru.h @@ -98,11 +98,6 @@ static void subaru_rx_hook(const CANPacket_t *msg) { torque_driver_new = ((GET_BYTES(msg, 0, 4) >> 16) & 0x7FFU); torque_driver_new = -1 * to_signed(torque_driver_new, 11); update_sample(&torque_driver, torque_driver_new); - - int angle_meas_new = (GET_BYTES(msg, 4, 2) & 0xFFFFU); - // convert Steering_Torque -> Steering_Angle to centidegrees, to match the ES_LKAS_ANGLE angle request units - angle_meas_new = ROUND(to_signed(angle_meas_new, 16) * -2.17); - update_sample(&angle_meas, angle_meas_new); } // enter controls on rising edge of ACC, exit controls on ACC off diff --git a/opendbc/safety/tests/test_subaru.py b/opendbc/safety/tests/test_subaru.py index a0ad42d8..d5183eec 100755 --- a/opendbc/safety/tests/test_subaru.py +++ b/opendbc/safety/tests/test_subaru.py @@ -95,10 +95,6 @@ class TestSubaruSafetyBase(common.CarSafetyTest): values = {s: speed for s in ["FR", "FL", "RR", "RL"]} return self.packer.make_can_msg_safety("Wheel_Speeds", self.ALT_MAIN_BUS, values) - def _angle_meas_msg(self, angle): - values = {"Steering_Angle": angle} - return self.packer.make_can_msg_safety("Steering_Torque", 0, values) - def _user_brake_msg(self, brake): values = {"Brake": brake} return self.packer.make_can_msg_safety("Brake_Status", self.ALT_MAIN_BUS, values) From c2eba0b51deb51a99380391c469859d3fc65cc0f Mon Sep 17 00:00:00 2001 From: Jacob Waller Date: Sat, 31 Jan 2026 23:18:21 -0600 Subject: [PATCH 62/77] Fix Subaru message definitions for HighBeamAssist and static messages (#3102) Co-authored-by: Jacob Waller --- opendbc/safety/modes/subaru.h | 6 +++--- opendbc/safety/tests/test_subaru.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/opendbc/safety/modes/subaru.h b/opendbc/safety/modes/subaru.h index f5487a67..a27b6e59 100644 --- a/opendbc/safety/modes/subaru.h +++ b/opendbc/safety/modes/subaru.h @@ -35,9 +35,9 @@ #define MSG_SUBARU_ES_UDS_Request 0x787U -#define MSG_SUBARU_ES_HighBeamAssist 0x121U -#define MSG_SUBARU_ES_STATIC_1 0x22aU -#define MSG_SUBARU_ES_STATIC_2 0x325U +#define MSG_SUBARU_ES_HighBeamAssist 0x22AU +#define MSG_SUBARU_ES_STATIC_1 0x325U +#define MSG_SUBARU_ES_STATIC_2 0x121U #define SUBARU_MAIN_BUS 0U #define SUBARU_ALT_BUS 1U diff --git a/opendbc/safety/tests/test_subaru.py b/opendbc/safety/tests/test_subaru.py index d5183eec..a882f072 100755 --- a/opendbc/safety/tests/test_subaru.py +++ b/opendbc/safety/tests/test_subaru.py @@ -25,9 +25,9 @@ class SubaruMsg(enum.IntEnum): ES_LKAS_State = 0x322 ES_Infotainment = 0x323 ES_UDS_Request = 0x787 - ES_HighBeamAssist = 0x121 - ES_STATIC_1 = 0x22a - ES_STATIC_2 = 0x325 + ES_HighBeamAssist = 0x22A + ES_STATIC_1 = 0x325 + ES_STATIC_2 = 0x121 SUBARU_MAIN_BUS = 0 From de9d0ef4509a9a55da4c14d6d20c0714da7909f4 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 31 Jan 2026 21:44:27 -0800 Subject: [PATCH 63/77] add Subaru angle/hybrid cruise TODO --- opendbc/car/subaru/carstate.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/opendbc/car/subaru/carstate.py b/opendbc/car/subaru/carstate.py index adb4f7b6..d90dfa98 100644 --- a/opendbc/car/subaru/carstate.py +++ b/opendbc/car/subaru/carstate.py @@ -86,6 +86,10 @@ class CarState(CarStateBase): if self.CP.flags & (SubaruFlags.HYBRID | SubaruFlags.LKAS_ANGLE): # ES_DashStatus->Cruise_Activated_Dash is likely intended for the dash display only, as it falls # during user gas override and at standstill. ES_Status is missing on hybrid, so we use ES_Brake instead + + # TODO: ES_Brake->Cruise_Activated has been seen staying high when Crosstrek 2025 angle LKAs user pressed + # brake while engaged at a stop. ES_Status and ES_DashStatus->Signal7 correctly fell, but is either missing or + # always zero on hybrids. Probably need to split angle & hybrid. 0x27 and 0x225 on hybrids may work for them. ret.cruiseState.enabled = cp_es_brake.vl["ES_Brake"]['Cruise_Activated'] != 0 ret.cruiseState.available = cp_cam.vl["ES_DashStatus"]['Cruise_On'] != 0 else: From fe3bf2383c7e18aca45368c7e6d7540999ca64cf Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 31 Jan 2026 21:45:15 -0800 Subject: [PATCH 64/77] typo route is 38b065e31c0a9ed7/000000cf--a4a20815a6 --- opendbc/car/subaru/carstate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc/car/subaru/carstate.py b/opendbc/car/subaru/carstate.py index d90dfa98..4d242f83 100644 --- a/opendbc/car/subaru/carstate.py +++ b/opendbc/car/subaru/carstate.py @@ -87,7 +87,7 @@ class CarState(CarStateBase): # ES_DashStatus->Cruise_Activated_Dash is likely intended for the dash display only, as it falls # during user gas override and at standstill. ES_Status is missing on hybrid, so we use ES_Brake instead - # TODO: ES_Brake->Cruise_Activated has been seen staying high when Crosstrek 2025 angle LKAs user pressed + # TODO: ES_Brake->Cruise_Activated has been seen staying high when Crosstrek 2025 angle LKAS user pressed # brake while engaged at a stop. ES_Status and ES_DashStatus->Signal7 correctly fell, but is either missing or # always zero on hybrids. Probably need to split angle & hybrid. 0x27 and 0x225 on hybrids may work for them. ret.cruiseState.enabled = cp_es_brake.vl["ES_Brake"]['Cruise_Activated'] != 0 From 3d6860a4b638b9522033835895a03a683cc9de4a Mon Sep 17 00:00:00 2001 From: Daniel Koepping Date: Sat, 31 Jan 2026 22:36:25 -0800 Subject: [PATCH 65/77] Car Diff: wrap output (#3098) hide changes --- opendbc/car/tests/car_diff.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opendbc/car/tests/car_diff.py b/opendbc/car/tests/car_diff.py index 74c9c959..b4424be8 100755 --- a/opendbc/car/tests/car_diff.py +++ b/opendbc/car/tests/car_diff.py @@ -297,7 +297,7 @@ def main(platform: str | None = None, segments_per_platform: int = 10, update_re print(f"\nERROR {plat} - {seg}: {err}") if with_diffs: - print("```") + print("
Show changes\n\n```") for plat, seg, diffs, ref, states in with_diffs: print(f"\n{plat} - {seg}") by_field = defaultdict(list) @@ -307,7 +307,7 @@ def main(platform: str | None = None, segments_per_platform: int = 10, update_re print(f"\n {field} ({len(fd)} diffs)") for line in format_diff(fd, ref, states, field): print(line) - print("```") + print("```\n
") return 1 if errors else 0 From c7a71c36cebce2224ced4b5cb5236537f68ccd32 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sun, 1 Feb 2026 22:03:59 -0500 Subject: [PATCH 66/77] Revert "Toyota: remove NO_STOP_TIMER flag (#3076)" This reverts commit 1cd92abbf86b50ccd0a5782e6a5d598c14d94e7e. --- opendbc/car/toyota/carcontroller.py | 29 ++++++++++++++++++++++------- opendbc/car/toyota/carstate.py | 13 ++++++++----- opendbc/car/toyota/interface.py | 9 +++++---- opendbc/car/toyota/values.py | 15 +++++++++++---- 4 files changed, 46 insertions(+), 20 deletions(-) diff --git a/opendbc/car/toyota/carcontroller.py b/opendbc/car/toyota/carcontroller.py index 82371d43..e5e3df96 100644 --- a/opendbc/car/toyota/carcontroller.py +++ b/opendbc/car/toyota/carcontroller.py @@ -8,7 +8,9 @@ from opendbc.car.common.pid import PIDController from opendbc.car.secoc import add_mac, build_sync_mac from opendbc.car.interfaces import CarControllerBase from opendbc.car.toyota import toyotacan -from opendbc.car.toyota.values import CAR, TSS2_CAR, UNSUPPORTED_DSU_CAR, CarControllerParams, ToyotaFlags +from opendbc.car.toyota.values import CAR, NO_STOP_TIMER_CAR, TSS2_CAR, \ + CarControllerParams, ToyotaFlags, \ + UNSUPPORTED_DSU_CAR from opendbc.can import CANPacker Ecu = structs.CarParams.Ecu @@ -53,6 +55,7 @@ class CarController(CarControllerBase): self.last_torque = 0 self.last_angle = 0 self.alert_active = False + self.last_standstill = False self.standstill_req = False self.permit_braking = True self.steer_rate_counter = 0 @@ -165,13 +168,17 @@ class CarController(CarControllerBase): self.secoc_lta_message_counter += 1 can_sends.append(lta_steer_2) - # handle UI messages - fcw_alert = hud_control.visualAlert == VisualAlert.fcw - steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) - lead = hud_control.leadVisible or CS.out.vEgo < 12. # at low speed we always assume the lead is present so ACC can be engaged - # *** gas and brake *** - if self.CP.openpilotLongitudinalControl: + + # on entering standstill, send standstill request for older TSS-P cars that aren't designed to stay engaged at a stop + if self.CP.carFingerprint not in NO_STOP_TIMER_CAR: + if CS.out.standstill and not self.last_standstill: + self.standstill_req = True + if CS.pcm_acc_status != 8: + # pcm entered standstill or it's disabled + self.standstill_req = False + + else: # if user engages at a stop with foot on brake, PCM starts in a special cruise standstill mode. on resume press, # brakes can take a while to ramp up causing a lurch forward. prevent resume press until planner wants to move. # don't use CC.cruiseControl.resume since it is gated on CS.cruiseState.standstill which goes false for 3s after resume press @@ -184,6 +191,14 @@ class CarController(CarControllerBase): if not should_resume and CS.out.cruiseState.standstill: self.standstill_req = True + self.last_standstill = CS.out.standstill + + # handle UI messages + fcw_alert = hud_control.visualAlert == VisualAlert.fcw + steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) + lead = hud_control.leadVisible or CS.out.vEgo < 12. # at low speed we always assume the lead is present so ACC can be engaged + + if self.CP.openpilotLongitudinalControl: if self.frame % 3 == 0: # Press distance button until we are at the correct bar length. Only change while enabled to avoid skipping startup popup if self.frame % 6 == 0 and self.CP.openpilotLongitudinalControl: diff --git a/opendbc/car/toyota/carstate.py b/opendbc/car/toyota/carstate.py index ca50e70b..3fb22740 100644 --- a/opendbc/car/toyota/carstate.py +++ b/opendbc/car/toyota/carstate.py @@ -5,8 +5,9 @@ from opendbc.car import Bus, DT_CTRL, create_button_events, structs from opendbc.car.common.conversions import Conversions as CV from opendbc.car.common.filter_simple import FirstOrderFilter from opendbc.car.interfaces import CarStateBase -from opendbc.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, TSS2_CAR, RADAR_ACC_CAR, \ - EPS_SCALE, UNSUPPORTED_DSU_CAR, SECOC_CAR +from opendbc.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \ + TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR, \ + SECOC_CAR ButtonType = structs.CarState.ButtonEvent.Type SteerControlType = structs.CarParams.SteerControlType @@ -159,10 +160,12 @@ class CarState(CarStateBase): if self.CP.openpilotLongitudinalControl: ret.accFaulted = ret.accFaulted or cp.vl["PCM_CRUISE_2"]["LOW_SPEED_LOCKOUT"] == 2 - pcm_acc_status = cp.vl["PCM_CRUISE"]["CRUISE_STATE"] - ret.cruiseState.standstill = pcm_acc_status == 7 + self.pcm_acc_status = cp.vl["PCM_CRUISE"]["CRUISE_STATE"] + if self.CP.carFingerprint not in (NO_STOP_TIMER_CAR - TSS2_CAR): + # ignore standstill state in certain vehicles, since pcm allows to restart with just an acceleration request + ret.cruiseState.standstill = self.pcm_acc_status == 7 ret.cruiseState.enabled = bool(cp.vl["PCM_CRUISE"]["CRUISE_ACTIVE"]) - ret.cruiseState.nonAdaptive = pcm_acc_status in (1, 2, 3, 4, 5, 6) + ret.cruiseState.nonAdaptive = self.pcm_acc_status in (1, 2, 3, 4, 5, 6) ret.genericToggle = bool(cp.vl["LIGHT_STALK"]["AUTO_HIGH_BEAM"]) ret.espDisabled = cp.vl["ESP_CONTROL"]["TC_DISABLED"] != 0 diff --git a/opendbc/car/toyota/interface.py b/opendbc/car/toyota/interface.py index 5f44a58e..03cab7dd 100644 --- a/opendbc/car/toyota/interface.py +++ b/opendbc/car/toyota/interface.py @@ -3,7 +3,7 @@ from opendbc.car.toyota.carstate import CarState from opendbc.car.toyota.carcontroller import CarController from opendbc.car.toyota.radar_interface import RadarInterface from opendbc.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, MIN_ACC_SPEED, \ - EPS_SCALE, ANGLE_CONTROL_CAR, ToyotaSafetyFlags + EPS_SCALE, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR, ToyotaSafetyFlags from opendbc.car.disable_ecu import disable_ecu from opendbc.car.interfaces import CarInterfaceBase @@ -86,7 +86,7 @@ class CarInterface(CarInterfaceBase): ret.radarUnavailable = Bus.radar not in DBC[candidate] - # since we don't yet parse radar on TSS2 radar-based ACC cars, gate longitudinal behind alpha toggle + # since we don't yet parse radar on TSS2 radar-based ACC cars, gate longitudinal behind experimental toggle if candidate in RADAR_ACC_CAR: ret.alphaLongitudinalAvailable = True @@ -94,14 +94,15 @@ class CarInterface(CarInterfaceBase): ret.flags |= ToyotaFlags.DISABLE_RADAR.value # openpilot longitudinal enabled by default: + # - cars w/ DSU disconnected # - TSS2 cars with camera sending ACC_CONTROL where we can block it - # openpilot longitudinal behind alpha long toggle: + # openpilot longitudinal behind experimental long toggle: # - TSS2 radar ACC cars (disables radar) ret.openpilotLongitudinalControl = (candidate in (TSS2_CAR - RADAR_ACC_CAR) or bool(ret.flags & ToyotaFlags.DISABLE_RADAR.value)) - ret.autoResumeSng = ret.openpilotLongitudinalControl + ret.autoResumeSng = ret.openpilotLongitudinalControl and candidate in NO_STOP_TIMER_CAR if not ret.openpilotLongitudinalControl: ret.safetyConfigs[0].safetyParam |= ToyotaSafetyFlags.STOCK_LONGITUDINAL.value diff --git a/opendbc/car/toyota/values.py b/opendbc/car/toyota/values.py index 69d9b330..e482e86f 100644 --- a/opendbc/car/toyota/values.py +++ b/opendbc/car/toyota/values.py @@ -70,6 +70,7 @@ class ToyotaFlags(IntFlag): RADAR_ACC = 64 # these cars use the Lane Tracing Assist (LTA) message for lateral control ANGLE_CONTROL = 128 + NO_STOP_TIMER = 256 # these cars can utilize 2.0 m/s^2 RAISED_ACCEL_LIMIT = 1024 SECOC = 2048 @@ -77,8 +78,6 @@ class ToyotaFlags(IntFlag): # deprecated flags # these cars are speculated to allow stop and go when the DSU is unplugged SNG_WITHOUT_DSU_DEPRECATED = 512 - # no resume button press required - NO_STOP_TIMER_DEPRECATED = 256 def dbc_dict(pt, radar): @@ -108,7 +107,7 @@ class ToyotaTSS2PlatformConfig(PlatformConfig): dbc_dict: dict = field(default_factory=lambda: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas')) def init(self): - self.flags |= ToyotaFlags.TSS2 | ToyotaFlags.NO_DSU + self.flags |= ToyotaFlags.TSS2 | ToyotaFlags.NO_STOP_TIMER | ToyotaFlags.NO_DSU if self.flags & ToyotaFlags.RADAR_ACC: self.dbc_dict = {Bus.pt: 'toyota_nodsu_pt_generated'} @@ -119,7 +118,7 @@ class ToyotaSecOCPlatformConfig(PlatformConfig): dbc_dict: dict = field(default_factory=lambda: dbc_dict('toyota_secoc_pt_generated', 'toyota_tss2_adas')) def init(self): - self.flags |= ToyotaFlags.TSS2 | ToyotaFlags.NO_DSU | ToyotaFlags.SECOC + self.flags |= ToyotaFlags.TSS2 | ToyotaFlags.NO_STOP_TIMER | ToyotaFlags.NO_DSU | ToyotaFlags.SECOC if self.flags & ToyotaFlags.RADAR_ACC: self.dbc_dict = {Bus.pt: 'toyota_secoc_pt_generated'} @@ -217,6 +216,7 @@ class CAR(Platforms): ], CarSpecs(mass=4516. * CV.LB_TO_KG, wheelbase=2.8194, steerRatio=16.0, tireStiffnessFactor=0.8), dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'), + flags=ToyotaFlags.NO_STOP_TIMER, ) TOYOTA_HIGHLANDER_TSS2 = ToyotaTSS2PlatformConfig( [ @@ -238,6 +238,7 @@ class CAR(Platforms): [ToyotaCarDocs("Toyota Prius v 2017", "Toyota Safety Sense P", min_enable_speed=MIN_ACC_SPEED)], CarSpecs(mass=3340. * CV.LB_TO_KG, wheelbase=2.78, steerRatio=17.4, tireStiffnessFactor=0.5533), dbc_dict('toyota_new_mc_pt_generated', 'toyota_adas'), + flags=ToyotaFlags.NO_STOP_TIMER, ) TOYOTA_PRIUS_TSS2 = ToyotaTSS2PlatformConfig( [ @@ -261,6 +262,8 @@ class CAR(Platforms): ], TOYOTA_RAV4.specs, dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'), + # Note that the ICE RAV4 does not respect positive acceleration commands under 19 mph + flags=ToyotaFlags.NO_STOP_TIMER, ) TOYOTA_RAV4_TSS2 = ToyotaTSS2PlatformConfig( [ @@ -302,6 +305,7 @@ class CAR(Platforms): [ToyotaCarDocs("Toyota Sienna 2018-20", video="https://www.youtube.com/watch?v=q1UPOo4Sh68", min_enable_speed=MIN_ACC_SPEED)], CarSpecs(mass=4590. * CV.LB_TO_KG, wheelbase=3.03, steerRatio=15.5, tireStiffnessFactor=0.444), dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'), + flags=ToyotaFlags.NO_STOP_TIMER, ) TOYOTA_SIENNA_4TH_GEN = ToyotaSecOCPlatformConfig( [ToyotaSecOcCarDocs("Toyota Sienna 2021-23", min_enable_speed=MIN_ACC_SPEED)], @@ -601,4 +605,7 @@ ANGLE_CONTROL_CAR = CAR.with_flags(ToyotaFlags.ANGLE_CONTROL) SECOC_CAR = CAR.with_flags(ToyotaFlags.SECOC) +# no resume button press required +NO_STOP_TIMER_CAR = CAR.with_flags(ToyotaFlags.NO_STOP_TIMER) + DBC = CAR.create_dbc_map() From b0716570170d25d28d3e7e75d2a32bc9ef4edc14 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sun, 1 Feb 2026 22:04:15 -0500 Subject: [PATCH 67/77] Revert "Toyota: clean up radarUnavailable (#3075)" This reverts commit cbff382e5bb42a705ba880ca8feaf20298df8f7a. --- opendbc/car/toyota/interface.py | 9 ++++++--- opendbc/car/toyota/values.py | 5 ++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/opendbc/car/toyota/interface.py b/opendbc/car/toyota/interface.py index 03cab7dd..025a7e8d 100644 --- a/opendbc/car/toyota/interface.py +++ b/opendbc/car/toyota/interface.py @@ -2,8 +2,9 @@ from opendbc.car import Bus, structs, get_safety_config, uds from opendbc.car.toyota.carstate import CarState from opendbc.car.toyota.carcontroller import CarController from opendbc.car.toyota.radar_interface import RadarInterface -from opendbc.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, MIN_ACC_SPEED, \ - EPS_SCALE, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR, ToyotaSafetyFlags +from opendbc.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \ + MIN_ACC_SPEED, EPS_SCALE, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR, \ + ToyotaSafetyFlags from opendbc.car.disable_ecu import disable_ecu from opendbc.car.interfaces import CarInterfaceBase @@ -84,7 +85,9 @@ class CarInterface(CarInterfaceBase): # Detect flipped signals and enable for C-HR and others ret.enableBsm = 0x3F6 in fingerprint[0] and candidate in TSS2_CAR - ret.radarUnavailable = Bus.radar not in DBC[candidate] + # No radar dbc for cars without DSU which are not TSS 2.0 + # TODO: make an adas dbc file for dsu-less models + ret.radarUnavailable = Bus.radar not in DBC[candidate] or candidate in (NO_DSU_CAR - TSS2_CAR) # since we don't yet parse radar on TSS2 radar-based ACC cars, gate longitudinal behind experimental toggle if candidate in RADAR_ACC_CAR: diff --git a/opendbc/car/toyota/values.py b/opendbc/car/toyota/values.py index e482e86f..b7206ba8 100644 --- a/opendbc/car/toyota/values.py +++ b/opendbc/car/toyota/values.py @@ -156,14 +156,13 @@ class CAR(Platforms): ], TOYOTA_AVALON.specs, ) - # TODO: determine if TSS-P NO_DSU cars can work with toyota_adas radar DBC and re-enable TOYOTA_CAMRY = PlatformConfig( [ ToyotaCarDocs("Toyota Camry 2018-20", video="https://www.youtube.com/watch?v=fkcjviZY9CM", footnotes=[Footnote.CAMRY]), ToyotaCarDocs("Toyota Camry Hybrid 2018-20", video="https://www.youtube.com/watch?v=Q2DYY0AWKgk"), ], CarSpecs(mass=3400. * CV.LB_TO_KG, wheelbase=2.82448, steerRatio=13.7, tireStiffnessFactor=0.7933), - {Bus.pt: 'toyota_nodsu_pt_generated'}, + dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), flags=ToyotaFlags.NO_DSU, ) TOYOTA_CAMRY_TSS2 = ToyotaTSS2PlatformConfig( # TSS 2.5 @@ -179,7 +178,7 @@ class CAR(Platforms): ToyotaCarDocs("Toyota C-HR Hybrid 2017-20"), ], CarSpecs(mass=3300. * CV.LB_TO_KG, wheelbase=2.63906, steerRatio=13.6, tireStiffnessFactor=0.7933), - {Bus.pt: 'toyota_nodsu_pt_generated'}, + dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), flags=ToyotaFlags.NO_DSU, ) TOYOTA_CHR_TSS2 = ToyotaTSS2PlatformConfig( From 19d54330cc73895276f878dc08b68fab01f5987a Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sun, 1 Feb 2026 22:04:19 -0500 Subject: [PATCH 68/77] Revert "Toyota: clean up alpha long (#3074)" This reverts commit 8a25621e97fc022a56d0f3eb47be691832169cf7. --- opendbc/car/toyota/interface.py | 9 +++++---- opendbc/car/toyota/tests/test_toyota.py | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/opendbc/car/toyota/interface.py b/opendbc/car/toyota/interface.py index 025a7e8d..aab8be63 100644 --- a/opendbc/car/toyota/interface.py +++ b/opendbc/car/toyota/interface.py @@ -89,11 +89,12 @@ class CarInterface(CarInterfaceBase): # TODO: make an adas dbc file for dsu-less models ret.radarUnavailable = Bus.radar not in DBC[candidate] or candidate in (NO_DSU_CAR - TSS2_CAR) - # since we don't yet parse radar on TSS2 radar-based ACC cars, gate longitudinal behind experimental toggle - if candidate in RADAR_ACC_CAR: - ret.alphaLongitudinalAvailable = True + # since we don't yet parse radar on TSS2/TSS-P radar-based ACC cars, gate longitudinal behind experimental toggle + if candidate in (RADAR_ACC_CAR | NO_DSU_CAR): + ret.alphaLongitudinalAvailable = candidate in RADAR_ACC_CAR - if alpha_long: + # Disabling radar is only supported on TSS2 radar-ACC cars + if alpha_long and candidate in RADAR_ACC_CAR: ret.flags |= ToyotaFlags.DISABLE_RADAR.value # openpilot longitudinal enabled by default: diff --git a/opendbc/car/toyota/tests/test_toyota.py b/opendbc/car/toyota/tests/test_toyota.py index 2d07af54..5ab47f35 100644 --- a/opendbc/car/toyota/tests/test_toyota.py +++ b/opendbc/car/toyota/tests/test_toyota.py @@ -18,7 +18,6 @@ def check_fw_version(fw_version: bytes) -> bool: class TestToyotaInterfaces: def test_car_sets(self): - # Angle and radar-ACC cars are always TSS2 cars assert len(ANGLE_CONTROL_CAR - TSS2_CAR) == 0 assert len(RADAR_ACC_CAR - TSS2_CAR) == 0 From ccbf96e0ded81e3674d8bee454f7890f48478061 Mon Sep 17 00:00:00 2001 From: commaci-public <60409688+commaci-public@users.noreply.github.com> Date: Mon, 2 Feb 2026 07:49:32 -0800 Subject: [PATCH 69/77] [bot] Update uv.lock (#3104) Co-authored-by: Vehicle Researcher --- uv.lock | 104 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/uv.lock b/uv.lock index a5a81f54..42c7d21d 100644 --- a/uv.lock +++ b/uv.lock @@ -531,39 +531,39 @@ wheels = [ [[package]] name = "numpy" -version = "2.4.1" +version = "2.4.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/62/ae72ff66c0f1fd959925b4c11f8c2dea61f47f6acaea75a08512cdfe3fed/numpy-2.4.1.tar.gz", hash = "sha256:a1ceafc5042451a858231588a104093474c6a5c57dcc724841f5c888d237d690", size = 20721320, upload-time = "2026-01-10T06:44:59.619Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/fd/0005efbd0af48e55eb3c7208af93f2862d4b1a56cd78e84309a2d959208d/numpy-2.4.2.tar.gz", hash = "sha256:659a6107e31a83c4e33f763942275fd278b21d095094044eb35569e86a21ddae", size = 20723651, upload-time = "2026-01-31T23:13:10.135Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/34/2b1bc18424f3ad9af577f6ce23600319968a70575bd7db31ce66731bbef9/numpy-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0cce2a669e3c8ba02ee563c7835f92c153cf02edff1ae05e1823f1dde21b16a5", size = 16944563, upload-time = "2026-01-10T06:42:14.615Z" }, - { url = "https://files.pythonhosted.org/packages/2c/57/26e5f97d075aef3794045a6ca9eada6a4ed70eb9a40e7a4a93f9ac80d704/numpy-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:899d2c18024984814ac7e83f8f49d8e8180e2fbe1b2e252f2e7f1d06bea92425", size = 12645658, upload-time = "2026-01-10T06:42:17.298Z" }, - { url = "https://files.pythonhosted.org/packages/8e/ba/80fc0b1e3cb2fd5c6143f00f42eb67762aa043eaa05ca924ecc3222a7849/numpy-2.4.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:09aa8a87e45b55a1c2c205d42e2808849ece5c484b2aab11fecabec3841cafba", size = 5474132, upload-time = "2026-01-10T06:42:19.637Z" }, - { url = "https://files.pythonhosted.org/packages/40/ae/0a5b9a397f0e865ec171187c78d9b57e5588afc439a04ba9cab1ebb2c945/numpy-2.4.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:edee228f76ee2dab4579fad6f51f6a305de09d444280109e0f75df247ff21501", size = 6804159, upload-time = "2026-01-10T06:42:21.44Z" }, - { url = "https://files.pythonhosted.org/packages/86/9c/841c15e691c7085caa6fd162f063eff494099c8327aeccd509d1ab1e36ab/numpy-2.4.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a92f227dbcdc9e4c3e193add1a189a9909947d4f8504c576f4a732fd0b54240a", size = 14708058, upload-time = "2026-01-10T06:42:23.546Z" }, - { url = "https://files.pythonhosted.org/packages/5d/9d/7862db06743f489e6a502a3b93136d73aea27d97b2cf91504f70a27501d6/numpy-2.4.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:538bf4ec353709c765ff75ae616c34d3c3dca1a68312727e8f2676ea644f8509", size = 16651501, upload-time = "2026-01-10T06:42:25.909Z" }, - { url = "https://files.pythonhosted.org/packages/a6/9c/6fc34ebcbd4015c6e5f0c0ce38264010ce8a546cb6beacb457b84a75dfc8/numpy-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ac08c63cb7779b85e9d5318e6c3518b424bc1f364ac4cb2c6136f12e5ff2dccc", size = 16492627, upload-time = "2026-01-10T06:42:28.938Z" }, - { url = "https://files.pythonhosted.org/packages/aa/63/2494a8597502dacda439f61b3c0db4da59928150e62be0e99395c3ad23c5/numpy-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f9c360ecef085e5841c539a9a12b883dff005fbd7ce46722f5e9cef52634d82", size = 18585052, upload-time = "2026-01-10T06:42:31.312Z" }, - { url = "https://files.pythonhosted.org/packages/6a/93/098e1162ae7522fc9b618d6272b77404c4656c72432ecee3abc029aa3de0/numpy-2.4.1-cp311-cp311-win32.whl", hash = "sha256:0f118ce6b972080ba0758c6087c3617b5ba243d806268623dc34216d69099ba0", size = 6236575, upload-time = "2026-01-10T06:42:33.872Z" }, - { url = "https://files.pythonhosted.org/packages/8c/de/f5e79650d23d9e12f38a7bc6b03ea0835b9575494f8ec94c11c6e773b1b1/numpy-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:18e14c4d09d55eef39a6ab5b08406e84bc6869c1e34eef45564804f90b7e0574", size = 12604479, upload-time = "2026-01-10T06:42:35.778Z" }, - { url = "https://files.pythonhosted.org/packages/dd/65/e1097a7047cff12ce3369bd003811516b20ba1078dbdec135e1cd7c16c56/numpy-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:6461de5113088b399d655d45c3897fa188766415d0f568f175ab071c8873bd73", size = 10578325, upload-time = "2026-01-10T06:42:38.518Z" }, - { url = "https://files.pythonhosted.org/packages/78/7f/ec53e32bf10c813604edf07a3682616bd931d026fcde7b6d13195dfb684a/numpy-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d3703409aac693fa82c0aee023a1ae06a6e9d065dba10f5e8e80f642f1e9d0a2", size = 16656888, upload-time = "2026-01-10T06:42:40.913Z" }, - { url = "https://files.pythonhosted.org/packages/b8/e0/1f9585d7dae8f14864e948fd7fa86c6cb72dee2676ca2748e63b1c5acfe0/numpy-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7211b95ca365519d3596a1d8688a95874cc94219d417504d9ecb2df99fa7bfa8", size = 12373956, upload-time = "2026-01-10T06:42:43.091Z" }, - { url = "https://files.pythonhosted.org/packages/8e/43/9762e88909ff2326f5e7536fa8cb3c49fb03a7d92705f23e6e7f553d9cb3/numpy-2.4.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5adf01965456a664fc727ed69cc71848f28d063217c63e1a0e200a118d5eec9a", size = 5202567, upload-time = "2026-01-10T06:42:45.107Z" }, - { url = "https://files.pythonhosted.org/packages/4b/ee/34b7930eb61e79feb4478800a4b95b46566969d837546aa7c034c742ef98/numpy-2.4.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:26f0bcd9c79a00e339565b303badc74d3ea2bd6d52191eeca5f95936cad107d0", size = 6549459, upload-time = "2026-01-10T06:42:48.152Z" }, - { url = "https://files.pythonhosted.org/packages/79/e3/5f115fae982565771be994867c89bcd8d7208dbfe9469185497d70de5ddf/numpy-2.4.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0093e85df2960d7e4049664b26afc58b03236e967fb942354deef3208857a04c", size = 14404859, upload-time = "2026-01-10T06:42:49.947Z" }, - { url = "https://files.pythonhosted.org/packages/d9/7d/9c8a781c88933725445a859cac5d01b5871588a15969ee6aeb618ba99eee/numpy-2.4.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ad270f438cbdd402c364980317fb6b117d9ec5e226fff5b4148dd9aa9fc6e02", size = 16371419, upload-time = "2026-01-10T06:42:52.409Z" }, - { url = "https://files.pythonhosted.org/packages/a6/d2/8aa084818554543f17cf4162c42f162acbd3bb42688aefdba6628a859f77/numpy-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:297c72b1b98100c2e8f873d5d35fb551fce7040ade83d67dd51d38c8d42a2162", size = 16182131, upload-time = "2026-01-10T06:42:54.694Z" }, - { url = "https://files.pythonhosted.org/packages/60/db/0425216684297c58a8df35f3284ef56ec4a043e6d283f8a59c53562caf1b/numpy-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf6470d91d34bf669f61d515499859fa7a4c2f7c36434afb70e82df7217933f9", size = 18295342, upload-time = "2026-01-10T06:42:56.991Z" }, - { url = "https://files.pythonhosted.org/packages/31/4c/14cb9d86240bd8c386c881bafbe43f001284b7cce3bc01623ac9475da163/numpy-2.4.1-cp312-cp312-win32.whl", hash = "sha256:b6bcf39112e956594b3331316d90c90c90fb961e39696bda97b89462f5f3943f", size = 5959015, upload-time = "2026-01-10T06:42:59.631Z" }, - { url = "https://files.pythonhosted.org/packages/51/cf/52a703dbeb0c65807540d29699fef5fda073434ff61846a564d5c296420f/numpy-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:e1a27bb1b2dee45a2a53f5ca6ff2d1a7f135287883a1689e930d44d1ff296c87", size = 12310730, upload-time = "2026-01-10T06:43:01.627Z" }, - { url = "https://files.pythonhosted.org/packages/69/80/a828b2d0ade5e74a9fe0f4e0a17c30fdc26232ad2bc8c9f8b3197cf7cf18/numpy-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:0e6e8f9d9ecf95399982019c01223dc130542960a12edfa8edd1122dfa66a8a8", size = 10312166, upload-time = "2026-01-10T06:43:03.673Z" }, - { url = "https://files.pythonhosted.org/packages/1e/48/d86f97919e79314a1cdee4c832178763e6e98e623e123d0bada19e92c15a/numpy-2.4.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8ad35f20be147a204e28b6a0575fbf3540c5e5f802634d4258d55b1ff5facce1", size = 16822202, upload-time = "2026-01-10T06:44:43.738Z" }, - { url = "https://files.pythonhosted.org/packages/51/e9/1e62a7f77e0f37dcfb0ad6a9744e65df00242b6ea37dfafb55debcbf5b55/numpy-2.4.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:8097529164c0f3e32bb89412a0905d9100bf434d9692d9fc275e18dcf53c9344", size = 12569985, upload-time = "2026-01-10T06:44:45.945Z" }, - { url = "https://files.pythonhosted.org/packages/c7/7e/914d54f0c801342306fdcdce3e994a56476f1b818c46c47fc21ae968088c/numpy-2.4.1-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:ea66d2b41ca4a1630aae5507ee0a71647d3124d1741980138aa8f28f44dac36e", size = 5398484, upload-time = "2026-01-10T06:44:48.012Z" }, - { url = "https://files.pythonhosted.org/packages/1c/d8/9570b68584e293a33474e7b5a77ca404f1dcc655e40050a600dee81d27fb/numpy-2.4.1-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:d3f8f0df9f4b8be57b3bf74a1d087fec68f927a2fab68231fdb442bf2c12e426", size = 6713216, upload-time = "2026-01-10T06:44:49.725Z" }, - { url = "https://files.pythonhosted.org/packages/33/9b/9dd6e2db8d49eb24f86acaaa5258e5f4c8ed38209a4ee9de2d1a0ca25045/numpy-2.4.1-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2023ef86243690c2791fd6353e5b4848eedaa88ca8a2d129f462049f6d484696", size = 14538937, upload-time = "2026-01-10T06:44:51.498Z" }, - { url = "https://files.pythonhosted.org/packages/53/87/d5bd995b0f798a37105b876350d346eea5838bd8f77ea3d7a48392f3812b/numpy-2.4.1-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8361ea4220d763e54cff2fbe7d8c93526b744f7cd9ddab47afeff7e14e8503be", size = 16479830, upload-time = "2026-01-10T06:44:53.931Z" }, - { url = "https://files.pythonhosted.org/packages/5b/c7/b801bf98514b6ae6475e941ac05c58e6411dd863ea92916bfd6d510b08c1/numpy-2.4.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:4f1b68ff47680c2925f8063402a693ede215f0257f02596b1318ecdfb1d79e33", size = 12492579, upload-time = "2026-01-10T06:44:57.094Z" }, + { url = "https://files.pythonhosted.org/packages/d3/44/71852273146957899753e69986246d6a176061ea183407e95418c2aa4d9a/numpy-2.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7e88598032542bd49af7c4747541422884219056c268823ef6e5e89851c8825", size = 16955478, upload-time = "2026-01-31T23:10:25.623Z" }, + { url = "https://files.pythonhosted.org/packages/74/41/5d17d4058bd0cd96bcbd4d9ff0fb2e21f52702aab9a72e4a594efa18692f/numpy-2.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7edc794af8b36ca37ef5fcb5e0d128c7e0595c7b96a2318d1badb6fcd8ee86b1", size = 14965467, upload-time = "2026-01-31T23:10:28.186Z" }, + { url = "https://files.pythonhosted.org/packages/49/48/fb1ce8136c19452ed15f033f8aee91d5defe515094e330ce368a0647846f/numpy-2.4.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:6e9f61981ace1360e42737e2bae58b27bf28a1b27e781721047d84bd754d32e7", size = 5475172, upload-time = "2026-01-31T23:10:30.848Z" }, + { url = "https://files.pythonhosted.org/packages/40/a9/3feb49f17bbd1300dd2570432961f5c8a4ffeff1db6f02c7273bd020a4c9/numpy-2.4.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:cb7bbb88aa74908950d979eeaa24dbdf1a865e3c7e45ff0121d8f70387b55f73", size = 6805145, upload-time = "2026-01-31T23:10:32.352Z" }, + { url = "https://files.pythonhosted.org/packages/3f/39/fdf35cbd6d6e2fcad42fcf85ac04a85a0d0fbfbf34b30721c98d602fd70a/numpy-2.4.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f069069931240b3fc703f1e23df63443dbd6390614c8c44a87d96cd0ec81eb1", size = 15966084, upload-time = "2026-01-31T23:10:34.502Z" }, + { url = "https://files.pythonhosted.org/packages/1b/46/6fa4ea94f1ddf969b2ee941290cca6f1bfac92b53c76ae5f44afe17ceb69/numpy-2.4.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c02ef4401a506fb60b411467ad501e1429a3487abca4664871d9ae0b46c8ba32", size = 16899477, upload-time = "2026-01-31T23:10:37.075Z" }, + { url = "https://files.pythonhosted.org/packages/09/a1/2a424e162b1a14a5bd860a464ab4e07513916a64ab1683fae262f735ccd2/numpy-2.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2653de5c24910e49c2b106499803124dde62a5a1fe0eedeaecf4309a5f639390", size = 17323429, upload-time = "2026-01-31T23:10:39.704Z" }, + { url = "https://files.pythonhosted.org/packages/ce/a2/73014149ff250628df72c58204822ac01d768697913881aacf839ff78680/numpy-2.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1ae241bbfc6ae276f94a170b14785e561cb5e7f626b6688cf076af4110887413", size = 18635109, upload-time = "2026-01-31T23:10:41.924Z" }, + { url = "https://files.pythonhosted.org/packages/6c/0c/73e8be2f1accd56df74abc1c5e18527822067dced5ec0861b5bb882c2ce0/numpy-2.4.2-cp311-cp311-win32.whl", hash = "sha256:df1b10187212b198dd45fa943d8985a3c8cf854aed4923796e0e019e113a1bda", size = 6237915, upload-time = "2026-01-31T23:10:45.26Z" }, + { url = "https://files.pythonhosted.org/packages/76/ae/e0265e0163cf127c24c3969d29f1c4c64551a1e375d95a13d32eab25d364/numpy-2.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:b9c618d56a29c9cb1c4da979e9899be7578d2e0b3c24d52079c166324c9e8695", size = 12607972, upload-time = "2026-01-31T23:10:47.021Z" }, + { url = "https://files.pythonhosted.org/packages/29/a5/c43029af9b8014d6ea157f192652c50042e8911f4300f8f6ed3336bf437f/numpy-2.4.2-cp311-cp311-win_arm64.whl", hash = "sha256:47c5a6ed21d9452b10227e5e8a0e1c22979811cad7dcc19d8e3e2fb8fa03f1a3", size = 10485763, upload-time = "2026-01-31T23:10:50.087Z" }, + { url = "https://files.pythonhosted.org/packages/51/6e/6f394c9c77668153e14d4da83bcc247beb5952f6ead7699a1a2992613bea/numpy-2.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:21982668592194c609de53ba4933a7471880ccbaadcc52352694a59ecc860b3a", size = 16667963, upload-time = "2026-01-31T23:10:52.147Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f8/55483431f2b2fd015ae6ed4fe62288823ce908437ed49db5a03d15151678/numpy-2.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40397bda92382fcec844066efb11f13e1c9a3e2a8e8f318fb72ed8b6db9f60f1", size = 14693571, upload-time = "2026-01-31T23:10:54.789Z" }, + { url = "https://files.pythonhosted.org/packages/2f/20/18026832b1845cdc82248208dd929ca14c9d8f2bac391f67440707fff27c/numpy-2.4.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:b3a24467af63c67829bfaa61eecf18d5432d4f11992688537be59ecd6ad32f5e", size = 5203469, upload-time = "2026-01-31T23:10:57.343Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/2eb97c8a77daaba34eaa3fa7241a14ac5f51c46a6bd5911361b644c4a1e2/numpy-2.4.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:805cc8de9fd6e7a22da5aed858e0ab16be5a4db6c873dde1d7451c541553aa27", size = 6550820, upload-time = "2026-01-31T23:10:59.429Z" }, + { url = "https://files.pythonhosted.org/packages/b1/91/b97fdfd12dc75b02c44e26c6638241cc004d4079a0321a69c62f51470c4c/numpy-2.4.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d82351358ffbcdcd7b686b90742a9b86632d6c1c051016484fa0b326a0a1548", size = 15663067, upload-time = "2026-01-31T23:11:01.291Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c6/a18e59f3f0b8071cc85cbc8d80cd02d68aa9710170b2553a117203d46936/numpy-2.4.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e35d3e0144137d9fdae62912e869136164534d64a169f86438bc9561b6ad49f", size = 16619782, upload-time = "2026-01-31T23:11:03.669Z" }, + { url = "https://files.pythonhosted.org/packages/b7/83/9751502164601a79e18847309f5ceec0b1446d7b6aa12305759b72cf98b2/numpy-2.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adb6ed2ad29b9e15321d167d152ee909ec73395901b70936f029c3bc6d7f4460", size = 17013128, upload-time = "2026-01-31T23:11:05.913Z" }, + { url = "https://files.pythonhosted.org/packages/61/c4/c4066322256ec740acc1c8923a10047818691d2f8aec254798f3dd90f5f2/numpy-2.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8906e71fd8afcb76580404e2a950caef2685df3d2a57fe82a86ac8d33cc007ba", size = 18345324, upload-time = "2026-01-31T23:11:08.248Z" }, + { url = "https://files.pythonhosted.org/packages/ab/af/6157aa6da728fa4525a755bfad486ae7e3f76d4c1864138003eb84328497/numpy-2.4.2-cp312-cp312-win32.whl", hash = "sha256:ec055f6dae239a6299cace477b479cca2fc125c5675482daf1dd886933a1076f", size = 5960282, upload-time = "2026-01-31T23:11:10.497Z" }, + { url = "https://files.pythonhosted.org/packages/92/0f/7ceaaeaacb40567071e94dbf2c9480c0ae453d5bb4f52bea3892c39dc83c/numpy-2.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:209fae046e62d0ce6435fcfe3b1a10537e858249b3d9b05829e2a05218296a85", size = 12314210, upload-time = "2026-01-31T23:11:12.176Z" }, + { url = "https://files.pythonhosted.org/packages/2f/a3/56c5c604fae6dd40fa2ed3040d005fca97e91bd320d232ac9931d77ba13c/numpy-2.4.2-cp312-cp312-win_arm64.whl", hash = "sha256:fbde1b0c6e81d56f5dccd95dd4a711d9b95df1ae4009a60887e56b27e8d903fa", size = 10220171, upload-time = "2026-01-31T23:11:14.684Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f8/50e14d36d915ef64d8f8bc4a087fc8264d82c785eda6711f80ab7e620335/numpy-2.4.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:89f7268c009bc492f506abd6f5265defa7cb3f7487dc21d357c3d290add45082", size = 16833179, upload-time = "2026-01-31T23:12:53.5Z" }, + { url = "https://files.pythonhosted.org/packages/17/17/809b5cad63812058a8189e91a1e2d55a5a18fd04611dbad244e8aeae465c/numpy-2.4.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6dee3bb76aa4009d5a912180bf5b2de012532998d094acee25d9cb8dee3e44a", size = 14889755, upload-time = "2026-01-31T23:12:55.933Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ea/181b9bcf7627fc8371720316c24db888dcb9829b1c0270abf3d288b2e29b/numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:cd2bd2bbed13e213d6b55dc1d035a4f91748a7d3edc9480c13898b0353708920", size = 5399500, upload-time = "2026-01-31T23:12:58.671Z" }, + { url = "https://files.pythonhosted.org/packages/33/9f/413adf3fc955541ff5536b78fcf0754680b3c6d95103230252a2c9408d23/numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:cf28c0c1d4c4bf00f509fa7eb02c58d7caf221b50b467bcb0d9bbf1584d5c821", size = 6714252, upload-time = "2026-01-31T23:13:00.518Z" }, + { url = "https://files.pythonhosted.org/packages/91/da/643aad274e29ccbdf42ecd94dafe524b81c87bcb56b83872d54827f10543/numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e04ae107ac591763a47398bb45b568fc38f02dbc4aa44c063f67a131f99346cb", size = 15797142, upload-time = "2026-01-31T23:13:02.219Z" }, + { url = "https://files.pythonhosted.org/packages/66/27/965b8525e9cb5dc16481b30a1b3c21e50c7ebf6e9dbd48d0c4d0d5089c7e/numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:602f65afdef699cda27ec0b9224ae5dc43e328f4c24c689deaf77133dbee74d0", size = 16727979, upload-time = "2026-01-31T23:13:04.62Z" }, + { url = "https://files.pythonhosted.org/packages/de/e5/b7d20451657664b07986c2f6e3be564433f5dcaf3482d68eaecd79afaf03/numpy-2.4.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be71bf1edb48ebbbf7f6337b5bfd2f895d1902f6335a5830b20141fc126ffba0", size = 12502577, upload-time = "2026-01-31T23:13:07.08Z" }, ] [[package]] @@ -991,38 +991,38 @@ wheels = [ [[package]] name = "tqdm" -version = "4.67.1" +version = "4.67.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +sdist = { url = "https://files.pythonhosted.org/packages/27/89/4b0001b2dab8df0a5ee2787dcbe771de75ded01f18f1f8d53dedeea2882b/tqdm-4.67.2.tar.gz", hash = "sha256:649aac53964b2cb8dec76a14b405a4c0d13612cb8933aae547dd144eacc99653", size = 169514, upload-time = "2026-01-30T23:12:06.555Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e2/31eac96de2915cf20ccaed0225035db149dfb9165a9ed28d4b252ef3f7f7/tqdm-4.67.2-py3-none-any.whl", hash = "sha256:9a12abcbbff58b6036b2167d9d3853042b9d436fe7330f06ae047867f2f8e0a7", size = 78354, upload-time = "2026-01-30T23:12:04.368Z" }, ] [[package]] name = "ty" -version = "0.0.13" +version = "0.0.14" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/dc/b607f00916f5a7c52860b84a66dc17bc6988e8445e96b1d6e175a3837397/ty-0.0.13.tar.gz", hash = "sha256:7a1d135a400ca076407ea30012d1f75419634160ed3b9cad96607bf2956b23b3", size = 4999183, upload-time = "2026-01-21T13:21:16.133Z" } +sdist = { url = "https://files.pythonhosted.org/packages/af/57/22c3d6bf95c2229120c49ffc2f0da8d9e8823755a1c3194da56e51f1cc31/ty-0.0.14.tar.gz", hash = "sha256:a691010565f59dd7f15cf324cdcd1d9065e010c77a04f887e1ea070ba34a7de2", size = 5036573, upload-time = "2026-01-27T00:57:31.427Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/df/3632f1918f4c0a33184f107efc5d436ab6da147fd3d3b94b3af6461efbf4/ty-0.0.13-py3-none-linux_armv6l.whl", hash = "sha256:1b2b8e02697c3a94c722957d712a0615bcc317c9b9497be116ef746615d892f2", size = 9993501, upload-time = "2026-01-21T13:21:26.628Z" }, - { url = "https://files.pythonhosted.org/packages/92/87/6a473ced5ac280c6ce5b1627c71a8a695c64481b99aabc798718376a441e/ty-0.0.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f15cdb8e233e2b5adfce673bb21f4c5e8eaf3334842f7eea3c70ac6fda8c1de5", size = 9860986, upload-time = "2026-01-21T13:21:24.425Z" }, - { url = "https://files.pythonhosted.org/packages/5d/9b/d89ae375cf0a7cd9360e1164ce017f8c753759be63b6a11ed4c944abe8c6/ty-0.0.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:0819e89ac9f0d8af7a062837ce197f0461fee2fc14fd07e2c368780d3a397b73", size = 9350748, upload-time = "2026-01-21T13:21:28.502Z" }, - { url = "https://files.pythonhosted.org/packages/a8/a6/9ad58518056fab344b20c0bb2c1911936ebe195318e8acc3bc45ac1c6b6b/ty-0.0.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1de79f481084b7cc7a202ba0d7a75e10970d10ffa4f025b23f2e6b7324b74886", size = 9849884, upload-time = "2026-01-21T13:21:21.886Z" }, - { url = "https://files.pythonhosted.org/packages/b1/c3/8add69095fa179f523d9e9afcc15a00818af0a37f2b237a9b59bc0046c34/ty-0.0.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4fb2154cff7c6e95d46bfaba283c60642616f20d73e5f96d0c89c269f3e1bcec", size = 9822975, upload-time = "2026-01-21T13:21:14.292Z" }, - { url = "https://files.pythonhosted.org/packages/a4/05/4c0927c68a0a6d43fb02f3f0b6c19c64e3461dc8ed6c404dde0efb8058f7/ty-0.0.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00be58d89337c27968a20d58ca553458608c5b634170e2bec82824c2e4cf4d96", size = 10294045, upload-time = "2026-01-21T13:21:30.505Z" }, - { url = "https://files.pythonhosted.org/packages/b4/86/6dc190838aba967557fe0bfd494c595d00b5081315a98aaf60c0e632aaeb/ty-0.0.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:72435eade1fa58c6218abb4340f43a6c3ff856ae2dc5722a247d3a6dd32e9737", size = 10916460, upload-time = "2026-01-21T13:21:07.788Z" }, - { url = "https://files.pythonhosted.org/packages/04/40/9ead96b7c122e1109dfcd11671184c3506996bf6a649306ec427e81d9544/ty-0.0.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:77a548742ee8f621d718159e7027c3b555051d096a49bb580249a6c5fc86c271", size = 10597154, upload-time = "2026-01-21T13:21:18.064Z" }, - { url = "https://files.pythonhosted.org/packages/aa/7d/e832a2c081d2be845dc6972d0c7998914d168ccbc0b9c86794419ab7376e/ty-0.0.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da067c57c289b7cf914669704b552b6207c2cc7f50da4118c3e12388642e6b3f", size = 10410710, upload-time = "2026-01-21T13:21:12.388Z" }, - { url = "https://files.pythonhosted.org/packages/31/e3/898be3a96237a32f05c4c29b43594dc3b46e0eedfe8243058e46153b324f/ty-0.0.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d1b50a01fffa140417fca5a24b658fbe0734074a095d5b6f0552484724474343", size = 9826299, upload-time = "2026-01-21T13:21:00.845Z" }, - { url = "https://files.pythonhosted.org/packages/bb/eb/db2d852ce0ed742505ff18ee10d7d252f3acfd6fc60eca7e9c7a0288a6d8/ty-0.0.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0f33c46f52e5e9378378eca0d8059f026f3c8073ace02f7f2e8d079ddfe5207e", size = 9831610, upload-time = "2026-01-21T13:21:05.842Z" }, - { url = "https://files.pythonhosted.org/packages/9e/61/149f59c8abaddcbcbb0bd13b89c7741ae1c637823c5cf92ed2c644fcadef/ty-0.0.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:168eda24d9a0b202cf3758c2962cc295878842042b7eca9ed2965259f59ce9f2", size = 9978885, upload-time = "2026-01-21T13:21:10.306Z" }, - { url = "https://files.pythonhosted.org/packages/a0/cd/026d4e4af60a80918a8d73d2c42b8262dd43ab2fa7b28d9743004cb88d57/ty-0.0.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d4917678b95dc8cb399cc459fab568ba8d5f0f33b7a94bf840d9733043c43f29", size = 10506453, upload-time = "2026-01-21T13:20:56.633Z" }, - { url = "https://files.pythonhosted.org/packages/63/06/8932833a4eca2df49c997a29afb26721612de8078ae79074c8fe87e17516/ty-0.0.13-py3-none-win32.whl", hash = "sha256:c1f2ec40daa405508b053e5b8e440fbae5fdb85c69c9ab0ee078f8bc00eeec3d", size = 9433482, upload-time = "2026-01-21T13:20:58.717Z" }, - { url = "https://files.pythonhosted.org/packages/aa/fd/e8d972d1a69df25c2cecb20ea50e49ad5f27a06f55f1f5f399a563e71645/ty-0.0.13-py3-none-win_amd64.whl", hash = "sha256:8b7b1ab9f187affbceff89d51076038363b14113be29bda2ddfa17116de1d476", size = 10319156, upload-time = "2026-01-21T13:21:03.266Z" }, - { url = "https://files.pythonhosted.org/packages/2d/c2/05fdd64ac003a560d4fbd1faa7d9a31d75df8f901675e5bed1ee2ceeff87/ty-0.0.13-py3-none-win_arm64.whl", hash = "sha256:1c9630333497c77bb9bcabba42971b96ee1f36c601dd3dcac66b4134f9fa38f0", size = 9808316, upload-time = "2026-01-21T13:20:54.053Z" }, + { url = "https://files.pythonhosted.org/packages/99/cb/cc6d1d8de59beb17a41f9a614585f884ec2d95450306c173b3b7cc090d2e/ty-0.0.14-py3-none-linux_armv6l.whl", hash = "sha256:32cf2a7596e693094621d3ae568d7ee16707dce28c34d1762947874060fdddaa", size = 10034228, upload-time = "2026-01-27T00:57:53.133Z" }, + { url = "https://files.pythonhosted.org/packages/f3/96/dd42816a2075a8f31542296ae687483a8d047f86a6538dfba573223eaf9a/ty-0.0.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f971bf9805f49ce8c0968ad53e29624d80b970b9eb597b7cbaba25d8a18ce9a2", size = 9939162, upload-time = "2026-01-27T00:57:43.857Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b4/73c4859004e0f0a9eead9ecb67021438b2e8e5fdd8d03e7f5aca77623992/ty-0.0.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:45448b9e4806423523268bc15e9208c4f3f2ead7c344f615549d2e2354d6e924", size = 9418661, upload-time = "2026-01-27T00:58:03.411Z" }, + { url = "https://files.pythonhosted.org/packages/58/35/839c4551b94613db4afa20ee555dd4f33bfa7352d5da74c5fa416ffa0fd2/ty-0.0.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee94a9b747ff40114085206bdb3205a631ef19a4d3fb89e302a88754cbbae54c", size = 9837872, upload-time = "2026-01-27T00:57:23.718Z" }, + { url = "https://files.pythonhosted.org/packages/41/2b/bbecf7e2faa20c04bebd35fc478668953ca50ee5847ce23e08acf20ea119/ty-0.0.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6756715a3c33182e9ab8ffca2bb314d3c99b9c410b171736e145773ee0ae41c3", size = 9848819, upload-time = "2026-01-27T00:57:58.501Z" }, + { url = "https://files.pythonhosted.org/packages/be/60/3c0ba0f19c0f647ad9d2b5b5ac68c0f0b4dc899001bd53b3a7537fb247a2/ty-0.0.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89d0038a2f698ba8b6fec5cf216a4e44e2f95e4a5095a8c0f57fe549f87087c2", size = 10324371, upload-time = "2026-01-27T00:57:29.291Z" }, + { url = "https://files.pythonhosted.org/packages/24/32/99d0a0b37d0397b0a989ffc2682493286aa3bc252b24004a6714368c2c3d/ty-0.0.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c64a83a2d669b77f50a4957039ca1450626fb474619f18f6f8a3eb885bf7544", size = 10865898, upload-time = "2026-01-27T00:57:33.542Z" }, + { url = "https://files.pythonhosted.org/packages/1a/88/30b583a9e0311bb474269cfa91db53350557ebec09002bfc3fb3fc364e8c/ty-0.0.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:242488bfb547ef080199f6fd81369ab9cb638a778bb161511d091ffd49c12129", size = 10555777, upload-time = "2026-01-27T00:58:05.853Z" }, + { url = "https://files.pythonhosted.org/packages/cd/a2/cb53fb6325dcf3d40f2b1d0457a25d55bfbae633c8e337bde8ec01a190eb/ty-0.0.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4790c3866f6c83a4f424fc7d09ebdb225c1f1131647ba8bdc6fcdc28f09ed0ff", size = 10412913, upload-time = "2026-01-27T00:57:38.834Z" }, + { url = "https://files.pythonhosted.org/packages/42/8f/f2f5202d725ed1e6a4e5ffaa32b190a1fe70c0b1a2503d38515da4130b4c/ty-0.0.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:950f320437f96d4ea9a2332bbfb5b68f1c1acd269ebfa4c09b6970cc1565bd9d", size = 9837608, upload-time = "2026-01-27T00:57:55.898Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ba/59a2a0521640c489dafa2c546ae1f8465f92956fede18660653cce73b4c5/ty-0.0.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4a0ec3ee70d83887f86925bbc1c56f4628bd58a0f47f6f32ddfe04e1f05466df", size = 9884324, upload-time = "2026-01-27T00:57:46.786Z" }, + { url = "https://files.pythonhosted.org/packages/03/95/8d2a49880f47b638743212f011088552ecc454dd7a665ddcbdabea25772a/ty-0.0.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a1a4e6b6da0c58b34415955279eff754d6206b35af56a18bb70eb519d8d139ef", size = 10033537, upload-time = "2026-01-27T00:58:01.149Z" }, + { url = "https://files.pythonhosted.org/packages/e9/40/4523b36f2ce69f92ccf783855a9e0ebbbd0f0bb5cdce6211ee1737159ed3/ty-0.0.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:dc04384e874c5de4c5d743369c277c8aa73d1edea3c7fc646b2064b637db4db3", size = 10495910, upload-time = "2026-01-27T00:57:26.691Z" }, + { url = "https://files.pythonhosted.org/packages/08/d5/655beb51224d1bfd4f9ddc0bb209659bfe71ff141bcf05c418ab670698f0/ty-0.0.14-py3-none-win32.whl", hash = "sha256:b20e22cf54c66b3e37e87377635da412d9a552c9bf4ad9fc449fed8b2e19dad2", size = 9507626, upload-time = "2026-01-27T00:57:41.43Z" }, + { url = "https://files.pythonhosted.org/packages/b6/d9/c569c9961760e20e0a4bc008eeb1415754564304fd53997a371b7cf3f864/ty-0.0.14-py3-none-win_amd64.whl", hash = "sha256:e312ff9475522d1a33186657fe74d1ec98e4a13e016d66f5758a452c90ff6409", size = 10437980, upload-time = "2026-01-27T00:57:36.422Z" }, + { url = "https://files.pythonhosted.org/packages/ad/0c/186829654f5bfd9a028f6648e9caeb11271960a61de97484627d24443f91/ty-0.0.14-py3-none-win_arm64.whl", hash = "sha256:b6facdbe9b740cb2c15293a1d178e22ffc600653646452632541d01c36d5e378", size = 9885831, upload-time = "2026-01-27T00:57:49.747Z" }, ] [[package]] From 7c78ee87b7b54bb2179d86d5e28c1f65bbf96669 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 2 Feb 2026 08:07:10 -0800 Subject: [PATCH 70/77] replace natsort with lil function (#3105) * replace natsort with lil function * sort --- .github/workflows/update-cars-docs.yml | 2 +- opendbc/car/docs.py | 17 ++++++++++++----- pyproject.toml | 1 - uv.lock | 11 ----------- 4 files changed, 13 insertions(+), 18 deletions(-) diff --git a/.github/workflows/update-cars-docs.yml b/.github/workflows/update-cars-docs.yml index bf72e528..1d2adefc 100644 --- a/.github/workflows/update-cars-docs.yml +++ b/.github/workflows/update-cars-docs.yml @@ -16,7 +16,7 @@ jobs: run: | pip install -e . scons -c && scons -j$(nproc) - python -m pip install jinja2==3.1.4 natsort==8.4.0 + python -m pip install jinja2==3.1.4 python opendbc/car/docs.py - uses: stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5058a842 with: diff --git a/opendbc/car/docs.py b/opendbc/car/docs.py index bfd8964a..505de6ae 100755 --- a/opendbc/car/docs.py +++ b/opendbc/car/docs.py @@ -1,12 +1,13 @@ #!/usr/bin/env python3 -import argparse +import re import os +import jinja2 +import argparse +import unicodedata from typing import get_args -from collections import defaultdict -import jinja2 from enum import Enum -from natsort import natsorted +from collections import defaultdict from opendbc.car.common.basedir import BASEDIR from opendbc.car import gen_empty_fingerprint @@ -43,6 +44,12 @@ def get_all_footnotes() -> dict[Enum, int]: return {fn: idx + 1 for idx, fn in enumerate(all_footnotes)} +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 build_sorted_car_docs_list(platforms, footnotes=None): collected_car_docs: list[CarDocs | ExtraCarDocs] = [] for platform in platforms.values(): @@ -60,7 +67,7 @@ def build_sorted_car_docs_list(platforms, footnotes=None): collected_car_docs.append(_car_docs) # Sort cars by make and model + year - sorted_cars = natsorted(collected_car_docs, key=lambda car: car.name.lower()) + sorted_cars = sorted(collected_car_docs, key=lambda car: _natural_sort_key(car.name)) return sorted_cars diff --git a/pyproject.toml b/pyproject.toml index d0d3cd27..20677278 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,6 @@ testing = [ ] docs = [ "Jinja2", - "natsort", ] examples = [ "inputs", diff --git a/uv.lock b/uv.lock index 42c7d21d..b82dab73 100644 --- a/uv.lock +++ b/uv.lock @@ -520,15 +520,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/73/e4/6d6f14b2a759c622f191b2d67e9075a3f56aaccb3be4bb9bb6890030d0a0/matplotlib-3.10.8-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ae029229a57cd1e8fe542485f27e7ca7b23aa9e8944ddb4985d0bc444f1eca2", size = 8713867, upload-time = "2025-12-10T22:56:48.954Z" }, ] -[[package]] -name = "natsort" -version = "8.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e2/a9/a0c57aee75f77794adaf35322f8b6404cbd0f89ad45c87197a937764b7d0/natsort-8.4.0.tar.gz", hash = "sha256:45312c4a0e5507593da193dedd04abb1469253b601ecaf63445ad80f0a1ea581", size = 76575, upload-time = "2023-06-20T04:17:19.925Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/82/7a9d0550484a62c6da82858ee9419f3dd1ccc9aa1c26a1e43da3ecd20b0d/natsort-8.4.0-py3-none-any.whl", hash = "sha256:4732914fb471f56b5cce04d7bae6f164a592c7712e1c85f9ef585e197299521c", size = 38268, upload-time = "2023-06-20T04:17:17.522Z" }, -] - [[package]] name = "numpy" version = "2.4.2" @@ -582,7 +573,6 @@ dependencies = [ [package.optional-dependencies] docs = [ { name = "jinja2" }, - { name = "natsort" }, ] examples = [ { name = "inputs" }, @@ -621,7 +611,6 @@ requires-dist = [ { name = "jinja2", marker = "extra == 'docs'" }, { name = "lefthook", marker = "extra == 'testing'" }, { name = "matplotlib", marker = "extra == 'examples'" }, - { name = "natsort", marker = "extra == 'docs'" }, { name = "numpy" }, { name = "parameterized", marker = "extra == 'testing'", specifier = ">=0.8,<0.9" }, { name = "pycapnp", specifier = "==2.1.0" }, From a653199681e95be113aea491bb7a6023c8b73eb1 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Mon, 2 Feb 2026 14:44:09 -0500 Subject: [PATCH 71/77] Reapply "Lateral: lower friction threshold (#2915)" (#378) (#394) This reverts commit a76d28a231dd8a3de11ed47db2d185d3852c6925. --- opendbc/car/lateral.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc/car/lateral.py b/opendbc/car/lateral.py index d94fe796..5cc5f86c 100644 --- a/opendbc/car/lateral.py +++ b/opendbc/car/lateral.py @@ -4,7 +4,7 @@ from dataclasses import dataclass from opendbc.car import structs, rate_limit, DT_CTRL from opendbc.car.vehicle_model import VehicleModel -FRICTION_THRESHOLD = 0.3 +FRICTION_THRESHOLD = 0.2 # ISO 11270 ISO_LATERAL_ACCEL = 3.0 # m/s^2 From 4d4b8b08dab387cde3f1059f9d0bcdba513f4591 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Mon, 2 Feb 2026 22:18:34 -0500 Subject: [PATCH 72/77] Revert "Mazda: Parse cruise control buttons (#307)" This reverts commit 153d90c2e5c246d44d765aa5cb6cd8f9bad4fd32. --- opendbc/car/mazda/carstate.py | 14 ++------ opendbc/sunnypilot/car/mazda/__init__.py | 0 opendbc/sunnypilot/car/mazda/carstate_ext.py | 36 -------------------- opendbc/sunnypilot/car/mazda/values.py | 20 ----------- 4 files changed, 3 insertions(+), 67 deletions(-) delete mode 100644 opendbc/sunnypilot/car/mazda/__init__.py delete mode 100644 opendbc/sunnypilot/car/mazda/carstate_ext.py delete mode 100644 opendbc/sunnypilot/car/mazda/values.py diff --git a/opendbc/car/mazda/carstate.py b/opendbc/car/mazda/carstate.py index 97542c84..f594dce8 100644 --- a/opendbc/car/mazda/carstate.py +++ b/opendbc/car/mazda/carstate.py @@ -4,15 +4,12 @@ from opendbc.car.common.conversions import Conversions as CV from opendbc.car.interfaces import CarStateBase from opendbc.car.mazda.values import DBC, LKAS_LIMITS -from opendbc.sunnypilot.car.mazda.carstate_ext import CarStateExt - ButtonType = structs.CarState.ButtonEvent.Type -class CarState(CarStateBase, CarStateExt): +class CarState(CarStateBase): def __init__(self, CP, CP_SP): - CarStateBase.__init__(self, CP, CP_SP) - CarStateExt.__init__(self, CP, CP_SP) + super().__init__(CP, CP_SP) can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt]) self.shifter_values = can_define.dv["GEAR"]["GEAR"] @@ -116,13 +113,8 @@ class CarState(CarStateBase, CarStateExt): self.cam_laneinfo = cp_cam.vl["CAM_LANEINFO"] ret.steerFaultPermanent = cp_cam.vl["CAM_LKAS"]["ERR_BIT_1"] == 1 - CarStateExt.update(self, ret, ret_sp, can_parsers) - # TODO: add button types for inc and dec - ret.buttonEvents = [ - *create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise}), - *self.button_events, - ] + ret.buttonEvents = create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise}) return ret, ret_sp diff --git a/opendbc/sunnypilot/car/mazda/__init__.py b/opendbc/sunnypilot/car/mazda/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/opendbc/sunnypilot/car/mazda/carstate_ext.py b/opendbc/sunnypilot/car/mazda/carstate_ext.py deleted file mode 100644 index 4686fcca..00000000 --- a/opendbc/sunnypilot/car/mazda/carstate_ext.py +++ /dev/null @@ -1,36 +0,0 @@ - -""" -Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - -This file is part of sunnypilot and is licensed under the MIT License. -See the LICENSE.md file in the root directory for more details. -""" - -from enum import StrEnum - -from opendbc.car import Bus, structs -from opendbc.can.parser import CANParser -from opendbc.sunnypilot.car.mazda.values import BUTTONS - - -class CarStateExt: - def __init__(self, CP, CP_SP): - self.CP = CP - self.CP_SP = CP_SP - - self.button_events = [] - self.button_states = {button.event_type: False for button in BUTTONS} - - def update(self, ret: structs.CarState, ret_sp: structs.CarStateSP, can_parsers: dict[StrEnum, CANParser]): - cp = can_parsers[Bus.pt] - - button_events = [] - for button in BUTTONS: - state = (cp.vl[button.can_addr][button.can_msg] in button.values) - if self.button_states[button.event_type] != state: - event = structs.CarState.ButtonEvent.new_message() - event.type = button.event_type - event.pressed = state - button_events.append(event) - self.button_states[button.event_type] = state - self.button_events = button_events diff --git a/opendbc/sunnypilot/car/mazda/values.py b/opendbc/sunnypilot/car/mazda/values.py deleted file mode 100644 index d2b9c597..00000000 --- a/opendbc/sunnypilot/car/mazda/values.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - -This file is part of sunnypilot and is licensed under the MIT License. -See the LICENSE.md file in the root directory for more details. -""" - -from collections import namedtuple - -from opendbc.car import structs - -ButtonType = structs.CarState.ButtonEvent.Type -Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values']) - -BUTTONS = [ - Button(ButtonType.accelCruise, "CRZ_BTNS", "SET_P", [1]), - Button(ButtonType.decelCruise, "CRZ_BTNS", "SET_M", [1]), - Button(ButtonType.cancel, "CRZ_BTNS", "CAN_OFF", [1]), - Button(ButtonType.resumeCruise, "CRZ_BTNS", "RES", [1]), -] From 14a04ec4cea69a76a022217e048a8fc3af495c2c Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Mon, 2 Feb 2026 22:21:46 -0500 Subject: [PATCH 73/77] Platform List: sync with latest --- opendbc/sunnypilot/car/car_list.json | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/opendbc/sunnypilot/car/car_list.json b/opendbc/sunnypilot/car/car_list.json index 649a4d03..5785e2ab 100644 --- a/opendbc/sunnypilot/car/car_list.json +++ b/opendbc/sunnypilot/car/car_list.json @@ -66,6 +66,16 @@ ], "package": "All" }, + "Acura TLX 2025": { + "platform": "ACURA_TLX_2G_MMR", + "make": "Acura", + "brand": "honda", + "model": "TLX", + "year": [ + "2025" + ], + "package": "All" + }, "Audi A3 2014-19": { "platform": "AUDI_A3_MK3", "make": "Audi", @@ -1251,6 +1261,17 @@ ], "package": "All" }, + "Honda Odyssey (Taiwan) 2018-19": { + "platform": "HONDA_ODYSSEY_TWN", + "make": "Honda", + "brand": "honda", + "model": "Odyssey (Taiwan)", + "year": [ + "2018", + "2019" + ], + "package": "Honda Sensing" + }, "Honda Passport 2019-25": { "platform": "HONDA_PILOT", "make": "Honda", From 23ce63d443c687cb7211eb06e286ec726483f0df Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Tue, 3 Feb 2026 23:32:17 -0500 Subject: [PATCH 74/77] docs: update CARS.md --- docs/CARS.md | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 88514042..0d9b25ad 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -1,6 +1,6 @@ -# Support Information for 390 Known Cars +# Support Information for 410 Known Cars |Make|Model|Package|Support Level| |---|---|---|:---:| @@ -32,11 +32,21 @@ |Audi|Q5 2017-24|All|[Not compatible](#flexray)| |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| +|Cadillac|CT6 Non-ACC 2017-18|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| +|Cadillac|XT5 Non-ACC 2018|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim, without Super Cruise Package|[Upstream](#upstream)| +|Chevrolet|Bolt EUV LT Non-ACC 2022-23|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| |Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|[Upstream](#upstream)| +|Chevrolet|Bolt EV LT Non-ACC 2022-23|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| +|Chevrolet|Bolt EV Non-ACC 2017|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| +|Chevrolet|Bolt EV Non-ACC 2018-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| +|Chevrolet|Equinox Non-ACC 2019-22|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| +|Chevrolet|Malibu Non-ACC 2016-23|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Chevrolet|Silverado 1500 2020-21|Safety Package II|[Upstream](#upstream)| +|Chevrolet|Suburban Non-ACC 2016-20|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| |Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| +|Chevrolet|Trailblazer Non-ACC 2021-22|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Chrysler|Pacifica 2021-23|All|[Upstream](#upstream)| @@ -73,6 +83,7 @@ |Genesis|G70 2018|All|[Upstream](#upstream)| |Genesis|G70 2019-21|All|[Upstream](#upstream)| |Genesis|G70 2022-23|All|[Upstream](#upstream)| +|Genesis|G70 Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Dashcam mode](#dashcam)| |Genesis|G80 2017|All|[Upstream](#upstream)| |Genesis|G80 2018-19|All|[Upstream](#upstream)| |Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024|Highway Driving Assist II|[Upstream](#upstream)| @@ -102,6 +113,7 @@ |Honda|Civic Hatchback Hybrid 2025-26|All|[Upstream](#upstream)| |Honda|Civic Hatchback Hybrid (Europe only) 2023|All|[Upstream](#upstream)| |Honda|Civic Hybrid 2025-26|All|[Upstream](#upstream)| +|Honda|Clarity 2018-21|Honda Sensing|[Upstream](#upstream)| |Honda|Clarity 2018-21|All|[Community](#community)| |Honda|CR-V 2015-16|Touring Trim|[Upstream](#upstream)| |Honda|CR-V 2017-22|Honda Sensing|[Upstream](#upstream)| @@ -128,12 +140,14 @@ |Hyundai|Azera 2022|All|[Upstream](#upstream)| |Hyundai|Azera Hybrid 2019|All|[Upstream](#upstream)| |Hyundai|Azera Hybrid 2020|All|[Upstream](#upstream)| +|Hyundai|Bayon Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Dashcam mode](#dashcam)| |Hyundai|Custin 2023|All|[Upstream](#upstream)| |Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Elantra 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| +|Hyundai|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Upstream](#upstream)| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|i30 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|[Upstream](#upstream)| @@ -147,11 +161,13 @@ |Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Ioniq Plug-in Hybrid 2020-22|All|[Upstream](#upstream)| |Hyundai|Kona 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)| -|Hyundai|Kona 2022-23|Smart Cruise Control (SCC)|[Dashcam mode](#dashcam)| +|Hyundai|Kona 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)| +|Hyundai|Kona Electric Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Upstream](#upstream)| |Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)| +|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Upstream](#upstream)| |Hyundai|Nexo 2021|All|[Upstream](#upstream)| |Hyundai|Palisade 2020-22|All|[Upstream](#upstream)| |Hyundai|Palisade 2023-24|Highway Driving Assist II|[Community](#community)| @@ -176,11 +192,14 @@ |Kia|Carnival 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Ceed 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)| +|Kia|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Upstream](#upstream)| |Kia|EV6 (Southeast Asia only) 2022-24|All|[Upstream](#upstream)| |Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)| |Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)| |Kia|Forte 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Forte 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| +|Kia|Forte Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Upstream](#upstream)| +|Kia|Forte Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Dashcam mode](#dashcam)| |Kia|K5 2021-24|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|K8 Hybrid (with HDA II) 2023|Highway Driving Assist II|[Upstream](#upstream)| @@ -203,6 +222,7 @@ |Kia|Optima Hybrid 2017|Advanced Smart Cruise Control|[Dashcam mode](#dashcam)| |Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Seltos 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)| +|Kia|Seltos Non-SCC 2023-24|No Smart Cruise Control (Non-SCC)|[Dashcam mode](#dashcam)| |Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|[Upstream](#upstream)| |Kia|Sorento 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Sorento 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| @@ -255,8 +275,8 @@ |Peugeot|208 2019-25|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)| |Porsche|Macan 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)| |Ram|1500 2019-24|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| -|Ram|2500 2020-24|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| -|Ram|3500 2019-22|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| +|Ram|2500 2020-24|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| +|Ram|3500 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Rivian|R1S 2022-24|All|[Upstream](#upstream)| |Rivian|R1T 2022-24|All|[Upstream](#upstream)| |SEAT|Alhambra 2018-20|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)| @@ -267,16 +287,16 @@ |Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)| |Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|[Upstream](#upstream)| |Subaru|Crosstrek Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)| -|Subaru|Forester 2017-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)| +|Subaru|Forester 2017-18|EyeSight Driver Assistance|[Upstream](#upstream)| |Subaru|Forester 2019-21|All|[Upstream](#upstream)| |Subaru|Forester 2022-24|All|[Dashcam mode](#dashcam)| |Subaru|Forester Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)| |Subaru|Impreza 2017-19|EyeSight Driver Assistance|[Upstream](#upstream)| |Subaru|Impreza 2020-22|EyeSight Driver Assistance|[Upstream](#upstream)| -|Subaru|Legacy 2015-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)| +|Subaru|Legacy 2015-18|EyeSight Driver Assistance|[Upstream](#upstream)| |Subaru|Legacy 2020-22|All|[Upstream](#upstream)| -|Subaru|Outback 2015-17|EyeSight Driver Assistance|[Dashcam mode](#dashcam)| -|Subaru|Outback 2018-19|EyeSight Driver Assistance|[Dashcam mode](#dashcam)| +|Subaru|Outback 2015-17|EyeSight Driver Assistance|[Upstream](#upstream)| +|Subaru|Outback 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)| |Subaru|Outback 2020-22|All|[Upstream](#upstream)| |Subaru|Outback 2023|All|[Dashcam mode](#dashcam)| |Subaru|Solterra 2023-25|All|[Not compatible](#can-bus-security)| From 56cd2cb94f1088dae7a03b288946ee27586b0891 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Tue, 3 Feb 2026 23:45:13 -0500 Subject: [PATCH 75/77] ci: disable Car diff --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bbce2c34..5afc22b0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -62,6 +62,7 @@ jobs: car_diff: name: car diff + if: false runs-on: ${{ github.repository == 'commaai/opendbc' && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }} env: GIT_REF: ${{ github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && github.event.before || format('origin/{0}', github.event.repository.default_branch) }} From b38eb75adbd18fac52567720f737a61743ae2279 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Wed, 4 Feb 2026 00:32:15 -0500 Subject: [PATCH 76/77] docs: cleanup for community supported platforms (#396) * ci: disable Car diff * hyundai * gm * honda --- docs/CARS.md | 32 ++++++------- opendbc/car/gm/values.py | 67 +++++++++++++++------------- opendbc/car/honda/values.py | 4 +- opendbc/car/hyundai/values.py | 67 ++++++++++++++++------------ opendbc/sunnypilot/car/car_list.json | 6 +-- 5 files changed, 96 insertions(+), 80 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 0d9b25ad..803cd32e 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -32,21 +32,21 @@ |Audi|Q5 2017-24|All|[Not compatible](#flexray)| |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)| -|Cadillac|CT6 Non-ACC 2017-18|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| -|Cadillac|XT5 Non-ACC 2018|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| +|Cadillac|CT6 Non-ACC 2017-18|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)| +|Cadillac|XT5 Non-ACC 2018|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim, without Super Cruise Package|[Upstream](#upstream)| -|Chevrolet|Bolt EUV LT Non-ACC 2022-23|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| +|Chevrolet|Bolt EUV LT Non-ACC 2022-23|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)| |Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|[Upstream](#upstream)| -|Chevrolet|Bolt EV LT Non-ACC 2022-23|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| -|Chevrolet|Bolt EV Non-ACC 2017|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| -|Chevrolet|Bolt EV Non-ACC 2018-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| +|Chevrolet|Bolt EV LT Non-ACC 2022-23|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)| +|Chevrolet|Bolt EV Non-ACC 2017|No Adaptive Cruise Control (Non-ACC)|[Community](community)| +|Chevrolet|Bolt EV Non-ACC 2018-21|No Adaptive Cruise Control (Non-ACC)|[Community](community)| |Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| -|Chevrolet|Equinox Non-ACC 2019-22|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| -|Chevrolet|Malibu Non-ACC 2016-23|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| +|Chevrolet|Equinox Non-ACC 2019-22|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)| +|Chevrolet|Malibu Non-ACC 2016-23|No Adaptive Cruise Control (Non-ACC)|[Community](community)| |Chevrolet|Silverado 1500 2020-21|Safety Package II|[Upstream](#upstream)| -|Chevrolet|Suburban Non-ACC 2016-20|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| +|Chevrolet|Suburban Non-ACC 2016-20|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)| |Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| -|Chevrolet|Trailblazer Non-ACC 2021-22|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)| +|Chevrolet|Trailblazer Non-ACC 2021-22|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)| |Chrysler|Pacifica 2021-23|All|[Upstream](#upstream)| @@ -113,7 +113,7 @@ |Honda|Civic Hatchback Hybrid 2025-26|All|[Upstream](#upstream)| |Honda|Civic Hatchback Hybrid (Europe only) 2023|All|[Upstream](#upstream)| |Honda|Civic Hybrid 2025-26|All|[Upstream](#upstream)| -|Honda|Clarity 2018-21|Honda Sensing|[Upstream](#upstream)| +|Honda|Clarity 2018-21|Honda Sensing|[Community](community)| |Honda|Clarity 2018-21|All|[Community](#community)| |Honda|CR-V 2015-16|Touring Trim|[Upstream](#upstream)| |Honda|CR-V 2017-22|Honda Sensing|[Upstream](#upstream)| @@ -147,7 +147,7 @@ |Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| -|Hyundai|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Upstream](#upstream)| +|Hyundai|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|i30 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|[Upstream](#upstream)| @@ -165,9 +165,9 @@ |Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)| -|Hyundai|Kona Electric Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Upstream](#upstream)| +|Hyundai|Kona Electric Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)| |Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)| -|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Upstream](#upstream)| +|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)| |Hyundai|Nexo 2021|All|[Upstream](#upstream)| |Hyundai|Palisade 2020-22|All|[Upstream](#upstream)| |Hyundai|Palisade 2023-24|Highway Driving Assist II|[Community](#community)| @@ -192,13 +192,13 @@ |Kia|Carnival 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Ceed 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)| -|Kia|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Upstream](#upstream)| +|Kia|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)| |Kia|EV6 (Southeast Asia only) 2022-24|All|[Upstream](#upstream)| |Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)| |Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)| |Kia|Forte 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|Forte 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)| -|Kia|Forte Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Upstream](#upstream)| +|Kia|Forte Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)| |Kia|Forte Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Dashcam mode](#dashcam)| |Kia|K5 2021-24|Smart Cruise Control (SCC)|[Upstream](#upstream)| |Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|[Upstream](#upstream)| diff --git a/opendbc/car/gm/values.py b/opendbc/car/gm/values.py index f4ef06a9..5df95595 100644 --- a/opendbc/car/gm/values.py +++ b/opendbc/car/gm/values.py @@ -3,7 +3,7 @@ from enum import Enum, IntFlag from opendbc.car import Bus, PlatformConfig, DbcDict, Platforms, CarSpecs from opendbc.car.structs import CarParams -from opendbc.car.docs_definitions import CarDocs, CarFootnote, CarHarness, CarParts, Column +from opendbc.car.docs_definitions import CarDocs, CarFootnote, CarHarness, CarParts, Column, SupportType from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries from opendbc.sunnypilot.car.gm.values_ext import GMFlagsSP @@ -88,6 +88,13 @@ class GMCarDocs(CarDocs): self.car_parts = CarParts.common([CarHarness.obd_ii]) +@dataclass +class GMNonAccCarDocs(GMCarDocs): + package: str = "No Adaptive Cruise Control (Non-ACC)" + support_type: SupportType = SupportType.COMMUNITY + support_link: str = "community" + + @dataclass(frozen=True, kw_only=True) class GMCarSpecs(CarSpecs): tireStiffnessFactor: float = 0.444 # not optimized yet @@ -116,6 +123,12 @@ class GMSDGMPlatformConfig(GMPlatformConfig): self.car_docs = [] +@dataclass +class GMNonSccPlatformConfig(GMPlatformConfig): + def init(self): + self.sp_flags |= GMFlagsSP.NON_ACC + + class CAR(Platforms): HOLDEN_ASTRA = GMASCMPlatformConfig( [GMCarDocs("Holden Astra 2017")], @@ -199,58 +212,48 @@ class CAR(Platforms): # port extensions # Separate car def is required when there is no ASCM # (for now) unless there is a way to detect it when it has been unplugged... - # CHEVROLET_VOLT_CC = GMPlatformConfig( - # [GMCarDocs("Chevrolet Volt LT 2017-18")], + # CHEVROLET_VOLT_CC = GMNonSccPlatformConfig( + # [GMNonAccCarDocs("Chevrolet Volt LT 2017-18")], # CHEVROLET_VOLT.specs, - # sp_flags=GMFlagsSP.NON_ACC, # ) - CHEVROLET_BOLT_NON_ACC = GMPlatformConfig( - [GMCarDocs("Chevrolet Bolt EV Non-ACC 2017")], + CHEVROLET_BOLT_NON_ACC = GMNonSccPlatformConfig( + [GMNonAccCarDocs("Chevrolet Bolt EV Non-ACC 2017")], CHEVROLET_BOLT_EUV.specs, - sp_flags=GMFlagsSP.NON_ACC, ) - CHEVROLET_BOLT_NON_ACC_1ST_GEN = GMPlatformConfig( - [GMCarDocs("Chevrolet Bolt EV Non-ACC 2018-21")], + CHEVROLET_BOLT_NON_ACC_1ST_GEN = GMNonSccPlatformConfig( + [GMNonAccCarDocs("Chevrolet Bolt EV Non-ACC 2018-21")], CHEVROLET_BOLT_EUV.specs, - sp_flags=GMFlagsSP.NON_ACC, ) - CHEVROLET_BOLT_NON_ACC_2ND_GEN = GMPlatformConfig( + CHEVROLET_BOLT_NON_ACC_2ND_GEN = GMNonSccPlatformConfig( [ - GMCarDocs("Chevrolet Bolt EUV LT Non-ACC 2022-23"), - GMCarDocs("Chevrolet Bolt EV LT Non-ACC 2022-23"), + GMNonAccCarDocs("Chevrolet Bolt EUV LT Non-ACC 2022-23"), + GMNonAccCarDocs("Chevrolet Bolt EV LT Non-ACC 2022-23"), ], CHEVROLET_BOLT_EUV.specs, - sp_flags=GMFlagsSP.NON_ACC, ) - CHEVROLET_EQUINOX_NON_ACC_3RD_GEN = GMPlatformConfig( - [GMCarDocs("Chevrolet Equinox Non-ACC 2019-22")], + CHEVROLET_EQUINOX_NON_ACC_3RD_GEN = GMNonSccPlatformConfig( + [GMNonAccCarDocs("Chevrolet Equinox Non-ACC 2019-22")], CHEVROLET_EQUINOX.specs, - sp_flags=GMFlagsSP.NON_ACC, ) - CHEVROLET_SUBURBAN_NON_ACC_11TH_GEN = GMPlatformConfig( - [GMCarDocs("Chevrolet Suburban Non-ACC 2016-20")], + CHEVROLET_SUBURBAN_NON_ACC_11TH_GEN = GMNonSccPlatformConfig( + [GMNonAccCarDocs("Chevrolet Suburban Non-ACC 2016-20")], CarSpecs(mass=2731, wheelbase=3.302, steerRatio=17.3, centerToFrontRatio=0.49), - sp_flags=GMFlagsSP.NON_ACC, ) - CADILLAC_CT6_NON_ACC_1ST_GEN = GMPlatformConfig( - [GMCarDocs("Cadillac CT6 Non-ACC 2017-18")], + CADILLAC_CT6_NON_ACC_1ST_GEN = GMNonSccPlatformConfig( + [GMNonAccCarDocs("Cadillac CT6 Non-ACC 2017-18")], CarSpecs(mass=2358, wheelbase=3.11, steerRatio=17.7, centerToFrontRatio=0.4), - sp_flags=GMFlagsSP.NON_ACC, ) - CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN = GMPlatformConfig( - [GMCarDocs("Chevrolet Trailblazer Non-ACC 2021-22")], + CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN = GMNonSccPlatformConfig( + [GMNonAccCarDocs("Chevrolet Trailblazer Non-ACC 2021-22")], CHEVROLET_TRAILBLAZER.specs, - sp_flags=GMFlagsSP.NON_ACC, ) - CHEVROLET_MALIBU_NON_ACC_9TH_GEN = GMPlatformConfig( - [GMCarDocs("Chevrolet Malibu Non-ACC 2016-23")], + CHEVROLET_MALIBU_NON_ACC_9TH_GEN = GMNonSccPlatformConfig( + [GMNonAccCarDocs("Chevrolet Malibu Non-ACC 2016-23")], CarSpecs(mass=1450, wheelbase=2.8, steerRatio=15.8, centerToFrontRatio=0.4), - sp_flags=GMFlagsSP.NON_ACC, ) - CADILLAC_XT5_NON_ACC_1ST_GEN = GMPlatformConfig( - [GMCarDocs("Cadillac XT5 Non-ACC 2018")], + CADILLAC_XT5_NON_ACC_1ST_GEN = GMNonSccPlatformConfig( + [GMNonAccCarDocs("Cadillac XT5 Non-ACC 2018")], CarSpecs(mass=1810, wheelbase=2.86, steerRatio=16.34, centerToFrontRatio=0.5), - sp_flags=GMFlagsSP.NON_ACC, ) diff --git a/opendbc/car/honda/values.py b/opendbc/car/honda/values.py index 50b173ad..17f6cb26 100644 --- a/opendbc/car/honda/values.py +++ b/opendbc/car/honda/values.py @@ -3,7 +3,7 @@ from enum import Enum, IntFlag from opendbc.car import Bus, CarSpecs, DbcDict, PlatformConfig, Platforms, structs, uds from opendbc.car.common.conversions import Conversions as CV -from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column +from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, SupportType from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16 Ecu = structs.CarParams.Ecu @@ -114,6 +114,8 @@ class HondaCarDocs(CarDocs): if CP.carFingerprint in (CAR.HONDA_CLARITY,): self.car_parts = CarParts.common([CarHarness.honda_clarity]) self.car_parts.custom_parts_url = "https://shop.retropilot.org/product/honda-clarity-proxy-board-kit" + self.support_type: SupportType = SupportType.COMMUNITY + self.support_link: str = "community" class Footnote(Enum): diff --git a/opendbc/car/hyundai/values.py b/opendbc/car/hyundai/values.py index feb73e72..ca23fb9b 100644 --- a/opendbc/car/hyundai/values.py +++ b/opendbc/car/hyundai/values.py @@ -5,7 +5,7 @@ from enum import IntFlag from opendbc.car import Bus, CarSpecs, DbcDict, PlatformConfig, Platforms, uds from opendbc.car.common.conversions import Conversions as CV from opendbc.car.structs import CarParams -from opendbc.car.docs_definitions import CarHarness, CarDocs, CarParts +from opendbc.car.docs_definitions import CarHarness, CarDocs, CarParts, SupportType from opendbc.car.fw_query_definitions import FwQueryConfig, Request, p16 from opendbc.sunnypilot.car.hyundai.values import HyundaiFlagsSP @@ -134,6 +134,13 @@ class HyundaiCarDocs(CarDocs): package: str = "Smart Cruise Control (SCC)" +@dataclass +class HyundaiNonSccCarDocs(CarDocs): + package: str = "No Smart Cruise Control (Non-SCC)" + support_type: SupportType = SupportType.COMMUNITY + support_link: str = "community" + + @dataclass class HyundaiPlatformConfig(PlatformConfig): dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: "hyundai_kia_generic"}) @@ -146,6 +153,17 @@ class HyundaiPlatformConfig(PlatformConfig): self.specs = self.specs.override(minSteerSpeed=32 * CV.MPH_TO_MS) +@dataclass +class HyundaiNonSccPlatformConfig(PlatformConfig): + dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: "hyundai_kia_generic"}) + + def init(self): + self.sp_flags |= HyundaiFlagsSP.NON_SCC + + if self.flags & HyundaiFlags.MIN_STEER_32_MPH: + self.specs = self.specs.override(minSteerSpeed=32 * CV.MPH_TO_MS) + + @dataclass class HyundaiCanFDPlatformConfig(PlatformConfig): dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: "hyundai_canfd_generated"}) @@ -589,57 +607,50 @@ class CAR(Platforms): ) # port extensions - HYUNDAI_BAYON_1ST_GEN_NON_SCC = HyundaiPlatformConfig( - [HyundaiCarDocs("Hyundai Bayon Non-SCC 2021", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_n]))], + HYUNDAI_BAYON_1ST_GEN_NON_SCC = HyundaiNonSccPlatformConfig( + [HyundaiNonSccCarDocs("Hyundai Bayon Non-SCC 2021", car_parts=CarParts.common([CarHarness.hyundai_n]))], CarSpecs(mass=1150, wheelbase=2.58, steerRatio=13.27 * 1.15), flags=HyundaiFlags.CHECKSUM_CRC8, - sp_flags=HyundaiFlagsSP.NON_SCC, ) - HYUNDAI_ELANTRA_2022_NON_SCC = HyundaiPlatformConfig( - [HyundaiCarDocs("Hyundai Elantra Non-SCC 2022", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_k]))], + HYUNDAI_ELANTRA_2022_NON_SCC = HyundaiNonSccPlatformConfig( + [HyundaiNonSccCarDocs("Hyundai Elantra Non-SCC 2022", car_parts=CarParts.common([CarHarness.hyundai_k]))], HYUNDAI_ELANTRA_2021.specs, flags=HyundaiFlags.CHECKSUM_CRC8, - sp_flags=HyundaiFlagsSP.NON_SCC, ) - HYUNDAI_KONA_NON_SCC = HyundaiPlatformConfig( - [HyundaiCarDocs("Hyundai Kona Non-SCC 2019", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_b]))], + HYUNDAI_KONA_NON_SCC = HyundaiNonSccPlatformConfig( + [HyundaiNonSccCarDocs("Hyundai Kona Non-SCC 2019", car_parts=CarParts.common([CarHarness.hyundai_b]))], HYUNDAI_KONA.specs, flags=HyundaiFlags.ALT_LIMITS, - sp_flags=HyundaiFlagsSP.NON_SCC, ) - HYUNDAI_KONA_EV_NON_SCC = HyundaiPlatformConfig( - [HyundaiCarDocs("Hyundai Kona Electric Non-SCC 2019", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_g]))], + HYUNDAI_KONA_EV_NON_SCC = HyundaiNonSccPlatformConfig( + [HyundaiNonSccCarDocs("Hyundai Kona Electric Non-SCC 2019", car_parts=CarParts.common([CarHarness.hyundai_g]))], HYUNDAI_KONA_EV.specs, flags=HyundaiFlags.EV | HyundaiFlags.ALT_LIMITS, - sp_flags=HyundaiFlagsSP.NON_SCC, ) - KIA_CEED_PHEV_2022_NON_SCC = HyundaiPlatformConfig( - [HyundaiCarDocs("Kia Ceed Plug-in Hybrid Non-SCC 2022", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_i]))], + KIA_CEED_PHEV_2022_NON_SCC = HyundaiNonSccPlatformConfig( + [HyundaiNonSccCarDocs("Kia Ceed Plug-in Hybrid Non-SCC 2022", car_parts=CarParts.common([CarHarness.hyundai_i]))], CarSpecs(mass=1650, wheelbase=2.65, steerRatio=13.75, tireStiffnessFactor=0.5), flags=HyundaiFlags.HYBRID, - sp_flags=HyundaiFlagsSP.NON_SCC, ) - KIA_FORTE_2019_NON_SCC = HyundaiPlatformConfig( - [HyundaiCarDocs("Kia Forte Non-SCC 2019", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_g]))], + KIA_FORTE_2019_NON_SCC = HyundaiNonSccPlatformConfig( + [HyundaiNonSccCarDocs("Kia Forte Non-SCC 2019", car_parts=CarParts.common([CarHarness.hyundai_g]))], KIA_FORTE.specs, - sp_flags=HyundaiFlagsSP.NON_SCC | HyundaiFlagsSP.NON_SCC_NO_FCA, + sp_flags=HyundaiFlagsSP.NON_SCC_NO_FCA, ) - KIA_FORTE_2021_NON_SCC = HyundaiPlatformConfig( - [HyundaiCarDocs("Kia Forte Non-SCC 2021", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_g]))], + KIA_FORTE_2021_NON_SCC = HyundaiNonSccPlatformConfig( + [HyundaiNonSccCarDocs("Kia Forte Non-SCC 2021", car_parts=CarParts.common([CarHarness.hyundai_g]))], KIA_FORTE.specs, - sp_flags=HyundaiFlagsSP.NON_SCC, ) - KIA_SELTOS_2023_NON_SCC = HyundaiPlatformConfig( - [HyundaiCarDocs("Kia Seltos Non-SCC 2023-24", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_l]))], + KIA_SELTOS_2023_NON_SCC = HyundaiNonSccPlatformConfig( + [HyundaiNonSccCarDocs("Kia Seltos Non-SCC 2023-24", car_parts=CarParts.common([CarHarness.hyundai_l]))], KIA_SELTOS.specs, flags=HyundaiFlags.CHECKSUM_CRC8, - sp_flags=HyundaiFlagsSP.NON_SCC, ) - GENESIS_G70_2021_NON_SCC = HyundaiPlatformConfig( - [HyundaiCarDocs("Genesis G70 Non-SCC 2021", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_f]))], + GENESIS_G70_2021_NON_SCC = HyundaiNonSccPlatformConfig( + [HyundaiNonSccCarDocs("Genesis G70 Non-SCC 2021", car_parts=CarParts.common([CarHarness.hyundai_f]))], GENESIS_G70_2020.specs, flags=HyundaiFlags.CHECKSUM_CRC8, - sp_flags=HyundaiFlagsSP.NON_SCC | HyundaiFlagsSP.NON_SCC_RADAR_FCA, + sp_flags=HyundaiFlagsSP.NON_SCC_RADAR_FCA, ) diff --git a/opendbc/sunnypilot/car/car_list.json b/opendbc/sunnypilot/car/car_list.json index 5785e2ab..6fce8e70 100644 --- a/opendbc/sunnypilot/car/car_list.json +++ b/opendbc/sunnypilot/car/car_list.json @@ -231,7 +231,7 @@ "year": [ "2017" ], - "package": "Adaptive Cruise Control (ACC)" + "package": "No Adaptive Cruise Control (Non-ACC)" }, "Chevrolet Bolt EV Non-ACC 2018-21": { "platform": "CHEVROLET_BOLT_NON_ACC_1ST_GEN", @@ -244,7 +244,7 @@ "2020", "2021" ], - "package": "Adaptive Cruise Control (ACC)" + "package": "No Adaptive Cruise Control (Non-ACC)" }, "Chevrolet Equinox 2019-22": { "platform": "CHEVROLET_EQUINOX", @@ -274,7 +274,7 @@ "2022", "2023" ], - "package": "Adaptive Cruise Control (ACC)" + "package": "No Adaptive Cruise Control (Non-ACC)" }, "Chevrolet Silverado 1500 2020-21": { "platform": "CHEVROLET_SILVERADO", From e956d6d7dd846fd8d04f02804f05e77517b799fe Mon Sep 17 00:00:00 2001 From: royjr Date: Wed, 4 Feb 2026 11:13:25 -0500 Subject: [PATCH 77/77] HKG: add KIA_FORTE_2019_NON_SCC fingerprint (#390) * Update fingerprints_ext.py * add missing sport gear * Apply suggestion from @sunnyhaibin --------- Co-authored-by: Jason Wen --- opendbc/sunnypilot/car/hyundai/fingerprints_ext.py | 1 + 1 file changed, 1 insertion(+) diff --git a/opendbc/sunnypilot/car/hyundai/fingerprints_ext.py b/opendbc/sunnypilot/car/hyundai/fingerprints_ext.py index 27c563a3..dbf0bbae 100644 --- a/opendbc/sunnypilot/car/hyundai/fingerprints_ext.py +++ b/opendbc/sunnypilot/car/hyundai/fingerprints_ext.py @@ -55,6 +55,7 @@ FW_VERSIONS_EXT = { CAR.KIA_FORTE_2019_NON_SCC: { (Ecu.eps, 0x7D4, None): [ b'\xf1\x00BD MDPS C 1.00 1.04 56310/M6000 4BDDC104', + b'\xf1\x00BD MDPS C 1.00 1.05 56310/M6000 4BDDC105', ], (Ecu.fwdCamera, 0x7C4, None): [ b'\xf1\x00BD LKAS AT USA LHD 1.00 1.02 95740-M6000 J31',